diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b0385219db4a2d4803659968015dfe356a0f4719 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +trace_streamer/out +.vscode +.idea +ide/bin +ide/cert +ide/dist +ide/node_modules +ide/package-lock.json +ide/third-party +trace_streamer/prebuilts/emsdk +trace_streamer/prebuilts/linux +trace_streamer/third_party +trace_streamer/compile_commands.json +trace_streamer/.cache +tmp_* +build-* +*.pro.use* +.DS_Store +._.DS_Store \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 0000000000000000000000000000000000000000..961fd6b4150b9d37732c0ee204cc3592490b61dd --- /dev/null +++ b/OAT.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 1e04572025d5a94157943bfe9f1f0b2263bd8907..3d93077a0aa0beaa8c81e502e3772e88a6ef7f50 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,69 @@ -# developtools_smartperf_host +# Smartperf-Host +## 简介 +Smartperf-Host是一款深入挖掘数据、细粒度地展示数据的性能功耗调优工具,旨在为开发者提供一套性能调优平台,支持对CPU调度、频点、进程线程时间片、堆内存、帧率等数据进行采集和展示,展示方式为泳道图,支持GUI(图形用户界面)操作进行详细数据分析。 +## 架构图 +![系统架构图](./figures/smartperf_frame.png) +该组件整体分为设备端和PC端两部分,设备端和PC端基于gRPC(Remote Procedure Call)通信框架进行数据交互。 -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +设备端内部分为应用程序内嵌组件、命令行工具、性能调优服务、性能调优插件集合、部分系统工具及部分系统内核等模块。设备端提供了插件扩展能力,对外提供了插件接口,基于该扩展能力可以按需定义自己的能力,并集成到框架中来,目前基于插件能力已经完成了native内存插件、trace插件等,详细介绍见[性能调优组件](https://gitee.com/openharmony/developtools_profiler)。 -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -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/) +PC端以Smartperf-Host网站的形式进行发布,内部分为Trace Streamer数据解析、SQLite数据存储、hdc设备管理、数据导入、UI绘制、数据分析等模块。下文会重点对Smartperf-Host提供的各项能力进行介绍。 +## 项目目录 +``` +/developtools/smartperf_host +├── figures # 图片资源 +├── ide # Smartperf-Host IDE 模块目录 +│ └── src # 主机测调优模块代码 +│ │ ├── base-ui # 基础组件目录 +│ │ └── Trace # 业务逻辑目录 +├── trace_streamer # 解析模块代码目录 +│ ├── base # 基础功能 +│ ├── cfg # 配置目录 +│ ├── filter # Filter 功能 +│ ├── include # Include 头文件 +│ ├── multi_platform # 平台适配 +│ ├── parser # 解析业务逻辑 +│ │ ├── bytrace_parser # byTrace 解析业务逻辑 +│ │ └── htrace_parser # hTrace 解析业务逻辑 +│ ├── table # 表结构 +│ ├── trace_data # trace 结构 +│ ├── trace_streamer # traceStreamer 结构 +│ └── kits # js/napi 接口存放目录 +``` +## 功能介绍 +### 网页加载trace +使用Smartperf-Host加载保存在本地的trace文件(htrace、ftrace等)并显示数据到泳道图中,trace数据分析详见《[网页加载trace说明](./ide/src/doc/md/quickstart_systemtrace.md)》。 +### 网页抓取trace +使用Smartperf-Host在线抓取trace,可以自定义抓取内容、抓取时长、trace保存路径,详见《[网页抓取trace说明](./ide/src/doc/md/quickstart_web_record.md)》。 +### 设备抓取trace +在设备端抓取trace,可以自定义抓取内容、抓取时长、trace保存路径,详见《[设备端抓取trace说明](./ide/src/doc/md/quickstart_device_record.md)》。 +### Ability Monitor抓取 +使用Smartperf-Host抓取应用的CPU、内存、磁盘IO和网络的使用情况,详见《[Ability Monitor抓取和展示说明](./ide/src/doc/md/quickstart_ability_monitor.md)》。 +### Native Memory抓取 +使用Smartperf-Host抓取应用的Native Memory(C和C++部分)的分配和释放情况,详见《[Native Memory抓取和展示说明](./ide/src/doc/md/quickstart_native_memory.md)》。 +### Hiperf抓取 +使用Smartperf-Host抓取应用的cpu使用量、方法的调用栈等,详见《[HiPerf的抓取和展示说明](./ide/src/doc/md/quickstart_hiperf.md)》。 +### HiSystemEvent抓取 +使用Smartperf-Host抓取应用的各个子类别功耗占比(CPU、网络、定位等)、应用的资源申请使用记录(WorkScheduler、Runninglock、Alarm、Location Request)、应用功耗异常事件显示、功耗关联系统状态显示(电池电量、屏幕状态),详见《[HiSystemEvent的抓取和展示说明](./ide/src/doc/md/quickstart_hisystemevent.md)》。 +### FileSystem抓取 +使用Smartperf-Host抓取所有文件系统系统调用信息、读写调用次数等,详见《[FileSystem的抓取和展示说明](./ide/src/doc/md/quickstart_filesystem.md)》。 +### 页内存抓取 +使用Smartperf-Host抓取页内存相关事件的开始时间、持续时间、触发进程、触发线程、事件类型、内存地址、内存大小等,详见《[页内存的抓取和展示说明](./ide/src/doc/md/quickstart_page_fault.md)》。 +### Bio抓取 +使用Smartperf-Host抓取每次IO访问的起始时间、总延迟、进程、每4k数据的平均延迟、线程、操作(写数据、页面换入、Metadata)、访问量、路径等、Block number、优先级、Backtrace调用栈,详见《[Bio的抓取和展示说明](./ide/src/doc/md/quickstart_bio.md)》。 +### 进程Smaps抓取 +使用Smartperf-Host抓取单个进程的smaps数据(类别、Pss、Rss、Vss等),数据源为/proc/$pid/smaps,详见《[进程smaps的抓取和展示说明](./ide/src/doc/md/quickstart_smaps.md)》。 +### Sql分析和Metrics说明 +Smartperf-Host网站trace解析完成后在线数据库使用说明,详见《[Sql分析和Metrics说明](./ide/src/doc/md/quickstart_sql_metrics.md)》。 +## 编译指南 +项目编译主要包括两部分,Trace Streamer编译和Smartperf-Host编译部署。 +### 构建约束 +- C++ 11或以上 +- node 版本 >= 16.15.1 +- npm 版本 >= 8.13.2 +- TypeScript 版本 >= 4.2.3 +- golang 版本 >= 1.13.8 +### Trace Streamer编译 +搭建Smartperf-Host网站需要编译出trace_streamer的wasm版本供网页端进行原始trace数据解析工作,具体的编译过程参考《[如何独立编译Trace Streamer](./trace_streamer/doc/compile_trace_streamer.md)》。 +### Smartperf-Host编译部署 +具体的编译部署过程参考《[SmartPerf 编译部署指导](./ide/README_zh.md)》,部署成功后通过浏览器访问页面 https://[部署机器ip地址]:9000/application/ 即可使用Smartperf-Host的全部功能。 diff --git a/figures/smartperf_frame.png b/figures/smartperf_frame.png new file mode 100755 index 0000000000000000000000000000000000000000..3ed5bb1d08cd1269078374e8ca2e962199f90e65 Binary files /dev/null and b/figures/smartperf_frame.png differ diff --git a/ide/LICENSE b/ide/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..e454a52586f29b8ce8a6799163eac1f875e9ac01 --- /dev/null +++ b/ide/LICENSE @@ -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 + diff --git a/ide/README_zh.md b/ide/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..2c73b0ac620af594982288d8a28269e89cc6200c --- /dev/null +++ b/ide/README_zh.md @@ -0,0 +1,121 @@ +# SmartPerf 编译部署指导文档 + + +## 编译环境搭建 +注意:在linux编译环境安装时以root或者其他 sudo 用户身份运行下面的命令。 +### node 环境安装 +##### 下载Node js安装包(windows推荐, linux跳过此步骤) +从网站下载node js安装包 https://nodejs.org/en/download/current/。 +##### 安装nodejs +- ubuntu 20.04 与Debian 11系统中,直接用apt-get安装,先切换到 root用户下,命令如下(node 版本 >= 16.15.1 npm 版本 >= 8.13.2) +``` + sudo su + apt-get update + apt-get install nodejs npm +``` +![](./src/figures/deploy/install_node.png) + + +- centos 系统中使用yum安装,先切换到root用户下,命令如下: +``` + sudo su + sudo yum -y install nodejs npm +``` +![](./src/figures/deploy/yum_install_node.png) + +- windows系统中, 用安装包一路next即可 + + +- 安装完成后运行检查是否安装成功 +``` + node -v + npm -v +``` +![](./src/figures/deploy/check_version.png) + + 出现版本号就代表安装成功了。 + +##### 更换npm源 +``` + npm config set registry http://registry.npmmirror.com +``` + +##### 安装tsc typeScript 编译器 +直接使用npm 安装运行命令。 +``` + npm install -g typescript + tsc -v +``` + + 验证安装完成: +![](./src/figures/deploy/install_tsc.png) + +### go 编译环境安装 +- ubuntu 环境下直接使用apt安装,以root用户执行(go 版本 >= 1.13.8 ) +``` + apt-get install golang-go +``` +![](./src/figures/deploy/install_golang.png) + +- centos系统中使用yum安装,先切换到root用户下,命令如下: + +``` + sudo su + sudo yum -y install go +``` +![](./src/figures/deploy/yum_install_go.png) + +- windows 系统下 从 https://golang.google.cn/dl/ 下载安装包, 一路next 完成 安装即可 + +- 安装完成后 命令行运行验证是否安装成功 + +``` + go version +``` +## 项目编译 +#### 先下载sql.js的二进制包 +从如下 https://github.com/sql-js/sql.js/releases/download/v1.6.2/sqljs-all.zip 获取到sql.js的二进制包。 +将压缩包解压后, 将文件放置到项目third-party 目录下。 + + +![](./src/figures/deploy/third_party.png) + +#### 先编译获取trace_streamer 的二进制包 +参照:smartperf/trace_streamer/compile_trace_streamer.md 编译出wasm、linux、Windows版本的二进制文件。 +将获取到二进制文件放入到项目bin目录下,如果项目目录中无bin目录 先创建bin目录。 +然后将trace_streamer的二进制文件放入bin目录中。 + +![](./src/figures/deploy/put_bin.png) +![](./src/figures/deploy/bin_files.png) + + +#### 代码编译(依赖于上面node环境 和 go环境) +在项目目录安装项目依赖: +``` + npm install +``` +在项目目录下运行命令: +``` + npm run compile +``` +![](./src/figures/deploy/compile.png) + 编译成功后会有main 可执行文件生成。 + +## 项目部署 +linux版本部署需要给trace_stream程序赋予执行权限,cd dist/bin 目录下,执行如下命令: +``` + chmod +x trace_streamer_* +``` +![](./src/figures/deploy/chomd+x.png) + +直接运行 ./main 可执行程序,完成项目的部署。 +![](./src/figures/deploy/run_main.png) + ## 访问项目 +在浏览器上打开 https://[部署机器ip地址]:9000/application/ +!!! 注意一定是https。 + +![](./src/figures/deploy/visit_website.png) + + 备注:如果未出现如图所示网页.而是显示 无法访问此网站。 +可以在window cmd 里执行telnet [部署机器ip地址] 9000。 +如果显示端口连接失败 可能是防火墙未对9000 端口放开即可。 \ No newline at end of file diff --git a/ide/build.js b/ide/build.js new file mode 100644 index 0000000000000000000000000000000000000000..6d2f658759a210dec8d2b227ba7bafc75848e6eb --- /dev/null +++ b/ide/build.js @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2022 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. + */ + +const path = require('path'); +const fs = require('fs'); +const child_process = require('child_process'); +const os = require('os'); +const log4js = require('log4js'); + +const compileServer = true; +const outDir = 'dist'; + +const sdkWams = [ + 'trace_streamer_sdk_builtin.js', + 'trace_streamer_sdk_builtin.wasm', + 'trace_streamer_dubai_builtin.js', + 'trace_streamer_dubai_builtin.wasm', +]; + +const staticPath = ['/src/img', '/server/cert', '/src/doc', '/src/figures']; + +const staticFiles = [ + '/server/version.txt', + '/src/index.html', + '/src/base-ui/icon.svg', + '/server/wasm.json', + '/server/server-config.txt', +]; + +const thirdParty = [ + { + srcFilePath: '/third-party/sql-wasm.wasm', + distFilePath: '/trace/database/sql-wasm.wasm', + }, + { + srcFilePath: '/third-party/sql-wasm.js', + distFilePath: '/trace/database/sql-wasm.js', + }, + { + srcFilePath: '/third-party/worker.sql-wasm.js', + distFilePath: '/trace/database/worker.sql-wasm.js', + }, +]; + +let log; + +function cpFile(from, to) { + if (fs.existsSync(from)) { + fs.writeFileSync(to, fs.readFileSync(from)); + log.info('cp file %s to %s', from, to); + } else { + log.warn('file %s is not exists', from, to); + } +} + +function checkEnvironment() { + let goVersion = child_process.execSync('go version', { + encoding: 'utf-8', + }); + log.info('go is', goVersion); + let nodeVersion = child_process.execSync('node -v', { + encoding: 'utf-8', + }); + log.info('node version is', nodeVersion); + let tscVersion = child_process.execSync('tsc -v', { + encoding: 'utf-8', + }); + log.info('tsc version is', tscVersion); + if (goVersion == '' || nodeVersion == '' || tscVersion == '') { + return false; + } + let traceStreamer = path.normalize(path.join(__dirname, '/bin')); + if (!checkDirExist(traceStreamer + '/trace_streamer_builtin.js')) { + log.error(traceStreamer + '/trace_streamer_builtin.js' + ' Must exist'); + return false; + } + if (!checkDirExist(traceStreamer + '/trace_streamer_builtin.wasm')) { + log.error(traceStreamer + '/trace_streamer_builtin.wasm' + ' Must exist'); + return false; + } + return true; +} + +function initLog() { + log4js.configure({ + appenders: { + out: { type: 'stdout' }, + }, + categories: { + default: { appenders: ['out'], level: 'debug' }, + }, + }); + return log4js.getLogger('smartPerf'); +} + +function main() { + log = initLog(); + if (!checkEnvironment()) { + return; + } + // clean outDir + let outPath = path.normalize(path.join(__dirname, '/', outDir)); + if (checkDirExist(outPath)) { + log.info('delete the last compilation result'); + removeDir(outPath); + log.info('delete the last compilation success'); + } + // run tsc compile + log.info('start compiling typeScript code'); + let rootPath = path.join(__dirname, '/'); + child_process.execSync('tsc -p ' + rootPath, { + encoding: 'utf-8', + }); + log.info('compiling typeScript code success'); + // run cp to mv all staticFile + staticFiles.forEach((value) => { + let filePath = path.join(__dirname, value); + let distFile; + if (value.startsWith('/src')) { + distFile = path.join(__dirname, outDir, value.substring(4, value.length + 1)); + } else if (value.startsWith('/server')) { + distFile = path.join(__dirname, outDir, value.substring(7, value.length + 1)); + } + cpFile(filePath, distFile); + }); + staticPath.forEach((value) => { + let pa = path.join(__dirname, value); + let distPath; + if (value.startsWith('/src')) { + distPath = path.join(__dirname, outDir, value.substring(4, value.length + 1)); + } else if (value.startsWith('/server')) { + distPath = path.join(__dirname, outDir, value.substring(7, value.length + 1)); + } + copyDirectory(pa, distPath); + }); + thirdParty.forEach((value) => { + let thirdFile = path.join(__dirname, value.srcFilePath); + let thirdDistFile = path.join(__dirname, outDir, value.distFilePath); + cpFile(thirdFile, thirdDistFile); + }); + let traceStreamer = path.normalize(path.join(__dirname, '/bin')); + if (checkDirExist(traceStreamer)) { + let dest = path.normalize(path.join(__dirname, outDir, '/bin')); + copyDirectory(traceStreamer, dest); + // to mv traceStream Wasm and js + cpFile( + traceStreamer + '/trace_streamer_builtin.js', + rootPath + outDir + '/trace/database/trace_streamer_builtin.js' + ); + cpFile( + traceStreamer + '/trace_streamer_builtin.wasm', + rootPath + outDir + '/trace/database/trace_streamer_builtin.wasm' + ); + if (sdkWams.length > 0) { + sdkWams.forEach((fileName) => { + cpFile(traceStreamer + '/' + fileName, rootPath + outDir + '/trace/database/' + fileName); + }); + } + } else { + log.error('traceStreamer dir is not Exits'); + return; + } + // compile server + if (compileServer) { + log.log('start compile server'); + let serverSrc = path.normalize(path.join(__dirname, '/server/main.go')); + let rs; + if (os.type() === 'Windows_NT') { + rs = child_process.spawnSync('go', ['build', '-o', outPath, serverSrc], { + encoding: 'utf-8', + }); + } else if (os.type() == 'Darwin') { + rs = child_process.spawnSync('go', ['build', '-o', outPath + '/main', serverSrc], { + encoding: 'utf-8', + }); + } else { + rs = child_process.spawnSync('go', ['build', '-o', outPath + '/main', serverSrc], { + encoding: 'utf-8', + }); + } + if (rs.status == 0) { + log.log('compile server success'); + } else { + log.error('compile server failed', rs); + } + } else { + log.warn('skip compile server'); + } + log.log('smartPerf compile success'); +} + +function copyDirectory(src, dest) { + if (checkDirExist(dest) == false) { + fs.mkdirSync(dest); + } + if (checkDirExist(src) == false) { + return false; + } + let directories = fs.readdirSync(src); + directories.forEach((value) => { + let filePath = path.join(src, value); + let fileSys = fs.statSync(filePath); + if (fileSys.isFile()) { + let destPath = path.join(dest, value); + log.info('cp file %s to %s', filePath, destPath); + fs.copyFileSync(filePath, destPath); + } else if (fileSys.isDirectory()) { + copyDirectory(filePath, path.join(dest, value)); + } + }); +} + +function checkDirExist(dirPath) { + return fs.existsSync(dirPath); +} + +function removeDir(outPath) { + let files = []; + if (fs.existsSync(outPath)) { + files = fs.readdirSync(outPath); + files.forEach((file, index) => { + let curPath = outPath + '/' + file; + if (fs.statSync(curPath).isDirectory()) { + removeDir(curPath); + } else { + fs.unlinkSync(curPath); + } + }); + fs.rmdirSync(outPath); + } +} + +main(); diff --git a/ide/package.json b/ide/package.json new file mode 100644 index 0000000000000000000000000000000000000000..cf9da3161d6f0bfefd95fcb91af08fc83277f17c --- /dev/null +++ b/ide/package.json @@ -0,0 +1,59 @@ +{ + "name": "SmartPerf", + "version": "1.0.0", + "description": "Smart Perf", + "main": "index.js", + "scripts": { + "compile": "node ./build.js", + "test": "jest -u", + "test-c": "jest --coverage -u" + }, + "jest": { + "testEnvironment": "jsdom", + "collectCoverageFrom": [ + "/dist/**/*.js", + "!/dist/bin/*", + "!/dist/trace/database/pixi.js", + "!/dist/trace/database/sql-wasm.js", + "!/dist/trace/database/uuidv4.min.js", + "!/dist/trace/database/worker.sql-wasm.js", + "!/dist/trace/database/worker.sql-wasm-debug.js", + "!/dist/trace/database/trace_streamer_builtin.js", + "!/dist/trace/database/trace_streamer_sdk_builtin.js", + "!/dist/trace/database/trace_streamer_dubai_builtin.js" + ], + "globals": { + "useWb": true + }, + "setupFiles": [ + "jsdom-worker", + "jest-canvas-mock" + ], + "setupFilesAfterEnv": [ + "/jest.setup.js" + ] + }, + "repository": { + "type": "git", + "url": "" + }, + "author": "", + "license": "Apache License", + "devDependencies": { + "@babel/plugin-proposal-class-properties": "^7.16.7", + "@babel/plugin-proposal-decorators": "^7.17.2", + "@babel/preset-env": "*", + "@babel/preset-typescript": "*", + "@types/jest": "*", + "@types/node": "^17.0.10", + "jest": "*", + "jest-canvas-mock": "^2.3.1", + "typescript": "^4.2.3", + "jsdom-worker": "^0.2.1", + "jest-environment-jsdom": "^28.1.0", + "node-fetch": "^2.6.7", + "log4js": "^6.4.4", + "usb": "^2.4.2" + }, + "dependencies": {} +} diff --git a/ide/server/go.mod b/ide/server/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..aaa88e400a264e7ea35f528c0793e783515c8c70 --- /dev/null +++ b/ide/server/go.mod @@ -0,0 +1,21 @@ +// Copyright (C) 2022 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. + +module dist + +go 1.17 + +require ( + github.com/djimenez/iconv-go v0.0.0-20160305225143-8960e66bd3da + golang.org/x/text v0.3.7 +) \ No newline at end of file diff --git a/ide/server/main.go b/ide/server/main.go new file mode 100644 index 0000000000000000000000000000000000000000..bf73502a52922a30b5bd7110ef0ad22324482bf4 --- /dev/null +++ b/ide/server/main.go @@ -0,0 +1,489 @@ +// Copyright (C) 2022 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. + +package main + +//遇到报错请在当前目录下执行这个命令: go mod download golang.org/x/text +import ( + "bufio" + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "fmt" + "io" + "io/fs" + "log" + "math/big" + "mime" + "net" + "net/http" + "net/http/cookiejar" + "os" + "os/exec" + "path" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "time" +) + +const HttpPort = 9000 + +var exPath string +var serveInfo string + +// CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go +// CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build main.go +func cors(fs http.Handler, version string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // return if you do not want the FileServer handle a specific request + r.Header.Add("Cross-Origin-Opener-Policy", "same-origin") + r.Header.Add("Cross-Origin-Embedder-Policy", "require-corp") + w.Header().Add("Cross-Origin-Opener-Policy", "same-origin") + w.Header().Add("Cross-Origin-Embedder-Policy", "require-corp") + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Credentials", "true") + w.Header().Set("Access-Control-Allow-Headers", "x-requested-with, authorization, blade-auth") //* + w.Header().Set("Access-Control-Allow-Methods", "*") //* + w.Header().Set("Access-Control-Max-Age", "3600") + w.Header().Set("data-version", version) + fs.ServeHTTP(w, r) + } +} + +func exist(path string) bool { + _, err := os.Stat(path) + if err != nil { + if os.IsExist(err) { + return true + } + return false + } + return true +} +func genSSL() { + if exist("cert/keyFile.key") || exist("cert/certFile.pem") { + fmt.Println("keyFile.key exists") + return + } + max := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, _ := rand.Int(rand.Reader, max) + subject := pkix.Name{ + Organization: []string{"www.smartperf.com"}, + OrganizationalUnit: []string{"ITs"}, + CommonName: "www.smartperf.com", + } + certificate509 := x509.Certificate{ + SerialNumber: serialNumber, + Subject: subject, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + IPAddresses: []net.IP{net.ParseIP("127.0.0.1")}, + } + chekDir("cert") + pk, _ := rsa.GenerateKey(rand.Reader, 1024) + derBytes, _ := x509.CreateCertificate(rand.Reader, &certificate509, &certificate509, &pk.PublicKey, pk) + certOut, _ := os.Create("cert/certFile.pem") + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certOut.Close() + keyOut, _ := os.Create("cert/keyFile.key") + pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)}) + keyOut.Close() +} +func main() { + checkPort(HttpPort) + genSSL() + exPath = getCurrentAbPath() + fmt.Println(exPath) + go func() { + version := "" + readVersion, versionErr := os.ReadFile(exPath + "/version.txt") + if versionErr != nil { + version = "" + } else { + version = string(readVersion) + } + readReqServerConfig() + mux := http.NewServeMux() + mime.TypeByExtension(".js") + mime.AddExtensionType(".js", "application/javascript") + log.Println(mime.TypeByExtension(".js")) + mux.HandleFunc("/logger", consoleHandler) + mux.Handle("/upload/", http.StripPrefix("/upload/", http.FileServer(http.Dir(filepath.FromSlash(exPath+"/upload"))))) + mux.HandleFunc("/download-file", downloadHandler) + mux.HandleFunc("/application/serverInfo", serverInfo) + fs := http.FileServer(http.Dir(exPath + "/")) + mux.Handle("/application/", http.StripPrefix("/application/", cors(fs, version))) + go func() { + ser := &http.Server{ + Addr: fmt.Sprintf(":%d", HttpPort), + Handler: mux, + } + log.Println(fmt.Sprintf("HTTPS[%d]服务启动", HttpPort)) + err := ser.ListenAndServeTLS("cert/certFile.pem", "cert/keyFile.key") + CheckErr(err) + }() + go func() { + ser := &http.Server{ + Addr: fmt.Sprintf(":%d", HttpPort+1), + Handler: mux, + } + log.Println(fmt.Sprintf("HTTP[%d]服务启动", HttpPort)) + err := ser.ListenAndServe() + CheckErr(err) + }() + open(fmt.Sprintf("https://localhost:%d/application", HttpPort)) + }() + select {} +} + +func getPidByPort(portNumber int) int { + resPid := -1 + var out bytes.Buffer + cmdRes := exec.Command("cmd", "/c", fmt.Sprintf("netstat -ano -p tcp | findstr %d", portNumber)) + cmdRes.Stdout = &out + cmdRes.Run() + cmdResStr := out.String() + findStr := regexp.MustCompile(`\s\d+\s`).FindAllString(cmdResStr, -1) + if len(findStr) > 0 { + pid, err := strconv.Atoi(strings.TrimSpace(findStr[0])) + if err != nil { + resPid = -1 + } else { + resPid = pid + } + } + return resPid +} + +type LoggerReq struct { + FileName string `json:"fileName"` + FileSize string `json:"fileSize"` +} + +func consoleHandler(w http.ResponseWriter, r *http.Request) { + chekDir(exPath + "/logger") + var now = time.Now() + var fileName = fmt.Sprintf("%d-%d-%d", now.Year(), now.Month(), now.Day()) + dst, err := os.OpenFile(exPath+"/logger/"+fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND|os.O_SYNC, 0666) + CheckErr(err) + contentType := r.Header["Content-Type"] + if len(contentType) > 0 { + contentTypeName := contentType[0] + if strings.HasPrefix(contentTypeName, "application/json") { + decoder := json.NewDecoder(r.Body) + var req LoggerReq + decoder.Decode(&req) + dst.WriteString(fmt.Sprintf("%s %s (%s M)\n", now.Format("2006-01-02 15:04:05"), req.FileName, req.FileSize)) + fmt.Fprintf(w, fmt.Sprintf("日志写入成功%s", exPath)) + } + } +} + +func serverInfo(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("request_info", serveInfo) + w.WriteHeader(200) +} + +func readReqServerConfig() string { + readServerConfig, serverConfigErr := os.ReadFile(exPath + "/server-config.txt") + if serverConfigErr != nil { + serveInfo = "" + } else { + serveInfo = string(readServerConfig) + } + return serveInfo +} + +func mapToJson(m map[string]interface{}) (string, error) { + marshal, err := json.Marshal(m) + if err != nil { + return "", err + } + var str = string(marshal) + return str, nil +} +func jsonToMap(str string) (map[string]interface{}, error) { + var m = make(map[string]interface{}) + err := json.Unmarshal([]byte(str), &m) + if err != nil { + return nil, err + } + return m, nil +} + +// MkDir 创建目录 +func MkDir(path string) { + dir := path[0:strings.LastIndex(path, string(os.PathSeparator))] //从文件路径获取目录 + if _, err := os.Stat(dir); err != nil { //如果目录不存在,创建目录 + os.MkdirAll(dir, os.ModePerm) + } +} + +func resp(w *http.ResponseWriter) func(bool, int, string, map[string]interface{}) { + return func(success bool, code int, msg string, obj map[string]interface{}) { + toJson, err := mapToJson(map[string]interface{}{ + "success": success, + "code": code, + "msg": msg, + "data": obj, + }) + if err != nil { + errRes, _ := mapToJson(map[string]interface{}{ + "success": false, + "code": -1, + "msg": err.Error(), + }) + fmt.Fprintf(*w, errRes) + } else { + fmt.Fprintf(*w, toJson) + } + } +} + +func get(url string) (*http.Response, error) { + jar, _ := cookiejar.New(nil) + c := &http.Client{ + Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, + CheckRedirect: nil, + Jar: jar, + Timeout: time.Duration(3600) * time.Second, + } + return c.Get(url) +} + +func clearOverdueFile() { + MkDir(filepath.FromSlash(fmt.Sprintf("./upload/"))) + now := time.Now() + loc, err := time.LoadLocation("Asia/Shanghai") + if err != nil { + return + } + var checkDue = func(fileName string) bool { + f := getSuffixByUrl(fileName) + parseTime, err := time.ParseInLocation("20060102150405000", f.fileName, loc) + if err != nil { + return false + } + sub := now.Sub(parseTime) + if sub.Minutes() > 60 { //bigger than 60 min flag due + return true + } + return false + } + slash := filepath.FromSlash(fmt.Sprintf("./upload/")) + filepath.WalkDir(slash, func(path string, d fs.DirEntry, err error) error { + if checkDue(d.Name()) { + fmt.Println(now, "delete->", path, d.Name(), err) + os.Remove(path) + } + return nil + }) +} +func getSuffixByUrl(u string) struct { + fileName string + suffix string +} { + lastIndex := strings.LastIndex(u, "/") + var f string + if lastIndex != -1 { + f = u[lastIndex:] + } else { + f = u + } + index := strings.LastIndex(f, ".") + if index != -1 { + return struct { + fileName string + suffix string + }{ + f[0:index], + f[index:], + } + } else { + return struct { + fileName string + suffix string + }{ + f, + "", + } + } +} + +func downloadHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "text/json") + clearOverdueFile() + contentType := r.Header["Content-Type"] + if len(contentType) > 0 { + contentTypeName := contentType[0] + if strings.HasPrefix(contentTypeName, "application/x-www-form-urlencoded") { + url := r.PostFormValue("url") + res, err := get(url) + if err != nil { + resp(&w)(false, -1, err.Error(), nil) + return + } + pth := filepath.FromSlash(fmt.Sprintf("/upload/%s%s", time.Now().Format("20060102150405000"), getSuffixByUrl(url).suffix)) + MkDir("." + pth) + create, err := os.Create("." + pth) + if err != nil { + resp(&w)(false, -1, err.Error(), nil) + return + } + written, err := io.Copy(create, res.Body) + if err != nil { + resp(&w)(false, -1, err.Error(), nil) + return + } + fmt.Println(url, written) + resp(&w)(true, 0, "success", map[string]interface{}{ + "url": pth, + "size": written, + }) + return + } + } + resp(&w)(false, -1, "请求方式错误", nil) +} + +func SplitLines(s string) []string { + var lines []string + sc := bufio.NewScanner(strings.NewReader(s)) + for sc.Scan() { + lines = append(lines, sc.Text()) + } + return lines +} + +func readFileFirstLine(path string) string { + file, err := os.Open(path) + if err != nil { + return "" + } + defer file.Close() + + readFile := bufio.NewReader(file) + line, readErr := readFile.ReadString('\n') + if readErr != nil || io.EOF == err { + return "" + } + return line +} + +func PathExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +func chekDir(path string) { + _, err := os.Stat(path) + if err != nil { + err := os.Mkdir(path, os.ModePerm) + if err != nil { + fmt.Printf("mkdir failed![%v]\n", err) + } else { + fmt.Printf("mkdir success!\n") + } + } +} +func CheckErr(err error) { + if err != nil { + log.Panicln(err) + } +} + +func open(url string) error { + if isWindows() { + return openUrlWindows(url) + } else if isDarwin() { + return openUrlDarwin(url) + } else { + return openUrlOther(url) + } +} + +func openUrlWindows(url string) error { + cmd := "cmd" + args := []string{"/c", "start", url} + return exec.Command(cmd, args...).Start() +} +func openUrlDarwin(url string) error { + var cmd = "open" + var args = []string{url} + return exec.Command(cmd, args...).Start() +} +func openUrlOther(url string) error { + var cmd = "xdg-open" + var args = []string{url} + return exec.Command(cmd, args...).Start() +} + +func isWindows() bool { + return runtime.GOOS == "windows" +} +func isDarwin() bool { + return runtime.GOOS == "darwin" +} + +func getCurrentAbPath() string { + dir := getExecutePath() + tmpDir, _ := filepath.EvalSymlinks(os.TempDir()) + if strings.Contains(dir, tmpDir) { + return getCallerPath() + } + return dir +} + +func getCallerPath() string { + var pth string + _, fName, _, ok := runtime.Caller(0) + if ok { + pth = path.Dir(fName) + } + return pth +} +func getExecutePath() string { + pth, err := os.Executable() + if err != nil { + log.Fatal(err) + } + res, _ := filepath.EvalSymlinks(filepath.Dir(pth)) + return res +} + +func checkPort(port int) { + if isWindows() { + pid := getPidByPort(port) + if pid != -1 { + res := exec.Command("cmd", "/c", fmt.Sprintf("taskkill /F /PID %d /T", pid)) + res.Run() + } + } +} diff --git a/ide/server/server-config.txt b/ide/server/server-config.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c740bc33cf0647e6a12c33e7b9694db960a0fea --- /dev/null +++ b/ide/server/server-config.txt @@ -0,0 +1 @@ +127.0.0.1:9100 \ No newline at end of file diff --git a/ide/server/version.txt b/ide/server/version.txt new file mode 100644 index 0000000000000000000000000000000000000000..13eb9fd76e77a11fbeea787631d5e10c91685e24 --- /dev/null +++ b/ide/server/version.txt @@ -0,0 +1 @@ +v1.0.001 \ No newline at end of file diff --git a/ide/server/wasm.json b/ide/server/wasm.json new file mode 100644 index 0000000000000000000000000000000000000000..a6ad72382448bff1c3142afd7a070ed989d4fc48 --- /dev/null +++ b/ide/server/wasm.json @@ -0,0 +1,20 @@ +{ + "WasmFiles": [ + { + "disPlayName": "common_mock", + "componentId": 0, + "pluginName": "mock-plugin", + "sampleInterval": 5000, + "wasmJsName": "trace_streamer_sdk_builtin.js", + "wasmName": "trace_streamer_sdk_builtin_wasm" + }, + { + "disPlayName": "dubai-plugin", + "componentId": 1, + "pluginName": "dubai-plugin", + "sampleInterval": 5000, + "wasmJsName": "trace_streamer_dubai_builtin.js", + "wasmName": "trace_streamer_dubai_builtin_wasm" + } + ] +} diff --git a/ide/src/base-ui/BaseElement.ts b/ide/src/base-ui/BaseElement.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa81e5ece740cb022218acf09299f0ac72a58d35 --- /dev/null +++ b/ide/src/base-ui/BaseElement.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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. + */ + +export function element(tag: string) { + return (el: any) => { + if (!customElements.get(tag)) { + customElements.define(tag, el); + } + }; +} + +export abstract class BaseElement extends HTMLElement { + args: any; + + public constructor(args: any | undefined | null = null) { + super(); + this.args = args; + this.attachShadow({ mode: 'open' }).innerHTML = this.initHtml(); + this.initElements(); + } + + abstract initElements(): void; + + abstract initHtml(): string; + + public connectedCallback() {} + + public disconnectedCallback() {} + + public adoptedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) {} +} diff --git a/ide/src/base-ui/button/LitButton.ts b/ide/src/base-ui/button/LitButton.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3604bf9b27d8be198f73658dd0bf87bf14b49c7 --- /dev/null +++ b/ide/src/base-ui/button/LitButton.ts @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-button') +export class LitButton extends BaseElement { + private slotHtml: HTMLElement | undefined; + private button: HTMLButtonElement | null | undefined; + private litIcon: LitButton | null | undefined; + + static get observedAttributes() { + return [ + 'text', + 'back', + 'icon', + 'height', + 'width', + 'color', + 'font_size', + 'border', + 'padding', + 'justify_content', + 'border_radius', + 'margin_icon', + 'opacity', + ]; + } + + get text() { + return this.getAttribute('text') || ''; + } + + set text(text: string) { + this.setAttribute('text', text); + } + + get back() { + return this.getAttribute('back') || ''; + } + + set back(backColor: string) { + this.button!.style.backgroundColor = backColor; + this.setAttribute('back', backColor); + } + + get icon() { + return this.getAttribute('icon') || ''; + } + + set icon(icon: string) { + this.litIcon?.setAttribute('name', icon); + this.setAttribute('icon', icon); + if (icon) { + this.litIcon!.style.display = 'block'; + } + } + + get height() { + return this.getAttribute('height') || ''; + } + + set height(height: string) { + this.setAttribute('height', height); + } + + get width() { + return this.getAttribute('width') || ''; + } + + set width(width: string) { + this.setAttribute('width', width); + } + + set color(color: string) { + this.setAttribute('color', color); + } + + set font_size(fontSize: string) { + this.setAttribute('font_size', fontSize); + } + + set border(border: string) { + this.setAttribute('border', border); + } + + set padding(padding: string) { + this.setAttribute('padding', padding); + } + + set justify_content(justifyContent: string) { + this.setAttribute('justify_content', justifyContent); + } + + set border_radius(borderRadius: string) { + this.setAttribute('border_radius', borderRadius); + } + + set margin_icon(value: string) { + this.litIcon?.setAttribute('margin_icon', value); + } + + set opacity(value: string) { + this.litIcon?.setAttribute('opacity', value); + } + + set hidden(hidden: boolean) { + if (hidden) { + this.setAttribute('hidden', 'true'); + this.style.display = 'none'; + } else { + this.removeAttribute('hidden'); + this.style.display = 'block'; + } + } + + initHtml(): string { + return ` + +
+ +
+ `; + } + + initElements(): void { + this.slotHtml = this.shadowRoot?.querySelector('#sl') as HTMLElement; + this.button = this.shadowRoot?.querySelector('#custom-button'); + this.litIcon = this.shadowRoot?.querySelector('#button-icon') as LitButton; + if (this.litIcon.getAttribute('name') == '') { + this.litIcon!.style.display = 'none'; + } + } + + attributeChangedCallback(name: string, oldValue: string, value: string) { + switch (name) { + case 'text': + this.slotHtml!.innerText = value; + break; + case 'back': + this.button!.style.backgroundColor = value; + break; + case 'icon': + this.litIcon?.setAttribute('name', value); + if (value) { + this.litIcon!.style.display = 'block'; + } + break; + case 'height': + this.button!.style.height = value; + break; + case 'color': + this.button!.style.color = value; + break; + case 'font_size': + this.button!.style.fontSize = value; + break; + case 'border': + this.button!.style.border = value; + break; + case 'padding': + this.button!.style.padding = value; + break; + case 'justify_content': + this.button!.style.justifyContent = value; + break; + case 'border_radius': + this.button!.style.borderRadius = value; + break; + case 'margin_icon': + this.litIcon!.style.margin = value; + break; + case 'opacity': + this.button!.style.opacity = value; + break; + } + } +} diff --git a/ide/src/base-ui/chart/column/LitChartColumn.ts b/ide/src/base-ui/chart/column/LitChartColumn.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b7464b54066482035430bfda1f02f36da70200a --- /dev/null +++ b/ide/src/base-ui/chart/column/LitChartColumn.ts @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../BaseElement.js'; +import { LitChartColumnConfig } from './LitChartColumnConfig.js'; +import { resizeCanvas } from '../helper.js'; + +class Pillar { + obj?: any; + xLabel?: string; + yLabel?: string; + type?: string; + root?: boolean; + bgFrame?: { + x: number; + y: number; + w: number; + h: number; + }; + frame?: { + x: number; + y: number; + w: number; + h: number; + }; + height?: number; + process?: boolean; + heightStep?: number; + centerX?: number; + centerY?: number; + color?: string; + hover?: boolean; +} + +interface RLine { + label: string; + y: number; +} + +@element('lit-chart-column') +export class LitChartColumn extends BaseElement { + private tipEL: HTMLDivElement | null | undefined; + canvas: HTMLCanvasElement | undefined | null; + ctx: CanvasRenderingContext2D | undefined | null; + cfg: LitChartColumnConfig | null | undefined; + offset?: { x: number | undefined; y: number | undefined }; + data: Pillar[] = []; + rowLines: RLine[] = []; + + connectedCallback() { + super.connectedCallback(); + this.tipEL = this.shadowRoot!.querySelector('#tip'); + this.canvas = this.shadowRoot!.querySelector('#canvas'); + this.ctx = this.canvas!.getContext('2d', { alpha: true }); + resizeCanvas(this.canvas!); + this.offset = { x: 40, y: 20 }; + this.canvas!.onmouseout = (e) => { + this.hideTip(); + this.data.forEach((it) => (it.hover = false)); + this.render(); + }; + this.canvas!.onmousemove = (ev) => { + let rect = this.getBoundingClientRect(); + let x = ev.pageX - rect.left; + let y = ev.pageY - rect.top; + this.data.forEach((it) => { + if (contains(it.bgFrame!, x, y)) { + it.hover = true; + this.cfg?.hoverHandler?.(it.obj.no); + } else { + it.hover = false; + } + }); + let pillars = this.data.filter((it) => it.hover); + if (this.cfg?.seriesField) { + if (pillars.length > 0) { + let title = ``; + let msg = pillars.map((it) => ``).join(''); + let sum = ``; + let innerHtml = `
${title}${msg}${sum}
`; + if (x >= this.clientWidth - this.tipEL!.clientWidth) { + this.showTip(x - this.tipEL!.clientWidth - 10, y - 20, this.cfg!.tip ? this.cfg!.tip(pillars) : innerHtml); + } else { + this.showTip(x + 10, y - 20, this.cfg!.tip ? this.cfg!.tip(pillars) : innerHtml); + } + } + } else { + if (pillars.length > 0) { + let title = ``; + let innerHtml = `
${title}
`; + if (x >= this.clientWidth - this.tipEL!.clientWidth) { + this.showTip(x - this.tipEL!.clientWidth - 10, y - 20, this.cfg!.tip ? this.cfg!.tip(pillars) : innerHtml); + } else { + this.showTip(x + 10, y - 20, this.cfg!.tip ? this.cfg!.tip(pillars) : innerHtml); + } + } + } + + if (this.data.filter((it) => it.process).length == 0) { + this.render(); + } + }; + this.render(); + } + + showHoverColumn(index: number) { + this.data.forEach((it) => { + if (it.obj.no === index) { + it.hover = true; + } else { + it.hover = false; + } + }); + let pillars = this.data.filter((it) => it.hover); + if (this.cfg?.seriesField) { + if (pillars.length > 0) { + let hoverData = pillars[0]; + let title = ``; + let msg = pillars.map((it) => ``).join(''); + let sum = ``; + let innerHtml = `
${title}${msg}${sum}
`; + this.showTip(this.clientWidth / 2, this.clientHeight / 2, this.cfg!.tip ? this.cfg!.tip(pillars) : innerHtml); + } + } else { + if (pillars.length > 0) { + let hoverData = pillars[0]; + let title = ``; + let innerHtml = `
${title}
`; + this.showTip(this.clientWidth / 2, this.clientHeight / 2, this.cfg!.tip ? this.cfg!.tip(pillars) : innerHtml); + } + } + + if (this.data.filter((it) => it.process).length == 0) { + this.render(); + } + } + + initElements(): void { + new ResizeObserver((entries, observer) => { + entries.forEach((it) => { + resizeCanvas(this.canvas!); + this.measure(); + this.render(false); + }); + }).observe(this); + } + + set config(cfg: LitChartColumnConfig | null | undefined) { + if (!cfg) return; + this.cfg = cfg; + this.measure(); + this.render(); + } + + set dataSource(arr: any[]) { + if (this.cfg) { + this.cfg.data = arr; + this.measure(); + this.render(); + } + } + + get dataSource() { + return this.cfg?.data || []; + } + + measure() { + if (!this.cfg) return; + this.data = []; + this.rowLines = []; + if (!this.cfg.seriesField) { + let maxValue = Math.max(...this.cfg.data.map((it) => it[this.cfg!.yField])); + maxValue = Math.ceil(maxValue * 0.1) * 10; + let partWidth = (this.clientWidth - this.offset!.x!) / this.cfg.data.length; + let partHeight = this.clientHeight - this.offset!.y!; + let gap = partHeight / 5; + let valGap = maxValue / 5; + for (let i = 0; i <= 5; i++) { + this.rowLines.push({ + y: gap * i, + label: `${maxValue - valGap * i} `, + }); + } + this.cfg?.data + .sort((a, b) => b[this.cfg!.yField] - a[this.cfg!.yField]) + .forEach((it, i, array) => { + this.data.push({ + color: this.cfg!.color(it), + obj: it, + root: true, + xLabel: it[this.cfg!.xField], + yLabel: it[this.cfg!.yField], + bgFrame: { + x: this.offset!.x! + partWidth * i, + y: 0, + w: partWidth, + h: partHeight, + }, + centerX: this.offset!.x! + partWidth * i + partWidth / 2, + centerY: + partHeight - + (it[this.cfg!.yField] * partHeight) / maxValue + + (it[this.cfg!.yField] * partHeight) / maxValue / 2, + frame: { + x: this.offset!.x! + partWidth * i + partWidth / 6, + y: partHeight - (it[this.cfg!.yField] * partHeight) / maxValue, + w: partWidth - partWidth / 3, + h: (it[this.cfg!.yField] * partHeight) / maxValue, + }, + height: 0, + heightStep: Math.ceil((it[this.cfg!.yField] * partHeight) / maxValue / 60), + process: true, + }); + }); + } else { + let reduceGroup = this.cfg.data.reduce((pre, current, index, arr) => { + (pre[current[this.cfg!.xField]] = pre[current[this.cfg!.xField]] || []).push(current); + return pre; + }, {}); + let sums = Reflect.ownKeys(reduceGroup).map((k) => + (reduceGroup[k] as any[]).reduce((pre, current) => pre + current[this.cfg!.yField], 0) + ); + let maxValue = Math.ceil(Math.max(...sums) * 0.1) * 10; + let partWidth = (this.clientWidth - this.offset!.x!) / Reflect.ownKeys(reduceGroup).length; + let partHeight = this.clientHeight - this.offset!.y!; + let gap = partHeight / 5; + let valGap = maxValue / 5; + for (let i = 0; i <= 5; i++) { + this.rowLines.push({ + y: gap * i, + label: `${maxValue - valGap * i} `, + }); + } + Reflect.ownKeys(reduceGroup) + .sort( + (b, a) => + (reduceGroup[a] as any[]).reduce((pre, cur) => pre + (cur[this.cfg!.yField] as number), 0) - + (reduceGroup[b] as any[]).reduce((pre, cur) => pre + (cur[this.cfg!.yField] as number), 0) + ) + .forEach((key, i) => { + let elements = reduceGroup[key]; + let initH = 0; + elements.forEach((it: any, y: number) => { + this.data.push({ + color: this.cfg!.color(it), + obj: it, + root: y == 0, + type: it[this.cfg!.seriesField], + xLabel: it[this.cfg!.xField], + yLabel: it[this.cfg!.yField], + bgFrame: { + x: this.offset!.x! + partWidth * i, + y: 0, + w: partWidth, + h: partHeight, + }, + centerX: this.offset!.x! + partWidth * i + partWidth / 2, + centerY: + partHeight - + initH - + (it[this.cfg!.yField] * partHeight) / maxValue + + (it[this.cfg!.yField] * partHeight) / maxValue / 2, + frame: { + x: this.offset!.x! + partWidth * i + partWidth / 6, + y: partHeight - (it[this.cfg!.yField] * partHeight) / maxValue - initH, + w: partWidth - partWidth / 3, + h: (it[this.cfg!.yField] * partHeight) / maxValue, + }, + height: 0, + heightStep: Math.ceil((it[this.cfg!.yField] * partHeight) / maxValue / 60), + process: true, + }); + initH += (it[this.cfg!.yField] * partHeight) / maxValue; + }); + }); + } + } + + get config(): LitChartColumnConfig | null | undefined { + return this.cfg; + } + + render(ease: boolean = true) { + if (!this.canvas || !this.cfg) return; + this.ctx!.clearRect(0, 0, this.clientWidth, this.clientHeight); + this.drawLine(this.ctx!); + this.data?.forEach((it) => this.drawColumn(this.ctx!, it, ease)); + if (ease) { + if (this.data.filter((it) => it.process).length > 0) { + requestAnimationFrame(() => this.render(ease)); + } + } + } + + drawLine(c: CanvasRenderingContext2D) { + c.strokeStyle = '#dfdfdf'; + c.lineWidth = 1; + c.beginPath(); + c.fillStyle = '#8c8c8c'; + this.rowLines.forEach((it, i) => { + c.moveTo(this.offset!.x!, it.y); + c.lineTo(this.clientWidth, it.y); + if (i == 0) { + c.fillText(it.label, this.offset!.x! - c.measureText(it.label).width - 2, it.y + 11); + } else { + c.fillText(it.label, this.offset!.x! - c.measureText(it.label).width - 2, it.y + 4); + } + }); + c.stroke(); + c.closePath(); + } + + drawColumn(c: CanvasRenderingContext2D, it: Pillar, ease: boolean) { + if (it.hover) { + c.globalAlpha = 0.2; + c.fillStyle = '#999999'; + c.fillRect(it.bgFrame!.x, it.bgFrame!.y, it.bgFrame!.w, it.bgFrame!.h); + c.globalAlpha = 1.0; + } + c.fillStyle = it.color || '#ff0000'; + if (ease) { + if (it.height! < it.frame!.h) { + it.process = true; + c.fillRect(it.frame!.x, it.frame!.y + (it.frame!.h - it.height!), it.frame!.w, it.height!); + it.height! += it.heightStep!; + } else { + c.fillRect(it.frame!.x, it.frame!.y, it.frame!.w, it.frame!.h); + it.process = false; + } + } else { + c.fillRect(it.frame!.x, it.frame!.y, it.frame!.w, it.frame!.h); + it.process = false; + } + + c.beginPath(); + c.strokeStyle = '#d8d8d8'; + c.moveTo(it.centerX!, it.frame!.y + it.frame!.h!); + if (it.root) { + c.lineTo(it.centerX!, it.frame!.y + it.frame!.h + 4); + } + let xMetrics = c.measureText(it.xLabel!); + let xMetricsH = xMetrics.actualBoundingBoxAscent + xMetrics.actualBoundingBoxDescent; + let yMetrics = c.measureText(it.yLabel!); + let yMetricsH = yMetrics.fontBoundingBoxAscent + yMetrics.fontBoundingBoxDescent; + c.fillStyle = '#8c8c8c'; + if (it.root) { + c.fillText(it.xLabel!, it.centerX! - xMetrics.width / 2, it.frame!.y + it.frame!.h + 15); + } + c.fillStyle = '#fff'; + if (this.cfg?.label) { + if (yMetricsH < it.frame!.h) { + c.fillText( + // @ts-ignore + this.cfg!.label!.content ? this.cfg!.label!.content(it.obj) : it.yLabel!, + it.centerX! - yMetrics.width / 2, + it.centerY! + (it.frame!.h - it.height!) / 2 + ); + } + } + c.stroke(); + c.closePath(); + } + + beginPath(stroke: boolean, fill: boolean) { + return (fn: (c: CanvasRenderingContext2D) => void) => { + this.ctx!.beginPath(); + fn?.(this.ctx!); + if (stroke) { + this.ctx!.stroke(); + } + if (fill) { + this.ctx!.fill(); + } + this.ctx!.closePath(); + }; + } + + showTip(x: number, y: number, msg: string) { + this.tipEL!.style.display = 'flex'; + this.tipEL!.style.top = `${y}px`; + this.tipEL!.style.left = `${x}px`; + this.tipEL!.innerHTML = msg; + } + + hideTip() { + this.tipEL!.style.display = 'none'; + } + + initHtml(): string { + return ` + +
+ +
+
`; + } +} + +function contains(rect: { x: number; y: number; w: number; h: number }, x: number, y: number): boolean { + return rect.x <= x && x <= rect.x + rect.w && rect.y <= y && y <= rect.y + rect.h; +} diff --git a/ide/src/base-ui/chart/column/LitChartColumnConfig.ts b/ide/src/base-ui/chart/column/LitChartColumnConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..b508e8278349182ee2f1a533a1d24374657c32fd --- /dev/null +++ b/ide/src/base-ui/chart/column/LitChartColumnConfig.ts @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 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. + */ + +export interface LitChartColumnConfig { + data: any[]; + appendPadding: number; + xField: string; + yField: string; + seriesField: string; + color: (a: any) => string; + tip: ((a: any) => string) | undefined; + hoverHandler?: (no: number) => void; + label: + | { + offset: number; + content: (it: any) => string; + } + | undefined + | null; +} diff --git a/ide/src/base-ui/chart/helper.ts b/ide/src/base-ui/chart/helper.ts new file mode 100644 index 0000000000000000000000000000000000000000..2fd7479c266a885e6597b333629322c2d0bb7308 --- /dev/null +++ b/ide/src/base-ui/chart/helper.ts @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 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. + */ + +export const resizeCanvas = (c: HTMLCanvasElement) => { + let el: Element = (c.getRootNode({ composed: false }) as ShadowRoot).host; + let dpr = window.devicePixelRatio || 1; + c.width = Math.ceil(el.clientWidth * dpr); + c.height = Math.ceil(el.clientHeight * dpr); + c.style.width = `${el.clientWidth}px`; + c.style.height = `${el.clientHeight}px`; + c.getContext('2d', { alpha: true })?.scale(dpr, dpr); +}; diff --git a/ide/src/base-ui/chart/pagenation/PageNation.ts b/ide/src/base-ui/chart/pagenation/PageNation.ts new file mode 100644 index 0000000000000000000000000000000000000000..6529ca14ed3b879fcc6dc0d38b2bffecc60b42c0 --- /dev/null +++ b/ide/src/base-ui/chart/pagenation/PageNation.ts @@ -0,0 +1,503 @@ +/* + * Copyright (C) 2022 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. + */ + +export class PageNation { + element: any; + pageInfo: any; + first: any; + prev: any; + next: any; + last: any; + inputBox: any; + btn: any; + list: any; + origin: HTMLElement | undefined; + static BtnBackColor = '#6C9BFA'; + static BtnColor = '#fff'; + constructor(selector: any, options = {}) { + selector!.innerHTML = ''; + //最大容器 + this.element = selector; + // 默认值 + this.pageInfo = { + current: 1, + total: 100, + pageSize: 15, + }; + //等待创建的元素 + this.first = null; + this.prev = null; + this.next = null; + this.last = null; + // 输入框 + this.inputBox = null; + // 跳转按钮 + this.btn = null; + // 中间的按钮组 + this.list = null; + this.setPageOptions(options); + this.setItemStyles(); + this.createPageElement(); + this.bindPageHtml(); + this.bindPageEvent(); + } + + setPageOptions(options: any) { + // 当前页 + this.pageInfo.current = options.current || 1; + // 一页显示多少条 + this.pageInfo.pageSize = options.pageSize || 15; + if (options.totalpage) { + //用户传递了多少页 + this.pageInfo.totalpage = options.totalpage; + } else { + //没有传递多少页 + if (options.total) { + // 如果传递了总条数 + this.pageInfo.totalpage = Math.ceil(options.total / this.pageInfo.pageSize); + } else { + // 如果没有传递总条数 + this.pageInfo.totalpage = 9; + } + } + this.pageInfo.first = options.first || '<<'; + this.pageInfo.change = options.change || function () {}; + } + + setElementStyles(ele: any, styles: any) { + for (let key in styles) { + ele.style[key] = styles[key]; + } + } + + setItemStyles() { + this.setElementStyles(this.element, { + margin: '18px auto', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }); + } + + // 创建元素 首页 上一页 按钮组 下一页 尾页 输入框 按钮 + createPageElement() { + //首页 + this.origin = document.createElement('p'); + this.setElementStyles(this.origin, { + 'border-radius': '4px', + padding: '5px', + border: '1px solid rgba(0,0,0,0.6)', + cursor: 'pointer', + margin: '0 5px', + }); + + this.first = this.origin.cloneNode(true); + this.first.innerText = this.pageInfo.first; + this.first.name = 'first'; + this.element.appendChild(this.first); + + this.prev = this.origin.cloneNode(true); + this.prev.innerText = '<'; + this.prev.name = 'prev'; + this.prev.style.padding = '5px 10px'; + this.element.appendChild(this.prev); + + // 创建ul + this.list = document.createElement('ul'); + this.setElementStyles(this.list, { + display: 'flex', + padding: '0', + }); + this.element.appendChild(this.list); + this.next = this.origin.cloneNode(true); + this.next.innerText = '>'; + this.next.name = 'next'; + this.next.style.padding = '5px 10px'; + this.next.style.margin = '0px 5px'; + this.element.appendChild(this.next); + this.last = this.origin.cloneNode(true); + this.last.innerText = '>>'; + this.last.name = 'last'; + this.last.style.padding = '5px'; + this.last.style.margin = '0px 5px'; + this.element.appendChild(this.last); + let jumpDiv = document.createElement('div'); + jumpDiv.style.display = 'flex'; + jumpDiv.style.border = '1px solid rgba(0,0,0,0.6)'; + jumpDiv.style.borderRadius = '4px'; + jumpDiv.style.width = '70px'; + jumpDiv.style.height = '32px'; + jumpDiv.style.marginLeft = '10px'; + + // 创建输入框 + this.inputBox = document.createElement('input'); + this.inputBox.value = this.pageInfo.current; + this.setElementStyles(this.inputBox, { + width: '35px', + height: '30px', + textAlign: 'center', + outline: 'none', + padding: '0', + border: '0', + 'border-radius': '5px', + }); + jumpDiv.appendChild(this.inputBox); + let span = document.createElement('span'); + span.style.width = '1px'; + span.style.height = '24px'; + span.style.alignSelf = 'center'; + span.style.backgroundColor = '#999999'; + jumpDiv.appendChild(span); + // 创建按钮 + this.btn = document.createElement('button'); + this.btn.innerText = ''; + this.btn.name = 'goto'; + this.setElementStyles(this.btn, { + height: '32px', + width: '30px', + cursor: 'pointer', + backgroundColor: '#FFF', + border: '0', + 'border-radius': '5px', + }); + this.btn.style.background = `url('img/arrowright.png') no-repeat 98% center var(--dark-background3,#FFFFFF)`; + this.btn.style.backgroundPosition = 'center'; + jumpDiv.appendChild(this.btn); + this.element.appendChild(jumpDiv); + } + + // 判断首页 上一页 下一页 尾页 是否可以点击 + bindPageHtml() { + const { current, totalpage } = this.pageInfo; + const disable = { color: '#999999', cursor: 'not-allowed' }; + const enable = { + color: '#000', + cursor: 'pointer', + }; + // 判断当前页是否是第一页 如果是第一页 那么首页和上一页就不能点击 + if (current <= 1) { + this.setElementStyles(this.first, disable); + this.setElementStyles(this.prev, disable); + } else { + this.setElementStyles(this.first, enable); + this.setElementStyles(this.prev, enable); + } + // 判断当前页是否是最后一页 如果是最后一页 那么下一页和尾页就不能点击 + if (current >= totalpage) { + this.setElementStyles(this.next, disable); + this.setElementStyles(this.last, disable); + } else { + this.setElementStyles(this.next, enable); + this.setElementStyles(this.last, enable); + } + this.inputBox.value = current; + //渲染的时候判断ul列表的显示情况 + this.bindPageList(); + this.pageInfo.change(this.pageInfo.current); + } + + bindPageList() { + // clear ul里面的内容 + this.list.innerHTML = ''; + //每次加载之前先清空ul里面的内容 + const { pageSize, current, totalpage } = this.pageInfo; + const origin = document.createElement('li'); + origin.dataset.name = 'item'; + this.setElementStyles(origin, { + listStyle: 'none', + 'border-radius': '4px', + border: '1px solid rgba(0,0,0,0.6)', + padding: '5px 10px', + margin: '0 5px', + cursor: 'pointer', + }); + if (totalpage <= 9) { + for (let i = 0; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + return; + } + // 左边5个 中间 ... 右边2个 + if (this.bindLeftList(current, totalpage, origin)) { + return; + } + // 当前页面 大于5页 小于倒数第5页 + for (let i = 0; i < 2; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + for (let i = current - 3; i < current + 2; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + for (let i = totalpage - 2; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + } + + bindLeftList(current: number, totalpage: number, origin: HTMLElement): boolean { + if (current < 5) { + // 左边5个 中间 ... 右边2个 + for (let i = 0; i < 5; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + for (let i = totalpage - 2; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + return true; + } + if (current == 5) { + // 左边5个 中间 ... 右边2个 + for (let i = 0; i < 7; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + + for (let i = totalpage - 2; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + return true; + } + // 当前页面 大于倒数第5页 + if (current > totalpage - 4) { + // 左边5个 中间 ... 右边2个 + for (let i = 0; i < 2; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + for (let i = totalpage - 5; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + return true; + } + if (current == totalpage - 4) { + // 左边5个 中间 ... 右边2个 + for (let i = 0; i < 2; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + for (let i = totalpage - 7; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + return true; + } + if (current == totalpage - 4) { + // 左边5个 中间 ... 右边2个 + for (let i = 0; i < 2; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + var span = document.createElement('span'); + span.innerText = '...'; + this.list.appendChild(span); + for (let i = totalpage - 7; i < totalpage; i++) { + const li = origin.cloneNode(true); + // @ts-ignore + li.innerText = i + 1; + if (i + 1 === current) { + this.setElementStyles(li, { + backgroundColor: PageNation.BtnBackColor, + color: PageNation.BtnColor, + }); + } + this.list.appendChild(li); + } + return true; + } + return false; + } + + bindPageEvent() { + this.element.addEventListener( + 'click', + (event: { + target: { + name: string; + dataset: { name: string }; + innerText: number; + }; + }) => { + if (event.target.name === 'first') { + if (this.pageInfo.current === 1) return; + this.pageInfo.current = 1; + this.bindPageHtml(); + } + if (event.target.name === 'prev') { + if (this.pageInfo.current === 1) return; + this.pageInfo.current--; + this.bindPageHtml(); + } + if (event.target.name === 'next') { + if (this.pageInfo.current === this.pageInfo.totalpage) return; + this.pageInfo.current++; + this.bindPageHtml(); + } + if (event.target.name === 'last') { + if (this.pageInfo.current === this.pageInfo.totalpage) return; + this.pageInfo.current = this.pageInfo.totalpage; + this.bindPageHtml(); + } + if (event.target.name === 'goto') { + // 拿到你文本的内容 + let page = this.inputBox.value - 0; + if (isNaN(page)) { + page = 1; + } + if (page <= 1) { + page = 1; + } + if (page >= this.pageInfo.totalpage) { + page = this.pageInfo.totalpage; + } + this.pageInfo.current = page; + this.bindPageHtml(); + } + if (event.target.dataset.name === 'item') { + this.pageInfo.current = event.target.innerText - 0; + this.bindPageHtml(); + } + } + ); + } +} diff --git a/ide/src/base-ui/chart/pagenation/pagination-box.ts b/ide/src/base-ui/chart/pagenation/pagination-box.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf57bd6b9e0c2bedaafebbdb2811550c193bec8a --- /dev/null +++ b/ide/src/base-ui/chart/pagenation/pagination-box.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../BaseElement.js'; + +@element('pagination-box') +export class PaginationBox extends BaseElement { + private page: any; + + static get observedAttributes() { + return ['text', 'height', 'width']; + } + + get text() { + return this.getAttribute('text') || ''; + } + + set text(text: string) { + this.setAttribute('text', text); + } + + get height() { + return this.getAttribute('height') || ''; + } + + set height(height: string) { + this.setAttribute('height', height); + } + + initHtml(): string { + return ` + + + `; + } + + initElements(): void { + this.page = this.shadowRoot?.querySelector('#box'); + } + + attributeChangedCallback(name: string, oldValue: string, value: string) { + switch (name) { + } + } +} diff --git a/ide/src/base-ui/chart/pie/LitChartPie.ts b/ide/src/base-ui/chart/pie/LitChartPie.ts new file mode 100644 index 0000000000000000000000000000000000000000..360106d1a9d96c99c04f8670fc48ff7bdd155984 --- /dev/null +++ b/ide/src/base-ui/chart/pie/LitChartPie.ts @@ -0,0 +1,543 @@ +/* + * Copyright (C) 2022 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 { resizeCanvas } from '../helper.js'; +import { BaseElement, element } from '../../BaseElement.js'; +import { LitChartPieConfig } from './LitChartPieConfig.js'; +import { isPointIsCircle, pieChartColors, randomRgbColor } from './LitChartPieData.js'; +import { Utils } from '../../../trace/component/trace/base/Utils.js'; + +interface Rectangle { + x: number; + y: number; + w: number; + h: number; +} + +class Sector { + id?: any; + obj?: any; + key: any; + value: any; + startAngle?: number; + endAngle?: number; + startDegree?: number; + endDegree?: number; + color?: string; + percent?: number; + hover?: boolean; + ease?: { + initVal?: number; + step?: number; + process?: boolean; + }; +} + +@element('lit-chart-pie') +export class LitChartPie extends BaseElement { + private eleShape: Element | null | undefined; + private tipEL: HTMLDivElement | null | undefined; + private labelsEL: HTMLDivElement | null | undefined; + canvas: HTMLCanvasElement | undefined | null; + ctx: CanvasRenderingContext2D | undefined | null; + cfg: LitChartPieConfig | null | undefined; + centerX: number | null | undefined; + centerY: number | null | undefined; + data: Sector[] = []; + radius: number | undefined; + private textRects: Rectangle[] = []; + + set config(cfg: LitChartPieConfig | null | undefined) { + if (!cfg) return; + this.cfg = cfg; + (this.shadowRoot!.querySelector('#root') as HTMLDivElement).className = + cfg && cfg.data.length > 0 ? 'bg_hasdata' : 'bg_nodata'; + this.measure(); + this.render(); + } + + set dataSource(arr: any[]) { + if (this.cfg) { + this.cfg.data = arr; + this.measure(); + this.render(); + } + } + + showHover() { + let hasHover = false; + this.data.forEach((it) => { + it.hover = it.obj.isHover; + if (it.hover) { + hasHover = true; + } + this.updateHoverItemStatus(it); + if (it.hover) { + this.showTip( + this.centerX || 0, + this.centerY || 0, + this.cfg!.tip ? this.cfg!.tip(it) : `${it.key}: ${it.value}` + ); + } + }); + if (!hasHover) { + this.hideTip(); + } + this.render(); + } + + measure() { + if (!this.cfg) return; + this.data = []; + this.radius = (Math.min(this.clientHeight, this.clientWidth) * 0.65) / 2 - 10; + let cfg = this.cfg!; + let startAngle = 0; + let startDegree = 0; + let full = Math.PI / 180; //每度 + let fullDegree = 0; //每度 + let sum = this.cfg.data.reduce((previousValue, currentValue) => currentValue[cfg.angleField] + previousValue, 0); + this.labelsEL!.textContent = ''; + let labelArray: string[] = []; + this.cfg.data.forEach((it, index) => { + let item: Sector = { + id: `id-${Utils.uuid()}`, + color: this.cfg!.label.color ? this.cfg!.label.color(it) : pieChartColors[index % pieChartColors.length], + obj: it, + key: it[cfg.colorField], + value: it[cfg.angleField], + startAngle: startAngle, + endAngle: startAngle + full * ((it[cfg.angleField] / sum) * 360), + startDegree: startDegree, + endDegree: startDegree + fullDegree + (it[cfg.angleField] / sum) * 360, + ease: { + initVal: 0, + step: (startAngle + full * ((it[cfg.angleField] / sum) * 360)) / startDegree, + process: true, + }, + }; + this.data.push(item); + startAngle += full * ((it[cfg.angleField] / sum) * 360); + startDegree += fullDegree + (it[cfg.angleField] / sum) * 360; + labelArray.push(``); + }); + this.labelsEL!.innerHTML = labelArray.join(''); + } + + get config(): LitChartPieConfig | null | undefined { + return this.cfg; + } + + connectedCallback() { + super.connectedCallback(); + this.eleShape = this.shadowRoot!.querySelector('#shape'); + this.tipEL = this.shadowRoot!.querySelector('#tip'); + this.labelsEL = this.shadowRoot!.querySelector('#labels'); + this.canvas = this.shadowRoot!.querySelector('#canvas'); + this.ctx = this.canvas!.getContext('2d', { alpha: true }); + resizeCanvas(this.canvas!); + this.radius = (Math.min(this.clientHeight, this.clientWidth) * 0.65) / 2 - 10; + this.centerX = this.clientWidth / 2; + this.centerY = this.clientHeight / 2 - 40; + this.ctx?.translate(this.centerX, this.centerY); + this.canvas!.onmouseout = (e) => { + this.hideTip(); + this.data.forEach((it) => { + it.hover = false; + this.updateHoverItemStatus(it); + }); + this.render(); + }; + //增加点击事件 + this.canvas!.onclick = (ev) => { + let rect = this.getBoundingClientRect(); + let x = ev.pageX - rect.left - this.centerX!; + let y = ev.pageY - rect.top - this.centerY!; + if (isPointIsCircle(0, 0, x, y, this.radius!)) { + let degree = this.computeDegree(x, y); + this.data.forEach((it) => { + if (degree >= it.startDegree! && degree <= it.endDegree!) { + this.config?.angleClick?.(it.obj); + } + }); + } + }; + this.canvas!.onmousemove = (ev) => { + let rect = this.getBoundingClientRect(); + let x = ev.pageX - rect.left - this.centerX!; + let y = ev.pageY - rect.top - this.centerY!; + if (isPointIsCircle(0, 0, x, y, this.radius!)) { + let degree = this.computeDegree(x, y); + this.data.forEach((it) => { + it.hover = degree >= it.startDegree! && degree <= it.endDegree!; + this.updateHoverItemStatus(it); + it.obj.isHover = it.hover; + if (it.hover && this.cfg) { + this.cfg.hoverHandler?.(it.obj); + this.showTip( + ev.pageX - rect.left + 10, + ev.pageY - this.offsetTop - 10, + this.cfg.tip ? this.cfg!.tip(it) : `${it.key}: ${it.value}` + ); + } + }); + } else { + this.hideTip(); + this.data.forEach((it) => { + it.hover = false; + it.obj.isHover = false; + this.updateHoverItemStatus(it); + }); + this.cfg?.hoverHandler?.(undefined); + } + this.render(); + }; + this.render(); + } + + updateHoverItemStatus(item: any) { + let label = this.shadowRoot!.querySelector(`#${item.id}`); + if (label) { + (label as HTMLLabelElement).style.boxShadow = item.hover ? '0 0 5px #22ffffff' : ''; + } + } + + computeDegree(x: number, y: number) { + let degree = (360 * Math.atan(y / x)) / (2 * Math.PI); + if (x >= 0 && y >= 0) { + degree = degree; + } else if (x < 0 && y >= 0) { + degree = 180 + degree; + } else if (x < 0 && y < 0) { + degree = 180 + degree; + } else { + degree = 270 + (90 + degree); + } + return degree; + } + + initElements(): void { + new ResizeObserver((entries, observer) => { + entries.forEach((it) => { + resizeCanvas(this.canvas!); + this.centerX = this.clientWidth / 2; + this.centerY = this.clientHeight / 2 - 40; + this.ctx?.translate(this.centerX, this.centerY); + this.measure(); + this.render(); + }); + }).observe(this); + } + + render(ease: boolean = true) { + if (!this.canvas || !this.cfg) return; + if (this.radius! <= 0) return; + this.ctx?.clearRect(0 - this.centerX!, 0 - this.centerY!, this.clientWidth, this.clientHeight); + this.data.forEach((it) => { + this.ctx!.beginPath(); + this.ctx!.fillStyle = it.color as string; + this.ctx!.strokeStyle = this.data.length > 1 ? '#fff' : (it.color as string); + this.ctx?.moveTo(0, 0); + if (it.hover) { + this.ctx!.lineWidth = 1; + this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false); + } else { + this.ctx!.lineWidth = 1; + if (ease) { + if (it.ease!.initVal! < it.endAngle! - it.startAngle!) { + it.ease!.process = true; + this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.startAngle! + it.ease!.initVal!, false); + it.ease!.initVal! += it.ease!.step!; + } else { + it.ease!.process = false; + this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false); + } + } else { + this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false); + } + } + this.ctx?.lineTo(0, 0); + this.ctx?.fill(); + this.ctx!.stroke(); + this.ctx?.closePath(); + }); + + this.data + .filter((it) => it.hover) + .forEach((it) => { + this.ctx!.beginPath(); + this.ctx!.fillStyle = it.color as string; + this.ctx!.lineWidth = 1; + this.ctx?.moveTo(0, 0); + this.ctx!.arc(0, 0, this.radius!, it.startAngle!, it.endAngle!, false); + this.ctx?.lineTo(0, 0); + this.ctx!.strokeStyle = this.data.length > 1 ? '#000' : (it.color as string); + this.ctx!.stroke(); + this.ctx?.closePath(); + }); + + this.textRects = []; + if (this.cfg.showChartLine) { + this.data.forEach((it) => { + let text = `${it.value}`; + let metrics = this.ctx!.measureText(text); + let textWidth = metrics.width; + let textHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent; + this.ctx!.beginPath(); + this.ctx!.strokeStyle = it.color!; + this.ctx!.fillStyle = '#595959'; + let deg = it.startDegree! + (it.endDegree! - it.startDegree!) / 2; + let dep = 25; + let x1 = 0 + this.radius! * Math.cos((deg * Math.PI) / 180); + let y1 = 0 + this.radius! * Math.sin((deg * Math.PI) / 180); + let x2 = 0 + (this.radius! + 13) * Math.cos((deg * Math.PI) / 180); + let y2 = 0 + (this.radius! + 13) * Math.sin((deg * Math.PI) / 180); + let x3 = 0 + (this.radius! + dep) * Math.cos((deg * Math.PI) / 180); + let y3 = 0 + (this.radius! + dep) * Math.sin((deg * Math.PI) / 180); + this.ctx!.moveTo(x1, y1); + this.ctx!.lineTo(x2, y2); + this.ctx!.stroke(); + let rect = this.correctRect({ + x: x3 - textWidth / 2, + y: y3 + textHeight / 2, + w: textWidth, + h: textHeight, + }); + this.ctx?.fillText(text, rect.x, rect.y); + this.ctx?.closePath(); + }); + } + if (this.data.filter((it) => it.ease!.process).length > 0) { + requestAnimationFrame(() => this.render(ease)); + } + } + + correctRect(rect: Rectangle): Rectangle { + if (this.textRects.length == 0) { + this.textRects.push(rect); + return rect; + } else { + let rectangles = this.textRects.filter((it) => this.intersect(it, rect).cross); + if (rectangles.length == 0) { + this.textRects.push(rect); + return rect; + } else { + let it = rectangles[0]; + let inter = this.intersect(it, rect); + if (inter.direction == 'Right') { + rect.x += inter.crossW; + } else if (inter.direction == 'Bottom') { + rect.y += inter.crossH; + } else if (inter.direction == 'Left') { + rect.x -= inter.crossW; + } else if (inter.direction == 'Top') { + rect.y -= inter.crossH; + } else if (inter.direction == 'Right-Top') { + rect.y -= inter.crossH; + } else if (inter.direction == 'Right-Bottom') { + rect.y += inter.crossH; + } else if (inter.direction == 'Left-Top') { + rect.y -= inter.crossH; + } else if (inter.direction == 'Left-Bottom') { + rect.y += inter.crossH; + } + this.textRects.push(rect); + return rect; + } + } + } + + intersect( + r1: Rectangle, + rect: Rectangle + ): { + cross: boolean; + direction: string; + crossW: number; + crossH: number; + } { + let cross: boolean; + let direction: string; + let crossW: number; + let crossH: number; + let maxX = r1.x + r1.w > rect.x + rect.w ? r1.x + r1.w : rect.x + rect.w; + let maxY = r1.y + r1.h > rect.y + rect.h ? r1.y + r1.h : rect.y + rect.h; + let minX = r1.x < rect.x ? r1.x : rect.x; + let minY = r1.y < rect.y ? r1.y : rect.y; + if (maxX - minX < rect.w + r1.w && maxY - minY < r1.h + rect.h) { + cross = true; + } else { + cross = false; + } + crossW = Math.abs(maxX - minX - (rect.w + r1.w)); + crossH = Math.abs(maxY - minY - (rect.y + r1.y)); + if (rect.x > r1.x) { + //right + if (rect.y > r1.y) { + //bottom + direction = 'Right-Bottom'; + } else if (rect.y == r1.y) { + //middle + direction = 'Right'; + } else { + //top + direction = 'Right-Top'; + } + } else if (rect.x < r1.x) { + //left + if (rect.y > r1.y) { + //bottom + direction = 'Left-Bottom'; + } else if (rect.y == r1.y) { + //middle + direction = 'Left'; + } else { + //top + direction = 'Left-Top'; + } + } else { + if (rect.y > r1.y) { + //bottom + direction = 'Bottom'; + } else if (rect.y == r1.y) { + //middle + direction = 'Right'; //superposition default right + } else { + //top + direction = 'Top'; + } + } + return { + cross, + direction, + crossW, + crossH, + }; + } + + showTip(x: number, y: number, msg: string) { + this.tipEL!.style.display = 'flex'; + this.tipEL!.style.top = `${y}px`; + this.tipEL!.style.left = `${x}px`; + this.tipEL!.innerHTML = msg; + } + + hideTip() { + this.tipEL!.style.display = 'none'; + } + + initHtml(): string { + return ` + +
+
+ +
+
+
`; + } +} diff --git a/ide/src/base-ui/chart/pie/LitChartPieConfig.ts b/ide/src/base-ui/chart/pie/LitChartPieConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..50846a86dc5adee92b0d2de6d6fda115476b36ed --- /dev/null +++ b/ide/src/base-ui/chart/pie/LitChartPieConfig.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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. + */ + +export interface LitChartPieConfig { + appendPadding: number; + data: any[]; + angleField: string; + colorField: string; + radius: number; + angleClick?: (it: object) => void; + label: { + type: string; // spider|inner|outer + offset?: string; + content?: (it: object) => string; + color?: (it: object) => string; + style?: { + fontSize: number; + textAlign: string; + }; + }; + hoverHandler?: (data: any) => void; + showChartLine?: boolean; + tip: ((a: any) => string) | undefined; + interactions: { + type: string; //element-active | element-selected + }[]; +} diff --git a/ide/src/base-ui/chart/pie/LitChartPieData.ts b/ide/src/base-ui/chart/pie/LitChartPieData.ts new file mode 100644 index 0000000000000000000000000000000000000000..af3a4b8e17d02ba0c290837313c05f3aca834c25 --- /dev/null +++ b/ide/src/base-ui/chart/pie/LitChartPieData.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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. + */ + +export function randomRgbColor() { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +} + +export function isPointIsCircle(x1: number, y1: number, x2: number, y2: number, radius: number): boolean { + return Math.sqrt(Math.pow(Math.abs(x2 - x1), 2) + Math.pow(Math.abs(y2 - y1), 2)) < radius; +} + +export const pieChartColors = [ + '#5b8ff9', + '#5ad8a6', + '#5d7092', + '#f6bd16', + '#e8684a', + '#6DC8EC', + '#9270CA', + '#FF9D4D', + '#269A99', + '#FF99C3', + '#0039AC', + '#229D00', + '#AEAEAE', + '#FFEE00', + '#FF3000', + '#CBE1FF', + '#6000FF', + '#A24900', + '#70FFFE', + '#FF00C4', +]; diff --git a/ide/src/base-ui/checkbox/LitCheckBox.ts b/ide/src/base-ui/checkbox/LitCheckBox.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b51cbac91ad00af3aa42b2f85ac532b7fd0b00a --- /dev/null +++ b/ide/src/base-ui/checkbox/LitCheckBox.ts @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-check-box') +export class LitCheckBox extends BaseElement { + private checkbox: HTMLInputElement | undefined; + + static get observedAttributes() { + return ['checked', 'value']; + } + + get indeterminate() { + return this.checkbox!.indeterminate; + } + + set indeterminate(value) { + if (value === null || value === false) { + this.checkbox!.indeterminate = false; + } else { + this.checkbox!.indeterminate = true; + } + } + + get checked() { + return this.getAttribute('checked') !== null; + } + + set checked(value: boolean) { + if (value === null || !value) { + this.removeAttribute('checked'); + } else { + this.setAttribute('checked', ''); + } + } + + get value() { + return this.getAttribute('value') || ''; + } + + set value(value: string) { + this.setAttribute('value', value); + } + + initHtml(): string { + return ` + + + + `; + } + + initElements(): void { + this.checkbox = this.shadowRoot?.getElementById('checkbox') as HTMLInputElement; + } + + connectedCallback() { + this.checkbox!.addEventListener('change', (ev) => { + this.checked = this.checkbox!.checked; + this.dispatchEvent( + new CustomEvent('change', { + detail: { + checked: this.checked, + }, + }) + ); + }); + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name == 'checked' && this.checkbox) { + this.checkbox.checked = newValue !== null; + } + if (name == 'value') { + let slot = this.shadowRoot?.getElementById('slot'); + slot!.textContent = newValue; + } + } +} diff --git a/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts b/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts new file mode 100644 index 0000000000000000000000000000000000000000..cba91f29b9d76efee9bbc9297e0074c4e6fc2f61 --- /dev/null +++ b/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { SpCheckDesBox } from '../../trace/component/setting/SpCheckDesBox.js'; + +@element('lit-check-text') +export class LitCheckBoxWithText extends BaseElement { + private _checkBox: SpCheckDesBox | undefined; + private _lowerLimit: HTMLInputElement | undefined; + private _upLimit: HTMLInputElement | undefined; + + static get observedAttributes() { + return ['text', 'lowerLimit', 'upLimit', 'checked']; + } + + get text(): string { + return this.getAttribute('text') || ''; + } + + set text(text: string) { + this.setAttribute('text', text); + } + + get lowerLimit(): string { + return this.getAttribute('lowerLimit') || '0'; + } + + set lowerLimit(lower: string) { + this.setAttribute('lowerLimit', lower); + } + + get upLimit(): string { + return this.getAttribute('upLimit') || '∞'; + } + + set upLimit(upLimit: string) { + this.setAttribute('upLimit', upLimit); + } + + get checked() { + return this.getAttribute('checked') != null; + } + + set checked(checked: boolean) { + if (checked) { + this.setAttribute('checked', ''); + } else { + this.removeAttribute('checked'); + } + } + + initElements(): void { + this._checkBox = this.shadowRoot?.getElementById('checkbox') as SpCheckDesBox; + this._lowerLimit = this.shadowRoot?.getElementById('textLowerLimit') as HTMLInputElement; + this._upLimit = this.shadowRoot?.getElementById('_upLimit') as HTMLInputElement; + } + + initHtml(): string { + return ` + + + + + `; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name == 'checked') { + this._checkBox!.checked = newValue !== null; + } + if (name == 'text') { + this._checkBox?.setAttribute('value', newValue); + } + if (name == 'lowerLimit') { + this._lowerLimit!.textContent = newValue; + } + if (name == 'upLimit') { + this._upLimit!.textContent = newValue; + } + } +} diff --git a/ide/src/base-ui/checkbox/LitCheckGroup.ts b/ide/src/base-ui/checkbox/LitCheckGroup.ts new file mode 100644 index 0000000000000000000000000000000000000000..1cb09f244607567a5ce4ac18aa0078db5f9bd6c8 --- /dev/null +++ b/ide/src/base-ui/checkbox/LitCheckGroup.ts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { LitCheckBox } from './LitCheckBox.js'; + +@element('lit-check-group') +export class LitCheckGroup extends BaseElement { + get direction() { + return this.getAttribute('direction'); + } + + get value(): Array { + let values = []; + for (const litCheckBoxElement of this.querySelectorAll('lit-check-box[checked]')) { + values.push(litCheckBoxElement.value); + } + return values; + } + + initElements(): void {} + + initHtml(): string { + return ` + + `; + } +} diff --git a/ide/src/base-ui/drawer/LitDrawer.ts b/ide/src/base-ui/drawer/LitDrawer.ts new file mode 100644 index 0000000000000000000000000000000000000000..6bd2efce48959a7bedeff37a339d90c686225a8d --- /dev/null +++ b/ide/src/base-ui/drawer/LitDrawer.ts @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-drawer') +export class LitDrawer extends BaseElement { + static get observedAttributes() { + return ['title', 'visible', 'placement', 'mask', 'mask-closable', 'closeable', 'content-padding', 'content-width']; + } + + initHtml(): string { + return ` + +
+
+
+ + +
+
+ +
+
+ `; + } + get contentWidth() { + return this.getAttribute('content-width') || '400px'; + } + set contentWidth(value) { + this.shadowRoot!.querySelector('.drawer')!.style.width = value; + this.setAttribute('content-width', value); + } + get contentPadding() { + return this.getAttribute('content-padding') || '20px'; + } + set contentPadding(value) { + this.shadowRoot!.querySelector('slot')!.style.padding = value; + this.setAttribute('content-padding', value); + } + get placement() { + return this.getAttribute('placement'); + } + set placement(value: any) { + this.setAttribute('placement', value); + } + get title() { + return this.getAttribute('title') || ''; + } + set title(value) { + this.shadowRoot!.querySelector('#drawer-tittle-text')!.textContent = value; + this.setAttribute('title', value); + } + get visible() { + return this.getAttribute('visible') !== null; + } + set visible(value: any) { + if (value) { + this.setAttribute('visible', value); + } else { + this.removeAttribute('visible'); + } + } + get mask() { + return this.getAttribute('mask') !== null; + } + set mask(value) { + if (value) { + this.setAttribute('mask', ''); + } else { + this.removeAttribute('mask'); + } + } + get maskCloseable() { + return this.getAttribute('mask-closeable') !== null; + } + set maskCloseable(value) { + if (value) { + this.setAttribute('mask-closeable', ''); + } else { + this.removeAttribute('mask-closeable'); + } + } + get closeable() { + return this.getAttribute('closeable') !== null; + } + + set closeable(value) { + if (value) { + this.setAttribute('closeable', ''); + } else { + this.removeAttribute('closeable'); + } + } + + //当 custom element首次被插入文档DOM时,被调用。 + initElements(): void { + let bg: HTMLDivElement | null = this.shadowRoot!.querySelector('.bg'); + if (this.maskCloseable) { + bg!.onclick = (e: any) => { + e.stopPropagation(); + this.visible = false; + this.dispatchEvent(new CustomEvent('onClose', e)); + }; + } + if (this.closeable) { + (this.shadowRoot!.querySelector('.close-icon') as any).onclick = (e: any) => { + this.visible = false; + this.dispatchEvent(new CustomEvent('onClose', e)); + }; + } + } + set onClose(fn: any) { + this.addEventListener('onClose', fn); + } + //当 custom element从文档DOM中删除时,被调用。 + disconnectedCallback() {} + + //当 custom element被移动到新的文档时,被调用。 + adoptedCallback() { + console.log('Custom square element moved to new page.'); + } + + //当 custom element增加、删除、修改自身属性时,被调用。 + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (this.mask) { + if (name === 'visible') { + if (newValue !== null) { + this.style.pointerEvents = 'all'; + } else { + this.style.pointerEvents = 'none'; + } + } else if (name === 'placement') { + if (newValue === 'bottom') { + let el = this.shadowRoot!.querySelector('.drawer'); + } + } + } + } +} + +if (!customElements.get('lit-drawer')) { + customElements.define('lit-drawer', LitDrawer); +} diff --git a/ide/src/base-ui/icon.svg b/ide/src/base-ui/icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..87156b88af11e43482ea4d5930bb9251d1027bce --- /dev/null +++ b/ide/src/base-ui/icon.svg @@ -0,0 +1,321 @@ + diff --git a/ide/src/base-ui/icon/LitIcon.ts b/ide/src/base-ui/icon/LitIcon.ts new file mode 100644 index 0000000000000000000000000000000000000000..c93b26f8ac6b85474282f571ba11681686ea2a8b --- /dev/null +++ b/ide/src/base-ui/icon/LitIcon.ts @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-icon') +export class LitIcon extends BaseElement { + private view?: number; + private icon: HTMLElement | undefined | null; + private use: SVGUseElement | undefined | null; + private d: SVGPathElement | undefined | null; + private _name?: string; + private _size?: number; + private _color?: string; + private _path?: string; + + static get observedAttributes() { + return ['name', 'size', 'color', 'path']; + } + + get name(): string { + return this.getAttribute('name') || ''; + } + + set name(value: string) { + this._name = value; + this.setAttribute('name', value); + } + + get size(): number { + return parseInt(this.getAttribute('size') || '0', 10); + } + + set size(value: number) { + this._size = value; + this.setAttribute('size', `${value}`); + } + + set color(value: string) { + this._color = value; + this.setAttribute('color', value); + } + + set path(value: string) { + this._path = value; + this.setAttribute('path', value); + } + + initHtml(): string { + return ` + + + `; + } + + initElements() { + if (this.shadowRoot) { + this.icon = this.shadowRoot.getElementById('icon'); + this.use = this.shadowRoot.querySelector('use'); + this.d = this.shadowRoot.querySelector('path'); + } + } + + attributeChangedCallback(name: string, oldValue: string, value: string) { + switch (name) { + case 'name': + if (this.use) + this.use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', `./base-ui/icon.svg#icon-${value}`); + break; + case 'path': + if (this.d) this.d.setAttribute('d', value); + break; + case 'color': + if (this.icon) this.icon.style.color = value as string; + break; + case 'size': + if (this.icon) this.icon.style.fontSize = `${value}px`; + break; + } + } +} diff --git a/ide/src/base-ui/menu/LitMainMenu.ts b/ide/src/base-ui/menu/LitMainMenu.ts new file mode 100644 index 0000000000000000000000000000000000000000..e92b74a9bc060a2be1ba2f852abb53aee3328742 --- /dev/null +++ b/ide/src/base-ui/menu/LitMainMenu.ts @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import './LitMainMenuItem.js'; +import './LitMainMenuGroup.js'; +import { LitMainMenuGroup } from './LitMainMenuGroup.js'; +import { LitMainMenuItem } from './LitMainMenuItem.js'; +let backgroundColor = sessionStorage.getItem('backgroundColor'); + +@element('lit-main-menu') +export class LitMainMenu extends BaseElement { + private slotElements: Element[] | undefined; + private _menus: Array | undefined; + + static get observedAttributes() { + return []; + } + + get menus(): Array | undefined { + return this._menus; + } + + set menus(value: Array | undefined) { + this._menus = value; + this.shadowRoot?.querySelectorAll('lit-main-menu-group').forEach((a) => a.remove()); + let menuBody = this.shadowRoot?.querySelector('.menu-body'); + value?.forEach((it) => { + let group = new LitMainMenuGroup(); + group.setAttribute('title', it.title || ''); + group.setAttribute('describe', it.describe || ''); + if (it.collapsed) { + group.setAttribute('collapsed', ''); + } else { + group.removeAttribute('collapsed'); + } + menuBody?.appendChild(group); + it.children?.forEach((item: any) => { + let th = new LitMainMenuItem(); + th.setAttribute('icon', item.icon || ''); + th.setAttribute('title', item.title || ''); + if (item.fileChoose) { + th.setAttribute('file', ''); + th.addEventListener('file-change', (e) => { + if (item.fileHandler && !th.disabled) { + item.fileHandler(e); + } + }); + } else { + th.removeAttribute('file'); + th.addEventListener('click', (e) => { + if (item.clickHandler && !th.disabled) { + item.clickHandler(item); + } + }); + } + if (item.disabled != undefined) { + th.disabled = item.disabled; + } + group?.appendChild(th); + }); + }); + } + + initElements(): void { + let st: HTMLSlotElement | null | undefined = this.shadowRoot?.querySelector('#st'); + st?.addEventListener('slotchange', (e) => { + this.slotElements = st?.assignedElements(); + this.slotElements?.forEach((it) => { + it.querySelectorAll('lit-main-menu-item').forEach((cell) => {}); + }); + }); + let versionDiv: HTMLElement | null | undefined = this.shadowRoot?.querySelector('.version'); + versionDiv!.innerText = (window as any).version || ''; + } + + initHtml(): string { + return ` + +
+ + +
+ +
+
+ +
+
+
+
`; + } +} + +export interface MenuGroup { + title: string; + describe: string; + collapsed: boolean; + children: Array; +} + +export interface MenuItem { + icon: string; + title: string; + fileChoose?: boolean; + clickHandler?: Function; + fileHandler?: Function; +} diff --git a/ide/src/base-ui/menu/LitMainMenuGroup.ts b/ide/src/base-ui/menu/LitMainMenuGroup.ts new file mode 100644 index 0000000000000000000000000000000000000000..9730ecad6099a48ade211484e49639b95c545434 --- /dev/null +++ b/ide/src/base-ui/menu/LitMainMenuGroup.ts @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +let textColor = ''; + +@element('lit-main-menu-group') +export class LitMainMenuGroup extends BaseElement { + protected _collapsed: boolean | undefined; + private groupNameEl: HTMLElement | null | undefined; + private groupDescEl: HTMLElement | null | undefined; + private group: HTMLElement | null | undefined; + + static get observedAttributes() { + return ['title', 'describe', 'collapsed', 'nocollapse', 'radius']; + } + + get collapsed(): boolean { + return this.hasAttribute('collapsed'); + } + + set collapsed(value: boolean) { + if (value) { + this.setAttribute('collapsed', ''); + } else { + this.removeAttribute('collapsed'); + } + } + + get nocollapsed() { + return this.hasAttribute('nocollapsed'); + } + + set nocollapsed(value: boolean) { + if (value) { + this.setAttribute('nocollapsed', ''); + } else { + this.removeAttribute('nocollapsed'); + } + } + + get radius() { + return this.hasAttribute('radius'); + } + + initElements(): void { + this.groupNameEl = this.shadowRoot?.querySelector('.group-name'); + this.groupDescEl = this.shadowRoot?.querySelector('.group-describe'); + this.group = this.shadowRoot?.querySelector('#group'); + this.group!.addEventListener('click', (e) => { + if (this.nocollapsed) { + return; + } + this.collapsed = !this.collapsed; + }); + let backgroundColor = sessionStorage.getItem('backgroundColor'); + if (backgroundColor == 'rgb(38, 47, 60)') { + textColor = 'white'; + this.groupNameEl!.style.color = 'white'; + this.groupDescEl!.style.color = 'white'; + } else { + textColor = 'black'; + this.groupNameEl!.style.color = 'black'; + this.groupDescEl!.style.color = 'black'; + } + } + + initHtml(): string { + return ` + +
+
+
+
+ + `; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'title': + if (this.groupNameEl) this.groupNameEl.textContent = newValue; + break; + case 'describe': + if (this.groupDescEl) this.groupDescEl.textContent = newValue; + break; + } + } +} diff --git a/ide/src/base-ui/menu/LitMainMenuItem.ts b/ide/src/base-ui/menu/LitMainMenuItem.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbe466bb597d554f047bb1ba3b4915cf8f382956 --- /dev/null +++ b/ide/src/base-ui/menu/LitMainMenuItem.ts @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +let textColor = ''; + +@element('lit-main-menu-item') +export class LitMainMenuItem extends BaseElement { + private titleEl: HTMLElement | null | undefined; + private rootEL: HTMLElement | null | undefined; + private iconEl: HTMLElement | null | undefined; + private fileEL: HTMLInputElement | undefined | null; + + static get observedAttributes() { + return ['title', 'icon', 'file', 'disabled']; + } + + get title(): string { + return this.getAttribute('title') || ''; + } + + set title(val: string) { + this.setAttribute('title', val); + } + + get disabled(): boolean { + return this.hasAttribute('disabled'); + } + + set disabled(val: boolean) { + if (val) { + this.setAttribute('disabled', val.toString()); + this.fileEL?.setAttribute('disabled', val.toString()); + } else { + this.removeAttribute('disabled'); + this.fileEL?.removeAttribute('disabled'); + } + } + + get back(): boolean { + return this.hasAttribute('back'); + } + + set back(isShowBack: boolean) { + if (isShowBack) { + this.setAttribute('back', ''); + } else { + this.removeAttribute('back'); + } + } + + initElements(): void { + this.rootEL = this.shadowRoot?.querySelector('.root'); + this.titleEl = this.shadowRoot?.querySelector('.name'); + this.iconEl = this.shadowRoot?.querySelector('.icon'); + this.fileEL = this.shadowRoot?.querySelector('.file'); + let backgroundColor = sessionStorage.getItem('backgroundColor'); + if (backgroundColor == 'rgb(38, 47, 60)') { + textColor = 'white'; + this.style.color = 'white'; + } else { + textColor = 'black'; + this.style.color = 'black'; + } + } + + isFile(): boolean { + if (this.hasAttribute('file')) { + if (this.fileEL) { + return true; + } + } + return false; + } + + connectedCallback() { + if (this.hasAttribute('file')) { + if (this.fileEL) { + this.fileEL.addEventListener('change', () => { + let files = this.fileEL!.files; + if (files && files.length > 0) { + this.dispatchEvent( + new CustomEvent('file-change', { + // @ts-ignore + target: this, + detail: files[0], + }) + ); + if (this.fileEL) this.fileEL.value = ''; + } + }); + } + } + this.addEventListener('click', (e) => { + e.stopPropagation(); + }); + } + + initHtml(): string { + return ` + + + + `; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'title': + if (this.titleEl) this.titleEl.textContent = newValue; + break; + case 'icon': + if (this.iconEl) this.iconEl.setAttribute('name', newValue); + break; + } + } +} diff --git a/ide/src/base-ui/modal/LitModal.ts b/ide/src/base-ui/modal/LitModal.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c2e65720581c2217ed3bf2790906a76d38325ba --- /dev/null +++ b/ide/src/base-ui/modal/LitModal.ts @@ -0,0 +1,555 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-modal') +export class LitModal extends BaseElement { + private headerTitleElement: HTMLElement | null | undefined; + private headerElement: HTMLElement | null | undefined; + private closeElement: HTMLElement | null | undefined; + private cancelElement: HTMLElement | null | undefined; + private okElement: HTMLElement | null | undefined; + private modalElement: HTMLElement | null | undefined; + private resizing: boolean = false; + private down: boolean = false; + private onmouseleaveMoveFunc: any; + private onmouseupFunc: any; + private onmousedownMoveFunc: any; + private onmousedownFunc: any; + private onmousemoveMoveFunc: any; + private onmousemoveFunc: any; + private onmouseupMoveFunc: any; + static get observedAttributes() { + return [ + 'title', //标题 + 'line', //body的线条 + 'visible', //是否显示modal窗口 + 'ok-text', //确定文本 + 'cancel-text', //取消文本 + 'moveable', //设置窗口是否可以鼠标拖动 + 'resizeable', //窗口可改变大小 + 'width', //modal宽度 + ]; + } + + get okText() { + return this.getAttribute('ok-text') || '确定'; + } + + set okText(value) { + this.setAttribute('ok-text', value); + } + + get cancelText() { + return this.getAttribute('cancel-text') || '取消'; + } + + set cancelText(value) { + this.setAttribute('cancel-text', value); + } + + get title() { + return this.getAttribute('title') || ''; + } + + set title(value) { + this.setAttribute('title', value); + } + + get visible() { + return this.hasAttribute('visible'); + } + + set visible(value) { + if (value) { + this.setAttribute('visible', ''); + } else { + this.removeAttribute('visible'); + } + } + + get width() { + return this.getAttribute('width') || '500px'; + } + + set width(value) { + this.setAttribute('width', value); + } + + get resizeable() { + return this.hasAttribute('resizeable'); + } + + set resizeable(value) { + if (value) { + this.setAttribute('resizeable', ''); + } else { + this.removeAttribute('resizeable'); + } + } + + get moveable() { + return this.hasAttribute('moveable'); + } + + set moveable(value) { + if (value) { + this.setAttribute('moveable', ''); + } else { + this.removeAttribute('moveable'); + } + } + + set onOk(fn: any) { + this.addEventListener('onOk', fn); + } + + set onCancel(fn: any) { + this.addEventListener('onCancel', fn); + } + + initHtml(): string { + return ` + + + `; + } + + //当 custom element首次被插入文档DOM时,被调用。 + initElements(): void { + this.headerTitleElement = this.shadowRoot!.querySelector('#modal-title'); + this.headerTitleElement!.textContent = this.title; + + this.headerElement = this.shadowRoot!.querySelector('.header'); + this.closeElement = this.shadowRoot!.querySelector('.close-icon'); + this.cancelElement = this.shadowRoot!.querySelector('#cancel'); + this.okElement = this.shadowRoot!.querySelector('#ok'); + this.closeElement!.onclick = (ev) => (this.visible = false); + this.modalElement = this.shadowRoot!.querySelector('.modal'); + this.shadowRoot!.querySelector('.modal')!.onclick = (e) => { + e.stopPropagation(); + }; + this.onclick = (ev) => { + ev.stopPropagation(); + if (!this.resizeable) { + this.visible = false; + } + }; + this.cancelElement!.onclick = (ev) => { + this.dispatchEvent(new CustomEvent('onCancel', ev)); + }; + this.okElement!.onclick = (ev) => { + this.dispatchEvent(new CustomEvent('onOk', ev)); + }; + if (this.moveable || this.resizeable) { + if (this.resizeable) { + //move + let resizeWidth = 8; + this.resizing = false; + let srcResizeClientX = 0, + srcResizeClientY = 0, + srcResizeRect, + srcResizeHeight = 0, + srcResizeWidth = 0, + srcResizeRight = 0, + srcResizeLeft = 0, + srcResizeTop = 0; + let direction: string; + this.onmousemoveFunc = (e: any) => { + e.stopPropagation(); + srcResizeRect = this.modalElement!.getBoundingClientRect(); + if ( + e.clientX > srcResizeRect.left - resizeWidth && + e.clientX < srcResizeRect.left + resizeWidth && + e.clientY > srcResizeRect.top - resizeWidth && + e.clientY < srcResizeRect.top + resizeWidth + ) { + //left top + this.style.cursor = 'nwse-resize'; + if (!this.resizing) direction = 'left-top'; + } else if ( + e.clientX > srcResizeRect.right - resizeWidth && + e.clientX < srcResizeRect.right + resizeWidth && + e.clientY > srcResizeRect.top - resizeWidth && + e.clientY < srcResizeRect.top + resizeWidth + ) { + //right top + this.style.cursor = 'nesw-resize'; + if (!this.resizing) direction = 'right-top'; + } else if ( + e.clientX > srcResizeRect.left - resizeWidth && + e.clientX < srcResizeRect.left + resizeWidth && + e.clientY > srcResizeRect.bottom - resizeWidth && + e.clientY < srcResizeRect.bottom + resizeWidth + ) { + //left bottom + this.style.cursor = 'nesw-resize'; + if (!this.resizing) direction = 'left-bottom'; + } else if ( + e.clientX > srcResizeRect.right - resizeWidth && + e.clientX < srcResizeRect.right + resizeWidth && + e.clientY > srcResizeRect.bottom - resizeWidth && + e.clientY < srcResizeRect.bottom + resizeWidth + ) { + //right bottom + this.style.cursor = 'nwse-resize'; + if (!this.resizing) direction = 'right-bottom'; + } else if (e.clientX > srcResizeRect.left - resizeWidth && e.clientX < srcResizeRect.left + resizeWidth) { + //left + this.style.cursor = 'ew-resize'; + if (!this.resizing) direction = 'left'; + } else if (e.clientX < srcResizeRect.right + resizeWidth && e.clientX > srcResizeRect.right - resizeWidth) { + //right + this.style.cursor = 'ew-resize'; + if (!this.resizing) direction = 'right'; + } else if (e.clientY > srcResizeRect.top - resizeWidth && e.clientY < srcResizeRect.top + resizeWidth) { + //top + this.style.cursor = 'ns-resize'; + if (!this.resizing) direction = 'top'; + } else if (e.clientY < srcResizeRect.bottom + resizeWidth && e.clientY > srcResizeRect.bottom - resizeWidth) { + //bottom + this.style.cursor = 'ns-resize'; + if (!this.resizing) direction = 'bottom'; + } else { + this.style.cursor = ''; + if (!this.resizing) direction = ''; + } + if (this.resizing) { + let offsetResizeY = e.clientY - srcResizeClientY; + let offsetResizeX = e.clientX - srcResizeClientX; + if (direction === 'bottom') { + this.modalElement!.style.height = srcResizeHeight + offsetResizeY + 'px'; + } else if (direction === 'top') { + this.modalElement!.style.top = srcResizeTop + offsetResizeY + 'px'; + this.modalElement!.style.height = srcResizeHeight - offsetResizeY + 'px'; + } else if (direction === 'right') { + this.modalElement!.style.left = srcResizeLeft + srcResizeWidth / 2 + offsetResizeX / 2 + 'px'; + this.modalElement!.style.width = srcResizeWidth + offsetResizeX + 'px'; + } else if (direction === 'left') { + this.modalElement!.style.left = srcResizeLeft + srcResizeWidth / 2 + offsetResizeX / 2 + 'px'; + this.modalElement!.style.width = srcResizeWidth - offsetResizeX + 'px'; + } else if (direction === 'left-top') { + this.modalElement!.style.left = srcResizeLeft + srcResizeWidth / 2 + offsetResizeX / 2 + 'px'; + this.modalElement!.style.width = srcResizeWidth - offsetResizeX + 'px'; + this.modalElement!.style.top = srcResizeTop + offsetResizeY + 'px'; + this.modalElement!.style.height = srcResizeHeight - offsetResizeY + 'px'; + } else if (direction === 'right-top') { + this.modalElement!.style.left = srcResizeLeft + srcResizeWidth / 2 + offsetResizeX / 2 + 'px'; + this.modalElement!.style.width = srcResizeWidth + offsetResizeX + 'px'; + this.modalElement!.style.top = srcResizeTop + offsetResizeY + 'px'; + this.modalElement!.style.height = srcResizeHeight - offsetResizeY + 'px'; + } else if (direction === 'left-bottom') { + this.modalElement!.style.left = srcResizeLeft + srcResizeWidth / 2 + offsetResizeX / 2 + 'px'; + this.modalElement!.style.width = srcResizeWidth - offsetResizeX + 'px'; + this.modalElement!.style.height = srcResizeHeight + offsetResizeY + 'px'; + } else if (direction === 'right-bottom') { + this.modalElement!.style.left = srcResizeLeft + srcResizeWidth / 2 + offsetResizeX / 2 + 'px'; + this.modalElement!.style.width = srcResizeWidth + offsetResizeX + 'px'; + this.modalElement!.style.height = srcResizeHeight + offsetResizeY + 'px'; + } + } + }; + this.onmousedownFunc = (e: any) => { + srcResizeRect = this.modalElement!.getBoundingClientRect(); + srcResizeClientX = e.clientX; + srcResizeClientY = e.clientY; + srcResizeHeight = srcResizeRect.height; + srcResizeWidth = srcResizeRect.width; + srcResizeRight = srcResizeRect.right; + srcResizeLeft = srcResizeRect.left; + srcResizeTop = srcResizeRect.top; + if ( + e.clientX > srcResizeRect.left - resizeWidth && + e.clientX < srcResizeRect.left + resizeWidth && + e.clientY > srcResizeRect.top - resizeWidth && + e.clientY < srcResizeRect.top + resizeWidth + ) { + //left top + this.resizing = true; + } else if ( + e.clientX > srcResizeRect.right - resizeWidth && + e.clientX < srcResizeRect.right + resizeWidth && + e.clientY > srcResizeRect.top - resizeWidth && + e.clientY < srcResizeRect.top + resizeWidth + ) { + //right top + this.resizing = true; + } else if ( + e.clientX > srcResizeRect.left - resizeWidth && + e.clientX < srcResizeRect.left + resizeWidth && + e.clientY > srcResizeRect.bottom - resizeWidth && + e.clientY < srcResizeRect.bottom + resizeWidth + ) { + //left bottom + this.resizing = true; + } else if ( + e.clientX > srcResizeRect.right - resizeWidth && + e.clientX < srcResizeRect.right + resizeWidth && + e.clientY > srcResizeRect.bottom - resizeWidth && + e.clientY < srcResizeRect.bottom + resizeWidth + ) { + //right bottom + this.resizing = true; + } else if (e.clientX > srcResizeRect.left - resizeWidth && e.clientX < srcResizeRect.left + resizeWidth) { + //left + this.resizing = true; + } else if (e.clientX < srcResizeRect.right + resizeWidth && e.clientX > srcResizeRect.right - resizeWidth) { + //right + this.resizing = true; + } else if (e.clientY > srcResizeRect.top - resizeWidth && e.clientY < srcResizeRect.top + resizeWidth) { + //top + this.resizing = true; + } else if (e.clientY < srcResizeRect.bottom + resizeWidth && e.clientY > srcResizeRect.bottom - resizeWidth) { + //bottom + this.resizing = true; + } else { + this.resizing = false; + } + if (this.resizing) document.body.style.userSelect = 'none'; + }; + this.onmouseupFunc = (e: any) => { + this.resizing = false; + }; + } + + if (this.moveable) { + this.down = false; + let srcClientX = 0; + let srcClientY = 0; + let srcLeft = 0; + let srcTop = 0; + let srcRight = 0; + let srcBottom = 0; + let clientRect; + let rootRect: any; + + this.onmousedownMoveFunc = (e: any) => { + if (this.resizing) return; + srcClientX = e.clientX; + srcClientY = e.clientY; + rootRect = this.getBoundingClientRect(); + clientRect = this.modalElement!.getBoundingClientRect(); + srcLeft = clientRect.left; + srcRight = clientRect.right; + srcTop = clientRect.top; + srcBottom = clientRect.bottom; + if ( + e.clientX > srcLeft + 10 && + e.clientX < srcRight - 10 && + e.clientY > srcTop + 10 && + e.clientY < srcTop + this.headerElement!.scrollHeight + ) { + this.down = true; + } else { + this.down = false; + } + if (this.down) document.body.style.userSelect = 'none'; + this.onmousemoveMoveFunc = (ev: any) => { + if (this.down) { + let offsetY = e.clientY - srcClientY; + let offsetX = e.clientX - srcClientX; + if (e.clientX > srcLeft + 10 && e.clientX < srcRight - 10 && e.clientY > srcTop + 10) { + this.headerElement!.style.cursor = 'move'; + clientRect = this.modalElement!.getBoundingClientRect(); + //下面 rootRect.height 改成 this.scrollHeight 解决modal 过长会出现滚动条的情况 + if ( + ev.clientY - srcClientY + srcTop > 0 && + ev.clientY - srcClientY + srcTop < this.scrollHeight - clientRect.height + ) { + this.modalElement!.style.top = ev.clientY - srcClientY + srcTop + 'px'; + } else { + if (ev.clientY - srcClientY + srcTop <= 0) { + this.modalElement!.style.top = '0px'; + } else { + //下面 rootRect.height 改成 this.scrollHeight 解决modal 过长会出现滚动条的情况 + this.modalElement!.style.top = this.scrollHeight - clientRect.height + 'px'; + } + } + //ev.clientX-srcClientX 鼠标移动像素 + if ( + ev.clientX - srcClientX + srcLeft > 0 && + ev.clientX - srcClientX + srcLeft < rootRect.width - clientRect.width + ) { + this.modalElement!.style.left = ev.clientX - srcClientX + srcLeft + clientRect.width / 2 + 'px'; + } else { + if (ev.clientX - srcClientX + srcLeft <= 0) { + this.modalElement!.style.left = clientRect.width / 2 + 'px'; + } else { + this.modalElement!.style.left = rootRect.width - clientRect.width + clientRect.width / 2 + 'px'; + } + } + } + } + }; + this.onmouseleaveMoveFunc = this.onmouseupMoveFunc = (e: any) => { + this.down = false; + this.headerElement!.style.cursor = ''; + }; + }; + } + this.onmousemove = (e) => { + if (this.onmousemoveFunc) this.onmousemoveFunc(e); + if (this.onmousemoveMoveFunc) this.onmousemoveMoveFunc(e); + }; + this.onmousedown = (e) => { + if (this.onmousedownFunc) this.onmousedownFunc(e); + if (this.onmousedownMoveFunc) this.onmousedownMoveFunc(e); + }; + this.onmouseleave = this.onmouseup = (e) => { + if (this.onmouseleaveMoveFunc) this.onmouseleaveMoveFunc(e); + if (this.onmouseupFunc) this.onmouseupFunc(e); + document.body.style.userSelect = ''; + }; + } + } + + //当 custom element从文档DOM中删除时,被调用。 + disconnectedCallback() {} + + //当 custom element被移动到新的文档时,被调用。 + adoptedCallback() { + console.log('Custom square element moved to new page.'); + } + + //当 custom element增加、删除、修改自身属性时,被调用。 + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name === 'visible') { + if (!newValue && this.modalElement) { + this.modalElement.style.top = '100px'; + this.modalElement.style.left = '50%'; + } + } else if (name === 'title' && this.headerTitleElement) { + this.headerTitleElement.textContent = newValue; + } + } +} + +if (!customElements.get('lit-modal')) { + customElements.define('lit-modal', LitModal); +} diff --git a/ide/src/base-ui/popover/LitPopContent.ts b/ide/src/base-ui/popover/LitPopContent.ts new file mode 100644 index 0000000000000000000000000000000000000000..f78382bca16ced0b018c5cb87a4eca596ac66e5b --- /dev/null +++ b/ide/src/base-ui/popover/LitPopContent.ts @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-pop-content') +export class LitPopContent extends BaseElement { + static get observedAttributes() { + return ['open']; + } + + get open() { + return this.hasAttribute('open'); + } + + set open(value: boolean) { + if (value === null || !value) { + this.removeAttribute('open'); + let parentElement = this.parentNode as Element; + parentElement?.removeAttribute('open'); + } else { + this.setAttribute('open', ''); + let parentElement = this.parentNode as Element; + parentElement?.setAttribute('open', ''); + } + } + + initElements(): void {} + + initHtml(): string { + return ` + +
+ +
+ `; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'open': + if (newValue === null || newValue === 'false') { + let parentElement = this.parentNode as Element; + parentElement?.removeAttribute('open'); + } else { + let parentElement = this.parentNode as Element; + parentElement?.setAttribute('open', ''); + } + break; + default: + break; + } + } +} diff --git a/ide/src/base-ui/popover/LitPopover.ts b/ide/src/base-ui/popover/LitPopover.ts new file mode 100644 index 0000000000000000000000000000000000000000..3afff2453c13b9fd4609d449da90c9b5a7a6d44d --- /dev/null +++ b/ide/src/base-ui/popover/LitPopover.ts @@ -0,0 +1,463 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { LitPopContent } from './LitPopContent.js'; +import { LitPopoverTitle } from './LitPopoverTitle.js'; +import { LitRadioGroup } from '../radiobox/LitRadioGroup.js'; +import { LitRadioBox } from '../radiobox/LitRadioBox.js'; +import { LitCheckBox } from '../checkbox/LitCheckBox.js'; +import { LitCheckGroup } from '../checkbox/LitCheckGroup.js'; +import { LitCheckBoxWithText } from '../checkbox/LitCheckBoxWithText.js'; + +@element('lit-popover') +export class LitPopover extends BaseElement { + private popContent: LitPopContent | null | undefined; + private litGroup: LitRadioGroup | LitCheckGroup | undefined; + private _texBox: LitCheckBoxWithText | undefined; + + static get observedAttributes() { + return []; + } + + get type() { + return this.getAttribute('type') || ''; + } + + set type(type: string) { + this.setAttribute('type', type); + } + + get title() { + return this.getAttribute('title') || ''; + } + + set title(title: string) { + this.setAttribute('title', title); + } + + get limit(): LimitText { + if (this._texBox?.checked) { + return { + textLowerLimit: this._texBox.lowerLimit, + textUpperLimit: this._texBox.upLimit, + }; + } + return { textLowerLimit: '', textUpperLimit: '' }; + } + + set dataSource(dataSource: Array) { + this.popContent = this.querySelector('lit-pop-content'); + if (!this.popContent) { + this.popContent = new LitPopContent(); + this.appendChild(this.popContent); + } + switch (this.type) { + case 'multiple': + this.litGroup = new LitCheckGroup(); + this.litGroup.setAttribute('layout', 'dispersion'); + this.popContent!.appendChild(this.litGroup); + dataSource.forEach((data) => { + let litCheckBox = new LitCheckBox(); + this.litGroup?.appendChild(litCheckBox); + if (data.isSelected) { + litCheckBox.setAttribute('checked', 'true'); + } + litCheckBox.setAttribute('value', data.text); + }); + break; + case 'radio': + this.litGroup = new LitRadioGroup(); + if (this.title !== '') { + let title = new LitPopoverTitle(); + title.setAttribute('title', this.title || ''); + this.popContent!.appendChild(title); + this.litGroup.setAttribute('layout', 'compact'); + } else { + this.litGroup.setAttribute('layout', 'dispersion'); + } + this.popContent!.appendChild(this.litGroup); + dataSource.forEach((data) => { + let litRadioBox = new LitRadioBox(); + if (this.title == '') { + litRadioBox.setAttribute('dis', 'round'); + } else { + litRadioBox.setAttribute('dis', 'check'); + } + if (data.isSelected) { + litRadioBox.setAttribute('checked', 'true'); + } + this.litGroup?.appendChild(litRadioBox); + litRadioBox.setAttribute('value', data.text); + }); + break; + case 'multiple-text': + dataSource.forEach((data) => { + this._texBox = new LitCheckBoxWithText(); + this._texBox.setAttribute('text', data.text); + this._texBox.setAttribute('checked', ''); + this.popContent!.appendChild(this._texBox); + }); + break; + case 'data-ming': + break; + } + } + + get select(): Array | undefined { + if (this._texBox?.checked) { + return [this._texBox!.text]; + } + return this.litGroup?.value; + } + + get trigger() { + return this.getAttribute('trigger'); + } + + get direction() { + return this.getAttribute('direction') || 'topright'; + } + + set direction(value: string) { + this.setAttribute('direction', value); + } + + get open() { + return this.getAttribute('open') !== null; + } + + set open(value: boolean) { + if (value === null || value === false) { + this.removeAttribute('open'); + } else { + this.setAttribute('open', ''); + } + } + + initElements(): void {} + + initHtml(): string { + return ` + + + `; + } + + connectedCallback() { + if (!(this.trigger && this.trigger !== 'click')) { + this.addEventListener('click', () => { + this.popContent = this.querySelector('lit-pop-content'); + if (!this.popContent) { + this.popContent = new LitPopContent(); + this.appendChild(this.popContent); + } + this.popContent?.setAttribute('open', 'true'); + }); + } + document.addEventListener('mousedown', (ev) => { + const path = ev.composedPath && ev.composedPath(); + if ( + // @ts-ignore + this.popContent && !path.includes(this.popContent) && !path.includes(this.children[0]) && !path.includes(this.popContent) + ) { + this.popContent!.open = false; + } + }); + } +} + +export interface SelectBean { + text: string; + isSelected: boolean; + limitText?: LimitText; +} + +export interface LimitText { + textUpperLimit: string; + textLowerLimit: string; +} + +export interface Charge { + text: string; + isSelected: boolean; +} diff --git a/ide/src/base-ui/popover/LitPopoverTitle.ts b/ide/src/base-ui/popover/LitPopoverTitle.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa0d27d832a205e9b96cbb9d20547193bdddd118 --- /dev/null +++ b/ide/src/base-ui/popover/LitPopoverTitle.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-popover-title') +export class LitPopoverTitle extends BaseElement { + private titleText: HTMLElement | null | undefined; + + static get observedAttributes() { + return ['title']; + } + + initElements(): void { + this.titleText = this.shadowRoot?.querySelector('.pop-title'); + } + + initHtml(): string { + return ` + +
+ `; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'title': + if (this.titleText) this.titleText.textContent = newValue; + break; + default: + break; + } + } +} diff --git a/ide/src/base-ui/popover/LitPopoverV.ts b/ide/src/base-ui/popover/LitPopoverV.ts new file mode 100644 index 0000000000000000000000000000000000000000..80e13782ce1fb39cbdc6b00127f7786a1560b7a6 --- /dev/null +++ b/ide/src/base-ui/popover/LitPopoverV.ts @@ -0,0 +1,473 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-popover') +export class LitPopover extends BaseElement { + static get observedAttributes() { + return ['title', 'trigger', 'width', 'placement', 'visible']; + } + + get visible() { + return this.getAttribute('visible') || 'false'; + } + + set visible(value) { + if (value) { + this.setAttribute('visible', 'true'); + } else { + this.setAttribute('visible', 'false'); + } + } + + get trigger() { + return this.getAttribute('trigger') || 'hover'; + } + + set trigger(value) { + this.setAttribute('trigger', value); + } + + get title() { + return this.getAttribute('title'); + } + + set title(value: any) { + this.setAttribute('title', value); + } + + get width() { + return this.getAttribute('width') || 'max-content'; + } + + set width(value) { + this.setAttribute('width', value); + } + + get haveRadio() { + return this.getAttribute('haveRadio'); + } + + initElements(): void {} + + initHtml() { + return ` + + +
+
${this.title}
+
+
+ + `; + } + + connectedCallback() { + let popover: any = this.shadowRoot!.querySelector('.popover'); + let checkbox: any = this.shadowRoot!.querySelector('.trigger-click'); + this.setAttribute('tabindex', '1'); + popover.onclick = (e: any) => { + e.stopPropagation(); + }; + popover.addEventListener('mousemove', (e: any) => { + e.stopPropagation(); + }); + this.onclick = (e: any) => { + e.stopPropagation(); + if (e.relatedTarget?.hasAttribute('not-close')) { + this.focus(); + } + checkbox.checked = !checkbox.checked; + this.visible = checkbox.checked; + }; + popover.onmouseleave = () => { + this.focus(); + }; + this.onblur = (ev: any) => { + if (ev.relatedTarget && this.haveRadio) { + if (ev.relatedTarget.hasAttribute('not-close')) { + } else if (ev.relatedTarget.type === 'radio') { + this.focus(); + } else { + // @ts-ignore + this.visible = false; + } + } else { + // @ts-ignore + this.visible = false; + } + }; + } + + disconnectedCallback() {} + + adoptedCallback() {} + + attributeChangedCallback(name: any, oldValue: any, newValue: any) { + if (name === 'visible') { + if (newValue === 'false') { + // @ts-ignore + this.shadowRoot!.querySelector('.trigger-click')!.checked = false; + } else { + // @ts-ignore + this.shadowRoot!.querySelector('.trigger-click')!.checked = true; + } + } + } +} diff --git a/ide/src/base-ui/progress-bar/LitProgressBar.ts b/ide/src/base-ui/progress-bar/LitProgressBar.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1f19556642fd08afd239509b96875e0fa184af0 --- /dev/null +++ b/ide/src/base-ui/progress-bar/LitProgressBar.ts @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-progress-bar') +export class LitProgressBar extends BaseElement { + static get observedAttributes() { + return ['loading']; + } + + get loading(): boolean { + return this.hasAttribute('loading'); + } + + set loading(value: boolean) { + if (value) { + this.setAttribute('loading', ''); + } else { + this.removeAttribute('loading'); + } + } + + initElements(): void {} + + initHtml(): string { + return ` + +
+
+
+
+ `; + } +} diff --git a/ide/src/base-ui/radiobox/LitRadioBox.ts b/ide/src/base-ui/radiobox/LitRadioBox.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b2e0a67fd47e2d73d5077eab4e82cf68a881680 --- /dev/null +++ b/ide/src/base-ui/radiobox/LitRadioBox.ts @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { LitRadioGroup } from './LitRadioGroup.js'; + +@element('lit-radio') +export class LitRadioBox extends BaseElement { + private group: LitRadioGroup | undefined | null; + private parent: LitRadioGroup | undefined | null; + private radio: HTMLInputElement | undefined | null; + + static get observedAttributes() { + return ['checked', 'value']; + } + + get checked() { + return this.getAttribute('checked') !== null; + } + + set checked(value: boolean) { + if (value === null || !value) { + this.removeAttribute('checked'); + } else { + this.setAttribute('checked', ''); + } + } + + get name() { + return this.getAttribute('name'); + } + + get value() { + let slot = this.shadowRoot?.getElementById('slot'); + return slot!.textContent || this.textContent || ''; + } + + set value(value: string) { + this.setAttribute('value', value); + } + + set dis(dis: string) { + this.setAttribute('dis', dis); + } + + initHtml(): string { + return ` + + + + `; + } + + initElements(): void { + this.radio = this.shadowRoot?.getElementById('radio') as HTMLInputElement; + } + + connectedCallback() { + this.group = this.closest('lit-radio-group') as LitRadioGroup; + this.parent = this.group || this.getRootNode(); + this.radio = this.shadowRoot?.getElementById('radio') as HTMLInputElement; + this.checked = this.checked; + this.radio.addEventListener('change', () => { + const selector = this.group ? `lit-radio[checked]` : `lit-radio[name="${this.name}"][checked]`; + const siblingNode = this.parent?.querySelector(selector) as LitRadioBox; + if (siblingNode) { + siblingNode.checked = false; + } + this.checked = true; + }); + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name == 'checked' && this.radio) { + this.radio.checked = newValue !== null; + } + if (name == 'value') { + let slot = this.shadowRoot?.getElementById('slot'); + slot!.textContent = newValue; + } + } +} diff --git a/ide/src/base-ui/radiobox/LitRadioGroup.ts b/ide/src/base-ui/radiobox/LitRadioGroup.ts new file mode 100644 index 0000000000000000000000000000000000000000..461d520a3ff5a6ca1fd1e44c904e0a3f8f106516 --- /dev/null +++ b/ide/src/base-ui/radiobox/LitRadioGroup.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { LitRadioBox } from './LitRadioBox.js'; + +@element('lit-radio-group') +export class LitRadioGroup extends BaseElement { + static get observedAttributes() { + return ['direction']; + } + + set layout(vale: string) { + this.setAttribute('layout', vale); + } + + get direction() { + return this.getAttribute('direction'); + } + + get value(): Array { + const radio = this.querySelector('lit-radio[checked]') as LitRadioBox; + return radio ? [radio.value] : []; + } + + initElements(): void {} + + //方向 + initHtml(): string { + return ` + + `; + } +} diff --git a/ide/src/base-ui/select/LitAllocationSelect.ts b/ide/src/base-ui/select/LitAllocationSelect.ts new file mode 100644 index 0000000000000000000000000000000000000000..33ca36700fa96ec3cbb3b111998eae9e86aeb057 --- /dev/null +++ b/ide/src/base-ui/select/LitAllocationSelect.ts @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-allocation-select') +export class LitAllocationSelect extends BaseElement { + private inputElement: HTMLInputElement | null | undefined; + private inputContent: HTMLDivElement | undefined; + private options: any; + + static get observedAttributes() { + return ['value', 'disabled', 'placeholder']; + } + + get defaultPlaceholder() { + return this.getAttribute('placeholder') || ''; + } + + get placeholder() { + return this.getAttribute('placeholder') || this.defaultPlaceholder; + } + + set placeholder(value) { + this.setAttribute('placeholder', value); + } + + get value() { + return this.getAttribute('value') || ''; + } + + set value(value: string) { + this.setAttribute('value', value); + } + + set processData(value: Array) { + this.options.innerHTML = ''; + value.forEach((item) => { + let option = document.createElement('div'); + option.className = 'option'; + option.innerHTML = item; + option.style.padding = '8px 10px'; + this.options.appendChild(option); + this.inputElement?.focus(); + }); + } + + get placement(): string { + return this.getAttribute('placement') || ''; + } + + set placement(placement: string) { + if (placement) { + this.setAttribute('placement', placement); + } else { + this.removeAttribute('placement'); + } + } + + get listHeight() { + return this.getAttribute('list-height') || '256px'; + } + + set listHeight(value) { + this.setAttribute('list-height', value); + } + + initElements(): void { + this.inputContent = this.shadowRoot!.querySelector('.multipleSelect') as HTMLDivElement; + this.addEventListener('click', () => { + if (this.options.style.visibility == 'visible') { + this.options.style.visibility = 'hidden'; + this.options.style.opacity = '0'; + } else { + this.options.style.visibility = 'visible'; + this.options.style.opacity = '1'; + } + this.inputContent!.dispatchEvent(new CustomEvent('inputClick', {})); + }); + this.addEventListener('focusout', (e) => { + this.options.style.visibility = 'hidden'; + this.options.style.opacity = '0'; + }); + this.initData(); + } + + initHtml() { + return ` + +
+
+ +
+ +
+
+ + +
+ `; + } + + connectedCallback() {} + + initData() { + this.inputElement = this.shadowRoot!.querySelector('input'); + this.options = this.shadowRoot!.querySelector('.body') as HTMLDivElement; + this.inputElement?.addEventListener('keyup', () => { + let filter = [...this.shadowRoot!.querySelectorAll('.option')].filter((a: HTMLDivElement) => { + if (a.textContent!.indexOf(this.inputElement!.value) <= -1) { + a.style.display = 'none'; + } else { + a.style.display = 'block'; + } + }); + this.value = this.inputElement!.value; + this.inputContent!.dispatchEvent(new CustomEvent('valuable', {})); + }); + this.shadowRoot?.querySelectorAll('.option').forEach((a) => { + a.addEventListener('mousedown', (e) => { + a.dispatchEvent( + new CustomEvent('onSelected', { + detail: { + selected: true, + text: a.textContent, + }, + }) + ); + }); + a.addEventListener('onSelected', (e: any) => { + this.inputElement!.value = e.detail.text; + this.value = e.detail.text; + this.inputContent!.dispatchEvent(new CustomEvent('valuable', {})); + }); + }); + } +} diff --git a/ide/src/base-ui/select/LitSelect.ts b/ide/src/base-ui/select/LitSelect.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fbe6946bc48002c1d33010efd0eac0e990028ef --- /dev/null +++ b/ide/src/base-ui/select/LitSelect.ts @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-select') +export class LitSelect extends BaseElement { + private focused: any; + private inputElement: any; + private clearElement: any; + private iconElement: any; + private searchElement: any; + private multipleRootElement: any; + + static get observedAttributes() { + return [ + 'value', + 'default-value', + 'placeholder', + 'disabled', + 'loading', + 'allow-clear', + 'show-search', + 'list-height', + 'border', + 'mode', + ]; + } + + get value() { + return this.getAttribute('value') || this.defaultValue; + } + + set value(value) { + this.setAttribute('value', value); + } + + get rounded() { + return this.hasAttribute('rounded'); + } + + set rounded(rounded: boolean) { + if (rounded) { + this.setAttribute('rounded', ''); + } else { + this.removeAttribute('rounded'); + } + } + + get placement(): string { + return this.getAttribute('placement') || ''; + } + + set placement(placement: string) { + if (placement) { + this.setAttribute('placement', placement); + } else { + this.removeAttribute('placement'); + } + } + + get border() { + return this.getAttribute('border') || 'true'; + } + + set border(value) { + if (value) { + this.setAttribute('border', 'true'); + } else { + this.setAttribute('border', 'false'); + } + } + + get listHeight() { + return this.getAttribute('list-height') || '256px'; + } + + set listHeight(value) { + this.setAttribute('list-height', value); + } + + get defaultPlaceholder() { + return this.getAttribute('placeholder') || '请选择'; + } + + set canInsert(can: boolean) { + if (can) { + this.setAttribute('canInsert', ''); + } else { + this.removeAttribute('canInsert'); + } + } + + get canInsert() { + return this.hasAttribute('canInsert'); + } + get showSearch() { + return this.hasAttribute('show-search'); + } + + get defaultValue() { + return this.getAttribute('default-value') || ''; + } + + set defaultValue(value) { + this.setAttribute('default-value', value); + } + + get placeholder() { + return this.getAttribute('placeholder') || this.defaultPlaceholder; + } + + set placeholder(value) { + this.setAttribute('placeholder', value); + } + + get loading() { + return this.hasAttribute('loading'); + } + + set loading(value) { + if (value) { + this.setAttribute('loading', ''); + } else { + this.removeAttribute('loading'); + } + } + + set dataSource(value: any) { + value.forEach((a: any) => { + let option = document.createElement('lit-select-option'); + if (a.file_name) { + option.textContent = a.file_name; + option.setAttribute('value', a.file_name); + } + this.append(option); + }); + this.initOptions(); + } + + initElements(): void {} + + initHtml() { + return ` + +
+
+
+ + + + +
+
+ + +
+ `; + } + + isMultiple() { + return this.hasAttribute('mode') && this.getAttribute('mode') === 'multiple'; + } + + newTag(value: any, text: any) { + let tag: any = document.createElement('div'); + let icon: any = document.createElement('lit-icon'); + icon.classList.add('tag-close'); + icon.name = 'close'; + let span = document.createElement('span'); + tag.classList.add('tag'); + span.dataset['value'] = value; + span.textContent = text; + tag.append(span); + tag.append(icon); + icon.onclick = (ev: any) => { + tag.parentElement.removeChild(tag); + this.querySelector(`lit-select-option[value=${value}]`)!.removeAttribute('selected'); + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + ev.stopPropagation(); + }; + tag.value = value; + tag.dataset['value'] = value; + tag.text = text; + tag.dataset['text'] = text; + return tag; + } + + connectedCallback() { + this.tabIndex = 0; + this.focused = false; + this.inputElement = this.shadowRoot!.querySelector('input'); + this.clearElement = this.shadowRoot!.querySelector('.clear'); + this.iconElement = this.shadowRoot!.querySelector('.icon'); + this.searchElement = this.shadowRoot!.querySelector('.search'); + this.multipleRootElement = this.shadowRoot!.querySelector('.multipleRoot'); + this.clearElement.onclick = (ev: any) => { + if (this.isMultiple()) { + let delNodes: Array = []; + this.multipleRootElement.childNodes.forEach((a: any) => { + if (a.tagName === 'DIV') { + delNodes.push(a); + } + }); + for (let i = 0; i < delNodes.length; i++) { + delNodes[i].remove(); + } + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + } + this.querySelectorAll('lit-select-option').forEach((a) => a.removeAttribute('selected')); + this.inputElement.value = ''; + this.clearElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + this.blur(); + ev.stopPropagation(); + this.dispatchEvent(new CustomEvent('onClear', { detail: ev })); + }; + this.initOptions(); + this.onclick = (ev: any) => { + if (ev.target.tagName === 'LIT-SELECT') { + if (this.focused === false) { + this.inputElement.focus(); + this.focused = true; + } else { + this.blur(); + this.focused = false; + } + } + }; + this.onmouseover = this.onfocus = (ev) => { + if (this.focused === false && this.hasAttribute('adaptive-expansion')) { + let body = this.shadowRoot!.querySelector('.body'); + if (this.parentElement!.offsetTop < body!.clientHeight) { + body!.classList.add('body-bottom'); + } else { + body!.classList.remove('body-bottom'); + } + } + if (this.hasAttribute('allow-clear')) { + if (this.inputElement.value.length > 0 || this.inputElement.placeholder !== this.defaultPlaceholder) { + this.clearElement.style.display = 'flex'; + this.iconElement.style.display = 'none'; + } else { + this.clearElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + } + }; + this.onmouseout = this.onblur = (ev) => { + if (this.hasAttribute('allow-clear')) { + this.clearElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + this.focused = false; + }; + this.inputElement.onfocus = (ev: any) => { + if (this.hasAttribute('disabled')) return; + if (this.inputElement.value.length > 0) { + this.inputElement.placeholder = this.inputElement.value; + this.inputElement.value = ''; + } + if (this.hasAttribute('show-search')) { + this.searchElement.style.display = 'flex'; + this.iconElement.style.display = 'none'; + } + this.querySelectorAll('lit-select-option').forEach((a) => { + // @ts-ignore + a.style.display = 'flex'; + }); + }; + this.inputElement.onblur = (ev: any) => { + if (this.hasAttribute('disabled')) return; + if (this.isMultiple()) { + if (this.hasAttribute('show-search')) { + this.searchElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + } else { + if (this.inputElement.placeholder !== this.defaultPlaceholder) { + this.inputElement.value = this.inputElement.placeholder; + this.inputElement.placeholder = this.defaultPlaceholder; + } + if (this.hasAttribute('show-search')) { + this.searchElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + } + }; + this.inputElement.oninput = (ev: any) => { + let els = [...this.querySelectorAll('lit-select-option')]; + if (this.hasAttribute('show-search')) { + if (!ev.target.value) { + els.forEach((a: any) => (a.style.display = 'flex')); + } else { + els.forEach((a: any) => { + let value = a.getAttribute('value'); + if ( + value.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 || + a.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 + ) { + a.style.display = 'flex'; + } else { + a.style.display = 'none'; + } + }); + } + } else { + this.value = ev.target.value; + } + }; + this.inputElement.onkeydown = (ev: any) => { + if (ev.key === 'Backspace') { + if (this.isMultiple()) { + let tag = this.multipleRootElement.lastElementChild.previousElementSibling; + if (tag) { + this.querySelector(`lit-select-option[value=${tag.value}]`)?.removeAttribute('selected'); + tag.remove(); + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + } + } else { + this.clear(); + this.dispatchEvent(new CustomEvent('onClear', { detail: ev })); //向外派发清理事件 + } + } else if (ev.key === 'Enter') { + if (!this.canInsert) { + let filter = [...this.querySelectorAll('lit-select-option')].filter((a: any) => a.style.display !== 'none'); + if (filter.length > 0) { + this.inputElement.value = filter[0].textContent; + this.inputElement.placeholder = filter[0].textContent; + this.blur(); + // @ts-ignore + this.value = filter[0].getAttribute('value'); + this.dispatchEvent( + new CustomEvent('change', { + detail: { + selected: true, + value: filter[0].getAttribute('value'), + text: filter[0].textContent, + }, + }) + ); + } + } + } + }; + } + + initOptions() { + this.querySelectorAll('lit-select-option').forEach((a) => { + if (this.isMultiple()) { + a.setAttribute('check', ''); + if (a.getAttribute('value') === this.defaultValue) { + let tag = this.newTag(a.getAttribute('value'), a.textContent); + this.multipleRootElement.insertBefore(tag, this.inputElement); + this.inputElement.placeholder = ''; + this.inputElement.value = ''; + this.inputElement.style.width = '1px'; + a.setAttribute('selected', ''); + } + } else { + if (a.getAttribute('value') === this.defaultValue) { + this.inputElement.value = a.textContent; + a.setAttribute('selected', ''); + } + } + a.addEventListener('mouseup', (e) => { + e.stopPropagation(); + }); + a.addEventListener('mousedown', (e) => { + e.stopPropagation(); + }); + a.addEventListener('onSelected', (e: any) => { + if (this.isMultiple()) { + if (a.hasAttribute('selected')) { + let tag = this.shadowRoot!.querySelector(`div[data-value=${e.detail.value}]`) as HTMLElement; + if (tag) { + tag.parentElement!.removeChild(tag); + } + e.detail.selected = false; + } else { + let tag = this.newTag(e.detail.value, e.detail.text); + this.multipleRootElement.insertBefore(tag, this.inputElement); + this.inputElement.placeholder = ''; + this.inputElement.value = ''; + this.inputElement.style.width = '1px'; + } + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + this.inputElement.focus(); + } else { + [...this.querySelectorAll('lit-select-option')].forEach((a) => a.removeAttribute('selected')); + this.blur(); + // @ts-ignore + this.inputElement.value = e.detail.text; + } + if (a.hasAttribute('selected')) { + a.removeAttribute('selected'); + } else { + a.setAttribute('selected', ''); + } + // @ts-ignore + this.value = e.detail.value; + this.dispatchEvent(new CustomEvent('change', { detail: e.detail })); //向外层派发change事件,返回当前选中项 + }); + }); + } + + clear() { + this.inputElement.value = ''; + this.inputElement.placeholder = this.defaultPlaceholder; + } + + reset() { + this.querySelectorAll('lit-select-option').forEach((a) => { + [...this.querySelectorAll('lit-select-option')].forEach((a) => a.removeAttribute('selected')); + if (a.getAttribute('value') === this.defaultValue) { + this.inputElement.value = a.textContent; + a.setAttribute('selected', ''); + } + }); + } + + disconnectedCallback() {} + + adoptedCallback() {} + + attributeChangedCallback(name: any, oldValue: any, newValue: any) { + if (name === 'value' && this.inputElement) { + if (newValue) { + [...this.querySelectorAll('lit-select-option')].forEach((a) => { + if (a.getAttribute('value') === newValue) { + a.setAttribute('selected', ''); + this.inputElement.value = a.textContent; + } else { + a.removeAttribute('selected'); + } + }); + } else { + this.clear(); + } + } + } +} diff --git a/ide/src/base-ui/select/LitSelectOption.ts b/ide/src/base-ui/select/LitSelectOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..60c3f3330d8d9effeb3de6429baba6b576303a32 --- /dev/null +++ b/ide/src/base-ui/select/LitSelectOption.ts @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2022 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 { BaseElement } from '../BaseElement.js'; +import '../icon/LitIcon.js'; + +export class LitSelectOption extends BaseElement { + static get observedAttributes() { + return ['selected', 'disabled', 'check']; + } + + initHtml() { + return ` + +
+ +
+ + + `; + } + + initElements(): void {} + + //当 custom element首次被插入文档DOM时,被调用。 + connectedCallback() { + if (!this.hasAttribute('disabled')) { + this.onclick = (ev) => { + this.dispatchEvent( + new CustomEvent('onSelected', { + detail: { + selected: true, + value: this.getAttribute('value'), + text: this.textContent, + }, + }) + ); + }; + } + } + + //当 custom element从文档DOM中删除时,被调用。 + disconnectedCallback() {} + + //当 custom element被移动到新的文档时,被调用。 + adoptedCallback() {} + + //当 custom element增加、删除、修改自身属性时,被调用。 + attributeChangedCallback(name: any, oldValue: any, newValue: any) {} +} + +if (!customElements.get('lit-select-option')) { + customElements.define('lit-select-option', LitSelectOption); +} diff --git a/ide/src/base-ui/select/LitSelectV.ts b/ide/src/base-ui/select/LitSelectV.ts new file mode 100644 index 0000000000000000000000000000000000000000..20de4efac4f68fcfe8b3179c790269ccc8fbd1c7 --- /dev/null +++ b/ide/src/base-ui/select/LitSelectV.ts @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { LitSelectOption } from './LitSelectOption.js'; + +@element('lit-select-v') +export class LitSelectV extends BaseElement { + showItems: Array = []; + itemValue: Array = []; + customItem: Array = []; + private focused: any; + private inputElement: any; + private searchInputElement: any; + private iconElement: any; + private options: HTMLDivElement | undefined; + private body: HTMLDivElement | undefined; + + private valueStr: string = ''; + + static get observedAttributes() { + return ['value', 'default-value', 'placeholder', 'disabled', 'show-search', 'border', 'mode']; + } + + get value() { + return this.inputElement!.value || this.defaultValue; + } + + get rounded() { + return this.hasAttribute('rounded'); + } + + set rounded(rounded: boolean) { + if (rounded) { + this.setAttribute('rounded', ''); + } else { + this.removeAttribute('rounded'); + } + } + + get placement(): string { + return this.getAttribute('placement') || ''; + } + + set placement(placement: string) { + if (placement) { + this.setAttribute('placement', placement); + } else { + this.removeAttribute('placement'); + } + } + + get border() { + return this.getAttribute('border') || 'true'; + } + + set border(value) { + if (value) { + this.setAttribute('border', 'true'); + } else { + this.setAttribute('border', 'false'); + } + } + + get defaultPlaceholder() { + return this.getAttribute('placeholder') || ''; + } + + get defaultValue() { + return this.getAttribute('default-value') || ''; + } + + set defaultValue(value) { + this.setAttribute('default-value', value); + } + + get placeholder() { + return this.getAttribute('placeholder') || this.defaultPlaceholder; + } + + set placeholder(value) { + this.setAttribute('placeholder', value); + } + + set all(isAll: boolean) { + if (isAll) { + this.setAttribute('is-all', ''); + } else { + this.removeAttribute('is-all'); + } + } + + get all() { + return this.hasAttribute('is-all'); + } + + dataSource(value: Array, valueStr: string) { + this.options!.innerHTML = ''; + if (value.length > 0) { + this.body!.style.display = 'block'; + this.valueStr = valueStr; + this.itemValue = value; + if (valueStr != '') { + let option = document.createElement('lit-select-option'); + if (this.all) { + option.setAttribute('selected', ''); + this.showItems = value; + } + option.setAttribute('value', valueStr); + option.textContent = valueStr; + this.options!.appendChild(option); + this.initDataItem(value); + this.initCustomOptions(); + } else { + this.initDataItem(value); + this.initOptions(); + } + } else { + this.body!.style.display = 'none'; + } + if (this.title == 'Event List') { + let inputElement = this.shadowRoot?.querySelector('input') as HTMLInputElement; + inputElement.readOnly = false; + } + } + + initDataItem(value: Array) { + value.forEach((item) => { + let option = document.createElement('lit-select-option'); + if (this.showItems.indexOf(item) > -1 || this.all) { + option.setAttribute('selected', ''); + } + option.className = 'option'; + option.setAttribute('value', item); + option.textContent = item; + this.options!.appendChild(option); + }); + } + + initElements(): void { + this.tabIndex = 0; + this.focused = false; + this.inputElement = this.shadowRoot!.querySelector('#select-input') as HTMLInputElement; + this.searchInputElement = this.shadowRoot!.querySelector('#search-input') as HTMLInputElement; + this.body = this.shadowRoot!.querySelector('.body') as HTMLDivElement; + this.options = this.shadowRoot!.querySelector('.body-opt') as HTMLDivElement; + this.iconElement = this.shadowRoot!.querySelector('.icon'); + this.onclick = (ev: any) => { + if (this.focused === false) { + this.focused = true; + } else { + this.focused = false; + } + }; + this.searchInputElement?.addEventListener('keyup', () => { + let options = [...this.shadowRoot!.querySelectorAll('.option')]; + options.filter((a: LitSelectOption) => { + if (a.textContent!.indexOf(this.searchInputElement!.value) <= -1) { + a.style.display = 'none'; + } else { + a.style.display = 'flex'; + } + }); + }); + + this.onmouseout = this.onblur = (ev) => { + this.focused = false; + }; + this.inputElement.onfocus = (ev: any) => { + if (this.hasAttribute('disabled')) return; + }; + this.inputElement.onblur = (ev: any) => { + if (this.hasAttribute('disabled')) return; + }; + } + + initHtml() { + return ` + +
+ + +
+
+
+ +
+
+ + +
+
+ `; + } + + connectedCallback() {} + + initCustomOptions() { + let querySelector = this.shadowRoot?.querySelector( + `lit-select-option[value="${this.valueStr}"]` + ) as LitSelectOption; + this.shadowRoot?.querySelectorAll('lit-select-option').forEach((a) => { + a.setAttribute('check', ''); + a.addEventListener('onSelected', (e: any) => { + if (a.hasAttribute('selected')) { + let number = this.showItems.indexOf(a.textContent!); + if (number > -1) { + this.showItems!.splice(number, 1); + this.inputElement!.value = this.showItems; + } + this.all = false; + querySelector.removeAttribute('selected'); + a.removeAttribute('selected'); + return; + } else { + let index = this.itemValue.indexOf(a.textContent!); + let value = this.showItems.indexOf(a.textContent!); + if (index > -1 && value == -1) { + this.showItems.push(a.textContent!); + this.inputElement!.value = this.showItems; + } + if (this.showItems.length >= this.itemValue.length) { + querySelector.setAttribute('selected', ''); + this.all = true; + } else { + querySelector.removeAttribute('selected'); + this.all = false; + } + a.setAttribute('selected', ''); + } + }); + }); + this.selectAll(querySelector); + } + + initOptions() { + this.options!.addEventListener('click', (ev) => { + let items = this.inputElement!.value.split(','); + this.customItem = []; + items.forEach((item: string) => { + if (item.trim() != '') { + let indexItem = this.itemValue.indexOf(item.trim()); + if (indexItem == -1) { + this.customItem.push(item.trim()); + } + } + }); + if (this.customItem.length > 0) { + this.inputElement.value = this.customItem.concat(this.showItems); + } else { + this.inputElement.value = this.showItems; + } + }); + this.shadowRoot?.querySelectorAll('lit-select-option').forEach((a) => { + a.setAttribute('check', ''); + a.addEventListener('onSelected', (e: any) => { + if (a.hasAttribute('selected')) { + let number = this.showItems.indexOf(a.textContent!); + if (number > -1) { + this.showItems.splice(number, 1); + } + a.removeAttribute('selected'); + return; + } else { + let index = this.itemValue.indexOf(a.textContent!); + if (index > -1) { + this.showItems.push(a.textContent!); + } + a.setAttribute('selected', ''); + } + }); + }); + } + + selectAll(querySelector: LitSelectOption) { + querySelector?.addEventListener('click', (ev) => { + if (querySelector.hasAttribute('selected')) { + this.shadowRoot?.querySelectorAll('lit-select-option').forEach((a) => { + a.setAttribute('selected', ''); + this.all = true; + }); + this.itemValue.forEach((i) => { + this.showItems.push(i); + }); + this.inputElement.value = this.itemValue; + } else { + this.shadowRoot?.querySelectorAll('lit-select-option').forEach((i) => { + i.removeAttribute('selected'); + this.all = false; + }); + this.showItems = []; + this.inputElement.value = ''; + } + }); + } + + attributeChangedCallback(name: any, oldValue: any, newValue: any) {} +} diff --git a/ide/src/base-ui/slicer/lit-slicer.ts b/ide/src/base-ui/slicer/lit-slicer.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6b36b552a95ca8ac83b29dc8c2c9ce8a69707de --- /dev/null +++ b/ide/src/base-ui/slicer/lit-slicer.ts @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2022 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. + */ + +export class LitSlicer extends HTMLElement { + static get observedAttributes() { + return ['direction']; //direction = 'horizontal'或者'vertical' + } + + constructor() { + super(); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ` + +
+ +
+ `; + } + + set direction(val: any) { + if (val.startsWith('h')) { + this.shadowRoot!.querySelector('div')!.style.flexDirection = 'row'; + } else if (val.startsWith('v')) { + this.shadowRoot!.querySelector('div')!.style.flexDirection = 'column'; + } + } + + connectedCallback() {} + + disconnectedCallback() {} + + attributeChangedCallback(name: any, oldValue: any, newValue: any) { + (this as any)[name] = newValue; + } + + set style(v: any) {} +} + +if (!customElements.get('lit-slicer')) { + customElements.define('lit-slicer', LitSlicer); +} + +export class LitSlicerTrack extends HTMLElement { + private line: HTMLElement | null | undefined; + private draging: boolean = false; + private normalWidth: number = 0; + + static get observedAttributes() { + return ['range-left', 'range-right']; + } + + get rangeLeft() { + return parseInt(this.getAttribute('range-left') || '200'); + } + + set rangeLeft(val: number) { + this.setAttribute('range-left', `${val}`); + } + + get rangeRight() { + return parseInt(this.getAttribute('range-right') || '300'); + } + + set rangeRight(val: number) { + this.setAttribute('range-right', `${val}`); + } + + constructor() { + super(); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ` + +
+
+ `; + } + + //当 custom element首次被插入文档DOM时,被调用。 + connectedCallback() { + this.line = this.shadowRoot?.querySelector('#root'); + let parentDirection = this.parentElement!.getAttribute('direction') || 'horizontal'; + if (parentDirection.startsWith('h')) { + this.line!.className = 'rootH'; + let previousElementSibling = this.previousElementSibling as HTMLElement; + let preX: number, preY: number, preWidth: number; + this.line!.onmousedown = (e) => { + this.draging = true; + preX = e.pageX; + preWidth = previousElementSibling!.clientWidth; + if (this.normalWidth == 0) this.normalWidth = previousElementSibling!.clientWidth; + previousElementSibling!.style.width = preWidth + 'px'; + document.body.style.userSelect = 'none'; + document.body.style.webkitUserSelect = 'none'; + // @ts-ignore + document.body.style.msUserSelect = 'none'; + document.onmousemove = (e1) => { + if (this.draging) { + if ( + preWidth + e1.pageX - preX >= this.normalWidth - this.rangeLeft && + preWidth + e1.pageX - preX <= this.normalWidth + this.rangeRight + ) { + previousElementSibling!.style.width = preWidth + e1.pageX - preX + 'px'; + } + } + }; + document.onmouseleave = (e2) => { + this.draging = false; + document.body.style.userSelect = 'auto'; + document.body.style.webkitUserSelect = 'auto'; + // @ts-ignore + document.body.style.msUserSelect = 'auto'; + }; + document.onmouseup = (e3) => { + this.draging = false; + document.body.style.userSelect = 'auto'; + document.body.style.webkitUserSelect = 'auto'; + // @ts-ignore + document.body.style.msUserSelect = 'auto'; + }; + }; + } else { + this.line!.className = 'rootV'; + let previousElementSibling = this.previousElementSibling as HTMLElement; + let preY: number, preHeight: number; + this.line!.onmousedown = (e) => { + this.draging = true; + preY = e.pageY; + preHeight = previousElementSibling?.clientHeight; + previousElementSibling!.style!.height = preHeight + 'px'; + document.onmousemove = (e1) => { + if (this.draging) { + previousElementSibling.style.height = preHeight + e1.pageY - preY + 'px'; + } + }; + document.onmouseleave = (e2) => { + this.draging = false; + }; + document.onmouseup = (e3) => { + this.draging = false; + }; + }; + } + } + + //当 custom element从文档DOM中删除时,被调用。 + disconnectedCallback() { + this.line!.onmousedown = null; + } + + //当 custom element被移动到新的文档时,被调用。 + adoptedCallback() {} + + //当 custom element增加、删除、修改自身属性时,被调用。 + attributeChangedCallback(name: any, oldValue: any, newValue: any) {} +} + +if (!customElements.get('lit-slicer-track')) { + customElements.define('lit-slicer-track', LitSlicerTrack); +} diff --git a/ide/src/base-ui/slider/LitSlider.ts b/ide/src/base-ui/slider/LitSlider.ts new file mode 100644 index 0000000000000000000000000000000000000000..173bd1885b4114174a0fce617039c510304369b0 --- /dev/null +++ b/ide/src/base-ui/slider/LitSlider.ts @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-slider') +export class LitSlider extends BaseElement { + private litSliderStyle: LitSliderStyle | undefined | null; + private litSlider: HTMLInputElement | undefined | null; + private litSliderCon: HTMLDivElement | undefined | null; + private litResult: HTMLInputElement | undefined | null; + private slotEl: HTMLSlotElement | undefined | null; + private currentValue: number = 0; + private defaultTimeText: string | undefined | null; + + static get observedAttributes() { + return ['percent', 'disabled-X', 'custom-slider', 'custom-line', 'custom-button']; + } + + get sliderStyle(): LitSliderStyle { + if (this.litSliderStyle) { + return this.litSliderStyle; + } else { + return { + minRange: 0, + maxRange: 100, + defaultValue: '0', + resultUnit: '', + stepSize: 1, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + } + } + + set sliderStyle(value: LitSliderStyle) { + this.litSliderStyle = value; + this.currentValue = Number(value.defaultValue); + this.litSliderStyle.defaultValue = value.defaultValue; + if (this.litSliderStyle.resultUnit === 'h:m:s') { + let timeData = this.litSliderStyle.defaultValue.split(':'); + let timeSize = Number(timeData[0]) * 3600 + Number(timeData[1]) * 60 + Number(timeData[2]); + this.defaultTimeText = timeSize.toString(); + let defaultSize = + ((timeSize - this.litSliderStyle.minRange) * 100) / + (this.litSliderStyle.maxRange - this.litSliderStyle.minRange); + this.litSlider!.style.backgroundSize = defaultSize + '%'; + } else { + this.defaultTimeText = this.litSliderStyle.defaultValue; + this.litSlider!.style.backgroundSize = '0%'; + if (Number(this.litSliderStyle.defaultValue)) { + let defaultSize = + ((Number(this.litSliderStyle.defaultValue) - this.litSliderStyle.minRange) / + (this.litSliderStyle.maxRange - this.litSliderStyle.minRange)) * + 100; + this.litSlider!.style.backgroundSize = defaultSize + '%'; + } + } + let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; + let attribute = htmlInputElement.getAttribute('type'); + if (attribute === 'range') { + htmlInputElement!.setAttribute('value', this.defaultTimeText!); + htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString()); + htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString()); + htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString()); + } + } + + get disabledX() { + return this.getAttribute('disabled-X') || ''; + } + + set disabledX(value: string) { + if (value) { + this.setAttribute('disabled-X', ''); + } else { + this.removeAttribute('disabled-X'); + } + } + + get customSlider() { + return this.getAttribute('custom-slider') || ''; + } + + set customSlider(value: string) { + if (value) { + this.setAttribute('custom-slider', ''); + } else { + this.removeAttribute('custom-slider'); + } + } + + get customLine() { + return this.getAttribute('custom-line') || ''; + } + + set customLine(value: string) { + this.setAttribute('custom-line', value); + } + + get customButton() { + return this.getAttribute('custom-button') || ''; + } + + set customButton(value: string) { + this.setAttribute('custom-button', value); + } + + get percent() { + return this.getAttribute('percent') || ''; + } + + set percent(value: string) { + this.setAttribute('percent', value); + let resultNumber = + ((Number(value) - this.sliderStyle!.minRange) * 100) / (this.sliderStyle!.maxRange - this.sliderStyle!.minRange); + this.litSlider!.style.backgroundSize = resultNumber + '%'; + } + + get resultUnit() { + return this.getAttribute('resultUnit') || ''; + } + + set resultUnit(value: string) { + this.setAttribute('resultUnit', value); + } + + initElements(): void { + this.litSlider = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; + } + + initHtml(): string { + return ` + + +
+ +
+ `; + } + + // It is called when the custom element is first inserted into the document DOM. + connectedCallback() { + this.slotEl = this.shadowRoot?.querySelector('#slot'); + this.litSliderCon = this.shadowRoot?.querySelector('#slider-con'); + // Add a slider for input event listeners + this.litSlider?.addEventListener('input', this.inputChangeEvent); + this.litSlider?.addEventListener('change', this.inputChangeEvent); + this.litSliderStyle = this.sliderStyle; + } + + inputChangeEvent = (event: any) => { + if (this.litSlider) { + this.currentValue = parseInt(this.litSlider?.value); + let resultNumber = + ((this.currentValue - this.litSliderStyle!.minRange) * 100) / + (this.litSliderStyle!.maxRange - this.litSliderStyle!.minRange); + this.percent = Number(resultNumber) + '%'; + this.litSliderCon?.style.setProperty('percent', this.currentValue + '%'); + let parentElement = this.parentNode as Element; + parentElement.setAttribute('percent', this.currentValue + ''); + if (this.sliderStyle.resultUnit === 'h:m:s') { + this.litSlider!.style.backgroundSize = this.percent; + } else { + this.litSlider!.style.backgroundSize = this.percent; + } + this.parentElement!.setAttribute('percent', this.litSlider?.value); + } + }; + + disconnectedCallback() { + this.litSlider?.removeEventListener('input', this.inputChangeEvent); + this.litSlider?.removeEventListener('change', this.inputChangeEvent); + } + + adoptedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'percent': + if (newValue === null || newValue === '0%') { + let parentElement = this.parentNode as Element; + parentElement?.removeAttribute('percent'); + } else { + let parentElement = this.parentNode as Element; + } + break; + default: + break; + } + } + + renderDefaultSlider() { + let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; + let attribute = htmlInputElement.getAttribute('type'); + if (attribute === 'range') { + htmlInputElement!.setAttribute('value', this.defaultTimeText!); + htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString()); + htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString()); + htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString()); + } + } + + formatSeconds(value: string) { + let result = parseInt(value); + let hours = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600); + let minute = + Math.floor((result / 60) % 60) < 10 ? '0' + Math.floor((result / 60) % 60) : Math.floor((result / 60) % 60); + let second = Math.floor(result % 60) < 10 ? '0' + Math.floor(result % 60) : Math.floor(result % 60); + let resultTime = ''; + if (hours === '00') { + resultTime += `00:`; + } else { + resultTime += `${hours}:`; + } + if (minute === '00') { + resultTime += `00:`; + } else { + resultTime += `${minute}:`; + } + resultTime += `${second}`; + return resultTime; + } +} + +export interface LitSliderStyle { + minRange: number; + maxRange: number; + defaultValue: string; + resultUnit: string; + stepSize: number; + lineColor?: string; + buttonColor?: string; +} + +export interface LitSliderLineStyle { + lineWith: number; + lineHeight: number; + border?: string; + borderRadiusValue?: number; + lineChangeColor?: string; +} + +export interface LitSliderButtonStyle { + buttonWith: number; + buttonHeight: number; + border?: string; + borderRadiusValue?: number; + buttonChangeColor?: string; +} diff --git a/ide/src/base-ui/switch/lit-switch.ts b/ide/src/base-ui/switch/lit-switch.ts new file mode 100644 index 0000000000000000000000000000000000000000..2355109c8ba05ae212c4a0ee1a92fd493515badc --- /dev/null +++ b/ide/src/base-ui/switch/lit-switch.ts @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; + +@element('lit-switch') +export default class LitSwitch extends BaseElement { + private switch: HTMLInputElement | null | undefined; + private isfocus: boolean | undefined; + + static get observedAttributes() { + return ['disabled', 'checked']; + } + + get disabled() { + return this.getAttribute('disabled') !== null; + } + + set disabled(value) { + if (value === null || value === false) { + this.removeAttribute('disabled'); + } else { + this.setAttribute('disabled', ''); + } + } + + get checked() { + return this.getAttribute('checked') !== null; + } + + set checked(value) { + if (value === null || value === false) { + this.removeAttribute('checked'); + } else { + this.setAttribute('checked', ''); + } + } + + get name() { + return this.getAttribute('name'); + } + + initElements(): void {} + + initHtml(): string { + return ` + + + `; + } + + connectedCallback() { + this.switch = this.shadowRoot?.getElementById('switch') as HTMLInputElement; + this.disabled = this.disabled; + this.checked = this.checked; + this.switch!.onchange = (ev) => { + this.checked = this.switch!.checked; + this.dispatchEvent(new CustomEvent('change', { detail: { checked: this.checked } })); + }; + this.switch.onkeydown = (ev) => { + switch (ev.keyCode) { + case 13: //enter + this.checked = !this.checked; + this.dispatchEvent( + new CustomEvent('change', { + detail: { checked: this.checked }, + }) + ); + break; + default: + break; + } + }; + this.switch.onfocus = (ev) => { + ev.stopPropagation(); + if (!this.isfocus) { + this.dispatchEvent( + new CustomEvent('focus', { + detail: { value: this.switch!.value }, + }) + ); + } + }; + this.switch.onblur = (ev) => { + ev.stopPropagation(); + if (getComputedStyle(this.switch!).zIndex == '2') { + this.isfocus = true; + } else { + this.isfocus = false; + this.dispatchEvent( + new CustomEvent('blur', { + detail: { value: this.switch!.value }, + }) + ); + } + }; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name === 'disabled' && this.switch) { + if (newValue !== null) { + this.switch.setAttribute('disabled', ''); + } else { + this.switch.removeAttribute('disabled'); + } + } + if (name === 'checked' && this.switch) { + if (newValue !== null) { + this.switch.checked = true; + } else { + this.switch.checked = false; + } + } + } +} diff --git a/ide/src/base-ui/table/TableRowObject.ts b/ide/src/base-ui/table/TableRowObject.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f4fa47a8e748b927589d65d507e0cd064832c5c --- /dev/null +++ b/ide/src/base-ui/table/TableRowObject.ts @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 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. + */ + +export class TableRowObject { + public top: number = 0; + public height: number = 0; + public rowIndex: number = 0; + public data: any | undefined; + public expanded: boolean = true; + public rowHidden: boolean = false; + public children: any[] = []; + public depth: number = -1; +} diff --git a/ide/src/base-ui/table/lit-table-column.ts b/ide/src/base-ui/table/lit-table-column.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba00a4d3a172503aeecd742fea0b1353657570e7 --- /dev/null +++ b/ide/src/base-ui/table/lit-table-column.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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 { element } from '../BaseElement.js'; + +@element('lit-table-column') +export class LitTableColumn extends HTMLElement { + template: Element | undefined | null; + private st: HTMLSlotElement | undefined | null; + + constructor() { + super(); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ` + + + `; + } + + static get observedAttributes() { + return ['name', 'order']; + } + + connectedCallback() { + this.template = null; + this.st = this.shadowRoot?.querySelector('#slot'); + this.st?.addEventListener('slotchange', () => { + const elements = this.st!.assignedElements({ flatten: false }); + if (elements!.length > 0) { + this.template = elements[0]; + } + }); + } + + disconnectedCallback() {} + + adoptedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) {} +} diff --git a/ide/src/base-ui/table/lit-table-group.ts b/ide/src/base-ui/table/lit-table-group.ts new file mode 100644 index 0000000000000000000000000000000000000000..700e5a81c06fa197ecc7197d058fce6f297a3bc6 --- /dev/null +++ b/ide/src/base-ui/table/lit-table-group.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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 { element } from '../BaseElement.js'; + +@element('lit-table-group') +export class LitTableGroup extends HTMLElement { + constructor() { + super(); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ` + + + `; + } + + static get observedAttributes() { + return ['title']; + } + + get title() { + return this.getAttribute('title') || ''; + } + + set title(value: string) { + this.setAttribute('title', value); + } + + connectedCallback() {} + + disconnectedCallback() {} + + adoptedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) {} +} diff --git a/ide/src/base-ui/table/lit-table.ts b/ide/src/base-ui/table/lit-table.ts new file mode 100644 index 0000000000000000000000000000000000000000..e46ac49d2224560102edd28adde6b353644f13d3 --- /dev/null +++ b/ide/src/base-ui/table/lit-table.ts @@ -0,0 +1,1751 @@ +/* + * Copyright (C) 2022 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 { LitTableColumn } from './lit-table-column.js'; +import { LitProgressBar } from './../progress-bar/LitProgressBar.js'; +import { element } from '../BaseElement.js'; +import '../utils/Template.js'; +import { TableRowObject } from './TableRowObject.js'; +import { ExcelFormater } from '../utils/ExcelFormater.js'; +import { JSonToCSV } from '../utils/CSVFormater.js'; +import { LitIcon } from '../icon/LitIcon.js'; + +@element('lit-table') +export class LitTable extends HTMLElement { + meauseRowElement: HTMLDivElement | undefined; + currentRecycleList: HTMLDivElement[] = []; + currentTreeDivList: HTMLDivElement[] = []; + public rememberScrollTop = false; + private ds: Array = []; + private recycleDs: Array = []; + private normalDs: Array = []; + private gridTemplateColumns: any; + /*Grid css layout descriptions are obtained according to the clustern[] nested structure*/ + private st: HTMLSlotElement | null | undefined; + private tableElement: HTMLDivElement | null | undefined; + private exportProgress: LitProgressBar | null | undefined; + private theadElement: HTMLDivElement | null | undefined; + private columns: Array | null | undefined; + private tbodyElement: HTMLDivElement | undefined | null; + private treeElement: HTMLDivElement | undefined | null; + private tableColumns: NodeListOf | undefined; + private colCount: number = 0; + private currentScrollTop: number = 0; + private isRecycleList: boolean = true; + private isScrollXOutSide: boolean = false; + private exportLoading: boolean = false; + + constructor() { + super(); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ` + + + + +
+ +
+
+
+
+
+
+
+
+ `; + } + + static get observedAttributes() { + return ['scroll-y', 'selectable', 'no-head', 'grid-line', 'defaultOrderColumn', 'hideDownload']; + } + + get hideDownload() { + return this.hasAttribute('hideDownload'); + } + + set hideDownload(value) { + if (value) { + this.setAttribute('hideDownload', ''); + } else { + this.removeAttribute('hideDownload'); + } + } + + get selectable() { + return this.hasAttribute('selectable'); + } + + set selectable(value) { + if (value) { + this.setAttribute('selectable', ''); + } else { + this.removeAttribute('selectable'); + } + } + + get scrollY() { + return this.getAttribute('scroll-y') || 'auto'; + } + + set scrollY(value) { + this.setAttribute('scroll-y', value); + } + + get dataSource() { + return this.ds || []; + } + + set dataSource(value) { + this.ds = value; + this.isRecycleList = false; + if (this.hasAttribute('tree')) { + this.renderTreeTable(); + } else { + this.renderTable(); + } + } + + get recycleDataSource() { + return this.ds || []; + } + + set recycleDataSource(value) { + this.isScrollXOutSide = this.tableElement!.scrollWidth > this.tableElement!.clientWidth; + this.isRecycleList = true; + this.ds = value; + if (this.rememberScrollTop) { + this.currentScrollTop = this.tableElement!.scrollTop; + this.tableElement!.scrollTop = 0; + } else { + this.tableElement!.scrollTop = 0; + } + if (this.hasAttribute('tree')) { + this.recycleDs = this.meauseTreeRowElement(value); + } else { + this.recycleDs = this.meauseAllRowHeight(value); + } + } + + get snapshotDataSource() { + return this.ds || []; + } + + set snapshotDataSource(value) { + this.ds = value; + if (this.hasAttribute('tree')) { + this.recycleDs = this.meauseTreeRowElement(value); + } else { + this.recycleDs = this.meauseAllRowHeight(value); + } + } + + move1px() { + this.tableElement!.scrollTop = this.tableElement!.scrollTop + 1; + } + + dataExportInit() { + let exportDiv = this.shadowRoot!.querySelector('.export'); + exportDiv && + (exportDiv.onclick = () => { + this.exportData(); + }); + } + + exportData() { + if (this.exportLoading) { + return; + } + this.exportLoading = true; + this.exportProgress!.loading = true; + let date = new Date(); + JSonToCSV.csvExport({ + columns: this.columns as any[], + tables: this.ds, + fileName: date.getTime() + '', + }).then((res) => { + this.exportLoading = false; + this.exportProgress!.loading = false; + }); + } + + exportExcelData() { + let now = Date.now(); + ExcelFormater.testExport( + [ + { + columns: this.columns as any[], + tables: this.ds, + sheetName: now + '', + }, + ], + now + '' + ); + } + + formatExportData(dataSource: any[]): any[] { + if (dataSource == undefined || dataSource.length == 0) { + return []; + } + if (this.columns == undefined) { + return []; + } + return dataSource.map((item) => { + let formatData: any = {}; + this.columns!.forEach((column) => { + let dataIndex = column.getAttribute('data-index'); + let columnName = column.getAttribute('title'); + if (columnName == '') { + columnName = dataIndex; + } + if (dataIndex && columnName && item[dataIndex] != undefined) { + formatData[columnName] = item[dataIndex]; + } + }); + if (item.children != undefined) { + formatData.children = this.formatExportData(item.children); + } + return formatData; + }); + } + + formatExportCsvData(dataSource: any[]): string { + if (dataSource == undefined || dataSource.length == 0) { + return ''; + } + if (this.columns == undefined) { + return ''; + } + let str = ''; + str += this.columns!.map((column) => { + let dataIndex = column.getAttribute('data-index'); + let columnName = column.getAttribute('title'); + if (columnName == '') { + columnName = dataIndex; + } + return columnName; + }).join(','); + str += this.recursionExportTableData(this.columns, dataSource); + return str; + } + + recursionExportTableData(columns: any[], dataSource: any[]): string { + let concatStr = '\r\n'; + dataSource.forEach((item, index) => { + concatStr += columns + .map((column) => { + let dataIndex = column.getAttribute('data-index'); + return `"${item[dataIndex] || ''}" `; + }) + .join(','); + if (item.children != undefined) { + concatStr += this.recursionExportTableData(columns, item.children); + } + if (index != dataSource.length - 1) { + concatStr += '\r\n'; + } + }); + return concatStr; + } + + //当 custom element首次被插入文档DOM时,被调用。 + connectedCallback() { + this.st = this.shadowRoot?.querySelector('#slot'); + this.tableElement = this.shadowRoot?.querySelector('.table'); + this.exportProgress = this.shadowRoot?.querySelector('#export_progress_bar'); + this.theadElement = this.shadowRoot?.querySelector('.thead'); + this.treeElement = this.shadowRoot?.querySelector('.tree'); + this.tbodyElement = this.shadowRoot?.querySelector('.body'); + this.tableColumns = this.querySelectorAll('lit-table-column'); + this.colCount = this.tableColumns!.length; + this.dataExportInit(); + this.tableElement?.addEventListener('copy', (e) => { + // @ts-ignore + let clipboardData = e.clipboardData || window.clipboardData; + if (!clipboardData) return; + // @ts-ignore + let text = window.getSelection().toString(); + if (text) { + e.preventDefault(); + let length = this.tableColumns?.length || 1; + let strings = text.split('\n'); + let formatStr = ''; + for (let i = 0; i < strings.length; i++) { + if (i % length != 0) { + formatStr += ' '; + } + formatStr += strings[i]; + if (i != 0 && i % length == length - 1) { + formatStr += '\n'; + } + } + clipboardData.setData('text/plain', formatStr); + } + }); + this.st?.addEventListener('slotchange', () => { + this.theadElement!.innerHTML = ''; + setTimeout(() => { + this.columns = this.st!.assignedElements(); + let rowElement = document.createElement('div'); + rowElement.classList.add('th'); + if (this.selectable) { + let box = document.createElement('div'); + box.style.display = 'flex'; + box.style.justifyContent = 'center'; + box.style.alignItems = 'center'; + box.style.gridArea = '_checkbox_'; + box.classList.add('td'); + box.style.backgroundColor = '#ffffff66'; + let checkbox = document.createElement('lit-checkbox'); + checkbox.classList.add('row-checkbox-all'); + checkbox.onchange = (e: any) => { + this.shadowRoot!.querySelectorAll('.row-checkbox').forEach((a: any) => (a.checked = e.detail.checked)); + if (e.detail.checked) { + this.shadowRoot!.querySelectorAll('.tr').forEach((a) => a.setAttribute('checked', '')); + } else { + this.shadowRoot!.querySelectorAll('.tr').forEach((a) => a.removeAttribute('checked')); + } + }; + box.appendChild(checkbox); + rowElement.appendChild(box); + } + let area: Array = [], + gridTemplateColumns: Array = []; + let resolvingArea = (columns: any, x: any, y: any) => { + columns.forEach((a: any, i: any) => { + if (!area[y]) area[y] = []; + let key = a.getAttribute('key') || a.getAttribute('title'); + if (a.tagName === 'LIT-TABLE-GROUP') { + let len = a.querySelectorAll('lit-table-column').length; + let children = [...a.children].filter((a) => a.tagName !== 'TEMPLATE'); + if (children.length > 0) { + resolvingArea(children, x, y + 1); + } + for (let j = 0; j < len; j++) { + area[y][x] = { x, y, t: key }; + x++; + } + let h = document.createElement('div'); + h.classList.add('td'); + h.style.justifyContent = a.getAttribute('align'); + h.style.borderBottom = '1px solid #f0f0f0'; + h.style.gridArea = key; + h.innerText = a.title; + if (a.hasAttribute('fixed')) { + this.fixed(h, a.getAttribute('fixed'), '#42b983'); + } + rowElement.append(h); + } else if (a.tagName === 'LIT-TABLE-COLUMN') { + area[y][x] = { x, y, t: key }; + x++; + let h: any = document.createElement('div'); + h.classList.add('td'); + if (a.hasAttribute('order')) { + h.sortType = 0; + h.classList.add('td-order'); + h.style.position = 'relative'; + let NS = 'http://www.w3.org/2000/svg'; + let upSvg: any = document.createElementNS(NS, 'svg'); + let upPath: any = document.createElementNS(NS, 'path'); + upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + upSvg.setAttribute('viewBox', '0 0 1024 1024'); + upSvg.setAttribute('stroke', 'let(--dark-color1,#212121)'); + upSvg.classList.add('up-svg'); + upPath.setAttribute( + 'd', + 'M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z' + ); + upSvg.appendChild(upPath); + let downSvg: any = document.createElementNS(NS, 'svg'); + let downPath: any = document.createElementNS(NS, 'path'); + downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + downSvg.setAttribute('viewBox', '0 0 1024 1024'); + downSvg.setAttribute('stroke', 'let(--dark-color1,#212121)'); + downSvg.classList.add('down-svg'); + downPath.setAttribute( + 'd', + 'M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z' + ); + downSvg.appendChild(downPath); + if (i == 0) { + h.sortType = 0; // 默认以第一列 降序排序 作为默认排序 + upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + } + upSvg.style.display = 'none'; + downSvg.style.display = 'none'; + h.appendChild(upSvg); + h.appendChild(downSvg); + h.onclick = () => { + this?.shadowRoot?.querySelectorAll('.td-order svg').forEach((it: any) => { + it.setAttribute('fill', 'let(--dark-color1,#212121)'); + it.sortType = 0; + it.style.display = 'none'; + }); + if (h.sortType == undefined || h.sortType == null) { + h.sortType = 0; + } else if (h.sortType === 2) { + h.sortType = 0; + } else { + h.sortType += 1; + } + switch (h.sortType) { + case 1: + this.theadElement!.setAttribute('sort', ''); + upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + upSvg.style.display = 'block'; + downSvg.style.display = 'none'; + break; + case 2: + upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + upSvg.style.display = 'none'; + downSvg.style.display = 'block'; + break; + default: + upSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + downSvg.setAttribute('fill', 'let(--dark-color1,#212121)'); + upSvg.style.display = 'none'; + downSvg.style.display = 'none'; + this.theadElement!.removeAttribute('sort'); + break; + } + this.dispatchEvent( + new CustomEvent('column-click', { + detail: { + sort: h.sortType, + key: key, + }, + composed: true, + }) + ); + }; + } + h.style.justifyContent = a.getAttribute('align'); + gridTemplateColumns.push(a.getAttribute('width') || '1fr'); + h.style.gridArea = key; + let titleLabel = document.createElement('label'); + titleLabel.textContent = a.title; + h.appendChild(titleLabel); + if (a.hasAttribute('fixed')) { + this.fixed(h, a.getAttribute('fixed'), '#42b983'); + } + rowElement.append(h); + } + }); + }; + resolvingArea(this.columns, 0, 0); + area.forEach((rows, j, array) => { + for (let i = 0; i < this.colCount; i++) { + if (!rows[i]) rows[i] = array[j - 1][i]; + } + }); + this.gridTemplateColumns = gridTemplateColumns.join(' '); + if (this.selectable) { + let s = area.map((a) => '"_checkbox_ ' + a.map((aa: any) => aa.t).join(' ') + '"').join(' '); + rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' '); + rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`; + rowElement.style.gridTemplateAreas = s; + } else { + let s = area.map((a) => '"' + a.map((aa: any) => aa.t).join(' ') + '"').join(' '); + rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); + rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)`; + rowElement.style.gridTemplateAreas = s; + } + this.theadElement!.innerHTML = ''; + this.theadElement!.append(rowElement); + this.treeElement!.style.top = this.theadElement?.clientHeight + 'px'; + }); + }); + + this.shadowRoot!.addEventListener('load', function (event) {}); + this.tableElement!.addEventListener('mouseout', (ev) => this.mouseOut()); + } + + // Is called when the custom element is removed from the document DOM. + disconnectedCallback() {} + + // It is called when the custom element is moved to a new document. + adoptedCallback() {} + + // It is called when a custom element adds, deletes, or modifies its own properties. + attributeChangedCallback(name: string, oldValue: string, newValue: string) {} + + fixed(td: HTMLElement, placement: string, bgColor: string) { + td.style.position = 'sticky'; + if (placement === 'left') { + td.style.left = '0px'; + td.style.boxShadow = '3px 0px 5px #33333333'; + } else if (placement === 'right') { + td.style.right = '0px'; + td.style.boxShadow = '-3px 0px 5px #33333333'; + } + } + + renderTable() { + if (!this.columns) return; + if (!this.ds) return; // If no data source is set, it is returned directly + this.normalDs = []; + this.tbodyElement!.innerHTML = ''; // Clear the table contents + this.ds.forEach((rowData: any) => { + let rowElement = document.createElement('div'); + rowElement.classList.add('tr'); + // @ts-ignore + rowElement.data = rowData; + let gridTemplateColumns: Array = []; + // If the table is configured with selectable (select row mode) add a checkbox at the head of the line alone + if (this.selectable) { + let box = document.createElement('div'); + box.style.display = 'flex'; + box.style.justifyContent = 'center'; + box.style.alignItems = 'center'; + box.classList.add('td'); + let checkbox = document.createElement('lit-checkbox'); + checkbox.classList.add('row-checkbox'); + checkbox.onchange = (e: any) => { + // Checkbox checking affects whether the div corresponding to the row has a checked attribute for marking + if (e.detail.checked) { + rowElement.setAttribute('checked', ''); + } else { + rowElement.removeAttribute('checked'); + } + }; + box.appendChild(checkbox); + rowElement.appendChild(box); + } + this.tableColumns!.forEach((cl) => { + let dataIndex = cl.getAttribute('data-index') || '1'; + gridTemplateColumns.push(cl.getAttribute('width') || '1fr'); + if (cl.template) { + // If you customize the rendering, you get the nodes from the template + // @ts-ignore + let cloneNode = cl.template.render(rowData).content.cloneNode(true); + let d = document.createElement('div'); + d.classList.add('td'); + d.style.wordBreak = 'break-all'; + d.style.whiteSpace = 'pre-wrap'; + d.style.justifyContent = cl.getAttribute('align') || ''; + if (cl.hasAttribute('fixed')) { + this.fixed(d, cl.getAttribute('fixed') || '', '#ffffff'); + } + d.append(cloneNode); + rowElement.append(d); + } else { + let td = document.createElement('div'); + td.classList.add('td'); + td.style.wordBreak = 'break-all'; + td.style.whiteSpace = 'pre-wrap'; + td.title = rowData[dataIndex]; + td.style.justifyContent = cl.getAttribute('align') || ''; + if (cl.hasAttribute('fixed')) { + this.fixed(td, cl.getAttribute('fixed') || '', '#ffffff'); + } + td.innerHTML = this.formatName(rowData[dataIndex]); + rowElement.append(td); + } + }); + if (this.selectable) { + // If the table with selection is preceded by a 60px column + rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' '); + } else { + rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); + } + rowElement.onclick = (e) => { + this.dispatchEvent( + new CustomEvent('row-click', { + detail: { + rowData, + data: rowData, + callBack: (isSelected: boolean) => { + //是否爲单选 + if (isSelected) { + this.clearAllSelection(rowData); + } + this.setSelectedRow(rowData.isSelected, [rowElement]); + }, + }, + composed: true, + }) + ); + }; + this.normalDs.push(rowElement); + this.tbodyElement!.append(rowElement); + }); + } + + renderTreeTable() { + if (!this.columns) return; + if (!this.ds) return; + this.tbodyElement!.innerHTML = ''; + this.treeElement!.innerHTML = ''; + let ids = JSON.parse(this.getAttribute('tree') || `["id","pid"]`); + let toTreeData = (data: any, id: any, pid: any) => { + let cloneData = JSON.parse(JSON.stringify(data)); + return cloneData.filter((father: any) => { + let branchArr = cloneData.filter((child: any) => father[id] == child[pid]); + branchArr.length > 0 ? (father['children'] = branchArr) : ''; + return !father[pid]; + }); + }; + let treeData = toTreeData(this.ds, ids[0], ids[1]); + let offset = 30; + let offsetVal = offset; + const drawRow = (arr: any, parentNode: any) => { + arr.forEach((rowData: any) => { + let rowElement = document.createElement('div'); + rowElement.classList.add('tr'); + // @ts-ignore + rowElement.data = rowData; + let gridTemplateColumns: Array = []; + if (this.selectable) { + let box = document.createElement('div'); + box.style.display = 'flex'; + box.style.justifyContent = 'center'; + box.style.alignItems = 'center'; + box.classList.add('td'); + let checkbox = document.createElement('lit-checkbox'); + checkbox.classList.add('row-checkbox'); + checkbox.onchange = (e: any) => { + if (e.detail.checked) { + rowElement.setAttribute('checked', ''); + } else { + rowElement.removeAttribute('checked'); + } + const changeChildNode = (rowElement: any, checked: any) => { + let id = rowElement.getAttribute('id'); + let pid = rowElement.getAttribute('pid'); + this.shadowRoot!.querySelectorAll(`div[pid=${id}]`).forEach((a) => { + // @ts-ignore + a.querySelector('.row-checkbox')!.checked = checked; + if (checked) { + a.setAttribute('checked', ''); + } else { + a.removeAttribute('checked'); + } + changeChildNode(a, checked); + }); + }; + changeChildNode(rowElement, e.detail.checked); + }; + box.appendChild(checkbox); + rowElement.appendChild(box); + } + this.tableColumns!.forEach((cl, index) => { + let dataIndex = cl.getAttribute('data-index'); + let td; + if (index !== 0) { + gridTemplateColumns.push(cl.getAttribute('width') || '1fr'); + if (cl.template) { + // @ts-ignore + let cloneNode = cl.template.render(rowData).content.cloneNode(true); + td = document.createElement('div'); + td.classList.add('td'); + td.style.wordBreak = 'break-all'; + td.style.justifyContent = cl.getAttribute('align') || ''; + if (cl.hasAttribute('fixed')) { + this.fixed(td, cl.getAttribute('fixed') || '', '#ffffff'); + } + td.append(cloneNode); + } else { + td = document.createElement('div'); + td.classList.add('td'); + td.style.wordBreak = 'break-all'; + td.style.justifyContent = cl.getAttribute('align') || ''; + if (cl.hasAttribute('fixed')) { + this.fixed(td, cl.getAttribute('fixed') || '', '#ffffff'); + } + // @ts-ignore + td.innerHTML = this.formatName(rowData[dataIndex]); + } + rowElement.append(td); + } else { + this.treeElement!.style.width = cl.getAttribute('width') || '260px'; + let treeElement = document.createElement('div'); + treeElement.classList.add('tree-first-body'); + if (cl.template) { + // @ts-ignore + let cloneNode = cl.template.render(rowData).content.cloneNode(true); + td = document.createElement('div'); + td.classList.add('td'); + td.style.justifyContent = cl.getAttribute('align') || ''; + if (cl.hasAttribute('fixed')) { + this.fixed(td, cl.getAttribute('fixed') || '', '#ffffff'); + } + td.append(cloneNode); + } else { + td = document.createElement('div'); + td.classList.add('td'); + td.style.justifyContent = cl.getAttribute('align') || ''; + if (cl.hasAttribute('fixed')) { + this.fixed(td, cl.getAttribute('fixed') || '', '#ffffff'); + } + // @ts-ignore + td.innerHTML = this.formatName(rowData[dataIndex]); + } + if (rowData.children && rowData.children.length > 0) { + let btn = document.createElement('lit-icon'); + btn.classList.add('tree-icon'); + // @ts-ignore + btn.name = 'minus-square'; + treeElement.append(btn); + treeElement.append(td); + treeElement.style.paddingLeft = offsetVal - 30 + 'px'; + } else { + treeElement.append(td); + treeElement.style.paddingLeft = offsetVal + 'px'; + } + this.treeElement!.append(treeElement); + } + }); + if (this.selectable) { + rowElement.style.gridTemplateColumns = '60px ' + gridTemplateColumns.join(' '); + } else { + rowElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); + } + rowElement.onclick = (e) => { + this.dispatchEvent( + new CustomEvent('row-click', { + detail: rowData, + composed: true, + }) + ); + }; + rowElement.style.cursor = 'pointer'; + parentNode.append(rowElement); + rowElement.setAttribute('id', rowData[ids[0]]); + rowElement.setAttribute('pid', rowData[ids[1]]); + rowElement.setAttribute('expend', ''); + if (rowData.children && rowData.children.length > 0) { + offsetVal = offsetVal + offset; + drawRow(rowData.children, parentNode); + offsetVal = offsetVal - offset; + } + }); + }; + drawRow(treeData, this.tbodyElement); + } + + getCheckRows() { + // @ts-ignore + return [...this.shadowRoot!.querySelectorAll('div[class=tr][checked]')] + .map((a) => (a as any).data) + .map((a) => { + delete a['children']; + return a; + }); + } + + deleteRowsCondition(fn: any) { + this.shadowRoot!.querySelectorAll('div[class=tr]').forEach((tr) => { + // @ts-ignore + if (fn(tr.data)) { + tr.remove(); + } + }); + } + + meauseElementHeight(rowData: any) { + return 27; + } + + meauseTreeElementHeight(rowData: any, depth: number) { + return 27; + } + + meauseAllRowHeight(list: any[]): TableRowObject[] { + this.tbodyElement!.innerHTML = ''; + this.meauseRowElement = undefined; + let head = this.shadowRoot!.querySelector('.th'); + this.tbodyElement && (this.tbodyElement.style.width = head?.clientWidth + 'px'); + this.currentRecycleList = []; + let headHeight = 0; + let totalHeight = headHeight; + let visibleObjects: TableRowObject[] = []; + list.forEach((rowData, index) => { + let height = this.meauseElementHeight(rowData); + let tableRowObject = new TableRowObject(); + tableRowObject.height = height; + tableRowObject.top = totalHeight; + tableRowObject.data = rowData; + tableRowObject.rowIndex = index; + if ( + Math.max(totalHeight, this.tableElement!.scrollTop + headHeight) <= + Math.min(totalHeight + height, this.tableElement!.scrollTop + this.tableElement!.clientHeight + headHeight) + ) { + let newTableElement = this.createNewTableElement(tableRowObject); + newTableElement.style.transform = `translateY(${totalHeight}px)`; + this.tbodyElement?.append(newTableElement); + this.currentRecycleList.push(newTableElement); + } + totalHeight += height; + visibleObjects.push(tableRowObject); + }); + this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px'); + this.tableElement && + (this.tableElement.onscroll = (event) => { + let top = this.tableElement!.scrollTop; + let skip = 0; + for (let i = 0; i < visibleObjects.length; i++) { + if (visibleObjects[i].top <= top && visibleObjects[i].top + visibleObjects[i].height >= top) { + skip = i; + break; + } + } + let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); + if (reduce == 0) { + return; + } + while (reduce <= this.tableElement!.clientHeight) { + let newTableElement = this.createNewTableElement(visibleObjects[skip]); + this.tbodyElement?.append(newTableElement); + this.currentRecycleList.push(newTableElement); + reduce += newTableElement.clientHeight; + } + for (let i = 0; i < this.currentRecycleList.length; i++) { + this.freshCurrentLine(this.currentRecycleList[i], visibleObjects[i + skip]); + } + }); + return visibleObjects; + } + + meauseTreeRowElement(list: any[]): TableRowObject[] { + this.meauseRowElement = undefined; + this.tbodyElement!.innerHTML = ''; + this.treeElement!.innerHTML = ''; + let headHeight = this.theadElement?.clientHeight || 0; + let totalHeight = 0; + let visibleObjects: TableRowObject[] = []; + this.currentRecycleList = []; + this.currentTreeDivList = []; + let resetAllHeight = (list: any[], depth: number, parentNode?: TableRowObject) => { + list.forEach((item) => { + let tableRowObject = new TableRowObject(); + tableRowObject.depth = depth; + tableRowObject.data = item; + tableRowObject.top = totalHeight; + tableRowObject.height = this.meauseTreeElementHeight(tableRowObject, depth); + if (parentNode != undefined) { + parentNode.children.push(tableRowObject); + } + if ( + Math.max(totalHeight, this.tableElement!.scrollTop) <= + Math.min( + totalHeight + tableRowObject.height, + this.tableElement!.scrollTop + this.tableElement!.clientHeight - headHeight + ) + ) { + let newTableElement = this.createNewTreeTableElement(tableRowObject); + newTableElement.style.transform = `translateY(${totalHeight}px)`; + this.tbodyElement?.append(newTableElement); + if (this.treeElement?.lastChild) { + (this.treeElement?.lastChild as HTMLElement).style.height = tableRowObject.height + 'px'; + } + this.currentRecycleList.push(newTableElement); + } + totalHeight += tableRowObject.height; + visibleObjects.push(tableRowObject); + if (item.hasNext) { + if (item.parents != undefined && item.parents.length > 0 && item.status) { + resetAllHeight(item.parents, depth + 1, tableRowObject); + } else if (item.children != undefined && item.children.length > 0 && item.status) { + resetAllHeight(item.children, depth + 1, tableRowObject); + } + } else { + if (item.children != undefined && item.children.length > 0) { + resetAllHeight(item.children, depth + 1, tableRowObject); + } + } + }); + }; + resetAllHeight(list, 0); + this.tbodyElement && (this.tbodyElement.style.height = totalHeight + 'px'); + this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px'; + this.tableElement && + (this.tableElement.onscroll = (event) => { + let visibleObjects = this.recycleDs.filter((item) => { + return !item.rowHidden; + }); + let top = this.tableElement!.scrollTop; + this.treeElement!.style.transform = `translateY(${top}px)`; + let skip = 0; + for (let i = 0; i < visibleObjects.length; i++) { + if (visibleObjects[i].top <= top && visibleObjects[i].top + visibleObjects[i].height >= top) { + skip = i; + break; + } + } + let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); + if (reduce == 0) { + return; + } + while (reduce <= this.tableElement!.clientHeight) { + let newTableElement = this.createNewTreeTableElement(visibleObjects[skip]); + this.tbodyElement?.append(newTableElement); + if (this.treeElement?.lastChild) { + (this.treeElement?.lastChild as HTMLElement).style.height = visibleObjects[skip].height + 'px'; + } + this.currentRecycleList.push(newTableElement); + reduce += newTableElement.clientHeight; + } + for (let i = 0; i < this.currentRecycleList.length; i++) { + this.freshCurrentLine( + this.currentRecycleList[i], + visibleObjects[i + skip], + this.treeElement?.children[i] as HTMLElement + ); + } + }); + return visibleObjects; + } + + createNewTreeTableElement(rowData: TableRowObject): any { + let newTableElement = document.createElement('div'); + newTableElement.classList.add('tr'); + let gridTemplateColumns: Array = []; + let treeTop = 0; + if (this.treeElement!.children?.length > 0) { + let transX = Number((this.treeElement?.lastChild as HTMLElement).style.transform.replace(/[^0-9]/gi, '')); + treeTop += transX + rowData.height; + } + this?.columns?.forEach((column: any, index) => { + let dataIndex = column.getAttribute('data-index') || '1'; + let td: any; + if (index === 0) { + if (column.template) { + td = column.template.render(rowData.data).content.cloneNode(true); + td.template = column.template; + } else { + td = document.createElement('div'); + td.innerHTML = this.formatName(rowData.data[dataIndex]); + td.dataIndex = dataIndex; + } + if (rowData.data.children && rowData.data.children.length > 0) { + let btn = this.createExpandBtn(rowData); + td.title = rowData.data.objectName; + td.insertBefore(btn, td.firstChild); + td.style.paddingLeft = rowData.depth * 15 + 'px'; + } else if (rowData.data.hasNext) { + td.title = rowData.data.objectName; + let btn = this.createBtn(rowData); + td.insertBefore(btn, td.firstChild); + td.style.paddingLeft = 15 * rowData.depth + 'px'; + btn.onclick = () => { + let indexOf = this.currentTreeDivList.indexOf(td); + this.dispatchRowClickEventIcon(rowData, [this.treeElement?.children[indexOf].children[indexOf] as LitIcon]); + }; + } else { + td.style.paddingLeft = rowData.depth * 15 + 20 + 'px'; + } + (td as any).data = rowData.data; + td.classList.add('tree-first-body'); + td.style.position = 'absolute'; + td.style.top = '0px'; + td.style.left = '0px'; + td.onmouseenter = () => { + let indexOf = this.currentTreeDivList.indexOf(td); + this.currentRecycleList.forEach((row) => { + row.classList.remove('mouse-in'); + }); + if (indexOf >= 0 && indexOf < this.currentRecycleList.length && td.innerHTML != '') { + this.setMouseIn(true, [newTableElement]); + } + }; + td.onmouseleave = () => { + let indexOf = this.currentTreeDivList.indexOf(td); + if (indexOf >= 0 && indexOf < this.currentRecycleList.length) { + this.setMouseIn(false, [newTableElement]); + } + }; + td.onclick = () => { + let indexOf = this.currentTreeDivList.indexOf(td); + this.dispatchRowClickEvent(rowData, [this.treeElement?.children[indexOf] as HTMLElement, newTableElement]); + }; + this.setHighLight(rowData.data.isSearch, td); + this.treeElement!.style.width = column.getAttribute('width'); + this.treeElement?.append(td); + this.currentTreeDivList.push(td); + } else { + gridTemplateColumns.push(column.getAttribute('width') || '1fr'); + td = document.createElement('div'); + td.classList.add('td'); + td.style.overflow = 'hidden'; + td.style.textOverflow = 'ellipsis'; + td.style.whiteSpace = 'nowrap'; + td.title = rowData.data[dataIndex]; + td.dataIndex = dataIndex; + td.style.justifyContent = column.getAttribute('align') || 'flex-start'; + if (column.template) { + td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); + td.template = column.template; + } else { + td.innerHTML = this.formatName(rowData.data[dataIndex]); + } + newTableElement.append(td); + } + }); + (this.treeElement?.lastChild as HTMLElement).style.transform = `translateY(${treeTop}px)`; + (newTableElement as any).data = rowData.data; + newTableElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); + newTableElement.style.position = 'absolute'; + newTableElement.style.top = '0px'; + newTableElement.style.left = '0px'; + newTableElement.style.cursor = 'pointer'; + this.setHighLight(rowData.data.isSearch, newTableElement); + newTableElement.onmouseenter = () => { + if ((newTableElement as any).data.isSelected) return; + let indexOf = this.currentRecycleList.indexOf(newTableElement); + this.currentTreeDivList.forEach((row) => { + row.classList.remove('mouse-in'); + }); + if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { + this.setMouseIn(true, [this.treeElement?.children[indexOf] as HTMLElement]); + } + }; + newTableElement.onmouseleave = () => { + if ((newTableElement as any).data.isSelected) return; + let indexOf = this.currentRecycleList.indexOf(newTableElement); + if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { + this.setMouseIn(false, [this.treeElement?.children[indexOf] as HTMLElement]); + } + }; + newTableElement.onclick = (e) => { + let indexOf = this.currentRecycleList.indexOf(newTableElement); + this.dispatchRowClickEvent(rowData, [this.treeElement?.children[indexOf] as HTMLElement, newTableElement]); + }; + return newTableElement; + } + + createBtn(rowData: any) { + let btn: any = document.createElement('lit-icon'); + btn.classList.add('tree-icon'); + // @ts-ignore + if (rowData.expanded) { + btn.name = 'plus-square'; + } else { + btn.name = 'minus-square'; + } + if (!rowData.data.status && rowData.data.children.length > 0 && rowData.data.hasNext) { + btn.name = 'plus-square'; + } + btn.onclick = (e: Event) => { + rowData.data.status = false; + const resetNodeHidden = (hidden: boolean, rowData: any) => { + if (rowData.data.hasNext || rowData.data.children.length > 0) { + if (hidden) { + rowData.children.forEach((child: any) => { + child.rowHidden = true; + resetNodeHidden(hidden, child); + }); + } else { + rowData.data.status = rowData.expanded; + rowData.children.forEach((child: any) => { + child.rowHidden = !rowData.expanded; + if (rowData.expanded) { + resetNodeHidden(hidden, child); + } + }); + } + } + }; + const foldNode = () => { + rowData.expanded = false; + resetNodeHidden(true, rowData); + }; + const expendNode = () => { + rowData.expanded = true; + resetNodeHidden(false, rowData); + }; + if (rowData.expanded) { + foldNode(); + } else { + expendNode(); + } + this.reMeauseHeight(); + e.stopPropagation(); + }; + return btn; + } + + createExpandBtn(rowData: any) { + let btn: any = document.createElement('lit-icon'); + btn.classList.add('tree-icon'); + // @ts-ignore + if (rowData.expanded) { + btn.name = 'minus-square'; + } else { + btn.name = 'plus-square'; + } + if (!rowData.data.status && rowData.data.children.length > 0 && rowData.data.hasNext) { + btn.name = 'plus-square'; + } + btn.onclick = (e: Event) => { + rowData.data.status = false; + const resetNodeHidden = (hidden: boolean, rowData: any) => { + if (rowData.children.length > 0) { + if (hidden) { + rowData.children.forEach((child: any) => { + child.rowHidden = true; + resetNodeHidden(hidden, child); + }); + } else { + rowData.data.status = rowData.expanded; + rowData.children.forEach((child: any) => { + child.rowHidden = !rowData.expanded; + rowData.data.status = true; + if (rowData.expanded) { + resetNodeHidden(hidden, child); + } + }); + } + } + }; + const foldNode = () => { + rowData.expanded = false; + resetNodeHidden(true, rowData); + }; + const expendNode = () => { + rowData.expanded = true; + resetNodeHidden(false, rowData); + }; + if (rowData.expanded) { + foldNode(); + } else { + expendNode(); + } + this.reMeauseHeight(); + e.stopPropagation(); + }; + return btn; + } + + reMeauseHeight() { + if (this.currentRecycleList.length == 0) { + return; + } + let totalHeight = 0; + this.recycleDs.forEach((it) => { + if (!it.rowHidden) { + it.top = totalHeight; + totalHeight += it.height; + } + }); + this.tbodyElement && (this.tbodyElement.style.height = totalHeight + (this.isScrollXOutSide ? 0 : 0) + 'px'); + this.treeElement!.style.height = this.tableElement!.clientHeight - this.theadElement!.clientHeight + 'px'; + let visibleObjects = this.recycleDs.filter((item) => { + return !item.rowHidden; + }); + let top = this.tableElement!.scrollTop; + let skip = 0; + for (let i = 0; i < visibleObjects.length; i++) { + if (visibleObjects[i].top <= top && visibleObjects[i].top + visibleObjects[i].height >= top) { + skip = i; + break; + } + } + let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); + if (reduce == 0) { + return; + } + while (reduce <= this.tableElement!.clientHeight) { + let newTableElement; + if (this.hasAttribute('tree')) { + newTableElement = this.createNewTreeTableElement(visibleObjects[skip]); + } else { + newTableElement = this.createNewTableElement(visibleObjects[skip]); + } + this.tbodyElement?.append(newTableElement); + if (this.hasAttribute('tree')) { + if (this.treeElement?.lastChild) { + (this.treeElement?.lastChild as HTMLElement).style.height = visibleObjects[skip].height + 'px'; + } + } + this.currentRecycleList.push(newTableElement); + reduce += newTableElement.clientHeight; + } + for (let i = 0; i < this.currentRecycleList.length; i++) { + if (this.hasAttribute('tree')) { + this.freshCurrentLine( + this.currentRecycleList[i], + visibleObjects[i + skip], + this.treeElement?.children[i] as HTMLElement + ); + } else { + this.freshCurrentLine(this.currentRecycleList[i], visibleObjects[i + skip]); + } + } + } + + createNewTableElement(rowData: any): any { + let newTableElement = document.createElement('div'); + newTableElement.classList.add('tr'); + let gridTemplateColumns: Array = []; + this?.columns?.forEach((column: any) => { + let dataIndex = column.getAttribute('data-index') || '1'; + gridTemplateColumns.push(column.getAttribute('width') || '1fr'); + let td: any; + td = document.createElement('div'); + td.classList.add('td'); + td.style.overflow = 'hidden'; + td.style.textOverflow = 'ellipsis'; + td.style.whiteSpace = 'nowrap'; + td.dataIndex = dataIndex; + td.style.justifyContent = column.getAttribute('align') || 'flex-start'; + td.title = rowData.data[dataIndex]; + if (column.template) { + td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); + td.template = column.template; + } else { + td.innerHTML = this.formatName(rowData.data[dataIndex]); + } + newTableElement.append(td); + }); + newTableElement.onclick = () => { + this.dispatchRowClickEvent(rowData, [newTableElement]); + }; + newTableElement.onmouseenter = () => { + this.dispatchRowHoverEvent(rowData, [newTableElement]); + }; + if (rowData.data.isSelected != undefined) { + this.setSelectedRow(rowData.data.isSelected, [newTableElement]); + } + (newTableElement as any).data = rowData.data; + newTableElement.style.cursor = 'pointer'; + newTableElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); + newTableElement.style.position = 'absolute'; + newTableElement.style.top = '0px'; + newTableElement.style.left = '0px'; + return newTableElement; + } + + freshCurrentLine(element: HTMLElement, rowObject: TableRowObject, firstElement?: HTMLElement) { + if (!rowObject) { + if (firstElement) { + firstElement.style.display = 'none'; + } + element.style.display = 'none'; + return; + } + let childIndex = -1; + this.setHighLight(rowObject.data.isSearch, element); + element.childNodes.forEach((child) => { + if (child.nodeType != 1) return; + childIndex++; + let idx = firstElement != undefined ? childIndex + 1 : childIndex; + if (firstElement != undefined && childIndex == 0) { + this.setHighLight(rowObject.data.isSearch, firstElement); + (firstElement as any).data = rowObject.data; + if ((this.columns![0] as any).template) { + firstElement.innerHTML = (this.columns![0] as any).template + .render(rowObject.data) + .content.cloneNode(true).innerHTML; + } else { + let dataIndex = this.columns![0].getAttribute('data-index') || '1'; + firstElement.innerHTML = this.formatName(rowObject.data[dataIndex]); + firstElement.title = rowObject.data[dataIndex]; + } + if (rowObject.children && rowObject.children.length > 0) { + let btn = this.createExpandBtn(rowObject); + firstElement.insertBefore(btn, firstElement.firstChild); + firstElement.style.paddingLeft = 15 * rowObject.depth + 'px'; + } else if (rowObject.data.hasNext) { + let btn = this.createBtn(rowObject); + firstElement.title = rowObject.data.objectName; + firstElement.insertBefore(btn, firstElement.firstChild); + firstElement.style.paddingLeft = 15 * rowObject.depth + 'px'; + btn.onclick = () => { + // @ts-ignore + let indexOf = this.currentTreeDivList.indexOf(firstElement); + this.dispatchRowClickEventIcon(rowObject, [ + this.treeElement?.children[indexOf].children[indexOf] as LitIcon, + ]); + }; + } else { + firstElement.style.paddingLeft = 20 + 15 * rowObject.depth + 'px'; + } + firstElement.onclick = () => { + this.dispatchRowClickEvent(rowObject, [firstElement, element]); + }; + firstElement.style.transform = `translateY(${rowObject.top - this.tableElement!.scrollTop}px)`; + if (rowObject.data.isSelected != undefined) { + this.setSelectedRow(rowObject.data.isSelected, [firstElement]); + } else { + this.setSelectedRow(false, [firstElement]); + } + } + let dataIndex = this.columns![idx].getAttribute('data-index') || '1'; + if ((this.columns![idx] as any).template) { + (child as HTMLElement).innerHTML = ''; + (child as HTMLElement).appendChild( + (this.columns![idx] as any).template.render(rowObject.data).content.cloneNode(true) + ); + (child as HTMLElement).title = rowObject.data[dataIndex]; + } else { + (child as HTMLElement).innerHTML = this.formatName(rowObject.data[dataIndex]); + (child as HTMLElement).title = rowObject.data[dataIndex]; + } + }); + if (element.style.display == 'none') { + element.style.display = 'grid'; + } + element.style.transform = `translateY(${rowObject.top}px)`; + if (firstElement && firstElement.style.display == 'none') { + firstElement.style.display = 'flex'; + } + element.onclick = (e) => { + if (firstElement != undefined) { + this.dispatchRowClickEvent(rowObject, [firstElement, element]); + } else { + this.dispatchRowClickEvent(rowObject, [element]); + } + }; + element.onmouseenter = () => { + this.dispatchRowHoverEvent(rowObject, [element]); + }; + (element as any).data = rowObject.data; + if (rowObject.data.isSelected != undefined) { + this.setSelectedRow(rowObject.data.isSelected, [element]); + } else { + this.setSelectedRow(false, [element]); + } + if (rowObject.data.isHover != undefined) { + this.setMouseIn(rowObject.data.isHover, [element]); + } else { + this.setMouseIn(false, [element]); + } + } + + setSelectedRow(isSelected: boolean, rows: any[]) { + if (isSelected) { + rows.forEach((row) => { + if (row.classList.contains('mouse-in')) row.classList.remove('mouse-in'); + row.classList.add('mouse-select'); + }); + } else { + rows.forEach((row) => { + row.classList.remove('mouse-select'); + }); + } + } + + setMouseIn(isMouseIn: boolean, rows: any[]) { + if (isMouseIn) { + rows.forEach((row) => { + row.classList.add('mouse-in'); + }); + } else { + rows.forEach((row) => { + row.classList.remove('mouse-in'); + }); + } + } + + scrollToData(data: any) { + if (this.isRecycleList) { + if (this.recycleDs.length > 0) { + let filter = this.recycleDs.filter((item) => { + return item.data == data; + }); + if (filter.length > 0) { + this.tableElement!.scrollTop = filter[0].top; + } + this.setCurrentSelection(data); + } + } else { + if (this.normalDs.length > 0) { + let filter = this.normalDs.filter((item) => { + return item.data == data; + }); + if (filter.length > 0) { + this.tableElement!.scrollTop = filter[0].top; + } + } + } + } + + expandList(datasource: any[]) { + let filter = this.recycleDs.filter((item) => { + return datasource.indexOf(item.data) != -1; + }); + if (filter.length > 0) { + filter.forEach((item) => { + item.expanded = true; + item.rowHidden = false; + }); + } + this.reMeauseHeight(); + } + + clearAllSelection(rowObjectData: any) { + if (this.isRecycleList) { + this.recycleDs.forEach((item) => { + if (item.data != rowObjectData && item.data.isSelected) { + item.data.isSelected = false; + } + }); + this.setSelectedRow(false, this.currentTreeDivList); + this.setSelectedRow(false, this.currentRecycleList); + } else { + this.dataSource.forEach((item) => { + if (item != rowObjectData && item.isSelected) { + item.isSelected = false; + } + }); + this.setSelectedRow(false, this.normalDs); + } + } + + clearAllHover(rowObjectData: any) { + if (this.isRecycleList) { + this.recycleDs.forEach((item) => { + if (item.data != rowObjectData && item.data.isHover) { + item.data.isHover = false; + } + }); + this.setMouseIn(false, this.currentTreeDivList); + this.setMouseIn(false, this.currentRecycleList); + } else { + this.dataSource.forEach((item) => { + if (item != rowObjectData && item.isHover) { + item.isHover = false; + } + }); + this.setMouseIn(false, this.normalDs); + } + } + + mouseOut() { + if (this.isRecycleList) { + this.recycleDs.forEach((item) => (item.data.isHover = false)); + this.setMouseIn(false, this.currentTreeDivList); + this.setMouseIn(false, this.currentRecycleList); + } else { + this.dataSource.forEach((item) => (item.isHover = false)); + this.setMouseIn(false, this.normalDs); + } + this.dispatchEvent( + new CustomEvent('row-hover', { + detail: { + data: undefined, + }, + composed: true, + }) + ); + } + + setCurrentSelection(data: any) { + if (this.isRecycleList) { + if (data.isSelected != undefined) { + this.currentTreeDivList.forEach((item) => { + if ((item as any).data == data) { + this.setSelectedRow(data.isSelected, [item]); + } + }); + this.currentRecycleList.forEach((item) => { + if ((item as any).data == data) { + this.setSelectedRow(data.isSelected, [item]); + } + }); + } + } else { + if (data.isSelected != undefined) { + this.normalDs.forEach((item) => { + if ((item as any).data == data) { + this.setSelectedRow(data.isSelected, [item]); + } + }); + } + } + } + + setCurrentHover(data: any) { + if (this.isRecycleList) { + this.setMouseIn(false, this.currentTreeDivList); + this.setMouseIn(false, this.currentRecycleList); + if (data.isHover != undefined) { + this.currentTreeDivList.forEach((item) => { + if ((item as any).data == data) { + this.setMouseIn(data.isHover, [item]); + } + }); + this.currentRecycleList.forEach((item) => { + if ((item as any).data == data) { + this.setMouseIn(data.isHover, [item]); + } + }); + } + } else { + this.setMouseIn(false, this.normalDs); + if (data.isHover != undefined) { + this.normalDs.forEach((item) => { + if ((item as any).data == data) { + this.setMouseIn(data.isHover, [item]); + } + }); + } + } + } + + dispatchRowClickEventIcon(rowObject: any, elements: any[]) { + this.dispatchEvent( + new CustomEvent('icon-click', { + detail: { + ...rowObject.data, + data: rowObject.data, + }, + composed: true, + }) + ); + } + + dispatchRowClickEvent(rowObject: any, elements: any[]) { + this.dispatchEvent( + new CustomEvent('row-click', { + detail: { + ...rowObject.data, + data: rowObject.data, + callBack: (isSelected: boolean) => { + //是否爲单选 + if (isSelected) { + this.clearAllSelection(rowObject.data); + } + this.setSelectedRow(rowObject.data.isSelected, elements); + }, + }, + composed: true, + }) + ); + } + + dispatchRowHoverEvent(rowObject: any, elements: any[]) { + this.dispatchEvent( + new CustomEvent('row-hover', { + detail: { + data: rowObject.data, + callBack: () => { + this.clearAllHover(rowObject.data); + this.setMouseIn(rowObject.data.isHover, elements); + }, + }, + composed: true, + }) + ); + } + + formatName(name: any) { + if (name != undefined && name !== null) { + return name.toString().replace(//g, '>'); + } + return ''; + } + + setHighLight(isSearch: boolean, element: any) { + if (isSearch) { + element.setAttribute('high-light', ''); + } else { + element.removeAttribute('high-light'); + } + } +} diff --git a/ide/src/base-ui/tabs/lit-tabpane.ts b/ide/src/base-ui/tabs/lit-tabpane.ts new file mode 100644 index 0000000000000000000000000000000000000000..358749fdc19ace8c4d5b88cbe1a1778d687be02f --- /dev/null +++ b/ide/src/base-ui/tabs/lit-tabpane.ts @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../BaseElement.js'; +import { LitTabs } from './lit-tabs.js'; + +@element('lit-tabpane') +export class LitTabpane extends BaseElement { + static get observedAttributes() { + return ['tab', 'key', 'disabled', 'icon', 'closeable', 'hidden']; + } + + get tab() { + return this.getAttribute('tab'); + } + + set tab(value) { + this.setAttribute('tab', value || ''); + } + + get icon() { + return this.getAttribute('icon'); + } + + get disabled() { + return this.getAttribute('disabled') !== null; + } + + set disabled(value) { + if (value === null || value === false) { + this.removeAttribute('disabled'); + } else { + this.setAttribute('disabled', value + ''); + } + } + + get hidden() { + return this.getAttribute('hidden') !== null; + } + + set hidden(value) { + this.setAttribute('hidden', `${value}`); + } + + get closeable() { + return this.getAttribute('closeable') !== null; + } + + set closeable(value) { + if (value === null || value === false) { + this.removeAttribute('closeable'); + } else { + this.setAttribute('closeable', value + ''); + } + } + + get key() { + return this.getAttribute('key') || ''; + } + + set key(value) { + this.setAttribute('key', value); + } + + initElements(): void {} + + initHtml(): string { + return ` + + + `; + } + + connectedCallback() {} + + disconnectedCallback() {} + + adoptedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (oldValue !== newValue && newValue !== undefined) { + if (name === 'tab' && this.parentNode && this.parentNode instanceof LitTabs) { + this.parentNode.updateLabel && this.parentNode.updateLabel(this.key, newValue); + } + if (name === 'disabled' && this.parentNode && this.parentNode instanceof LitTabs) { + this.parentNode.updateDisabled && this.parentNode.updateDisabled(this.key, newValue); + } + if (name === 'closeable' && this.parentNode && this.parentNode instanceof LitTabs) { + this.parentNode.updateCloseable && this.parentNode.updateCloseable(this.key, newValue); + } + if (name === 'hidden' && this.parentNode && this.parentNode instanceof LitTabs) { + this.parentNode.updateHidden && this.parentNode.updateHidden(this.key, newValue); + } + } + } +} diff --git a/ide/src/base-ui/tabs/lit-tabs.ts b/ide/src/base-ui/tabs/lit-tabs.ts new file mode 100644 index 0000000000000000000000000000000000000000..59c18808dad21ed301921ebb751cdb995e848e92 --- /dev/null +++ b/ide/src/base-ui/tabs/lit-tabs.ts @@ -0,0 +1,744 @@ +/* + * Copyright (C) 2022 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 { element } from '../BaseElement.js'; +import { LitTabpane } from './lit-tabpane.js'; +import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('lit-tabs') +export class LitTabs extends HTMLElement { + private tabPos: any; + private nav: HTMLDivElement | undefined | null; + private line: HTMLDivElement | undefined | null; + private slots: HTMLSlotElement | undefined | null; + + constructor() { + super(); + const shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ` + + +
+ +
+ NEED CONTENT +
+
+ `; + } + + static get observedAttributes() { + return ['activekey', 'mode', 'position']; + } + + get position() { + return this.getAttribute('position') || 'top'; + } + + set position(value) { + this.setAttribute('position', value); + } + + get mode() { + return this.getAttribute('mode') || 'flat'; + } + + set mode(value) { + this.setAttribute('mode', value); + } + + get activekey() { + return this.getAttribute('activekey') || ''; + } + + set activekey(value: string) { + this.setAttribute('activekey', value); + } + + set onTabClick(fn: any) { + this.addEventListener('onTabClick', fn); + } + + updateLabel(key: string, value: string) { + if (this.nav) { + let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); + if (item) { + item.querySelector('span')!.innerHTML = value; + this.initTabPos(); + } + } + } + + updateDisabled(key: string, value: string) { + if (this.nav) { + let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); + if (item) { + if (value) { + item.setAttribute('data-disabled', ''); + } else { + item.removeAttribute('data-disabled'); + } + this.initTabPos(); + } + } + } + + updateCloseable(key: string, value: string) { + if (this.nav) { + let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); + if (item) { + if (value) { + item.setAttribute('data-closeable', ''); + } else { + item.removeAttribute('data-closeable'); + } + this.initTabPos(); + } + } + } + + updateHidden(key: string, value: string) { + if (this.nav) { + let item = this.nav.querySelector(`.nav-item[data-key='${key}']`); + if (item) { + if (value === 'true') { + item.setAttribute('data-hidden', ''); + } else { + item.removeAttribute('data-hidden'); + } + this.initTabPos(); + } + } + } + + initTabPos() { + const items = this.nav!.querySelectorAll('.nav-item'); + Array.from(items).forEach((a, index) => { + // @ts-ignore + this.tabPos[a.dataset.key] = { + index: index, + width: a.offsetWidth, + height: a.offsetHeight, + left: a.offsetLeft, + top: a.offsetTop, + label: a.textContent, + }; + }); + if (this.activekey) { + if (this.position.startsWith('left')) { + this.line?.setAttribute( + 'style', + `height:${this.tabPos[this.activekey].height}px;transform:translate(100%,${ + this.tabPos[this.activekey].top + }px)` + ); + } else if (this.position.startsWith('top')) { + if (this.tabPos[this.activekey]) { + this.line?.setAttribute( + 'style', + `width:${this.tabPos[this.activekey].width}px;transform:translate(${ + this.tabPos[this.activekey].left + }px,100%)` + ); + } + } else if (this.position.startsWith('right')) { + this.line?.setAttribute( + 'style', + `height:${this.tabPos[this.activekey].height}px;transform:translate(-100%,${ + this.tabPos[this.activekey].top + }px)` + ); + } else if (this.position.startsWith('bottom')) { + this.line?.setAttribute( + 'style', + `width:${this.tabPos[this.activekey].width}px;transform:translate(${this.tabPos[this.activekey].left}px,100%)` + ); + } + } + } + + connectedCallback() { + let that = this; + this.tabPos = {}; + this.nav = this.shadowRoot?.querySelector('#nav'); + this.line = this.shadowRoot?.querySelector('#tab-line'); + this.slots = this.shadowRoot?.querySelector('#slot'); + this.slots?.addEventListener('slotchange', () => { + const elements: Element[] | undefined = this.slots?.assignedElements(); + let panes = this.querySelectorAll('lit-tabpane'); + if (this.activekey) { + panes.forEach((a) => { + if (a.key === this.activekey) { + a.style.display = 'block'; + } else { + a.style.display = 'none'; + } + }); + } else { + panes.forEach((a, index) => { + if (index === 0) { + a.style.display = 'block'; + this.activekey = a.key || ''; + } else { + a.style.display = 'none'; + } + }); + } + let navHtml = ''; + elements + ?.map((it) => it as LitTabpane) + .forEach((a) => { + if (a.disabled) { + navHtml += ``; + } else if (a.hidden) { + navHtml += ``; + } else { + if (a.key === this.activekey) { + navHtml += ``; + } else { + navHtml += ``; + } + } + }); + this.nav!.innerHTML = navHtml; + this.initTabPos(); + this.nav!.querySelectorAll('.close-icon').forEach((a) => { + a.onclick = (e) => { + e.stopPropagation(); + const closeKey = (e.target! as HTMLElement).parentElement!.dataset.key; + this.dispatchEvent( + new CustomEvent('close-handler', { + detail: { key: closeKey }, + composed: true, + }) + ); + }; + }); + }); + this.nav!.onclick = (e) => { + if ((e.target! as HTMLElement).closest('div')!.hasAttribute('data-disabled')) return; + let key = (e.target! as HTMLElement).closest('div')!.dataset.key; + if (key) { + this.activeByKey(key); + } + let label = (e.target! as HTMLElement).closest('div')!.querySelector('span')!.textContent; + this.dispatchEvent( + new CustomEvent('onTabClick', { + detail: { key: key, tab: label }, + }) + ); + }; + + new ResizeObserver((entries) => { + let filling = this.shadowRoot!.querySelector('#tab-filling'); + + this.shadowRoot!.querySelector('.tab-nav-container')!.style.height = filling!.offsetWidth + 'px'; + }).observe(this.shadowRoot!.querySelector('#tab-filling')!); + } + + activeByKey(key: string, isValid: boolean = true) { + if (key === null || key === undefined) return; //如果没有key 不做相应 + this.nav!.querySelectorAll('.nav-item').forEach((a) => { + if (a.querySelector('span')?.innerText === 'Comparison') { + a.setAttribute('id', 'nav-comparison'); + } + if (a.getAttribute('data-key') === key) { + a.setAttribute('data-selected', 'true'); + if (isValid) { + let span = a.querySelector('span') as HTMLSpanElement; + let title = span.innerText; + let rowType = document + .querySelector('sp-application')! + .shadowRoot?.querySelector('sp-system-trace')! + .getAttribute('clickRow'); + if (title === 'Counters' || title === 'Thread States') { + title += `(${rowType})`; + } + if (title === 'Analysis') { + let rowId = document + .querySelector('sp-application')! + .shadowRoot?.querySelector('sp-system-trace')! + .getAttribute('rowId'); + if (rowId!.indexOf('DiskIOLatency') > -1) { + title += '(disk-io)'; + } else if (rowId!.indexOf('VirtualMemory') > -1) { + title += '(virtual-memory-cell)'; + } else { + title += `(${rowType})`; + } + } + if (title === 'Slices' || title === 'Current Selection') { + let rowName = document + .querySelector('sp-application')! + .shadowRoot?.querySelector('sp-system-trace')! + .getAttribute('rowName'); + if (rowName && rowName!.indexOf('deliverInputEvent') > -1) { + title += '(deliverInputEvent)'; + } else { + let rowType = document + .querySelector('sp-application')! + .shadowRoot?.querySelector('sp-system-trace')! + .getAttribute('clickRow'); + title += `(${rowType})`; + } + } + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: title, + action: 'trace_tab', + }); + } + } else { + a.removeAttribute('data-selected'); + } + }); + let tbp = this.querySelector(`lit-tabpane[key='${key}']`); + let panes = this.querySelectorAll('lit-tabpane'); + panes.forEach((a) => { + if (a.key === key) { + a.style.display = 'block'; + this.activekey = a.key; + this.initTabPos(); + } else { + a.style.display = 'none'; + } + }); + } + + activePane(key: string) { + if (key === null || key === undefined) return false; + let tbp = this.querySelector(`lit-tabpane[key='${key}']`); + if (tbp) { + this.activeByKey(key); + return true; + } else { + return false; + } + } + + disconnectedCallback() {} + + adoptedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name === 'activekey' && this.nav && oldValue !== newValue && newValue != '') { + this.activeByKey(newValue, false); + } + } +} diff --git a/ide/src/base-ui/utils/CSVFormater.ts b/ide/src/base-ui/utils/CSVFormater.ts new file mode 100644 index 0000000000000000000000000000000000000000..6cae263bba747fd408452e468413503f8b2b4d36 --- /dev/null +++ b/ide/src/base-ui/utils/CSVFormater.ts @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2022 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. + */ + +export class JSonToCSV { + static setDataConver(obj: any) { + let that = this; + let bw = this.browser(); + if (bw['ie'] < 9) return; + let data = obj['data'], + Show = typeof obj['showLabel'] === 'undefined' ? true : obj['showLabel'], + fileName = (obj['fileName'] || 'UserExport') + '.csv', + columns = obj['columns'] || { + title: [], + key: [], + formatter: undefined, + }; + let ShowLabel = typeof Show === 'undefined' ? true : Show; + let row = '', + CSV = '', + key; + // 如果要现实表头文字 + if (ShowLabel) { + // 如果有传入自定义的表头文字 + if (columns.title.length) { + columns.title.map(function (n: any) { + row += n + ','; + }); + } else { + // 如果没有,就直接取数据第一条的对象的属性 + for (key in data[0]) row += key + ','; + } + row = row.slice(0, -1); + CSV += row + '\r\n'; + } + // 具体的数据处理 + data.map(function (n: any) { + row = ''; + // 如果存在自定义key值 + if (columns.key.length) { + columns.key.map(function (m: any, idx: number) { + let strItem = n[m]; + if (typeof n[m] == 'undefined') { + strItem = ''; + } else if (typeof n[m] == 'object') { + strItem = JSON.stringify(n[m]); + strItem = strItem.replaceAll('"', ''); + } + if (idx === 0 && typeof n['depthCSV'] !== 'undefined') { + row += + '"' + + that.treeDepth(n['depthCSV']) + + (typeof columns.formatter === 'function' ? columns.formatter(m, n[m]) || n[m] : strItem) + + '",'; + } else { + row += + '"' + (typeof columns.formatter === 'function' ? columns.formatter(m, n[m]) || n[m] : strItem) + '",'; + } + }); + } else { + for (key in n) { + row += + '"' + (typeof columns.formatter === 'function' ? columns.formatter(key, n[key]) || n[key] : n[key]) + '",'; + } + } + row.slice(0, row.length - 1); // 删除最后一个, + CSV += row + '\r\n'; // 添加换行符号 + }); + if (!CSV) return; + this.SaveAs(fileName, CSV); + } + + static SaveAs(fileName: any, csvData: any) { + let bw: any = this.browser(); + if (!bw['edge'] || !bw['ie']) { + let alink: any = document.createElement('a'); + alink.id = 'linkDwnldLink'; + alink.href = this.getDownloadUrl(csvData); + document.body.appendChild(alink); + let linkDom: any = document.getElementById('linkDwnldLink'); + linkDom.setAttribute('download', fileName); + linkDom.click(); + document.body.removeChild(linkDom); + } else if (bw['ie'] >= 10 || bw['edge'] == 'edge') { + let _utf = '\uFEFF'; + let _csvData = new Blob([_utf + csvData], { + type: 'text/csv', + }); + (navigator as any).msSaveBlob(_csvData, fileName); + } else { + let oWin: any = window.top?.open('about:blank', '_blank'); + oWin.document.write('sep=,\r\n' + csvData); + oWin.document.close(); + oWin.document.execCommand('SaveAs', true, fileName); + oWin.close(); + } + } + + static getDownloadUrl(csvData: any) { + let _utf = '\uFEFF'; + if (window.Blob && window.URL && (window.URL as any).createObjectURL) { + var csvData: any = new Blob([_utf + csvData], { + type: 'text/csv', + }); + return URL.createObjectURL(csvData); + } + } + + static browser() { + let Sys: any = {}; + let ua = navigator.userAgent.toLowerCase(); + let s; + (s = ua.indexOf('edge') !== -1 ? (Sys.edge = 'edge') : ua.match(/rv:([\d.]+)\) like gecko/)) + ? (Sys.ie = s[1]) + : (s = ua.match(/msie ([\d.]+)/)) + ? (Sys.ie = s[1]) + : (s = ua.match(/firefox\/([\d.]+)/)) + ? (Sys.firefox = s[1]) + : (s = ua.match(/chrome\/([\d.]+)/)) + ? (Sys.chrome = s[1]) + : (s = ua.match(/opera.([\d.]+)/)) + ? (Sys.opera = s[1]) + : (s = ua.match(/version\/([\d.]+).*safari/)) + ? (Sys.safari = s[1]) + : 0; + return Sys; + } + + static treeDepth(depth: number) { + let str = ''; + for (let i = 0; i < depth; i++) { + str += ' '; + } + return str; + } + + static treeToArr(data: any) { + const result: Array = []; + data.forEach((item: any) => { + let depthCSV = 0; + const loop = (data: any, depth: any) => { + result.push({ depthCSV: depth, ...data }); + let child = data.children; + if (child) { + for (let i = 0; i < child.length; i++) { + loop(child[i], depth + 1); + } + } + }; + loop(item, depthCSV); + }); + return result; + } + + static columnDatas(columns: Array) { + let titleList: Array = []; + let ketList: Array = []; + columns.forEach((column) => { + let dataIndex = column.getAttribute('data-index'); + let columnName = column.getAttribute('title'); + if (columnName == '') { + columnName = dataIndex; + } + if (columnName !== ' ') { + titleList.push(columnName); + ketList.push(dataIndex); + } + }); + return { + titleList: titleList, + ketList: ketList, + }; + } + + static async csvExport(dataSource: { columns: any[]; tables: any[]; fileName: string }): Promise { + return new Promise((resolve) => { + let data: any = this.columnDatas(dataSource.columns); + let resultArr = JSonToCSV.treeToArr(dataSource.tables); + JSonToCSV.setDataConver({ + data: resultArr, + fileName: dataSource.fileName, + columns: { + title: data.titleList, + key: data.ketList, + }, + }); + resolve('ok'); + }); + } +} diff --git a/ide/src/base-ui/utils/ExcelFormater.ts b/ide/src/base-ui/utils/ExcelFormater.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f2ee1e55977dcaf281b7691d881d9deb6c48a2c --- /dev/null +++ b/ide/src/base-ui/utils/ExcelFormater.ts @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2022 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. + */ + +export class ExcelFormater { + static tmplCellXML = '{data}'; + static base64 = function (s: any) { + return window.btoa(unescape(encodeURIComponent(s))); + }; + + static format(s: any, c: any): string { + return s.replace(/{(\w+)}/g, function (m: any, p: any) { + return c[p]; + }); + } + + static createExcelRow(columns: any[], data: any): string { + let rowsXML = ''; + rowsXML += ''; + for (let k = 0; k < columns.length; k++) { + let dataIndex = columns[k].getAttribute('data-index'); + let columnName = columns[k].getAttribute('title'); + if (columnName == '') { + columnName = dataIndex; + } + let ctx = { + attributeStyleID: '', + nameType: 'String', + data: data ? data[dataIndex] || '' : columnName, + attributeFormula: '', + }; + rowsXML += this.format(this.tmplCellXML, ctx); + } + rowsXML += ''; + if (data && data.children != undefined && data.children.length > 0) { + data.children.forEach((child: any) => { + rowsXML += this.createExcelRow(columns, child); + }); + } + return rowsXML; + } + + static addImage(baseStr: string) { + return `${this.format(this.tmplCellXML, { + attributeStyleID: '', + nameType: 'String', + data: `
`, + attributeFormula: '', + })}
`; + } + + static testExport(dataSource: { columns: any[]; tables: any[]; sheetName: string }[], fileName: string) { + this.tablesToHtmlExcelMultipleSheet(dataSource, fileName); + } + + static tablesToHtmlExcelMultipleSheet( + dataSource: { columns: any[]; tables: any[]; sheetName: string }[], + fileName: string, + image?: string + ) { + let sheets: any[] = []; + dataSource.forEach((data) => { + sheets.push(this.createTableData(data.columns, data.tables, image)); + }); + this.tablesToExcelTestSheet(sheets, fileName, dataSource); + } + + static createTableData(columns: any[], dataSource: any[], image?: string) { + let tableData = ''; + let columnDatas = columns.map((column) => { + let dataIndex = column.getAttribute('data-index'); + let columnName = column.getAttribute('title'); + if (columnName == '') { + columnName = dataIndex; + } + return { + columnName: columnName, + dataIndex: dataIndex, + }; + }); + tableData += this.createTHead( + columnDatas.map((item) => { + return item.columnName; + }) + ); + let columnDataIndexes = columnDatas.map((item) => item.dataIndex); + dataSource.forEach((data, index) => { + if (index == 0 && image) { + tableData += this.createTableRow(columnDataIndexes, data, image); + } else { + tableData += this.createTableRow(columnDataIndexes, data); + } + }); + return tableData; + } + + static createTHead(columns: any[]) { + let header = ''; + columns.forEach((column) => { + header += `${column}`; + }); + header += ''; + return header; + } + + static createTableRow(columns: any[], data: any, image?: any) { + let childrenData = ''; + if (data.children !== undefined) { + data.children.forEach((child: any) => { + if (child) { + childrenData += this.createTableRow(columns, child); + } + }); + } + return `${columns + .map((column) => { + return `${(data[column] + '').replace('μ', 'u')}` || ''; + }) + .join('')}${image ? `
` : ''}${childrenData}`; + } + + static tablesToExcelTestSheet( + tables: any[], + filename: string, + dataSource: { columns: any[]; tables: any[]; sheetName: string }[] + ) { + let uri = 'data:application/vnd.ms-excel;base64,', + html_start = ``, + template_ExcelWorksheet = `{SheetName}`, + template_ListWorksheet = ``, + template_HTMLWorksheet = + ` +------=_NextPart_dummy +Content-Location: sheet{SheetIndex}.htm +Content-Type: text/html; charset=windows-1252 + +` + + html_start + + ` + + + + + +{SheetContent}
+`, + template_WorkBook = + `MIME-Version: 1.0 +X-Document-Type: Workbook +Content-Type: multipart/related; boundary="----=_NextPart_dummy" + +------=_NextPart_dummy +Content-Location: WorkBook.htm +Content-Type: text/html; charset=windows-1252 + +` + + html_start + + ` + + + + + + + + + <body><p>This page uses frames, but your browser does not support them.</p></body> + + +{HTMLWorksheets} +Content-Location: filelist.xml +Content-Type: text/xml; charset="utf-8" + + + + {ListWorksheets} + + +------=_NextPart_dummy-- +`; + let context_WorkBook = { + ExcelWorksheets: '', + HTMLWorksheets: '', + ListWorksheets: '', + }; + tables.forEach((item, sheetIndex) => { + context_WorkBook.ExcelWorksheets += this.format(template_ExcelWorksheet, { + SheetIndex: sheetIndex, + SheetName: dataSource[sheetIndex].sheetName, + }); + context_WorkBook.HTMLWorksheets += this.format(template_HTMLWorksheet, { + SheetIndex: sheetIndex, + SheetContent: item, + }); + context_WorkBook.ListWorksheets += this.format(template_ListWorksheet, { + SheetIndex: sheetIndex, + }); + }); + let link = document.createElement('a'); + link.href = uri + this.base64(this.format(template_WorkBook, context_WorkBook)); + link.download = filename + '.xls'; + link.target = '_blank'; + link.click(); + } +} diff --git a/ide/src/base-ui/utils/Template.ts b/ide/src/base-ui/utils/Template.ts new file mode 100644 index 0000000000000000000000000000000000000000..7066052d455a3ec46b39ab7b59b606ced74c4299 --- /dev/null +++ b/ide/src/base-ui/utils/Template.ts @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2022 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. + */ + +const propsMap: string[] = ['disabled', 'hidden', 'checked', 'selected', 'required', 'open', 'readonly']; + +declare interface HTMLTemplateElement { + render(data: any): any; +} + +(HTMLTemplateElement as any).prototype.render = function (data: any) { + if (!this.$fragment) { + const rule = this.getAttribute('rule') || 'v-'; + this.$fragment = this.cloneNode(true); + this.fragment = document.createElement('TEMPLATE'); + + // v-for Loop rendering + //
=> ${ list.map(function(item,index){ return '
' }).join('') } + const repeatEls = this.$fragment.content.querySelectorAll(`[\\${rule}for]`); + repeatEls.forEach((el: any) => { + const strFor = el.getAttribute(`${rule}for`); + const { isArray, items, params } = parseFor(strFor); + el.before( + '${Object.entries(' + + items + + ').map(function([' + + `${isArray ? '$index$' : params[1] || 'name'},${params[0] || (isArray ? 'item' : 'value')}],${ + params[2] || 'index' + }` + + '){ return `' + ); + el.removeAttribute(`${rule}for`); + el.after('`}).join("")}'); + }); + + // v-if Conditional rendering + //
=> ${ if ? '
' : '' } + const ifEls = this.$fragment.content.querySelectorAll(`[\\${rule}if]`); + ifEls.forEach((el: any) => { + const ifs = el.getAttribute(`${rule}if`); + el.before('${' + ifs + '?`'); + el.removeAttribute(`${rule}if`); + el.after('`:``}'); + }); + + // fragment aa => aa + const fragments = this.$fragment.content.querySelectorAll('fragment,block'); + fragments.forEach((el: any) => { + el.after(el.innerHTML); + el.parentNode.removeChild(el); + }); + } + this.fragment.innerHTML = this.$fragment.innerHTML.interpolate(data); + + // props + const propsEls = this.fragment.content.querySelectorAll(`[${propsMap.join('],[')}]`); + propsEls.forEach((el: any) => { + propsMap.forEach((props: any) => { + // If these attribute values are false, they are removed directly + if (el.getAttribute(props) === 'false') { + el.removeAttribute(props); + } + }); + }); + return this.fragment; +}; + +function parseFor(strFor: String) { + // Whether it is an object + const isObject = strFor.includes(' of '); + const reg = /\s(?:in|of)\s/g; + const [keys, obj] = strFor.match(reg) ? strFor.split(reg) : ['item', strFor]; + const items = Number(obj) > 0 ? `[${'null,'.repeat(Number(obj) - 1)}null]` : obj; + const params = keys.split(/[\(|\)|,\s?]/g).filter(Boolean); + return { isArray: !isObject, items, params }; +} + +// String to template string +(String as any).prototype.interpolate = function (params: any) { + const names = Object.keys(params); + // @ts-ignore + const vals = Object.values(params); + const str = this.replace(/\{\{([^\}]+)\}\}/g, (all: any, s: any) => `\${${s}}`); + return new Function(...names, `return \`${escape2Html(str)}\`;`)(...vals); +}; + +// HTML Character inversion meaning < => < +function escape2Html(str: string) { + let arrEntities: any = { lt: '<', gt: '>', nbsp: ' ', amp: '&', quot: '"' }; + return str.replace(/&(lt|gt|nbsp|amp|quot);/gi, function (all, t) { + return arrEntities[t]; + }); +} diff --git a/ide/src/command/Cmd.ts b/ide/src/command/Cmd.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e430c1cb507d7b95914ae701e619797e3408451 --- /dev/null +++ b/ide/src/command/Cmd.ts @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2022 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. + */ + +export class Cmd { + /** + * exec objdump to disassembling binary and find addr to show 100 line + * @param command obj dump command + * @param addr addr of select line + * @param callback result callback + */ + static execObjDump(command: string, addr: string, callback: Function) { + const data = { cmd: command, addr: addr }; + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/exec`; + fetch(uri, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }).then((response) => { + if (response.ok) { + let result = response.text(); + result.then((output) => { + callback(output); + }); + } + }); + } + + static execHdcCmd(command: string, callback: Function) { + const data = { + cmd: command, + tag: 'shell', + }; + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/hdcCmd`; + fetch(uri, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }).then((response) => { + if (response.ok) { + let result = response.text(); + result.then((output) => { + callback(output); + }); + } + }); + } + + static async execFileRecv(command: string, filePath: string, callback: Function) { + let fileName = filePath.substring(filePath.lastIndexOf('/') + 1); + const data = { + cmd: command, + tag: 'file', + fileName: fileName, + }; + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/hdcCmd`; + let buf = await fetch(uri, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }).then((res) => res.arrayBuffer()); + callback(buf); + } + + static execHdcTraceCmd(command: string, serialNumber: string, callback: Function) { + const data = { + cmd: command, + tag: 'hiprofiler_cmd', + serialNumber: serialNumber, + }; + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/hdcCmd`; + fetch(uri, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }).then((response) => { + if (response.ok) { + let result = response.text(); + result.then((output) => { + callback(output); + }); + } + }); + } + + static formatString(string: string, params: string[]) { + if (params.length == 0) { + return string; + } + for (let i = 0; i < params.length; i++) { + string = string.replace(new RegExp('\\{' + i + '\\}', 'g'), params[i]); + } + return string; + } + + static showSaveFile(callback: Function) { + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/showSaveDialog`; + fetch(uri, { + method: 'GET', + }).then((response) => { + if (response.ok) { + let result = response.text(); + result.then((output) => { + callback(output); + }); + } + }); + } + + static uploadFile(fd: FormData, callback: Function) { + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/upload`; + fetch(uri, { + method: 'POST', + body: fd, + }).then((response) => { + callback(response); + }); + } + + static copyFile(fileName: string, distFile: string, callback: Function) { + const data = { + filename: fileName, + distfile: distFile, + }; + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/copyfile`; + fetch(uri, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }).then((response) => { + callback(response); + }); + } + + static async openFileDialog() { + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/showOpenDialog`; + let res = await fetch(uri, { method: 'POST' }); + let result = res.ok ? await res.text() : ''; + return result; + } +} diff --git a/ide/src/command/CmdConstant.ts b/ide/src/command/CmdConstant.ts new file mode 100644 index 0000000000000000000000000000000000000000..3662a1d65c424dd50f06bc0a99cfecf65a434072 --- /dev/null +++ b/ide/src/command/CmdConstant.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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. + */ + +export class CmdConstant { + static CMD_TRACE_FILE_SIZE = 'hdc_std shell stat --format=%s '; + static CMD_SHELL = 'hdc_std shell '; + static CMD_MOUNT = 'hdc_std shell mount -o remount,rw /'; + static CMD_GET_PROCESS = 'hdc_std shell ps -A -opid,cmd'; + static CMD_GET_APP_NMAE = 'hdc_std shell ps -A -ocmd'; + static CMD_GET_CPU_COUNT = "hdc_std shell grep -c 'processor' /proc/cpuinfo"; + static CMD_GET_HIPERF_EVENTS = 'hdc_std shell hiperf list'; + static CMD_GET_VERSION = 'hdc_std shell param get const.product.software.version'; + static CMD_HDC_DEVICES = 'hdc_std list targets'; + static CMD_MOUNT_DEVICES = 'hdc_std -t {0} shell mount -o remount,rw /'; + static CMD_GET_PROCESS_DEVICES = 'hdc_std -t {0} shell ps -A -opid,cmd'; + static CMD_GET_APP_NMAE_DEVICES = 'hdc_std -t {0} shell ps -A -ocmd'; + static CMD_GET_CPU_COUNT_DEVICES = "hdc_std -t {0} shell grep -c 'processor' /proc/cpuinfo"; + static CMD_GET_HIPERF_EVENTS_DEVICES = 'hdc_std -t {0} shell hiperf list'; + static CMD_FIEL_RECV_DEVICES = 'hdc_std -t {0} file recv {1} ./'; + static CMS_HDC_STOP = + 'hdc_std -t {0} shell killall hiprofilerd hiprofiler_plugins native_daemon hiperf hiebpf' + ' hiprofiler_cmd'; + static CMS_STOP = 'hdc_std shell killall hiprofilerd hiprofiler_plugins native_daemon hiperf hiebpf hiprofiler_cmd'; + static CMD_GET_VERSION_DEVICES = 'hdc_std -t {0} shell param get const.product.software.version'; +} diff --git a/ide/src/doc/compile_trace_streamer.html b/ide/src/doc/compile_trace_streamer.html new file mode 100644 index 0000000000000000000000000000000000000000..64eb5f5aa814dc8f6cc4851d9f3fe0a942343c26 --- /dev/null +++ b/ide/src/doc/compile_trace_streamer.html @@ -0,0 +1,845 @@ + + + + compile_trace_streamer + + + + + + +
+

1.如何独立编译Trace_streamer

+ +

尽管本工具(trace_streamer)是在ohos工具箱中的一员,但你依然可以独立编译此工具。

+

本工具可以编译linux, mac, windows, WebAssembly版本。

+

本工具默认编译方式是使用gn

+
    +
  • 编译方式
  • +
+
third_party部分安装方式
+third_party相关控件下载链接:https://gitee.com/organizations/openharmony/projects
+在src路径下创建同级目录third_party。
+一、sqlite:
+1.打开上方链接,搜索sqlite。
+2.点击搜索结果进入下载界面,下载sqlite组件。
+3.把下载的文件解压后,文件夹命名为sqlite,并用代码路径中\prebuilts\buildsqlite\sqlite3build.gn文件替换sqlite目录中的BUILD.gn文件。
+4.把sqlite文件夹放入third_party目录中。
+二、protobuf:
+1.按上述下载方法,下载protobuf组件。
+2.把下载的文件解压后,文件夹命名为protobuf,并用代码路径中\prebuilts\buildprotobuf\protobufbuild.gn文件替换protobuf目录中的BUILD.gn文件。
+3.把protobuf文件夹放入third_party目录中。
+三、googletest:
+1.按上述下载方法,下载googletest相关组件。
+2.把下载的文件解压后,文件夹命名为googletest,并用代码路径中\prebuilts\buildgoogletest\googletestbuild.gn文件替换googletest目录中的BUILD.gn文件。
+3.把googletest文件夹放入third_party目录中。
+4.找到文件\googletest\include\gtest\internal\ gtest-port.h 把286行 #include <sstream> // NOLINT修改为
+#undef private
+#define private private
+#include <sstream>  // NOLINT
+#undef private
+#define private public
+ +

编译不同版本:linux, WebAssembly, mac

+
./build.sh linux/wasm/macx
+
+ +

如果需要编译WebAssembly版本,您需要在prebuilts/目录下安装emsdk

+
git clone https://github.com/juj/emsdk.git --depth=1
+cd emsdk
+git pull
+./emsdk update # this may not work, ignore it
+./emsdk install latest
+./emsdk activate latest
+安装之后,您需要将upstream目录复制到prebuilts/emsdk/emsdk,node复制到prebuilts/emsdk/node
+
+

安装之后,目录结构当如:

+
prebuilts/emsdk
+├── prebuilts/emsdk/emsdk
+│   ├── prebuilts/emsdk/emsdk/bin
+│   ├── prebuilts/emsdk/emsdk/emscripten
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/cache
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/cmake
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/docs
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/media
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/node_modules
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/__pycache__
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/src
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/system
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/tests
+│   │   ├── prebuilts/emsdk/emsdk/emscripten/third_party
+│   │   └── prebuilts/emsdk/emsdk/emscripten/tools
+│   ├── prebuilts/emsdk/emsdk/include
+│   │   └── prebuilts/emsdk/emsdk/include/c++
+│   └── prebuilts/emsdk/emsdk/lib
+│       └── prebuilts/emsdk/emsdk/lib/clang
+└── prebuilts/emsdk/node
+    └── prebuilts/emsdk/node/14.18.2_64bit
+        ├── prebuilts/emsdk/node/14.18.2_64bit/bin
+        ├── prebuilts/emsdk/node/14.18.2_64bit/include
+        ├── prebuilts/emsdk/node/14.18.2_64bit/lib
+        └── prebuilts/emsdk/node/14.18.2_64bit/share
+
+

之后调用

+
./build.sh wasm进行编译,您需要将sh脚本进行部分修改,因为这个脚本内置了一些库的下载和解析方式
+
+
+ + + diff --git a/ide/src/doc/des_binder.html b/ide/src/doc/des_binder.html new file mode 100644 index 0000000000000000000000000000000000000000..0c9e8cbacdf7a1720cb75fb9d459317a1364e63d --- /dev/null +++ b/ide/src/doc/des_binder.html @@ -0,0 +1,880 @@ + + + + des_binder + + + + + +
+

binder事件上下文如何关联

+ +

+ binder事件相对复杂,这里是从ftrace事件中抽离出来的binder相关消息,用来作为开发者或用户追踪binder事件的参考
+ a binder event is identified by the sender and receive device, and a reply message only end
+ the last binder msg which reply the calling one.
+ the alloc_buf msg can always flow the binder_transaction, so we no need to identify the alloc msg with + transactionID +

+

TAG TT need reply!!! needReply = !isReply && !(flags & 0x01);

+ +
 RenderThread-2267  ( 1592) [003] ...1 168766.128108: binder_transaction: transaction=25155526 dest_node=25155471 dest_proc=506 dest_thread=0 reply=0 flags=0x10 code=0x9
+RenderThread-2267  ( 1592) [003] ...1 168766.128110: binder_transaction_alloc_buf: transaction=25155526 data_size=120 offsets_size=8
+
+

received

+ +
 Binder:506_2-537   (  506) [003] ...1 168766.128154: binder_transaction_received: transaction=25155526
+
+

binder is in DB, TAG A needReply

+ +
 Binder:506_2-537   (  506) [003] ...1 168766.128221: binder_transaction: transaction=25155529 dest_node=25155527 dest_proc=1592 dest_thread=2267 reply=0 flags=0x10 code=0x5f474854
+Binder:506_2-537   (  506) [003] ...1 168766.128223: binder_transaction_alloc_buf: transaction=25155529 data_size=72 offsets_size=0
+
+

+ +
 RenderThread-2267  ( 1592) [003] ...1 168766.128243: binder_transaction_received: transaction=25155529
+
+

the flowing is for TAG A, this is the reply for TAG A

+ +
 RenderThread-2267  ( 1592) [003] ...1 168766.128262: binder_transaction: transaction=25155530 dest_node=0 dest_proc=506 dest_thread=537 reply=1 flags=0x8 code=0x0
+
+RenderThread-2267  ( 1592) [003] ...1 168766.128264: binder_transaction_alloc_buf: transaction=25155530 data_size=4 offsets_size=0
+
+

calc the dur of TAG A

+ +
 Binder:506_2-537   (  506) [003] ...1 168766.128288: binder_transaction_received: transaction=25155530
+
+

binder last TAG A needReply, this is TAG B needReply!!!

+ +
 Binder:506_2-537   (  506) [003] ...1 168766.128328: binder_transaction: transaction=25155532 dest_node=25155527 dest_proc=1592 dest_thread=2267 reply=0 flags=0x10 code=0x2
+Binder:506_2-537   (  506) [003] ...1 168766.128330: binder_transaction_alloc_buf: transaction=25155532 data_size=72 offsets_size=0
+
+

in db

+ +
 RenderThread-2267  ( 1592) [003] ...1 168766.128347: binder_transaction_received: transaction=25155532
+
+

the reply message is not in db Session D, this is the reply for TAG B

+ +
 RenderThread-2267  ( 1592) [003] ...1 168766.128361: binder_transaction: transaction=25155533 dest_node=0 dest_proc=506 dest_thread=537 reply=1 flags=0x0 code=0x0
+RenderThread-2267  ( 1592) [003] ...1 168766.128363: binder_transaction_alloc_buf: transaction=25155533 data_size=4 offsets_size=0
+
+

no this message in db, calcate the dur of TAG B

+ +
 Binder:506_2-537   (  506) [003] ...1 168766.128385: binder_transaction_received: transaction=25155533
+
+

no this message in db Session E, this is the reply for TAG TT

+ +
 Binder:506_2-537   (  506) [003] ...1 168766.128412: binder_transaction: transaction=25155534 dest_node=0 dest_proc=1592 dest_thread=2267 reply=1 flags=0x0 code=0x0
+
+Binder:506_2-537   (  506) [003] ...1 168766.128413: binder_transaction_alloc_buf: transaction=25155534 data_size=68 offsets_size=0
+
+

the dur of TAG TT is calcated by the flowing msg

+ +
 RenderThread-2267  ( 1592) [003] ...1 168766.128430: binder_transaction_received: transaction=25155534
+
+
+ + + diff --git a/ide/src/doc/des_stat.html b/ide/src/doc/des_stat.html new file mode 100644 index 0000000000000000000000000000000000000000..df51e09f71fedb8fd9e93e84b075841c9f28095f --- /dev/null +++ b/ide/src/doc/des_stat.html @@ -0,0 +1,2883 @@ + + + + des_stat + + + + + + +
+

TraceStreamer 解析数据状态表

+ +

+ TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件状态。通过stat表可以对trace数据源中各个类型事件的数据的数量,数据质量有一个基本了解。
+ 我们对不同类型的数据,统计了收到多少条,数据逻辑是否匹配,是否有不合法数据,是否有数据丢失情况,所有这些,是基于对数据格式本身和数据前后关系的主观认识。欢迎开发者提供更多的思路来帮我们完善数据本身的校验工作。 +

+

stat表支持统计的事件列表如下:

+

ftrace事件统计

+

ftrace相关事件属于系统内核事件,具体请参考linux内核相关技术网站(www.kernel.org)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
事件名称
binder_transaction
binder_transaction_alloc_buf
binder_transaction_lock
binder_transaction_locked
binder_transaction_received
binder_transaction_unlock
clk_disable
clk_enable
clk_set_rate
clock_disable
clock_enable
clock_set_rate
cpu_frequency
cpu_idle
ipi_entry
ipi_exit
irq_handler_entry
irq_handler_exit
memory (进程内存)
oom_score_adj_update
print
regulator_disable
regulator_disable_complete
regulator_set_voltage
regulator_set_voltage_complete
sched_process_exit
sched_process_free
sched_switch
sched_wakeup
sched_wakeup_new
sched_waking
signal_deliver
signal_generate
softirq_entry
softirq_exit
softirq_raise
suspend_resume
sys_enter
sys_exit
task_newtask
task_rename
trace_bblock_bio_queue
trace_block_bio_backmerge
trace_block_bio_bounce
trace_block_bio_complete
trace_block_bio_frontmerge
trace_block_bio_remap
trace_block_dirty_buffer
trace_block_getrq
trace_block_plug
trace_block_rq_complete
trace_block_rq_insert
trace_block_rq_issue
trace_block_rq_remap
trace_event_clock_sync
tracing_mark_write
workqueue_execute_end
workqueue_execute_start
+

fps事件统计

+ + + + + + + + + + + + +
事件名称
hidump_fps
+

日志事件统计

+ + + + + + + + + + + + +
事件名称
hilog
+

系统内存和系统虚拟内存事件

+ + + + + + + + + + + + + + + +
事件名称
sys_memory
sys_virtual_memory
+

内存申请和释放事件

+ + + + + + + + + + + + + + + +
事件名称
native_hook_free
native_hook_malloc
+

磁盘读写事件统计

+ + + + + + + + + + + + +
事件名称
trace_diskio
+

进程事件统计

+ + + + + + + + + + + + +
事件名称
trace_process
+

CPU使用率事件解析

+ + + + + + + + + + + + +
事件名称
trace_cpu_usage
+

网络数据事件解析

+ + + + + + + + + + + + +
事件名称
trace_network
+

事件对应解析状态:

+ +

每种事件解析数据都有5种状态,描述如下表:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
stat_typedescription
received统计trace数据源中总共有多少该事件。
data_lost统计TraceStreamer解析过程中发现丢失数据条数。
not_match统计有多少数据与上下文其他数据不匹配。
not_supported + 统计有多少暂不支持解析该事件(一个事件可能包含多种类型的子事件, + TraceStreamer可能支持该事件的一部分子事件)。 +
invalid_data统计收到多少条该事件的非法数据。
+

数据状态级别

+ +

+ 数据状态级别总共有4种,分别是:info, warn, + error,fatal。由于数据的重要性不同,不同事件的同一种状态可能对应不同的级别。 例如binder_transaction_received的 + not_supported状态的数据为info级别,而binder_transaction_alloc_buf的not_supported状态数据为warn级别。 +

+

+ 您可以在src/cfg/trace_streamer_config.cpp的InitSecurityMap方法中自行定义相关事件的优先级。 +

+

事件,状态与级别对应关系

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
event_namestat_typeserverity
binder_transactionreceivedinfo
binder_transactiondata_losterror
binder_transactionnot_matchinfo
binder_transactionnot_supportedinfo
binder_transactioninvalid_dataerror
binder_transaction_receivedreceivedinfo
binder_transaction_receiveddata_losterror
binder_transaction_receivednot_matchinfo
binder_transaction_receivednot_supportedinfo
binder_transaction_receivedinvalid_dataerror
binder_transaction_alloc_bufreceivedinfo
binder_transaction_alloc_bufdata_losterror
binder_transaction_alloc_bufnot_matchinfo
binder_transaction_alloc_bufnot_supportedwarn
binder_transaction_alloc_bufinvalid_dataerror
binder_transaction_lockreceivedinfo
binder_transaction_lockdata_losterror
binder_transaction_locknot_matchinfo
binder_transaction_locknot_supportedwarn
binder_transaction_lockinvalid_dataerror
binder_transaction_lockedreceivedinfo
binder_transaction_lockeddata_losterror
binder_transaction_lockednot_matchinfo
binder_transaction_lockednot_supportedwarn
binder_transaction_lockedinvalid_dataerror
binder_transaction_unlockreceivedinfo
binder_transaction_unlockdata_losterror
binder_transaction_unlocknot_matchinfo
binder_transaction_unlocknot_supportedwarn
binder_transaction_unlockinvalid_dataerror
sched_switchreceivedinfo
sched_switchdata_losterror
sched_switchnot_matchinfo
sched_switchnot_supportedinfo
sched_switchinvalid_dataerror
task_renamereceivedinfo
task_renamedata_losterror
task_renamenot_matchinfo
task_renamenot_supportedinfo
task_renameinvalid_dataerror
task_newtaskreceivedinfo
task_newtaskdata_losterror
task_newtasknot_matchinfo
task_newtasknot_supportedinfo
task_newtaskinvalid_dataerror
tracing_mark_writereceivedinfo
tracing_mark_writedata_losterror
tracing_mark_writenot_matchinfo
tracing_mark_writenot_supportedinfo
tracing_mark_writeinvalid_dataerror
printreceivedinfo
printdata_losterror
printnot_matchinfo
printnot_supportedinfo
printinvalid_dataerror
sched_wakeupreceivedinfo
sched_wakeupdata_losterror
sched_wakeupnot_matchinfo
sched_wakeupnot_supportedinfo
sched_wakeupinvalid_dataerror
sched_wakingreceivedinfo
sched_wakingdata_losterror
sched_wakingnot_matchinfo
sched_wakingnot_supportedinfo
sched_wakinginvalid_dataerror
cpu_idlereceivedinfo
cpu_idledata_losterror
cpu_idlenot_matchinfo
cpu_idlenot_supportedinfo
cpu_idleinvalid_dataerror
cpu_frequencyreceivedinfo
cpu_frequencydata_losterror
cpu_frequencynot_matchinfo
cpu_frequencynot_supportedinfo
cpu_frequencyinvalid_dataerror
suspend_resumereceivedinfo
suspend_resumedata_losterror
suspend_resumenot_matchinfo
suspend_resumenot_supportedinfo
suspend_resumeinvalid_dataerror
workqueue_execute_startreceivedinfo
workqueue_execute_startdata_losterror
workqueue_execute_startnot_matchinfo
workqueue_execute_startnot_supportedinfo
workqueue_execute_startinvalid_dataerror
workqueue_execute_endreceivedinfo
workqueue_execute_enddata_losterror
workqueue_execute_endnot_matchinfo
workqueue_execute_endnot_supportedwarn
workqueue_execute_endinvalid_dataerror
clock_set_ratereceivedinfo
clock_set_ratedata_losterror
clock_set_ratenot_matchinfo
clock_set_ratenot_supportedwarn
clock_set_rateinvalid_dataerror
clock_enablereceivedinfo
clock_enabledata_losterror
clock_enablenot_matchinfo
clock_enablenot_supportedwarn
clock_enableinvalid_dataerror
clock_disablereceivedinfo
clock_disabledata_losterror
clock_disablenot_matchinfo
clock_disablenot_supportedwarn
clock_disableinvalid_dataerror
clk_set_ratereceivedinfo
clk_set_ratedata_losterror
clk_set_ratenot_matchinfo
clk_set_ratenot_supportedwarn
clk_set_rateinvalid_dataerror
clk_enablereceivedinfo
clk_enabledata_losterror
clk_enablenot_matchinfo
clk_enablenot_supportedwarn
clk_enableinvalid_dataerror
clk_disablereceivedinfo
clk_disabledata_losterror
clk_disablenot_matchinfo
clk_disablenot_supportedwarn
clk_disableinvalid_dataerror
sys_enterreceivedinfo
sys_enterdata_losterror
sys_enternot_matchinfo
sys_enternot_supportedwarn
sys_enterinvalid_dataerror
sys_exitreceivedinfo
sys_exitdata_losterror
sys_exitnot_matchinfo
sys_exitnot_supportedwarn
sys_exitinvalid_dataerror
regulator_set_voltagereceivedinfo
regulator_set_voltagedata_losterror
regulator_set_voltagenot_matchinfo
regulator_set_voltagenot_supportedwarn
regulator_set_voltageinvalid_dataerror
regulator_set_voltage_completereceivedinfo
regulator_set_voltage_completedata_losterror
regulator_set_voltage_completenot_matchinfo
regulator_set_voltage_completenot_supportedwarn
regulator_set_voltage_completeinvalid_dataerror
regulator_disablereceivedinfo
regulator_disabledata_losterror
regulator_disablenot_matchinfo
regulator_disablenot_supportedwarn
regulator_disableinvalid_dataerror
regulator_disable_completereceivedinfo
regulator_disable_completedata_losterror
regulator_disable_completenot_matchinfo
regulator_disable_completenot_supportedwarn
regulator_disable_completeinvalid_dataerror
ipi_entryreceivedinfo
ipi_entrydata_losterror
ipi_entrynot_matchinfo
ipi_entrynot_supportedwarn
ipi_entryinvalid_dataerror
ipi_exitreceivedinfo
ipi_exitdata_losterror
ipi_exitnot_matchinfo
ipi_exitnot_supportedwarn
ipi_exitinvalid_dataerror
irq_handler_entryreceivedinfo
irq_handler_entrydata_losterror
irq_handler_entrynot_matchinfo
irq_handler_entrynot_supportedwarn
irq_handler_entryinvalid_dataerror
irq_handler_exitreceivedinfo
irq_handler_exitdata_losterror
irq_handler_exitnot_matchinfo
irq_handler_exitnot_supportedwarn
irq_handler_exitinvalid_dataerror
softirq_raisereceivedinfo
softirq_raisedata_losterror
softirq_raisenot_matchinfo
softirq_raisenot_supportedwarn
softirq_raiseinvalid_dataerror
softirq_entryreceivedinfo
softirq_entrydata_losterror
softirq_entrynot_matchinfo
softirq_entrynot_supportedwarn
softirq_entryinvalid_dataerror
softirq_exitreceivedinfo
softirq_exitdata_losterror
softirq_exitnot_matchinfo
softirq_exitnot_supportedwarn
softirq_exitinvalid_dataerror
oom_score_adj_updatereceivedinfo
oom_score_adj_updatedata_losterror
oom_score_adj_updatenot_matchinfo
oom_score_adj_updatenot_supportedwarn
oom_score_adj_updateinvalid_dataerror
sched_wakeup_newreceivedinfo
sched_wakeup_newdata_losterror
sched_wakeup_newnot_matchinfo
sched_wakeup_newnot_supportedwarn
sched_wakeup_newinvalid_dataerror
sched_process_exitreceivedinfo
sched_process_exitdata_losterror
sched_process_exitnot_matchinfo
sched_process_exitnot_supportedwarn
sched_process_exitinvalid_dataerror
sched_process_freereceivedinfo
sched_process_freedata_losterror
sched_process_freenot_matchinfo
sched_process_freenot_supportedwarn
sched_process_freeinvalid_dataerror
trace_event_clock_syncreceivedinfo
trace_event_clock_syncdata_losterror
trace_event_clock_syncnot_matchinfo
trace_event_clock_syncnot_supportedwarn
trace_event_clock_syncinvalid_dataerror
memoryreceivedinfo
memorydata_losterror
memorynot_matchinfo
memorynot_supportedwarn
memoryinvalid_dataerror
hilogreceivedinfo
hilogdata_losterror
hilognot_matchinfo
hilognot_supportedwarn
hiloginvalid_dataerror
hidump_fpsreceivedinfo
hidump_fpsdata_losterror
hidump_fpsnot_matchinfo
hidump_fpsnot_supportedwarn
hidump_fpsinvalid_dataerror
native_hook_mallocreceivedinfo
native_hook_mallocdata_losterror
native_hook_mallocnot_matchinfo
native_hook_mallocnot_supportedwarn
native_hook_mallocinvalid_dataerror
native_hook_freereceivedinfo
native_hook_freedata_losterror
native_hook_freenot_matchinfo
native_hook_freenot_supportedwarn
native_hook_freeinvalid_dataerror
trace_diskioreceivedinfo
trace_diskiodata_losterror
trace_diskionot_matchinfo
trace_diskionot_supportedwarn
trace_diskioinvalid_dataerror
trace_processreceivedinfo
trace_processdata_losterror
trace_processnot_matchinfo
trace_processnot_supportedwarn
trace_processinvalid_dataerror
trace_cpu_usagereceivedinfo
trace_cpu_usagedata_losterror
trace_cpu_usagenot_matchinfo
trace_cpu_usagenot_supportedwarn
trace_cpu_usageinvalid_dataerror
trace_networkreceivedinfo
trace_networkdata_losterror
trace_networknot_matchinfo
trace_networknot_supportedwarn
trace_networkinvalid_dataerror
sys_memoryreceivedinfo
sys_memorydata_losterror
sys_memorynot_matchinfo
sys_memorynot_supportedwarn
sys_memoryinvalid_dataerror
sys_virtual_memoryreceivedinfo
sys_virtual_memorydata_losterror
sys_virtual_memorynot_matchinfo
sys_virtual_memorynot_supportedwarn
sys_virtual_memoryinvalid_dataerror
signal_generatereceivedinfo
signal_generatedata_losterror
signal_generatenot_matchinfo
signal_generatenot_supportedwarn
signal_generateinvalid_dataerror
signal_deliverreceivedinfo
signal_deliverdata_losterror
signal_delivernot_matchinfo
signal_delivernot_supportedwarn
signal_deliverinvalid_dataerror
trace_block_bio_backmergereceivedinfo
trace_block_bio_backmergedata_losterror
trace_block_bio_backmergenot_matchinfo
trace_block_bio_backmergenot_supportedwarn
trace_block_bio_backmergeinvalid_dataerror
trace_block_bio_bouncereceivedinfo
trace_block_bio_bouncedata_losterror
trace_block_bio_bouncenot_matchinfo
trace_block_bio_bouncenot_supportedwarn
trace_block_bio_bounceinvalid_dataerror
trace_block_bio_completereceivedinfo
trace_block_bio_completedata_losterror
trace_block_bio_completenot_matchinfo
trace_block_bio_completenot_supportedwarn
trace_block_bio_completeinvalid_dataerror
trace_block_bio_frontmergereceivedinfo
trace_block_bio_frontmergedata_losterror
trace_block_bio_frontmergenot_matchinfo
trace_block_bio_frontmergenot_supportedwarn
trace_block_bio_frontmergeinvalid_dataerror
trace_bblock_bio_queuereceivedinfo
trace_bblock_bio_queuedata_losterror
trace_bblock_bio_queuenot_matchinfo
trace_bblock_bio_queuenot_supportedwarn
trace_bblock_bio_queueinvalid_dataerror
trace_block_bio_remapreceivedinfo
trace_block_bio_remapdata_losterror
trace_block_bio_remapnot_matchinfo
trace_block_bio_remapnot_supportedwarn
trace_block_bio_remapinvalid_dataerror
trace_block_dirty_bufferreceivedinfo
trace_block_dirty_bufferdata_losterror
trace_block_dirty_buffernot_matchinfo
trace_block_dirty_buffernot_supportedwarn
trace_block_dirty_bufferinvalid_dataerror
trace_block_getrqreceivedinfo
trace_block_getrqdata_losterror
trace_block_getrqnot_matchinfo
trace_block_getrqnot_supportedwarn
trace_block_getrqinvalid_dataerror
trace_block_plugreceivedinfo
trace_block_plugdata_losterror
trace_block_plugnot_matchinfo
trace_block_plugnot_supportedwarn
trace_block_pluginvalid_dataerror
trace_block_rq_completereceivedinfo
trace_block_rq_completedata_losterror
trace_block_rq_completenot_matchinfo
trace_block_rq_completenot_supportedwarn
trace_block_rq_completeinvalid_dataerror
trace_block_rq_insertreceivedinfo
trace_block_rq_insertdata_losterror
trace_block_rq_insertnot_matchinfo
trace_block_rq_insertnot_supportedwarn
trace_block_rq_insertinvalid_dataerror
trace_block_rq_remapreceivedinfo
trace_block_rq_remapdata_losterror
trace_block_rq_remapnot_matchinfo
trace_block_rq_remapnot_supportedwarn
trace_block_rq_remapinvalid_dataerror
trace_block_rq_issuereceivedinfo
trace_block_rq_issuedata_losterror
trace_block_rq_issuenot_matchinfo
trace_block_rq_issuenot_supportedwarn
trace_block_rq_issueinvalid_dataerror
otherreceivedinfo
otherdata_losterror
othernot_matchinfo
othernot_supportedwarn
otherinvalid_dataerror
+
+ + + diff --git a/ide/src/doc/des_support_event.html b/ide/src/doc/des_support_event.html new file mode 100644 index 0000000000000000000000000000000000000000..d4b448540f894c856f5ba9512c8c03b30dc5d90c --- /dev/null +++ b/ide/src/doc/des_support_event.html @@ -0,0 +1,1016 @@ + + + + des_support_event + + + + + +
+

TraceStreamer支持解析事件列表

+ +

ftrace事件

+ +
binder_transaction
+binder_transaction_received
+binder_transaction_alloc_buf
+binder_transaction_lock
+binder_transaction_locked
+binder_transaction_unlock
+sched_switch
+task_rename
+task_newtask
+tracing_mark_write
+print
+sched_wakeup
+sched_waking
+cpu_idle
+cpu_frequency
+suspend_resume
+workqueue_execute_start
+workqueue_execute_end
+clock_set_rate
+clock_enable
+clock_disable
+clk_set_rate
+clk_enable
+clk_disable
+sys_enter
+sys_exit
+regulator_set_voltage
+regulator_set_voltage_complete
+regulator_disable
+regulator_disable_complete
+ipi_entry
+ipi_exit
+irq_handler_entry
+irq_handler_exit
+softirq_raise
+softirq_entry
+softirq_exit
+sched_wakeup_new
+sched_process_exit
+trace_event_clock_sync
+
+

内存事件

+ +
mem.vm.size
+mem.rss
+mem.rss.anon
+mem.rss.file
+mem.rss.schem
+mem.swap
+mem.locked
+mem.hwm
+mem.oom_score_adj
+
+

系统内存事件

+ +
sys.mem.unspecified
+sys.mem.total
+sys.mem.free
+sys.mem.avaiable
+sys.mem.buffers
+sys.mem.cached
+sys.mem.swap.chard
+sys.mem.active
+sys.mem.inactive
+sys.mem.active.anon
+sys.mem.inactive.anon
+sys.mem.active_file
+sys.mem.inactive_file
+sys.mem.unevictable
+sys.mem.mlocked
+sys.mem.swap.total
+sys.mem.swap.free
+sys.mem.dirty
+sys.mem.writeback
+sys.mem.anon.pages
+sys.mem.mapped
+sys.mem.shmem
+sys.mem.slab
+sys.mem.slab.reclaimable
+sys.mem.slab.unreclaimable
+sys.mem.kernel.stack
+sys.mem.page.tables
+sys.mem.commit.limit
+sys.mem.commited.as
+sys.mem.vmalloc.total
+sys.mem.vmalloc.used
+sys.mem.vmalloc.chunk
+sys.mem.cma.total
+sys.mem.cma.free
+
+

系统虚拟内存事件

+ +
sys.virtual.mem.unspecified
+sys.virtual.mem.nr.free.pages
+sys.virtual.mem.nr.alloc.batch
+sys.virtual.mem.nr.inactive.anon
+sys.virtual.mem.nr.active_anon
+sys.virtual.mem.nr.inactive.file
+sys.virtual.mem.nr.active_file
+sys.virtual.mem.nr.unevictable
+sys.virtual.mem.nr.mlock
+sys.virtual.mem.anon.pages
+sys.virtual.mem.nr.mapped
+sys.virtual.mem.nr.file.pages
+sys.virtual.mem.nr.dirty
+sys.virtual.mem.nr.writeback
+sys.virtual.mem.nr.slab.reclaimable
+sys.virtual.mem.nr.slab.unreclaimable
+sys.virtual.mem.nr.page_table.pages
+sys.virtual.mem.nr_kernel.stack
+sys.virtual.mem.nr.overhead
+sys.virtual.mem.nr.unstable
+sys.virtual.mem.nr.bounce
+sys.virtual.mem.nr.vmscan.write
+sys.virtual.mem.nr.vmscan.immediate.reclaim
+sys.virtual.mem.nr.writeback_temp
+sys.virtual.mem.nr.isolated_anon
+sys.virtual.mem.nr.isolated_file
+sys.virtual.mem.nr.shmem
+sys.virtual.mem.nr.dirtied
+sys.virtual.mem.nr.written
+sys.virtual.mem.nr.pages.scanned
+sys.virtual.mem.workingset.refault
+sys.virtual.mem.workingset.activate
+sys.virtual.mem.workingset_nodereclaim
+sys.virtual.mem.nr_anon.transparent.hugepages
+sys.virtual.mem.nr.free_cma
+sys.virtual.mem.nr.swapcache
+sys.virtual.mem.nr.dirty.threshold
+sys.virtual.mem.nr.dirty.background.threshold
+sys.virtual.mem.vmeminfo.pgpgin
+sys.virtual.mem.pgpgout
+sys.virtual.mem.pgpgoutclean
+sys.virtual.mem.pswpin
+sys.virtual.mem.pswpout
+sys.virtual.mem.pgalloc.dma
+sys.virtual.mem.pgalloc.normal
+sys.virtual.mem.pgalloc.movable
+sys.virtual.mem.pgfree
+sys.virtual.mem.pgactivate
+sys.virtual.mem.pgdeactivate
+sys.virtual.mem.pgfault
+sys.virtual.mem.pgmajfault
+sys.virtual.mem.pgrefill.dma
+sys.virtual.mem.pgrefill.normal
+sys.virtual.mem.pgrefill.movable
+sys.virtual.mem.pgsteal.kswapd.dma
+sys.virtual.mem.pgsteal.kswapd.normal
+sys.virtual.mem.pgsteal.kswapd.movable
+sys.virtual.mem.pgsteal.direct.dma
+sys.virtual.mem.pgsteal.direct.normal
+sys.virtual.mem.pgsteal_direct.movable
+sys.virtual.mem.pgscan.kswapd.dma
+sys.virtual.mem.pgscan_kswapd.normal
+sys.virtual.mem.pgscan.kswapd.movable
+sys.virtual.mem.pgscan.direct.dma
+sys.virtual.mem.pgscan.direct.normal
+sys.virtual.mem.pgscan.direct.movable
+sys.virtual.mem.pgscan.direct.throttle
+sys.virtual.mem.pginodesteal
+sys.virtual.mem.slabs_scanned
+sys.virtual.mem.kswapd.inodesteal
+sys.virtual.mem.kswapd.low.wmark.hit.quickly
+sys.virtual.mem.high.wmark.hit.quickly
+sys.virtual.mem.pageoutrun
+sys.virtual.mem.allocstall
+sys.virtual.mem.pgrotated
+sys.virtual.mem.drop.pagecache
+sys.virtual.mem.drop.slab
+sys.virtual.mem.pgmigrate.success
+sys.virtual.mem.pgmigrate.fail
+sys.virtual.mem.compact.migrate.scanned
+sys.virtual.mem.compact.free.scanned
+sys.virtual.mem.compact.isolated
+sys.virtual.mem.compact.stall
+sys.virtual.mem.compact.fail
+sys.virtual.mem.compact.success
+sys.virtual.mem.compact.daemon.wake
+sys.virtual.mem.unevictable.pgs.culled
+sys.virtual.mem.unevictable.pgs.scanned
+sys.virtual.mem.unevictable.pgs.rescued
+sys.virtual.mem.unevictable.pgs.mlocked
+sys.virtual.mem.unevictable.pgs.munlocked
+sys.virtual.mem.unevictable.pgs.cleared
+sys.virtual.mem.unevictable.pgs.stranded
+sys.virtual.mem.nr.zspages
+sys.virtual.mem.nr.ion.heap
+sys.virtual.mem.nr.gpu.heap
+sys.virtual.mem.allocstall.dma
+sys.virtual.mem.allocstall.movable
+sys.virtual.mem.allocstall.normal
+sys.virtual.mem.compact_daemon.free.scanned
+sys.virtual.mem.compact.daemon.migrate.scanned
+sys.virtual.mem.nr.fastrpc
+sys.virtual.mem.nr.indirectly.reclaimable
+sys.virtual.mem.nr_ion_heap_pool
+sys.virtual.mem.nr.kernel_misc.reclaimable
+sys.virtual.mem.nr.shadow_call.stack_bytes
+sys.virtual.mem.nr.shmem.hugepages
+sys.virtual.mem.nr.shmem.pmdmapped
+sys.virtual.mem.nr.unreclaimable.pages
+sys.virtual.mem.nr.zone.active.anon
+sys.virtual.mem.nr.zone.active.file
+ys.virtual.mem.nr.zone.inactive_anon
+sys.virtual.mem.nr.zone.inactive_file
+sys.virtual.mem.nr.zone.unevictable
+sys.virtual.mem.nr.zone.write_pending
+sys.virtual.mem.oom.kill
+sys.virtual.mem.pglazyfree
+sys.virtual.mem.pglazyfreed
+sys.virtual.mem.pgrefill
+sys.virtual.mem.pgscan.direct
+sys.virtual.mem.pgscan.kswapd
+sys.virtual.mem.pgskip.dma
+sys.virtual.mem.pgskip.movable
+sys.virtual.mem.pgskip.normal
+sys.virtual.mem.pgsteal.direct
+sys.virtual.mem.pgsteal.kswapd
+sys.virtual.mem.swap.ra
+sys.virtual.mem.swap.ra.hit
+
+
+ + + diff --git a/ide/src/doc/des_tables.html b/ide/src/doc/des_tables.html new file mode 100644 index 0000000000000000000000000000000000000000..82879585cca652373870881b3de9970be0fc0a56 --- /dev/null +++ b/ide/src/doc/des_tables.html @@ -0,0 +1,4316 @@ + + + + + des_tables + + + + + + +
+

TraceStreamer数据表概述

+ +

+ TraceStreamer可以将trace数据源转化为易于理解和使用的数据库。用户可以通过SmartPerf界面直观的研究系统跟踪数据,也可在理解TraceStreamer生成的数据库的基础上,在TraceStreamer的交互模式或者Smartperf的数据库查询模式下,使用SQL查询语句自由组装查看用户关心的数据。下文将对TraceStreamer生成的数据库进行详细描述,给用户使用SQL查询系统跟踪数据提供帮助。 +

+

TraceStreamer输出的数据表分类

+ +
    +
  • + 常规泳道图数据表
    + GitHub Logo +
  • +
  • + native memory数据源相关表
    + GitHub Logo +
  • +
  • + perf相关数据表
    + GitHub Logo +
  • +
  • + hisysevent相关数据表
    + GitHub Logo +
  • +
+

TraceStreamer输出数据库包含以下表格

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
表名称作用
app_name记录HiSysEvent事件的事件名与IDE部分事件的字段名为APPNAME中存放的相关信息的映射关系
args记录方法参数集合
bio_latency_sample记录IO操作相关方法调用,及调用栈数据
callstack + 记录调用堆栈和异步调用信息,其中depth,stack_id和parent_stack_id仅在非异步调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号 +
clk_event_filter记录时钟相关的信息
clock_event_filter此结构用来维护时钟事件,cpu与唯一的ID做关联
cpu_measure_filtercpu事件过滤器表
cpu_usage记录CPU使用率事件
data_dict记录常用的字符串,将字符串和索引关联,降低程序运行的内存占用,用作辅助数据
data_type记录数据类型和typeId的关联关系
diskio记录磁盘读写数据事件
ebpf_callstack记录了采样相关信息
file_system_samp记录了调用栈的相关信息
hidump记录FPS(Frame Per Second)数据
hisys_event_measure记录了HiSysEvent事件相关数据,目前HiSysEvent事件包括了异常事件,IDE事件,器件状态事件
instant记录Sched_waking, sched_wakeup事件, 用作ThreadState表的上下文使用
irq记录中断相关事件
live_process记录了一些实时的进程中执行的一些数据
log记录hilog打印日志数据
measure_filter + 记录一个递增的filterid队列,所有其他的filter类型在获取过程中,均从此数据列表中获取下一个可用的filter_id并做记录 +
meta记录执行解析操作相关的基本信息
native_hook记录堆内存申请与释放相关的数据
native_hook_frame记录堆内存申请与释放相关的调用栈
network抓取网络信息传输时产生的一些相关信息
paged_memory_sample记录内存操作相关方法调用,及调用栈数据
perf_callchain记录Hiperf采样数据的调用栈信息
perf_files记录Hiperf工具采集到的函数符号表和文件名
perf_report记录Hiperf工具采集数据时的配置信息。包括
perf_sample记录Hiperf工具的采样信息
perf_thread记录Hiperf工具采集到的进程和线程数据
process记录所有的进程信息
process_filter过滤进程
process_measure保存进程的所有计量值
process_measure_filter将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id
raw此数据结构主要作为ThreadState的上下文使用,这张表是sched_waking,sched_wakup, cpu_idle事件的原始记录
sched_slice此数据结构主要作为ThreadState的上下文使用,这张表是sched_switch事件的原始记录
smaps记录进程的内存消耗的相关信息采样
stat + 此结果用来统计数据解析中各类数据的数据条数,数据和合法性,数据的匹配程度(begin-end),数据的损失等,查看此结构对应的表,可对数据源有基本的了解 +
symbols记录系统调用名称和其函数指针的对应关系,trace中用addr来映射function_name来节省存储空间
syscall记录用户空间函数与内核空间函数相互调用记录
sys_event_filter记录所有的filter
sys_mem_measure记录了所有的系统内存相关的测量信息
thread记录所有的线程信息
thread_filter过滤线程
thread_state记录线程状态信息
trace_range记录ftrace数据与其他类型数据的时间交集,供前端展示数据时使用
clock_snapshot时钟号和时间,时钟名的映射表
datasource_clockid数据源和时钟号的映射表
+

表与事件来源

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
表名称事件源插件名备注
app_name-hisysevent-pluginJSON数据源
args-ftrace-plugin配合callstack使用
callstack-ftrace-plugin异步或非异步的调用
cpu_measure_filter-ftrace-plugincpu跟踪器,cpu频率等
cpu_usage-cpu-plugincpu使用率
data_dict通用的-所有字符串的记录
data_type通用的-辅助表
file_system_callstack--ebpf文件系统
file_system_sample--ebpf文件系统
frame_maps-ftrace-plugin帧渲染数据,app到RS的映射
frame_slice-ftrace-plugin帧渲染数据
gpu_slice-ftrace-plugingpu渲染时长
hidump-hidump-pluginFPS数据
hisys_event_measure-hisysevent-pluginJSON数据源
instant-ftrace-pluginwaking和wakeup事件
irq-ftrace-plugin记录中断事件
live_process-process-pluginMonitor数据
network-network-pluginMonitor数据
diskio-diskio-pluginMonitor数据
log-hilog-plugin系统日志
measure通用的-系统中的计量值(数值型)
measure_filter通用的-计量值的查询辅助表
meta通用的-记录解析现场数据(解析时间,数据类型,解析工具等)
native_hook-nativehook/hookdaemon内存数据
native_hook_frame-nativehook/hookdaemon内存数据
perf_callchain-perf-pluginperf数据(非插件模式)
perf_files--perf数据(非插件模式)
perf_report--perf数据(非插件模式)
perf_sample--perf数据(非插件模式)
perf_thread--perf数据(非插件模式)
process-ftrace-plugin进程信息
process_filter-ftrace-plugin进程计量表的辅助表
process_measure-ftrace-plugin进程内存
process_measure_filter-ftrace-pluginprocess_measure的辅助表
raw-ftrace-plugin线程唤醒信息
sched_slice-ftrace-plugin配合现场状态表使用,dsched_switch的原始数据
smaps-memory-plugin进程的内存消耗
stat通用的-记录不同种类数据的数据量
symbols-ftrace-plugin符号表(地址到字符串的映射)
syscall-ftrace-plugin系统调用 sys_enter/exit
sys_event_filter-ftrace-plugin
sys_mem_measure-memory-plugin系统内存
thread通用的-线程信息(常用)
thread_state通用的ftrace-plugin线程调度图(常用)
trace_range通用的-trace数据的时长
thread_filter通用的ftrace-plugin线程计量跟踪表(比较少用)
clock_snapshot通用的通用的时钟号和时间,时钟名的映射表
datasource_clockid通用的通用的数据源和时钟号的映射表
+

+ 表格关系图 +

+ +
+

进程表与线程表关系

+ +

+ 当一个进程或者线程结束后,系统可能再次将该进程号或者线程号分配给其他进程或者线程,造成一个进程号或线程号代表多个进程或线程的情况。
+ Process和Thread表中的id字段可以唯一标识进程和线程。process表中的id在其他表中用作ipid字段。thread表中的id在其他表中用作itid字段。
+ thread表通过ipid字段关联process表的id字段,可以查询线程归属进程。
+ GitHub Logo +

+

查询举例

+ +
    +
  • + 已知pid = 123,查看当前进程下的所有线程信息,可以使用如下SQL语句:
    + select thread.* from thread, process where process.pid = 123 and thread.ipid = process.id +
  • +
+

线程表与线程运行状态表关系图

+

+ thread_state表记录所有线程的运行状态信息,包含ts(状态起始时间),dur(状态持续时间),cpu, itid, + state(线程状态)。 thread表的id字段与thread_state表的itid字段相关联。
+ GitHub Logo +

+

查询举例

+
    +
  • + 已知tid = 123, 查看当前线程的所有运行状态信息,可以使用如下SQL语句:
    + select thread_state.* from thread, thread_state where thread.tid = 123 and thread.id = + thread_state.itid +
  • +
+

堆内存数据变化表关系图

+ +

+ native_hook表记录堆内存申请(AllocEvent)和释放(FreeEvent)数据。native_hook表通过ipid和itid字段分别与process和thread表的id字段关联,通过callChainId与native_hook_frame表的callChainId字段相关联。
+ native_hook表字段解释如下: +

+
    +
  • + callChainId:唯一标识一次堆内存申请或释放, + 通过与native_hook_frame表关联可以拿到当前申请或释放的函数调用堆栈。 +
  • +
  • addr:堆内存申请/释放的地址。
  • +
  • native_hook_size:堆内存申请/释放的大小。
  • +
+

+ native_hook_frame表记录内存申请/释放的调用堆栈。通过callChainId区分一组调用堆栈,depth为堆栈深度,depth为0时,表示当前行为栈顶数据。
+ GitHub Logo +

+

查询举例

+ +
    +
  • + 已知tid = 123,查看当前线程的所有堆内存变化信息,可以使用如下SQL语句:
    + select native_hook.* from thread, native_hook where thread.tid = 123 and thread.id = native_hook.itid +
  • +
  • + 已知callchainid = 0, 查看当前内存变化调用堆栈
    + select * from native_hook_frame where callChainId = 0 +
  • +
+

日志表与进程线程表关系图

+ +

+ log表记录日志信息。可以根据seq字段的连续性,来判断是否存在日志丢失的情况。
+ GitHub Logo +

+

查询举例

+ +
    +
  • + 已知tid = 123,查看当前线程的所有error级别的日志,可以使用如下SQL语句:
    + select * from log where tid = 123 and level = "error" +
  • +
+

perf表之间关系图

+
    +
  • perf_report:此表记录Hiperf工具采集数据时的配置信息。
  • +
  • perf_thread:此表记录hiperf采集到的进程和线程数据。
  • +
  • + perf_sample:此表中记录Hiperf工具的采样信息。sample_id唯一表识一次采样记录,与perf_callchain表中的sample_id字段相关联。thread_id为线程号。与perf_thread表中的thread_id字段相关联。event_type_id为当前采样的事件类型id,与perf_report表中的id字段相关联。 +
  • +
  • perf_callchain:此表格记录的是调用栈信息。
  • +
  • + Perf_files:此表格主要存放着获取到的函数符号表和文件信息。file_id唯一表识一个文件,与perf_callchain表中的file_id字段相关联。 +
  • +
+

GitHub Logo

+

查询举例

+
    +
  • +

    + 已知同步后的时间戳为28463134340470,查询采样数据
    + select * from perf_sample where timestamp_trace = 28463134340470 +

    +
  • +
  • +

    + 已知同步后的时间戳为28463134340470,查询采样数据对应的的调用栈信息
    + select A.* from perf_callchain as A, perf_sample as B where B.timestamp_trace = 28463134340470 and + A.sample_id = B.sample_id +

    +
  • +
  • +

    + 已知同步后的时间戳为28463134277762,查询采样数据的函数名及文件路径
    + select A.*, B.name, C.path from perf_sample as A, perf_callchain as B, perf_files as C where + A.timestamp_trace = 28463134277762 and B.sample_id = A.sample_id and B.callchain_id = 0 and B.file_id = + C.file_id and C.serial_id = 0 +

    +
  • +
  • +

    + 已知线程号为6700,查询所有的采样记录
    + select * from perf_sample where thread_id = 6700 +

    +
  • +
  • +

    + 已知进程号为7863,查询所有的采样记录
    + select A.* from perf_sample as A, perf_thread as B where B.process_id = 7863 and A.thread_id = + B.thread_id +

    +
  • +
  • +

    + 查询所有采样对应的事件类型
    + select A.*, B.report_value from perf_sample as A, perf_report as B where A.event_type_id = B.id +

    +
  • +
+

帧渲染表之间的关系图

+

+ frame_slice: 记录RS(RenderService)和应用的帧渲染。
+ gpu_slice: 记录RS的帧对应的gpu渲染时长。
+ frame_maps:记录应用到RS的帧的映射关系。
+ GitHub Logo +

+

查询示例

+
    +
  • +

    + 已知进程,查询进程对应的实际渲染帧
    + select * from frame_slice where ipid = 1 +

    +
  • +
  • +

    + 已知进程的实际渲染帧的dst为12,求其对应的RS进程的渲染帧
    + select * from frame_slice where id = 12 +

    +
  • +
  • +

    + 已知RS的渲染帧在frame_slice中所在行是14,求其对应的GPU渲染时长
    + select * from gpu_slice where frame_row = 14 +

    +
  • +
+

TraceStreamer输出数据库表格详细介绍

+ +

app_name表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
flagINT
app_nameINT
app_keyINT
+

表描述

+ +

记录HiSysevent上报事件中的IDE相关事件中APPNAME的表关联信息。

+

字段详细描述

+ +
    +
  • id:用于与表hisys_event_measure表中的key_id字段做对应
  • +
  • app_name:对应的事件的信息ID
  • +
  • app_key:对应的事件的APPNAME字段的信息ID
  • +
+

args表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
keyINT
datatypeINT
valueINT
argsetINT
+

表描述

+ +

记录方法的参数集合。

+

字段详细描述

+ +
    +
  • key:键
  • +
  • datatype:数据类型
  • +
  • value:取值
  • +
  • argset:参数集合
  • +
+

bio_latency_sample表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callchain_idINT
datatypeINT
typeINT
ipidINT
itidINT
start_tsINT
end_tsINT
latency_durINT
tierINT
sizeINT
block_numberTEXT
pathTEXT
dur_per_4kINT
+

表描述

+ +

记录IO操作相关方法调用,及调用栈数据。

+

字段详细描述

+ +
    +
  • callchain_id:调用栈的唯一标识。与ebpf_callstack表中Callchain_id字段关联
  • +
  • + type:事件类型其取值为枚举类型(DATA_READ,DATA_WRITE,METADATA_READ,- METADATA_WRITE,PAGE_IN,PAGE_OUT) +
  • +
  • ipid:TS内部进程号
  • +
  • itid:TS内部线程号
  • +
  • start_ts:开始时间
  • +
  • end_ts:结束时间
  • +
  • latency_dur:总延迟
  • +
  • tier:优先级
  • +
  • size:文件大小
  • +
  • block_number:数据量大小(一般为4K)
  • +
  • path:路径id
  • +
  • dur_per_4k:每4k数据的平均延迟
  • +
+

callstack表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
tsINT
durINT
callidINT
catTEXT
identifyINT
nameTEXT
depthINT
cookieINT
parent_idINT
argsetidINT
chainIdTEXT
spanIdTEXT
parentSpanIdTEXT
flagTEXT
argsTEXT
+

表描述

+ +

+ 记录调用堆栈和异步调用信息,其中depth,stack_id和parent_stack_id仅在非异步的调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号。 +

+

字段详细描述

+ +
    +
  • dur:调用时长
  • +
  • callid:调用者的ID,比如针对线程表里面的id
  • +
  • identify:调用栈的名字,与表dataDict相关联能够取出其string值
  • +
  • name:调用名称
  • +
  • depth:调用深度
  • +
  • parent_id:父调用的id
  • +
  • spanId:分布式调用关联关系
  • +
  • flag:C表示分布式调用发送方,S表示接受方
  • +
  • args:分布式调用函数参数
  • +
+

clk_event_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
cpuINT
+

表描述

+ +

记录时钟信息。

+

字段详细描述

+ +
    +
  • Type:时钟事件类型
  • +
  • Name:时钟事件名称
  • +
+

clock_event_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
cpuINT
+

表描述

+ +

此结构用来维护时钟事件,cpu与唯一的ID做关联。

+

主要字段描述

+ +
    +
  • Type:时钟事件类型
  • +
  • Name:时钟事件名称
  • +
+

cpu_measure_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
cpuINT
+

表描述

+ +

将cpu号作为key1,cpu的频率,空闲等状态作为key2,唯一确定一个filter_id。

+

主要字段描述

+ +
    +
  • Id(filterid), cpu:事件名称,cpu号
  • +
+

cpu_usage表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
durINT
total_loadREAL
user_loadREAL
system_loadREAL
process_numINT
+

表描述

+ +

记录了与CPU使用率相关的数据。

+

主要字段描述

+ +
    +
  • total_load:总负荷
  • +
  • user_load:用户负载
  • +
  • system_load:系统负载
  • +
  • process_num:线程数
  • +
+

data_dict表

+ +

表结构

+ + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
dataTEXT
+

表描述

+ +

此表记录了一个数据类型ID和字符串的映射。

+

主要字段描述

+ +
    +
  • id:索引值
  • +
  • data:字符串
  • +
+

data_type表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeIdINT
descTEXT
+

表描述

+ +

此表记录了一个数据类型ID和数据描述的映射。

+

主要字段描述

+ +
    +
  • typeId::数据类型id
  • +
  • Desc:数据类型描述
  • +
+

diskio表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
durINT
rdINT
wrINT
rd_speedREAL
wr_speedREAL
rd_countINT
wr_countINT
rd_count_speedREAL
wr_count_speedREAL
+

表描述

+ +

记录了与磁盘读写相关的数据。

+

主要字段描述

+ +
    +
  • rd_sectors_kb:读数据的速度
  • +
  • wr_sectors_kb:写入数据的速度
  • +
  • ts:时间戳
  • +
+

ebpf_callstack表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callchain_idINT
depthTEXT
ipTEXT
symbols_idINT
file_path_idINT
+

表描述

+ +

记录了与磁盘读写相关的数据。

+

主要字段描述

+ +
    +
  • callchain_id:调用栈的唯一标识。与ebpf_callstack表中Callchain_id字段关联
  • +
  • depth:调用栈深度。取值为零时表示栈顶
  • +
  • ip:调用栈ip
  • +
  • symbols_id:调用栈函数名称, 与data_dict中的id字段关联
  • +
  • file_path_id:调用栈函数所属文件路径, 与data_dict中的id字段关联
  • +
+

file_system_sample表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
callchain_idINT
typeINT
ipidINT
itidINT
start_tsINT
end_tsINT
durINT
return_valueTEXT
error_codeTEXT
fdINT
file_idINT
sizeINT
first_argumentTEXT
second_argumentTEXT
third_argumentTEXT
fourth_argumentTEXT
+

表描述

+ +

记录了调用栈的相关信息。

+

主要字段描述

+ +
    +
  • callchain_id:调用栈信息ID与file_system_callstack表中call_chain_id字段相关联
  • +
  • type:对应文件操作open,close,read,write
  • +
  • ipid:线程所属的进程ID
  • +
  • start_ts:开始时间
  • +
  • end_ts:结束时间
  • +
  • dur:耗时
  • +
  • return_value:文件操作的返回值
  • +
  • error_code:文件操作发生错误时的错误码
  • +
  • fd:文件描述符fd
  • +
  • file_id:当type为open,close时为其操作的文件路径,当type为read,write时为固定字段(null)
  • +
  • size:在type为read,write时对应的文件的读或者写的大小
  • +
  • first_argument:参数一
  • +
  • second_argument:参数二
  • +
  • third_argument:参数三
  • +
  • fourth_argument:参数四
  • +
+

hidump表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
tsINT
fpsINT
+

表描述

+ +

此表记录了设备的帧率信息,fps。

+

相关字段描述

+ +
    +
  • fps:帧率值
  • +
+

hisys_event_measure表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
serialINT
tsINT
name_idINT
key_idINT
typeINT
int_valueREAL
string_valueTEXT
+

表描述

+ +

记录所有的system event事件的相关数据,及其相关表的映射信息。

+

相关字段描述

+ +
    +
  • serial:每条数据过来携带唯一一条id作为标识
  • +
  • name_id:存放事件对应的ID,与data_dict表相关联可以取出对应的字段
  • +
  • + key_id:存放事件包含的字段的ID,与表app_name的id字段相关联,找到app_name表的 + id字段对应行的app_key字段与表data_dict表相关联取出对应的字段 +
  • +
  • type:存放事件所包含的字段的值所属的类型为int型还是string(0为int,1为string)
  • +
  • int_value:存放本事件所包含的字段的int型的值
  • +
  • string_value:存放本事件所包含的字段的string型的值
  • +
+

instant表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
nameTEXT
refINT
wakeup_fromINT
ref_typeTEXT
valueREAL
+

表描述

+ +

记录了系统中的waking和wakeup事件。

+

字段描述

+ +
    +
  • ts:唤醒时间
  • +
  • name:唤醒事件的名称
  • +
  • ref:索引号
  • +
  • wakeup_from:唤醒当前线程的内部线程号(itid)
  • +
  • ref_type:描述了value字段的类型(一般取值为itid)
  • +
  • value:一般为当前线程的内部线程号取值
  • +
+

irq表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
tsINT
durINT
callidINT
catTEXT
nameTEXT
depthINT
cookieINT
parent_idINT
argsetidINT
chainIdTEXT
spanIdTEXT
parentSpanIdTEXT
flagTEXT
argsTEXT
+

表描述

+ +

记录中断相关事件。

+

相关字段描述

+ +
    +
  • dur:调用中断时长
  • +
  • callid:调用中断者的ID,比如针对线程表里面的id
  • +
  • cat:调用栈数据类型(取值范围:irq,softirq...)
  • +
  • name:调用中断的名称
  • +
  • depth:中断调用的深度
  • +
  • parent_id:父调用中断的id
  • +
  • spanId:分布式调用中断关联关系
  • +
+

live_process表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
durINT
cpu_timeINT
process_idINT
process_nameTEXT
parent_process_idINT
uidINT
user_nameTEXT
cpu_usageREAL
pss_infoINT
thread_numINT
disk_writesINT
disk_readsINT
+

表描述

+ +

记录了一些实时的进程中执行的一些数据(Monitor)。

+

主要字段描述

+ +
    +
  • process_id:进程id
  • +
  • process_name:进程名
  • +
  • parent_process_id:父进程的id
  • +
  • uid:用户id
  • +
  • user_name:用户名
  • +
  • cpu_usage:cpu使用率
  • +
  • pss_info:进程信息
  • +
  • thread_num:线程数量
  • +
  • disk_writes:磁盘写量
  • +
  • disk_reads:磁盘读量
  • +
+

log表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
seqINT
tsINT
pidINT
tidINT
levelTEXT
tagTEXT
contextTEXT
origintsINT
+

表描述

+ +

记录日志信息。

+

关键字段描述

+ +
    +
  • Seq:日志序号,保证日志解析的准确性
  • +
  • Ts:打印日志时间
  • +
  • Pid:日志的进程号
  • +
  • Tid:日志的线程号
  • +
  • Level:日志级别
  • +
  • Tag:日志标签
  • +
  • Context:日志内容
  • +
+

measure表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
typeTEXT
tsINT
durINT
valueINT
filter_idINT
+

表描述

+ +

记录所有的计量值。

+

关键字段描述

+ +
    +
  • type:固定字段(measure)
  • +
  • ts:事件时间
  • +
  • dur:该值持续的时长
  • +
  • value:数值
  • +
  • filter_id:对应filter表中的ID
  • +
+

measure_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
source_arg_set_idINT
+

表描述

+ +

+ 记录一个递增的filterid队列,所有其他的filter类型在获取过程中,均从此数据列表中获取下一个可用的filter_id并做记录。 +

+

字段详细描述

+ +

+ 过滤分类(type),过滤名称(key2),数据ID(key1)。
+ 数据ID在process_measure_filter, sys_event_filter中作为id。 +

+

meta表

+ +

表结构

+ + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
nameTEXT
valueTEXT
+

表描述

+ +

+ 此表记录了数据解析或导出时的一些现场数据,比如使用的TraceStreamer版本, + 工具的发布时间,数据解析的时间,数据的持续时长,以及原始数据的格式。 +

+

主要字段描述

+ +
    +
  • Name:指定元数据的key
  • +
  • Value:指定元数据的value
  • +
+

native_hook表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callChainIdINT
ipidINT
itidINT
event_typeTEXT
sub_type_idNUM
start_tsINT
end_tsINT
durINT
addrINT
heap_sizeINT
all_heap_sizeINT
current_size_durINT
last_lib_idINT
+

表描述

+ +

记录native_hook抓取的某个进程的堆内存,内存映射相关数据。

+

关键字段描述

+ +
    +
  • callChainId:唯一标识一条native_hook数据
  • +
  • event_type:事件类型取值范围(AllocEvent,FreeEvent,MmapEvent, MunmapEvent)
  • +
  • sub_type_id:子事件类型(只有sub_type字段为MmapEvent时,该字段才会有值)
  • +
  • start_ts:申请内存开始时间
  • +
  • end_ts:释放内存时间
  • +
  • Dur:申请内存活跃时间
  • +
  • Addr:申请内存地址
  • +
  • mem_size:申请或释放内存大小
  • +
  • + all_mem_size:从采集数据开始到当前时刻,申请并活跃的内存总量。 + event_type为AllocEvent或者FreeEvent时,表示活跃的堆内存总量。当event_type为MmapEvent或者MunmapEvent时,表示活跃的映射内存总量 +
  • +
  • current_size_dur:表示当前活跃内存总量的持续时间
  • +
  • last_lib_id:函数调用栈他最后一个函数所属的文件路径,除了文件名中带musl和libc++
  • +
+

native_hook_frame表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callchain_idINT
depthINT
symbol_idINT
file_idINT
offsetINT
symbol_offsetINT
+

表描述

+ +

记录了内存的申请和释放的堆栈。

+

相关字段描述

+ +
    +
  • callchain_id:标识一组调用堆栈
  • +
  • depth:调用栈深度
  • +
  • symbol_id:函数名
  • +
  • file_id:函数所属文件
  • +
+

network表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
durINT
txINT
rxINT
tx_speedREAL
rx_speedREAL
packet_inINT
packet_in_secREAL
packet_outINT
packet_out_secREAL
net_typeTEXT
+

表描述

+ +

记录了网络数据传输相关的信息。

+

主要字段描述

+ +
    +
  • tv_sec:时间,秒为单位
  • +
  • tv_nsec:时间,纳秒为单位
  • +
  • tx_bytes:网络数据的写入量
  • +
  • rx_bytes:网络数据的读取量
  • +
+

paged_memory_sample表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callchain_idINT
typeINT
ipidINT
start_tsINT
end_tsINT
durINT
sizeINT
addrTEXT
itidINT
+

表描述

+ +

记录了网络数据传输相关的信息。

+

主要字段描述

+ +
    +
  • callchain_id: 取值相同的一组数据,表示一个完整的调用栈
  • +
  • type:事件类型
  • +
  • ipid:TS内部进程号
  • +
  • start_ts:开始时间
  • +
  • end_ts:结束时间
  • +
  • dur:持续时间
  • +
  • size:操作页数
  • +
  • itid:TS内部线程号
  • +
+

perf_callchain表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callchain_idINT
depthINT
vaddr_in_fileINT
file_idINT
symbol_idINT
nameTEXT
+

表描述

+ +

记录了Hiperf采样数据的调用栈信息。

+

主要字段描述

+ +
    +
  • callchain_id:标识一组调用堆栈
  • +
  • depth:调用栈深度
  • +
  • vaddr_in_file:函数在文件中的虚拟地址
  • +
  • file_id:与PerfFiles中的file_id字段相关联
  • +
  • symbol_id:与PerfFiles中的symbol_id相关联
  • +
  • name:函数名
  • +
+

perf_files表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
file_idINT
serial_idINT
symbolTEXT
pathTEXT
+

表描述

+ +

记录Hiperf工具采集到的函数符号表和文件名。

+

主要字段描述

+ +
    +
  • file_id:文件编号
  • +
  • serial_id:一个文件中可能有多个函数,serial_id表示函数的编号
  • +
  • symbol:函数名
  • +
  • path:文件路径
  • +
+

perf_report表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
report_typeTEXT
report_valueTEXT
+

表描述

+ +

+ 记录Hiperf工具采集数据时的配置信息。包括:抓取的事件类型,抓取数据的命令, 抓数据时指定的进程名称。 +

+

主要字段描述

+ +
    +
  • + report_type:数据类型。取值只有三种类型:config_name(事件类型), workload(抓取的进程名), + cmdline(抓取命令) +
  • +
  • report_value:对应类型的取值
  • +
+

perf_sample表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
callchain_idINT
timestampINT
thread_idINT
event_countINT
event_type_idINT
timestamp_traceINT
cpu_idINT
thread_stateTEXT
+

表描述

+ +

记录Hiperf工具的采样信息。

+

主要字段描述

+ +
    +
  • timestamp:未进行时钟源同步的时间戳
  • +
  • thread_id:线程号
  • +
  • event_count:采样统计
  • +
  • event_type_id:事件类型编号。与PerfReport表的id字段相关联
  • +
  • timestamp_trace:时钟源同步后的时间戳
  • +
  • cpu_id:cpu核编号
  • +
  • + thread_state:线程状态。采样对应Sched_Waking事件时,为Runing;对应Sched_Switch事件时,为Suspend。其余事件类型,为“-” +
  • +
+

perf_thread表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
thread_idINT
process_idINT
thread_nameTEXT
+

表描述

+ +

记录Hiperf工具采集到的进程和线程数据。

+

主要字段描述

+ +
    +
  • thread_id:线程号
  • +
  • process_id:进程号
  • +
  • thread_name:线程名
  • +
+

process表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
ipidINT
typeTEXT
pidINT
nameTEXT
start_tsINT
switch_countINT
thread_countINT
slice_countINT
mem_countINT
+

表描述

+ +

记录了进程相关数据。

+

关键字段描述

+ +
    +
  • id:进程在数据库重新重新定义的id,从0开始序列增长
  • +
  • ipid:TS内部进程id
  • +
  • type:固定取值:process
  • +
  • pid:进程的真实id
  • +
  • name:进程名字
  • +
  • start_ts:开始时间
  • +
  • switch_count:统计内部有多少个线程有切换
  • +
  • thread_count:统计其线程个数
  • +
  • slice_count:进程内有多个线程有slice数据
  • +
  • mem_count:进程是否有内存数据
  • +
+

process_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
ipidINT
+

表描述

+ +

+ 将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, + filter_id同时被记录在filter表中。 +

+

主要字段描述

+ +
    +
  • id:进程id
  • +
  • type:固定取值:process_filter
  • +
  • name:进程名
  • +
  • ipid:该进程表中的id与process表中的id相关联
  • +
+

process_measure表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
typeTEXT
tsINT
valueNUM
filter_idINT
+

表描述

+ +

保存进程的内存,堆栈值等所有计量值信息。

+

字段详细描述

+ +
    +
  • ts:事件时间
  • +
  • value:数值
  • +
  • filter_id:对应process_measure_filter表中的ID
  • +
+

process_measure_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
ipidINT
+

表描述

+ +

+ 将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, + filter_id同时被记录在measure_filter表中。 +

+

字段详细描述

+ +
    +
  • type:固定取值:process_measure_filter
  • +
  • name:cpu状态名
  • +
  • ipid:进程内部编号
  • +
+

raw表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
tsINT
nameTEXT
cpuINT
itidINT
+

表描述

+ +

记录了系统中的waking、wakup、cpu_idel、cpu_frequency数据。

+

相关字段描述

+ +
    +
  • type:固定字段(raw)
  • +
  • name:调度名称(取值:cpu_idle,sched_wakeup,sched_waking)
  • +
  • cpu:事件发生在哪个CPU
  • +
  • itid:时间对应哪个utid
  • +
+

sched_slice表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
tsINT
durINT
ts_endINT
cpuINT
itidINT
end_stateTEXT
priorityINT
+

表描述

+ +

此数据结构主要作为ThreadState的上下文使用,这张表是sched_switch事件的原始记录。

+

主要字段描述

+ +
    +
  • ts:事件发生事件
  • +
  • type:固定字段(sched_slice)
  • +
  • dur:状态持续时长
  • +
  • ts_end:状态结束时长
  • +
  • cpu:事件发生在哪个cpu
  • +
  • itid:事件对应哪个utid
  • +
  • end_state:线程的终结状态
  • +
+

smaps表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
timestampINT
start_addrTEXT
end_addrTEXT
dirtyINT
swapperINT
resident_sizeINT
pssINT
virtaul_sizeINT
resideREAL
protection_idINT
path_idINT
+

表描述

+ +

记录进程的内存消耗的相关信息采样。

+

主要字段描述

+ +
    +
  • id:状态持续时长
  • +
  • timestamp:事件发生事件
  • +
  • start_addr:内存段地址的起始位置
  • +
  • end_addr:内存段地址的结束位置
  • +
  • dirty:其他进程共享的被写的页的大小 + 已被改写的私有页面的大小
  • +
  • swapper:存在于交换分区的数据大小
  • +
  • resident_size:实际分配的内存大小
  • +
  • pss:平摊计算后的实际物理使用内存
  • +
  • virtaul_size:虚拟内存空间的大小
  • +
  • reside:实际分配的内存大小与虚拟内存空间的大小的比
  • +
  • protection_id:内存段的权限id与表data_dict的id字段相关联
  • +
  • path_id:如果区域是从文件映射的,则这是文件的名称对应的id序号与表data_dict的id字段相关联
  • +
+

stat表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
event_nameTEXT
stat_typeTEXT
countINT
serverityTEXT
sourceTEXT
+

表描述

+ +

+ 此结果用来统计数据解析中各类数据的数据条数,数据和合法性,数据的匹配程度(begin-end),数据的损失等,查看此结构对应的表,可对数据源有基本的了解。 +

+

主要字段描述

+ +
    +
  • event_name:数据类型
  • +
  • stat_type:数据状态
  • +
  • count:数据条数
  • +
  • severity:严重级别
  • +
  • source:数据来源
  • +
+

symbols表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
funcnameTEXT
addrINT
+

表描述

+ +

此表记录了被调用函数与其地址的映射关系。

+

相关字段描述

+ +
    +
  • funcname:系统调用名称
  • +
  • adr:系统调用地址
  • +
+

syscall表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
syscall_numINT
typeTEXT
ipidINT
tsINT
retINT
+

表描述

+ +

记录用户空间函数与内核空间函数相互调用记录。

+

相关字段描述

+ +
    +
  • syscall_num:系统调用的序号
  • +
  • type:固定取值:enter或者exit
  • +
  • ipid:线程所属的进程ID
  • +
  • ts:时间戳
  • +
  • ret:返回值,在type为exit时有效
  • +
+

sys_event_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
+

表描述

+ +

记录所有的filter。

+

相关字段描述

+ +
    +
  • type:文件类型
  • +
  • name:文件名
  • +
+

sys_mem_measure表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
typeTEXT
tsINT
valueINT
filter_idINT
+

表描述

+ +

记录系统内存与系统虚拟内存。

+

相关字段描述

+ +
    +
  • ts:事件时间
  • +
  • value:数值
  • +
  • filter_id:对应filter表中的ID
  • +
+

thread表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
itidINT
typeTEXT
tidINT
nameTEXT
start_tsINT
end_tsINT
ipidINT
is_main_threadINT
switch_countINT
+

表描述

+ +

记录了线程相关数据。

+

字段详细描述

+ +
    +
  • id:线程在数据库重新重新定义的id,从0开始序列增长
  • +
  • itid:TS内部线程id
  • +
  • type:固定字段(thread)
  • +
  • tid:线程号
  • +
  • name:线程名
  • +
  • start_ts:开始时间
  • +
  • end_ts:结束时间
  • +
  • ipid:线程所属的进程id, 关联process表中的ID
  • +
  • is_main_thread:是否主线程,主线程即该线程实际就是进程本身
  • +
  • switch_count:当前线程的切换次数
  • +
+

thread_filter表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
nameTEXT
itidINT
+

表描述

+ +

+ 将线程ID作为key1,线程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, + filter_id同时被记录在filter表中。 +

+

主要字段描述

+ +
    +
  • id:线程id
  • +
  • type:线程类型
  • +
  • name:线程名称
  • +
  • itid:该表中的tid与thread表中的tid相关联
  • +
+

thread_state表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
idINT
typeTEXT
tsINT
durINT
cpuINT
itidINT
tidINT
pidINT
stateTEXT
+

表描述

+ +

记录了线程状态相关的数据。

+

字段详细描述

+ +
    +
  • id:线程状态在数据库中的id,从0开始序列增长
  • +
  • ts:该线程状态的起始时间
  • +
  • dur:该线程状态的持续时间
  • +
  • cpu:该线程在哪个cpu上执行(针对running状态的线程)
  • +
  • itid:该状态所属的线程id, 关联线程表中的id
  • +
  • tid:线程号
  • +
  • pid:进程号
  • +
  • state:线程实际的的状态值
  • +
+
'R', Runnable状态
+'S', interruptible sleep
+'D', uninterruptible sleep
+'T', Stoped
+'t', Traced
+'X', ExitedDead
+'Z', ExitZombie
+'x', TaskDead
+'I', TaskDead
+'K', WakeKill
+'P', Parked
+'N', NoLoad
+
+

clock_snapshot表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
clock_idINT
tsINT
clock_nameTEXT
+

表描述

+ +

时钟号和时间,时钟名的映射表。

+

关键字段描述

+ +
    +
  • clock_id:时钟号
  • +
  • ts:时钟快照报的时间
  • +
  • + clock_name:时钟号对应的时钟名字
    + 时钟快照是用来对齐不同时钟号的时间
    + 比如,时钟号1的时间100,和时钟号2的时间200对齐
    + 则时钟号为2 的250,转换为时钟号1的时间后,为150 +
  • +
+

datasource_clockid表

+ +

表结构

+ + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
data_source_nameTEXT
clock_idINT
+

表描述

+ +

数据源和时钟号的映射表。

+

关键字段描述

+ +
    +
  • data_source_name:数据源的名称,和数据源的插件名保持一致
  • +
  • + clock_id:时钟号,对应clock_snapshot中的时钟号
    + 这个表是用来告诉IDE,不同的事件源的事件,原始时钟号是多少,在数据库中保存的事件,通常是转换为boottime后的时间,但有些情况下,IDE仍然需要知道原始的时钟号是怎样的 +
  • +
+

frame_slice表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
vsyncINT
ipidINT
itidINT
callstack_idINT
durINT
srcTEXT
dstINT
typeINT
flagINT
depthINT
frame_noINT
+

表描述

+ +

应用的实际渲染帧和期望渲染帧的开始时间,持续时长,以及RenderService和App之间的关联关系。

+

关键字段描述

+ +
    +
  • callstack_id:该帧数据对应着callstack表的调用栈所在的行数
  • +
  • dur:该帧渲染时长(当数据不完整时,改行数据为空)
  • +
  • src:该帧是被哪一帧(该表中对应的行数)触发的,有多个值时,用逗号分割
  • +
  • dst:该帧对应的渲染帧是哪一行
  • +
  • type: 0 说明该行数据是实际渲染帧, 1 说明该行数据是期望渲染帧
  • +
  • + flag: 空时,为不完整的数据;0 表示实际渲染帧不卡帧, 1 表示实际渲染帧卡帧, 2 + 表示数据不需要绘制(没有frameNum信息) +
  • +
  • depth:预留
  • +
  • frame_no:预留
  • +
+

frame_maps表

+ +

表结构

+ + + + + + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
tsINT
src_rowINT
dst_rowINT
+

表描述

+ +

该表记录了app到RenderService的帧的映射关系,同frame_slice表中的src映射到dst的关系。

+

关键字段描述

+ +
    +
  • src_row:frame_slice表中app的帧所在的行
  • +
  • dst_row:frame_slice表中RenderService的帧所在的行
  • +
+

gpu_slice表

+ +

表结构

+ + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
frame_rowINT
durINT
+

表描述

+ +

该表记录了每一帧数据在GPU上的渲染时长。

+

关键字段描述

+ +
    +
  • frame_row:frame_slice表中渲染帧所在的行
  • +
  • dur:帧渲染时长
  • +
+

trace_range表

+ +

表结构

+ + + + + + + + + + + + + + + + + + +
Columns NameSQL TYPE
start_tsINT
end_tsINT
+

表描述

+ +

记录解析解析开始时间以及结束时间。

+

关键字段描述

+ +
    +
  • start_ts:trace的开始时间,纳秒为单位
  • +
  • end_ts:trace的结束时间,纳秒为单位
  • +
+
+ + + + diff --git a/ide/src/doc/des_wakup.html b/ide/src/doc/des_wakup.html new file mode 100644 index 0000000000000000000000000000000000000000..1a586723b774bbb24bb0dbfecdb7000a5ed22e9c --- /dev/null +++ b/ide/src/doc/des_wakup.html @@ -0,0 +1,804 @@ + + + + des_wakup + + + + + +
+

+ 各应用程序对于trace事件的waking和wakeup处理是略有区别的。
+ waking是开始唤醒线程,wakeup是线程正式被唤醒,进入runnable(可运行状态)
+ 我们的策略是:被唤醒才是真正进入runnable状态,在没有wakeup事件的情况下,以waking为准。 +

+
+ + + diff --git a/ide/src/doc/md/quickstart_Frametimeline.md b/ide/src/doc/md/quickstart_Frametimeline.md new file mode 100644 index 0000000000000000000000000000000000000000..99d722b3f9eb6ffe06db66600f5ddc22f6d40879 --- /dev/null +++ b/ide/src/doc/md/quickstart_Frametimeline.md @@ -0,0 +1,47 @@ +# Frame timeline抓取和展示说明 +抓取和展示卡顿丢帧检测的数据。 +## Frame timeline的抓取 +### Frame timeline抓取界面配置说明 +打开Frame timeline开关抓取Frametimeline数据。 +![GitHub Logo]( ../../figures/Frame/frameset.jpg) +### Frame timeline文件的抓取 +点击Record setting,在output file path输入文件名hiprofiler_dataframe.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo]( ../../figures/Frame/framesetting.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。 +![GitHub Logo]( ../../figures/Frame/frameexcuting.jpg) +## Frame timeline功能介绍 +将抓取的文件导入到smartperf工具查看。 +### Frame timeline泳道图展示 +Frame timeline展开就可以看到泳道图,泳道图上可以显示帧编号。 +![GitHub Logo]( ../../figures/Frame/framechart.jpg) ++ Expected Timeline:理想帧泳道图。 ++ Actual Timeline:真实帧泳道图。 +### Frame timeline泳道图的框选功能 +可以对真实帧数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格。 +Frames的Tab页如图: +![GitHub Logo]( ../../figures/Frame/frameprocess.jpg) ++ Jank Type:卡顿类型。 ++ Min duration:最小持续时间。 ++ Max duration:最大持续时间。 ++ Mean duration:平均持续时间。 ++ Occurrences:事件数。 +### Frame timeline泳道图的点选功能 +通过点选理想帧和真实帧展示Tab页(Current Selection)。 +理想帧Tab页如下图: +![GitHub Logo]( ../../figures/Frame/frameexpectedtab.jpg) ++ Name:帧编号。 ++ StartTime:启动时间。 ++ Absolute Time:绝对时间。 ++ Duration:持续时间。 ++ Process:进程名。 +真实帧Tab页如下图: +![GitHub Logo]( ../../figures/Frame/frameactualtab.jpg) ++ Name:帧编号。 ++ StartTime:启动时间。 ++ Absolute Time:绝对时间。 ++ Duration:持续时间。 ++ Process:进程名。 ++ Jank Type:卡顿类型。 ++ Gpu Duration:GPU耗时。 ++ FrameTimeLine flows:显示的是绘制一帧的完整过程, 由两个阶段组成应用的提交一帧。 ++ Following flows:展示真实帧包含的关联的帧,图中斜向上箭头点击会进行跳转功能直接定位到具体进程真实帧位置,点选的同时还将包含的关联帧通过线连起来,可以跨越多个进程。 diff --git a/ide/src/doc/md/quickstart_Js_memory.md b/ide/src/doc/md/quickstart_Js_memory.md new file mode 100644 index 0000000000000000000000000000000000000000..cbdf468c83683df9cf98011854ee668589fa67a2 --- /dev/null +++ b/ide/src/doc/md/quickstart_Js_memory.md @@ -0,0 +1,61 @@ +# Js Memory抓取和展示说明 +Js Memory是查看程序中存量内存的情况。 +## Js Memory的抓取 +### Js Memory抓取配置参数 +![GitHub Logo](../../figures/Jsmemory/jsmemorysetting.jpg) +配置参数说明: +* Process:设置抓取的进程ID,此处以1747进程号为例。 +* Heap snapshot:堆快照性能分析会显示网页的JavaScript对象和相关DOM节点中内存分配情况。 +* include numerical values in capture:在快照中添加数字。 +* Interval:抓取的时间间隔。 +* Allocation insteumentation on timeline:分配时间轴显示了插桩的JavaScript内存分配随时间变化的情况。 +* record stack traces of allocations(extra performance overhead):录制各项分配的堆栈轨迹(会产生额外的性能开销)。 + +再点击Record setting,在output file path输入文件名hiprofiler_data_jsmemory.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是30s。 +![GitHub Logo](../../figures/Jsmemory/jsmemoryset.jpg) + +点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。 +![GitHub Logo](../../figures/Jsmemory/jsmemoryrecord.jpg) +## Js Memory展示说明 +将抓取的jsmemory文件导入到smartperf工具中查看,查看程序中存量内存的情况。 +### Js Memory泳道图展示类型 +堆快照类型文件的泳道图展示。 +![GitHub Logo](../../figures/Jsmemory/jsnapshotChart.jpg) ++ Heapsnapshot:堆快照性能分析会显示网页的JavaScript对象和相关DOM节点中内存分配情况。 +时间轴上分配插桩类型文件的泳道图展示。 +![GitHub Logo](../../figures/Jsmemory/jstimelineChart.jpg) ++ Heaptimeline:分配时间轴显示了插桩的JavaScript内存分配随时间变化的情况。 + +### Js Memory泳道图的框选功能 +可以对内存的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有两个tab页。 +Summary的Tab页,主要显示了总览视图,通过类的名称来分组显示对象。 +![GitHub Logo](../../figures/Jsmemory/JsSummary.jpg) ++ Constructor:类创建的所有对象,其中 + 第一层为类名,后面的x表示该类创建了多少实例。 + 第二层为该类的实例名+id,id唯一。 + 第三层以下为实例中的成员变量。 ++ Distance:使用节点的最短简单路径显示到根的距离。 ++ ShallowSize:类创建的所有对象的本身的内存大小之和。 ++ RetainedSize:对象以及其相关的对象一起被删除后所释放的内存大小,同一组对象之间的最大保留大小。 +Comparison的Tab页,主要显示了比较视图,显示两份快照间的不同之处,主要比较类创建与释放的实例数量。 +![GitHub Logo](../../figures/Jsmemory/JsComparison.jpg) ++ #Constructor:类创建的所有对象,类名与id相同视为同一个实例,其中 + 第一层为类的比较,每个时间点的对比其他时间点的类创建与销毁了哪些实例。 + 第二层为实例,由于展示的是创建或者销毁实例,固只展示Size大小。 + 第三层以下为实例的成员变量,不存在比较信息。 ++ #New:新增的实例数量,圆点代表有意义的数据,下划线代表无意义的数据。 ++ #Deleted:删除的实例数量。 ++ #Delta:#New减去#Deleted的数量。 ++ Alloc.Size:新增实例的Size。 ++ Freed Size:删除实例的Size。 ++ Size Delta:Delta的Size。 +### Js Memory的辅助信息功能 +在Summary和Comparison的Tab页,选中左边实例,右边Retainers的Tab页会显示多少个实例引用了左边选中的实例。 +![GitHub Logo](../../figures/Jsmemory/jsmemorycallstack.jpg) ++ Object:引用的实例。 ++ Distance:使用节点的最短简单路径显示到根的距离。 ++ ShallowSize:所有对象的本身的内存大小之和。 ++ RetainedSize:对象以及其相关的对象一起被删除后所释放的内存大小,同一组对象之间的最大保留大小。 +### Js Memory详细显示的过滤功能 +在下方的Class Filter中输入类名,可以对类名进行过滤,如下图输入array,会过滤出类名是array的相关数据。 +![GitHub Logo](../../figures/Jsmemory/Jsmemoryfilter.jpg) \ No newline at end of file diff --git a/ide/src/doc/md/quickstart_ability_monitor.md b/ide/src/doc/md/quickstart_ability_monitor.md new file mode 100644 index 0000000000000000000000000000000000000000..083c87af83e4a3ada6ea1c95576f9e2055b99511 --- /dev/null +++ b/ide/src/doc/md/quickstart_ability_monitor.md @@ -0,0 +1,113 @@ +# Ability Monitor抓取和展示说明 +抓取和展示处理的CPU,内存,磁盘IO和网络使用情况统计。 +## Ability Monitor的抓取 +### Ability Monitor抓取界面配置说明 +点击Probes config,如选择抓取AbilityMonitor。 +![GitHub Logo]( ../../figures/AbilityMonitor/abilityset.jpg) +### Ability Monitor文件的抓取 +点击Record setting,在output file path输入文件名hiprofiler_data_abilitymonitor.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo]( ../../figures/AbilityMonitor/abilitysetting.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。 +![GitHub Logo]( ../../figures/AbilityMonitor/abilitycommand.jpg) +输入hdc_shell,进入设备,执行命令。 +![GitHub Logo]( ../../figures/AbilityMonitor/abilityexcutecommand.jpg) +进入指定目录,cd /data/local/tmp进入到目录,会看到生成的trace文件。 +![GitHub Logo]( ../../figures/AbilityMonitor/abilityhtrace.jpg) +## Ability Monitor功能介绍 +将抓取的文件导入到smartperf工具查看,能了解CPU,内存,磁盘IO和网络的使用情况。 +### Ability Monitor泳道图展示 +Ability Monitor展开就可以看到泳道图,包括CPU,内存,磁盘IO,网络的使用情况。 +![GitHub Logo]( ../../figures/AbilityMonitor/abilitymonitorflowchart.jpg) ++ CPU Total Load:总的CPU使用率。 ++ CPU User Load:CPU在用户态空间运行的使用率。 ++ CPU System Load:CPU在内核空间运行的使用率。 ++ MemoryTotal: 总计物理内存的大小。 ++ Cached:缓存的大小。 ++ SwapTotal: 虚拟内存。 ++ Disk Bytes Read/Sec:每秒从磁盘读取到内存的字节数。 ++ Disk Bytes Written/Sec: 每秒从内存写入磁盘的字节数。 ++ Disk Read Ops/Sec:读入的字节数。 ++ Disk Written Ops/Sec: 写入的字节数。 ++ Network Bytes In/Sec:每秒接收的网络数据字节数。 ++ Network Bytes Out/Sec: 每秒发送的网络数据字节数。 ++ Network Packets In/Sec:每秒接收的网络数据包数。 ++ Network Packets Out/Sec: 每秒发送的网络数据包数。 +### Ability Monitor泳道图的框选功能 +可以对CPU,内存,磁盘IO和网络的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有六个tab页。 +Live Processes的Tab页如图: +![GitHub Logo]( ../../figures/AbilityMonitor/liveprocess.jpg) ++ Process ID:进程的ID。 ++ Process Name:进程名称。 ++ Responsible Process:父进程ID。 ++ User ID:用户ID。 ++ %CPU:进程的CPU占用率。 ++ CPU Time:CPU运行时间。 ++ #Threads:进程的线程数量。 ++ Memory:内存值。 ++ Disk Writes(B):磁盘读入的字节数。 ++ Disk Reads(B):磁盘写入的字节数。 +Processes History的Tab页如图: +![GitHub Logo]( ../../figures/AbilityMonitor/ProcessesHistory.jpg) ++ Process ID:进程ID。 ++ Alive:进程是否存活。 ++ First Seen:开始时间。 ++ Last Seen:所选区域的结束时间。 ++ Process Name:进程名称。 ++ Responsible Process:父进程ID。 ++ User ID:用户ID。 ++ CPU Time:CPU运行时间。 +框选CPU Total Load,CPU User Load,CPU System Load三个区域的泳道图,会展示System CPU Summary的Tab页。 +![GitHub Logo]( ../../figures/AbilityMonitor/cpusummary.jpg) ++ Start Time:采集时间的时间戳。 ++ Duration:前一次采集到本次采集的时间差。 ++ TotalLoad%:总的CPU使用率。 ++ UserLoad%:CPU在用户态空间运行的使用率。 ++ SystemLoad%:CPU在内核空间运行的使用率。 ++ Process:进程号。 +框选MemoryTotal,Cached,SwapTota三个区域的泳道图,会展示System Memory Summary的Tab页。 +![GitHub Logo]( ../../figures/AbilityMonitor/memorytab.jpg) ++ Start Time:采集时间的时间戳。 ++ Duration:前一次采集到本次采集的时间差。 ++ MemTotal:总内存大小。 ++ MemFree:空闲内存大小。 ++ Buffers:文件的缓冲大小。 ++ Cached:缓存的大小。 ++ Shmem:已被分配的共享内存大小。 ++ Slab:内核数据缓存大小。 ++ SUnreclaim:不可回收的Slab大小。 ++ Swap Toal:交换空间的总大小。 ++ SwapFree:未被使用交换空间的大小。 ++ Mapped:设备和文件等映射的大小。 ++ VmallocUsed:已被使用的虚拟内存大小。 ++ PageTables:管理内存分页的索引表大小。 ++ KernelStack:Kernel消耗的内存。 ++ Active: 在活跃使用中的缓冲或高速缓冲存储器页面文件的大小。 ++ Inactive:在不经常使用中的缓冲或高速缓冲存储器页面文件的大小。 ++ Unevictable:不能被释放的内存页。 ++ VmallocTotal:可以vmalloc虚拟内存大小。 ++ CmaTotal:总的连续可用内存。 ++ CmaFree:空闲的可用内存。 +框选Disk Bytes Read/Sec,Disk Bytes Written/Sec,Disk Read Ops/Sec,Disk Written Ops/Sec四个区域的泳道图,会展示System Disk Summary的Tab页。 +![GitHub Logo]( ../../figures/AbilityMonitor/disktab.jpg) ++ Start Time:采集时间的时间戳。 ++ Duration:前一次采集到本次采集的时间差。 ++ Data Read:从磁盘读取到内存的总字节数。 ++ Data Read/sec:每秒从磁盘读取到内存的字节数。 ++ Data Write:从磁盘写入磁盘的总字节数。 ++ Data Write/sec:每秒从内存写入磁盘的字节数。 ++ Reads In:读入的字节数。 ++ Reads In/sec:每秒读入的字节数。 ++ Write Out:写入的字节数。 ++ Write Out/sec:每秒写入的字节数。 +框选Network Bytes In/Sec,Network Bytes Out/Sec,Network Packets In/Sec,Network Packets Out/Sec四个区域的泳道图,会展示System Network Summary的Tab页。 +![GitHub Logo]( ../../figures/AbilityMonitor/network.jpg) ++ Start Time:采集时间的时间戳。 ++ Duration:前一次采集到本次采集的时间差。 ++ Data Received:接收的网络数据总字节数。 ++ Data Received/sec:每秒接收的网络数据字节数。 ++ Data Send:发送的网络数据总字节数。 ++ Data Send/sec:每秒发送的网络数据字节数。 ++ Packets In:接收的网络总数据包数。 ++ Packets In/sec:每秒接收的网络数据包数。 ++ Packets Out:发送的网络总数据包数。 ++ Packets Out/sec:每秒发送的网络数据包数。 diff --git a/ide/src/doc/md/quickstart_bio.md b/ide/src/doc/md/quickstart_bio.md new file mode 100644 index 0000000000000000000000000000000000000000..d4182083de97647a1521fb00cf857e41df006b65 --- /dev/null +++ b/ide/src/doc/md/quickstart_bio.md @@ -0,0 +1,85 @@ +# Bio的抓取和展示说明 +抓取和展示IO延迟的数据。 +## Bio的抓取 +### Bio抓取配置参数 +![GitHub Logo](../../figures/Bio/Biosetting.jpg) +配置项说明: ++ Start BIO Latency Record:配置项的总开关。 ++ Process:默认配置的是整个系统的,也可选择单进程抓取。 ++ Max Unwind Level:配置抓取调用栈的最大深度。 +再点击Record setting,在output file path输入文件名hiprofiler_data_bio.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/Bio/Biorecord.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。 +![GitHub Logo](../../figures/Bio/Bioexcuting.jpg) +### Bio展示说明 +抓取结束后Bio的trace会自动加载展示。 +![GitHub Logo](../../figures/Bio/Biosummary.jpg) + +界面布局介绍:页内存整体界面布局分为3个部分: ++ 红色区域:泳道图。 ++ 绿色区域:详细信息。 ++ 黄色区域:辅助信息(Callstack)。 + +### Bio泳道图展示 +Bio泳道图鼠标悬浮以10ms为区间展示该周期内最大的读或者写延迟。 +![GitHub Logo](../../figures/Bio/Biochart.jpg) +### Bio泳道图的框选功能 +可以对泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有三个tab页。 +Disk I/O Tier Statistics的Tab页如图: +![GitHub Logo](../../figures/Bio/Biostatistics.jpg) ++ Tier/Process/Path:按照Tier,Process,Path的维度去展示。 ++ Count:事件数量。 ++ Total Latency:每种进程,事件的总延迟。 ++ Min Total Latency:最小延迟时间。 ++ Avg Total Latency:平均延迟时间。 ++ Max Total Latency:最大延迟时间。 +Disk I/O Latency Calltree的Tab页如图: +![GitHub Logo](../../figures/Bio/BioCalltree.jpg) ++ Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。 ++ Local:为该调用方法自身占用的CPU时间。 ++ Weight:调用方法的执行占比。 +Trace Completion Times的Tab页如图: +![GitHub Logo](../../figures/Bio/Biotimes.jpg) ++ Start:事件的开始时间。 ++ Total Latency:事件的延迟时间。 ++ Process:进程名(pid)。 ++ Thread:线程名(tid)。 ++ Latency per 4KB:原始数据里没有,每4k数据的延迟时间,需要根据延迟的size跟延迟的时间去计算。 ++ Opration:事件类型。 ++ Bytes:延迟的数据量。 ++ Path:操作的文件路径。 ++ Block Number:块数量。 ++ Tier:层级。 ++ BackTrace:调用栈顶部函数,并显示调用栈深度。 +### Bio支持多种Options展示风格 +点击Disk I/O Latency Calltree的Tab页底部的Options,会有两个CheckBox复选框。 +![GitHub Logo](../../figures/Bio/BioOptions.jpg) ++ Invert:反向输出调用树。 ++ Hide System so:隐藏系统库文件 。 +### Bio支持过滤调用栈调用次数的展示风格 +点击Disk I/O Latency Calltree的Tab页底部的Sample Counter Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。 +![GitHub Logo](../../figures/Bio/Biocounter.jpg) + +### Bio功能的调用栈Group展示-数据分析支持剪裁功能 +![GitHub Logo](../../figures/Bio/Biodatamining.jpg) ++ 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 + ++ 裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。 ++ 点击Reset按钮,将恢复选中的裁剪内容。 +### Bio功能的调用栈Group展示支持按条件过滤 +在Input Filter输入关键字,会显示出带有该关键字的展示信息。 + ![GitHub Logo](../../figures/Bio/Bioinputfilter.jpg) +### Bio辅助信息区展示调用栈 +当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。如下图的Heaviest Stack Trace: + ![GitHub Logo](../../figures/Bio/Bioheaviesttrace.jpg) +### Bio的Tier的过滤 + 通过选择根据Tier去过滤。 + ![GitHub Logo](../../figures/Bio/Biofilter.jpg) +### Bio的火焰图功能 +点击Disk I/O Latency Calltree左下角的柱状图的图标,会切换到火焰图页面。 +![GitHub Logo](../../figures/Bio/Bioflame.jpg) +进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和Duration时长。 +![GitHub Logo](../../figures/Bio/Bioflameshow.jpg) +鼠标左键火焰图,会进入下一级界面,右键回到上一级。 +![GitHub Logo](../../figures/Bio/Bioflamelevel.jpg) + diff --git a/ide/src/doc/md/quickstart_device_record.md b/ide/src/doc/md/quickstart_device_record.md new file mode 100644 index 0000000000000000000000000000000000000000..37598543904bfd6f396ef7656419fa8e969e5725 --- /dev/null +++ b/ide/src/doc/md/quickstart_device_record.md @@ -0,0 +1,37 @@ +# 设备端抓取trace说明 +从设备端抓取trace文件的配置和方法。 +## 界面配置说明 +![GitHub Logo](../../figures/hiprofilercmd/systraceconfig.jpg) +说明: +* Record setting:设置trace的抓取模式,buffer size大小,抓取时长。 +* Trace command:生成的抓取命令行。 +* Probes config:trace的抓取参数配置。 +* Native Memory:NativeMemory数据的抓取参数配置。 +* Hiperf:Hiperf数据的抓取参数配置。 +* eBPF Config:ebpf数据的抓取参数配置。 +* VM Tracker:smaps数据的抓取参数配置。 +* HiSystemEvent:HiSystemEvent数据抓取参数配置。 +* SDK Config:SDK数据抓取参数配置。 +## 命令行的生成和trace文件的抓取 +点击Probes config,如选择抓取Scheduling details。 +![GitHub Logo](../../figures/hiprofilercmd/Scheduling.jpg) +再点击Record setting,在output file path输入文件名hiprofiler_data_example.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/hiprofilercmd/tracesetting.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。 +![GitHub Logo](../../figures/hiprofilercmd/command.jpg) +命令参数说明: +* -o:文件的输入路径和名称。 +* -t:抓取的时长。 +* buffer pages:buffer size大小。 +* sample_duration:数据采集的时间。 +* sample_interval:主动获取插件数据的间隔时间(ms,只针对轮询插件,例如memory插件,cpu插件,dikio插件等,对流式插件和独立插件无效)。 +* trace_period_ms:ftrace插件读取内核缓冲区数据的间隔时间(ms)。 +* hitrace_time:hitrace命令行抓取时间,与hiprofiler_cmd下发的-t配置联动。 + +输入hdc_std shell,进入设备,执行命令。 +![GitHub Logo](../../figures/hiprofilercmd/excutecommand.jpg) + +执行完成后,命令行会给出提示。 +![GitHub Logo](../../figures/hiprofilercmd/commandend.jpg) +进入指定目录,cd /data/local/tmp 进入到目录,会看到生成的trace文件。 +![GitHub Logo](../../figures/hiprofilercmd/htrace.jpg) \ No newline at end of file diff --git a/ide/src/doc/md/quickstart_filesystem.md b/ide/src/doc/md/quickstart_filesystem.md new file mode 100644 index 0000000000000000000000000000000000000000..838175afd5f7cb22931ea1ef762740d16c1736c0 --- /dev/null +++ b/ide/src/doc/md/quickstart_filesystem.md @@ -0,0 +1,110 @@ +# FileSystem的抓取和展示说明 +FileSystem分析文件系统的信息和活动,比如读和写操作等。 +## FileSystem的抓取 +### FileSystem抓取配置参数 +![GitHub Logo](../../figures/FileSystem/filesystemsetting.jpg) +配置项说明: ++ Start FileSystem Record:配置项的总开关。 ++ Process:默认配置的是整个系统的,也可选择单进程抓取。 ++ Max Unwind Level:配置抓取调用栈的最大深度。 + +再点击Record setting,在output file path输入文件名hiprofiler_data_filesystem.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/FileSystem/filesystemrecord.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。 +![GitHub Logo](../../figures/FileSystem/FileSystemcommand.jpg) +输入hdc_std shell,进入设备,执行命令。 +![GitHub Logo](../../figures/FileSystem/FileSystemexcutecommand.jpg) +执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。 +![GitHub Logo](../../figures/FileSystem/FileSystemfile.jpg) +### FileSystem展示说明 +将抓取的trace文件导入smartperf界面查看。 +![GitHub Logo](../../figures/FileSystem/FileSystemsummary.jpg) + +界面布局介绍:FileSystem整体界面布局分为3个部分: ++ 红色区域:泳道图。 ++ 绿色区域:详细信息。 ++ 黄色区域:辅助信息(Callstack)。 + +### FileSystem泳道图展示 +FileSystem泳道图按照读操作和写操作展示,鼠标移动都泳道图上,悬浮框会以10ms为周期展示读,写类型系统调用的次数。 +![GitHub Logo](../../figures/FileSystem/FileSystemchart.jpg) +按住w键放大界面,悬浮框会显示当前时刻的文件读写次数。 +![GitHub Logo](../../figures/FileSystem/FileSystemcount.jpg) +### FileSystem泳道图的框选功能 +可以对读写操作泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有五个tab页。 +FileSystem statistics的Tab页如图: +![GitHub Logo](../../figures/FileSystem/FileSystemstatistics.jpg) ++ Syscall/Process: 按照数据类型,进程分类显示。 ++ Count: 系统调用的数量。 ++ Logical Writes:写数据统计。 ++ Logical Reads:读数据统计。 ++ Other Filesystem Bytes:其他数据量。 ++ Duration:总时长。 ++ Min Duration:最小时长。 ++ Avg Duration: 平均时长。 ++ Max Duration:最大时长。 +FileSystem Calltree的Tab页如图: +![GitHub Logo](../../figures/FileSystem/FileSystemCalltree.jpg) ++ Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。 ++ Local:为该调用方法自身占用的CPU时间。 ++ Weight:调用方法的执行占比。 +FileSystem Events的Tab页如图: +![GitHub Logo](../../figures/FileSystem/FileSystemevents.jpg) ++ Start: 起始时间。 ++ Duration:时长。 ++ Process:进程名。 ++ Thread:线程名。 ++ Firsr Argument:系统调用的第一个参数。 ++ Second Argument:系统调用的第二个参数。 ++ Third Argument:系统调用的第三个参数。 ++ Fourth Argument:系统调用的第四个参数。 ++ Retrun:系统调用的返回值。 ++ Error:错误码。 ++ Backtrace:调用栈顶部函数,并显示调用栈深度。 +File Descriptor History的Tab页如图: +![GitHub Logo](../../figures/FileSystem/FileSystemhistory.jpg) ++ Start: 起始时间。 ++ Duration:时长。 ++ Process:进程名。 ++ Type:操作类型。 ++ File Descriptor:fd。 ++ Backtrace:调用栈顶部函数,并显示调用栈深度。 +File Descriptor Time Slice的Tab页如图: +![GitHub Logo](../../figures/FileSystem/FileSystemtimeslice.jpg) ++ Open Time: 打开的起始时间。 ++ Open Duration:打开的时长。 ++ Process:进程名。 ++ File Descriptor:fd。 ++ Backtrace:调用栈顶部函数,并显示调用栈深度。 +### FileSystem支持多种Options展示风格 +点击FileSystem Calltree的Tab页底部的Options,会有两个CheckBox复选框。 +![GitHub Logo](../../figures/FileSystem/FileSystemOptions.jpg) ++ Invert:反向输出调用树。 ++ Hide System so:隐藏系统库文件。 +### FileSystem支持过滤调用栈调用次数的展示风格 +点击FileSystem Calltree的Tab页底部的Sample Counter Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。 +![GitHub Logo](../../figures/FileSystem/FileSystemsamplecounter.jpg) + +### FileSystem功能的调用栈Group展示-数据分析支持剪裁功能 +![GitHub Logo](../../figures/FileSystem/FileSystemdatamining.jpg) ++ 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 + ++ 裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。 ++ 点击Reset按钮,将恢复选中的裁剪内容。 +### FileSystem功能的调用栈Group展示支持按条件过滤 +在Input Filter输入关键字,会显示出带有该关键字的展示信息。 + ![GitHub Logo](../../figures/FileSystem/FileSysteminputfilter.jpg) +### FileSystem辅助信息区展示调用栈 +当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。如下图的Heaviest Stack Trace: + ![GitHub Logo](../../figures/FileSystem/FileSystemheaviesttrace.jpg) +### FileSystem的事件类型的过滤 + 通过选择可以过滤是Open类型,还是Close类型事件。 + ![GitHub Logo](../../figures/FileSystem/filesystemfilter.jpg) +### FileSystem的火焰图功能 +点击FileSystem Calltre左下角的柱状图的图标,会切换到火焰图页面。 +![GitHub Logo](../../figures/FileSystem/FileSystemflame.jpg) +进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和Duration时长。 +![GitHub Logo](../../figures/FileSystem/FileSystemflameshow.jpg) +鼠标左键火焰图,会进入下一级界面,右键回到上一级。 +![GitHub Logo](../../figures/FileSystem/FileSystemflamelevel.jpg) + diff --git a/ide/src/doc/md/quickstart_hiperf.md b/ide/src/doc/md/quickstart_hiperf.md new file mode 100644 index 0000000000000000000000000000000000000000..3c04e187cf51f3f0767b7800697ce39090871c1c --- /dev/null +++ b/ide/src/doc/md/quickstart_hiperf.md @@ -0,0 +1,79 @@ +# HiPerf的抓取和展示说明 +HiPerf工具是对系统性能数据进行采样记录,并将采样数据保存为文件,进行读取,展示分析。 +## HiPerf的抓取 +### HiPerf抓取配置参数 +![GitHub Logo](../../figures/perf/perfsetting.jpg) +配置项说明: ++ Start Hiperf Sampling:配置项的总开关。 ++ Process:离线模式下配置的是整个系统的。 ++ Frequency:配置抓取的频率。 ++ Call Stack:配置抓取的堆栈类型。 ++ Advance Options:更多的抓取配置项。 +再点击Record setting,在output file path输入文件名hiprofiler_data_perf.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/perf/perfset.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。 +![GitHub Logo](../../figures/perf/perfcommand.jpg) +输入hdc_shell,进入设备,执行命令。 +![GitHub Logo](../../figures/perf/perfexcutecommand.jpg) +执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。 +![GitHub Logo](../../figures/perf/perffile.jpg) +### HiPerf展示说明 +将抓取的trace文件导入smartperf界面查看。 +![GitHub Logo](../../figures/perf/summary.jpg) + +界面布局介绍:Perf整体界面布局分为3个部分: ++ 红色区域:泳道图。 ++ 绿色区域:详细信息(Perf Profile和Sample List)。 ++ 黄色区域:辅助信息(Callstack)。 + +### HiPerf泳道图展示 +Perf泳道图展示按照CPU使用量和线程和进程展示,鼠标移动都泳道图上,悬浮框会显示CPU的使用量。 +![GitHub Logo](../../figures/perf/chart.jpg) +按住w键放大界面,泳道图会出现P的标志,鼠标移动到P图标上,悬浮框会显示每个callstack和调用的深度如下图。 +![GitHub Logo](../../figures/perf/callstack.jpg) +### HiPerf泳道图的框选功能 +可以对CPU使用量区,线程和进程区数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有两个tab页。 +Perf Profile的Tab页如图: +![GitHub Logo](../../figures/perf/PerfProfile.jpg) ++ Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。 ++ Local:为该调用方法自身占用的CPU时间。 ++ Weight:调用方法的执行次数和占比。 +Sample List的Tab页如图: +![GitHub Logo](../../figures/perf/Samplelist.jpg) ++ Sample Time:采样的时间戳信息。 ++ Core:当前的CPU核信息。 ++ Process:进程名。 ++ Thread:线程名。 ++ State:运行状态。 ++ Backtrace:栈顶的调用栈名称。 + +### HiPerf支持多种Options展示风格 +点击Perf Profile的Tab页底部的Options,会有两个CheckBox复选框。 +![GitHub Logo](../../figures/perf/Options.jpg) ++ Invert:反向输出调用树。 ++ Hide System so:隐藏系统库文件。 +### HiPerf支持过滤调用栈调用次数的展示风格 +点击Perf Profile的Tab页底部的Sample Counter Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。 +![GitHub Logo](../../figures/perf/samplecounter.jpg) + +### HiPerf功能的调用栈Group展示-数据分析支持剪裁功能 +![GitHub Logo](../../figures/perf/datamining.jpg) ++ 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 + ++ 裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。 ++ 点击Reset按钮,将恢复选中的裁剪内容。 +### HiPerf功能的调用栈Group展示支持按条件过滤 +在Input Filter输入关键字,会显示出带有该关键字的展示信息。 + ![GitHub Logo](../../figures/perf/inputfilter.jpg) +### HiPerf辅助信息区展示调用栈 +当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。对上展示到根节点,对下则展示CPU占用率最大的调用栈。调用栈右侧有Sliding bar可以滚动。 +如下图的Heaviest Stack Trace: + ![GitHub Logo](../../figures/perf/heaviesttrace1.jpg) +### HiPerf的火焰图功能 +点击Perf Profile左下角的柱状图的图标,会切换到火焰图页面。 +![GitHub Logo](../../figures/perf/flame.jpg) +进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和count大小。 +![GitHub Logo](../../figures/perf/flameshow.jpg) +鼠标左键火焰图,会进入下一级界面,右键回到上一级。 +![GitHub Logo](../../figures/perf/flamelevel2.jpg) + diff --git a/ide/src/doc/md/quickstart_hisystemevent.md b/ide/src/doc/md/quickstart_hisystemevent.md new file mode 100644 index 0000000000000000000000000000000000000000..618941ffcbde7f1d077135ca4bf29da71258b947 --- /dev/null +++ b/ide/src/doc/md/quickstart_hisystemevent.md @@ -0,0 +1,81 @@ +# HiSystemEvent的抓取和展示说明 + HiSystemEvent应用功耗模块主要是展示应用的各个子类别功耗占比信息、应用的资源申请使用记录信息、应用功耗异常事件信息、功耗关联系统状态信息。 +## HiSystemEvent的抓取 +### HiSystemEvent抓取配置参数 +打开Start Hisystem Event Tracker Record开关抓取HiSystemEvent数据。 +![GitHub Logo](../../figures/HiSystemEvent/hisyseventsetting.jpg) +再点击Record setting,在output file path输入文件名hiprofiler_data_hisystemevent.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/HiSystemEvent/hisystemeventrecord.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。 +![GitHub Logo](../../figures/HiSystemEvent/hisystemcommand.jpg) +输入hdc_std shell,进入设备,执行上述生成的命令。 +![GitHub Logo](../../figures/HiSystemEvent/hisystemeventemexcute.jpg) +执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。 +![GitHub Logo](../../figures/HiSystemEvent/hisystemeventfile.jpg) +### HiSystemEvent展示说明 +### HiSystemEvent泳道图展示 +将抓取的trace文件导入smartperf界面查看。 +![GitHub Logo](../../figures/HiSystemEvent/hisystemeventsummary.jpg) +泳道图说明: ++ Anomaly Event泳道: 显示系统异常和应用异常的ToolTip。 ++ System Event泳道: 以条状图显示,红色代表后台任务(WORKSCHEDULER),黄色代表应用锁(POWER),蓝色代表GPS定位(LOCATION)。 ++ Power泳道:应用各个子类的功耗柱状图、折现图以及应用各个子类绘制的图例,鼠标的悬浮可以显示出各个子类功耗的具体值。 ++ Brightness Nit泳道:鼠标悬浮可以显示屏幕亮度值。 ++ Wifi Event Received泳道:鼠标悬浮可以显示WiFi信号强度值。 ++ Audio Stream Change泳道:鼠标悬浮可以显示Audio状态(AUDIO_STREAM_CHANGE事件)。 ++ Audio Volume Change泳道:鼠标悬浮可以显示Audio状态(AUDIO_VOLUME_CHANGE事件)。 ++ Wifi State泳道:鼠标悬浮可以显示wifi开关状态(enable:开,disable:关)。 ++ Bluetooth Br Switch State泳道:鼠标悬浮可以显示蓝牙开关状态(enable:开, disable:关)。 ++ Location Switch State泳道:鼠标悬浮可以显示GPS开关状态(enable:开,disable:关)。 +### HiSystemEvent泳道图的框选功能 +可以对Energy各泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格。 +System Details的Tab页如图: +![GitHub Logo](../../figures/HiSystemEvent/hisystemdetails.jpg) ++ Event Name: 事件名称,事件包括后台任务,应用锁,GPS定位。 ++ Time: 时间戳信息。 +点击事件名会显示该事件的详细信息的Tab页。 +![GitHub Logo](../../figures/HiSystemEvent/systemselectdetals.jpg) ++ EVENT_NAME:事件名称。 ++ PID:应用PID。 ++ UID:应用UID。 ++ TYPE:类型。 ++ STATE:状态值。 ++ LOG_LEVEL:日志级别。 ++ NAME:NAME信息。 ++ MESSAGE:MESSAGE信息。 ++ TAG:锁名。 +Power Battery的Tab页如图: +![GitHub Logo](../../figures/HiSystemEvent/hisyseventPowerBattery.jpg) ++ Gas Gauge: 电池电量。 ++ Charge:充电状态。 ++ Screen:屏幕状态。 ++ Level:电池百分比。 ++ Current:电池电流。 ++ Capacity:电池容量。 ++ APP Name:应用包名。 +Power Details的Tab页如图: +![GitHub Logo](../../figures/HiSystemEvent/hisyseventPowerdetails.jpg) ++ UID: 应用UID。 ++ Charge:充电状态。 ++ Foreground Duration(ms):前台使用时长。 ++ Foreground Energy(mAs):前台使用功耗值。 ++ Background Duration(ms):后台使用时长。 ++ Background Energy(mAs):后台使用功耗值。 ++ Screen On Duration(ms):亮屏使用时长。 ++ Screen On Energy(mAs):亮屏使用功耗值。 ++ Screen Off Duration(ms):灭屏使用时长。 ++ Screen Off Energy(mAs):灭屏使用功耗值。 ++ Foreground Count:应用前台扫描次数。 ++ Background Count:应用后台扫描次数。 ++ Screen On Count:应用亮屏扫描次数。 ++ Screen Off Count:应用灭屏扫描次数。 ++ Background Time(ms):灭屏使用功耗值。 ++ Screen On Time(ms):应用亮屏使用时长。 ++ Screen Off Time(ms):应用灭屏使用时长。 ++ Energy(mAs):功耗值。 ++ Load(%):占用率。 ++ Usage(ms):应用使用时长。 ++ Duration(ms):持续时长。 ++ Camera Id:Camera类型,0:后置,1:前置。 ++ Count:应用个数。 ++ Energy Percent(%):功耗占比。 \ No newline at end of file diff --git a/ide/src/doc/md/quickstart_native_memory.md b/ide/src/doc/md/quickstart_native_memory.md new file mode 100644 index 0000000000000000000000000000000000000000..497f5a36cdbf852b782bb03015f1a08056b1927c --- /dev/null +++ b/ide/src/doc/md/quickstart_native_memory.md @@ -0,0 +1,108 @@ +# Native Memory抓取和展示说明 +Native Memory是查看内存的分配和释放等情况。 +## Native Memory的抓取 +### Native Memory抓取配置参数 +![GitHub Logo](../../figures/NativeMemory/nativememorysetting.jpg) +配置参数说明: +* ProcessId or ProcessName:设置抓取的进程ID或者进程名,此处以输入com.ohos.mms进程名为例。 +* Max unwind level:抓取的栈的最大深度。 +* Shared Memory Size:native_daemon和native_hook进程之间存储数据的共享内存大小。 +* Filter Memory Size:只抓取大于该size的malloc数据(free不受影响)。 +* Use Fp Unwind:Fp回栈。 +* Use Record Accurately:不过滤数据,上报全量的。 +* Use Offline Symbolization:离线符号化。 +* Use Record Statistics:统计数据上报。 +* statistics interval:统计数据上报周期。 + +再点击Record setting,在output file path输入文件名hiprofiler_data_nativememory.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/NativeMemory/nativememoryset.jpg) + +点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。 +![GitHub Logo](../../figures/NativeMemory/nativememorycommand.jpg) + +命令行参数说明: +* save_file:是否将hook数据保存成文件,不上报protobuf形式数据给hiprofilerd。 +* filter_size:过滤malloc的大小,最小值是0,默认值是4096Byte。 +* smb_pages:nativedeamon与libnativehook间的共享内存大小。 +* max_stack_depth:最多回栈的层数,也就是抓取的栈的最大深度。 +* fp_unwind:是否进行fp回栈。 +* malloc_free_matching_interval:native_daemon从nativehook so的共享内存里取数据的间隔时间。 +* string_compressed:是否进行字符串压缩。 +* fp_unwind:fp回栈。 + +输入hdc_std shell,进入设备,执行命令。 +![GitHub Logo](../../figures/NativeMemory/nativeexcutecommand.jpg) +执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。 +![GitHub Logo](../../figures/NativeMemory/naitvememoryfile.jpg) +## Native Memory展示说明 +将抓取的nativememory文件导入到smartperf工具中查看,查看内存的分配和释放等情况。 +### Native Memory泳道图展示类型 +点击齿轮状的图标可以设置内存的展示单位。 +![GitHub Logo](../../figures/NativeMemory/NativeChart.jpg) ++ Current Bytes:以申请内存的size绘制泳道图。 ++ Native Memory Density:以申请内存的数量绘制泳道图。 ++ All Heap&AnonuymousVM:malloc分配和mmap分配的总量。 ++ All Heap:malloc分配的内存。 ++ All Anonymous VM:mmap分配的内存。 +### Native Memory泳道图的框选功能 +可以对内存的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有四个tab页。 +Statistics的Tab页,主要显示了统计明细类型。 +![GitHub Logo](../../figures/NativeMemory/Statistics.jpg) ++ Memory Type:内存的类型。 ++ Exsiting:框选区域内申请没有释放的大小。 ++ #Exsiting:框选区域内申请没有释放的次数。 ++ Transient:框选区域内释放的大小。 ++ #Transient:框选区域内释放的次数。 ++ Total Bytes:框选区间内申请的大小。 ++ #Total: 框选区间内申请的次数。 ++ Peak Value: 框选区间内内存申请的峰值。 ++ Exsiting/Total:框选区间内剩余的内存比上申请的内存,其中浅紫色是框选区间内申请的大小/整个时间轴(申请+释放的总大小),深紫色是框选区间内(申请+释放)的大小/整个时间轴(申请+释放的总大小)。 + +Call Info的Tab页,主要显示了调用树详细类型。 +![GitHub Logo](../../figures/NativeMemory/CallInfo.jpg) ++ Symble Name:每个内存分配的调用栈。 ++ Size:分配的总大小。 ++ Count:相同调用栈出现的次数。 +Native Memory的Tab页,主要显示了单次分配信息列表。 +![GitHub Logo](../../figures/NativeMemory/NativeMemory.jpg) ++ Address:内存块的地址。 ++ Memory Type:内存分配的类型。 ++ Timestamp:时间戳信息。 ++ State:内存地址当前状态Existed 表示框选范围内未释放,Freed表示已释放。 ++ Size:该次申请分配内存的大小。 ++ Responsible Library :调用该函数的库。 ++ Responsible Caller :调用该函数的方法。 +Snapshot List的Tab页,主要显示了各时刻内存的增长的差值。 +![GitHub Logo](../../figures/NativeMemory/Snapshotlist.jpg) ++ Snapshot:标记的打点说明。 ++ Timestamp :时间戳信息。 ++ Net Growth :自从上次Snapshot的增长量,是计算的分配和释放的。 ++ Total Growth :自从上次Snapshot的增长量,是计算的每一次分配的。 ++ #Exsiting :仍然存在的内存数。 +### Native Memory的辅助信息功能 +在Call Info和Native Memory的Tab页,点击选中某一行,右边画红线处会显示出该行调用栈的树结构信息。 +![GitHub Logo](../../figures/NativeMemory/nativecallstack.jpg) +### Native Memory详细显示的过滤功能 +点击下方的All Allocations可以对Allocation的lifeSpan进行过滤,有三个选择:All Allocatios,Create & Exsiting,Create & Destroyed。 +![GitHub Logo](../../figures/NativeMemory/lifespan.jpg) ++ All Allocations:所有的内存。 ++ Created & Exsiting:创建且被存活的内存。 ++ Created & Destroyed: 创建且被销毁的内存。 +点击下方的All Heap&Anonymous可以对内存类型进行过滤。 +![GitHub Logo](../../figures/NativeMemory/AllocationType.jpg) ++ All Heap&AnonuymousVM:Heap和AnonuymousVM的总量。 ++ All Heap:malloc分配的内存。 ++ All Anonymous VM:mmap的匿名页。 +点击下方的Mark Snapshot可以在时间轴上打标签。出现小旗的标志,通过标注多个时间点。点击到Snapshot List标签页可以看到各个时间点的内存的增长值。 +![GitHub Logo](../../figures/NativeMemory/Generation.jpg) +### Native Memory的火焰图功能 +点击callinfo左下角的柱状图的图标,会切换到火焰图页面。 +![GitHub Logo](../../figures/NativeMemory/nativeflame.jpg) +进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和size大小。 +![GitHub Logo](../../figures/NativeMemory/nativeflameshow.jpg) +鼠标左键火焰图,会进入下一级界面,右键回到上一级。 +![GitHub Logo](../../figures/NativeMemory/nativeflamelevel2.jpg) +### Native Memory数据统计功能 +选择Use Record Statistics和statistics interval配置项抓取的数据,只会显示Call Info的Tab页,Call Info相关功能同上。 +![GitHub Logo](../../figures/NativeMemory/statiscsCallInfo.jpg) + diff --git a/ide/src/doc/md/quickstart_page_fault.md b/ide/src/doc/md/quickstart_page_fault.md new file mode 100644 index 0000000000000000000000000000000000000000..c4461c35bad8266d897a173f2dc84f5104b6095f --- /dev/null +++ b/ide/src/doc/md/quickstart_page_fault.md @@ -0,0 +1,84 @@ +# 页内存的抓取和展示说明 +页内存从page层面更深层次剖析应用程序的虚拟内存操作。 +## 页内存的抓取 +### 页内存抓取配置参数 +![GitHub Logo](../../figures/EBPF/ebpfsetting.jpg) +配置项说明: ++ Start Page Fault Record:配置项的总开关。 ++ Process:默认配置的是整个系统的,也可选择单进程抓取。 ++ Max Unwind Level:配置抓取调用栈的最大深度。 + +再点击Record setting,在output file path输入文件名hiprofiler_data_ebpf.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/EBPF/ebpfrecord.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。 +![GitHub Logo](../../figures/EBPF/ebpfexcuting.jpg) +### 页内存展示说明 +抓取结束后页内存的trace会自动加载展示。 +![GitHub Logo](../../figures/EBPF/ebpfsummary.jpg) + +界面布局介绍:页内存整体界面布局分为3个部分: ++ 红色区域:泳道图。 ++ 绿色区域:详细信息。 ++ 黄色区域:辅助信息(Callstack)。 + +### 页内存泳道图展示 +页内存泳道图展示事件(Operation)发生的次数,每个事件都有持续时间,鼠标悬浮以10ms为区间进行次数统计。 +![GitHub Logo](../../figures/EBPF/EBPFchart.jpg) +按住w键放大界面,悬浮框会显示当前时刻的事件发生次数。 +![GitHub Logo](../../figures/EBPF/EBPFcount.jpg) +### 页内存泳道图的框选功能 +可以对泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有三个tab页。 +Page Fault Statistics的Tab页如图: +![GitHub Logo](../../figures/EBPF/vmstatistics.jpg) ++ Operation/Process/Thread: 按照Operation为基点显示。 ++ Count: 事件数量。 ++ Duration:总时长。 ++ Min Duration:最小时长。 ++ Avg Duration: 平均时长。 ++ Max Duration:最大时长。 +点击下方的Statistics by Thread,可以切换到按照Thread为基点显示数据。 +![GitHub Logo](../../figures/EBPF/ebpf_bythread.jpg) +Page Fault Calltree的Tab页如图: +![GitHub Logo](../../figures/EBPF/VMCalltree.jpg) ++ Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。 ++ Local:为该调用方法自身占用的CPU时间。 ++ Weight:调用方法的执行占比。 +Page Fault Events的Tab页如图: +![GitHub Logo](../../figures/EBPF/VMEvents.jpg) ++ Start Time:起始时间。 ++ Duration:时长。 ++ Thread:线程名。 ++ Operation:事件类型。 ++ Address:内存地址。 ++ Size:内存大小。 +### 页内存支持多种Options展示风格 +点击Page Fault Calltree的Tab页底部的Options,会有两个CheckBox复选框。 +![GitHub Logo](../../figures/EBPF/vmOptions.jpg) ++ Invert:反向输出调用树。 ++ Hide System so:隐藏系统库文件。 +### 页内存支持过滤调用栈调用次数的展示风格 +点击Page Fault Calltree的Tab页底部的Sample Counter Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。 +![GitHub Logo](../../figures/EBPF/vmcounter.jpg) + +### 页内存功能的调用栈Group展示-数据分析支持剪裁功能 +![GitHub Logo](../../figures/EBPF/vmdatamining.jpg) ++ 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 ++ 裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。 ++ 点击Reset按钮,将恢复选中的裁剪内容。 +### 页内存功能的调用栈Group展示支持按条件过滤 +在Input Filter输入关键字,会显示出带有该关键字的展示信息。 + ![GitHub Logo](../../figures/EBPF/vminputfilter.jpg) +### 页内存辅助信息区展示调用栈 +当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。如下图的Heaviest Stack Trace: + ![GitHub Logo](../../figures/EBPF/vmheaviesttrace.jpg) +### 页内存的事件类型的过滤 + 通过选择可以过滤是File Backed In类型,还是Copy On Write类型事件。 + ![GitHub Logo](../../figures/EBPF/VMfilter.jpg) +### 页内存的火焰图功能 +点击Page Fault Calltree左下角的柱状图的图标,会切换到火焰图页面。 +![GitHub Logo](../../figures/EBPF/vmflame.jpg) +进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和Duration时长。 +![GitHub Logo](../../figures/EBPF/vmflameshow.jpg) +鼠标左键火焰图,会进入下一级界面,右键回到上一级。 +![GitHub Logo](../../figures/EBPF/vmflamelevel.jpg) + diff --git a/ide/src/doc/md/quickstart_schedulinganalysis.md b/ide/src/doc/md/quickstart_schedulinganalysis.md new file mode 100644 index 0000000000000000000000000000000000000000..45750d5fb1862ffcbfe50e30ae2bce22eb5ec650 --- /dev/null +++ b/ide/src/doc/md/quickstart_schedulinganalysis.md @@ -0,0 +1,123 @@ +# Scheduling analysis抓取和展示说明 +抓取和展示CPU调度分析,线程调度分析相关数据。 +## Scheduling analysis的抓取 +### Scheduling analysis抓取界面配置说明 +打开Scheduling analysis开关抓取调度分析数据。 +![GitHub Logo]( ../../figures/Schedulinganalysis/scheduset.jpg) +### Scheduling analysis文件的抓取 +点击Record setting,在output file path输入文件名hiprofiler_dataScheduling.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo]( ../../figures/Schedulinganalysis/schedusetting.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。 +![GitHub Logo]( ../../figures/Schedulinganalysis/scheduexcuting.jpg) +## Scheduling analysis功能介绍 +将抓取的文件导入到smartperf工具查看。 +### CPU频点分析 +点击下拉列表框选择CPU Frequency,可以看到各核CPU的各频点持续时长的占比图,以颜色区分各频点。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUFrequencychart.jpg) +点击CPU Frequency饼图,可以跳转到详细信息界面,用饼图和表格来展示某个CPU下各频点持续时长的的相关数据。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUFrequencydetailinfo.jpg) ++ No:编号。 ++ frequency:频率。 ++ min:最小时长。 ++ max:最大时长。 ++ average:平均时长。 ++ duration:运行总时长。 +点击详细页的CPU Frequency饼图,可以跳转某个CPU下某个频点的运行的线程信息。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUFrequencythreaddetail.jpg) ++ No:编号。 ++ t_name:线程名。 ++ tid:线程id。 ++ p_name:进程名。 ++ p_pid:进程id。 ++ duration:运行总时长。 +### CPU Idle分析 +点击下拉列表框选择CPU Idle,可以看到各CPU的Idle的时长占比饼图,以颜色区分各Idle。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUidlechart.jpg) +点击CPU Idle饼图,可以跳转到某CPU的idle分析的详细数据,以饼图和表格的形式展示。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUidledetailinfo.jpg) ++ No:编号。 ++ idle:idle值。 ++ min:最小时长。 ++ max:最大时长。 ++ average:平均时长。 ++ duration:运行总时长。 +### CPU Irq分析 +点击下拉列表框选择CPU Irq,可以看到各CPU的Irq的时长占比饼图,以颜色区分。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUirqchart.jpg) +点击CPU Irq饼图,可以跳转到某CPU的Irq分析的详细数据,以饼图和表格的形式展示。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUirqdetailinfo.jpg) ++ No:编号。 ++ block:irq的类型。 ++ name:irp名称。 ++ min:最小时长。 ++ max:最大时长。 ++ average:平均时长。 ++ duration:运行总时长。 +### CPU占用率显示 +以表格显示各CPU的占用率。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUusagechart.jpg) +### Top20线程大中小核占用率 +选择Thread Analysis标签页,各个CPU通过勾选big或者middle或者small来设置CPU的分类。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUsetting.jpg) +各CPU勾选好大中小核,点击Upload可以跳转到各个线程CPU占用率情况的展示页面。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUdetailsetting.jpg) +如上图所示: ++ 三色柱状图:各个线程CPU的占用率情况,其中以颜色区分占用的大中小核的占用率情况,并以表格的形式展示各个线程的基本信息和大中小核占用率。 ++ 单色柱状图:分别统计线程在某一个类别(大、中、小)的CPU的占用率,并显示出线程的基本信息和占用率。 +表格的字段说明: ++ tid:线程号。 ++ t_name:线程名。 ++ pid:进程号。 ++ p_name:进程名。 ++ big core:大核占用时长。 ++ middle core:中核占用时长。 ++ small core:小核占用时长。 ++ cpu..(us):运行总时长(..代表cpu号)。 +### 单个线程频点分布 +点击单个线程频点分布的标签,通过在Thread Search选择线程,来展示单个线程的频点分布情况。 +![GitHub Logo]( ../../figures/Schedulinganalysis/CPUfrequencybythread.jpg) ++ NO:编号。 ++ cpu:cpu编号。 ++ frequency:频点。 ++ duration:运行时长。 ++ %:频点占用率。 +### Top20单次运行超长线程 +通过点击Top20单次运行超长线程标签,显示线程的单次运行时长来统计出单次运行时长最大的20个线程。 +![GitHub Logo]( ../../figures/Schedulinganalysis/Top20Threadduration.jpg) ++ NO:编号。 ++ tid:线程号。 ++ t_name:线程名。 ++ pid:进程号。 ++ p_name:进程名。 ++ max duration:最大运行时长。 ++ timestamp:时间戳信息。 +### Top20进程线程数 +通过点击Top20进程线程数标签,显示线程数量最多的20个进程,以饼图和表格方式显示。 +![GitHub Logo]( ../../figures/Schedulinganalysis/Top20Threadnum.jpg) ++ NO:编号。 ++ pid:进程号。 ++ p_name:进程名。 ++ thread count:线程数量。 +### Top20切换次数线程 +通过点击Top20切换次数线程标签,显示切换次数最多的20个进程,以饼图和表格方式显示。 +![GitHub Logo]( ../../figures/Schedulinganalysis/Top20swtichcount.jpg) ++ NO:编号。 ++ tid:线程号。 ++ t_name:线程名。 ++ pid:进程号。 ++ p_name:进程名。 ++ sched_switch count:切换次数。 + + + + + + + + + + + + + + diff --git a/ide/src/doc/md/quickstart_sdk.md b/ide/src/doc/md/quickstart_sdk.md new file mode 100644 index 0000000000000000000000000000000000000000..4be2355c80b79a387c795eb389fb1db809a67ff7 --- /dev/null +++ b/ide/src/doc/md/quickstart_sdk.md @@ -0,0 +1,6 @@ +# Sdk抓取 +抓取Sdk数据。 +## Sdk的抓取 +### Sdk抓取配置参数 +打开Start Custom Config开关抓取Sdk数据。 +![GitHub Logo](../../figures/sdk/sdk.jpg) diff --git a/ide/src/doc/md/quickstart_smaps.md b/ide/src/doc/md/quickstart_smaps.md new file mode 100644 index 0000000000000000000000000000000000000000..c94216dc0498d436f73e23b68f0cb2810bb7adf6 --- /dev/null +++ b/ide/src/doc/md/quickstart_smaps.md @@ -0,0 +1,50 @@ +# 进程smaps的抓取和展示说明 +smaps展示了一个进程的内存消耗。 +## smaps的抓取 +### smaps抓取配置参数 +![GitHub Logo](../../figures/smaps/smapssetting.jpg) +配置项说明: ++ Start VM Tracker Record:配置项的总开关。 ++ Process:smaps的抓取只能选择单进程抓取。 + +再点击Record setting,在output file path输入文件名hiprofiler_data_smaps.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/smaps/smapsrecord.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。 +![GitHub Logo](../../figures/smaps/smapsexcuting.jpg) +### smaps展示说明 +抓取结束后smaps的trace会自动加载展示。 +![GitHub Logo](../../figures/smaps/smapssummary.jpg) + +界面布局介绍:smaps整体界面布局分为3个部分: ++ 红色区域:泳道图。 ++ 绿色区域:详细信息。 + +### smaps泳道图展示 +smaps泳道图展示当前时刻该进程的内存消耗。 +![GitHub Logo](../../figures/smaps/smapschart.jpg) +### smaps泳道图的框选功能 +可以对泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有两个个tab页。 +VM Tracker Statistics的Tab页如图: +![GitHub Logo](../../figures/smaps/smapsstatistics.jpg) ++ Type: 将抓取到的信息根据Type归类,分四类,Data,Text,Const,Other。 ++ % of Res: 每行的Resident Size 占总Ressident Size的比例。 ++ #Reg:统计的类型个数。 ++ Path:虚拟内存块路径,类型中有多个则显示multiple。 ++ Resident Size: smaps节点中Rss(Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty)。 ++ Dirty Size:smaps节点中Shared_Dirty + Private_Dirty。 ++ Swapped: smaps节点中Swap + SwapPss。 ++ Virtual Size:smaps节点中Size。 ++ Pss: smaps节点中Pss。 ++ Res. %:Resident Size / Virtual Size 比值。 +VM Tracker Record List的Tab页如图: +![GitHub Logo](../../figures/smaps/smapslist.jpg) ++ Type: 将抓取到的信息根据Type归类,Data,Text,Const,Other。 ++ Address Range: 每段虚拟内存段的开始和结束位置。 ++ Dirty Size:smaps节点中Shared_Dirty + Private_Dirty。 ++ Swapper: smaps节点中Swap + SwapPss。 ++ Resident Size:smaps节点中Rss(Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty)。 ++ Virtual Size:smaps节点中Size。 ++ Pss:smaps节点中Pss。 ++ Reside: Rss / Size 比值。 ++ Protection: 内存块的权限(读写执行执行)。 ++ Path: 内存段路径。 \ No newline at end of file diff --git a/ide/src/doc/md/quickstart_sql_metrics.md b/ide/src/doc/md/quickstart_sql_metrics.md new file mode 100644 index 0000000000000000000000000000000000000000..8e771ad81271b5088e715574506e528377445d50 --- /dev/null +++ b/ide/src/doc/md/quickstart_sql_metrics.md @@ -0,0 +1,16 @@ +# Sql分析和Metrics说明 +Sql功能是方便使用者查询sql语句查看相关业务,Metrics是更高级别的查询接口,无需手动键入任何SQL语句,只需要选择定制好的查询接口,就能获得想要跟踪的结果。 +## Sql分析功能介绍 +点击Query(SQL),输入需要查询的sql语句,如select * from process,可以看到进程表数据。 +![GitHub Logo](../../figures/Metrics/Sql.jpg) +## Metrics功能介绍 +Metrics是更高级别的查询接口,无需手动键入任何SQL语句,只需要选择定制好的查询接口,就能获得想要跟踪的结果。 +### Metrics查询接口展示 +如下图,查询接口在下拉框中,如选择trace_task_names,点击run,就能展示线程和进程相关数据。 +![GitHub Logo](../../figures/Metrics/metrics.jpg) +## Info和stats功能 +点击Info and stats,能查看到meta表和stats表信息。 +![GitHub Logo](../../figures/Metrics/infoandstats.jpg) +## Download功能 +点击DownLoad按钮,会将在线抓取的文件下载到本地。 +![GitHub Logo](../../figures/Metrics/download.jpg) \ No newline at end of file diff --git a/ide/src/doc/md/quickstart_systemtrace.md b/ide/src/doc/md/quickstart_systemtrace.md new file mode 100644 index 0000000000000000000000000000000000000000..caaee7c16764ce54d2138875389d289ce1097852 --- /dev/null +++ b/ide/src/doc/md/quickstart_systemtrace.md @@ -0,0 +1,89 @@ +# web端加载trace说明 +从web端查看trace文件,进行性能检测的分析。 +## 文件加载入口 +将抓取的trace导入查看。 +![GitHub Logo](../../figures/Web/opentrace.jpg) + +说明: ++ Open trace file:导入离线trace文件入口。 ++ Record new trace:抓取新的trace文件入口。 + +## 导入trace文件后显示页面 +![GitHub Logo](../../figures/Web/trace.jpg) +说明: ++ 操作说明:在当前页面可以通过键盘上的wasd四个键位操纵当前的时间轴进行缩放,w为放大,s为缩小,a为左移,d为右移。 +## trace功能介绍 +trace模块从上往下主要展示时间轴、cpu使用率、cpu使用情况、进程间通讯数据的方法调用情况、进程、线程和方法调用情况。 +### 时间轴和cpu使用率 +![GitHub Logo](../../figures/Web/time.jpg) +最上方带刻度的为时间轴,主要展示当前抓取数据的总时长和时间刻度的分布情况,如上图所示,左下角展示总时长。 +中间区域展示的是抓取数据时间段内的cpu使用率,颜色越深代表cpu使用率越高,颜色越浅代表cpu使用率越低。 +![GitHub Logo](../../figures/Web/highlit.jpg) +在白色背景时间轴区域内可以点击后拖拽鼠标,可以对从鼠标按下到拖拽完成鼠标松开的区域内的数据进行筛选,高亮显示的部分为当前所选区域,如上图所示。 +### cpu使用情况 +![GitHub Logo](../../figures/Web/cpu.jpg) + +如上图所示,当前抓取数据有4个cpu工作,前四组数据对应的是当前调用cpu的线程和对应的进程情况,以颜色作为区分。后四组数据则为cpu的使用频率信息。鼠标移动到相应的线程上还会将当前选中的进程信息全部置为高亮,其他的进程会置灰,如下图所示。 +![GitHub Logo](../../figures/Web/gray.jpg) +#### cpu使用情况的框选功能 +可以对cpu的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有七个tab页。 +CPU by thread的Tab页,主要显示了在框选时间区间内的进程名、进程号、线程名、线程号、总运行时长、平均运行时长和调度次数信息。 +![GitHub Logo](../../figures/Web/cpubythread.jpg) +CPU by process的Tab页,主要显示了在框选时间区间内的进程名、进程号、总运行时长、平均运行时长和调度次数信息。 +![GitHub Logo](../../figures/Web/cpubyprocess.jpg) +CPU Usage的Tab页,主要显示了在框选时间区间内,该频率时间占比前三的信息。 +![GitHub Logo](../../figures/Web/cpusage.jpg) +States List的Tab页,按状态>进程>线程的维度去统计,需要呈现该状态的线程名、该状态次数、该状态下时长、最大最小时长、平均时长、最大时长。 +![GitHub Logo](../../figures/Web/StatesList.jpg) +Switches List的Tab页,按照进程>线程>状态,统计对应状态下的次数。 +![GitHub Logo](../../figures/Web/Switchlist.jpg) +Thread States的Tab页,按进程>线程>状态的维度去统计,需要呈现该状态的线程名、进入该状态次数、该状态下时长、最小时长、平均时长、最大时长。 +![GitHub Logo](../../figures/Web/threadstates.jpg) +Thread Switches的Tab页,按照状态>进程>线程,统计对应状态下的次数。 +![GitHub Logo](../../figures/Web/threadswitches.jpg) +States List、Switches List、Thread States、Thread Switches的4个Tab页,点击移动到某一行,鼠标会变成一个小手的标志,点击一下,就会进入辅助信息界面,会将选中行的辅助信息展示出来,包括开始时间、进程、线程、线程状态、对应的CPU、优先级等信息如下图。 +![GitHub Logo](../../figures/Web/details.jpg) +#### cpu使用情况的单选功能 +单选CPU使用情况数据会在选中的色块外层加上深色边框,能够突出当前选中色块,弹出层中会展示当前CPU上的进程名,线程名,开始时间和运行时长,线程运行状态等信息。 +![GitHub Logo](../../figures/Web/cpuclick.jpg) +### 进程、线程和方法数据 +下图是进程数据,左边部分展示进程名称和id,右边显示线程切换关系,线程的调用方法,进程间内存信息等。 +![GitHub Logo](../../figures/Web/process.jpg) +点击进程名前面向下箭头可以展开对应的线程进行查看,展开后的线程如下图,如果存在堆内存占用情况,就会显示在第一行,如果出现两个名字和id一样的线程,则第一个为线程的使用情况,第二为线程内的方法栈调用情况。 +![GitHub Logo](../../figures/Web/threadinfo.jpg) +#### 进程、线程和方法数据的框选功能 +可以对线程的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,包含线程运行状态,线程调用栈的统计情况。当框选的数据中同时存在线程运行状态和线程调用栈数据,下方的弹出层中就会出现多个tab选项,可以进行切换。 + +下图是线程运行状态框选统计信息,包括进程名、进程号、线程名、线程号、线程状态、状态持续时间、平均持续时间、该线程状态发生的次数。 +![GitHub Logo](../../figures/Web/threadselect.jpg) + +下图是线程调用栈框选统计信息,包括方法名、持续时间、平均持续时间、调用的次数。 +![GitHub Logo](../../figures/Web/callstackselect.jpg) +#### 进程、线程和方法数据的单选功能 +单选线程的state数据时,会展示当前选中线程的状态数据,开始时间和持续时长,线程状态,所在进程名称。 +![GitHub Logo](../../figures/Web/threadclick.jpg) +单选调用栈数据,单击方法会在选中的方法外层加上黑色边框,能够突出当前选中的方法,弹出层中会展示当前方法的名称、开始时间和运行时长信息。 +![GitHub Logo](../../figures/Web/callstackclick.jpg) +#### 线程的跳转功能 +点击画红框处的带箭头的标志,会从CPU的线程概览视图跳转到线程的详情视图,同时从线程的详情视图也能跳转到CPU的线程概览视图。 +![GitHub Logo](../../figures/Web/jumpthread.jpg) +### trace的其他功能 +#### 小旗标志的功能 +将选中数据的时间点通过小旗的方式在时间轴上展示,直观的展示选中数据的时间。 +![GitHub Logo](../../figures/Web/flag.jpg) +在下方输入空输入文字:我是trace,可以给小旗打备注。 +![GitHub Logo](../../figures/Web/flaginput.jpg) +#### 收藏置顶功能 +鼠标移动到某个页签,会出现星形的标志,点击该星形,可以将该行收藏置顶。 +![GitHub Logo](../../figures/Web/stars.jpg) +#### 勾选功能 +框选某一区域,该区域左边会出现CheckBox的复选框,选中的区域的复选框会出现打勾的状态,可以取消勾选,也可以重新勾选。 +![GitHub Logo](../../figures/Web/checkbox.jpg) +#### 搜索功能 +在搜索框中,可以输入线程,线程号等搜索自己想要的信息,搜索完成会高亮显示。 +![GitHub Logo](../../figures/Web/search.jpg) +在搜索框中输入调用栈的方法名,会跳转到对应的调用栈。 +![GitHub Logo](../../figures/Web/searchcallstack.jpg) +#### M键测量功能 +放大trace中的色块,选中色块,键盘按下M,会出现像尺子一样的形状。 +![GitHub Logo](../../figures/Web/M.jpg) \ No newline at end of file diff --git a/ide/src/doc/md/quickstart_web_record.md b/ide/src/doc/md/quickstart_web_record.md new file mode 100644 index 0000000000000000000000000000000000000000..f2b3493b3ece12ae72af66746f2a4c9b40aa2cb8 --- /dev/null +++ b/ide/src/doc/md/quickstart_web_record.md @@ -0,0 +1,30 @@ +# web端抓取trace说明 +从web端抓取trace文件的配置和方法。 +## 界面配置说明 +![GitHub Logo](../../figures/hdc/hdc.jpg) +说明: +* Record:trace抓取按钮。 +* Add HDC Device:连接设备。 +## trace文件的在线抓取 +点击Add HDC Device在弹出的框里选择HDC-配对,点击连接,连接设备。 +![GitHub Logo](../../figures/hdc/Device.jpg) +点击Probes config,如选择抓取Scheduling details。 +![GitHub Logo](../../figures/hdc/Schedulingdetails.jpg) +抓取项说明: + * Scheduling details:线程切换事件,暂停恢复方法,线程唤醒事件,进程退出和销毁处理,新建线程处理方法,线程重命名处理方法。 + * CPU Frequency and idle states:CPU频率信息和CPU空闲状态。 + * Advanced ftrace config:线程切换事件,暂停恢复方法,线程唤醒事件,进程退出和销毁处理,新建线程处理方法,线程重命名处理方法,IRQ事件,时钟频率处理方法,Binder事件,线程调用堆栈开始和结束的处理。 + * AbilityMonitor:进程的CPU,内存,磁盘,网络使用情况。 + * Kernel meminfo:内核内存。 + * Virtual memory stats:系统虚拟内存。 + * Hitrace categories:Bytrace的抓取项,各解释项说明如下图: +![GitHub Logo](../../figures/hdc/bytacedescription.jpg) + +再点击Record setting,在output file path输入文件名hiprofiler_data_example.htrace,拖动滚动条设置buffer size大小是64M,抓取时长是50s。 +![GitHub Logo](../../figures/hdc/examplerecord.jpg) +点击Trace command,就会根据上面的配置生成抓取命令,点击Record。 +![GitHub Logo](../../figures/hdc/record.jpg) +抓取过程中,上方会给出提示正在抓取,并显示出抓取时长。 +![GitHub Logo](../../figures/hdc/hdctracing.jpg) +抓取完成后,界面会自动加载展示trace文件。 +![GitHub Logo](../../figures/hdc/hdcfile.jpg) \ No newline at end of file diff --git a/ide/src/doc/quickstart_Frametimeline.html b/ide/src/doc/quickstart_Frametimeline.html new file mode 100644 index 0000000000000000000000000000000000000000..f52ac9b47a5f03dce14beb096df24c7faa6e284d --- /dev/null +++ b/ide/src/doc/quickstart_Frametimeline.html @@ -0,0 +1,997 @@ + + + + + quickstart_Frametimeline + + + + + + +
+

Frame timeline抓取和展示说明

+ +

抓取和展示卡顿丢帧检测的数据。

+

Frame timeline的抓取

+ +

Frame timeline抓取界面配置说明

+ +

+ 打开Frame timeline开关抓取Frametimeline数据。
+ GitHub Logo +

+

Frame timeline文件的抓取

+ +

+ 点击Record setting,在output file path输入文件名hiprofiler_dataframe.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。
+ GitHub Logo +

+

Frame timeline功能介绍

+ +

将抓取的文件导入到smartperf工具查看。

+

Frame timeline泳道图展示

+ +

+ Frame timeline展开就可以看到泳道图,泳道图上可以显示帧编号。
+ GitHub Logo +

+
    +
  • +
    +Expected Timeline:理想帧泳道图。
    +
    +
  • +
  • +
    +Actual Timeline:真实帧泳道图。
    +
    +
  • +
+

Frame timeline泳道图的框选功能

+ +

+ 可以对真实帧数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格。
+ Frames的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Jank Type:卡顿类型。
    +
    +
  • +
  • +
    +Min duration:最小持续时间。
    +
    +
  • +
  • +
    +Max duration:最大持续时间。
    +
    +
  • +
  • +
    +Mean duration:平均持续时间。
    +
    +
  • +
  • +
    +Occurrences:事件数。
    +
    +
  • +
+

Frame timeline泳道图的点选功能

+ +

+ 通过点选理想帧和真实帧展示Tab页(Current Selection)。
+ 理想帧Tab页如下图:
+ GitHub Logo +

+
    +
  • +
    +Name:帧编号。
    +
    +
  • +
  • +
    +StartTime:启动时间。
    +
    +
  • +
  • +
    +Absolute Time:绝对时间。
    +
    +
  • +
  • +
    +Duration:持续时间。
    +
    +
  • +
  • +
    +Process:进程名。
    +
    +
  • +
+

+ 真实帧Tab页如下图:
+ GitHub Logo +

+
    +
  • +
    +Name:帧编号。
    +
    +
  • +
  • +
    +StartTime:启动时间。
    +
    +
  • +
  • +
    +Absolute Time:绝对时间。
    +
    +
  • +
  • +
    +Duration:持续时间。
    +
    +
  • +
  • +
    +Process:进程名。
    +
    +
  • +
  • +
    +Jank Type:卡顿类型。
    +
    +
  • +
  • +
    +Gpu Duration:GPU耗时。
    +
    +
  • +
  • +
    +FrameTimeLine flows:显示的是绘制一帧的完整过程,  由两个阶段组成应用的提交一帧。
    +
    +
  • +
  • +
    +Following flows:展示真实帧包含的关联的帧,图中斜向上箭头点击会进行跳转功能直接定位到具体进程真实帧位置,点选的同时还将包含的关联帧通过线连起来,可以跨越多个进程。
    +
    +
  • +
+
+ + + + diff --git a/ide/src/doc/quickstart_Js_memory.html b/ide/src/doc/quickstart_Js_memory.html new file mode 100644 index 0000000000000000000000000000000000000000..4642f1e8514c65884125869bdebf9838ebdb32fc --- /dev/null +++ b/ide/src/doc/quickstart_Js_memory.html @@ -0,0 +1,919 @@ + + + + + quickstart_Js_memory + + + + +
+

Js Memory抓取和展示说明

+ +

Js Memory是查看程序中存量内存的情况。

+

Js Memory的抓取

+ +

Js Memory抓取配置参数

+ +

GitHub Logo
+ 配置参数说明:

+
    +
  • Process:设置抓取的进程ID,此处以1747进程号为例。
  • +
  • Heap snapshot:堆快照性能分析会显示网页的JavaScript对象和相关DOM节点中内存分配情况。
  • +
  • include numerical values in capture:在快照中添加数字。
  • +
  • Interval:抓取的时间间隔。
  • +
  • Allocation insteumentation on timeline:分配时间轴显示了插桩的JavaScript内存分配随时间变化的情况。
  • +
  • record stack traces of allocations(extra performance + overhead):录制各项分配的堆栈轨迹(会产生额外的性能开销)。 +
  • +
+

再点击Record setting,在output file path输入文件名hiprofiler_data_jsmemory.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是30s。
+ GitHub Logo

+

点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。
+ GitHub Logo

+

Js Memory展示说明

+ +

将抓取的jsmemory文件导入到smartperf工具中查看,查看程序中存量内存的情况。

+

Js Memory泳道图展示类型

+ +

堆快照类型文件的泳道图展示。
+ GitHub Logo

+
    +
  • +
    Heapsnapshot:堆快照性能分析会显示网页的JavaScript对象和相关DOM节点中内存分配情况。
    +
    +
  • +
+

时间轴上分配插桩类型文件的泳道图展示。
+ GitHub Logo

+
    +
  • +
    Heaptimeline:分配时间轴显示了插桩的JavaScript内存分配随时间变化的情况。
    +
    +
  • +
+

Js Memory泳道图的框选功能

+ +

可以对内存的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有两个tab页。
+ Summary的Tab页,主要显示了总览视图,通过类的名称来分组显示对象。
+ GitHub Logo

+
    +
  • +
    Constructor:类创建的所有对象,其中
    +              第一层为类名,后面的x表示该类创建了多少实例。
    +              第二层为该类的实例名+id,id唯一。
    +              第三层以下为实例中的成员变量。
    +
    +
  • +
  • +
    Distance:使用节点的最短简单路径显示到根的距离。
    +
    +
  • +
  • +
    ShallowSize:类创建的所有对象的本身的内存大小之和。
    +
    +
  • +
  • +
    RetainedSize:对象以及其相关的对象一起被删除后所释放的内存大小,同一组对象之间的最大保留大小。
    +
    +
  • +
+

+ Comparison的Tab页,主要显示了比较视图,显示两份快照间的不同之处,主要比较类创建与释放的实例数量。
+ GitHub Logo

+
    +
  • +
    #Constructor:类创建的所有对象,类名与id相同视为同一个实例,其中
    +              第一层为类的比较,每个时间点的对比其他时间点的类创建与销毁了哪些实例。
    +              第二层为实例,由于展示的是创建或者销毁实例,固只展示Size大小。
    +              第三层以下为实例的成员变量,不存在比较信息。
    +
    +
  • +
  • +
    #New:新增的实例数量,圆点代表有意义的数据,下划线代表无意义的数据。
    +
    +
  • +
  • +
    #Deleted:删除的实例数量。
    +
    +
  • +
  • +
    #Delta:#New减去#Deleted的数量。
    +
    +
  • +
  • +
    Alloc.Size:新增实例的Size。
    +
    +
  • +
  • +
    Freed Size:删除实例的Size。
    +
    +
  • +
  • +
    Size Delta:Delta的Size。
    +
    +
  • +
+

Js Memory的辅助信息功能

+ +

在Summary和Comparison的Tab页,选中左边实例,右边Retainers的Tab页会显示多少个实例引用了左边选中的实例。
+ GitHub Logo

+
    +
  • +
    Object:引用的实例。
    +
    +
  • +
  • +
    Distance:使用节点的最短简单路径显示到根的距离。
    +
    +
  • +
  • +
    ShallowSize:所有对象的本身的内存大小之和。
    +
    +
  • +
  • +
    RetainedSize:对象以及其相关的对象一起被删除后所释放的内存大小,同一组对象之间的最大保留大小。
    +
    +
  • +
+

Js Memory详细显示的过滤功能

+ +

在下方的Class Filter中输入类名,可以对类名进行过滤,如下图输入array,会过滤出类名是array的相关数据。
+ GitHub Logo

+ +
+ + + + + + \ No newline at end of file diff --git a/ide/src/doc/quickstart_ability_monitor.html b/ide/src/doc/quickstart_ability_monitor.html new file mode 100644 index 0000000000000000000000000000000000000000..2dd87205e40ebae600b16860f6125a727598ca03 --- /dev/null +++ b/ide/src/doc/quickstart_ability_monitor.html @@ -0,0 +1,1365 @@ + + + + + quickstart_ability_monitor + + + + + +
+

Ability Monitor抓取和展示说明

+ +

抓取和展示处理的CPU,内存,磁盘IO和网络使用情况统计。

+

Ability Monitor的抓取

+ +

Ability Monitor抓取界面配置说明

+ +

+ 点击Probes config,如选择抓取AbilityMonitor。
+ GitHub Logo +

+

Ability Monitor文件的抓取

+ +

+ 点击Record setting,在output file path输入文件名hiprofiler_data_abilitymonitor.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。
+ GitHub Logo
+ 输入hdc_shell,进入设备,执行命令。
+ GitHub Logo
+ 进入指定目录,cd /data/local/tmp进入到目录,会看到生成的trace文件。
+ GitHub Logo +

+

Ability Monitor功能介绍

+ +

将抓取的文件导入到smartperf工具查看,能了解CPU,内存,磁盘IO和网络的使用情况。

+

Ability Monitor泳道图展示

+ +

+ Ability Monitor展开就可以看到泳道图,包括CPU,内存,磁盘IO,网络的使用情况。
+ GitHub Logo +

+
    +
  • +
    +CPU Total Load:总的CPU使用率。
    +
    +
  • +
  • +
    +CPU User Load:CPU在用户态空间运行的使用率。
    +
    +
  • +
  • +
    +CPU System Load:CPU在内核空间运行的使用率。
    +
    +
  • +
  • +
    +MemoryTotal: 总计物理内存的大小。
    +
    +
  • +
  • +
    +Cached:缓存的大小。
    +
    +
  • +
  • +
    +SwapTotal: 虚拟内存。
    +
    +
  • +
  • +
    +Disk Bytes Read/Sec:每秒从磁盘读取到内存的字节数。
    +
    +
  • +
  • +
    +Disk Bytes Written/Sec: 每秒从内存写入磁盘的字节数。
    +
    +
  • +
  • +
    +Disk Read Ops/Sec:读入的字节数。
    +
    +
  • +
  • +
    +Disk Written Ops/Sec: 写入的字节数。
    +
    +
  • +
  • +
    +Network Bytes In/Sec:每秒接收的网络数据字节数。
    +
    +
  • +
  • +
    +Network Bytes Out/Sec: 每秒发送的网络数据字节数。
    +
    +
  • +
  • +
    +Network Packets In/Sec:每秒接收的网络数据包数。
    +
    +
  • +
  • +
    +Network Packets Out/Sec: 每秒发送的网络数据包数。
    +
    +
  • +
+

Ability Monitor泳道图的框选功能

+ +

+ 可以对CPU,内存,磁盘IO和网络的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有六个tab页。
+ Live Processes的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Process ID:进程的ID。
    +
    +
  • +
  • +
    +Process Name:进程名称。
    +
    +
  • +
  • +
    +Responsible Process:父进程ID。
    +
    +
  • +
  • +
    +User ID:用户ID。
    +
    +
  • +
  • +
    +%CPU:进程的CPU占用率。
    +
    +
  • +
  • +
    +CPU Time:CPU运行时间。
    +
    +
  • +
  • +
    +#Threads:进程的线程数量。
    +
    +
  • +
  • +
    +Memory:内存值。
    +
    +
  • +
  • +
    +Disk Writes(B):磁盘读入的字节数。
    +
    +
  • +
  • +
    +Disk Reads(B):磁盘写入的字节数。
    +
    +
  • +
+

+ Processes History的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Process ID:进程ID。
    +
    +
  • +
  • +
    +Alive:进程是否存活。
    +
    +
  • +
  • +
    +First Seen:开始时间。
    +
    +
  • +
  • +
    +Last Seen:所选区域的结束时间。
    +
    +
  • +
  • +
    +Process Name:进程名称。
    +
    +
  • +
  • +
    +Responsible Process:父进程ID。
    +
    +
  • +
  • +
    +User ID:用户ID。
    +
    +
  • +
  • +
    +CPU Time:CPU运行时间。
    +
    +
  • +
+

+ 框选CPU Total Load,CPU User Load,CPU System Load三个区域的泳道图,会展示System CPU Summary的Tab页。
+ GitHub Logo +

+
    +
  • +
    +Start Time:采集时间的时间戳。
    +
    +
  • +
  • +
    +Duration:前一次采集到本次采集的时间差。
    +
    +
  • +
  • +
    +TotalLoad%:总的CPU使用率。
    +
    +
  • +
  • +
    +UserLoad%:CPU在用户态空间运行的使用率。
    +
    +
  • +
  • +
    +SystemLoad%:CPU在内核空间运行的使用率。
    +
    +
  • +
  • +
    +Process:进程号。
    +
    +
  • +
+

+ 框选MemoryTotal,Cached,SwapTota三个区域的泳道图,会展示System Memory Summary的Tab页。
+ GitHub Logo +

+
    +
  • +
    +Start Time:采集时间的时间戳。
    +
    +
  • +
  • +
    +Duration:前一次采集到本次采集的时间差。
    +
    +
  • +
  • +
    +MemTotal:总内存大小。
    +
    +
  • +
  • +
    +MemFree:空闲内存大小。
    +
    +
  • +
  • +
    +Buffers:文件的缓冲大小。
    +
    +
  • +
  • +
    +Cached:缓存的大小。
    +
    +
  • +
  • +
    +Shmem:已被分配的共享内存大小。
    +
    +
  • +
  • +
    +Slab:内核数据缓存大小。
    +
    +
  • +
  • +
    +SUnreclaim:不可回收的Slab大小。
    +
    +
  • +
  • +
    +Swap Toal:交换空间的总大小。
    +
    +
  • +
  • +
    +SwapFree:未被使用交换空间的大小。
    +
    +
  • +
  • +
    +Mapped:设备和文件等映射的大小。
    +
    +
  • +
  • +
    +VmallocUsed:已被使用的虚拟内存大小。
    +
    +
  • +
  • +
    +PageTables:管理内存分页的索引表大小。
    +
    +
  • +
  • +
    +KernelStack:Kernel消耗的内存。
    +
    +
  • +
  • +
    +Active: 在活跃使用中的缓冲或高速缓冲存储器页面文件的大小。
    +
    +
  • +
  • +
    +Inactive:在不经常使用中的缓冲或高速缓冲存储器页面文件的大小。
    +
    +
  • +
  • +
    +Unevictable:不能被释放的内存页。
    +
    +
  • +
  • +
    +VmallocTotal:可以vmalloc虚拟内存大小。
    +
    +
  • +
  • +
    +CmaTotal:总的连续可用内存。
    +
    +
  • +
  • +
    +CmaFree:空闲的可用内存。
    +
    +
  • +
+

+ 框选Disk Bytes Read/Sec,Disk Bytes Written/Sec,Disk Read Ops/Sec,Disk Written + Ops/Sec四个区域的泳道图,会展示System Disk Summary的Tab页。
+ GitHub Logo +

+
    +
  • +
    +Start Time:采集时间的时间戳。
    +
    +
  • +
  • +
    +Duration:前一次采集到本次采集的时间差。
    +
    +
  • +
  • +
    +Data Read:从磁盘读取到内存的总字节数。
    +
    +
  • +
  • +
    +Data Read/sec:每秒从磁盘读取到内存的字节数。
    +
    +
  • +
  • +
    +Data Write:从磁盘写入磁盘的总字节数。
    +
    +
  • +
  • +
    +Data Write/sec:每秒从内存写入磁盘的字节数。
    +
    +
  • +
  • +
    +Reads In:读入的字节数。
    +
    +
  • +
  • +
    +Reads In/sec:每秒读入的字节数。
    +
    +
  • +
  • +
    +Write Out:写入的字节数。
    +
    +
  • +
  • +
    +Write Out/sec:每秒写入的字节数。
    +
    +
  • +
+

+ 框选Network Bytes In/Sec,Network Bytes Out/Sec,Network Packets In/Sec,Network Packets + Out/Sec四个区域的泳道图,会展示System Network Summary的Tab页。
+ GitHub Logo +

+
    +
  • +
    +Start Time:采集时间的时间戳。
    +
    +
  • +
  • +
    +Duration:前一次采集到本次采集的时间差。
    +
    +
  • +
  • +
    +Data Received:接收的网络数据总字节数。
    +
    +
  • +
  • +
    +Data Received/sec:每秒接收的网络数据字节数。
    +
    +
  • +
  • +
    +Data Send:发送的网络数据总字节数。
    +
    +
  • +
  • +
    +Data Send/sec:每秒发送的网络数据字节数。
    +
    +
  • +
  • +
    +Packets In:接收的网络总数据包数。
    +
    +
  • +
  • +
    +Packets In/sec:每秒接收的网络数据包数。
    +
    +
  • +
  • +
    +Packets Out:发送的网络总数据包数。
    +
    +
  • +
  • +
    +Packets Out/sec:每秒发送的网络数据包数。
    +
    +
  • +
+
+ + + + diff --git a/ide/src/doc/quickstart_bio.html b/ide/src/doc/quickstart_bio.html new file mode 100644 index 0000000000000000000000000000000000000000..a378d2ab14d6dfeeb8e4f994ae70b15164e5146d --- /dev/null +++ b/ide/src/doc/quickstart_bio.html @@ -0,0 +1,1100 @@ + + + + + quickstart_bio + + + + + + +
+

Bio的抓取和展示说明

+ +

抓取和展示IO延迟的数据。

+

Bio的抓取

+ +

Bio抓取配置参数

+ +

+ GitHub Logo
+ 配置项说明: +

+
    +
  • +
    +Start BIO Latency Record:配置项的总开关。
    +
    +
  • +
  • +
    +Process:默认配置的是整个系统的,也可选择单进程抓取。
    +
    +
  • +
  • +
    +Max Unwind Level:配置抓取调用栈的最大深度。
    +
    +
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_bio.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。
+ GitHub Logo +

+

Bio展示说明

+ +

+ 抓取结束后Bio的trace会自动加载展示。
+ GitHub Logo +

+

界面布局介绍:页内存整体界面布局分为3个部分:

+
    +
  • +
    +红色区域:泳道图。
    +
    +
  • +
  • +
    +绿色区域:详细信息。
    +
    +
  • +
  • +
    +黄色区域:辅助信息(Callstack)。
    +
    +
  • +
+

Bio泳道图展示

+ +

+ Bio泳道图鼠标悬浮以10ms为区间展示该周期内最大的读或者写延迟。
+ GitHub Logo +

+

Bio泳道图的框选功能

+ +

+ 可以对泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有三个tab页。
+ Disk I/O Tier Statistics的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Tier/Process/Path:按照Tier,Process,Path的维度去展示。
    +
    +
  • +
  • +
    +Count:事件数量。
    +
    +
  • +
  • +
    +Total Latency:每种进程,事件的总延迟。
    +
    +
  • +
  • +
    +Min Total Latency:最小延迟时间。
    +
    +
  • +
  • +
    +Avg Total Latency:平均延迟时间。
    +
    +
  • +
  • +
    +Max Total Latency:最大延迟时间。
    +
    +
  • +
+

+ Disk I/O Latency Calltree的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。
    +
    +
  • +
  • +
    +Local:为该调用方法自身占用的CPU时间。
    +
    +
  • +
  • +
    +Weight:调用方法的执行占比。
    +
    +
  • +
+

+ Trace Completion Times的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Start:事件的开始时间。
    +
    +
  • +
  • +
    +Total Latency:事件的延迟时间。
    +
    +
  • +
  • +
    +Process:进程名(pid)。
    +
    +
  • +
  • +
    +Thread:线程名(tid)。
    +
    +
  • +
  • +
    +Latency per 4KB:原始数据里没有,每4k数据的延迟时间,需要根据延迟的size跟延迟的时间去计算。
    +
    +
  • +
  • +
    +Opration:事件类型。
    +
    +
  • +
  • +
    +Bytes:延迟的数据量。
    +
    +
  • +
  • +
    +Path:操作的文件路径。
    +
    +
  • +
  • +
    +Block Number:块数量。
    +
    +
  • +
  • +
    +Tier:层级。
    +
    +
  • +
  • +
    +BackTrace:调用栈顶部函数,并显示调用栈深度。
    +
    +
  • +
+

Bio支持多种Options展示风格

+ +

+ 点击Disk I/O Latency Calltree的Tab页底部的Options,会有两个CheckBox复选框。
+ GitHub Logo +

+
    +
  • +
    +Invert:反向输出调用树。
    +
    +
  • +
  • +
    +Hide System so:隐藏系统库文件  。 
    +
    +
  • +
+

Bio支持过滤调用栈调用次数的展示风格

+ +

+ 点击Disk I/O Latency Calltree的Tab页底部的Sample Counter + Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。
+ GitHub Logo +

+

Bio功能的调用栈Group展示-数据分析支持剪裁功能

+ +

GitHub Logo

+
    +
  • +

    + 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol + Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 +

    +
  • +
  • +

    裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。

    +
  • +
  • +

    点击Reset按钮,将恢复选中的裁剪内容。

    +
  • +
+

Bio功能的调用栈Group展示支持按条件过滤

+ +

+ 在Input Filter输入关键字,会显示出带有该关键字的展示信息。
+ GitHub Logo +

+

Bio辅助信息区展示调用栈

+ +

+ 当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。如下图的Heaviest Stack Trace:
+ GitHub Logo +

+

Bio的Tier的过滤

+ +

+ 通过选择根据Tier去过滤。
+ GitHub Logo +

+

Bio的火焰图功能

+ +

+ 点击Disk I/O Latency Calltree左下角的柱状图的图标,会切换到火焰图页面。
+ GitHub Logo
+ 进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和Duration时长。
+ GitHub Logo
+ 鼠标左键火焰图,会进入下一级界面,右键回到上一级。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_device_record.html b/ide/src/doc/quickstart_device_record.html new file mode 100644 index 0000000000000000000000000000000000000000..df214c61e896bcc2b0fe1e2f32486ae7e81b948c --- /dev/null +++ b/ide/src/doc/quickstart_device_record.html @@ -0,0 +1,869 @@ + + + + + quickstart_device_record + + + + + + +
+

设备端抓取trace说明

+ +

从设备端抓取trace文件的配置和方法。

+

界面配置说明

+ +

+ GitHub Logo
+ 说明: +

+
    +
  • Record setting:设置trace的抓取模式,buffer size大小,抓取时长。
  • +
  • Trace command:生成的抓取命令行。
  • +
  • Probes config:trace的抓取参数配置。
  • +
  • Native Memory:NativeMemory数据的抓取参数配置。
  • +
  • Hiperf:Hiperf数据的抓取参数配置。
  • +
  • eBPF Config:ebpf数据的抓取参数配置。
  • +
  • VM Tracker:smaps数据的抓取参数配置。
  • +
  • HiSystemEvent:HiSystemEvent数据抓取参数配置。
  • +
  • SDK Config:SDK数据抓取参数配置。
  • +
+

命令行的生成和trace文件的抓取

+ +

+ 点击Probes config,如选择抓取Scheduling details。
+ GitHub Logo
+ 再点击Record setting,在output file path输入文件名hiprofiler_data_example.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。
+ GitHub Logo
+ 命令参数说明: +

+
    +
  • -o:文件的输入路径和名称。
  • +
  • -t:抓取的时长。
  • +
  • buffer pages:buffer size大小。
  • +
  • sample_duration:数据采集的时间。
  • +
  • + sample_interval:主动获取插件数据的间隔时间(ms,只针对轮询插件,例如memory插件,cpu插件,dikio插件等,对流式插件和独立插件无效)。 +
  • +
  • trace_period_ms:ftrace插件读取内核缓冲区数据的间隔时间(ms)。
  • +
  • hitrace_time:hitrace命令行抓取时间,与hiprofiler_cmd下发的-t配置联动。
  • +
+

+ 输入hdc_std shell,进入设备,执行命令。
+ GitHub Logo +

+

+ 执行完成后,命令行会给出提示。
+ GitHub Logo
+ 进入指定目录,cd /data/local/tmp 进入到目录,会看到生成的trace文件。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_filesystem.html b/ide/src/doc/quickstart_filesystem.html new file mode 100644 index 0000000000000000000000000000000000000000..d0bf9e88adb8fa70c72444fbf4e65cda17b12dc1 --- /dev/null +++ b/ide/src/doc/quickstart_filesystem.html @@ -0,0 +1,1202 @@ + + + + + quickstart_filesystem + + + + + + +
+

FileSystem的抓取和展示说明

+ +

FileSystem分析文件系统的信息和活动,比如读和写操作等。

+

FileSystem的抓取

+ +

FileSystem抓取配置参数

+ +

+ GitHub Logo
+ 配置项说明: +

+
    +
  • +
    +Start FileSystem Record:配置项的总开关。
    +
    +
  • +
  • +
    +Process:默认配置的是整个系统的,也可选择单进程抓取。
    +
    +
  • +
  • +
    +Max Unwind Level:配置抓取调用栈的最大深度。
    +
    +
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_filesystem.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。
+ GitHub Logo
+ 输入hdc_std shell,进入设备,执行命令。
+ GitHub Logo
+ 执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。
+ GitHub Logo +

+

FileSystem展示说明

+ +

+ 将抓取的trace文件导入smartperf界面查看。
+ GitHub Logo +

+

界面布局介绍:FileSystem整体界面布局分为3个部分:

+
    +
  • +
    +红色区域:泳道图。
    +
    +
  • +
  • +
    +绿色区域:详细信息。
    +
    +
  • +
  • +
    +黄色区域:辅助信息(Callstack)。
    +
    +
  • +
+

FileSystem泳道图展示

+ +

+ FileSystem泳道图按照读操作和写操作展示,鼠标移动都泳道图上,悬浮框会以10ms为周期展示读,写类型系统调用的次数。
+ GitHub Logo
+ 按住w键放大界面,悬浮框会显示当前时刻的文件读写次数。
+ GitHub Logo +

+

FileSystem泳道图的框选功能

+ +

+ 可以对读写操作泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有五个tab页。
+ FileSystem statistics的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Syscall/Process: 按照数据类型,进程分类显示。
    +
    +
  • +
  • +
    +Count: 系统调用的数量。
    +
    +
  • +
  • +
    +Logical Writes:写数据统计。
    +
    +
  • +
  • +
    +Logical Reads:读数据统计。
    +
    +
  • +
  • +
    +Other Filesystem Bytes:其他数据量。
    +
    +
  • +
  • +
    +Duration:总时长。
    +
    +
  • +
  • +
    +Min Duration:最小时长。
    +
    +
  • +
  • +
    +Avg Duration: 平均时长。
    +
    +
  • +
  • +
    +Max Duration:最大时长。
    +
    +
  • +
+

+ FileSystem Calltree的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。
    +
    +
  • +
  • +
    +Local:为该调用方法自身占用的CPU时间。
    +
    +
  • +
  • +
    +Weight:调用方法的执行占比。
    +
    +
  • +
+

+ FileSystem Events的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Start: 起始时间。
    +
    +
  • +
  • +
    +Duration:时长。
    +
    +
  • +
  • +
    +Process:进程名。
    +
    +
  • +
  • +
    +Thread:线程名。
    +
    +
  • +
  • +
    +Firsr Argument:系统调用的第一个参数。
    +
    +
  • +
  • +
    +Second Argument:系统调用的第二个参数。
    +
    +
  • +
  • +
    +Third Argument:系统调用的第三个参数。
    +
    +
  • +
  • +
    +Fourth Argument:系统调用的第四个参数。
    +
    +
  • +
  • +
    +Retrun:系统调用的返回值。
    +
    +
  • +
  • +
    +Error:错误码。
    +
    +
  • +
  • +
    +Backtrace:调用栈顶部函数,并显示调用栈深度。
    +
    +
  • +
+

+ File Descriptor History的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Start: 起始时间。
    +
    +
  • +
  • +
    +Duration:时长。
    +
    +
  • +
  • +
    +Process:进程名。
    +
    +
  • +
  • +
    +Type:操作类型。
    +
    +
  • +
  • +
    +File Descriptor:fd。
    +
    +
  • +
  • +
    +Backtrace:调用栈顶部函数,并显示调用栈深度。
    +
    +
  • +
+

+ File Descriptor Time Slice的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Open Time: 打开的起始时间。
    +
    +
  • +
  • +
    +Open Duration:打开的时长。
    +
    +
  • +
  • +
    +Process:进程名。
    +
    +
  • +
  • +
    +File Descriptor:fd。
    +
    +
  • +
  • +
    +Backtrace:调用栈顶部函数,并显示调用栈深度。
    +
    +
  • +
+

FileSystem支持多种Options展示风格

+ +

+ 点击FileSystem Calltree的Tab页底部的Options,会有两个CheckBox复选框。
+ GitHub Logo +

+
    +
  • +
    +Invert:反向输出调用树。
    +
    +
  • +
  • +
    +Hide System so:隐藏系统库文件。
    +
    +
  • +
+

FileSystem支持过滤调用栈调用次数的展示风格

+ +

+ 点击FileSystem Calltree的Tab页底部的Sample Counter + Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。
+ GitHub Logo +

+

FileSystem功能的调用栈Group展示-数据分析支持剪裁功能

+ +

GitHub Logo

+
    +
  • +

    + 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol + Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 +

    +
  • +
  • +

    裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。

    +
  • +
  • +

    点击Reset按钮,将恢复选中的裁剪内容。

    +
  • +
+

FileSystem功能的调用栈Group展示支持按条件过滤

+ +

+ 在Input Filter输入关键字,会显示出带有该关键字的展示信息。
+ GitHub Logo +

+

FileSystem辅助信息区展示调用栈

+ +

+ 当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。如下图的Heaviest Stack Trace:
+ GitHub Logo +

+

FileSystem的事件类型的过滤

+ +

+ 通过选择可以过滤是Open类型,还是Close类型事件。
+ GitHub Logo +

+

FileSystem的火焰图功能

+ +

+ 点击FileSystem Calltre左下角的柱状图的图标,会切换到火焰图页面。
+ GitHub Logo
+ 进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和Duration时长。
+ GitHub Logo
+ 鼠标左键火焰图,会进入下一级界面,右键回到上一级。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_hiperf.html b/ide/src/doc/quickstart_hiperf.html new file mode 100644 index 0000000000000000000000000000000000000000..2fb413788c4c284d88f7f4c05ce687a9b1048ff1 --- /dev/null +++ b/ide/src/doc/quickstart_hiperf.html @@ -0,0 +1,1041 @@ + + + + + quickstart_hiperf + + + + + + +
+

HiPerf的抓取和展示说明

+ +

HiPerf工具是对系统性能数据进行采样记录,并将采样数据保存为文件,进行读取,展示分析。

+

HiPerf的抓取

+ +

HiPerf抓取配置参数

+ +

+ GitHub Logo
+ 配置项说明: +

+
    +
  • +
    +Start Hiperf Sampling:配置项的总开关。
    +
    +
  • +
  • +
    +Process:离线模式下配置的是整个系统的。
    +
    +
  • +
  • +
    +Frequency:配置抓取的频率。
    +
    +
  • +
  • +
    +Call Stack:配置抓取的堆栈类型。
    +
    +
  • +
  • +
    +Advance Options:更多的抓取配置项。
    +
    +
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_perf.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。
+ GitHub Logo
+ 输入hdc_shell,进入设备,执行命令。
+ GitHub Logo
+ 执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。
+ GitHub Logo +

+

HiPerf展示说明

+ +

+ 将抓取的trace文件导入smartperf界面查看。
+ GitHub Logo +

+

界面布局介绍:Perf整体界面布局分为3个部分:

+
    +
  • +
    +红色区域:泳道图。
    +
    +
  • +
  • +
    +绿色区域:详细信息(Perf Profile和Sample List)。
    +
    +
  • +
  • +
    +黄色区域:辅助信息(Callstack)。
    +
    +
  • +
+

HiPerf泳道图展示

+ +

+ Perf泳道图展示按照CPU使用量和线程和进程展示,鼠标移动都泳道图上,悬浮框会显示CPU的使用量。
+ GitHub Logo
+ 按住w键放大界面,泳道图会出现P的标志,鼠标移动到P图标上,悬浮框会显示每个callstack和调用的深度如下图。
+ GitHub Logo +

+

HiPerf泳道图的框选功能

+ +

+ 可以对CPU使用量区,线程和进程区数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有两个tab页。
+ Perf Profile的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。
    +
    +
  • +
  • +
    +Local:为该调用方法自身占用的CPU时间。
    +
    +
  • +
  • +
    +Weight:调用方法的执行次数和占比。
    +
    +
  • +
+

+ Sample List的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Sample Time:采样的时间戳信息。
    +
    +
  • +
  • +
    +Core:当前的CPU核信息。
    +
    +
  • +
  • +
    +Process:进程名。
    +
    +
  • +
  • +
    +Thread:线程名。
    +
    +
  • +
  • +
    +State:运行状态。
    +
    +
  • +
  • +
    +Backtrace:栈顶的调用栈名称。
    +
    +
  • +
+

HiPerf支持多种Options展示风格

+ +

+ 点击Perf Profile的Tab页底部的Options,会有两个CheckBox复选框。
+ GitHub Logo +

+
    +
  • +
    +Invert:反向输出调用树。
    +
    +
  • +
  • +
    +Hide System so:隐藏系统库文件。
    +
    +
  • +
+

HiPerf支持过滤调用栈调用次数的展示风格

+ +

+ 点击Perf Profile的Tab页底部的Sample Counter Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。
+ GitHub Logo +

+

HiPerf功能的调用栈Group展示-数据分析支持剪裁功能

+ +

GitHub Logo

+
    +
  • +

    + 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol + Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 +

    +
  • +
  • +

    裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。

    +
  • +
  • +

    点击Reset按钮,将恢复选中的裁剪内容。

    +
  • +
+

HiPerf功能的调用栈Group展示支持按条件过滤

+ +

+ 在Input Filter输入关键字,会显示出带有该关键字的展示信息。
+ GitHub Logo +

+

HiPerf辅助信息区展示调用栈

+ +

+ 当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。对上展示到根节点,对下则展示CPU占用率最大的调用栈。调用栈右侧有Sliding + bar可以滚动。
+ 如下图的Heaviest Stack Trace:
+ GitHub Logo +

+

HiPerf的火焰图功能

+ +

+ 点击Perf Profile左下角的柱状图的图标,会切换到火焰图页面。
+ GitHub Logo
+ 进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和count大小。
+ GitHub Logo
+ 鼠标左键火焰图,会进入下一级界面,右键回到上一级。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_hisystemevent.html b/ide/src/doc/quickstart_hisystemevent.html new file mode 100644 index 0000000000000000000000000000000000000000..dfd639894340cbd8982e17c4f0f449c4c8eb6a69 --- /dev/null +++ b/ide/src/doc/quickstart_hisystemevent.html @@ -0,0 +1,1188 @@ + + + + + quickstart_hisystemevent + + + + + + +
+

HiSystemEvent的抓取和展示说明

+ +

+ HiSystemEvent应用功耗模块主要是展示应用的各个子类别功耗占比信息、应用的资源申请使用记录信息、应用功耗异常事件信息、功耗关联系统状态信息。 +

+

HiSystemEvent的抓取

+ +

HiSystemEvent抓取配置参数

+ +

+ 打开Start Hisystem Event Tracker Record开关抓取HiSystemEvent数据。
+ GitHub Logo
+ 再点击Record setting,在output file path输入文件名hiprofiler_data_hisystemevent.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。
+ GitHub Logo
+ 输入hdc_std shell,进入设备,执行上述生成的命令。
+ GitHub Logo
+ 执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。
+ GitHub Logo +

+

HiSystemEvent展示说明

+ +

HiSystemEvent泳道图展示

+ +

+ 将抓取的trace文件导入smartperf界面查看。
+ GitHub Logo
+ 泳道图说明: +

+
    +
  • +
    +Anomaly Event泳道: 显示系统异常和应用异常的ToolTip。
    +
    +
  • +
  • +
    +System Event泳道: 以条状图显示,红色代表后台任务(WORKSCHEDULER),黄色代表应用锁(POWER),蓝色代表GPS定位(LOCATION)。
    +
    +
  • +
  • +
    +Power泳道:应用各个子类的功耗柱状图、折现图以及应用各个子类绘制的图例,鼠标的悬浮可以显示出各个子类功耗的具体值。
    +
    +
  • +
  • +
    +Brightness Nit泳道:鼠标悬浮可以显示屏幕亮度值。
    +
    +
  • +
  • +
    +Wifi Event Received泳道:鼠标悬浮可以显示WiFi信号强度值。
    +
    +
  • +
  • +
    +Audio Stream Change泳道:鼠标悬浮可以显示Audio状态(AUDIO_STREAM_CHANGE事件)。
    +
    +
  • +
  • +
    +Audio Volume Change泳道:鼠标悬浮可以显示Audio状态(AUDIO_VOLUME_CHANGE事件)。
    +
    +
  • +
  • +
    +Wifi State泳道:鼠标悬浮可以显示wifi开关状态(enable:开,disable:关)。
    +
    +
  • +
  • +
    +Bluetooth Br Switch State泳道:鼠标悬浮可以显示蓝牙开关状态(enable:开, disable:关)。
    +
    +
  • +
  • +
    +Location Switch State泳道:鼠标悬浮可以显示GPS开关状态(enable:开,disable:关)。
    +
    +
  • +
+

HiSystemEvent泳道图的框选功能

+ +

+ 可以对Energy各泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格。
+ System Details的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Event Name: 事件名称,事件包括后台任务,应用锁,GPS定位。
    +
    +
  • +
  • +
    +Time: 时间戳信息。
    +
    +
  • +
+

+ 点击事件名会显示该事件的详细信息的Tab页。
+ GitHub Logo +

+
    +
  • +
    +EVENT_NAME:事件名称。
    +
    +
  • +
  • +
    +PID:应用PID。
    +
    +
  • +
  • +
    +UID:应用UID。
    +
    +
  • +
  • +
    +TYPE:类型。
    +
    +
  • +
  • +
    +STATE:状态值。
    +
    +
  • +
  • +
    +LOG_LEVEL:日志级别。
    +
    +
  • +
  • +
    +NAME:NAME信息。
    +
    +
  • +
  • +
    +MESSAGE:MESSAGE信息。
    +
    +
  • +
  • +
    +TAG:锁名。
    +
    +
  • +
+

+ Power Battery的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Gas Gauge: 电池电量。
    +
    +
  • +
  • +
    +Charge:充电状态。
    +
    +
  • +
  • +
    +Screen:屏幕状态。
    +
    +
  • +
  • +
    +Level:电池百分比。
    +
    +
  • +
  • +
    +Current:电池电流。
    +
    +
  • +
  • +
    +Capacity:电池容量。
    +
    +
  • +
  • +
    +APP Name:应用包名。
    +
    +
  • +
+

+ Power Details的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +UID: 应用UID。
    +
    +
  • +
  • +
    +Charge:充电状态。
    +
    +
  • +
  • +
    +Foreground Duration(ms):前台使用时长。
    +
    +
  • +
  • +
    +Foreground Energy(mAs):前台使用功耗值。
    +
    +
  • +
  • +
    +Background Duration(ms):后台使用时长。
    +
    +
  • +
  • +
    +Background Energy(mAs):后台使用功耗值。
    +
    +
  • +
  • +
    +Screen On Duration(ms):亮屏使用时长。
    +
    +
  • +
  • +
    +Screen On Energy(mAs):亮屏使用功耗值。
    +
    +
  • +
  • +
    +Screen Off Duration(ms):灭屏使用时长。
    +
    +
  • +
  • +
    +Screen Off Energy(mAs):灭屏使用功耗值。
    +
    +
  • +
  • +
    +Foreground Count:应用前台扫描次数。
    +
    +
  • +
  • +
    +Background Count:应用后台扫描次数。
    +
    +
  • +
  • +
    +Screen On Count:应用亮屏扫描次数。
    +
    +
  • +
  • +
    +Screen Off Count:应用灭屏扫描次数。
    +
    +
  • +
  • +
    +Background Time(ms):灭屏使用功耗值。
    +
    +
  • +
  • +
    +Screen On Time(ms):应用亮屏使用时长。
    +
    +
  • +
  • +
    +Screen Off Time(ms):应用灭屏使用时长。
    +
    +
  • +
  • +
    +Energy(mAs):功耗值。
    +
    +
  • +
  • +
    +Load(%):占用率。
    +
    +
  • +
  • +
    +Usage(ms):应用使用时长。
    +
    +
  • +
  • +
    +Duration(ms):持续时长。
    +
    +
  • +
  • +
    +Camera Id:Camera类型,0:后置,1:前置。
    +
    +
  • +
  • +
    +Count:应用个数。
    +
    +
  • +
  • +
    +Energy Percent(%):功耗占比。
    +
    +
  • +
+
+ + + + diff --git a/ide/src/doc/quickstart_native_memory.html b/ide/src/doc/quickstart_native_memory.html new file mode 100644 index 0000000000000000000000000000000000000000..4f7c2d684485ab4437abee094a45c4b777518af2 --- /dev/null +++ b/ide/src/doc/quickstart_native_memory.html @@ -0,0 +1,1155 @@ + + + + + quickstart_native_memory + + + + + + +
+

Native Memory抓取和展示说明

+ +

Native Memory是查看内存的分配和释放等情况。

+

Native Memory的抓取

+ +

Native Memory抓取配置参数

+ +

+ GitHub Logo
+ 配置参数说明: +

+
    +
  • ProcessId or ProcessName:设置抓取的进程ID或者进程名,此处以输入com.ohos.mms进程名为例。
  • +
  • Max unwind level:抓取的栈的最大深度。
  • +
  • Shared Memory Size:native_daemon和native_hook进程之间存储数据的共享内存大小。
  • +
  • Filter Memory Size:只抓取大于该size的malloc数据(free不受影响)。
  • +
  • Use Fp Unwind:Fp回栈。
  • +
  • Use Record Accurately:不过滤数据,上报全量的。
  • +
  • Use Offline Symbolization:离线符号化。
  • +
  • Use Record Statistics:统计数据上报。
  • +
  • statistics interval:统计数据上报周期。
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_nativememory.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo +

+

+ 点击Trace command,就会根据上面的配置生成抓取命令,点击复制按钮,会将命令行复制。
+ GitHub Logo +

+

命令行参数说明:

+
    +
  • save_file:是否将hook数据保存成文件,不上报protobuf形式数据给hiprofilerd。
  • +
  • filter_size:过滤malloc的大小,最小值是0,默认值是4096Byte。
  • +
  • smb_pages:nativedeamon与libnativehook间的共享内存大小。
  • +
  • max_stack_depth:最多回栈的层数,也就是抓取的栈的最大深度。
  • +
  • fp_unwind:是否进行fp回栈。
  • +
  • malloc_free_matching_interval:native_daemon从nativehook so的共享内存里取数据的间隔时间。
  • +
  • string_compressed:是否进行字符串压缩。
  • +
  • fp_unwind:fp回栈。
  • +
+

+ 输入hdc_std shell,进入设备,执行命令。
+ GitHub Logo
+ 执行完成后,进入指定目录查看,在/data/local/tmp下就会生成trace文件。
+ GitHub Logo +

+

Native Memory展示说明

+ +

将抓取的nativememory文件导入到smartperf工具中查看,查看内存的分配和释放等情况。

+

Native Memory泳道图展示类型

+ +

+ 点击齿轮状的图标可以设置内存的展示单位。
+ GitHub Logo +

+
    +
  • +
    +Current Bytes:以申请内存的size绘制泳道图。
    +
    +
  • +
  • +
    +Native Memory Density:以申请内存的数量绘制泳道图。
    +
    +
  • +
  • +
    +All Heap&AnonuymousVM:malloc分配和mmap分配的总量。
    +
    +
  • +
  • +
    +All Heap:malloc分配的内存。
    +
    +
  • +
  • +
    +All Anonymous VM:mmap分配的内存。
    +
    +
  • +
+

Native Memory泳道图的框选功能

+ +

+ 可以对内存的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有四个tab页。
+ Statistics的Tab页,主要显示了统计明细类型。
+ GitHub Logo +

+
    +
  • +
    +Memory Type:内存的类型。
    +
    +
  • +
  • +
    +Exsiting:框选区域内申请没有释放的大小。
    +
    +
  • +
  • +
    +#Exsiting:框选区域内申请没有释放的次数。
    +
    +
  • +
  • +
    +Transient:框选区域内释放的大小。
    +
    +
  • +
  • +
    +#Transient:框选区域内释放的次数。
    +
    +
  • +
  • +
    +Total Bytes:框选区间内申请的大小。
    +
    +
  • +
  • +
    +#Total: 框选区间内申请的次数。
    +
    +
  • +
  • +
    +Peak Value: 框选区间内内存申请的峰值。
    +
    +
  • +
  • +
    +Exsiting/Total:框选区间内剩余的内存比上申请的内存,其中浅紫色是框选区间内申请的大小/整个时间轴(申请+释放的总大小),深紫色是框选区间内(申请+释放)的大小/整个时间轴(申请+释放的总大小)。
    +
    +
  • +
+

+ Call Info的Tab页,主要显示了调用树详细类型。
+ GitHub Logo +

+
    +
  • +
    +Symble Name:每个内存分配的调用栈。
    +
    +
  • +
  • +
    +Size:分配的总大小。
    +
    +
  • +
  • +
    +Count:相同调用栈出现的次数。
    +
    +
  • +
+

+ Native Memory的Tab页,主要显示了单次分配信息列表。
+ GitHub Logo +

+
    +
  • +
    +Address:内存块的地址。
    +
    +
  • +
  • +
    +Memory Type:内存分配的类型。
    +
    +
  • +
  • +
    +Timestamp:时间戳信息。
    +
    +
  • +
  • +
    +State:内存地址当前状态Existed 表示框选范围内未释放,Freed表示已释放。
    +
    +
  • +
  • +
    +Size:该次申请分配内存的大小。
    +
    +
  • +
  • +
    +Responsible Library :调用该函数的库。
    +
    +
  • +
  • +
    +Responsible Caller  :调用该函数的方法。
    +
    +
  • +
+

+ Snapshot List的Tab页,主要显示了各时刻内存的增长的差值。
+ GitHub Logo +

+
    +
  • +
    +Snapshot:标记的打点说明。
    +
    +
  • +
  • +
    +Timestamp :时间戳信息。
    +
    +
  • +
  • +
    +Net Growth :自从上次Snapshot的增长量,是计算的分配和释放的。
    +
    +
  • +
  • +
    +Total Growth :自从上次Snapshot的增长量,是计算的每一次分配的。
    +
    +
  • +
  • +
    +#Exsiting  :仍然存在的内存数。
    +
    +
  • +
+

Native Memory的辅助信息功能

+ +

+ 在Call Info和Native Memory的Tab页,点击选中某一行,右边画红线处会显示出该行调用栈的树结构信息。
+ GitHub Logo +

+

Native Memory详细显示的过滤功能

+ +

+ 点击下方的All Allocations可以对Allocation的lifeSpan进行过滤,有三个选择:All Allocatios,Create & + Exsiting,Create & Destroyed。
+ GitHub Logo +

+
    +
  • +
    + All Allocations:所有的内存。
    +
    +
  • +
  • +
    + Created & Exsiting:创建且被存活的内存。
    +
    +
  • +
  • +
    + Created & Destroyed: 创建且被销毁的内存。
    +
    +
  • +
+

+ 点击下方的All Heap&Anonymous可以对内存类型进行过滤。
+ GitHub Logo +

+
    +
  • +
    +All Heap&AnonuymousVM:Heap和AnonuymousVM的总量。
    +
    +
  • +
  • +
    +All Heap:malloc分配的内存。
    +
    +
  • +
  • +
    +All Anonymous VM:mmap的匿名页。
    +
    +
  • +
+

+ 点击下方的Mark Snapshot可以在时间轴上打标签。出现小旗的标志,通过标注多个时间点。点击到Snapshot + List标签页可以看到各个时间点的内存的增长值。
+ GitHub Logo +

+

Native Memory的火焰图功能

+ +

+ 点击callinfo左下角的柱状图的图标,会切换到火焰图页面。
+ GitHub Logo
+ 进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和size大小。
+ GitHub Logo
+ 鼠标左键火焰图,会进入下一级界面,右键回到上一级。
+ GitHub Logo +

+

Native Memory数据统计功能

+ +

+ 选择Use Record Statistics和statistics interval配置项抓取的数据,只会显示Call Info的Tab页,Call + Info相关功能同上。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_page_fault.html b/ide/src/doc/quickstart_page_fault.html new file mode 100644 index 0000000000000000000000000000000000000000..5ed0a8c7061251609a49716ec9b1b1b93b1a5713 --- /dev/null +++ b/ide/src/doc/quickstart_page_fault.html @@ -0,0 +1,1068 @@ + + + + + quickstart_page_fault + + + + + + +
+

页内存的抓取和展示说明

+ +

页内存从page层面更深层次剖析应用程序的虚拟内存操作。

+

页内存的抓取

+ +

页内存抓取配置参数

+ +

+ GitHub Logo
+ 配置项说明: +

+
    +
  • +
    +Start Page Fault Record:配置项的总开关。
    +
    +
  • +
  • +
    +Process:默认配置的是整个系统的,也可选择单进程抓取。
    +
    +
  • +
  • +
    +Max Unwind Level:配置抓取调用栈的最大深度。
    +
    +
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_ebpf.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。
+ GitHub Logo +

+

页内存展示说明

+ +

+ 抓取结束后页内存的trace会自动加载展示。
+ GitHub Logo +

+

界面布局介绍:页内存整体界面布局分为3个部分:

+
    +
  • +
    +红色区域:泳道图。
    +
    +
  • +
  • +
    +绿色区域:详细信息。
    +
    +
  • +
  • +
    +黄色区域:辅助信息(Callstack)。
    +
    +
  • +
+

页内存泳道图展示

+ +

+ 页内存泳道图展示事件(Operation)发生的次数,每个事件都有持续时间,鼠标悬浮以10ms为区间进行次数统计。
+ GitHub Logo
+ 按住w键放大界面,悬浮框会显示当前时刻的事件发生次数。
+ GitHub Logo +

+

页内存泳道图的框选功能

+ +

+ 可以对泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有三个tab页。
+ Page Fault Statistics的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Operation/Process/Thread: 按照Operation为基点显示。
    +
    +
  • +
  • +
    +Count: 事件数量。
    +
    +
  • +
  • +
    +Duration:总时长。
    +
    +
  • +
  • +
    +Min Duration:最小时长。
    +
    +
  • +
  • +
    +Avg Duration: 平均时长。
    +
    +
  • +
  • +
    +Max Duration:最大时长。
    +
    +
  • +
+

+ 点击下方的Statistics by Thread,可以切换到按照Thread为基点显示数据。
+ GitHub Logo
+ Page Fault Calltree的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Call Stack:为经过符号解析后的Callstack,并且给出动态链接库或者进程名的信息。
    +
    +
  • +
  • +
    +Local:为该调用方法自身占用的CPU时间。
    +
    +
  • +
  • +
    +Weight:调用方法的执行占比。
    +
    +
  • +
+

+ Page Fault Events的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Start Time:起始时间。
    +
    +
  • +
  • +
    +Duration:时长。
    +
    +
  • +
  • +
    +Thread:线程名。
    +
    +
  • +
  • +
    +Operation:事件类型。
    +
    +
  • +
  • +
    +Address:内存地址。
    +
    +
  • +
  • +
    +Size:内存大小。
    +
    +
  • +
+

页内存支持多种Options展示风格

+ +

+ 点击Page Fault Calltree的Tab页底部的Options,会有两个CheckBox复选框。
+ GitHub Logo +

+
    +
  • +
    +Invert:反向输出调用树。
    +
    +
  • +
  • +
    +Hide System so:隐藏系统库文件。
    +
    +
  • +
+

页内存支持过滤调用栈调用次数的展示风格

+ +

+ 点击Page Fault Calltree的Tab页底部的Sample Counter + Filter,可以填上区间值。过滤出符合该区间值调用次数的调用栈信息。
+ GitHub Logo +

+

页内存功能的调用栈Group展示-数据分析支持剪裁功能

+ +

GitHub Logo

+
    +
  • + 裁剪Callstack,点击Callstack上一个节点符号,再点击底部Symbol + Filter按钮,则该符号自动被裁剪掉,同时将该节点往下所有的Callstack内容裁剪掉。 +
  • +
  • 裁剪Library,点击Library Filter按钮,则该库文件符号下所有的子节点也被裁剪。
  • +
  • 点击Reset按钮,将恢复选中的裁剪内容。
  • +
+

页内存功能的调用栈Group展示支持按条件过滤

+ +

+ 在Input Filter输入关键字,会显示出带有该关键字的展示信息。
+ GitHub Logo +

+

页内存辅助信息区展示调用栈

+ +

+ 当在详细信息区选择一个符号时,将展示与该符号相关的完整的调用栈。如下图的Heaviest Stack Trace:
+ GitHub Logo +

+

页内存的事件类型的过滤

+ +

+ 通过选择可以过滤是File Backed In类型,还是Copy On Write类型事件。
+ GitHub Logo +

+

页内存的火焰图功能

+ +

+ 点击Page Fault Calltree左下角的柱状图的图标,会切换到火焰图页面。
+ GitHub Logo
+ 进入到火焰图页面,火焰图的展示跟Callinfo的tab页的调用栈显示一致,鼠标放到色块上,悬浮框可以显示调用栈名称和Duration时长。
+ GitHub Logo
+ 鼠标左键火焰图,会进入下一级界面,右键回到上一级。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_schedulinganalysis.html b/ide/src/doc/quickstart_schedulinganalysis.html new file mode 100644 index 0000000000000000000000000000000000000000..32dca3547ffe59f7d20aad2c72b5a9a0f61c57a9 --- /dev/null +++ b/ide/src/doc/quickstart_schedulinganalysis.html @@ -0,0 +1,1269 @@ + + + + + quickstart_schedulinganalysis + + + + + + +
+

Scheduling analysis抓取和展示说明

+ +

抓取和展示CPU调度分析,线程调度分析相关数据。

+

Scheduling analysis的抓取

+ +

Scheduling analysis抓取界面配置说明

+ +

+ 打开Scheduling analysis开关抓取调度分析数据。
+ GitHub Logo +

+

Scheduling analysis文件的抓取

+ +

+ 点击Record setting,在output file path输入文件名hiprofiler_dataScheduling.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。
+ GitHub Logo +

+

Scheduling analysis功能介绍

+ +

将抓取的文件导入到smartperf工具查看。

+

CPU频点分析

+ +

+ 点击下拉列表框选择CPU Frequency,可以看到各核CPU的各频点持续时长的占比图,以颜色区分各频点。
+ GitHub Logo
+ 点击CPU Frequency饼图,可以跳转到详细信息界面,用饼图和表格来展示某个CPU下各频点持续时长的的相关数据。
+ GitHub Logo +

+
    +
  • +
    +No:编号。
    +
    +
  • +
  • +
    +frequency:频率。
    +
    +
  • +
  • +
    +min:最小时长。
    +
    +
  • +
  • +
    +max:最大时长。
    +
    +
  • +
  • +
    +average:平均时长。
    +
    +
  • +
  • +
    +duration:运行总时长。
    +
    +
  • +
+

+ 点击详细页的CPU Frequency饼图,可以跳转某个CPU下某个频点的运行的线程信息。
+ GitHub Logo +

+
    +
  • +
    +No:编号。
    +
    +
  • +
  • +
    +t_name:线程名。
    +
    +
  • +
  • +
    +tid:线程id。
    +
    +
  • +
  • +
    +p_name:进程名。
    +
    +
  • +
  • +
    +p_pid:进程id。
    +
    +
  • +
  • +
    +duration:运行总时长。
    +
    +
  • +
+

CPU Idle分析

+ +

+ 点击下拉列表框选择CPU Idle,可以看到各CPU的Idle的时长占比饼图,以颜色区分各Idle。
+ GitHub Logo
+ 点击CPU Idle饼图,可以跳转到某CPU的idle分析的详细数据,以饼图和表格的形式展示。
+ GitHub Logo +

+
    +
  • +
    +No:编号。
    +
    +
  • +
  • +
    +idle:idle值。
    +
    +
  • +
  • +
    +min:最小时长。
    +
    +
  • +
  • +
    +max:最大时长。
    +
    +
  • +
  • +
    +average:平均时长。
    +
    +
  • +
  • +
    +duration:运行总时长。
    +
    +
  • +
+

CPU Irq分析

+ +

+ 点击下拉列表框选择CPU Irq,可以看到各CPU的Irq的时长占比饼图,以颜色区分。
+ GitHub Logo
+ 点击CPU Irq饼图,可以跳转到某CPU的Irq分析的详细数据,以饼图和表格的形式展示。
+ GitHub Logo +

+
    +
  • +
    +No:编号。
    +
    +
  • +
  • +
    +block:irq的类型。
    +
    +
  • +
  • +
    +name:irp名称。
    +
    +
  • +
  • +
    +min:最小时长。
    +
    +
  • +
  • +
    +max:最大时长。
    +
    +
  • +
  • +
    +average:平均时长。
    +
    +
  • +
  • +
    +duration:运行总时长。
    +
    +
  • +
+

CPU占用率显示

+ +

+ 以表格显示各CPU的占用率。
+ GitHub Logo +

+

Top20线程大中小核占用率

+ +

+ 选择Thread Analysis标签页,各个CPU通过勾选big或者middle或者small来设置CPU的分类。
+ GitHub Logo
+ 各CPU勾选好大中小核,点击Upload可以跳转到各个线程CPU占用率情况的展示页面。
+ GitHub Logo
+ 如上图所示: +

+
    +
  • +
    +三色柱状图:各个线程CPU的占用率情况,其中以颜色区分占用的大中小核的占用率情况,并以表格的形式展示各个线程的基本信息和大中小核占用率。
    +
    +
  • +
  • +
    +单色柱状图:分别统计线程在某一个类别(大、中、小)的CPU的占用率,并显示出线程的基本信息和占用率。
    +
    +
  • +
+

表格的字段说明:

+
    +
  • +
    +tid:线程号。
    +
    +
  • +
  • +
    +t_name:线程名。
    +
    +
  • +
  • +
    +pid:进程号。
    +
    +
  • +
  • +
    +p_name:进程名。
    +
    +
  • +
  • +
    +big core:大核占用时长。
    +
    +
  • +
  • +
    +middle core:中核占用时长。
    +
    +
  • +
  • +
    +small core:小核占用时长。
    +
    +
  • +
  • +
    +cpu..(us):运行总时长(..代表cpu号)。
    +
    +
  • +
+

单个线程频点分布

+ +

+ 点击单个线程频点分布的标签,通过在Thread Search选择线程,来展示单个线程的频点分布情况。
+ GitHub Logo +

+
    +
  • +
    +NO:编号。
    +
    +
  • +
  • +
    +cpu:cpu编号。
    +
    +
  • +
  • +
    +frequency:频点。
    +
    +
  • +
  • +
    +duration:运行时长。
    +
    +
  • +
  • +
    +%:频点占用率。
    +
    +
  • +
+

Top20单次运行超长线程

+ +

+ 通过点击Top20单次运行超长线程标签,显示线程的单次运行时长来统计出单次运行时长最大的20个线程。
+ GitHub Logo +

+
    +
  • +
    +NO:编号。
    +
    +
  • +
  • +
    +tid:线程号。
    +
    +
  • +
  • +
    +t_name:线程名。
    +
    +
  • +
  • +
    +pid:进程号。
    +
    +
  • +
  • +
    +p_name:进程名。
    +
    +
  • +
  • +
    +max duration:最大运行时长。
    +
    +
  • +
  • +
    +timestamp:时间戳信息。
    +
    +
  • +
+

Top20进程线程数

+ +

+ 通过点击Top20进程线程数标签,显示线程数量最多的20个进程,以饼图和表格方式显示。
+ GitHub Logo +

+
    +
  • +
    +NO:编号。
    +
    +
  • +
  • +
    +pid:进程号。
    +
    +
  • +
  • +
    +p_name:进程名。
    +
    +
  • +
  • +
    +thread count:线程数量。
    +
    +
  • +
+

Top20切换次数线程

+ +

+ 通过点击Top20切换次数线程标签,显示切换次数最多的20个进程,以饼图和表格方式显示。
+ GitHub Logo +

+
    +
  • +
    +NO:编号。
    +
    +
  • +
  • +
    +tid:线程号。
    +
    +
  • +
  • +
    +t_name:线程名。
    +
    +
  • +
  • +
    +pid:进程号。
    +
    +
  • +
  • +
    +p_name:进程名。
    +
    +
  • +
  • +
    +sched_switch count:切换次数。
    +
    +
  • +
+
+ + + + diff --git a/ide/src/doc/quickstart_sdk.html b/ide/src/doc/quickstart_sdk.html new file mode 100644 index 0000000000000000000000000000000000000000..f47806089966c76dc051ab4c3abf59094061f159 --- /dev/null +++ b/ide/src/doc/quickstart_sdk.html @@ -0,0 +1,827 @@ + + + + + quickstart_sdk + + + + + + +
+

Sdk抓取

+ +

抓取Sdk数据。

+

Sdk的抓取

+ +

Sdk抓取配置参数

+ +

+ 打开Start Custom Config开关抓取Sdk数据。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_smaps.html b/ide/src/doc/quickstart_smaps.html new file mode 100644 index 0000000000000000000000000000000000000000..644dda7fe55c21c92286e4538e9a3865eff60b2d --- /dev/null +++ b/ide/src/doc/quickstart_smaps.html @@ -0,0 +1,1010 @@ + + + + + quickstart_smaps + + + + + + +
+

进程smaps的抓取和展示说明

+ +

smaps展示了一个进程的内存消耗。

+

smaps的抓取

+ +

smaps抓取配置参数

+ +

+ GitHub Logo
+ 配置项说明: +

+
    +
  • +
    +Start VM Tracker Record:配置项的总开关。
    +
    +
  • +
  • +
    +Process:smaps的抓取只能选择单进程抓取。
    +
    +
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_smaps.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击Record抓取,抓取过程中会显示抓取时长。
+ GitHub Logo +

+

smaps展示说明

+ +

+ 抓取结束后smaps的trace会自动加载展示。
+ GitHub Logo +

+

界面布局介绍:smaps整体界面布局分为3个部分:

+
    +
  • +
    +红色区域:泳道图。
    +
    +
  • +
  • +
    +绿色区域:详细信息。
    +
    +
  • +
+

smaps泳道图展示

+ +

+ smaps泳道图展示当前时刻该进程的内存消耗。
+ GitHub Logo +

+

smaps泳道图的框选功能

+ +

+ 可以对泳道图进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有两个个tab页。
+ VM Tracker Statistics的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Type: 将抓取到的信息根据Type归类,分四类,Data,Text,Const,Other。
    +
    +
  • +
  • +
    +% of Res: 每行的Resident Size 占总Ressident Size的比例。
    +
    +
  • +
  • +
    +#Reg:统计的类型个数。
    +
    +
  • +
  • +
    +Path:虚拟内存块路径,类型中有多个则显示multiple。
    +
    +
  • +
  • +
    +Resident Size: smaps节点中Rss(Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty)。
    +
    +
  • +
  • +
    +Dirty Size:smaps节点中Shared_Dirty + Private_Dirty。
    +
    +
  • +
  • +
    +Swapped: smaps节点中Swap + SwapPss。
    +
    +
  • +
  • +
    +Virtual Size:smaps节点中Size。
    +
    +
  • +
  • +
    +Pss: smaps节点中Pss。
    +
    +
  • +
  • +
    +Res. %:Resident Size / Virtual Size 比值。
    +
    +
  • +
+

+ VM Tracker Record List的Tab页如图:
+ GitHub Logo +

+
    +
  • +
    +Type: 将抓取到的信息根据Type归类,Data,Text,Const,Other。
    +
    +
  • +
  • +
    +Address Range: 每段虚拟内存段的开始和结束位置。
    +
    +
  • +
  • +
    +Dirty Size:smaps节点中Shared_Dirty + Private_Dirty。
    +
    +
  • +
  • +
    +Swapper: smaps节点中Swap + SwapPss。
    +
    +
  • +
  • +
    +Resident Size:smaps节点中Rss(Shared_Clean+Shared_Dirty+Private_Clean+Private_Dirty)。
    +
    +
  • +
  • +
    +Virtual Size:smaps节点中Size。
    +
    +
  • +
  • +
    +Pss:smaps节点中Pss。
    +
    +
  • +
  • +
    +Reside: Rss / Size 比值。
    +
    +
  • +
  • +
    +Protection: 内存块的权限(读写执行执行)。
    +
    +
  • +
  • +
    +Path: 内存段路径。
    +
    +
  • +
+
+ + + + diff --git a/ide/src/doc/quickstart_smartperflinux_compile_guide.html b/ide/src/doc/quickstart_smartperflinux_compile_guide.html new file mode 100644 index 0000000000000000000000000000000000000000..33ef905f5a53a27b1b3039c141758345b51ad3ed --- /dev/null +++ b/ide/src/doc/quickstart_smartperflinux_compile_guide.html @@ -0,0 +1,982 @@ + + + + + quickstart_smartperflinux_compile_guide + + + + + + +
+

SmartPerf 编译部署指导文档

+ +

编译环境搭建

+ +

注意:在linux编译环境安装时以root或者其他 sudo 用户身份运行下面的命令。

+

node 环境安装

+ +
下载Node js安装包(windows推荐, linux跳过此步骤)
+ +

+ 从网站下载node js安装包 + https://nodejs.org/en/download/current/。 +

+
安装nodejs
+ +
    +
  • + ubuntu 20.04 与Debian 11系统中,直接用apt-get安装,先切换到 root用户下,命令如下(node 版本 >= 16.15.1 npm + 版本 >= 8.13.2) +
  • +
+
        sudo su
+        apt-get update 
+        apt-get install nodejs npm
+
+

+
    +
  • centos 系统中使用yum安装,先切换到root用户下,命令如下:
  • +
+
        sudo su
+        sudo yum -y install nodejs npm 
+
+

+
    +
  • +

    windows系统中, 用安装包一路next即可

    +
  • +
  • +

    安装完成后运行检查是否安装成功

    +
  • +
+
        node -v
+        npm -v
+
+

+

出现版本号就代表安装成功了。

+
更换npm源
+ +
        npm config set registry http://registry.npmmirror.com
+
+
安装tsc typeScript 编译器
+ +

直接使用npm 安装运行命令。

+
        npm install -g typescript
+        tsc -v
+
+

+ 验证安装完成:
+ +

+

go 编译环境安装

+ +
    +
  • ubuntu 环境下直接使用apt安装,以root用户执行(go 版本 >= 1.13.8 )
  • +
+
        apt-get install golang-go
+
+

+
    +
  • centos系统中使用yum安装,先切换到root用户下,命令如下:
  • +
+
        sudo su
+        sudo yum -y install go 
+
+

+
    +
  • +

    + windows 系统下 从 https://golang.google.cn/dl/ 下载安装包, + 一路next 完成 安装即可 +

    +
  • +
  • +

    安装完成后 命令行运行验证是否安装成功

    +
  • +
+
        go version
+
+

项目编译

+ +

先下载sql.js的二进制包

+ +

+ 从如下 + https://github.com/sql-js/sql.js/releases/download/v1.6.2/sqljs-all.zip + 获取到sql.js的二进制包。
+ 将压缩包解压后, 将文件放置到项目third-party 目录下。 +

+

+

先编译获取trace_streamer 的二进制包

+ +

+ 参照:smartperf/trace_streamer/compile_trace_streamer.md 编译出wasm、linux、Windows版本的二进制文件。
+ 将获取到二进制文件放入到项目bin目录下,如果项目目录中无bin目录 先创建bin目录。
+ 然后将trace_streamer的二进制文件放入bin目录中。 +

+

+
+ +

+

代码编译(依赖于上面node环境 和 go环境)

+ +

在项目目录安装项目依赖:

+
        npm install
+
+

在项目目录下运行命令:

+
        npm run compile
+
+

+
+ 编译成功后会有main 可执行文件生成。 +

+

项目部署

+ +

linux版本部署需要给trace_stream程序赋予执行权限,cd dist/bin 目录下,执行如下命令:

+
        chmod +x trace_streamer_*
+
+

+

+ 直接运行 ./main 可执行程序,完成项目的部署。
+ +

+

访问项目

+

+ 在浏览器上打开 https://[部署机器ip地址]:9000/application/
+ !!! 注意一定是https。 +

+

+

+ 备注:如果未出现如图所示网页.而是显示 无法访问此网站。
+ 可以在window cmd 里执行telnet [部署机器ip地址] 9000。
+ 如果显示端口连接失败 可能是防火墙未对9000 端口放开即可。 +

+
+ + + + diff --git a/ide/src/doc/quickstart_sql_metrics.html b/ide/src/doc/quickstart_sql_metrics.html new file mode 100644 index 0000000000000000000000000000000000000000..53aec19df074bd9f53ef5f416b9767bd343b7ec5 --- /dev/null +++ b/ide/src/doc/quickstart_sql_metrics.html @@ -0,0 +1,850 @@ + + + + + quickstart_sql_metrics + + + + + + +
+

Sql分析和Metrics说明

+ +

+ Sql功能是方便使用者查询sql语句查看相关业务,Metrics是更高级别的查询接口,无需手动键入任何SQL语句,只需要选择定制好的查询接口,就能获得想要跟踪的结果。 +

+

Sql分析功能介绍

+ +

+ 点击Query(SQL),输入需要查询的sql语句,如select * from process,可以看到进程表数据。
+ GitHub Logo +

+

Metrics功能介绍

+ +

+ Metrics是更高级别的查询接口,无需手动键入任何SQL语句,只需要选择定制好的查询接口,就能获得想要跟踪的结果。 +

+

Metrics查询接口展示

+ +

+ 如下图,查询接口在下拉框中,如选择trace_task_names,点击run,就能展示线程和进程相关数据。
+ GitHub Logo +

+

Info和stats功能

+ +

+ 点击Info and stats,能查看到meta表和stats表信息。
+ GitHub Logo +

+

Download功能

+ +

+ 点击DownLoad按钮,会将在线抓取的文件下载到本地。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_systemtrace.html b/ide/src/doc/quickstart_systemtrace.html new file mode 100644 index 0000000000000000000000000000000000000000..88aa193b88535c15653b04a85e6eecdb8a909e02 --- /dev/null +++ b/ide/src/doc/quickstart_systemtrace.html @@ -0,0 +1,964 @@ + + + + + quickstart_systemtrace + + + + + + +
+

web端加载trace说明

+ +

从web端查看trace文件,进行性能检测的分析。

+

文件加载入口

+ +

+ 将抓取的trace导入查看。
+ GitHub Logo +

+

说明:

+
    +
  • Open trace file:导入离线trace文件入口。
  • +
  • Record new trace:抓取新的trace文件入口。
  • +
+

导入trace文件后显示页面

+ +

+ GitHub Logo
+ 说明: +

+
    +
  • + 操作说明:在当前页面可以通过键盘上的wasd四个键位操纵当前的时间轴进行缩放,w为放大,s为缩小,a为左移,d为右移。 +
  • +
+

trace功能介绍

+ +

+ trace模块从上往下主要展示时间轴、cpu使用率、cpu使用情况、进程间通讯数据的方法调用情况、进程、线程和方法调用情况。 +

+

时间轴和cpu使用率

+ +

+ GitHub Logo
+ 最上方带刻度的为时间轴,主要展示当前抓取数据的总时长和时间刻度的分布情况,如上图所示,左下角展示总时长。
+ 中间区域展示的是抓取数据时间段内的cpu使用率,颜色越深代表cpu使用率越高,颜色越浅代表cpu使用率越低。
+ GitHub Logo
+ 在白色背景时间轴区域内可以点击后拖拽鼠标,可以对从鼠标按下到拖拽完成鼠标松开的区域内的数据进行筛选,高亮显示的部分为当前所选区域,如上图所示。 +

+

cpu使用情况

+ +

GitHub Logo

+

+ 如上图所示,当前抓取数据有4个cpu工作,前四组数据对应的是当前调用cpu的线程和对应的进程情况,以颜色作为区分。后四组数据则为cpu的使用频率信息。鼠标移动到相应的线程上还会将当前选中的进程信息全部置为高亮,其他的进程会置灰,如下图所示。
+ GitHub Logo +

+

cpu使用情况的框选功能

+ +

+ 可以对cpu的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,总共有七个tab页。
+ CPU by + thread的Tab页,主要显示了在框选时间区间内的进程名、进程号、线程名、线程号、总运行时长、平均运行时长和调度次数信息。
+ GitHub Logo
+ CPU by process的Tab页,主要显示了在框选时间区间内的进程名、进程号、总运行时长、平均运行时长和调度次数信息。
+ GitHub Logo
+ CPU Usage的Tab页,主要显示了在框选时间区间内,该频率时间占比前三的信息。
+ GitHub Logo
+ States + List的Tab页,按状态>进程>线程的维度去统计,需要呈现该状态的线程名、该状态次数、该状态下时长、最大最小时长、平均时长、最大时长。
+ GitHub Logo
+ Switches List的Tab页,按照进程>线程>状态,统计对应状态下的次数。
+ GitHub Logo
+ Thread + States的Tab页,按进程>线程>状态的维度去统计,需要呈现该状态的线程名、进入该状态次数、该状态下时长、最小时长、平均时长、最大时长。
+ GitHub Logo
+ Thread Switches的Tab页,按照状态>进程>线程,统计对应状态下的次数。
+ GitHub Logo
+ States List、Switches List、Thread States、Thread + Switches的4个Tab页,点击移动到某一行,鼠标会变成一个小手的标志,点击一下,就会进入辅助信息界面,会将选中行的辅助信息展示出来,包括开始时间、进程、线程、线程状态、对应的CPU、优先级等信息如下图。
+ GitHub Logo +

+

cpu使用情况的单选功能

+ +

+ 单选CPU使用情况数据会在选中的色块外层加上深色边框,能够突出当前选中色块,弹出层中会展示当前CPU上的进程名,线程名,开始时间和运行时长,线程运行状态等信息。
+ GitHub Logo +

+

进程、线程和方法数据

+ +

+ 下图是进程数据,左边部分展示进程名称和id,右边显示线程切换关系,线程的调用方法,进程间内存信息等。
+ GitHub Logo
+ 点击进程名前面向下箭头可以展开对应的线程进行查看,展开后的线程如下图,如果存在堆内存占用情况,就会显示在第一行,如果出现两个名字和id一样的线程,则第一个为线程的使用情况,第二为线程内的方法栈调用情况。
+ GitHub Logo +

+

进程、线程和方法数据的框选功能

+ +

+ 可以对线程的数据进行框选,框选后在最下方的弹出层中会展示框选数据的统计表格,包含线程运行状态,线程调用栈的统计情况。当框选的数据中同时存在线程运行状态和线程调用栈数据,下方的弹出层中就会出现多个tab选项,可以进行切换。 +

+

+ 下图是线程运行状态框选统计信息,包括进程名、进程号、线程名、线程号、线程状态、状态持续时间、平均持续时间、该线程状态发生的次数。
+ GitHub Logo +

+

+ 下图是线程调用栈框选统计信息,包括方法名、持续时间、平均持续时间、调用的次数。
+ GitHub Logo +

+

进程、线程和方法数据的单选功能

+ +

+ 单选线程的state数据时,会展示当前选中线程的状态数据,开始时间和持续时长,线程状态,所在进程名称。
+ GitHub Logo
+ 单选调用栈数据,单击方法会在选中的方法外层加上黑色边框,能够突出当前选中的方法,弹出层中会展示当前方法的名称、开始时间和运行时长信息。
+ GitHub Logo +

+

线程的跳转功能

+ +

+ 点击画红框处的带箭头的标志,会从CPU的线程概览视图跳转到线程的详情视图,同时从线程的详情视图也能跳转到CPU的线程概览视图。
+ GitHub Logo +

+

trace的其他功能

+ +

小旗标志的功能

+ +

+ 将选中数据的时间点通过小旗的方式在时间轴上展示,直观的展示选中数据的时间。
+ GitHub Logo
+ 在下方输入空输入文字:我是trace,可以给小旗打备注。
+ GitHub Logo +

+

收藏置顶功能

+ +

+ 鼠标移动到某个页签,会出现星形的标志,点击该星形,可以将该行收藏置顶。
+ GitHub Logo +

+

勾选功能

+ +

+ 框选某一区域,该区域左边会出现CheckBox的复选框,选中的区域的复选框会出现打勾的状态,可以取消勾选,也可以重新勾选。
+ GitHub Logo +

+

搜索功能

+ +

+ 在搜索框中,可以输入线程,线程号等搜索自己想要的信息,搜索完成会高亮显示。
+ GitHub Logo
+ 在搜索框中输入调用栈的方法名,会跳转到对应的调用栈。
+ GitHub Logo +

+

M键测量功能

+ +

+ 放大trace中的色块,选中色块,键盘按下M,会出现像尺子一样的形状。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/doc/quickstart_trace_streamer.html b/ide/src/doc/quickstart_trace_streamer.html new file mode 100644 index 0000000000000000000000000000000000000000..06b98bcdcda5c33fbd36d795269c9d9c66b02347 --- /dev/null +++ b/ide/src/doc/quickstart_trace_streamer.html @@ -0,0 +1,898 @@ + + + + quickstart_trace_streamer + + + + + + +
+

trace_streamer工具说明

+

trace_streamer是一个trace数据流转化器,可以将一个trace文本文件或者基于proto序列化的二进制文件转换成为sqlite数据库的形式。 trace_streamer使用C++实现,支持在ohos, linux, mac等系统上使用,具有良好的跨平台特性。

+ GitHub Logo

+

+ 关于trace解析工具的使用说明:

+

trace_streamer工具可以2种方式使用

+
    +
  1. 可以将系统离线trace文件解析并转为db,此工具支持基于文本的trace和基于proto的trace。
  2. +
  3. trace_streamer工具还可以WebAssembly的方式在浏览器中运行,需暴露相关接口给js文件。
  4. +
+ +

+ 导出db模式

+ +

在导出db模式下,trace_streamer.exe trace文件路径名 -e 导出db路径名.db
+ 此命令可以将trace文件转为db
+ 本应用支持在ohos, linux, windows, mac使用。
+ 关于db文件的说明:
+ 使用db查看工具查看stat表,可以浏览当前数据一共有多少类数据,各类数据都收到多少条,数据是否正常等情况。在meta表会记录数据库导出时的一些系统信息,比如导入和导出的文件全路径,解析时间等信息。
+ meta表可以选择不导出(有些情况下会暴露系统敏感信息),在导出时添加 -nm选项即可。
+ 在数据导出之后,会在本地目录下生成一个trace_streamer.log文件,在导出db的目录下生成一个数据库文件同名,.db.ohos.ts后缀的文件
+ 文件内容如下:
+ 时间戳:执行结果(数字)
+ 应用运行时间

+

执行结果解释如下:0 代表执行成功 1 表示输入文件不匹配, 2 表示解析错误, 3其他错误

+

内置浏览器方式

+ +

trace_streamer可以WebAssembly方式在浏览器中运行,暴露如下接口给js

+
extern "C" {
+/* 上传trace数据
+ *
+ * @data: 数据的缓冲区
+ * @dataLen: 数据长度
+ *
+ * return: 0:成功; -1:失败
+*/
+EMSCRIPTEN_KEEPALIVE int TraceStreamerParseData(const uint8_t* data, int dataLen);
+
+/* 通知TS上传trace数据结束
+ *
+ * return: 0:成功; -1:失败
+*/
+EMSCRIPTEN_KEEPALIVE int TraceStreamerParseDataOver();
+
+/* 通过sql语句操作数据库
+ *
+ * @sql: sql语句
+ * @sqlLen: sql语句长度
+ *
+ * return: 0:成功; -1:失败
+*/
+EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlOperate(const uint8_t* sql, int sqlLen);
+
+/* 通过sql语句查询数据库
+ *
+ * @sql: sql语句
+ * @sqlLen: sql语句长度
+ * @out: 查询结果的缓冲区,查询结果为json
+ * @outLen: 缓冲区长度
+ *
+ * return: >0:查询成功,返回查询结果数据长度; -1:失败
+*/
+EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlQuery(const uint8_t* sql, int sqlLen, uint8_t* out, int outLen);
+
+} // extern "C"
+
+

+ 你也可以执行如下命令查看应用帮助

+ +

./trace_streamer --help
+ -i 选项可查看应用支持的事件源和具体的事件名列表 +

+

trace_streamer支持解析的事件列表

+

支持的事件列表参见<<SupportEventList.md>>

+

TraceStreamer重要概念介绍

+ +

1. 进程和线程标识符

+ +
 在通用操作系统中,进程号(pid/tgid)和线程号(tid)可能会被重复用于标识不同的进程或者线程。所以在trace数据源中,进程号(pid)和线程号(tid)也可能被重用。
+TraceStreamer在解析数据过程中,使用ipid(internal pid)唯一标识进程, itid(internal tid)唯一标识线程。
+

2. 计量器

+ +

用来记录系统中各种随时间连续变化的数值。例如: CPU的频率, 内存的使用量, 界面刷新频率。

+

举例

+ +

CPU频率:
+ GitHub Logo
+ 内存占用:
+ GitHub Logo

+

3. 过滤器

+ +

TraceStreamer设计过程中使用了流式处理的思想,数据从入口进入以后,就像进入一条河流,从上游流向下游,在河道中央有很多过滤器,每种过滤器会将流过的数据中自己关注的内容吸附捕捉到。最终,每个过滤器都拥有了大量同类型的数据,而且这些数据都是按时间序列排列的。TraceStreamer使用filterid来标识同一种用途的数据,可以方便在UI中绘制。
+ ![image][filterimageid]

+

Stat表设计

+ +

具体内容参见 des_stat

+

trace_streamer开发环境搭建和编译运行指引

+ +

本应用使用gn作为构建工具。

+

1、开发环境

+ +

ubuntu和mac使用vscode

+

对外部的依赖

+ +

本应用依赖与sqlite,protobuf(htrace解析部分依赖)

+

本应用同时依赖于src/protos目录下文件来生成相关pb.h,pb.cc文件

+

2.1、 编译linux和Mac版应用

+ +

在根目录下执行相关命令进行编译

+

2.2、 编译wasm

+ +

在根目录下执行相关命令进行编译

+

2.3、开始编译

+ +

具体方法可参考compile_trace_streamer

+ + +
+ + + \ No newline at end of file diff --git a/ide/src/doc/quickstart_web_record.html b/ide/src/doc/quickstart_web_record.html new file mode 100644 index 0000000000000000000000000000000000000000..3ac9c612bafac2a922013cd356bf41af89edba5a --- /dev/null +++ b/ide/src/doc/quickstart_web_record.html @@ -0,0 +1,867 @@ + + + + + quickstart_web_record + + + + + + +
+

web端抓取trace说明

+ +

从web端抓取trace文件的配置和方法。

+

界面配置说明

+ +

+ GitHub Logo
+ 说明: +

+
    +
  • Record:trace抓取按钮。
  • +
  • Add HDC Device:连接设备。
  • +
+

trace文件的在线抓取

+ +

+ 点击Add HDC Device在弹出的框里选择HDC-配对,点击连接,连接设备。
+ GitHub Logo
+ 点击Probes config,如选择抓取Scheduling details。
+ GitHub Logo
+ 抓取项说明: +

+
    +
  • + Scheduling + details:线程切换事件,暂停恢复方法,线程唤醒事件,进程退出和销毁处理,新建线程处理方法,线程重命名处理方法。 +
  • +
  • CPU Frequency and idle states:CPU频率信息和CPU空闲状态。
  • +
  • + Advanced ftrace + config:线程切换事件,暂停恢复方法,线程唤醒事件,进程退出和销毁处理,新建线程处理方法,线程重命名处理方法,IRQ事件,时钟频率处理方法,Binder事件,线程调用堆栈开始和结束的处理。 +
  • +
  • AbilityMonitor:进程的CPU,内存,磁盘,网络使用情况。
  • +
  • Kernel meminfo:内核内存。
  • +
  • Virtual memory stats:系统虚拟内存。
  • +
  • + Hitrace categories:Bytrace的抓取项,各解释项说明如下图:
    + GitHub Logo +
  • +
+

+ 再点击Record setting,在output file path输入文件名hiprofiler_data_example.htrace,拖动滚动条设置buffer + size大小是64M,抓取时长是50s。
+ GitHub Logo
+ 点击Trace command,就会根据上面的配置生成抓取命令,点击Record。
+ GitHub Logo
+ 抓取过程中,上方会给出提示正在抓取,并显示出抓取时长。
+ GitHub Logo
+ 抓取完成后,界面会自动加载展示trace文件。
+ GitHub Logo +

+
+ + + + diff --git a/ide/src/figures/AbilityMonitor/ProcessesHistory.jpg b/ide/src/figures/AbilityMonitor/ProcessesHistory.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59ddc205b3b4ca3fa6ee13342c2e251494677896 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/ProcessesHistory.jpg differ diff --git a/ide/src/figures/AbilityMonitor/abilitycommand.jpg b/ide/src/figures/AbilityMonitor/abilitycommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1aa5372774340e5228fefd5b1c36bafd2a7bd02 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/abilitycommand.jpg differ diff --git a/ide/src/figures/AbilityMonitor/abilityexcutecommand.jpg b/ide/src/figures/AbilityMonitor/abilityexcutecommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d9a4fe8ad1cb51d711cb6e681863f8bf81d12878 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/abilityexcutecommand.jpg differ diff --git a/ide/src/figures/AbilityMonitor/abilityhtrace.jpg b/ide/src/figures/AbilityMonitor/abilityhtrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..51ca07880e200c51453d22fc52120f3e9c1b02cd Binary files /dev/null and b/ide/src/figures/AbilityMonitor/abilityhtrace.jpg differ diff --git a/ide/src/figures/AbilityMonitor/abilitymonitorflowchart.jpg b/ide/src/figures/AbilityMonitor/abilitymonitorflowchart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..15c86a5b816003dbb850e203794d3ee8c7a0c2f7 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/abilitymonitorflowchart.jpg differ diff --git a/ide/src/figures/AbilityMonitor/abilityset.jpg b/ide/src/figures/AbilityMonitor/abilityset.jpg new file mode 100644 index 0000000000000000000000000000000000000000..32c6a705d6934772354329bf17dcec883f5d5696 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/abilityset.jpg differ diff --git a/ide/src/figures/AbilityMonitor/abilitysetting.jpg b/ide/src/figures/AbilityMonitor/abilitysetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b10a98900ad422fe742481425f99b9e52f32fc5 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/abilitysetting.jpg differ diff --git a/ide/src/figures/AbilityMonitor/cpusummary.jpg b/ide/src/figures/AbilityMonitor/cpusummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83b2fcac39d8e119c502275efed6a40af9c7f2c4 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/cpusummary.jpg differ diff --git a/ide/src/figures/AbilityMonitor/disktab.jpg b/ide/src/figures/AbilityMonitor/disktab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4eaa9d89a260542ae24354db834b695b7b47971c Binary files /dev/null and b/ide/src/figures/AbilityMonitor/disktab.jpg differ diff --git a/ide/src/figures/AbilityMonitor/liveprocess.jpg b/ide/src/figures/AbilityMonitor/liveprocess.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2088ba7ab29c07f105ed62df4a6226244326f34d Binary files /dev/null and b/ide/src/figures/AbilityMonitor/liveprocess.jpg differ diff --git a/ide/src/figures/AbilityMonitor/memorytab.jpg b/ide/src/figures/AbilityMonitor/memorytab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76849b0b19d38d67efb563ac7fb04c5fc6e8b487 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/memorytab.jpg differ diff --git a/ide/src/figures/AbilityMonitor/network.jpg b/ide/src/figures/AbilityMonitor/network.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a928cf3ad96b3d0701dbe79013d48792b360f172 Binary files /dev/null and b/ide/src/figures/AbilityMonitor/network.jpg differ diff --git a/ide/src/figures/Bio/BioCalltree.jpg b/ide/src/figures/Bio/BioCalltree.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ee3f25ddb028fbda43662b7baf976fc990407de8 Binary files /dev/null and b/ide/src/figures/Bio/BioCalltree.jpg differ diff --git a/ide/src/figures/Bio/BioOptions.jpg b/ide/src/figures/Bio/BioOptions.jpg new file mode 100644 index 0000000000000000000000000000000000000000..80dd5a57e9f373cccf373c6b7fda9c3fc513ff15 Binary files /dev/null and b/ide/src/figures/Bio/BioOptions.jpg differ diff --git a/ide/src/figures/Bio/Biochart.jpg b/ide/src/figures/Bio/Biochart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b5451727c787f29b45ac8a4aad974b9062b30925 Binary files /dev/null and b/ide/src/figures/Bio/Biochart.jpg differ diff --git a/ide/src/figures/Bio/Biocounter.jpg b/ide/src/figures/Bio/Biocounter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2eedd02185175fe09cd6c180fc3af8777aeb283 Binary files /dev/null and b/ide/src/figures/Bio/Biocounter.jpg differ diff --git a/ide/src/figures/Bio/Biodatamining.jpg b/ide/src/figures/Bio/Biodatamining.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abc7a5dd5bc29966d066e8dacca88f0c6a974948 Binary files /dev/null and b/ide/src/figures/Bio/Biodatamining.jpg differ diff --git a/ide/src/figures/Bio/Bioexcuting.jpg b/ide/src/figures/Bio/Bioexcuting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea6bef53925ca569c5847c938ca561e6478009f2 Binary files /dev/null and b/ide/src/figures/Bio/Bioexcuting.jpg differ diff --git a/ide/src/figures/Bio/Biofilter.jpg b/ide/src/figures/Bio/Biofilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..851944c928003870a4693ecae15d08c30c17c50c Binary files /dev/null and b/ide/src/figures/Bio/Biofilter.jpg differ diff --git a/ide/src/figures/Bio/Bioflame.jpg b/ide/src/figures/Bio/Bioflame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..592e6b343243a00ecdefc4aef63b7c6e5d5bc51b Binary files /dev/null and b/ide/src/figures/Bio/Bioflame.jpg differ diff --git a/ide/src/figures/Bio/Bioflamelevel.jpg b/ide/src/figures/Bio/Bioflamelevel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..78d2f14c2ca40f20a231c7dc060a667f08356914 Binary files /dev/null and b/ide/src/figures/Bio/Bioflamelevel.jpg differ diff --git a/ide/src/figures/Bio/Bioflameshow.jpg b/ide/src/figures/Bio/Bioflameshow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7e8f9974ee4a6131e87f2164dde82009e2cf0a9 Binary files /dev/null and b/ide/src/figures/Bio/Bioflameshow.jpg differ diff --git a/ide/src/figures/Bio/Bioheaviesttrace.jpg b/ide/src/figures/Bio/Bioheaviesttrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e76b66303697967022de21c22e4b7bad1f2e1c93 Binary files /dev/null and b/ide/src/figures/Bio/Bioheaviesttrace.jpg differ diff --git a/ide/src/figures/Bio/Bioinputfilter.jpg b/ide/src/figures/Bio/Bioinputfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d6e6b1a8b250e0eb01b5ba7882d2a0da8f00cc5 Binary files /dev/null and b/ide/src/figures/Bio/Bioinputfilter.jpg differ diff --git a/ide/src/figures/Bio/Biorecord.jpg b/ide/src/figures/Bio/Biorecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d4aed0679233db239eb1b34cb06759d88d500399 Binary files /dev/null and b/ide/src/figures/Bio/Biorecord.jpg differ diff --git a/ide/src/figures/Bio/Biosetting.jpg b/ide/src/figures/Bio/Biosetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cba0d83665357941db514293f73bc8721da96394 Binary files /dev/null and b/ide/src/figures/Bio/Biosetting.jpg differ diff --git a/ide/src/figures/Bio/Biostatistics.jpg b/ide/src/figures/Bio/Biostatistics.jpg new file mode 100644 index 0000000000000000000000000000000000000000..259a9bc8f77c6db6f5516b57b60ed27915406ff5 Binary files /dev/null and b/ide/src/figures/Bio/Biostatistics.jpg differ diff --git a/ide/src/figures/Bio/Biosummary.jpg b/ide/src/figures/Bio/Biosummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d102cd8d03af610d7fa905664401df8334cb539 Binary files /dev/null and b/ide/src/figures/Bio/Biosummary.jpg differ diff --git a/ide/src/figures/Bio/Biotimes.jpg b/ide/src/figures/Bio/Biotimes.jpg new file mode 100644 index 0000000000000000000000000000000000000000..60cd75aca70a6d55a66a26f9bd766fbefe7c6f33 Binary files /dev/null and b/ide/src/figures/Bio/Biotimes.jpg differ diff --git a/ide/src/figures/EBPF/EBPFchart.jpg b/ide/src/figures/EBPF/EBPFchart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..896abef911d44c977136f147226e4d49ff938593 Binary files /dev/null and b/ide/src/figures/EBPF/EBPFchart.jpg differ diff --git a/ide/src/figures/EBPF/EBPFcount.jpg b/ide/src/figures/EBPF/EBPFcount.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f25d8077bd11a1d541710f4babdd5ed0cb60295c Binary files /dev/null and b/ide/src/figures/EBPF/EBPFcount.jpg differ diff --git a/ide/src/figures/EBPF/VMCalltree.jpg b/ide/src/figures/EBPF/VMCalltree.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8bcf0dbd3231bb8f62186234ac33ba31c36cb90 Binary files /dev/null and b/ide/src/figures/EBPF/VMCalltree.jpg differ diff --git a/ide/src/figures/EBPF/VMEvents.jpg b/ide/src/figures/EBPF/VMEvents.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f719806a770a36ee063376b623639753ece6234a Binary files /dev/null and b/ide/src/figures/EBPF/VMEvents.jpg differ diff --git a/ide/src/figures/EBPF/VMfilter.jpg b/ide/src/figures/EBPF/VMfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ac44d11f7861b8b180b0dbafce04279ef1ac89a Binary files /dev/null and b/ide/src/figures/EBPF/VMfilter.jpg differ diff --git a/ide/src/figures/EBPF/ebpf_bythread.jpg b/ide/src/figures/EBPF/ebpf_bythread.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bac0e25fa0bc771e1e3f5f8e531742b2cffde100 Binary files /dev/null and b/ide/src/figures/EBPF/ebpf_bythread.jpg differ diff --git a/ide/src/figures/EBPF/ebpfcommand.jpg b/ide/src/figures/EBPF/ebpfcommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2af7869dba909de20ea57959bddce15a53f3d572 Binary files /dev/null and b/ide/src/figures/EBPF/ebpfcommand.jpg differ diff --git a/ide/src/figures/EBPF/ebpfexcuting.jpg b/ide/src/figures/EBPF/ebpfexcuting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54b3afd3e2410f60df2c2bd79490d7bc88a902f8 Binary files /dev/null and b/ide/src/figures/EBPF/ebpfexcuting.jpg differ diff --git a/ide/src/figures/EBPF/ebpfrecord.jpg b/ide/src/figures/EBPF/ebpfrecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706f7b8271eb363eeb2c93cc2be677176a21b32e Binary files /dev/null and b/ide/src/figures/EBPF/ebpfrecord.jpg differ diff --git a/ide/src/figures/EBPF/ebpfsetting.jpg b/ide/src/figures/EBPF/ebpfsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fa0686632e1b10c31fde5f1fb376c828a2c2ef76 Binary files /dev/null and b/ide/src/figures/EBPF/ebpfsetting.jpg differ diff --git a/ide/src/figures/EBPF/ebpfsummary.jpg b/ide/src/figures/EBPF/ebpfsummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db5ddf667e1a0306d04dc55a004edfc92205fa42 Binary files /dev/null and b/ide/src/figures/EBPF/ebpfsummary.jpg differ diff --git a/ide/src/figures/EBPF/vmOptions.jpg b/ide/src/figures/EBPF/vmOptions.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9882c3cd4fd07bc256f76dc9d56a8df7cd3d6493 Binary files /dev/null and b/ide/src/figures/EBPF/vmOptions.jpg differ diff --git a/ide/src/figures/EBPF/vmcounter.jpg b/ide/src/figures/EBPF/vmcounter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..40119bd7d2daa113ff2fa2b798f12e5a2cf7d58a Binary files /dev/null and b/ide/src/figures/EBPF/vmcounter.jpg differ diff --git a/ide/src/figures/EBPF/vmdatamining.jpg b/ide/src/figures/EBPF/vmdatamining.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b2417582bf55e1352cb568438580d9cabce0d03 Binary files /dev/null and b/ide/src/figures/EBPF/vmdatamining.jpg differ diff --git a/ide/src/figures/EBPF/vmflame.jpg b/ide/src/figures/EBPF/vmflame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6681178216885068aa3e5d0a9987013746b91e5d Binary files /dev/null and b/ide/src/figures/EBPF/vmflame.jpg differ diff --git a/ide/src/figures/EBPF/vmflamelevel.jpg b/ide/src/figures/EBPF/vmflamelevel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37b9b4f64420deeca9f587483e8ff4efffa5dd0f Binary files /dev/null and b/ide/src/figures/EBPF/vmflamelevel.jpg differ diff --git a/ide/src/figures/EBPF/vmflameshow.jpg b/ide/src/figures/EBPF/vmflameshow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9cef6d91b3affcc951cbe090c5476e7c364aa6a Binary files /dev/null and b/ide/src/figures/EBPF/vmflameshow.jpg differ diff --git a/ide/src/figures/EBPF/vmheaviesttrace.jpg b/ide/src/figures/EBPF/vmheaviesttrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abb016ba8164506fc0a4b8b01889b052fbce5342 Binary files /dev/null and b/ide/src/figures/EBPF/vmheaviesttrace.jpg differ diff --git a/ide/src/figures/EBPF/vminputfilter.jpg b/ide/src/figures/EBPF/vminputfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..726051576941b38419465d02d72069c1f9de71c1 Binary files /dev/null and b/ide/src/figures/EBPF/vminputfilter.jpg differ diff --git a/ide/src/figures/EBPF/vmstatistics.jpg b/ide/src/figures/EBPF/vmstatistics.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f056cd5a267f550870943f079bdcbb717b957c6b Binary files /dev/null and b/ide/src/figures/EBPF/vmstatistics.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemCalltree.jpg b/ide/src/figures/FileSystem/FileSystemCalltree.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e7e2de008c1e5d6b670e9d6109292fc1a21e10e Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemCalltree.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemOptions.jpg b/ide/src/figures/FileSystem/FileSystemOptions.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b5ce7a6a6816502550c40d7e5237a8bd088233d0 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemOptions.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemchart.jpg b/ide/src/figures/FileSystem/FileSystemchart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77ee172cf174350a55027c91ccc8f76b06596ad5 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemchart.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemcommand.jpg b/ide/src/figures/FileSystem/FileSystemcommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4f8a671ee41b3205c84ae4d932f3e10a72edd888 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemcommand.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemcount.jpg b/ide/src/figures/FileSystem/FileSystemcount.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c049c9b564b301f5b28820bf748dc9831a29bb7 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemcount.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemdatamining.jpg b/ide/src/figures/FileSystem/FileSystemdatamining.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dbcd816b0ac0db534f97f05d263e8aca4db12019 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemdatamining.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemevents.jpg b/ide/src/figures/FileSystem/FileSystemevents.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5914209c0352e4cb950f361af79fa2395fe9508f Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemevents.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemexcutecommand.jpg b/ide/src/figures/FileSystem/FileSystemexcutecommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abd178fdab114642fcde657a497dc97a3f0804ec Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemexcutecommand.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemfile.jpg b/ide/src/figures/FileSystem/FileSystemfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..536595781f01a39a41079c141439e0989bd6ca3b Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemfile.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemflame.jpg b/ide/src/figures/FileSystem/FileSystemflame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d644c143e7a782d2a7e03708a589c2bc701d92d5 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemflame.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemflamelevel.jpg b/ide/src/figures/FileSystem/FileSystemflamelevel.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2cff0eeb107da9e4155944eca57590011ed8b34e Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemflamelevel.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemflameshow.jpg b/ide/src/figures/FileSystem/FileSystemflameshow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b03f7b31ca17606e26768406a0effab4a3ec5cee Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemflameshow.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemheaviesttrace.jpg b/ide/src/figures/FileSystem/FileSystemheaviesttrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2644870c90be8fcaa7a8ecc370a35faacdee2534 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemheaviesttrace.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemhistory.jpg b/ide/src/figures/FileSystem/FileSystemhistory.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2cf792ddc44796d32114a4be2c4463c192a74b3e Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemhistory.jpg differ diff --git a/ide/src/figures/FileSystem/FileSysteminputfilter.jpg b/ide/src/figures/FileSystem/FileSysteminputfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec0965db18378980c4f63be7a812a19ded10aaa9 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSysteminputfilter.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemsamplecounter.jpg b/ide/src/figures/FileSystem/FileSystemsamplecounter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..666200868fce4b88495e1f3a95741ee84cf11ade Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemsamplecounter.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemstatistics.jpg b/ide/src/figures/FileSystem/FileSystemstatistics.jpg new file mode 100644 index 0000000000000000000000000000000000000000..86e2838c35e8c44dd740ce0c3847ab8aea873bac Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemstatistics.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemsummary.jpg b/ide/src/figures/FileSystem/FileSystemsummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2e201cc6dca939ff309c5aca740bca190c07dd0 Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemsummary.jpg differ diff --git a/ide/src/figures/FileSystem/FileSystemtimeslice.jpg b/ide/src/figures/FileSystem/FileSystemtimeslice.jpg new file mode 100644 index 0000000000000000000000000000000000000000..570ada550e41b1850a01c55cc51444f2be922b2c Binary files /dev/null and b/ide/src/figures/FileSystem/FileSystemtimeslice.jpg differ diff --git a/ide/src/figures/FileSystem/filesystemfilter.jpg b/ide/src/figures/FileSystem/filesystemfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..39bffd42a0f6c667ad1aad05ee27b31c2782fa9b Binary files /dev/null and b/ide/src/figures/FileSystem/filesystemfilter.jpg differ diff --git a/ide/src/figures/FileSystem/filesystemrecord.jpg b/ide/src/figures/FileSystem/filesystemrecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f6130bb8c8c222bbd58b40d8a562575c07e1270e Binary files /dev/null and b/ide/src/figures/FileSystem/filesystemrecord.jpg differ diff --git a/ide/src/figures/FileSystem/filesystemsetting.jpg b/ide/src/figures/FileSystem/filesystemsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..37cd13fb6f367ed56aa296e484f3dc576627e93f Binary files /dev/null and b/ide/src/figures/FileSystem/filesystemsetting.jpg differ diff --git a/ide/src/figures/Frame/frameactualtab.jpg b/ide/src/figures/Frame/frameactualtab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4908b93cedb7d540ebd765001397ef5b2a1314d Binary files /dev/null and b/ide/src/figures/Frame/frameactualtab.jpg differ diff --git a/ide/src/figures/Frame/framechart.jpg b/ide/src/figures/Frame/framechart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7beeb525e7d1d845fd8024f05b81adedc456e2f8 Binary files /dev/null and b/ide/src/figures/Frame/framechart.jpg differ diff --git a/ide/src/figures/Frame/frameexcuting.jpg b/ide/src/figures/Frame/frameexcuting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..974298855444d6fc09223dcdbfb9c83b6e32154a Binary files /dev/null and b/ide/src/figures/Frame/frameexcuting.jpg differ diff --git a/ide/src/figures/Frame/frameexpectedtab.jpg b/ide/src/figures/Frame/frameexpectedtab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48ac72025806ee24abd83717286f5683ba021ebc Binary files /dev/null and b/ide/src/figures/Frame/frameexpectedtab.jpg differ diff --git a/ide/src/figures/Frame/frameprocess.jpg b/ide/src/figures/Frame/frameprocess.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d08141342088e7691e20ca635c1aea619c81645c Binary files /dev/null and b/ide/src/figures/Frame/frameprocess.jpg differ diff --git a/ide/src/figures/Frame/frameset.jpg b/ide/src/figures/Frame/frameset.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ef19dc8a8862f640a6bf2d63824a20dcd9dc6c0d Binary files /dev/null and b/ide/src/figures/Frame/frameset.jpg differ diff --git a/ide/src/figures/Frame/framesetting.jpg b/ide/src/figures/Frame/framesetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..11b9586f41f8ed200522becc352c02a60477f89d Binary files /dev/null and b/ide/src/figures/Frame/framesetting.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisyseventPowerBattery.jpg b/ide/src/figures/HiSystemEvent/hisyseventPowerBattery.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b38ed1956188e99d96eaa35c414ba04d66ebd843 Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisyseventPowerBattery.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisyseventPowerdetails.jpg b/ide/src/figures/HiSystemEvent/hisyseventPowerdetails.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ce1e9af717655d732a90fe086f04a9734e1e7cbf Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisyseventPowerdetails.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisyseventsetting.jpg b/ide/src/figures/HiSystemEvent/hisyseventsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f97ec6bf7f25b09a8ee5e2b255fa836be120684d Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisyseventsetting.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisystemcommand.jpg b/ide/src/figures/HiSystemEvent/hisystemcommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a213fb514968fc44ec993d6af4c5a15712d59141 Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisystemcommand.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisystemdetails.jpg b/ide/src/figures/HiSystemEvent/hisystemdetails.jpg new file mode 100644 index 0000000000000000000000000000000000000000..92e88f53834cf64559ad1841ac7f797574e5b114 Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisystemdetails.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisystemeventemexcute.jpg b/ide/src/figures/HiSystemEvent/hisystemeventemexcute.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6117dd7150004449c56d227b28b4ce33b1a5c0cd Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisystemeventemexcute.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisystemeventfile.jpg b/ide/src/figures/HiSystemEvent/hisystemeventfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df88e858a69ecf2e4a9a9f3f85bd8c71c0f750a3 Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisystemeventfile.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisystemeventrecord.jpg b/ide/src/figures/HiSystemEvent/hisystemeventrecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8ef5587d40bf09e2325f5d696cd9761380ca21e5 Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisystemeventrecord.jpg differ diff --git a/ide/src/figures/HiSystemEvent/hisystemeventsummary.jpg b/ide/src/figures/HiSystemEvent/hisystemeventsummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ce9654a92bd2e8564023b4fdeea4c711ec3e976c Binary files /dev/null and b/ide/src/figures/HiSystemEvent/hisystemeventsummary.jpg differ diff --git a/ide/src/figures/HiSystemEvent/systemselectdetals.jpg b/ide/src/figures/HiSystemEvent/systemselectdetals.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65fee85ce45ea6ebcfbd57bdd2e2b5001ad73365 Binary files /dev/null and b/ide/src/figures/HiSystemEvent/systemselectdetals.jpg differ diff --git a/ide/src/figures/Jsmemory/JsComparison.jpg b/ide/src/figures/Jsmemory/JsComparison.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f04b4416d8c23553ab2bd489c030a35c81e8e079 Binary files /dev/null and b/ide/src/figures/Jsmemory/JsComparison.jpg differ diff --git a/ide/src/figures/Jsmemory/JsSummary.jpg b/ide/src/figures/Jsmemory/JsSummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..80e207d62b606f12afb24ecdd38d1178edeee926 Binary files /dev/null and b/ide/src/figures/Jsmemory/JsSummary.jpg differ diff --git a/ide/src/figures/Jsmemory/Jsmemoryfilter.jpg b/ide/src/figures/Jsmemory/Jsmemoryfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..55186bb215af8456cd63ec68a8d647486fe579dd Binary files /dev/null and b/ide/src/figures/Jsmemory/Jsmemoryfilter.jpg differ diff --git a/ide/src/figures/Jsmemory/jsmemorycallstack.jpg b/ide/src/figures/Jsmemory/jsmemorycallstack.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3dde152e64ac645af49cf593dabd55ce1f65a15b Binary files /dev/null and b/ide/src/figures/Jsmemory/jsmemorycallstack.jpg differ diff --git a/ide/src/figures/Jsmemory/jsmemoryrecord.jpg b/ide/src/figures/Jsmemory/jsmemoryrecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..90c0525bcb7acfa53dab7718dc5216736b03eacf Binary files /dev/null and b/ide/src/figures/Jsmemory/jsmemoryrecord.jpg differ diff --git a/ide/src/figures/Jsmemory/jsmemoryset.jpg b/ide/src/figures/Jsmemory/jsmemoryset.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad353a41ebd9148ecade30f0e4d087086fa96128 Binary files /dev/null and b/ide/src/figures/Jsmemory/jsmemoryset.jpg differ diff --git a/ide/src/figures/Jsmemory/jsmemorysetting.jpg b/ide/src/figures/Jsmemory/jsmemorysetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eaaab9d3b8fadbef4a4911f01513116da6041047 Binary files /dev/null and b/ide/src/figures/Jsmemory/jsmemorysetting.jpg differ diff --git a/ide/src/figures/Jsmemory/jsnapshotChart.jpg b/ide/src/figures/Jsmemory/jsnapshotChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dc4ec9db75843e84d52ca77228756d3e9cfb7c25 Binary files /dev/null and b/ide/src/figures/Jsmemory/jsnapshotChart.jpg differ diff --git a/ide/src/figures/Jsmemory/jstimelineChart.jpg b/ide/src/figures/Jsmemory/jstimelineChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b5b3642d334a9eda2d4c6532be948f1abd633e8 Binary files /dev/null and b/ide/src/figures/Jsmemory/jstimelineChart.jpg differ diff --git a/ide/src/figures/Metrics/Sql.jpg b/ide/src/figures/Metrics/Sql.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24dcde8f9216b9ef5a8dc59af3a61371b09a29ca Binary files /dev/null and b/ide/src/figures/Metrics/Sql.jpg differ diff --git a/ide/src/figures/Metrics/download.jpg b/ide/src/figures/Metrics/download.jpg new file mode 100644 index 0000000000000000000000000000000000000000..227a292968d3ddefe6ac0252a620ec36e179d2cd Binary files /dev/null and b/ide/src/figures/Metrics/download.jpg differ diff --git a/ide/src/figures/Metrics/infoandstats.jpg b/ide/src/figures/Metrics/infoandstats.jpg new file mode 100644 index 0000000000000000000000000000000000000000..79d8be3e5c48ff7070d45a99b7875390ce6edbd5 Binary files /dev/null and b/ide/src/figures/Metrics/infoandstats.jpg differ diff --git a/ide/src/figures/Metrics/metrics.jpg b/ide/src/figures/Metrics/metrics.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d00a8999fe7c9790bf9e3d4c55ee6d05bd3f7568 Binary files /dev/null and b/ide/src/figures/Metrics/metrics.jpg differ diff --git a/ide/src/figures/NativeMemory/AllocationType.jpg b/ide/src/figures/NativeMemory/AllocationType.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4372e720d7f3e0786603dfb0c7a535483e232eb Binary files /dev/null and b/ide/src/figures/NativeMemory/AllocationType.jpg differ diff --git a/ide/src/figures/NativeMemory/CallInfo.jpg b/ide/src/figures/NativeMemory/CallInfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..347a3106c492f364c24bab24a8996928c84ad853 Binary files /dev/null and b/ide/src/figures/NativeMemory/CallInfo.jpg differ diff --git a/ide/src/figures/NativeMemory/Generation.jpg b/ide/src/figures/NativeMemory/Generation.jpg new file mode 100644 index 0000000000000000000000000000000000000000..91424c0d513ac85e677d0c114d3b8959f2f18520 Binary files /dev/null and b/ide/src/figures/NativeMemory/Generation.jpg differ diff --git a/ide/src/figures/NativeMemory/NativeChart.jpg b/ide/src/figures/NativeMemory/NativeChart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..adac97a1428ad42bd8a040a4f4656a2b69346f46 Binary files /dev/null and b/ide/src/figures/NativeMemory/NativeChart.jpg differ diff --git a/ide/src/figures/NativeMemory/NativeMemory.jpg b/ide/src/figures/NativeMemory/NativeMemory.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4790f80f37bb4e3b146da8a65c344f56f9d7934a Binary files /dev/null and b/ide/src/figures/NativeMemory/NativeMemory.jpg differ diff --git a/ide/src/figures/NativeMemory/Snapshotlist.jpg b/ide/src/figures/NativeMemory/Snapshotlist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..126208381afb6229ed169c1fb00ed81490e954c9 Binary files /dev/null and b/ide/src/figures/NativeMemory/Snapshotlist.jpg differ diff --git a/ide/src/figures/NativeMemory/Statistics.jpg b/ide/src/figures/NativeMemory/Statistics.jpg new file mode 100644 index 0000000000000000000000000000000000000000..466a3822cb995cc704323c89571e9dc5adf9d1ae Binary files /dev/null and b/ide/src/figures/NativeMemory/Statistics.jpg differ diff --git a/ide/src/figures/NativeMemory/lifespan.jpg b/ide/src/figures/NativeMemory/lifespan.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1976a4d15ea68334eff34cf60c21ffb9211c691 Binary files /dev/null and b/ide/src/figures/NativeMemory/lifespan.jpg differ diff --git a/ide/src/figures/NativeMemory/naitvememoryfile.jpg b/ide/src/figures/NativeMemory/naitvememoryfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..009480032a1bf861fadefe7a84ab7d00a7fa133a Binary files /dev/null and b/ide/src/figures/NativeMemory/naitvememoryfile.jpg differ diff --git a/ide/src/figures/NativeMemory/nativecallstack.jpg b/ide/src/figures/NativeMemory/nativecallstack.jpg new file mode 100644 index 0000000000000000000000000000000000000000..18714303c76bb94aabb7d5a94ab95e15999152cf Binary files /dev/null and b/ide/src/figures/NativeMemory/nativecallstack.jpg differ diff --git a/ide/src/figures/NativeMemory/nativeexcutecommand.jpg b/ide/src/figures/NativeMemory/nativeexcutecommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24347f52d666aca9a0c529dff413c0dea8e9dbda Binary files /dev/null and b/ide/src/figures/NativeMemory/nativeexcutecommand.jpg differ diff --git a/ide/src/figures/NativeMemory/nativeflame.jpg b/ide/src/figures/NativeMemory/nativeflame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fdf303d888566eb899e2705bee52f6024530c855 Binary files /dev/null and b/ide/src/figures/NativeMemory/nativeflame.jpg differ diff --git a/ide/src/figures/NativeMemory/nativeflamelevel2.jpg b/ide/src/figures/NativeMemory/nativeflamelevel2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..91cfecc809aa9ef66c088c7df2b635686783f20f Binary files /dev/null and b/ide/src/figures/NativeMemory/nativeflamelevel2.jpg differ diff --git a/ide/src/figures/NativeMemory/nativeflameshow.jpg b/ide/src/figures/NativeMemory/nativeflameshow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e4c88206c6213ac4934f9f38f4de381ef3dddb1 Binary files /dev/null and b/ide/src/figures/NativeMemory/nativeflameshow.jpg differ diff --git a/ide/src/figures/NativeMemory/nativememorycommand.jpg b/ide/src/figures/NativeMemory/nativememorycommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..522c6f2c3bbc0aaade02e9c3fb177d6b87ec686c Binary files /dev/null and b/ide/src/figures/NativeMemory/nativememorycommand.jpg differ diff --git a/ide/src/figures/NativeMemory/nativememoryset.jpg b/ide/src/figures/NativeMemory/nativememoryset.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f536eb23db314c642530744d14833566eee2f572 Binary files /dev/null and b/ide/src/figures/NativeMemory/nativememoryset.jpg differ diff --git a/ide/src/figures/NativeMemory/nativememorysetting.jpg b/ide/src/figures/NativeMemory/nativememorysetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c3d1086b04c75ea2d3f08c75450eb3bf738fd9cc Binary files /dev/null and b/ide/src/figures/NativeMemory/nativememorysetting.jpg differ diff --git a/ide/src/figures/NativeMemory/statiscsCallInfo.jpg b/ide/src/figures/NativeMemory/statiscsCallInfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..45d8467005e8cbe5c4e0980abcc10f27bc6c41e8 Binary files /dev/null and b/ide/src/figures/NativeMemory/statiscsCallInfo.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUFrequencychart.jpg b/ide/src/figures/Schedulinganalysis/CPUFrequencychart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77cfb66920a068438fcfa2419b2727eb90700fe4 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUFrequencychart.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUFrequencydetailinfo.jpg b/ide/src/figures/Schedulinganalysis/CPUFrequencydetailinfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2eed4282b081fbb4e0c647323e0889c4444b9035 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUFrequencydetailinfo.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUFrequencythreaddetail.jpg b/ide/src/figures/Schedulinganalysis/CPUFrequencythreaddetail.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e254fe7932d49a17ae634586cf427cb496d8fda Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUFrequencythreaddetail.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUdetailsetting.jpg b/ide/src/figures/Schedulinganalysis/CPUdetailsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9683b732eee0a99ca2afd50a42bae44befba67cb Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUdetailsetting.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUfrequencybythread.jpg b/ide/src/figures/Schedulinganalysis/CPUfrequencybythread.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cb33233aa84c12c42dddc203c85653b37d0cf13 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUfrequencybythread.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUidlechart.jpg b/ide/src/figures/Schedulinganalysis/CPUidlechart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8201d0a64e6529fd8635f7acf23349c15dafa504 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUidlechart.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUidledetailinfo.jpg b/ide/src/figures/Schedulinganalysis/CPUidledetailinfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..52ddfd670647f85a56a0b47fdd0409ec0550f7e7 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUidledetailinfo.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUirqchart.jpg b/ide/src/figures/Schedulinganalysis/CPUirqchart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4e630d0bbfcda05b606dbfd122b09599e2b2ed19 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUirqchart.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUirqdetailinfo.jpg b/ide/src/figures/Schedulinganalysis/CPUirqdetailinfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..91127e8c7dc83683a1aa330536355c8478f7adaa Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUirqdetailinfo.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUsetting.jpg b/ide/src/figures/Schedulinganalysis/CPUsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2d43b9b41cfd5023acfd195cbaf829355ba9f7d Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUsetting.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/CPUusagechart.jpg b/ide/src/figures/Schedulinganalysis/CPUusagechart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..623b0ca500e5d59830a6790a31e9a3cb3d3e9475 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/CPUusagechart.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/Top20Threadduration.jpg b/ide/src/figures/Schedulinganalysis/Top20Threadduration.jpg new file mode 100644 index 0000000000000000000000000000000000000000..077fc47358044518b0f22b868f4413ebcda37a5c Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/Top20Threadduration.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/Top20Threadnum.jpg b/ide/src/figures/Schedulinganalysis/Top20Threadnum.jpg new file mode 100644 index 0000000000000000000000000000000000000000..87c07c29eaded212e8ecd7833a3fa7c2285eac1a Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/Top20Threadnum.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/Top20swtichcount.jpg b/ide/src/figures/Schedulinganalysis/Top20swtichcount.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd6ac16d575bb3ef3aeb98a005e2ab37fe06d907 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/Top20swtichcount.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/scheduexcuting.jpg b/ide/src/figures/Schedulinganalysis/scheduexcuting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..669011d9be9f2463d135247286c90ad0d07a2fc4 Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/scheduexcuting.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/scheduset.jpg b/ide/src/figures/Schedulinganalysis/scheduset.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ef19dc8a8862f640a6bf2d63824a20dcd9dc6c0d Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/scheduset.jpg differ diff --git a/ide/src/figures/Schedulinganalysis/schedusetting.jpg b/ide/src/figures/Schedulinganalysis/schedusetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d977ff703d8c44045172553ee3da3444c7f61ef Binary files /dev/null and b/ide/src/figures/Schedulinganalysis/schedusetting.jpg differ diff --git a/ide/src/figures/Web/M.jpg b/ide/src/figures/Web/M.jpg new file mode 100644 index 0000000000000000000000000000000000000000..574188a550e2fd585d5f596ac7076c9adc31fcf9 Binary files /dev/null and b/ide/src/figures/Web/M.jpg differ diff --git a/ide/src/figures/Web/StatesList.jpg b/ide/src/figures/Web/StatesList.jpg new file mode 100644 index 0000000000000000000000000000000000000000..511000076ca1034ef6f286182d6d1ee8b529070f Binary files /dev/null and b/ide/src/figures/Web/StatesList.jpg differ diff --git a/ide/src/figures/Web/Switchlist.jpg b/ide/src/figures/Web/Switchlist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..75e572346234b744ecb48286b896558c1635111c Binary files /dev/null and b/ide/src/figures/Web/Switchlist.jpg differ diff --git a/ide/src/figures/Web/callstackclick.jpg b/ide/src/figures/Web/callstackclick.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd9ed65526a34d967a1ac45b15aa8ecf96a0d1a4 Binary files /dev/null and b/ide/src/figures/Web/callstackclick.jpg differ diff --git a/ide/src/figures/Web/callstackselect.jpg b/ide/src/figures/Web/callstackselect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ccdbde9c618790875c1d1646f49504eca1f39583 Binary files /dev/null and b/ide/src/figures/Web/callstackselect.jpg differ diff --git a/ide/src/figures/Web/checkbox.jpg b/ide/src/figures/Web/checkbox.jpg new file mode 100644 index 0000000000000000000000000000000000000000..acbc9a40be5c054184bcbff8dba257b9d277e51d Binary files /dev/null and b/ide/src/figures/Web/checkbox.jpg differ diff --git a/ide/src/figures/Web/cpu.jpg b/ide/src/figures/Web/cpu.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f21a80d736774623f24a8f6a1472d5d7b4a2ad30 Binary files /dev/null and b/ide/src/figures/Web/cpu.jpg differ diff --git a/ide/src/figures/Web/cpubyprocess.jpg b/ide/src/figures/Web/cpubyprocess.jpg new file mode 100644 index 0000000000000000000000000000000000000000..470d4f3fdf5119773bc7b180d880a962d495b19d Binary files /dev/null and b/ide/src/figures/Web/cpubyprocess.jpg differ diff --git a/ide/src/figures/Web/cpubythread.jpg b/ide/src/figures/Web/cpubythread.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99c06e9d6fc87e390f33297623f519dc8fc37189 Binary files /dev/null and b/ide/src/figures/Web/cpubythread.jpg differ diff --git a/ide/src/figures/Web/cpuclick.jpg b/ide/src/figures/Web/cpuclick.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1a3c6d358474a1c649993cd673b66fade9871d6 Binary files /dev/null and b/ide/src/figures/Web/cpuclick.jpg differ diff --git a/ide/src/figures/Web/cpusage.jpg b/ide/src/figures/Web/cpusage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ecb696bb7f4bc7212999941c208daef0ff5abab5 Binary files /dev/null and b/ide/src/figures/Web/cpusage.jpg differ diff --git a/ide/src/figures/Web/details.jpg b/ide/src/figures/Web/details.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d9faf9dac54e6ec29953be33def7250e0eaa44b Binary files /dev/null and b/ide/src/figures/Web/details.jpg differ diff --git a/ide/src/figures/Web/flag.jpg b/ide/src/figures/Web/flag.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8720740c3256c2b64be4411809d9fa87d1ba0100 Binary files /dev/null and b/ide/src/figures/Web/flag.jpg differ diff --git a/ide/src/figures/Web/flaginput.jpg b/ide/src/figures/Web/flaginput.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bc0b554ebb7569a2c65424c1025c7115b3f1c77d Binary files /dev/null and b/ide/src/figures/Web/flaginput.jpg differ diff --git a/ide/src/figures/Web/fps.jpg b/ide/src/figures/Web/fps.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bfc18dfe881b738f6e9b100e4e32d5ab04dcb383 Binary files /dev/null and b/ide/src/figures/Web/fps.jpg differ diff --git a/ide/src/figures/Web/fpsselect.jpg b/ide/src/figures/Web/fpsselect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..14300f78ce384f8ad0366657e3b0eed2177e7505 Binary files /dev/null and b/ide/src/figures/Web/fpsselect.jpg differ diff --git a/ide/src/figures/Web/fpstip.jpg b/ide/src/figures/Web/fpstip.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b5954226117c9ffd08fb2a974214006180a8160 Binary files /dev/null and b/ide/src/figures/Web/fpstip.jpg differ diff --git a/ide/src/figures/Web/gray.jpg b/ide/src/figures/Web/gray.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9bdb38037a286ea531485e6445553ea61f6d2e04 Binary files /dev/null and b/ide/src/figures/Web/gray.jpg differ diff --git a/ide/src/figures/Web/highlit.jpg b/ide/src/figures/Web/highlit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24278fdc9e13fa79efcac8b8355f5d94919a01a7 Binary files /dev/null and b/ide/src/figures/Web/highlit.jpg differ diff --git a/ide/src/figures/Web/jumpthread.jpg b/ide/src/figures/Web/jumpthread.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bdb494ed810dab30cfd998718c08d6b891dd09db Binary files /dev/null and b/ide/src/figures/Web/jumpthread.jpg differ diff --git a/ide/src/figures/Web/main.jpg b/ide/src/figures/Web/main.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5209395cb5c65c857a192b7e0ec768cd2170181e Binary files /dev/null and b/ide/src/figures/Web/main.jpg differ diff --git a/ide/src/figures/Web/opentrace.jpg b/ide/src/figures/Web/opentrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..394bb8ae7a9767056a70005e4bc7a4bc11ea15bd Binary files /dev/null and b/ide/src/figures/Web/opentrace.jpg differ diff --git a/ide/src/figures/Web/process.jpg b/ide/src/figures/Web/process.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62cad6b1f899e3be5abc1e17764a7aba6fca4a39 Binary files /dev/null and b/ide/src/figures/Web/process.jpg differ diff --git a/ide/src/figures/Web/search.jpg b/ide/src/figures/Web/search.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9e5900ec03c7cc688c2f150775db3a0b11028e71 Binary files /dev/null and b/ide/src/figures/Web/search.jpg differ diff --git a/ide/src/figures/Web/searchcallstack.jpg b/ide/src/figures/Web/searchcallstack.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2dbd4cf5a838980b641df9a4e9c2871fd73034d8 Binary files /dev/null and b/ide/src/figures/Web/searchcallstack.jpg differ diff --git a/ide/src/figures/Web/stars.jpg b/ide/src/figures/Web/stars.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62a3492126d240e8080f4be976abe0eb2d99315d Binary files /dev/null and b/ide/src/figures/Web/stars.jpg differ diff --git a/ide/src/figures/Web/threadclick.jpg b/ide/src/figures/Web/threadclick.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65811e9317fd845bb5b2d3df752ffb742ad743e8 Binary files /dev/null and b/ide/src/figures/Web/threadclick.jpg differ diff --git a/ide/src/figures/Web/threadinfo.jpg b/ide/src/figures/Web/threadinfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2b6be2acf86bcc2612ff4ab1a6b820e6551b9b6 Binary files /dev/null and b/ide/src/figures/Web/threadinfo.jpg differ diff --git a/ide/src/figures/Web/threadselect.jpg b/ide/src/figures/Web/threadselect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38fda253bd3bab6d3388b1e19cd39d488386d2ba Binary files /dev/null and b/ide/src/figures/Web/threadselect.jpg differ diff --git a/ide/src/figures/Web/threadstates.jpg b/ide/src/figures/Web/threadstates.jpg new file mode 100644 index 0000000000000000000000000000000000000000..475dde7276e119266eb76d2ab0f3d4eaa45d9df1 Binary files /dev/null and b/ide/src/figures/Web/threadstates.jpg differ diff --git a/ide/src/figures/Web/threadswitches.jpg b/ide/src/figures/Web/threadswitches.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc5974681992956657428d63cb8fbf8b8e01bd1c Binary files /dev/null and b/ide/src/figures/Web/threadswitches.jpg differ diff --git a/ide/src/figures/Web/time.jpg b/ide/src/figures/Web/time.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0221cb47e5874a05280a7315831fd61ec13cdd0 Binary files /dev/null and b/ide/src/figures/Web/time.jpg differ diff --git a/ide/src/figures/Web/trace.jpg b/ide/src/figures/Web/trace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d4bb1c2e32d840b3cf64cf6267a36184d2032145 Binary files /dev/null and b/ide/src/figures/Web/trace.jpg differ diff --git a/ide/src/figures/deploy/bin_files.png b/ide/src/figures/deploy/bin_files.png new file mode 100644 index 0000000000000000000000000000000000000000..6657337dce8d72b262e1c02473098f5be59aa33c Binary files /dev/null and b/ide/src/figures/deploy/bin_files.png differ diff --git a/ide/src/figures/deploy/check_version.png b/ide/src/figures/deploy/check_version.png new file mode 100644 index 0000000000000000000000000000000000000000..b76b41ed4fb9ba9bc6d1538b245ccc7ff5e98d06 Binary files /dev/null and b/ide/src/figures/deploy/check_version.png differ diff --git a/ide/src/figures/deploy/chomd+x.png b/ide/src/figures/deploy/chomd+x.png new file mode 100644 index 0000000000000000000000000000000000000000..e2781fc8e4fe005376d85b18ca220a5c6ef8a5e5 Binary files /dev/null and b/ide/src/figures/deploy/chomd+x.png differ diff --git a/ide/src/figures/deploy/compile.png b/ide/src/figures/deploy/compile.png new file mode 100644 index 0000000000000000000000000000000000000000..1221e25c0b69e87feaeddf767334620716fe4726 Binary files /dev/null and b/ide/src/figures/deploy/compile.png differ diff --git a/ide/src/figures/deploy/install_golang.png b/ide/src/figures/deploy/install_golang.png new file mode 100644 index 0000000000000000000000000000000000000000..a4a58e9fa7e5f4ede6d96b6a2727f1385292c28c Binary files /dev/null and b/ide/src/figures/deploy/install_golang.png differ diff --git a/ide/src/figures/deploy/install_node.png b/ide/src/figures/deploy/install_node.png new file mode 100644 index 0000000000000000000000000000000000000000..14f15af1343948d39098f2f75c7cd64dd2c0b412 Binary files /dev/null and b/ide/src/figures/deploy/install_node.png differ diff --git a/ide/src/figures/deploy/install_tsc.png b/ide/src/figures/deploy/install_tsc.png new file mode 100644 index 0000000000000000000000000000000000000000..5ea36c6a86b8459d0ca34ddc4c20bbd651828a3a Binary files /dev/null and b/ide/src/figures/deploy/install_tsc.png differ diff --git a/ide/src/figures/deploy/put_bin.png b/ide/src/figures/deploy/put_bin.png new file mode 100644 index 0000000000000000000000000000000000000000..7945c95d265437d89924d8d19072f643f7b19b62 Binary files /dev/null and b/ide/src/figures/deploy/put_bin.png differ diff --git a/ide/src/figures/deploy/run_main.png b/ide/src/figures/deploy/run_main.png new file mode 100644 index 0000000000000000000000000000000000000000..eae89d97cabcad187d37f126a24ef69095c328bf Binary files /dev/null and b/ide/src/figures/deploy/run_main.png differ diff --git a/ide/src/figures/deploy/third_party.png b/ide/src/figures/deploy/third_party.png new file mode 100644 index 0000000000000000000000000000000000000000..77ff8ca912ee369c1f8407ce511e4e17de16c579 Binary files /dev/null and b/ide/src/figures/deploy/third_party.png differ diff --git a/ide/src/figures/deploy/visit_website.png b/ide/src/figures/deploy/visit_website.png new file mode 100644 index 0000000000000000000000000000000000000000..889041aabcfb57a9c24d8de10450356cca9f54c1 Binary files /dev/null and b/ide/src/figures/deploy/visit_website.png differ diff --git a/ide/src/figures/deploy/yum_install_go.png b/ide/src/figures/deploy/yum_install_go.png new file mode 100644 index 0000000000000000000000000000000000000000..4eae4fabc664f521db101288c8491e10b4013870 Binary files /dev/null and b/ide/src/figures/deploy/yum_install_go.png differ diff --git a/ide/src/figures/deploy/yum_install_node.png b/ide/src/figures/deploy/yum_install_node.png new file mode 100644 index 0000000000000000000000000000000000000000..b05160f060bec9bd90d951626af88ba6b3fda63b Binary files /dev/null and b/ide/src/figures/deploy/yum_install_node.png differ diff --git a/ide/src/figures/hdc/Device.jpg b/ide/src/figures/hdc/Device.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e8174d7d6ff5e50b7d6623c091ccade8bc85c8b2 Binary files /dev/null and b/ide/src/figures/hdc/Device.jpg differ diff --git a/ide/src/figures/hdc/Schedulingdetails.jpg b/ide/src/figures/hdc/Schedulingdetails.jpg new file mode 100644 index 0000000000000000000000000000000000000000..27d3dc9354922634b3dea53a956bf141b202f652 Binary files /dev/null and b/ide/src/figures/hdc/Schedulingdetails.jpg differ diff --git a/ide/src/figures/hdc/bytacedescription.jpg b/ide/src/figures/hdc/bytacedescription.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3fa24ba1a434f70254294685e6b600e6518e4773 Binary files /dev/null and b/ide/src/figures/hdc/bytacedescription.jpg differ diff --git a/ide/src/figures/hdc/examplerecord.jpg b/ide/src/figures/hdc/examplerecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ccfb6b35eba8903e4c25b1b562919f481e34cc6e Binary files /dev/null and b/ide/src/figures/hdc/examplerecord.jpg differ diff --git a/ide/src/figures/hdc/hdc.jpg b/ide/src/figures/hdc/hdc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf8c0e8bfd2ac208214203dd972f3b3821b06d5d Binary files /dev/null and b/ide/src/figures/hdc/hdc.jpg differ diff --git a/ide/src/figures/hdc/hdcfile.jpg b/ide/src/figures/hdc/hdcfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d5d56f9abdab6f8ce697daaf82a8c0449f909c82 Binary files /dev/null and b/ide/src/figures/hdc/hdcfile.jpg differ diff --git a/ide/src/figures/hdc/hdctracing.jpg b/ide/src/figures/hdc/hdctracing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7f6ab5e716a714c470e2babaa63d715eba78253c Binary files /dev/null and b/ide/src/figures/hdc/hdctracing.jpg differ diff --git a/ide/src/figures/hdc/record.jpg b/ide/src/figures/hdc/record.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2dcd197597c774d522c1c0a8987c201791e4ac6d Binary files /dev/null and b/ide/src/figures/hdc/record.jpg differ diff --git a/ide/src/figures/hiprofilercmd/Scheduling.jpg b/ide/src/figures/hiprofilercmd/Scheduling.jpg new file mode 100644 index 0000000000000000000000000000000000000000..725d7f6588e32949847d5def5a1e24dbe874ee2b Binary files /dev/null and b/ide/src/figures/hiprofilercmd/Scheduling.jpg differ diff --git a/ide/src/figures/hiprofilercmd/command.jpg b/ide/src/figures/hiprofilercmd/command.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f46dbfce09bf8d0ea5e77bb29798f5de4785951 Binary files /dev/null and b/ide/src/figures/hiprofilercmd/command.jpg differ diff --git a/ide/src/figures/hiprofilercmd/commandend.jpg b/ide/src/figures/hiprofilercmd/commandend.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54996a8d125d988cce045a5411f716aec23a986e Binary files /dev/null and b/ide/src/figures/hiprofilercmd/commandend.jpg differ diff --git a/ide/src/figures/hiprofilercmd/excutecommand.jpg b/ide/src/figures/hiprofilercmd/excutecommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..800db358d13c7144419e4620ae1a3a5e60f8d7e3 Binary files /dev/null and b/ide/src/figures/hiprofilercmd/excutecommand.jpg differ diff --git a/ide/src/figures/hiprofilercmd/hiprofiler_plggins.jpg b/ide/src/figures/hiprofilercmd/hiprofiler_plggins.jpg new file mode 100644 index 0000000000000000000000000000000000000000..026e2e665ef7f385bb89997381f714fa5400a698 Binary files /dev/null and b/ide/src/figures/hiprofilercmd/hiprofiler_plggins.jpg differ diff --git a/ide/src/figures/hiprofilercmd/hiprofilerd.jpg b/ide/src/figures/hiprofilercmd/hiprofilerd.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d67f1a118dc151533f1b7047f821aa270508f5dc Binary files /dev/null and b/ide/src/figures/hiprofilercmd/hiprofilerd.jpg differ diff --git a/ide/src/figures/hiprofilercmd/htrace.jpg b/ide/src/figures/hiprofilercmd/htrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ed4d99923ec33d120db0e96b27bc4b772097eafe Binary files /dev/null and b/ide/src/figures/hiprofilercmd/htrace.jpg differ diff --git a/ide/src/figures/hiprofilercmd/systraceconfig.jpg b/ide/src/figures/hiprofilercmd/systraceconfig.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d3fabe97909c1f9895c0c021c24e1a6ed16b303 Binary files /dev/null and b/ide/src/figures/hiprofilercmd/systraceconfig.jpg differ diff --git a/ide/src/figures/hiprofilercmd/tracesetting.jpg b/ide/src/figures/hiprofilercmd/tracesetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e490d6a13a5c7ad743717924312b2c0c9b3fd86a Binary files /dev/null and b/ide/src/figures/hiprofilercmd/tracesetting.jpg differ diff --git a/ide/src/figures/perf/Options.jpg b/ide/src/figures/perf/Options.jpg new file mode 100644 index 0000000000000000000000000000000000000000..465b4cf6a06057fbe7e116c8bc72e967b94b59ec Binary files /dev/null and b/ide/src/figures/perf/Options.jpg differ diff --git a/ide/src/figures/perf/PerfProfile.jpg b/ide/src/figures/perf/PerfProfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2732b9541a582b0fcd91836cf34a7ada08e336cd Binary files /dev/null and b/ide/src/figures/perf/PerfProfile.jpg differ diff --git a/ide/src/figures/perf/Samplelist.jpg b/ide/src/figures/perf/Samplelist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f161a6c5a40405149ae296df339b43c154c2f81d Binary files /dev/null and b/ide/src/figures/perf/Samplelist.jpg differ diff --git a/ide/src/figures/perf/callstack.jpg b/ide/src/figures/perf/callstack.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fbcc33cf142a373fc381be32a1636b80096f7878 Binary files /dev/null and b/ide/src/figures/perf/callstack.jpg differ diff --git a/ide/src/figures/perf/chart.jpg b/ide/src/figures/perf/chart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c17758ab78a2fd465bed0c13eeb84ad9e95fe588 Binary files /dev/null and b/ide/src/figures/perf/chart.jpg differ diff --git a/ide/src/figures/perf/datamining.jpg b/ide/src/figures/perf/datamining.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcc45679dba8ad79e227314b853a54d76f8ab3e2 Binary files /dev/null and b/ide/src/figures/perf/datamining.jpg differ diff --git a/ide/src/figures/perf/flame.jpg b/ide/src/figures/perf/flame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a188dcef2e8d44d2819f25e7c3599298900d7080 Binary files /dev/null and b/ide/src/figures/perf/flame.jpg differ diff --git a/ide/src/figures/perf/flamelevel2.jpg b/ide/src/figures/perf/flamelevel2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..93b379960a2f0f01da97eef1e2aeeb2f7e1cd60c Binary files /dev/null and b/ide/src/figures/perf/flamelevel2.jpg differ diff --git a/ide/src/figures/perf/flameshow.jpg b/ide/src/figures/perf/flameshow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..618a552a8a43811c92979d512c647ffc9915f331 Binary files /dev/null and b/ide/src/figures/perf/flameshow.jpg differ diff --git a/ide/src/figures/perf/heaviesttrace1.jpg b/ide/src/figures/perf/heaviesttrace1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de01d6767b988bc99b02d92869d2e9e66b0d6d30 Binary files /dev/null and b/ide/src/figures/perf/heaviesttrace1.jpg differ diff --git a/ide/src/figures/perf/inputfilter.jpg b/ide/src/figures/perf/inputfilter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0beea5695a229a7527812634aaefdd2316074331 Binary files /dev/null and b/ide/src/figures/perf/inputfilter.jpg differ diff --git a/ide/src/figures/perf/perfcommand.jpg b/ide/src/figures/perf/perfcommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..51ea2d696b88ce260b6ff0e0f16b12c6dbc00c73 Binary files /dev/null and b/ide/src/figures/perf/perfcommand.jpg differ diff --git a/ide/src/figures/perf/perfexcutecommand.jpg b/ide/src/figures/perf/perfexcutecommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..43c0361a2e363c8e645671cf525e005cc32d9f18 Binary files /dev/null and b/ide/src/figures/perf/perfexcutecommand.jpg differ diff --git a/ide/src/figures/perf/perffile.jpg b/ide/src/figures/perf/perffile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e4b200913b1d0cad24ec5aab6b9535099686f66 Binary files /dev/null and b/ide/src/figures/perf/perffile.jpg differ diff --git a/ide/src/figures/perf/perfset.jpg b/ide/src/figures/perf/perfset.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3032dac77c2d5a53ccab6c8634fdf4933fa82efe Binary files /dev/null and b/ide/src/figures/perf/perfset.jpg differ diff --git a/ide/src/figures/perf/perfsetting.jpg b/ide/src/figures/perf/perfsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35de22f253d8143b2e9285a8dec4f245feb95fe9 Binary files /dev/null and b/ide/src/figures/perf/perfsetting.jpg differ diff --git a/ide/src/figures/perf/samplecounter.jpg b/ide/src/figures/perf/samplecounter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b7e92468b8b1ce414a831dd8134f3d6c5baa163e Binary files /dev/null and b/ide/src/figures/perf/samplecounter.jpg differ diff --git a/ide/src/figures/perf/summary.jpg b/ide/src/figures/perf/summary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8c01ad4ffec6b75b5efcae534084b53ce7370de Binary files /dev/null and b/ide/src/figures/perf/summary.jpg differ diff --git a/ide/src/figures/perf/trace2.jpg b/ide/src/figures/perf/trace2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e324c54473450441105300db941db200b3da778 Binary files /dev/null and b/ide/src/figures/perf/trace2.jpg differ diff --git a/ide/src/figures/sdk/sdk.jpg b/ide/src/figures/sdk/sdk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d834d135a70a9ec080850d45f7b4e8e80237ab36 Binary files /dev/null and b/ide/src/figures/sdk/sdk.jpg differ diff --git a/ide/src/figures/smaps/smapschart.jpg b/ide/src/figures/smaps/smapschart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..032d543261f85121367fa3f7e260e688b018d815 Binary files /dev/null and b/ide/src/figures/smaps/smapschart.jpg differ diff --git a/ide/src/figures/smaps/smapsexcuting.jpg b/ide/src/figures/smaps/smapsexcuting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53f86e1472c53801d7d3637ffadae6d493233921 Binary files /dev/null and b/ide/src/figures/smaps/smapsexcuting.jpg differ diff --git a/ide/src/figures/smaps/smapslist.jpg b/ide/src/figures/smaps/smapslist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..598f6a1289980ead2857757d8d7ff513d5a022d9 Binary files /dev/null and b/ide/src/figures/smaps/smapslist.jpg differ diff --git a/ide/src/figures/smaps/smapsrecord.jpg b/ide/src/figures/smaps/smapsrecord.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9380722264bf06e22a1b1231e97eca0f06a0db1f Binary files /dev/null and b/ide/src/figures/smaps/smapsrecord.jpg differ diff --git a/ide/src/figures/smaps/smapssetting.jpg b/ide/src/figures/smaps/smapssetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c79f7f9d047c0ca2e4d4b90ab15a58f81e279f81 Binary files /dev/null and b/ide/src/figures/smaps/smapssetting.jpg differ diff --git a/ide/src/figures/smaps/smapsstatistics.jpg b/ide/src/figures/smaps/smapsstatistics.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4af1ef5ad619eeb8a0ed024286c868421118c428 Binary files /dev/null and b/ide/src/figures/smaps/smapsstatistics.jpg differ diff --git a/ide/src/figures/smaps/smapssummary.jpg b/ide/src/figures/smaps/smapssummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df74018bc3bdfd6bec26d540415e2125e929530a Binary files /dev/null and b/ide/src/figures/smaps/smapssummary.jpg differ diff --git a/ide/src/figures/smartperf_framework.png b/ide/src/figures/smartperf_framework.png new file mode 100644 index 0000000000000000000000000000000000000000..62c1bc6cd61e07ba3014141f70941e6134d75681 Binary files /dev/null and b/ide/src/figures/smartperf_framework.png differ diff --git a/ide/src/figures/traceStreamer/cpu_frequency.png b/ide/src/figures/traceStreamer/cpu_frequency.png new file mode 100644 index 0000000000000000000000000000000000000000..a18715fc696b3231b94425e4acd6aaf319bf399f Binary files /dev/null and b/ide/src/figures/traceStreamer/cpu_frequency.png differ diff --git a/ide/src/figures/traceStreamer/db_common.png b/ide/src/figures/traceStreamer/db_common.png new file mode 100644 index 0000000000000000000000000000000000000000..29dbb080e1d213672b74d553610f6a24445663ad Binary files /dev/null and b/ide/src/figures/traceStreamer/db_common.png differ diff --git a/ide/src/figures/traceStreamer/db_hiperf.png b/ide/src/figures/traceStreamer/db_hiperf.png new file mode 100644 index 0000000000000000000000000000000000000000..85cacf15a7153a0853c7aeee2fe34fba1f8983a8 Binary files /dev/null and b/ide/src/figures/traceStreamer/db_hiperf.png differ diff --git a/ide/src/figures/traceStreamer/db_hisys_event.png b/ide/src/figures/traceStreamer/db_hisys_event.png new file mode 100644 index 0000000000000000000000000000000000000000..215265182de684f1b4a31fd7158309f8c7532053 Binary files /dev/null and b/ide/src/figures/traceStreamer/db_hisys_event.png differ diff --git a/ide/src/figures/traceStreamer/db_native_memory.png b/ide/src/figures/traceStreamer/db_native_memory.png new file mode 100644 index 0000000000000000000000000000000000000000..0e1403e958fbf76f3d2c31fc6304426de6579afb Binary files /dev/null and b/ide/src/figures/traceStreamer/db_native_memory.png differ diff --git a/ide/src/figures/traceStreamer/dump_and_mem.png b/ide/src/figures/traceStreamer/dump_and_mem.png new file mode 100644 index 0000000000000000000000000000000000000000..2c3f59eef7476de91cafb8f59832c93fe4117e51 Binary files /dev/null and b/ide/src/figures/traceStreamer/dump_and_mem.png differ diff --git a/ide/src/figures/traceStreamer/filters.png b/ide/src/figures/traceStreamer/filters.png new file mode 100644 index 0000000000000000000000000000000000000000..a02d9416f08382ff7a03e176e37e6479f5922c08 Binary files /dev/null and b/ide/src/figures/traceStreamer/filters.png differ diff --git a/ide/src/figures/traceStreamer/frames.jpg b/ide/src/figures/traceStreamer/frames.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0cd54de43e8ca22de9e33fe19aaa0800bec3ef7 Binary files /dev/null and b/ide/src/figures/traceStreamer/frames.jpg differ diff --git a/ide/src/figures/traceStreamer/log.png b/ide/src/figures/traceStreamer/log.png new file mode 100644 index 0000000000000000000000000000000000000000..0c9ac304183f2276454caeb2fea593a5e88bdc13 Binary files /dev/null and b/ide/src/figures/traceStreamer/log.png differ diff --git a/ide/src/figures/traceStreamer/mem_usage.png b/ide/src/figures/traceStreamer/mem_usage.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ebd6e272c424d6861e2e8150c72c1f4de9802a Binary files /dev/null and b/ide/src/figures/traceStreamer/mem_usage.png differ diff --git a/ide/src/figures/traceStreamer/perf.png b/ide/src/figures/traceStreamer/perf.png new file mode 100644 index 0000000000000000000000000000000000000000..9fc88ad255cece0040093392329e639e261c8bd9 Binary files /dev/null and b/ide/src/figures/traceStreamer/perf.png differ diff --git a/ide/src/figures/traceStreamer/process_thread.png b/ide/src/figures/traceStreamer/process_thread.png new file mode 100644 index 0000000000000000000000000000000000000000..305a9bdb02d7776f086f8f13d5f6f72e72443226 Binary files /dev/null and b/ide/src/figures/traceStreamer/process_thread.png differ diff --git a/ide/src/figures/traceStreamer/thread_state.png b/ide/src/figures/traceStreamer/thread_state.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9f846fcc4b88c1b8e9df75e3aff7ada69537dc Binary files /dev/null and b/ide/src/figures/traceStreamer/thread_state.png differ diff --git a/ide/src/figures/traceStreamer/trace_streamer_stream.png b/ide/src/figures/traceStreamer/trace_streamer_stream.png new file mode 100644 index 0000000000000000000000000000000000000000..d36687d164a32bcb07f8f8bd699f0fb0b37e63bd Binary files /dev/null and b/ide/src/figures/traceStreamer/trace_streamer_stream.png differ diff --git a/ide/src/hdc/HdcDeviceManager.ts b/ide/src/hdc/HdcDeviceManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..c43bd6b80bd30d2ec7b071d424b833adc0c510c5 --- /dev/null +++ b/ide/src/hdc/HdcDeviceManager.ts @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2022 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 { HdcClient } from './hdcclient/HdcClient.js'; +import { UsbTransmissionChannel } from './transmission/UsbTransmissionChannel.js'; +import { HDC_DEVICE_FILTERS } from './common/ConstantType.js'; +import { FormatCommand } from './hdcclient/FormatCommand.js'; +import { log } from '../log/Log.js'; +import { HdcStream } from './hdcclient/HdcStream.js'; +import { HdcCommand } from './hdcclient/HdcCommand.js'; +import { SpRecordTrace } from '../trace/component/SpRecordTrace.js'; + +export class HdcDeviceManager { + private static clientList: Map = new Map(); + private static currentHdcClient: HdcClient; + private static FILE_RECV_PREFIX_STRING = 'hdc file recv -cwd C:\\ '; + + /** + * getDevices + */ + // @ts-ignore + public static async getDevices(): Promise { + // @ts-ignore + return navigator.usb.getDevices(); + } + + /** + * findDevice + */ + public static findDevice() { + if (!('usb' in navigator)) { + throw new Error('WebUSB not supported by the browser (requires HTTPS)'); + } + // @ts-ignore + return navigator.usb.requestDevice({ filters: HDC_DEVICE_FILTERS }); + } + + /** + * connect by serialNumber + * + * @param serialNumber serialNumber + */ + public static async connect(serialNumber: string): Promise { + let client = this.clientList.get(serialNumber); + if (client) { + if (client.usbDevice!.opened) { + log('device Usb is Open'); + return true; + } else { + if (SpRecordTrace.serialNumber == serialNumber) { + SpRecordTrace.serialNumber = ''; + } + log('device Usb not Open'); + return false; + } + } else { + let connectDevice = await this.getDeviceBySerialNumber(serialNumber); + let usbChannel = await UsbTransmissionChannel.openHdcDevice(connectDevice); + if (usbChannel) { + let hdcClient = new HdcClient(usbChannel, connectDevice); + let connected = await hdcClient.connectDevice(); + if (connected) { + this.currentHdcClient = hdcClient; + this.clientList.set(serialNumber, hdcClient); + } + log('device Usb connected : ' + connected); + return connected; + } else { + log('device Usb connected failed: '); + return false; + } + } + } + + // @ts-ignore + public static async getDeviceBySerialNumber(serialNumber: string): Promise { + // @ts-ignore + const devices = await navigator.usb.getDevices(); + // @ts-ignore + return devices.find((dev) => dev.serialNumber === serialNumber); + } + + /** + * disConnect by serialNumber + * + * @param serialNumber + */ + public static async disConnect(serialNumber: string): Promise { + let hdcClient = this.clientList.get(serialNumber); + if (hdcClient) { + await hdcClient.disconnect(); + this.clientList.delete(serialNumber); + return true; + } else { + return true; + } + } + + /** + * Execute shell on the currently connected device and return the result as a string + * + * @param cmd cmd + */ + public static async shellResultAsString(cmd: string, isSkipResult: boolean): Promise { + if (this.currentHdcClient) { + let hdcStream = new HdcStream(this.currentHdcClient, false); + await hdcStream.DoCommand(cmd); + let result: string = ''; + while (true) { + let dataMessage = await hdcStream.getMessage(); + if (dataMessage.channelClose || isSkipResult) { + result += dataMessage.getDataToString(); + await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false)); + log('result is end, close'); + break; + } + if (dataMessage.usbHead.sessionId == -1) { + return Promise.resolve('The device is abnormal'); + } + result += dataMessage.getDataToString(); + } + await hdcStream.closeStream(); + await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false)); + return Promise.resolve(result); + } + return Promise.reject('not select device'); + } + + /** + * Execute shell on the currently connected device and return the result as a string + * + * @param cmd cmd + */ + public static async stopHiprofiler(cmd: string, isSkipResult: boolean): Promise { + if (this.currentHdcClient) { + let hdcStream = new HdcStream(this.currentHdcClient, true); + await hdcStream.DoCommand(cmd); + let result: string = ''; + while (true) { + let dataMessage = await hdcStream.getMessage(); + if (dataMessage.channelClose || isSkipResult) { + await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false)); + log('result is end, close'); + break; + } + result += dataMessage.getDataToString(); + } + await hdcStream.closeStopStream(); + await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '0', false)); + return Promise.resolve(result); + } + return Promise.reject('not select device'); + } + + /** + * Execute shell on the currently connected device, the result is returned as Blob + * + * @param cmd cmd + */ + public static async shellResultAsBlob(cmd: string, isSkipResult: boolean): Promise { + if (this.currentHdcClient) { + let hdcStream = new HdcStream(this.currentHdcClient, false); + log('cmd is ' + cmd); + await hdcStream.DoCommand(cmd); + let finalBuffer; + while (true) { + let dataMessage = await hdcStream.getMessage(); + if (dataMessage.channelClose || isSkipResult) { + log('result is end, close'); + break; + } + let res = dataMessage.getData(); + if (res) { + if (!finalBuffer) { + finalBuffer = new Uint8Array(res); + } else { + finalBuffer = HdcDeviceManager.appendBuffer(finalBuffer, new Uint8Array(res)); + } + } + } + await hdcStream.closeStream(); + if (finalBuffer) { + return Promise.resolve(new Blob([finalBuffer])); + } + return Promise.resolve(new Blob()); + } + return Promise.reject('not select device'); + } + + /** + * appendBuffer + * + * @param buffer1 firstBuffer + * @param buffer2 secondBuffer + * @private + */ + private static appendBuffer(buffer1: Uint8Array, buffer2: Uint8Array) { + let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); + tmp.set(buffer1, 0); + tmp.set(buffer2, buffer1.byteLength); + return tmp; + } + + /** + * Pull the corresponding file from the device side + * + * @param filename filename + */ + public static async fileRecv(filename: string, callBack: Function): Promise { + let finalBuffer; + if (this.currentHdcClient) { + let hdcStream = new HdcStream(this.currentHdcClient, false); + await hdcStream.DoCommand(HdcDeviceManager.FILE_RECV_PREFIX_STRING + filename + ' ./'); + if (!finalBuffer && hdcStream.fileSize > 0) { + finalBuffer = new Uint8Array(hdcStream.fileSize); + log('Uint8Array size is ' + finalBuffer.byteLength); + } + let offset = 0; + while (true) { + let dataMessage = await hdcStream.getMessage(); + if (dataMessage.channelClose) { + log('result is end, close'); + break; + } + if (dataMessage.commandFlag == HdcCommand.CMD_FILE_FINISH) { + await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_KERNEL_CHANNEL_CLOSE, '', false)); + log('CMD_FILE_FINISH is end, close'); + break; + } + let res = dataMessage.getData(); + if (res) { + let resRS: ArrayBuffer = res.slice(64); + if (finalBuffer) { + finalBuffer.set(new Uint8Array(resRS), offset); + offset += resRS.byteLength; + callBack(((offset / hdcStream.fileSize) * 100).toFixed(3)); + } + } + if (hdcStream.fileSize != -1 && offset >= hdcStream.fileSize) { + callBack(100); + await hdcStream.DoCommandRemote(new FormatCommand(HdcCommand.CMD_FILE_FINISH, '', false)); + } + } + } + if (finalBuffer) { + return Promise.resolve(new Blob([finalBuffer])); + } else { + return Promise.resolve(new Blob([])); + } + } +} diff --git a/ide/src/hdc/common/BaseConversion.ts b/ide/src/hdc/common/BaseConversion.ts new file mode 100644 index 0000000000000000000000000000000000000000..967e439af5f65b1bc697aa47ef5c977920de8266 --- /dev/null +++ b/ide/src/hdc/common/BaseConversion.ts @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 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. + */ + +export function toHex8(num: number): string { + const padLen = 1 - num.toString(16).length; + let padded = ''; + for (let i = 0; i < padLen; i++) { + padded += '0'; + } + return padded + num.toString(16); +} + +export function toHex16(num: number): string { + const padLen = 2 - num.toString(16).length; + let padded = ''; + for (let i = 0; i < padLen; i++) { + padded += '0'; + } + return padded + num.toString(16); +} + +export function toHex32(num: number): string { + const padLen = 4 - num.toString(16).length; + let padded = ''; + for (let i = 0; i < padLen; i++) { + padded += '0'; + } + return padded + num.toString(16); +} + +export function toHex64(num: number): string { + const padLen = 8 - num.toString(16).length; + let padded = ''; + for (let i = 0; i < padLen; i++) { + padded += '0'; + } + return padded + num.toString(16); +} + +export function uint8ArrayToString(array: Uint8Array, convertToHex16: boolean): string { + let result: string = ''; + for (let i = 0; i < array.length; i++) { + if (convertToHex16) { + result = result + toHex16(array[i]); + } else { + result = result + array[i]; + } + } + return result; +} + +export const Sleep = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; diff --git a/ide/src/hdc/common/ConstantType.ts b/ide/src/hdc/common/ConstantType.ts new file mode 100644 index 0000000000000000000000000000000000000000..106a37c42186cc2209cf99df5b4b517183c9908f --- /dev/null +++ b/ide/src/hdc/common/ConstantType.ts @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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. + */ + +export const HANDSHAKE_MESSAGE: string = 'OHOS HDC'; // sep not char '-', not more than 11 bytes +export const PACKET_FLAG = 'HW'; +export const USB_PACKET_FLAG: string = 'UB'; +export const MAX_PACKET_SIZE_HISPEED: number = 512; // uint16_t +export const MAX_USBFFS_BULK: number = 16384; +export const ERR_IO_FAIL = -14000; + +export const CMDSTR_SHELL: string = 'shell'; +export const CMDSTR_FILE_SEND: string = 'file send'; +export const CMDSTR_FILE_RECV: string = 'file recv'; +// @ts-ignore +export const HDC_DEVICE_FILTER = { classCode: 255, subclassCode: 80, protocolCode: 1 } as USBDeviceFilter; + +export const HDC_DEVICE_FILTERS = [HDC_DEVICE_FILTER]; diff --git a/ide/src/hdc/common/ObjectToMemorySize.ts b/ide/src/hdc/common/ObjectToMemorySize.ts new file mode 100644 index 0000000000000000000000000000000000000000..6fe8a38b05173d64b0d3402faad48e207fcd7abd --- /dev/null +++ b/ide/src/hdc/common/ObjectToMemorySize.ts @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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. + */ + +export class objectToMemorySize { + private seen = new WeakSet(); + + /** + * objectToSize + * + * number:8 bytes (64-bit storage) + * String:一characters 2 bytes + * Boolean:4 bytes + * + * @param object + */ + objectToSize(object: any): any { + const objType = typeof object; + switch (objType) { + case 'string': + return object.length * 2; + case 'boolean': + return 4; + case 'number': + return 8; + case 'object': + if (Array.isArray(object)) { + return object.map(this.objectToSize).reduce((res, cur) => res + cur, 0); + } else { + return this.sizeOfObj(object); + } + default: + return 0; + } + } + + sizeOfObj(object: any): number { + if (object === null) return 0; + + let bytes = 0; + // The key in the object also takes up memory space + const props = Object.keys(object); + for (let i = 0; i < props.length; i++) { + const key = props[i]; + // Whether the value is repeated or not, the key needs to be calculated + bytes += this.objectToSize(key); + if (typeof object[key] === 'object' && object[key] !== null) { + // 这里需要注意value使用相同内存空间(只需计算一次内存) + if (this.seen.has(object[key])) continue; + this.seen.add(object[key]); + } + bytes += this.objectToSize(object[key]); + } + return bytes; + } +} diff --git a/ide/src/hdc/common/Serialize.ts b/ide/src/hdc/common/Serialize.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7b21675a3811362134c30abbdc55e44f9d74783 --- /dev/null +++ b/ide/src/hdc/common/Serialize.ts @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2022 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 { WireType } from '../message/WireType.js'; +import { SessionHandShake } from '../message/SessionHandShake.js'; +import { PayloadProtect } from '../message/PayloadProtect.js'; +import { TransferConfig } from '../message/TransferConfig.js'; +import { TransferPayload } from '../message/TransferPayload.js'; +import { log } from '../../log/Log.js'; + +export class Serialize { + static bannerByteLength: number = 8; + + static serializeSessionHandShake(handShake: SessionHandShake): Uint8Array { + let bannerValue = this.serializeToString(1, handShake.banner); + let authTypeValue = this.serializeU8(2, handShake.authType); + let sessionIdValue = this.serializeU32(3, handShake.sessionId); + let connectKey = this.serializeToString(4, handShake.connectKey); + let buf = this.serializeToString(5, handShake.buf); + let mergedArray = new Uint8Array( + bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length + buf.length + ); + mergedArray.set(bannerValue); + mergedArray.set(authTypeValue, bannerValue.length); + mergedArray.set(sessionIdValue, bannerValue.length + authTypeValue.length); + mergedArray.set(connectKey, bannerValue.length + authTypeValue.length + sessionIdValue.length); + mergedArray.set(buf, bannerValue.length + authTypeValue.length + sessionIdValue.length + connectKey.length); + return mergedArray; + } + + static serializePayloadProtect(payloadProtect: PayloadProtect): Uint8Array { + let channelId = this.serializeU32(1, payloadProtect.channelId); + let commandFlag = this.serializeU32(2, payloadProtect.commandFlag); + let checkSum = this.serializeU8(3, payloadProtect.checkSum); + let vCode = this.serializeU8(4, payloadProtect.vCode); + let mergedArray = new Uint8Array(channelId.length + commandFlag.length + checkSum.length + vCode.length); + mergedArray.set(channelId); + mergedArray.set(commandFlag, channelId.length); + mergedArray.set(checkSum, channelId.length + commandFlag.length); + mergedArray.set(vCode, channelId.length + commandFlag.length + checkSum.length); + return mergedArray; + } + + static serializeTransferConfig(transferConfig: TransferConfig): Uint8Array { + let fileSizeValue = this.serializeU64(1, transferConfig.fileSize); + let atimeValue = this.serializeU64(2, transferConfig.atime); + let mtimeValue = this.serializeU64(3, transferConfig.mtime); + let optionsValue = this.serializeToString(4, transferConfig.options); + let pathValue = this.serializeToString(5, transferConfig.path); + let optionalNameValue = this.serializeToString(6, transferConfig.optionalName); + let updateIfNewValue = this.serializeU32(7, transferConfig.updateIfNew ? 1 : 0); + let compressTypeValue = this.serializeU8(8, transferConfig.compressType); + let holdTimestampValue = this.serializeU32(9, transferConfig.holdTimestamp ? 1 : 0); + let functionNameValue = this.serializeToString(10, transferConfig.functionName); + let clientCwdValue = this.serializeToString(11, transferConfig.clientCwd); + let reserve1Value = this.serializeToString(12, transferConfig.reserve1); + let reserve2Value = this.serializeToString(13, transferConfig.reserve2); + let mergedArray = new Uint8Array( + fileSizeValue.length + + atimeValue.length + + mtimeValue.length + + optionsValue.length + + pathValue.length + + optionalNameValue.length + + updateIfNewValue.length + + compressTypeValue.length + + holdTimestampValue.length + + functionNameValue.length + + clientCwdValue.length + + reserve1Value.length + + reserve2Value.length + ); + let offset = 0; + mergedArray.set(fileSizeValue); + offset += fileSizeValue.length; + mergedArray.set(atimeValue, offset); + offset += atimeValue.length; + mergedArray.set(mtimeValue, offset); + offset += mtimeValue.length; + mergedArray.set(optionsValue, offset); + offset += optionsValue.length; + mergedArray.set(pathValue, offset); + offset += pathValue.length; + mergedArray.set(optionalNameValue, offset); + offset += optionalNameValue.length; + mergedArray.set(updateIfNewValue, offset); + offset += updateIfNewValue.length; + mergedArray.set(compressTypeValue, offset); + offset += compressTypeValue.length; + mergedArray.set(holdTimestampValue, offset); + offset += holdTimestampValue.length; + mergedArray.set(functionNameValue, offset); + offset += functionNameValue.length; + mergedArray.set(clientCwdValue, offset); + offset += clientCwdValue.length; + mergedArray.set(reserve1Value, offset); + offset += reserve1Value.length; + mergedArray.set(reserve2Value, offset); + return mergedArray; + } + + static serializeTransferPayload(transferPayload: TransferPayload): Uint8Array { + let indexValue = this.serializeU64(1, transferPayload.index); + let compressTypeValue = this.serializeU8(2, transferPayload.compressType); + let compressSizeValue = this.serializeU32(3, transferPayload.compressSize); + let uncompressSizeValue = this.serializeU32(4, transferPayload.uncompressSize); + let mergedArray = new Uint8Array( + indexValue.length + compressTypeValue.length + compressSizeValue.length + uncompressSizeValue.length + ); + let offset = 0; + mergedArray.set(indexValue); + offset += indexValue.length; + mergedArray.set(compressTypeValue, offset); + offset += compressTypeValue.length; + mergedArray.set(compressSizeValue, offset); + offset += compressSizeValue.length; + mergedArray.set(uncompressSizeValue, offset); + return mergedArray; + } + + static serializeToString(tag: number, value: string): Uint8Array { + let number = this.makeTagWireType(tag, WireType.LENGTH_DELIMETED); + let data = this.writeVarIntU32(number); + let dataLength = this.writeVarIntU32(value.length); + const encoder = new TextEncoder(); + const buffer = encoder.encode(value); + let stringValue = new Uint8Array(data.length + dataLength.length + buffer.length); + stringValue.set(data); + stringValue.set(dataLength, data.length); + stringValue.set(buffer, data.length + dataLength.length); + return stringValue; + } + + static serializeU8(tag: number, value: number): Uint8Array { + return this.serializeU32(tag, value); + } + + static serializeU32(tag: number, value: number): Uint8Array { + let makeTagWireType = this.writeTagWriteType(tag, WireType.VARINT); + let writeVarInt = this.writeVarIntU32(value); + let mergedArray = new Uint8Array(makeTagWireType.length + writeVarInt.length); + mergedArray.set(makeTagWireType); + mergedArray.set(writeVarInt, makeTagWireType.length); + return mergedArray; + } + + static serializeU64(tag: number, value: number): Uint8Array { + let makeTagWireType = this.writeTagWriteType(tag, WireType.VARINT); + let writeVarInt = this.writeVarIntU64(value); + let mergedArray = new Uint8Array(makeTagWireType.length + writeVarInt.length); + mergedArray.set(makeTagWireType); + mergedArray.set(writeVarInt, makeTagWireType.length); + return mergedArray; + } + + static writeTagWriteType(tag: number, wireType: number): Uint8Array { + let number = this.makeTagWireType(tag, wireType); + return this.writeVarIntU32(number); + } + + static makeTagWireType(tag: number, wireType: number): number { + return (tag << 3) | wireType; + } + + static writeVarIntU64(value: number): Uint8Array { + let buffer: number[] = []; + for (let index = 0; index < 10; index++) { + buffer[index] = value & 0b01111111; + value = value >> 7; + if (value) { + buffer[index] = buffer[index] | 0b10000000; + } else { + break; + } + } + return new Uint8Array(buffer); + } + + static writeVarIntU32(value: number): Uint8Array { + let buffer: number[] = []; + for (let index = 0; index < 5; index++) { + buffer[index] = value & 0b01111111; + value = value >> 7; + if (value) { + buffer[index] = buffer[index] | 0b10000000; + } else { + break; + } + } + return new Uint8Array(buffer); + } + + static parseHandshake(data: Uint8Array): SessionHandShake { + // banner + let bannerBuffer = data.buffer; + let bannerTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(bannerBuffer)); + let bannerLengthBuf = bannerBuffer.slice(1); + let bannerSize = this.readVarIntU32(new DataView(bannerLengthBuf)); + let bannerDataBuffer = bannerLengthBuf.slice(1); + let banner = this.parseString(bannerDataBuffer, bannerSize); + + // authType + let authBuffer = bannerDataBuffer.slice(bannerSize); + let authTypeTag = this.getTag(WireType.VARINT, new DataView(authBuffer)); + let authDataBuffer = authBuffer.slice(1); + let authTypeDataView = new DataView(authDataBuffer); + let authType = this.parseU8(authTypeDataView, 1); + + // sessionId + let sessionIdBuffer = authDataBuffer.slice(1); + let sessionIdTag = this.getTag(WireType.VARINT, new DataView(sessionIdBuffer)); + let sessionDataBuffer = sessionIdBuffer.slice(1); + let sessionIdDataView = new DataView(sessionDataBuffer); + let sessionId = this.parseU32(sessionIdDataView, 3); + + // connectKey + let connectKeyBuffer = sessionDataBuffer.slice(3); + let connectKeyTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(connectKeyBuffer)); + let connectLengthBuffer = connectKeyBuffer.slice(1); + let connectKeyDataView = new DataView(connectLengthBuffer); + let connectKeySize = this.readVarIntU32(connectKeyDataView); + let connectDataBuffer = connectLengthBuffer.slice(1); + let connectKey = this.parseString(connectDataBuffer, connectKeySize); + + // buf + let bufBuffer = connectDataBuffer.slice(connectKeySize); + let bufTag = this.getTag(WireType.LENGTH_DELIMETED, new DataView(bufBuffer)); + let lengthBuffer = bufBuffer.slice(1); + let bufDataView = new DataView(lengthBuffer); + let bufSize = this.readVarIntU32(bufDataView); + let dataBuffer = lengthBuffer.slice(1); + let buf = this.parseString(dataBuffer, bufSize); + return new SessionHandShake(banner, authType, sessionId, connectKey, buf); + } + + static parseTransferConfig(data: ArrayBuffer): TransferConfig { + let uint8Array = new Uint8Array(data); + // channelId + let dataBuffer = uint8Array.buffer; + let channelTag = this.getTag(WireType.VARINT, new DataView(dataBuffer)); + let channelDataBuffer = dataBuffer.slice(1); + let channelDataView = new DataView(channelDataBuffer); + let fileSize = this.parseU64(channelDataView, 1); + console.log('parseTransferConfig fileSize,', fileSize); + return new TransferConfig(fileSize, 0, 0, '', '', '', false, 0, false, '', '', '', ''); + } + + static parsePayloadProtect(data: ArrayBuffer): PayloadProtect { + let uint8Array = new Uint8Array(data); + + // channelId + let dataBuffer = uint8Array.buffer; + let channelTag = this.getTag(WireType.VARINT, new DataView(dataBuffer)); + let channelDataBuffer = dataBuffer.slice(1); + let channelDataView = new DataView(channelDataBuffer); + let channelId = this.parseU32(channelDataView, 1); + + // commandFlag + let commandTagBuffer = channelDataBuffer.slice(1); + let commandTag = this.getTag(WireType.VARINT, new DataView(commandTagBuffer)); + let commandDataBuffer = commandTagBuffer.slice(1); + let commandDataView = new DataView(commandDataBuffer); + let commandFlag = this.parseU32(commandDataView, 1); + + // checkSum + let checkSumTagBuffer = commandDataBuffer.slice(1); + let checkSumTag = this.getTag(WireType.VARINT, new DataView(checkSumTagBuffer)); + let checkSumDataBuffer = checkSumTagBuffer.slice(1); + let checkSumDataView = new DataView(checkSumDataBuffer); + let checkSum = this.parseU8(checkSumDataView, 1); + + // vCode + let vCodeTagBuffer = checkSumDataBuffer.slice(1); + let vCodeTag = this.getTag(WireType.VARINT, new DataView(vCodeTagBuffer)); + let vCodeDataBuffer = vCodeTagBuffer.slice(1); + let vCodeDataView = new DataView(vCodeDataBuffer); + let vCode = this.parseU8(vCodeDataView, 1); + + return new PayloadProtect(channelId, commandFlag, checkSum, vCode); + } + + static parseString(buffer: ArrayBuffer, size: number): string { + let arrayBuffer = buffer.slice(0, size); + let textDecoder = new TextDecoder(); + return textDecoder.decode(arrayBuffer); + } + + static parseU8(dataView: DataView, size: number): number { + return this.parseU32(dataView, size); + } + + static parseU32(dataView: DataView, size: number): number { + return this.readVarIntU32(dataView); + } + + static parseU64(dataView: DataView, size: number): number { + return this.readVarIntU64(dataView); + } + + static readVarIntU32(dataView: DataView): number { + let value: number = 0; + for (let index = 0; index < 5; index++) { + if (dataView.byteLength < index + 1) { + return -1; + } + let int8 = dataView.getUint8(index); + let readValue = int8 & 0b01111111; + value |= readValue << (7 * index); + if (!(int8 & 0b10000000)) { + return value; + } + } + return -1; + } + + static readVarIntU64(dataView: DataView): number { + let value: number = 0; + for (let index = 0; index < 10; index++) { + if (dataView.byteLength < index + 1) { + return -1; + } + let int8 = dataView.getUint8(index); + let readValue = int8 & 0b01111111; + value |= readValue << (7 * index); + if (!(int8 & 0b10000000)) { + return value; + } + } + return -1; + } + + static readTagWireType(tagKey: number) { + let wireNewType: WireType = tagKey & 0b0111; + return tagKey >> 3; + } + + static getTag(wireType: WireType, dataView: DataView) { + let tagKey = this.readVarIntU32(dataView); + return this.readTagWireType(tagKey); + } +} diff --git a/ide/src/hdc/common/Utils.ts b/ide/src/hdc/common/Utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..84ba571056c8a48802920f0f4f89fe63803057e2 --- /dev/null +++ b/ide/src/hdc/common/Utils.ts @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 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 { FormatCommand } from '../hdcclient/FormatCommand.js'; +import { warn } from '../../log/Log.js'; + +export class Utils { + private static localId = 1; + + public static getSessionId(): number { + return Math.round(Math.random() * 100000000); + } + + public static getLocalId(): number { + if (this.localId == 4294967295) { + this.localId = 1; + } + return this.localId++; + } + + public static formatCommand(cmd: string): FormatCommand { + let command = cmd; + if (cmd.startsWith('hdc_std')) { + command = command.substring('hdc_std '.length); + } else if (cmd.startsWith('hdc')) { + command = command.substring('hdc '.length); + } + let formatCommand = FormatCommand.string2FormatCommand(command); + // formatCommand Success + if (formatCommand.cmdFlag <= -1) { + warn('command : ' + command + ' is not Support'); + } + return formatCommand; + } + + public static numToHexString(num: number): string { + if (num == undefined || num == null || isNaN(num)) { + return '0x0'; + } + if (num < 0) { + return '0x' + (num >>> 0).toString(16); + } else { + return '0x' + num.toString(16); + } + } +} diff --git a/ide/src/hdc/hdcclient/AsyncQueue.ts b/ide/src/hdc/hdcclient/AsyncQueue.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b2099451a99096dd43cb431424afa42e691b361 --- /dev/null +++ b/ide/src/hdc/hdcclient/AsyncQueue.ts @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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 { DataMessage } from '../message/DataMessage.js'; + +export class DataMessageQueue { + private eleArray: Array; + + constructor() { + this.eleArray = new Array(); + } + + public push(entry: T): boolean { + if (entry == null) { + return false; + } + this.eleArray.unshift(entry); + return true; + } + + public pop(): T | undefined { + return this.eleArray.pop(); + } + + public size(): number { + return this.eleArray.length; + } +} + +interface Resolver { + (data: DataMessage): void; +} + +export class AsyncQueue { + private promiseQueue: DataMessageQueue> = new DataMessageQueue>(); + private resolverQueue: DataMessageQueue = new DataMessageQueue(); + + add() { + this.promiseQueue.push( + new Promise((resolve) => { + this.resolverQueue.push(resolve); + }) + ); + } + + enqueue(item: DataMessage) { + if (this.resolverQueue.size() == 0) { + this.add(); + } + const resolve = this.resolverQueue.pop(); + resolve ? resolve(item) : null; + } + + async dequeue(): Promise { + if (this.promiseQueue.size() == 0) { + this.add(); + } + return this.promiseQueue.pop() || new Promise(() => {}); + } +} diff --git a/ide/src/hdc/hdcclient/DataListener.ts b/ide/src/hdc/hdcclient/DataListener.ts new file mode 100644 index 0000000000000000000000000000000000000000..b741e1fa223ed416cf2bb1165b3a0df3924204a4 --- /dev/null +++ b/ide/src/hdc/hdcclient/DataListener.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2022 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 { DataMessage } from '../message/DataMessage.js'; + +export interface DataListener { + createDataMessage(data: DataMessage): void; +} diff --git a/ide/src/hdc/hdcclient/FormatCommand.ts b/ide/src/hdc/hdcclient/FormatCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..46eeab31f7628aca790d7dcf40a285e6dab14547 --- /dev/null +++ b/ide/src/hdc/hdcclient/FormatCommand.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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 { HdcCommand } from './HdcCommand.js'; +import { CMDSTR_FILE_RECV, CMDSTR_FILE_SEND, CMDSTR_SHELL } from '../common/ConstantType.js'; +import { log } from '../../log/Log.js'; + +export class FormatCommand { + cmdFlag: number; // uint16_t + parameters: string; //string + bJumpDo: boolean; // boolean + + constructor(cmdFlag: number, parameters: string, bJumpDo: boolean) { + this.cmdFlag = cmdFlag; + this.parameters = parameters; + this.bJumpDo = bJumpDo; + } + + static string2FormatCommand(cmd: string): FormatCommand { + log('Command : ' + cmd); + let formatCommand = new FormatCommand(-1, '', false); + if (cmd.startsWith(CMDSTR_SHELL + ' ')) { + formatCommand.cmdFlag = HdcCommand.CMD_UNITY_EXECUTE; + formatCommand.parameters = cmd.substring((CMDSTR_SHELL + ' ').length); + } else if (cmd.startsWith(CMDSTR_SHELL)) { + formatCommand.cmdFlag = HdcCommand.CMD_SHELL_INIT; + } else if (cmd.startsWith(CMDSTR_FILE_RECV)) { + formatCommand.cmdFlag = HdcCommand.CMD_FILE_INIT; + formatCommand.parameters = cmd.substring((CMDSTR_FILE_RECV + ' ').length); + } else if (cmd.startsWith(CMDSTR_FILE_SEND)) { + formatCommand.cmdFlag = HdcCommand.CMD_FILE_INIT; + formatCommand.parameters = cmd.substring((CMDSTR_FILE_SEND + ' ').length); + } else { + formatCommand.bJumpDo = true; + } + log('formatCommand cmdFlag is : ' + formatCommand.cmdFlag); + log('formatCommand parameters is : ' + formatCommand.parameters); + log('formatCommand bJumpDo is : ' + formatCommand.bJumpDo); + return formatCommand; + } +} diff --git a/ide/src/hdc/hdcclient/HdcClient.ts b/ide/src/hdc/hdcclient/HdcClient.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a7b56b9da8d7a66c9b7074f7feb7deff111bd43 --- /dev/null +++ b/ide/src/hdc/hdcclient/HdcClient.ts @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2022 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 { Serialize } from '../common/Serialize.js'; +import { HdcCommand } from './HdcCommand.js'; +import { Utils } from '../common/Utils.js'; +import { HANDSHAKE_MESSAGE } from '../common/ConstantType.js'; +import { PayloadHead } from '../message/PayloadHead.js'; +import { TransmissionInterface } from '../transmission/TransmissionInterface.js'; +import { DataProcessing } from '../transmission/DataProcessing.js'; +import { DataListener } from './DataListener.js'; +import { DataMessage } from '../message/DataMessage.js'; +import { SessionHandShake } from '../message/SessionHandShake.js'; +import { AuthType } from '../message/AuthType.js'; +import { debug, log } from '../../log/Log.js'; +import { HdcStream } from './HdcStream.js'; +import { toHex16 } from '../common/BaseConversion.js'; + +export class HdcClient implements DataListener { + // @ts-ignore + usbDevice: USBDevice | undefined; + sessionId: number = 0; + private transmissionChannel: TransmissionInterface; + public readDataProcessing: DataProcessing; + private stream: HdcStream | undefined | null; + private hdcStopStream: HdcStream | undefined | null; + private cmdStream: number = -1; + private stopStream: number = -1; + + constructor( + transmissionChannel: TransmissionInterface, + // @ts-ignore + usbDevice: USBDevice | undefined + ) { + this.transmissionChannel = transmissionChannel; + this.usbDevice = usbDevice; + this.readDataProcessing = new DataProcessing(this, transmissionChannel); + } + + async connectDevice(): Promise { + debug('start Connect Device'); + this.sessionId = Utils.getSessionId(); + log('sessionId is ' + this.sessionId); + // @ts-ignore + let handShake: SessionHandShake = new SessionHandShake( + HANDSHAKE_MESSAGE, + AuthType.AUTH_NONE, + this.sessionId, + // @ts-ignore + this.usbDevice.serialNumber, + '' + ); + let hs = Serialize.serializeSessionHandShake(handShake); + debug('start Connect hs ', hs); + let sendResult = await this.readDataProcessing.send( + handShake.sessionId, + 0, + HdcCommand.CMD_KERNEL_HANDSHAKE, + hs, + hs.length + ); + if (sendResult) { + let handShake = await this.readDataProcessing.readUsbHead(); + let handBody = await this.readDataProcessing.readBody(handShake!.dataSize); + if (this.sessionId == handShake!.sessionId) { + debug('handShake: ', handShake); + let playHeadArray = handBody.buffer.slice(0, PayloadHead.getPayloadHeadLength()); + let resultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(playHeadArray)); + debug('resultPayloadHead is ', resultPayloadHead); + let headSize = resultPayloadHead.headSize; + let dataSize = resultPayloadHead.dataSize; + let resPlayProtectBuffer = handBody.buffer.slice( + PayloadHead.getPayloadHeadLength(), + PayloadHead.getPayloadHeadLength() + headSize + ); + debug('PlayProtect is ', resPlayProtectBuffer); + let resData = handBody.buffer.slice( + PayloadHead.getPayloadHeadLength() + headSize, + PayloadHead.getPayloadHeadLength() + headSize + dataSize + ); + debug('resData is ', resData); + this.readDataProcessing.startReadData().then(() => {}); + return true; + } else { + log( + 'session is not eq handShake?.sessionId is : ' + handShake?.sessionId + ' now session is ' + this.sessionId + ); + return false; + } + } else { + return false; + } + } + + public async disconnect(): Promise { + try { + await this.transmissionChannel.close(); + this.readDataProcessing.stopReadData(); + } catch (e) {} + } + + public bindStream(channel: number, hdcStream: HdcStream) { + this.cmdStream = channel; + this.stream = hdcStream; + } + + public bindStopStream(channel: number, hdcStopStream: HdcStream) { + this.stopStream = channel; + this.hdcStopStream = hdcStopStream; + } + + public unbindStream(channel: number): boolean { + this.stream = null; + return this.stream == null; + } + + public unbindStopStream(channel: number): boolean { + this.hdcStopStream = null; + return this.hdcStopStream == null; + } + + createDataMessage(data: DataMessage): void { + if (this.hdcStopStream && data.getChannelId() == this.stopStream) { + this.hdcStopStream.putMessageInQueue(data); + } + if (this.stream && data.getChannelId() == this.cmdStream) { + this.stream.putMessageInQueue(data); + } + if (data.getChannelId() == -1) { + this.stream?.putMessageInQueue(data); + this.hdcStopStream?.putMessageInQueue(data); + } + } +} diff --git a/ide/src/hdc/hdcclient/HdcCommand.ts b/ide/src/hdc/hdcclient/HdcCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..a411dcbbd7053333207403d4c3c5cc897d13908a --- /dev/null +++ b/ide/src/hdc/hdcclient/HdcCommand.ts @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2022 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. + */ + +export enum HdcCommand { + // core commands types + CMD_KERNEL_HELP = 0, + CMD_KERNEL_HANDSHAKE = 1, + CMD_KERNEL_CHANNEL_CLOSE = 2, + CMD_KERNEL_SERVER_KILL = 3, + CMD_KERNEL_TARGET_DISCOVER = 4, + CMD_KERNEL_TARGET_LIST = 5, + CMD_KERNEL_TARGET_ANY = 6, + CMD_KERNEL_TARGET_CONNECT = 7, + CMD_KERNEL_TARGET_DISCONNECT = 8, + CMD_KERNEL_ECHO = 9, + CMD_KERNEL_ECHO_RAW = 10, + CMD_KERNEL_ENABLE_KEEPALIVE = 11, + CMD_KERNEL_WAKEUP_SLAVETASK = 12, + // One-pass simple commands + CMD_UNITY_COMMAND_HEAD = 1000, // not use + CMD_UNITY_EXECUTE = 1001, + CMD_UNITY_REMOUNT = 1002, + CMD_UNITY_REBOOT = 1003, + CMD_UNITY_RUNMODE = 1004, + CMD_UNITY_HILOG = 1005, + CMD_UNITY_TERMINATE = 1006, + CMD_UNITY_ROOTRUN = 1007, + CMD_JDWP_LIST = 1008, + CMD_JDWP_TRACK = 1009, + CMD_UNITY_COMMAND_TAIL = 1010, // not use + // It will be separated from unity in the near future + CMD_UNITY_BUGREPORT_INIT = 1011, + CMD_UNITY_BUGREPORT_DATA = 1012, + // Shell commands types + CMD_SHELL_INIT = 2000, + CMD_SHELL_DATA = 2001, + // File commands + CMD_FILE_INIT = 3000, + CMD_FILE_CHECK = 3001, + CMD_FILE_BEGIN = 3002, + CMD_FILE_DATA = 3003, + CMD_FILE_FINISH = 3004, + // App commands + CMD_APP_SIDELOAD = 3005, + CMD_APP_INIT = 3500, + CMD_APP_CHECK = 3501, + CMD_APP_BEGIN = 3502, + CMD_APP_DATA = 3503, + CMD_APP_FINISH = 3504, + CMD_APP_UNINSTALL = 3505, +} diff --git a/ide/src/hdc/hdcclient/HdcStream.ts b/ide/src/hdc/hdcclient/HdcStream.ts new file mode 100644 index 0000000000000000000000000000000000000000..31a24c073f3d757f2f9d6f51c528117c0c11f2cd --- /dev/null +++ b/ide/src/hdc/hdcclient/HdcStream.ts @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 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 { DataMessage } from '../message/DataMessage.js'; +import { HdcClient } from './HdcClient.js'; +import { FormatCommand } from './FormatCommand.js'; +import { HdcCommand } from './HdcCommand.js'; +import { Utils } from '../common/Utils.js'; +import { AsyncQueue } from './AsyncQueue.js'; +import { toHex16 } from '../common/BaseConversion.js'; +import { PayloadHead } from '../message/PayloadHead.js'; +import { Serialize } from '../common/Serialize.js'; + +export class HdcStream { + private dataMessages: AsyncQueue = new AsyncQueue(); + private readonly channelId: number; + private interactiveShellMode: boolean = false; + private hdcClient: HdcClient; + public fileSize: number = -1; + + constructor(hdcClient: HdcClient, isStopCmd: boolean) { + this.hdcClient = hdcClient; + this.channelId = Utils.getLocalId(); + if (isStopCmd) { + this.hdcClient.bindStopStream(this.channelId, this); + } else { + this.hdcClient.bindStream(this.channelId, this); + } + } + + public async DoCommand(cmd: string): Promise { + let formatCommand; + if (this.interactiveShellMode) { + formatCommand = new FormatCommand(HdcCommand.CMD_SHELL_DATA, cmd, false); + } else { + formatCommand = Utils.formatCommand(cmd); + } + return this.DoCommandRemote(formatCommand); + } + + public async DoCommandRemote(command: FormatCommand): Promise { + switch (command.cmdFlag) { + case HdcCommand.CMD_SHELL_INIT: + case HdcCommand.CMD_SHELL_DATA: + case HdcCommand.CMD_UNITY_EXECUTE: + case HdcCommand.CMD_UNITY_TERMINATE: + case HdcCommand.CMD_UNITY_REMOUNT: + case HdcCommand.CMD_UNITY_REBOOT: + case HdcCommand.CMD_UNITY_RUNMODE: + case HdcCommand.CMD_UNITY_HILOG: { + let textEncoder = new TextEncoder(); + let data = textEncoder.encode(command.parameters); + let sendResult = await this.sendToDaemon(command, data, data.length); + if (sendResult) { + if (HdcCommand.CMD_SHELL_INIT == command.cmdFlag) { + this.interactiveShellMode = true; + } + } + break; + } + case HdcCommand.CMD_FILE_INIT: { + await this.FileRecvCommand(command); + break; + } + case HdcCommand.CMD_FILE_FINISH: + case HdcCommand.CMD_KERNEL_CHANNEL_CLOSE: { + let dataView = new DataView(new ArrayBuffer(1)); + if (command.parameters == '0') { + dataView.setUint8(0, 0); + } else { + dataView.setUint8(0, 1); + } + await this.sendToDaemon(command, new Uint8Array(dataView.buffer), 1); + break; + } + } + return false; + } + + async FileRecvCommand(command: FormatCommand) { + let sizeSend = command.parameters.length; + let cmdFlag: string = ''; + let sizeCmdFlag: number = 0; + if (HdcCommand.CMD_FILE_INIT == command.cmdFlag) { + cmdFlag = 'send '; + sizeCmdFlag = 5; // 5: cmdFlag send size + } + if (!(command.parameters.length > cmdFlag.length)) { + } else { + let textEncoder = new TextEncoder(); + let data = textEncoder.encode(command.parameters); + let aa = data.slice(5); + await this.sendToDaemon(command, aa, aa.length); + let dataMessage = await this.getMessage(); + let playHeadArray = dataMessage.body!.buffer.slice(0, PayloadHead.getPayloadHeadLength()); + let resultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(playHeadArray)); + let headSize = resultPayloadHead.headSize; + let dataSize = resultPayloadHead.dataSize; + let resPlayProtectBuffer = dataMessage.body!.buffer.slice(11, 11 + headSize); + let payloadProtect = Serialize.parsePayloadProtect(resPlayProtectBuffer); + await this.handleCommandFileCheck(); + } + } + + private async handleCommandFileCheck() { + let dataMessage = await this.getMessage(); + let playHeadArray = dataMessage.body!.buffer.slice(0, PayloadHead.getPayloadHeadLength()); + let resultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(playHeadArray)); + let headSize = resultPayloadHead.headSize; + let dataSize = resultPayloadHead.dataSize; + let resPlayProtectBuffer = dataMessage.body!.buffer.slice( + PayloadHead.getPayloadHeadLength(), + PayloadHead.getPayloadHeadLength() + headSize + ); + let payloadProtect = Serialize.parsePayloadProtect(resPlayProtectBuffer); + if (payloadProtect.commandFlag == HdcCommand.CMD_FILE_CHECK) { + if (dataSize > 0) { + let transferConfigBuffer = dataMessage.body!.buffer.slice( + PayloadHead.getPayloadHeadLength() + headSize, + PayloadHead.getPayloadHeadLength() + headSize + dataSize + ); + let transferConfig = Serialize.parseTransferConfig(transferConfigBuffer); + this.fileSize = transferConfig.fileSize; + } + let fileBegin = new FormatCommand(HdcCommand.CMD_FILE_BEGIN, '', false); + await this.sendToDaemon(fileBegin, new Uint8Array(0), 0); + } + } + + async sendToDaemon(command: FormatCommand, payload: Uint8Array, dataLength: number): Promise { + return await this.hdcClient.readDataProcessing.send( + this.hdcClient.sessionId, + this.channelId, + command.cmdFlag, + payload, + dataLength + ); + } + + putMessageInQueue(dataMessage: DataMessage) { + this.dataMessages.enqueue(dataMessage); + } + + getMessage(): Promise { + return this.dataMessages.dequeue(); + } + + closeStream() { + this.hdcClient.unbindStream(this.channelId); + } + + closeStopStream() { + this.hdcClient.unbindStopStream(this.channelId); + } +} diff --git a/ide/src/hdc/hdcclient/UsbProtocolOption.ts b/ide/src/hdc/hdcclient/UsbProtocolOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..abdca077e48301951951253557acdae53755cb22 --- /dev/null +++ b/ide/src/hdc/hdcclient/UsbProtocolOption.ts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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. + */ + +export enum UsbProtocolOption { + USB_OPTION_HEADER = 1, + USB_OPTION_RESET = 2, + USB_OPTION_RESERVE4 = 4, + USB_OPTION_RESERVE8 = 8, + USB_OPTION_RESERVE16 = 16, +} diff --git a/ide/src/hdc/message/AuthType.ts b/ide/src/hdc/message/AuthType.ts new file mode 100644 index 0000000000000000000000000000000000000000..4962a481f723d2b2cadeb1067d30178d1c9f008e --- /dev/null +++ b/ide/src/hdc/message/AuthType.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ + +export class AuthType { + static AUTH_NONE: number = 0; // uint8 + static AUTH_TOKEN: number = 1; // uint8 + static AUTH_SIGNATURE: number = 2; //uint8 + static AUTH_PUBLICKEY: number = 3; //uint8 + static AUTH_OK: number = 4; //uint8 + + static getAuthTypeLength() { + return 1; + } +} diff --git a/ide/src/hdc/message/BaseBean.ts b/ide/src/hdc/message/BaseBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2566c8243671d6d89dc95312309ab6c27601ea6 --- /dev/null +++ b/ide/src/hdc/message/BaseBean.ts @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2022 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. + */ + +export interface BaseBean { + getDataView(): DataView; +} diff --git a/ide/src/hdc/message/DataMessage.ts b/ide/src/hdc/message/DataMessage.ts new file mode 100644 index 0000000000000000000000000000000000000000..811205a352fe7b18aa97942134a1c2e8de9bb0e0 --- /dev/null +++ b/ide/src/hdc/message/DataMessage.ts @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 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 { USBHead } from './USBHead.js'; +import { debug, log } from '../../log/Log.js'; +import { PayloadHead } from './PayloadHead.js'; +import { Serialize } from '../common/Serialize.js'; +import { Utils } from '../common/Utils.js'; +import { HdcCommand } from '../hdcclient/HdcCommand.js'; + +export class DataMessage extends Object { + body?: DataView; + + private _usbHead: USBHead; + private _channelId: number = -1; + private _result: string = ''; + private _channelClose: boolean = false; + private _resArrayBuffer: ArrayBuffer | undefined; + private _commandFlag: number = -1; + + constructor(usbHead: USBHead, body?: DataView) { + super(); + this._usbHead = usbHead; + this.body = body; + if (this.body) { + this.splitData(); + } + } + + splitData() { + let playHeadArray = this.body!.buffer.slice(0, 11); + let resultPayloadHead: PayloadHead = PayloadHead.parsePlayHead(new DataView(playHeadArray)); + let headSize = resultPayloadHead.headSize; + let dataSize = resultPayloadHead.dataSize; + let resultPlayProtectBuffer = this.body!.buffer.slice(11, 11 + headSize); + let payloadProtect = Serialize.parsePayloadProtect(resultPlayProtectBuffer); + this._channelId = payloadProtect.channelId; + this._commandFlag = payloadProtect.commandFlag; + if (payloadProtect.commandFlag == HdcCommand.CMD_KERNEL_CHANNEL_CLOSE) { + log('commandFlag: ' + payloadProtect.commandFlag); + this._channelClose = true; + } else { + if (dataSize > 0) { + this._resArrayBuffer = this.body!.buffer.slice(11 + headSize, 11 + headSize + dataSize); + } + } + } + + public getChannelId(): number { + return this._channelId; + } + + public getData(): ArrayBuffer | undefined { + return this._resArrayBuffer; + } + + public getDataToString(): string { + let textDecoder = new TextDecoder(); + this._result = textDecoder.decode(this._resArrayBuffer); + return this._result; + } + + get usbHead(): USBHead { + return this._usbHead; + } + + set usbHead(value: USBHead) { + this._usbHead = value; + } + + get channelId(): number { + return this._channelId; + } + + set channelId(value: number) { + this._channelId = value; + } + + get result(): string { + return this._result; + } + + set result(value: string) { + this._result = value; + } + + get channelClose(): boolean { + return this._channelClose; + } + + set channelClose(value: boolean) { + this._channelClose = value; + } + + get resArrayBuffer(): ArrayBuffer | undefined { + return this._resArrayBuffer; + } + + set resArrayBuffer(value: ArrayBuffer | undefined) { + this._resArrayBuffer = value; + } + + get commandFlag(): number { + return this._commandFlag; + } + + set commandFlag(value: number) { + this._commandFlag = value; + } + + toString(): string { + return ( + 'usbHead: ' + + this._usbHead + + ' channelId: ' + + this._channelId + + ' result: ' + + this._result + + ' channelClose: ' + + this._channelClose + + ' commandFlag: ' + + this._commandFlag + ); + } +} diff --git a/ide/src/hdc/message/PayloadHead.ts b/ide/src/hdc/message/PayloadHead.ts new file mode 100644 index 0000000000000000000000000000000000000000..cea209a9892ad845560fc0d484906a6b7c3bb189 --- /dev/null +++ b/ide/src/hdc/message/PayloadHead.ts @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 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 { BaseBean } from './BaseBean.js'; + +export class PayloadHead extends Object implements BaseBean { + private _flag: Array = [0, 0]; //uint8_t ct.c_uint8 * 2 + private _reserve: Array; //uint8_t // encrypt'flag or others options ct.c_uint8 * 2 + private _protocolVer: number; // uint8_t 1 + private _headSize: number = 0; // uint16_t 2 + private _dataSize: number = 0; // uint32_t 4 + + constructor(flag: Array, reserve: Array, protocolVer: number, headSize: number, dataSize: number) { + super(); + this._flag = flag; + this._reserve = reserve; + this._protocolVer = protocolVer; + this._headSize = headSize; + this._dataSize = dataSize; + } + + static getPayloadHeadLength() { + return 11; + } + getDataView(): DataView { + const view = new DataView(new ArrayBuffer(11)); + view.setUint8(0, this._flag[0]); + view.setUint8(1, this._flag[1]); + view.setUint8(2, this._reserve[0]); + view.setUint8(3, this._reserve[1]); + view.setUint8(4, this._protocolVer); + view.setUint16(5, this._headSize, false); + view.setUint32(7, this._dataSize); + return view; + } + + static parsePlayHead(data: DataView): PayloadHead { + let flagZero = data.getUint8(0); + let flagOne = data.getUint8(1); + let reserveZero = data.getUint8(2); + let reserveOne = data.getUint8(3); + let protocolVer = data.getUint8(4); + let headSize = data.getUint16(5); + let dataSize; + if (data.byteLength < 11) { + dataSize = 0; + } else { + dataSize = data.getUint32(7); + } + return new PayloadHead([flagZero, flagOne], [reserveZero, reserveOne], protocolVer, headSize, dataSize); + } + + get flag(): Array { + return this._flag; + } + + set flag(value: Array) { + this._flag = value; + } + + get headSize(): number { + return this._headSize; + } + + set headSize(value: number) { + this._headSize = value; + } + + get dataSize(): number { + return this._dataSize; + } + + set dataSize(value: number) { + this._dataSize = value; + } + + toString(): string { + return 'PayloadHead: ' + this.getDataView.toString() + ', parsePlayHead: ' + PayloadHead.parsePlayHead.toString(); + } +} diff --git a/ide/src/hdc/message/PayloadProtect.ts b/ide/src/hdc/message/PayloadProtect.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc5a935df1645ae142fcd1831691289c2596e0ac --- /dev/null +++ b/ide/src/hdc/message/PayloadProtect.ts @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 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 { BaseBean } from './BaseBean.js'; + +export class PayloadProtect extends Object implements BaseBean { + // reserve for encrypt and decrypt + private _channelId: number; //uint32_t + private _commandFlag: number; //uint32_t + private _checkSum: number; // uint8_t enable it will be lose about 20% speed + private _vCode: number; //uint8_t + + constructor(channelId: number, commandFlag: number, checkSum: number, vCode: number) { + super(); + this._channelId = channelId; + this._commandFlag = commandFlag; + this._checkSum = checkSum; + this._vCode = vCode; + } + + getDataView(): DataView { + return new DataView(new ArrayBuffer(24)); + } + + get channelId(): number { + return this._channelId; + } + + set channelId(value: number) { + this._channelId = value; + } + + get commandFlag(): number { + return this._commandFlag; + } + + set commandFlag(value: number) { + this._commandFlag = value; + } + + get checkSum(): number { + return this._checkSum; + } + + set checkSum(value: number) { + this._checkSum = value; + } + + get vCode(): number { + return this._vCode; + } + + set vCode(value: number) { + this._vCode = value; + } + + toString(): string { + return ( + 'channelId: ' + + this._channelId + + ' commandFlag: ' + + this._commandFlag + + ' checkSum: ' + + this._checkSum + + ' vCode: ' + + this._vCode + ); + } +} diff --git a/ide/src/hdc/message/SessionHandShake.ts b/ide/src/hdc/message/SessionHandShake.ts new file mode 100644 index 0000000000000000000000000000000000000000..a256f76c3047bece31c8ff95530b88fe56cecb61 --- /dev/null +++ b/ide/src/hdc/message/SessionHandShake.ts @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 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 { AuthType } from './AuthType.js'; +import { HANDSHAKE_MESSAGE } from '../common/ConstantType.js'; +import { BaseBean } from './BaseBean.js'; + +export class SessionHandShake extends Object implements BaseBean { + private _banner: string = HANDSHAKE_MESSAGE; // string must first index + private _authType: number = AuthType.AUTH_NONE; // uint8_t auth none + private _sessionId: number = 0; // uint32_t + private _connectKey: string = ''; // string + private _buf: string = ''; // string + private _version: string = ''; + + constructor(banner: string, authType: number, sessionId: number, connectKey: string, buf: string) { + super(); + this._banner = banner; + this._authType = authType; + this._sessionId = sessionId; + this._connectKey = connectKey; + this._buf = buf; + } + + getDataView(): DataView { + const view = new DataView(new ArrayBuffer(24)); + return view; + } + + get banner(): string { + return this._banner; + } + + set banner(value: string) { + this._banner = value; + } + + get authType(): number { + return this._authType; + } + + set authType(value: number) { + this._authType = value; + } + + get sessionId(): number { + return this._sessionId; + } + + set sessionId(value: number) { + this._sessionId = value; + } + + get connectKey(): string { + return this._connectKey; + } + + set connectKey(value: string) { + this._connectKey = value; + } + + get buf(): string { + return this._buf; + } + + set buf(value: string) { + this._buf = value; + } + + get version(): string { + return this._version; + } + + set version(value: string) { + this._version = value; + } + + toString(): string { + return ( + 'banner: ' + + this._banner + + ' authType: ' + + this._authType + + ' sessionId: ' + + this._sessionId + + ' connectKey: ' + + this._connectKey + + ' buf: ' + + this._buf + + ' version: ' + + this._version + ); + } +} diff --git a/ide/src/hdc/message/TransferConfig.ts b/ide/src/hdc/message/TransferConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..42bcefee246fd4893296c7a2846600911bdef01e --- /dev/null +++ b/ide/src/hdc/message/TransferConfig.ts @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2022 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. + */ + +export class TransferConfig extends Object { + private _fileSize: number = -1; // uint64_t + private _atime: number = -1; // uint64_t ns + private _mtime: number = -1; // uint64_t ns + private _options: string = ''; // string + private _path: string = ''; + private _optionalName: string = ''; + private _updateIfNew: boolean = false; //bool + private _compressType: number = CompressType.COMPRESS_NONE; // uint8_t + private _holdTimestamp: boolean = false; //bool + private _functionName: string = ''; + private _clientCwd: string = ''; + private _reserve1: string = ''; + private _reserve2: string = ''; + + constructor( + fileSize: number, + atime: number, + mtime: number, + options: string, + path: string, + optionalName: string, + updateIfNew: boolean, + compressType: number, + holdTimestamp: boolean, + functionName: string, + clientCwd: string, + reserve1: string, + reserve2: string + ) { + super(); + this._fileSize = fileSize; + this._atime = atime; + this._mtime = mtime; + this._options = options; + this._path = path; + this._optionalName = optionalName; + this._updateIfNew = updateIfNew; + this._compressType = compressType; + this._holdTimestamp = holdTimestamp; + this._functionName = functionName; + this._clientCwd = clientCwd; + this._reserve1 = reserve1; + this._reserve2 = reserve2; + } + + get fileSize(): number { + return this._fileSize; + } + + set fileSize(value: number) { + this._fileSize = value; + } + + get atime(): number { + return this._atime; + } + + set atime(value: number) { + this._atime = value; + } + + get mtime(): number { + return this._mtime; + } + + set mtime(value: number) { + this._mtime = value; + } + + get options(): string { + return this._options; + } + + set options(value: string) { + this._options = value; + } + + get path(): string { + return this._path; + } + + set path(value: string) { + this._path = value; + } + + get optionalName(): string { + return this._optionalName; + } + + set optionalName(value: string) { + this._optionalName = value; + } + + get updateIfNew(): boolean { + return this._updateIfNew; + } + + set updateIfNew(value: boolean) { + this._updateIfNew = value; + } + + get compressType(): number { + return this._compressType; + } + + set compressType(value: number) { + this._compressType = value; + } + + get holdTimestamp(): boolean { + return this._holdTimestamp; + } + + set holdTimestamp(value: boolean) { + this._holdTimestamp = value; + } + + get functionName(): string { + return this._functionName; + } + + set functionName(value: string) { + this._functionName = value; + } + + get clientCwd(): string { + return this._clientCwd; + } + + set clientCwd(value: string) { + this._clientCwd = value; + } + + get reserve1(): string { + return this._reserve1; + } + + set reserve1(value: string) { + this._reserve1 = value; + } + + get reserve2(): string { + return this._reserve2; + } + + set reserve2(value: string) { + this._reserve2 = value; + } + + toString(): string { + return ( + 'fileSize: ' + + this._fileSize + + ' atime: ' + + this._atime + + ' mtime: ' + + this._mtime + + ' options: ' + + this._options + + ' path: ' + + this._path + + ' optionalName: ' + + this._optionalName + + ' updateIfNew: ' + + this._updateIfNew + + ' compressType: ' + + this._compressType + + ' holdTimestamp: ' + + this._holdTimestamp + + ' functionName: ' + + this._functionName + + ' clientCwd: ' + + this._clientCwd + + ' reserve1: ' + + this._reserve1 + + ' reserve2: ' + + this._reserve2 + ); + } +} + +enum CompressType { + COMPRESS_NONE, + COMPRESS_LZ4, + COMPRESS_LZ77, + COMPRESS_LZMA, + COMPRESS_BROTLI, +} diff --git a/ide/src/hdc/message/TransferPayload.ts b/ide/src/hdc/message/TransferPayload.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad59a7d71759276b11df50abd5103964b914b8c5 --- /dev/null +++ b/ide/src/hdc/message/TransferPayload.ts @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 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. + */ + +export class TransferPayload extends Object { + private _index: number; // uint64_t + private _compressType: number; // uint8_t; + private _compressSize: number; // uint32_t + private _uncompressSize: number; //uint32_t + + constructor(index: number, compressType: number, compressSize: number, uncompressSize: number) { + super(); + this._index = index; + this._compressType = compressType; + this._compressSize = compressSize; + this._uncompressSize = uncompressSize; + } + + getDataView(): DataView { + const view = new DataView(new ArrayBuffer(24)); + return view; + } + + get index(): number { + return this._index; + } + + set index(value: number) { + this._index = value; + } + + get compressType(): number { + return this._compressType; + } + + set compressType(value: number) { + this._compressType = value; + } + + get compressSize(): number { + return this._compressSize; + } + + set compressSize(value: number) { + this._compressSize = value; + } + + get uncompressSize(): number { + return this._uncompressSize; + } + + set uncompressSize(value: number) { + this._uncompressSize = value; + } + + toString(): string { + return ( + 'index: ' + + this._index + + ' compressType: ' + + this._compressType + + ' compressSize: ' + + this._compressSize + + ' uncompressSize: ' + + this._uncompressSize + ); + } +} diff --git a/ide/src/hdc/message/USBHead.ts b/ide/src/hdc/message/USBHead.ts new file mode 100644 index 0000000000000000000000000000000000000000..1da3cda47272f70f787016172f0754e3da5487c3 --- /dev/null +++ b/ide/src/hdc/message/USBHead.ts @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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 { BaseBean } from './BaseBean.js'; + +export class USBHead extends Object implements BaseBean { + private _flag: number[]; // uint8_t 'flag', ct.c_uint8 * 2 flag[2] 2 + private _option: number; // uint8_t 1 + private _sessionId: number; // uint32_t 4 + private _dataSize: number; // uint32_t 4 + + constructor(flag: number[], option: number, sessionId: number, dataSize: number) { + super(); + this._flag = flag; + this._option = option; + this._sessionId = sessionId; + this._dataSize = dataSize; + } + static getFlag0Length() { + return 1; + } + + static getFlag1Length() { + return 1; + } + + static getOptionLength() { + return 1; + } + + static getSessionIdLength() { + return 4; + } + + static getDataSizeLength() { + return 4; + } + + static getUSBHeadLength() { + return 11; + } + + getDataView(): DataView { + let dataView = new DataView(new ArrayBuffer(11)); + dataView.setUint8(0, this._flag[0]); + dataView.setUint8(1, this._flag[1]); + dataView.setUint8(2, this._option); + dataView.setUint32(3, this._sessionId); + dataView.setUint32(7, this._dataSize); + return dataView; + } + + static parseHeadData(data: DataView): USBHead { + let flagZero = data.getUint8(0); + let flagOne = data.getUint8(1); + let option = data.getUint8(2); + let sessionId = data.getUint32(3); + let dataSize = data.getUint32(7); + return new USBHead([flagZero, flagOne], option, sessionId, dataSize); + } + + get flag(): number[] { + return this._flag; + } + + set flag(value: number[]) { + this._flag = value; + } + + get option(): number { + return this._option; + } + + set option(value: number) { + this._option = value; + } + + get sessionId(): number { + return this._sessionId; + } + + set sessionId(value: number) { + this._sessionId = value; + } + + get dataSize(): number { + return this._dataSize; + } + + set dataSize(value: number) { + this._dataSize = value; + } + + toString(): string { + return ( + 'flag: ' + + this._flag + + ' option: ' + + this._option + + ' sessionId: ' + + this._sessionId + + ' dataSize: ' + + this._dataSize + ); + } +} diff --git a/ide/src/hdc/message/WireType.ts b/ide/src/hdc/message/WireType.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c3b86cf9ffbc02435e03e6b49f006e8bb4ecbd5 --- /dev/null +++ b/ide/src/hdc/message/WireType.ts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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. + */ + +export class WireType { + static VARINT: number = 0; //uint32 + static FIXED64: number = 1; //uint32 + static LENGTH_DELIMETED: number = 2; //uint32 + static START_GROUP: number = 3; //uint32 + static END_GROUP: number = 4; //uint32 + static FIXED32: number = 5; //uint32 +} diff --git a/ide/src/hdc/transmission/DataProcessing.ts b/ide/src/hdc/transmission/DataProcessing.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b7d6491f3fe78d062a7c4e49e3bfe9905902960 --- /dev/null +++ b/ide/src/hdc/transmission/DataProcessing.ts @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2022 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 { TransmissionInterface } from './TransmissionInterface.js'; +import { PACKET_FLAG, USB_PACKET_FLAG } from '../common/ConstantType.js'; +import { USBHead } from '../message/USBHead.js'; +import { DataMessage } from '../message/DataMessage.js'; +import { DataListener } from '../hdcclient/DataListener.js'; +import { PayloadProtect } from '../message/PayloadProtect.js'; +import { Serialize } from '../common/Serialize.js'; +import { PayloadHead } from '../message/PayloadHead.js'; +import { UsbProtocolOption } from '../hdcclient/UsbProtocolOption.js'; +import { toHex16 } from '../common/BaseConversion.js'; +import { error, log } from '../../log/Log.js'; + +export class DataProcessing { + private readonly transmissionChannel: TransmissionInterface; + private dataListener: DataListener; + public readData = true; + private static usbHeadSize: number = 11; + private static vCode: number = 0x09; + private static checkSum: number = 0; + + constructor(dataListener: DataListener, transmissionChannel: TransmissionInterface) { + this.dataListener = dataListener; + this.transmissionChannel = transmissionChannel; + } + + public async startReadData(): Promise { + try { + while (this.readData) { + let usbHead = await this.readUsbHead(); + if (usbHead != null) { + let dataSize = usbHead!.dataSize; + if (dataSize > 0) { + let body = await this.readBody(dataSize); + let message = new DataMessage(usbHead, body); + this.dataListener.createDataMessage(message); + } else { + let message = new DataMessage(usbHead); + this.dataListener.createDataMessage(message); + } + } else { + log('head is null'); + } + } + } catch (e) { + let ubsHead = new USBHead([-1, -1], -1, -1, -1); + let message = new DataMessage(ubsHead); + this.dataListener.createDataMessage(message); + error('error', e); + } + } + + public async readUsbHead(): Promise { + let res = await this.transmissionChannel.readData(USBHead.getUSBHeadLength()); + if (res) { + let useHead: USBHead = USBHead.parseHeadData(res); + return useHead; + } + return null; + } + + public async readBody(dataSize: number): Promise { + let data = await this.transmissionChannel.readData(dataSize); + return data; + } + + public async send( + sessionId: number, + channelId: number, + commandFlag: number, + data: Uint8Array, + dataSize: number + ): Promise { + let protectBuf: PayloadProtect = new PayloadProtect( + channelId, + commandFlag, + DataProcessing.checkSum, + DataProcessing.vCode + ); + let pbs = Serialize.serializePayloadProtect(protectBuf); + let payloadHead: PayloadHead = new PayloadHead( + [PACKET_FLAG.charCodeAt(0), PACKET_FLAG.charCodeAt(1)], + [0, 0], + 1, + pbs.byteLength, + dataSize + ); + let dataView = payloadHead.getDataView(); + let playHeadArray = new Uint8Array(dataView.buffer); + let finalBufSize = dataView.byteLength + pbs.byteLength + dataSize; + let finalBuf = new Uint8Array(finalBufSize); + finalBuf.set(playHeadArray); + finalBuf.set(pbs, dataView.byteLength); + finalBuf.set(data, dataView.byteLength + pbs.byteLength); + if (this.transmissionChannel) { + let header = this.buildPacketHeader(sessionId, UsbProtocolOption.USB_OPTION_HEADER, finalBufSize); + await this.transmissionChannel.writeData(header); + await this.transmissionChannel.writeData(finalBuf); + return true; + } else { + this.stopReadData(); + return false; + } + } + + private buildPacketHeader(sessionId: number, option: number, dataSize: number): Uint8Array { + let head: USBHead = new USBHead( + [USB_PACKET_FLAG.charCodeAt(0), USB_PACKET_FLAG.charCodeAt(1)], + option, + sessionId, + dataSize + ); + let dataView = head.getDataView(); + return new Uint8Array(dataView.buffer); + } + + public stopReadData() { + this.readData = false; + } +} diff --git a/ide/src/hdc/transmission/TransmissionInterface.ts b/ide/src/hdc/transmission/TransmissionInterface.ts new file mode 100644 index 0000000000000000000000000000000000000000..924729191cc46ad3ec7bede7171d24c9ed7ef43a --- /dev/null +++ b/ide/src/hdc/transmission/TransmissionInterface.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2022 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. + */ + +export interface TransmissionInterface { + writeData(writeData: ArrayBuffer): Promise; + readData(length: number): Promise; + close(): Promise; +} diff --git a/ide/src/hdc/transmission/UsbTransmissionChannel.ts b/ide/src/hdc/transmission/UsbTransmissionChannel.ts new file mode 100644 index 0000000000000000000000000000000000000000..26cad5a1a634ebeb02313f19e771fad1d7dd1fc0 --- /dev/null +++ b/ide/src/hdc/transmission/UsbTransmissionChannel.ts @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2022 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 { TransmissionInterface } from './TransmissionInterface.js'; +import { error, info, log } from '../../log/Log.js'; +import { HDC_DEVICE_FILTER } from '../common/ConstantType.js'; +import { HdcDeviceManager } from '../HdcDeviceManager.js'; + +export interface matchingUsbDevice { + configurationValue: number; + interfaceNumber: number; + // @ts-ignore + endPoints: USBEndpoint[]; +} + +export class UsbTransmissionChannel implements TransmissionInterface { + // @ts-ignore + private _device: USBDevice | null; + private readonly endpointIn: number; + private readonly endpointOut: number; + private readonly interfaceNumber: number; + + private constructor( + // @ts-ignore + device: USBDevice, + endpointIn: number, + endpointOut: number, + interfaceNumber: number + ) { + this._device = device; + this.endpointIn = endpointIn; + this.endpointOut = endpointOut; + this.interfaceNumber = interfaceNumber; + } + + /** + * Send data to the device side + * + * @param writeData writeData + */ + async writeData(writeData: ArrayBuffer) { + await this._device?.transferOut(this.endpointOut, writeData); + } + + /** + * read data from device via usb + * + * @param length + */ + async readData(length: number): Promise { + const result = await this._device?.transferIn(this.endpointOut, length); + if (result?.data) { + return result.data; + } else { + return Promise.resolve(new DataView(new ArrayBuffer(0))); + } + } + + /** + * Close the device connection + */ + async close(): Promise { + await this._device?.releaseInterface(this.interfaceNumber); + await this._device?.close(); + this._device = null; + } + + /** + * 打开设备 + * + * @param usbDevice + */ + static async openHdcDevice( + // @ts-ignore + usbDevice: USBDevice + ): Promise { + try { + await usbDevice.open(); + const matchDevice = this.filterAndFindDevice(usbDevice, HDC_DEVICE_FILTER); + info('matchDevice is', matchDevice); + if (!matchDevice) { + throw new Error('Could not find hdc device'); + } + await usbDevice.selectConfiguration(matchDevice.configurationValue); + await usbDevice.claimInterface(matchDevice.interfaceNumber); + const endpointIn = UsbTransmissionChannel.filterEndpointNumber(matchDevice.endPoints, 'in'); + const endpointOut = UsbTransmissionChannel.filterEndpointNumber(matchDevice.endPoints, 'out'); + return new UsbTransmissionChannel(usbDevice, endpointIn, endpointOut, matchDevice.interfaceNumber); + } catch (e) { + return Promise.resolve(null); + } + } + + /** + * Filter out matching devices + * + * @param device device + * @param filter filter + */ + private static filterAndFindDevice( + // @ts-ignore + device: USBDevice, + // @ts-ignore + filter: USBDeviceFilter + ): matchingUsbDevice | null { + for (const config of device.configurations) { + for (const intf of config.interfaces) + for (const al of intf.alternates) { + if ( + filter.classCode === al.interfaceClass && + filter.subclassCode === al.interfaceSubclass && + filter.protocolCode === al.interfaceProtocol + ) { + return { + configurationValue: config.configurationValue, + interfaceNumber: intf.interfaceNumber, + endPoints: al.endpoints, + }; + } + } + } + return null; + } + + private static filterEndpointNumber( + // @ts-ignore + usbEndpoints: USBEndpoint[], + dir: 'in' | 'out', + type = 'bulk' + ): number { + let endpoint = usbEndpoints.filter((element) => { + return element.direction === dir && element.type === type; + }); + return endpoint[0].endpointNumber; + } +} diff --git a/ide/src/icon.svg b/ide/src/icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..1cce633830ef2e9caf112ee0fe44e07f6bed4e53 --- /dev/null +++ b/ide/src/icon.svg @@ -0,0 +1,2173 @@ + diff --git a/ide/src/img/arrowright.png b/ide/src/img/arrowright.png new file mode 100644 index 0000000000000000000000000000000000000000..be68e42d4e0745136ff6c29540c957b2ed06e14a Binary files /dev/null and b/ide/src/img/arrowright.png differ diff --git a/ide/src/img/config_chart.png b/ide/src/img/config_chart.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca78bbd35c6c229cebcb664a41963da2cd7470b Binary files /dev/null and b/ide/src/img/config_chart.png differ diff --git a/ide/src/img/config_filter.png b/ide/src/img/config_filter.png new file mode 100644 index 0000000000000000000000000000000000000000..c8ff0a727081312809594c46e9ce64f104d0205c Binary files /dev/null and b/ide/src/img/config_filter.png differ diff --git a/ide/src/img/config_scene.png b/ide/src/img/config_scene.png new file mode 100644 index 0000000000000000000000000000000000000000..b7610498a75c140fbffbec9f7cbe56538a1cff1c Binary files /dev/null and b/ide/src/img/config_scene.png differ diff --git a/ide/src/img/copy.png b/ide/src/img/copy.png new file mode 100644 index 0000000000000000000000000000000000000000..be910ccc40175ea1452faa36d44725662aaea3d5 Binary files /dev/null and b/ide/src/img/copy.png differ diff --git a/ide/src/img/dark_pic.png b/ide/src/img/dark_pic.png new file mode 100644 index 0000000000000000000000000000000000000000..508917c210653e638a13c8eae2c28bba5daad3cc Binary files /dev/null and b/ide/src/img/dark_pic.png differ diff --git a/ide/src/img/down.png b/ide/src/img/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcde0fbd8e8d15b7b2ce76fd0ac419bf29e107a Binary files /dev/null and b/ide/src/img/down.png differ diff --git a/ide/src/img/function.png b/ide/src/img/function.png new file mode 100644 index 0000000000000000000000000000000000000000..f68381ff4ad756c6a3ddd60b2c219deb80aeb0cc Binary files /dev/null and b/ide/src/img/function.png differ diff --git a/ide/src/img/help.png b/ide/src/img/help.png new file mode 100644 index 0000000000000000000000000000000000000000..05cc5d13cb1d94025ac8c6381c0d1ef1cc7c7443 Binary files /dev/null and b/ide/src/img/help.png differ diff --git a/ide/src/img/library.png b/ide/src/img/library.png new file mode 100644 index 0000000000000000000000000000000000000000..c10c520ee27346318c2db99586543dc1d12810ef Binary files /dev/null and b/ide/src/img/library.png differ diff --git a/ide/src/img/logo.png b/ide/src/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..725db32f13c43af3ede6c3e5fe2fa51e2c0ad263 Binary files /dev/null and b/ide/src/img/logo.png differ diff --git a/ide/src/img/normal_off.png b/ide/src/img/normal_off.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6aa75d2bed70f851cf7269f86fa8d6432dbd08 Binary files /dev/null and b/ide/src/img/normal_off.png differ diff --git a/ide/src/img/normal_on.png b/ide/src/img/normal_on.png new file mode 100644 index 0000000000000000000000000000000000000000..90e57e33025b81e539f0f289a4d3866db0e21d71 Binary files /dev/null and b/ide/src/img/normal_on.png differ diff --git a/ide/src/img/pic.png b/ide/src/img/pic.png new file mode 100644 index 0000000000000000000000000000000000000000..5ed51ecbf5c94788e37a11485045558f8c64dd2e Binary files /dev/null and b/ide/src/img/pic.png differ diff --git a/ide/src/img/pie_chart_no_data.png b/ide/src/img/pie_chart_no_data.png new file mode 100644 index 0000000000000000000000000000000000000000..c414bff49adfbce4c1fd018b2dfc18e8af1dc50f Binary files /dev/null and b/ide/src/img/pie_chart_no_data.png differ diff --git a/ide/src/img/screening.png b/ide/src/img/screening.png new file mode 100644 index 0000000000000000000000000000000000000000..ee7259c851aa4656d6896eac17ac2894ed300ac3 Binary files /dev/null and b/ide/src/img/screening.png differ diff --git a/ide/src/img/table_no_data.svg b/ide/src/img/table_no_data.svg new file mode 100644 index 0000000000000000000000000000000000000000..344982cdc1ee6848ed03850adca49b1a70f20cff --- /dev/null +++ b/ide/src/img/table_no_data.svg @@ -0,0 +1,109 @@ + + + table_no_data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ide/src/index.html b/ide/src/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e73acb40dd8f0ce287e22da7b50926b3b66457ec --- /dev/null +++ b/ide/src/index.html @@ -0,0 +1,49 @@ + + + + Trace Example + + + + + + + + + diff --git a/ide/src/js-heap/HeapDataInterface.ts b/ide/src/js-heap/HeapDataInterface.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9946bf9e606d6fe228fff1eadc65cdcfc303595 --- /dev/null +++ b/ide/src/js-heap/HeapDataInterface.ts @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2022 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 { HeapLoader } from './logic/HeapLoader.js'; +import { + AllocationFunction, + ConstructorComparison, + ConstructorItem, + ConstructorType, + FileInfo, +} from './model/UiStruct.js'; +import { HeapNodeToConstructorItem } from './utils/Utils.js'; +import { FileStruct, HeapSample, HeapTraceFunctionInfo } from './model/DatabaseStruct.js'; + +export interface ParseListener { + parseDone(fileModule: Array): void; + process(info: string, process: number): void; +} + +export class HeapDataInterface { + private static instance: HeapDataInterface; + private isParsing = false; + private isParseDone = false; + private parseListener!: ParseListener; + private fileStructs!: Array; + private baseFileStruct!: FileStruct | null; + + public static getInstance() { + if (!this.instance) { + this.instance = new HeapDataInterface(); + } + return this.instance; + } + + private getFileStructById(id: number): FileStruct | null { + for (let fileStruct of this.fileStructs) { + if (fileStruct.id == id) { + return fileStruct; + } + } + return null; + } + + /** + * tell interface current file to provider file interface + * @param fileId file id + */ + public setFileId(fileId: number) { + this.baseFileStruct = this.getFileStructById(fileId); + } + + /** + * set ParseListener to callback when node_files table in database is parse done + * @param listener callback + */ + public setPraseListener(listener: ParseListener) { + this.parseListener = listener; + } + + /** + * obtain the list of Constructor classes + * @returns Array + */ + public getClassesListForSummary(fileId: number, minNodeId?: number, maxNodeId?: number): Array { + let constructorMap; + let constructorList = new Array(); + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); + if (this.isParseDone && filStruct) { + constructorMap = filStruct.heapLoader.getClassesForSummary(minNodeId, maxNodeId); + constructorMap.forEach((construct, _) => { + constructorList.push(construct); + }); + constructorList.sort(function (a, b) { + return b.retainedSize - a.retainedSize; + }); + } + return constructorList; + } + + /** + * compare base file and target file, calculate delta size and count to target class + * @param baseFileId current file id + * @param targetFileId select id which file is to compare + * @returns diff class list + */ + public getClassListForComparison(baseFileId: number, targetFileId: number) { + let baseFileStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(baseFileId); + let targetFileStruct = this.getFileStructById(targetFileId); + if (!baseFileStruct || !targetFileStruct) { + return []; + } + let diffClassList = new Array(); + let diffClassMap = baseFileStruct.heapLoader.getClassesForComparison( + targetFileId, + targetFileStruct.heapLoader.getClassesForSummary() + ); + if (!diffClassMap || diffClassMap.size === 0) { + return []; + } + + for (let diffClass of diffClassMap.values()) { + diffClassList.push(diffClass); + } + diffClassList.sort((a, b) => b.addedSize - a.addedSize); + return diffClassList; + } + + /** + * get sample data for timeline + * @param fileId timeline file id + * @returns time stamp with size + */ + public getSamples(fileId: number): Array { + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); + if (!filStruct) { + return []; + } + let samples = filStruct.snapshotStruct.samples; + return samples; + } + + /** + * get the functions which call the node + * @param node current select node + * @returns node.parent + */ + public getParentFunction(node: AllocationFunction) { + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(node.fileId); + if (!filStruct) { + return; + } + filStruct.heapLoader.loadAllocationParent(node); + } + + /** + * get select node children while node type is class + * @param node current select node + * @returns node.children + */ + public getNextForConstructor(node: ConstructorItem): Array { + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(node.fileId); + let children = new Array(); + switch (node.type) { + case ConstructorType.ClassType: + children = node.classChildren; + break; + case ConstructorType.InstanceType: + case ConstructorType.FiledType: + children = filStruct!.heapLoader.getNextNode(node); + break; + } + return children; + } + + public getNextForComparison(comparisonNode: ConstructorComparison): Array { + let baseFileStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(comparisonNode.fileId); + let targetFileStruct = this.getFileStructById(comparisonNode.targetFileId); + if (!baseFileStruct || !targetFileStruct) { + return []; + } + let children = new Array(); + if (comparisonNode.type === ConstructorType.ComparisonType) { + for (let idx of comparisonNode.addedIndx) { + let node = baseFileStruct.heapLoader.getNodes()[idx]; + let compareNode = HeapNodeToConstructorItem(node); + compareNode.type = ConstructorType.InstanceType; + compareNode.addedSize = compareNode.shallowSize; + compareNode.isAdd = true; + compareNode.hasNext = node.edgeCount > 0; + children.push(compareNode); + } + + for (let idx of comparisonNode.deletedIdx) { + let node = targetFileStruct.heapLoader.getNodes()[idx]; + let compareNode = HeapNodeToConstructorItem(node); + compareNode.type = ConstructorType.InstanceType; + compareNode.removedSize = compareNode.shallowSize; + compareNode.isAdd = false; + compareNode.hasNext = node.edgeCount > 0; + children.push(compareNode); + } + } else { + children = this.getNextForConstructor(comparisonNode); + } + return children; + } + + /** + * get nodes which referenced this node + * @param constructor current node + * @returns reference nodes + */ + public getRetains(constructor: ConstructorItem) { + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(constructor.fileId); + if (!filStruct) { + return []; + } + return filStruct?.heapLoader.getRetains(constructor); + } + + /** + * get AllocationStack page data + * @param node the row of data clicked + * @returns AllocationStackFrame[] + */ + public getAllocationStackData(node: ConstructorItem): Array { + let functions = new Array(); + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(node.fileId); + if (!filStruct && (node.type == ConstructorType.ClassType || node.type == ConstructorType.RetainersType)) { + return functions; + } else { + functions = filStruct!.heapLoader.getAllocationStack(node.traceNodeId); + } + return functions; + } + + /** + * obtain the minimum id of the node + * @param fileId current file id + * @returns minNodeId + */ + public getMinNodeId(fileId: number): number | undefined { + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); + if (!filStruct) { + return undefined; + } + return filStruct!.heapLoader.getMinAndMaxNodeId().minNodeId; + } + + /** + * obtain the maximum id of the node + * @param fileId current file id + * @returns maxNodeId + */ + public getMaxNodeId(fileId: number): number | undefined { + let filStruct = this.baseFileStruct ? this.baseFileStruct : this.getFileStructById(fileId); + if (!filStruct) { + return undefined; + } + return filStruct!.heapLoader.getMinAndMaxNodeId().maxNodeId; + } + + async parseData(fileModule: Array) { + this.fileStructs = fileModule; + this.isParsing = true; + this.isParseDone = false; + let percent: number; + for (let fileStruct of fileModule) { + let heapLoader = new HeapLoader(fileStruct); + fileStruct.heapLoader = heapLoader; + percent = 50 + Math.floor(50 / fileModule.length) * (fileModule.indexOf(fileStruct) + 1); + this.parseListener.process('parsing data of ' + fileStruct.name + ' ', percent); + } + this.isParsing = false; + this.isParseDone = true; + if (this.parseListener) { + this.parseListener.parseDone(fileModule); + this.parseListener.process('parsing completed', 100); + } + } + + /** + * get all file struct in database + * @returns all fileInfo + */ + public getFileStructs(): Array { + return this.fileStructs; + } +} diff --git a/ide/src/js-heap/LoadDatabase.ts b/ide/src/js-heap/LoadDatabase.ts new file mode 100644 index 0000000000000000000000000000000000000000..63f9d1965f230e85f54289503db36a3eb6308098 --- /dev/null +++ b/ide/src/js-heap/LoadDatabase.ts @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2022 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 { HeapDataInterface, ParseListener } from './HeapDataInterface.js'; +import { AllocationFunction, FileType } from './model/UiStruct.js'; +import { getTimeForLog } from './utils/Utils.js'; +import { + HeapEdge, + HeapNode, + HeapTraceFunctionInfo, + HeapSample, + HeapLocation, + FileStruct, +} from './model/DatabaseStruct.js'; +import { + queryHeapFile, + queryHeapInfo, + queryHeapNode, + queryHeapEdge, + queryHeapFunction, + queryHeapTraceNode, + queryHeapSample, + queryHeapLocation, + queryHeapString, +} from '../trace/database/SqlLite.js'; +import { info } from '../log/Log.js'; + +export class LoadDatabase { + private static loadDB: LoadDatabase; + private fileModule!: Array; + + static getInstance() { + if (!this.loadDB) { + this.loadDB = new LoadDatabase(); + } + return this.loadDB; + } + + private async loadFile(listener: ParseListener) { + this.fileModule = new Array(); + let result = await queryHeapFile(); + listener.process('start loading file ', 1); + for (let row of result) { + let fileStruct = new FileStruct(); + fileStruct.id = row.id; + fileStruct.name = row.file_name; + fileStruct.start_ts = row.start_time; + fileStruct.end_ts = row.end_time; + fileStruct.pid = row.pid; + if (fileStruct.name.startsWith('Snapshot')) { + fileStruct.type = FileType.SNAPSHOT; + } else { + fileStruct.type = FileType.TIMELINE; + } + info(`read ${fileStruct.name} from db ${getTimeForLog()}`); + //fileStruct.profile.root_index = 0 + await this.loadInfo(fileStruct); + await this.loadStrings(fileStruct); + await this.loadNode(fileStruct); + await this.loadEdge(fileStruct); + await this.loadTraceFunctionInfos(fileStruct); + await this.loadTraceTree(fileStruct); + await this.loadSamples(fileStruct); + await this.loadLocations(fileStruct); + let percent = Math.floor(50 / result.length) * (row.id + 1); + listener.process('loading file ' + fileStruct.name + ' from db ', percent); + info(`read ${fileStruct.name} from db Success ${getTimeForLog()}`); + this.fileModule.push(fileStruct); + } + listener.process('Loading completed ', 50); + let dataParse = HeapDataInterface.getInstance(); + dataParse.setPraseListener(listener); + dataParse.parseData(this.fileModule); + } + + private async loadInfo(file: FileStruct) { + let result = await queryHeapInfo(file.id); + for (let row of result) { + if (row.key.includes('types')) continue; + switch (row.key) { + case 'node_count': + file.snapshotStruct.nodeCount = row.int_value; + break; + case 'edge_count': + file.snapshotStruct.edgeCount = row.int_value; + break; + case 'trace_function_count': + file.snapshotStruct.functionCount = row.int_value; + break; + } + } + } + + private async loadNode(file: FileStruct) { + let result = await queryHeapNode(file.id); + let heapNodes = file.snapshotStruct.nodeMap; + + let items = new Array(); + let firstEdgeIndex = 0; + for (let row of result) { + let node = new HeapNode( + file.id, + row.node_index, + row.type, + file.snapshotStruct.strings[row.name], + row.id, + row.self_size, + row.edge_count, + row.trace_node_id, + row.detachedness, + firstEdgeIndex + ); + if (file.snapshotStruct.rootNodeId === -1) { + file.snapshotStruct.rootNodeId = row.id; + } + heapNodes.set(row.id, node); + items.push(...[row.type, row.name, row.id, row.self_size, row.edge_count, row.trace_node_id, row.detachedness]); + firstEdgeIndex += node.edgeCount; + } + } + + private async loadEdge(file: FileStruct) { + let result = await queryHeapEdge(file.id); + let heapEdges = file.snapshotStruct.edges; + + let items = new Array(); + for (let row of result) { + let edge = new HeapEdge( + row.edge_index, + row.type, + file.snapshotStruct.strings[row.name_or_index], + row.to_node, + row.from_node_id, + row.to_node_id + ); + heapEdges.push(edge); + items.push(...[row.type, row.name_or_index, row.to_node]); + } + } + + private async loadTraceFunctionInfos(file: FileStruct) { + let result = await queryHeapFunction(file.id); + let heapFunction = file.snapshotStruct.functionInfos; + + let items = new Array(); + for (let row of result) { + let functionInfo = new HeapTraceFunctionInfo( + row.function_id, + row.function_index, + file.snapshotStruct.strings[row.name], + file.snapshotStruct.strings[row.script_name], + row.script_id, + row.line, + row.column + ); + heapFunction.push(functionInfo); + + items.push(...[row.function_id, row.name, row.script_name, row.script_id, row.line, row.column]); + } + } + + private async loadTraceTree(file: FileStruct) { + let result = await queryHeapTraceNode(file.id); + let heapTraceNode = file.snapshotStruct.traceNodes; + let strings = file.snapshotStruct.strings; + for (let row of result) { + let traceNode = new AllocationFunction( + row.id, + strings[row.name], + strings[row.script_name], + row.script_id, + row.line, + row.column, + row.count, + row.size, + row.live_count, + row.live_size, + false + ); + traceNode.parentsId.push(row.parent_id); + traceNode.functionIndex = row.function_info_index; + traceNode.fileId = file.id; + heapTraceNode.push(traceNode); + } + } + + private async loadSamples(file: FileStruct) { + let result = await queryHeapSample(file.id); + let samples = file.snapshotStruct.samples; + + for (let row of result) { + let functionInfo = new HeapSample(row.timestamp_us, row.last_assigned_id); + samples.push(functionInfo); + } + } + + private async loadLocations(file: FileStruct) { + let result = await queryHeapLocation(file.id); + let locations = file.snapshotStruct.locations; + + for (let row of result) { + let location = new HeapLocation(row.object_index / 7, row.script_id, row.line, row.column); + locations.set(location.objectIndex, location); + } + } + + private async loadStrings(file: FileStruct) { + let result = await queryHeapString(file.id); + for (let row of result) { + file.snapshotStruct.strings.push(row.string); + } + } + + async loadDatabase(listener: ParseListener) { + await this.loadFile(listener); + } +} diff --git a/ide/src/js-heap/logic/Allocation.ts b/ide/src/js-heap/logic/Allocation.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4fbdec87d02e53a00bc9865ad46e63bdef7f4fb --- /dev/null +++ b/ide/src/js-heap/logic/Allocation.ts @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 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 { AllocationFunction } from '../model/UiStruct.js'; +import { FileStruct, HeapTraceFunctionInfo } from '../model/DatabaseStruct.js'; + +export class AllocationLogic { + private fileStruct: FileStruct; + private traceNodes: Array; + private bottomUpList: Array; + + constructor(fileStruct: FileStruct) { + this.fileStruct = fileStruct; + this.bottomUpList = []; + this.traceNodes = this.fileStruct.snapshotStruct.traceNodes; + this.init(); + } + + private init() { + this.setBottomUpTree(); + } + + private setBottomUpTree() { + let keyMap = new Map(); + for (let node of this.traceNodes) { + if (node.parentsId.length > 1) { + node.hasParent = true; + } else if (node.parentsId.length == 0) { + node.hasParent = false; + } else { + if (node.parentsId[0] == -1) { + node.hasParent = false; + } else { + node.hasParent = true; + } + } + // combine node + if (keyMap.has(node.name + node.functionIndex)) { + let uniqueNode = keyMap.get(node.name + node.functionIndex); + if (!uniqueNode) continue; + uniqueNode.size += node.size; + uniqueNode.count += node.count; + uniqueNode.liveSize += node.liveSize; + uniqueNode.liveCount += node.liveCount; + uniqueNode.parentsId.push(...node.parentsId); + uniqueNode.combineId.add(uniqueNode.id); + uniqueNode.combineId.add(node.id); + } else { + keyMap.set(node.name + node.functionIndex, node); + node.combineId.add(node.id); + this.bottomUpList.push(node); + } + } + this.bottomUpList.sort(function (a, b) { + return b.size - a.size; + }); + } + + private getNodeById(id: number): AllocationFunction | null { + for (let func of this.bottomUpList) { + if (func.id == id) { + return func; + } + } + return null; + } + + private getFunctionStack(node: AllocationFunction, functionList: Array) { + functionList.push(this.fileStruct.snapshotStruct.functionInfos[node.functionIndex]); + if (node.parentsId.length > 0) { + for (let parentId of node.parentsId) { + let parentNode = this.getNodeById(parentId); + if (parentNode) { + this.getFunctionStack(parentNode, functionList); + } + } + } + } + + /** + * get Bottom Up FUnction List + * @returns bottomUpList + */ + public getFunctionList(): Array { + return this.bottomUpList; + } + + /** + * set node parents node + * node has multi parent because bottom up combine multi node + * @param node selected node + */ + public getParent(node: AllocationFunction) { + if (node.hasParent) { + if (node.parentsId.length > 1) { + for (let childrenId of node.parentsId) { + let children = this.traceNodes[childrenId - 1].clone(); + children.size = node.size; + children.count = node.count; + children.liveSize = node.liveSize; + children.liveCount = node.liveCount; + node.parents.push(children); + } + } else if ((node.parentsId.length = 1)) { + let childrenId = node.parentsId[0]; + if (!node.parents) node.parents = new Array(); + let children = this.traceNodes[childrenId - 1].clone(); + children.size = node.size; + children.count = node.count; + children.liveSize = node.liveSize; + children.liveCount = node.liveCount; + node.parents.push(children); + this.getParent(children); + } else { + // no need to do anything + } + } + } + + /** + * get use bottom up method combine's node ids + * @param allocationNodeId node id + * @returns node combine id + */ + public getFunctionNodeIds(allocationNodeId: number): Array { + let node = this.getNodeById(allocationNodeId); + if (node) { + return Array.from(node.combineId); + } else { + return []; + } + } + + /** + * get full stack for node + * @param allocationNodeId node.traceNodeId + * @returns stack list + */ + public getNodeStack(allocationNodeId: number): Array { + let currentNode = this.getNodeById(allocationNodeId); + let functionList = new Array(); + if (currentNode) { + this.getFunctionStack(currentNode, functionList); + } + return functionList; + } +} diff --git a/ide/src/js-heap/logic/HeapLoader.ts b/ide/src/js-heap/logic/HeapLoader.ts new file mode 100644 index 0000000000000000000000000000000000000000..4edab66486c0451634986d7df56ed0fb09bd54b6 --- /dev/null +++ b/ide/src/js-heap/logic/HeapLoader.ts @@ -0,0 +1,1057 @@ +/* + * Copyright (C) 2022 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 { AllocationLogic } from './Allocation.js'; +import { AllocationFunction, ConstructorComparison, ConstructorItem, ConstructorType } from '../model/UiStruct.js'; +import { + DetachedNessState, + EdgeType, + FileStruct, + HeapEdge, + HeapNode, + HeapSample, + HeapTraceFunctionInfo, + NodeType, +} from '../model/DatabaseStruct.js'; +import { HeapNodeToConstructorItem } from '../utils/Utils.js'; + +const BASE_SYSTEM_DISTANCE = 100000000; +const CAN_BE_QUERIED = 1; +const DETACHED_DOM_NODE = 2; +const PAGE_PROJECT = 4; + +export class HeapLoader { + private fileId: number; + private fileStruct: FileStruct; + private allocationLogic: AllocationLogic; + private nodeMap: Map; + private edges: Array; + private rootNode: HeapNode | undefined; + private nodeCount: number; + private edgeCount: number; + private nodes: Array; + private retainingNodes: Uint32Array; + private retainingEdges: Uint32Array; + private firstRetainerIndex: Uint32Array; + private dominatorTree: Uint32Array; + private firstDominatedNodesIdx: Uint32Array; + private dominatedNodes: Uint32Array; + private allClasses!: Map; + private diffToOtherFile: Map>; + + constructor(fileStruct: FileStruct) { + this.fileStruct = fileStruct; + this.fileId = fileStruct.id; + this.nodeCount = fileStruct.snapshotStruct.nodeCount; + this.edgeCount = fileStruct.snapshotStruct.edgeCount; + this.nodeMap = fileStruct.snapshotStruct.nodeMap; + this.edges = fileStruct.snapshotStruct.edges; + this.allocationLogic = new AllocationLogic(this.fileStruct); + this.nodes = new Array(this.nodeCount); + this.nodeMap.forEach((value) => { + this.nodes[value.nodeIndex] = value; + }); + this.nodes.sort((a, b) => a.nodeIndex - b.nodeIndex); + this.rootNode = this.nodes[0]; + this.retainingNodes = new Uint32Array(this.edgeCount); //每一个值为node index + this.retainingEdges = new Uint32Array(this.edgeCount); // 每一个值为edge index + this.firstRetainerIndex = new Uint32Array(this.nodeCount + 1); + this.dominatorTree = new Uint32Array(this.nodeCount); + this.firstDominatedNodesIdx = new Uint32Array(this.nodeCount + 1); + this.dominatedNodes = new Uint32Array(this.nodeCount - 1); + this.diffToOtherFile = new Map>(); + this.preprocess(); + } + + get allocation() { + return this.allocationLogic; + } + + private preprocess() { + if (!this.rootNode) { + return; + } + this.buildNodeEdge(); + this.buildRetainers(); + this.distributeDOMState(); + this.calFlags(); + this.calDistances(); + this.calRetainedSize(); + // use to cal class Retained Size + this.buildDominatedNode(); + this.buildSamples(); + } + + /** + * set node parents node + * node has multi parent because bottom up combine multi node + * @param node selected node + */ + loadAllocationParent(node: AllocationFunction) { + this.allocationLogic.getParent(node); + } + + /** + * get Bottom Up Function List + * @returns bottomUpList + */ + getAllocationFunctionList(): Array { + return this.allocationLogic.getFunctionList(); + } + + /** + * get full stack for node + * @param allocationNodeId node.traceNodeId + * @returns stack list + */ + getAllocationStack(traceNodeId: number): Array { + return this.allocationLogic.getNodeStack(traceNodeId); + } + + getFunctionNodeIds(id: number) { + return this.allocationLogic.getFunctionNodeIds(id); + } + + getAllocation() { + return this.allocationLogic; + } + + private buildNodeEdge(): void { + for (let node of this.nodes) { + for (let i = 0; i < node.edgeCount; i++) { + let edgeIndex = node.firstEdgeIndex + i; + if (this.edges.length > edgeIndex) { + node.addEdge(this.edges[edgeIndex]); + } + } + } + } + + private buildRetainers(): void { + // Iterate over edges and count how many times each node is retained by other nodes + for (let edge of this.edges) { + let toNode = this.nodeMap.get(edge.toNodeId); + if (toNode) { + ++this.firstRetainerIndex[toNode.nodeIndex]; + } + } + // Assign the first retainer slot index for each node + let firstUnusedRetainerSlot = 0; + for (let node of this.nodes) { + let retainCount = this.firstRetainerIndex[node.nodeIndex]; + this.firstRetainerIndex[node.nodeIndex] = firstUnusedRetainerSlot; + this.retainingNodes[firstUnusedRetainerSlot] = retainCount; + firstUnusedRetainerSlot += retainCount; + } + this.firstRetainerIndex[this.nodeCount] = this.retainingNodes.length; + + // Fill the retainer slots with the retaining nodes and edges + for (let node of this.nodes) { + for (let edge of node.edges) { + let childNode = this.nodeMap.get(edge.toNodeId); + if (!childNode) { + continue; + } + if (node.nodeIndex !== this.rootNode?.nodeIndex){ + childNode.retainsNodeIdx.push(node.nodeIndex); + childNode.retainsEdgeIdx.push(edge.edgeIndex); + } + + let firstRetainerSlotIndex = this.firstRetainerIndex[childNode.nodeIndex]; + + let nextUnusedRetainerSlotIndex = firstRetainerSlotIndex + --this.retainingNodes[firstRetainerSlotIndex]; + this.retainingNodes[nextUnusedRetainerSlotIndex] = node.nodeIndex; + this.retainingEdges[nextUnusedRetainerSlotIndex] = edge.edgeIndex; + } + } + } + + private distributeDOMState(): void { + // 1.重用反序列化字段来存储传播的状态。虽然已知节点的状态已经设置, + // 但仍然需要经过处理以调整其名称并将其放入各自的队列中。 + let domState = new DOMState(this.nodeCount); + for (let node of this.nodes) { + if (node.detachedness === DetachedNessState.UNKNOWN) { + continue; + } + this.processNode(domState, node, node.detachedness); + } + + // 2. 如果父节点被Attached,那么子节点也被Attached。 + while (domState.attached.length > 0) { + let nodeId = domState.attached.pop() as number; + let node = this.nodeMap.get(nodeId); + if (node) { + this.iterateFilteredChildren(domState, node, DetachedNessState.ATTACHED); + } + } + + // 3. 如果父节点为Attached,那么子节点将继承父节点的状态。 + while (domState.detached.length > 0) { + let nodeId = domState.detached.pop() as number; + let node = this.nodeMap.get(nodeId); + if (node && node.detachedness !== DetachedNessState.ATTACHED) { + this.iterateFilteredChildren(domState, node, DetachedNessState.DETACHED); + } + } + } + + private calFlags(): void { + this.markQueryableNodes(); + this.markPageOwnedNodes(); + } + + private buildOrderIdxAndDominateTree(): Uint32Array { + let stackNodes = new Uint32Array(this.nodeCount); // node index + let stackCurrentEdge = new Uint32Array(this.nodeCount); // edge index + let orderIdx2NodeIdx = new Uint32Array(this.nodeCount); + let nodeIdx2OrderIdx = new Uint32Array(this.nodeCount); + let visited = new Uint8Array(this.nodeCount); + let postOrderIdx = 0; + let stack = 0; + stackNodes[0] = this.rootNode!.nodeIndex; + visited[this.rootNode!.nodeIndex] = 1; + + let iteration = 0; + while (true) { + ++iteration; + while (stack >= 0 && stack < this.nodeCount) { + let nodeIndex = stackNodes[stack]; + let node = this.nodes[nodeIndex]; + if (!node) { + continue; + } + let edgeIndex = stackCurrentEdge[stack]; + let edgeEnd = node.firstEdgeIndex + node.edgeCount; + if (edgeIndex < edgeEnd) { + stackCurrentEdge[stack] += 1; + let edge = this.edges[edgeIndex]; + if (!this.isEssentialEdge(edge, node.id)) { + continue; + } + let childNode = this.nodeMap.get(edge.toNodeId); + if (!childNode || visited[childNode!.nodeIndex]) { + continue; + } + //跳过从非页面拥有的节点到页面拥有的节点的边缘 + let childNodeFlag = childNode.flag & PAGE_PROJECT; + if (node.id != this.rootNode!.id && childNodeFlag && !node.flag) { + continue; + } + ++stack; + stackNodes[stack] = childNode.nodeIndex; + stackCurrentEdge[stack] = childNode.firstEdgeIndex; + visited[childNode.nodeIndex] = 1; + } else { + nodeIdx2OrderIdx[node.nodeIndex] = postOrderIdx; + orderIdx2NodeIdx[postOrderIdx++] = node.nodeIndex; + --stack; + } + } + if (postOrderIdx == this.nodeCount || iteration > 1) { + break; + } + + // Remove root from the result (last node in the array) and put it at the bottom of the stack so that it is + // visited after all orphan nodes and their subgraphs. + --postOrderIdx; + stack = 0; + stackNodes[0] = this.rootNode!.nodeIndex; + stackCurrentEdge[0] = this.nodes[this.rootNode!.nodeIndex + 1].firstEdgeIndex; + for (let node of this.nodes) { + if (visited[node.nodeIndex] || !this.hasOnlyWeakRetainers(node)) { + continue; + } + stackNodes[++stack] = node.nodeIndex; + stackCurrentEdge[stack] = node.firstEdgeIndex; + visited[node.nodeIndex] = 1; + } + } + // If we already processed all orphan nodes that have only weak retainers and still have some orphans... + if (postOrderIdx !== this.nodeCount) { + // Remove root from the result (last node in the array) and put it at the bottom of the stack so that it is + // visited after all orphan nodes and their subgraphs. + --postOrderIdx; + for (let i = 0; i < this.nodeCount; i++) { + if (visited[i]) { + continue; + } + // Fix it by giving the node a postorder index anyway. + nodeIdx2OrderIdx[i] = postOrderIdx; + orderIdx2NodeIdx[postOrderIdx++] = i; + } + nodeIdx2OrderIdx[this.rootNode!.nodeIndex] = postOrderIdx; + orderIdx2NodeIdx[postOrderIdx++] = this.rootNode!.nodeIndex; + } + this.buildDominatorTree(orderIdx2NodeIdx, nodeIdx2OrderIdx); + return orderIdx2NodeIdx; + } + + // The algorithm is based on the article: + // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" + // Softw. Pract. Exper. 4 (2001), pp. 1-10. + private buildDominatorTree(orderIdx2NodeIdx: Uint32Array, nodeIdx2OrderIdx: Uint32Array): void { + let rootOrderedIdx = this.nodeCount - 1; + let dominators = new Uint32Array(this.nodeCount).fill(this.nodeCount); + dominators[rootOrderedIdx] = rootOrderedIdx; + + // The affected array is used to mark entries which dominators + // have to be racalculated because of changes in their retainers. + let affected = new Uint8Array(this.nodeCount); + + // 标记root节点的子节点为affected. + for (let edge of this.rootNode!.edges) { + if (!this.isEssentialEdge(edge, this.rootNode!.id)) { + continue; + } + let childNode = this.nodeMap.get(edge.toNodeId); + if (childNode) { + affected[nodeIdx2OrderIdx[childNode.nodeIndex]] = 1; + } + } + + let changed = true; + let nodeIdx; + while (changed) { + changed = false; + for (let orderIdx = rootOrderedIdx - 1; orderIdx >= 0; --orderIdx) { + // If dominator of the entry has already been set to root, + // then it can't propagate any further. + if (affected[orderIdx] === 0) { + continue; + } + affected[orderIdx] = 0; + if (dominators[orderIdx] === rootOrderedIdx) { + continue; + } + nodeIdx = orderIdx2NodeIdx[orderIdx]; + let node = this.nodes[nodeIdx]; + let nodeFlag = node.flag & PAGE_PROJECT; + let newDominatorIdx = this.nodeCount; + let retainerStart = this.firstRetainerIndex[nodeIdx]; + let retainerEnd = this.firstRetainerIndex[nodeIdx + 1]; + let orphanNode = true; + for (let idx = retainerStart; idx < retainerEnd; idx++) { + let retainerNodeIdx = this.retainingNodes[idx]; + let retainerEdgeIdx = this.retainingEdges[idx]; + let node = this.nodes[retainerNodeIdx]; + let edge = this.edges[retainerEdgeIdx]; + if (!this.isEssentialEdge(edge, node.id)) { + continue; + } + orphanNode = false; + let retainerNodeFlag = node.flag & PAGE_PROJECT; + if (retainerNodeIdx !== this.rootNode?.nodeIndex && nodeFlag && !retainerNodeFlag) { + continue; + } + let retainerOrderIdx = nodeIdx2OrderIdx[retainerNodeIdx]; + if (dominators[retainerOrderIdx] !== this.nodeCount) { + if (newDominatorIdx === this.nodeCount) { + newDominatorIdx = retainerOrderIdx; + } else { + while (retainerOrderIdx !== newDominatorIdx) { + while (retainerOrderIdx < newDominatorIdx) { + retainerOrderIdx = dominators[retainerOrderIdx]; + } + while (newDominatorIdx < retainerOrderIdx) { + newDominatorIdx = dominators[newDominatorIdx]; + } + } + } + // If idom has already reached the root, it doesn't make sense + // to check other retainers. + if (newDominatorIdx === rootOrderedIdx) { + break; + } + } + } + // Make root dominator of orphans. + if (orphanNode) { + newDominatorIdx = rootOrderedIdx; + } + if (newDominatorIdx !== this.nodeCount && dominators[orderIdx] !== newDominatorIdx) { + dominators[orderIdx] = newDominatorIdx; + changed = true; + nodeIdx = orderIdx2NodeIdx[orderIdx]; + let node = this.nodes[nodeIdx]; + for (let edge of node.edges) { + let childNode = this.nodeMap.get(edge.toNodeId); + if (childNode) { + affected[nodeIdx2OrderIdx[childNode.nodeIndex]] = 1; + } + } + } + } + } + + for (let orderIdx = 0; orderIdx < dominators.length; orderIdx++) { + nodeIdx = orderIdx2NodeIdx[orderIdx]; + this.dominatorTree[nodeIdx] = orderIdx2NodeIdx[dominators[orderIdx]]; + } + } + + private calDistances(): void { + if (!this.rootNode) return; + let nodesToVisit = new Uint32Array(this.nodeCount); + let nodesToVisitLen = 0; + // root节点下所有的edge distance 为1 + for (let edge of this.rootNode.edges) { + let node = this.nodeMap.get(edge.toNodeId); + if (!node) { + continue; + } + if (node.isUserRoot() || node.isDocumentDOMTreesRoot()) { + node.distance = 1; + nodesToVisit[nodesToVisitLen++] = node.id; + } + } + this.bfs(nodesToVisit, nodesToVisitLen); + + // 如果roo节点下有能访问到的子节点,将root节点的distance设置为100000000,否则为0 + this.rootNode.distance = nodesToVisitLen > 0 ? BASE_SYSTEM_DISTANCE : 0; + // 设置root节点下访问不到的哪些独立节点的distance,从100000000开始计数 + nodesToVisit[0] = this.rootNode.id; + nodesToVisitLen = 1; + this.bfs(nodesToVisit, nodesToVisitLen); + } + + private calRetainedSize(): void { + let orderIdx2NodeIdx = this.buildOrderIdxAndDominateTree(); + // Propagate retained sizes for each node excluding root. + for (let idx = 0; idx < this.nodeCount - 1; idx++) { + let node = this.nodes[orderIdx2NodeIdx[idx]]; + let dominatorNode = this.nodes[this.dominatorTree[node.nodeIndex]]; + dominatorNode.retainedSize += node.retainedSize; + } + } + + private buildDominatedNode() { + //赋值两个数组: + //-dominatedNodes是一个连续数组,其中每个节点拥有一个与相应的被支配节点的间隔(可以为空)。 + //—indexArray 是dominatedNodes中与_nodeIndex位置相同的索引数组。 + // const indexArray = this.firstDominatedNodeIdx; + // // All nodes except the root have dominators. + // const dominatedNodes = this.dominatedNodes; + let fromNodeIdx = 0; + let toNodeIdx = this.nodeCount; + + if (this.rootNode?.nodeIndex === 0) { + fromNodeIdx = 1; + } else if (this.rootNode?.nodeIndex == toNodeIdx - 1) { + toNodeIdx -= 1; + } else { + throw new Error('Root node is expected to be either first or last'); + } + for (let nodeIdx = fromNodeIdx; nodeIdx < toNodeIdx; ++nodeIdx) { + ++this.firstDominatedNodesIdx[this.dominatorTree[nodeIdx]]; + } + // Put in the first slot of each dominatedNodes slice the count of entries + // that will be filled. + let firstDominatedNodeIdx = 0; + for (let idx = 0; idx < this.nodeCount; idx++) { + let dominateCount = (this.dominatedNodes[firstDominatedNodeIdx] = this.firstDominatedNodesIdx[idx]); + this.firstDominatedNodesIdx[idx] = firstDominatedNodeIdx; + firstDominatedNodeIdx += dominateCount; + } + this.firstDominatedNodesIdx[this.nodeCount] = this.dominatedNodes.length; + // Fill up the dominatedNodes array with indexes of dominated nodes. Skip the root (node at + // index 0) as it is the only node that dominates itself. + for (let nodeIdx = fromNodeIdx; nodeIdx < toNodeIdx; nodeIdx++) { + let dominatorIdx = this.dominatorTree[nodeIdx]; + let dominatorRefIdx = this.firstDominatedNodesIdx[dominatorIdx]; + dominatorRefIdx += --this.dominatedNodes[dominatorRefIdx]; + this.dominatedNodes[dominatorRefIdx] = nodeIdx * 7; + } + } + + private buildSamples() { + let samples = this.fileStruct.snapshotStruct.samples; + if (!samples.length) { + return; + } + for (let node of this.nodes) { + if (node.id % 2 === 0) { + continue; + } + let rangeIdx = this.binarySearchNodeInSamples(node.id, samples); + if (rangeIdx === samples.length) { + continue; + } + samples[rangeIdx].size += node.selfSize; + } + } + + getMinAndMaxNodeId() { + return { + minNodeId: this.nodes[0].id, + maxNodeId: this.nodes[this.nodeCount - 1].id, + }; + } + + private binarySearchNodeInSamples(nodeId: number, samples: Array): number { + let left = 0; + let right = samples.length - 1; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const currentSample = samples[mid]; + if (currentSample.lastAssignedId === nodeId) { + return left; + } else if (currentSample.lastAssignedId < nodeId) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private filterForBpf(node: HeapNode, edge: HeapEdge): boolean { + if (node.type === NodeType.HIDDEN) { + return edge.nameOrIndex !== 'sloppy_function_map' || node.name !== 'system / NativeContext'; + } + if (node.type === NodeType.ARRAY) { + if (node.name !== '(map descriptors)') { + return true; + } + const index = parseInt(edge.nameOrIndex, 10); + return index < 2 || index % 3 !== 1; + } + return true; + } + + /** + * 广度优先算法遍历所有能从root节点访问到的节点,设置节点的的distance + * @param nodesToVisit 能被访问到的node id 数组 + * @param nodesToVisitLen 有效的node数量 + */ + private bfs(nodesToVisit: Uint32Array, nodesToVisitLen: number) { + let index = 0; + while (index < nodesToVisitLen) { + let nodeId = nodesToVisit[index++]; + let node = this.nodeMap.get(nodeId); + if (!node) { + continue; + } + let distance = node.distance + 1; + + for (let edge of node.edges) { + if (edge.type === EdgeType.WEAK || !this.nodeMap.has(edge.toNodeId)) { + continue; + } + let childNode = this.nodeMap.get(edge.toNodeId); + // 如果已经设置过一次distance了 不再设置 + if (!childNode || childNode.distance != -5 || !this.filterForBpf(node, edge)) { + continue; + } + childNode.distance = distance; + nodesToVisit[nodesToVisitLen++] = childNode.id; + } + } + if (nodesToVisitLen > this.nodeCount) { + throw new Error('BFS failed. Nodes to visit ' + nodesToVisitLen + ' is more than nodes count ' + this.nodeCount); + } + } + + private processNode(domState: DOMState, node: HeapNode, newState: number) { + if (domState.visited[node.nodeIndex]) { + return; + } + if (node.type !== NodeType.NATIVE) { + domState.visited[node.nodeIndex] = 1; + return; + } + + node.detachedness = newState; + + if (newState === DetachedNessState.ATTACHED) { + domState.attached.push(node.id); + } else if (newState === DetachedNessState.DETACHED) { + node.displayName = 'Detached ' + node.name; + // mark detached dom + node.flag |= DETACHED_DOM_NODE; + domState.detached.push(node.id); + } + domState.visited[node.nodeIndex] = 1; + } + + /** + * Iterates children of a node. + */ + private iterateFilteredChildren(domState: DOMState, node: HeapNode, newState: number): void { + for (let edge of node.edges) { + if (edge.type === EdgeType.HIDDEN || edge.type === EdgeType.WEAK || edge.type === EdgeType.INVISIBLE) { + continue; + } + let childNode = this.nodeMap.get(edge.toNodeId); + if (childNode) { + this.processNode(domState, childNode, newState); + } + } + } + + /** + * mark the node can reachable from root node + */ + private markQueryableNodes(): void { + let list = new Array(); + let flag = CAN_BE_QUERIED; + for (let edge of this.rootNode!.edges) { + let childNode = this.nodeMap.get(edge.toNodeId); + if (childNode && childNode.isUserRoot()) { + list.push(childNode); + } + } + + while (list.length) { + let node = list.pop() as HeapNode; + if (!node || node.flag & flag) { + continue; + } + node.flag |= flag; + for (let edge of node.edges) { + let childNode = this.nodeMap.get(edge.toNodeId); + if ( + !childNode || + childNode.flag & flag || + // @ts-ignore + [EdgeType.HIDDEN, EdgeType.INVISIBLE, EdgeType.INTERNAL, EdgeType.WEAK].includes(edge.type) + ) { + continue; + } + list.push(childNode); + } + } + } + + private markPageOwnedNodes(): void { + let nodesToVisitLen = 0; + let nodesToVisit = new Array(this.nodeCount); + let flag = PAGE_PROJECT; + if (!this.rootNode) { + return; + } + + for (let edge of this.rootNode.edges) { + let node = this.nodeMap.get(edge.toNodeId); + if (!node) { + continue; + } + if (edge.type === EdgeType.ELEMENT) { + if (!node.isDocumentDOMTreesRoot()) { + continue; + } + } else if (edge.type !== EdgeType.SHORTCUT) { + continue; + } + nodesToVisit[nodesToVisitLen++] = node; + node.flag |= flag; + } + + while (nodesToVisitLen) { + let node = nodesToVisit[--nodesToVisitLen]; + for (let edge of node.edges) { + let childNode = this.nodeMap.get(edge.toNodeId); + if (!childNode || childNode.flag & flag || edge.type === EdgeType.WEAK) { + continue; + } + nodesToVisit[nodesToVisitLen++] = childNode; + childNode.flag |= flag; + } + } + } + + private isEssentialEdge(edge: HeapEdge, nodeId: number): boolean { + return edge.type !== EdgeType.WEAK && (edge.type !== EdgeType.SHORTCUT || nodeId === this.rootNode!.id); + } + + private hasOnlyWeakRetainers(node: HeapNode): boolean { + let retainerStart = this.firstRetainerIndex[node.nodeIndex]; + let retainerEnd = this.firstRetainerIndex[node.nodeIndex + 1]; + for (let index = retainerStart; index < retainerEnd; index++) { + let retainingEdgeIdx = this.retainingEdges[index]; + let edge = this.edges[retainingEdgeIdx]; + if (edge.type !== EdgeType.WEAK && edge.type !== EdgeType.SHORTCUT) { + return false; + } + } + return true; + } + + private calClassDiff(baseClass: ConstructorItem, classItem?: ConstructorItem) { + let diff = new ConstructorComparison(); + diff.type = ConstructorType.ComparisonType; + diff.fileId = this.fileId; + diff.targetFileId = baseClass.fileId; + diff.nodeName = baseClass.nodeName; + let i = 0; + let j = 0; + let classLen = classItem ? classItem.childCount : 0; + let baseLen = baseClass.childCount; + baseClass.classChildren.sort((a, b) => a.id - b.id); + if (classItem) { + classItem.classChildren.sort((a, b) => a.id - b.id); + } + // The overlap between the base class and the target class + while (i < baseLen && j < classLen) { + let classNode = classItem!.classChildren[j]; + let baseNode = baseClass.classChildren[i]; + if (baseNode.id < classNode.id) { + diff.deletedIdx.push(baseNode.index); + diff.removedCount++; + diff.removedSize += baseNode.shallowSize; + i++; + } else if (baseNode.id > classNode.id) { + diff.addedIndx.push(classNode.index); + diff.addedCount++; + diff.addedSize += classNode.shallowSize; + j++; + } else { + i++; + j++; + } + } + // base more then target + while (i < baseLen) { + let baseNode = baseClass!.classChildren[i]; + diff.deletedIdx.push(baseNode.index); + diff.removedCount++; + diff.removedSize += baseNode.shallowSize; + i++; + } + // + while (j < classLen) { + let classNode = classItem!.classChildren[j]; + diff.addedIndx.push(classNode.index); + diff.addedCount++; + diff.addedSize += classNode.shallowSize; + j++; + } + diff.deltaCount = diff.addedCount - diff.removedCount; + diff.deltaSize = diff.addedSize - diff.removedSize; + if (diff.addedCount == 0 && diff.removedCount == 0) { + return null; + } + diff.childCount = diff.addedCount + diff.removedCount; + diff.hasNext = true; + return diff; + } + + public getClassesForSummary(minNodeId?: number, maxNodeId?: number): Map { + let hasFiler = typeof minNodeId === 'number' && typeof maxNodeId === 'number'; + function filter(nodeId: number): boolean { + if (hasFiler) { + if (hasFiler && nodeId >= minNodeId! && nodeId <= maxNodeId!) { + return true; + } else { + return false; + } + } else { + return true; + } + } + if (!hasFiler && this.allClasses) { + return this.allClasses; + } + let classes = new Map(); + // combine node with className + for (let node of this.nodes) { + if (!filter(node.id) || (node.selfSize === 0 && node.type !== NodeType.NATIVE)) { + continue; + } + + if (!classes.has(node.className())) { + let classItem = HeapNodeToConstructorItem(node); + classItem.fileId = this.fileId; + classItem.childCount = 1; + classItem.type = ConstructorType.ClassType; + classItem.retainedSize = 0; + classItem.nodeName = node.className(); + classItem.hasNext = true; + classes.set(node.className(), classItem); + + let instanceItem = classItem.clone(); + instanceItem.type = ConstructorType.InstanceType; + instanceItem.id = node.id; + instanceItem.index = node.nodeIndex; + instanceItem.childCount = node.edgeCount; + instanceItem.retainedSize = node.retainedSize; + instanceItem.hasNext = instanceItem.childCount > 0; + instanceItem.traceNodeId = node.traceNodeId; + classItem.classChildren.push(instanceItem); + } else { + let classItem = classes.get(node.className()); + if (!classItem) { + continue; + } + // set min node distance to class distance + classItem.distance = Math.min(classItem.distance, node.distance); + ++classItem.childCount; + classItem.shallowSize += node.selfSize; + + let nodeItem = HeapNodeToConstructorItem(node); + nodeItem.fileId = this.fileId; + nodeItem.type = ConstructorType.InstanceType; + nodeItem.id = node.id; + nodeItem.index = node.nodeIndex; + nodeItem.childCount = node.edgeCount; + nodeItem.hasNext = nodeItem.childCount > 0; + + classItem.classChildren.push(nodeItem); + } + } + + // cal class retained size + let list = [this.rootNode]; + const sizes = [-1]; + const classesName = []; + let seenClassName = new Map(); + + while (list.length) { + let node = list.pop(); + if (!node) { + continue; + } + let nodeClassName = node.className(); + let seen = Boolean(seenClassName.get(nodeClassName)); + let dominatorFromIdx = this.firstDominatedNodesIdx[node.nodeIndex]; + let dominatorToIdx = this.firstDominatedNodesIdx[node.nodeIndex + 1]; + + if (!seen && (!hasFiler || filter(node.id)) && (node.selfSize || node.type === NodeType.NATIVE)) { + let classItem = classes.get(nodeClassName); + if (classItem) { + classItem.retainedSize += node.retainedSize; + if (dominatorFromIdx !== dominatorToIdx) { + seenClassName.set(nodeClassName, true); + sizes.push(list.length); + classesName.push(nodeClassName); + } + } + } + + for (let idx = dominatorFromIdx; idx < dominatorToIdx; idx++) { + let nodeOldIdx = this.dominatedNodes[idx]; + let domNode = this.nodes[nodeOldIdx / 7]; + list.push(domNode); + } + + while (sizes[sizes.length - 1] === list.length) { + sizes.pop(); + nodeClassName = classesName.pop() as string; + seenClassName.set(nodeClassName, false); + } + } + if (!hasFiler) { + this.allClasses = classes; + } + return classes; + } + /** + * compare base file and target file, calculate delta size and count to target class + * @param baseFileId to compare file's id + * @param targetFileClasses to compare file's constructor + */ + public getClassesForComparison(baseFileId: number, targetFileClasses: Map) { + // Return the result if it has been obtained before + if (this.diffToOtherFile.has(baseFileId)) { + return this.diffToOtherFile.get(baseFileId); + } + // get base file class if not init before + if (!this.allClasses) { + this.allClasses = this.getClassesForSummary(); + } + + //deal target class + let diffMap = new Map(); + for (let baseClass of targetFileClasses.values()) { + let classes = this.allClasses.get(baseClass.nodeName); + let different = this.calClassDiff(baseClass, classes); + if (different) { + diffMap.set(baseClass.nodeName, different); + } + } + + // deal base class which is not in target + for (let classItem of this.allClasses.values()) { + if (targetFileClasses.has(classItem.nodeName)) { + continue; + } + let different = this.calClassDiff(classItem); + if (different) { + diffMap.set(classItem.nodeName, different); + } + } + this.diffToOtherFile.set(baseFileId, diffMap); + return diffMap; + } + + /** + * Summary get Node Children + * @param item select Node + * @returns child Nodes + */ + public getNextNode(item: ConstructorItem): Array { + if (item.children.length > 0) { + return item.children; + } + // get children from edge + let node = this.nodes[item.index]; + let childNodes = new Array(); + for (let edge of node.edges) { + let childNode = this.nodeMap.get(edge.toNodeId); + if (!childNode) { + continue; + } + let instanceItem = HeapNodeToConstructorItem(childNode); + instanceItem.childCount = instanceItem.edgeCount = childNode.edgeCount; + instanceItem.edgeName = edge.nameOrIndex; + instanceItem.hasNext = instanceItem.childCount > 0; + instanceItem.traceNodeId = childNode.traceNodeId; + instanceItem.type = ConstructorType.FiledType; + instanceItem.parent = item; + childNodes.push(instanceItem); + } + + let clickNode = childNodes[0].parent; + // If there are duplicate IDs in the third layer and beyond, they will not be expanded again + if (clickNode!.type == ConstructorType.FiledType) { + function findParents(clickNode: any, parents: any): any { + if (!clickNode.parent) { + return parents; + } + // add the parent of the current node to the result array + parents.push(clickNode); + for (let childNode of childNodes) { + for (let p of parents) { + if (p.id === childNode!.id) { + childNode.hasNext = false; + } + } + } + return findParents(clickNode.parent, parents); + } + findParents(clickNode, []); + } + let filterChildNodes = new Array(); + for (let item of childNodes) { + if (item.id !== this.rootNode!.id) { + filterChildNodes.push(item); + } + } + item.children = filterChildNodes; + return filterChildNodes; + } + + /** + * get nodes which referenced this node + * @param constructor current node + * @returns reference nodes + */ + public getRetains(item: ConstructorItem): Array { + let obj: any; + if (item.retains.length > 0) { + return item.retains; + } + if (item.type === ConstructorType.ClassType) { + return []; + } + let node = this.nodes[item.index]; + let retains = new Array(); + if (node && node.retainsEdgeIdx.length === node.retainsNodeIdx.length) { + for (let i = 0; i < node.retainsNodeIdx.length; i++) { + let retainsNode = this.nodes[node.retainsNodeIdx[i]]; + let retainEdge = this.edges[node.retainsEdgeIdx[i]]; + + if (retainEdge.type == EdgeType.WEAK) { + continue; + } + let retainsItem = HeapNodeToConstructorItem(retainsNode); + retainsItem.edgeName = retainEdge.nameOrIndex; + retainsItem.edgeType = retainEdge.type; + retainsItem.type = ConstructorType.RetainersType; + retainsItem.childCount = retainsNode.retainsNodeIdx.length; + retainsItem.hasNext = retainsNode.retainsNodeIdx.length > 0; + if (item!.type == ConstructorType.RetainersType) { + retainsItem.parent = item; + } + retains.push(retainsItem); + } + } + + // Because the node with id 1 needs to be deleted, there is only one child and id 1 does not need to expand the symbol + for (let childNode of retains) { + let node = this.nodes[childNode.index]; + if (node && node.retainsEdgeIdx.length === node.retainsNodeIdx.length) { + for (let i = 0; i < node.retainsNodeIdx.length; i++) { + let retainsNode = this.nodes[node.retainsNodeIdx[i]]; + if (node.retainsNodeIdx.length == 1 && retainsNode.id == this.rootNode!.id) { + childNode.hasNext = false; + } + } + } + } + + if (retains.length > 0 && retains[0].parent) { + let clickNode = retains[0].parent; + // If there are duplicate IDs in the third layer and beyond, they will not be expanded again + if (clickNode!.type == ConstructorType.RetainersType) { + function findParents(clickNode: any, parents: any): any { + if (!clickNode.parent) { + return parents; + } + // add the parent of the current node to the result array + parents.push(clickNode); + for (let childNode of retains) { + for (let p of parents) { + if (p.id === childNode!.id) { + childNode.hasNext = false; + } + } + } + return findParents(clickNode.parent, parents); + } + findParents(clickNode, []); + } + } + + retains.sort(function (a: any, b: any) { + return a.distance - b.distance; + }); + + let filterRetains = new Array(); + for (let item of retains) { + if (item.id !== this.rootNode!.id) { + filterRetains.push(item); + } + } + return filterRetains; + } + + public getNodes(): Array { + return this.nodes; + } +} + +class DOMState { + visited: Uint8Array; + attached: Array; + detached: Array; + + constructor(nodeSize: number) { + this.visited = new Uint8Array(nodeSize); + this.attached = new Array(); + this.detached = new Array(); + } +} diff --git a/ide/src/js-heap/model/DatabaseStruct.ts b/ide/src/js-heap/model/DatabaseStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..0d8da58aa2291f5005b4dc8ab5b30ff13501368e --- /dev/null +++ b/ide/src/js-heap/model/DatabaseStruct.ts @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2022 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 { HeapLoader } from '../logic/HeapLoader.js'; +import { AllocationFunction, FileInfo } from './UiStruct.js'; + +export enum NodeType { + HIDDEN = 0, + ARRAY = 1, + STRING = 2, + OBJECT = 3, + CODE = 4, + CLOSURE = 5, + REGEXP = 6, + NUMBER = 7, + NATIVE = 8, + SYNTHETIC = 9, + CONCATENATED_STRING = 10, + SLICED_STRING = 11, + SYMBOL = 12, + BIGINT = 13, + OBJECT_SHAPE = 14, +} + +export enum EdgeType { + CONTEXT = 0, + ELEMENT = 1, + PROPERTY = 2, + INTERNAL = 3, + HIDDEN = 4, + SHORTCUT = 5, + WEAK = 6, + STRING_OR_NUMBER = 6, + NODE = 7, + INVISIBLE = 8, +} + +function getNodeTypeName(nodeType: NodeType): keyof typeof NodeType { + return Object.keys(NodeType).find( + (key) => NodeType[key as keyof typeof NodeType] === nodeType + ) as keyof typeof NodeType; +} + +function getEdgeTypeName(nodeType: EdgeType): keyof typeof EdgeType { + return Object.keys(EdgeType).find( + (key) => EdgeType[key as keyof typeof EdgeType] === nodeType + ) as keyof typeof EdgeType; +} + +export enum DetachedNessState { + UNKNOWN, + ATTACHED, + DETACHED, +} + +export class HeapNode { + fileId: number; + nodeIndex: number; + nodeOldIndex: number; + type: NodeType; + name: string; + id: number; + selfSize: number; + edgeCount: number; + traceNodeId: number; + detachedness: number; + edges: Set; + distance: number = -5; + retainedSize: number; + displayName: string = ''; + firstEdgeIndex: number; + flag: number; + retainsCount: number = 0; + retainsEdgeIdx: Array; + retainsNodeIdx: Array; + + constructor( + fileId: number, + node_index: number, + type: number, + name: string, + id: number, + selfSize: number, + edgeCount: number, + traceNodeId: number, + detachedness: number, + firstEdgeIndex: number + ) { + this.fileId = fileId; + this.nodeIndex = node_index; + this.nodeOldIndex = node_index * 7; + this.type = type; + this.name = name; + this.id = id; + this.selfSize = selfSize; + this.retainedSize = selfSize; + this.edgeCount = edgeCount; + this.traceNodeId = traceNodeId; + this.detachedness = detachedness; + this.firstEdgeIndex = firstEdgeIndex; + this.edges = new Set(); + this.retainsEdgeIdx = new Array(); + this.retainsNodeIdx = new Array(); + this.flag = 0; + } + + className(): string { + const type = this.type; + switch (type) { + case NodeType.HIDDEN: + return '(system)'; + case NodeType.OBJECT: + case NodeType.NATIVE: + return this.nodeName(); + case NodeType.CODE: + return '(compiled code)'; + default: + let typeName = '(' + getNodeTypeName(type) + ')'; + return typeName.toLowerCase(); + } + } + + nodeName(): string { + return this.displayName || this.name; + } + + classIndex(): number { + if (this.type === NodeType.OBJECT || this.type === NodeType.NATIVE) { + return this.nodeIndex; + } + return -1 - this.type; + } + + addEdge(edge: HeapEdge) { + this.edges.add(edge); + } + + idHidden(): boolean { + return this.type == NodeType.HIDDEN; + } + + isArray(): boolean { + return this.type === NodeType.ARRAY; + } + + isUserRoot(): boolean { + return this.type != NodeType.SYNTHETIC; + } + + isDocumentDOMTreesRoot(): boolean { + return this.type != NodeType.SYNTHETIC && this.name === '(Document DOM trees)'; + } +} + +export class HeapEdge { + edgeOldIndex: number; + edgeIndex: number; + type: EdgeType; + nameOrIndex: string; + nodeId: number; + fromNodeId: number; + toNodeId: number; + retainsNode: Array; + retainEdge: Array; + + constructor( + edgeIndex: number, + type: number, + nameOrIndex: string, + nodeId: number, + fromNodeId: number, + toNodeId: number + ) { + this.edgeIndex = edgeIndex; + this.edgeOldIndex = edgeIndex * 3; + this.type = type; + this.nameOrIndex = nameOrIndex; + this.nodeId = nodeId; + this.fromNodeId = fromNodeId; + this.toNodeId = toNodeId; + this.retainsNode = new Array(); + this.retainEdge = new Array(); + } +} + +export class HeapTraceFunctionInfo { + id: number; + index: number; + name: string; + scriptName: string; + scriptId: number; + line: number; + column: number; + + constructor( + id: number, + index: number, + name: string, + scriptName: string, + scriptId: number, + line: number, + column: number + ) { + this.id = id; + this.index = index; + this.name = name; + this.scriptName = scriptName; + this.scriptId = scriptId; + this.line = line; + this.column = column; + } +} + +export class HeapSample { + timestamp: number; + lastAssignedId: number; + size: number; + + constructor(timestamp: number, lastAssignedId: number) { + this.timestamp = timestamp; + this.lastAssignedId = lastAssignedId; + this.size = 0; + } +} + +export class HeapLocation { + objectIndex: number; + scriptId: number; + line: number; + column: number; + + constructor(objectIndex: number, scriptId: number, line: number, column: number) { + this.objectIndex = objectIndex; + this.scriptId = scriptId; + this.line = line; + this.column = column; + } +} + +export class HeapSnapshotStruct { + nodeCount!: number; + edgeCount!: number; + functionCount!: number; + + nodeMap: Map; + edges: Array; + functionInfos: Array; + traceNodes: Array; + samples: Array; + locations: Map; + strings: Array; + + rootNodeId: number = -1; + + constructor() { + this.nodeMap = new Map(); + this.edges = new Array(); + this.functionInfos = new Array(); + this.traceNodes = new Array(); + this.samples = new Array(); + this.locations = new Map(); + this.strings = new Array(); + } +} + +export class FileStruct extends FileInfo { + snapshotStruct: HeapSnapshotStruct; + isParseSuccess: boolean; + heapLoader!: HeapLoader; + + constructor() { + super(); + this.isParseSuccess = true; + this.snapshotStruct = new HeapSnapshotStruct(); + } +} diff --git a/ide/src/js-heap/model/UiStruct.ts b/ide/src/js-heap/model/UiStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d4f797db96205ddbf61914ba505f25a246bbfa1 --- /dev/null +++ b/ide/src/js-heap/model/UiStruct.ts @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2022 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 { HeapDataInterface } from '../HeapDataInterface.js'; +import { EdgeType } from './DatabaseStruct'; + +export enum FileType { + SNAPSHOT, + TIMELINE, +} + +export enum ConstructorType { + ClassType, + InstanceType, + FiledType, + RetainersType, + ComparisonType, +} + +export class ConstructorItem { + fileId = -1; + nodeName = ''; + edgeName = ''; + childCount = 1; // child count + distance = -1; + shallowSize = -1; + retainedSize = -1; + showBox = false; + showCut = false; + hasNext = true; + status = true; + isSelected: boolean = false; + objectName = ''; + + edgeCount = 0; + edgeType!: EdgeType; + type!: ConstructorType; + nextId: [] = []; + id = -1; + index = -1; + traceNodeId = -1; + parent!: ConstructorItem; + children: Array = []; + retains: Array = []; + classChildren: Array = []; + + getChildren(): ConstructorItem[] { + if (!this.hasNext) return []; + let data = HeapDataInterface.getInstance(); + switch (this.type) { + case ConstructorType.ClassType: + case ConstructorType.InstanceType: + case ConstructorType.FiledType: + this.children = data.getNextForConstructor(this); + break; + case ConstructorType.RetainersType: + this.children = data.getRetains(this); + break; + } + return this.children; + } + + clone(): ConstructorItem { + let copyItem = new ConstructorItem(); + this.cloneContent(copyItem); + return copyItem; + } + + protected cloneContent(copyItem: ConstructorItem) { + copyItem.fileId = this.fileId; + copyItem.distance = this.distance; + copyItem.shallowSize = this.shallowSize; + copyItem.nodeName = this.nodeName; + copyItem.edgeCount = this.edgeCount; + copyItem.edgeType = this.edgeType; + copyItem.childCount = this.childCount; + copyItem.hasNext = this.hasNext; + } +} + +export class ConstructorComparison extends ConstructorItem { + targetFileId = -1; + addedCount = 0; + removedCount = 0; + deltaCount = 0; + + addedSize = 0; + removedSize = 0; + deltaSize = 0; + + deletedIdx: Array = []; + addedIndx: Array = []; + + isAdd = false; + status = true; + + getChildren(): ConstructorItem[] { + if (this.type !== ConstructorType.ComparisonType) { + return super.getChildren(); + } + if (!this.hasNext) return []; + let data = HeapDataInterface.getInstance(); + if (this.type == ConstructorType.ComparisonType) { + this.children = data.getNextForComparison(this); + } + return this.children; + } + + clone(): ConstructorComparison { + let copyItem = new ConstructorComparison(); + this.cloneContent(copyItem); + return copyItem; + } +} +export class AllocationFunction { + fileId = -1; + functionIndex = -1; + parentsId: Array; + parents: Array; + combineId: Set; + status = true; + + id: number; + name: string; + scriptName: string; + scriptId: number; + line: number; + column: number; + count: number; + size: number; + liveCount: number; + liveSize: number; + hasParent: boolean; + + constructor( + nodeId: number, + functionName: string, + scriptName: string, + scriptId: number, + line: number, + column: number, + count: number, + size: number, + liveCount: number, + liveSize: number, + hasParent: boolean + ) { + this.combineId = new Set(); + this.parentsId = new Array(); + this.parents = new Array(); + this.id = nodeId; + this.name = functionName; + this.scriptName = scriptName; + this.scriptId = scriptId; + this.line = line; + this.column = column; + this.count = count; + this.size = size; + this.liveCount = liveCount; + this.liveSize = liveSize; + this.hasParent = hasParent; + } + + /** + * bottom up next level is parent + * return Parents + */ + getChildren(): AllocationFunction[] { + if (!this.hasParent) return []; + let data = HeapDataInterface.getInstance(); + //bottom up next level is parent + data.getParentFunction(this); + return this.parents; + } + + clone(): AllocationFunction { + let cloneItem = new AllocationFunction( + this.id, + this.name, + this.scriptName, + this.scriptId, + this.line, + this.column, + this.count, + this.size, + this.liveCount, + this.liveSize, + this.hasParent + ); + cloneItem.parentsId = this.parentsId; + return cloneItem; + } +} + +export class FileInfo { + id: number = -1; + name: string = ''; + path: string = ''; + type!: FileType; + start_ts: number = 0; + end_ts: number = 0; + pid: number = 0; +} diff --git a/ide/src/js-heap/utils/Utils.ts b/ide/src/js-heap/utils/Utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4be1d475e6cea1da6f18c00f2cc544f5b1e9786 --- /dev/null +++ b/ide/src/js-heap/utils/Utils.ts @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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 { HeapNode } from '../model/DatabaseStruct.js'; +import { ConstructorComparison } from '../model/UiStruct.js'; + +export function HeapNodeToConstructorItem(node: HeapNode): ConstructorComparison { + let constructor = new ConstructorComparison(); + constructor.fileId = node.fileId; + constructor.id = node.id; + constructor.index = node.nodeIndex; + constructor.nodeName = node.nodeName(); + constructor.edgeCount = node.edgeCount; + constructor.distance = node.distance; + constructor.shallowSize = node.selfSize; + constructor.retainedSize = node.retainedSize; + return constructor; +} + +export function getTimeForLog() { + let date = new Date(Date.now()); + return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}.${date.getMilliseconds()} `; +} diff --git a/ide/src/log/Log.ts b/ide/src/log/Log.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9fb3a38f1134a127320c6e35808dee9d4115c93 --- /dev/null +++ b/ide/src/log/Log.ts @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 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. + */ + +export enum LogLevel { + OFF = Number.MAX_VALUE, + ERROR = 4000, + WARN = 3000, + INFO = 2000, + DEBUG = 1000, + TRACE = 500, + ALL = Number.MIN_VALUE, +} + +export const error = (message?: any, ...optionalParams: any[]) => { + SpLog.logger(LogLevel.ERROR, message, ...optionalParams); +}; +export const warn = (message?: any, ...optionalParams: any[]) => { + SpLog.logger(LogLevel.WARN, message, ...optionalParams); +}; +export const info = (message?: any, ...optionalParams: any[]) => { + SpLog.logger(LogLevel.INFO, message, ...optionalParams); +}; +export const debug = (message?: any, ...optionalParams: any[]) => { + SpLog.logger(LogLevel.DEBUG, message, ...optionalParams); +}; +export const trace = (message?: any, ...optionalParams: any[]) => { + SpLog.logger(LogLevel.TRACE, message, ...optionalParams); +}; +export const log = (message?: any) => { + SpLog.logger(LogLevel.TRACE, message); +}; + +class SpLog { + private static nowLogLevel: LogLevel = LogLevel.OFF; + + public static getNowLogLevel(): LogLevel { + return this.nowLogLevel; + } + + public static setLogLevel(logLevel: LogLevel) { + SpLog.nowLogLevel = logLevel; + } + + public static logger(logLevel: LogLevel, message?: any, ...optionalParams: any[]) { + if (logLevel >= SpLog.nowLogLevel) { + switch (logLevel) { + case LogLevel.ERROR: + console.error(message, ...optionalParams); + break; + case LogLevel.WARN: + console.warn(message, ...optionalParams); + break; + case LogLevel.INFO: + console.info(message, ...optionalParams); + break; + case LogLevel.DEBUG: + console.debug(message, ...optionalParams); + break; + case LogLevel.TRACE: + console.trace(message, ...optionalParams); + break; + default: + console.log(message); + } + } + } +} diff --git a/ide/src/statistics/util/SpStatisticsHttpBean.ts b/ide/src/statistics/util/SpStatisticsHttpBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..dedd1123f6afded8d5e26e969a3ab8025eedf083 --- /dev/null +++ b/ide/src/statistics/util/SpStatisticsHttpBean.ts @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 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. + */ + +export interface BurialPointRequestBody { + action: string; + event: string; + ts?: number; + eventData?: EventData; +} + +export interface EventData { + plugin?: Array; +} diff --git a/ide/src/statistics/util/SpStatisticsHttpUtil.ts b/ide/src/statistics/util/SpStatisticsHttpUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ac69493e6a3c98827eae1fc8626bb56694a91b6 --- /dev/null +++ b/ide/src/statistics/util/SpStatisticsHttpUtil.ts @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 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 { BurialPointRequestBody } from './SpStatisticsHttpBean.js'; + +export class SpStatisticsHttpUtil { + static requestServerInfo: string = ''; + static serverTime: number = 0; + static timeDiff: number = 0; + static retryCount: number = 0; + static retryMaxCount: number = 5; + static pauseRetry: boolean = false; + static retryRestTimeOut: boolean = false; + + static initStatisticsServerConfig() { + if (SpStatisticsHttpUtil.requestServerInfo === '') { + SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); + } + if (SpStatisticsHttpUtil.serverTime == 0) { + SpStatisticsHttpUtil.getServerTime(); + } + } + + static getRequestServerInfo(): string { + let req = new XMLHttpRequest(); + req.open( + 'GET', + `${window.location.protocol}//${window.location.host.split(':')[0]}:${window.location.port}/application/serverInfo`, + false + ); + req.send(null); + if (req.status == 200) { + let requestInfo = req.getResponseHeader('request_info'); + if (requestInfo && requestInfo.length > 0) { + return requestInfo; + } + } + return ''; + } + + static getServerTime() { + if (SpStatisticsHttpUtil.requestServerInfo === '') { + SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); + } + if (SpStatisticsHttpUtil.pauseRetry) { + return; + } + fetch(`https://${SpStatisticsHttpUtil.requestServerInfo}/serverTime`) + .then((resp) => { + resp.text().then((it) => { + if (it && it.length > 0) { + SpStatisticsHttpUtil.serverTime = Number(it); + SpStatisticsHttpUtil.timeDiff = SpStatisticsHttpUtil.serverTime - Date.now(); + } + }); + }) + .catch((e) => { + this.handleRequestException(); + }); + } + + private static handleRequestException() { + if (SpStatisticsHttpUtil.retryCount >= SpStatisticsHttpUtil.retryMaxCount) { + SpStatisticsHttpUtil.pauseRetry = true; + if (SpStatisticsHttpUtil.retryRestTimeOut) { + return; + } + SpStatisticsHttpUtil.retryRestTimeOut = true; + setTimeout(() => { + SpStatisticsHttpUtil.retryCount = 0; + SpStatisticsHttpUtil.pauseRetry = false; + SpStatisticsHttpUtil.retryRestTimeOut = false; + }, 600000); + } + ++SpStatisticsHttpUtil.retryCount; + } + + static addUserVisitAction(requestUrl: string) { + if (SpStatisticsHttpUtil.requestServerInfo === '') { + SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); + } + if (SpStatisticsHttpUtil.pauseRetry) { + return; + } + let visitId = 0; + fetch(`https://${SpStatisticsHttpUtil.requestServerInfo}/${requestUrl}`, { + method: 'post', + headers: { + 'Content-Type': 'application/json', + }, + }) + .then((resp) => { + resp.text().then((it) => { + let res = JSON.parse(it); + if (res && res.data) { + visitId = res.data.accessId; + } + }); + }) + .catch((err) => {}); + setTimeout(() => { + fetch(`https://${SpStatisticsHttpUtil.requestServerInfo}/${requestUrl}`, { + method: 'post', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + effectiveAccess: true, + visitId: visitId, + }), + }) + .catch((err) => {}) + .then((resp) => {}); + }, 1800000); + } + + static addOrdinaryVisitAction(requestBody: BurialPointRequestBody) { + if (SpStatisticsHttpUtil.requestServerInfo === '') { + SpStatisticsHttpUtil.requestServerInfo = SpStatisticsHttpUtil.getRequestServerInfo(); + } + if (SpStatisticsHttpUtil.pauseRetry) { + return; + } + requestBody.ts = SpStatisticsHttpUtil.getCorrectRequestTime(); + if (SpStatisticsHttpUtil.serverTime === 0) { + return; + } + fetch(`https://${SpStatisticsHttpUtil.requestServerInfo}/record`, { + method: 'post', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(requestBody), + }) + .catch((err) => { + this.handleRequestException(); + }) + .then((resp) => {}); + } + + static getCorrectRequestTime(): number { + if (SpStatisticsHttpUtil.serverTime === 0) { + SpStatisticsHttpUtil.getServerTime(); + } + return Date.now() + SpStatisticsHttpUtil.timeDiff; + } +} diff --git a/ide/src/trace/SpApplication.ts b/ide/src/trace/SpApplication.ts new file mode 100644 index 0000000000000000000000000000000000000000..abb854f1a841ddbc5cd6eb92565ef74e3c9c074f --- /dev/null +++ b/ide/src/trace/SpApplication.ts @@ -0,0 +1,1434 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../base-ui/BaseElement.js'; +import '../base-ui/menu/LitMainMenu.js'; +import '../base-ui/icon/LitIcon.js'; +import { SpMetrics } from './component/SpMetrics.js'; +import { SpHelp } from './component/SpHelp.js'; +import './component/SpHelp.js'; +import { SpQuerySQL } from './component/SpQuerySQL.js'; +import './component/SpQuerySQL.js'; +import { SpSystemTrace } from './component/SpSystemTrace.js'; +import { LitMainMenu, MenuItem } from '../base-ui/menu/LitMainMenu.js'; +import { SpInfoAndStats } from './component/SpInfoAndStas.js'; +import '../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../base-ui/progress-bar/LitProgressBar.js'; +import { SpRecordTrace } from './component/SpRecordTrace.js'; +import { SpWelcomePage } from './component/SpWelcomePage.js'; +import { LitSearch } from './component/trace/search/Search.js'; +import { DbPool, threadPool } from './database/SqlLite.js'; +import './component/trace/search/Search.js'; +import './component/SpWelcomePage.js'; +import './component/SpSystemTrace.js'; +import './component/SpRecordTrace.js'; +import './component/SpMetrics.js'; +import './component/SpInfoAndStas.js'; +import './component/trace/base/TraceRow.js'; +import './component/schedulingAnalysis/SpSchedulingAnalysis.js'; +import { info, log } from '../log/Log.js'; +import { LitMainMenuGroup } from '../base-ui/menu/LitMainMenuGroup.js'; +import { LitMainMenuItem } from '../base-ui/menu/LitMainMenuItem.js'; +import { LitIcon } from '../base-ui/icon/LitIcon.js'; +import { Cmd } from '../command/Cmd.js'; +import { TraceRow } from './component/trace/base/TraceRow.js'; +import { SpSchedulingAnalysis } from './component/schedulingAnalysis/SpSchedulingAnalysis.js'; +import './component/trace/base/TraceRowConfig.js'; +import { TraceRowConfig } from './component/trace/base/TraceRowConfig.js'; +import { ColorUtils } from './component/trace/base/ColorUtils.js'; +import { SpStatisticsHttpUtil } from '../statistics/util/SpStatisticsHttpUtil.js'; + +@element('sp-application') +export class SpApplication extends BaseElement { + private static loadingProgress: number = 0; + private static progressStep: number = 2; + static skinChange: Function | null | undefined = null; + static skinChange2: Function | null | undefined = null; + skinChangeArray: Array = []; + private icon: HTMLDivElement | undefined | null; + private rootEL: HTMLDivElement | undefined | null; + private spHelp: SpHelp | undefined | null; + private keyCodeMap = { + 61: true, + 107: true, + 109: true, + 173: true, + 187: true, + 189: true, + }; + colorTransiton: any; + + static get observedAttributes() { + return ['server', 'sqlite', 'wasm', 'dark', 'vs', 'query-sql', 'subsection']; + } + + get dark() { + return this.hasAttribute('dark'); + } + + set dark(value) { + if (value) { + this.rootEL!.classList.add('dark'); + this.setAttribute('dark', ''); + } else { + this.rootEL!.classList.remove('dark'); + this.removeAttribute('dark'); + } + if (this.skinChangeArray.length > 0) { + this.skinChangeArray.forEach((item) => item(value)); + } + if (SpApplication.skinChange) { + SpApplication.skinChange(value); + } + if (SpApplication.skinChange2) { + SpApplication.skinChange2(value); + } + + if (this.spHelp) { + this.spHelp.dark = value; + } + } + + get vs(): boolean { + return this.hasAttribute('vs'); + } + + set vs(isVs: boolean) { + if (isVs) { + this.setAttribute('vs', ''); + } + } + + get sqlite(): boolean { + return this.hasAttribute('sqlite'); + } + + get wasm(): boolean { + return this.hasAttribute('wasm'); + } + + get server(): boolean { + return this.hasAttribute('server'); + } + + set server(s: boolean) { + if (s) { + this.setAttribute('server', ''); + } else { + this.removeAttribute('server'); + } + } + + get querySql(): boolean { + return this.hasAttribute('query-sql'); + } + + set querySql(isShowMetric) { + if (isShowMetric) { + this.setAttribute('query-sql', ''); + } else { + this.removeAttribute('query-sql'); + } + } + + set search(search: boolean) { + if (search) { + this.setAttribute('search', ''); + } else { + this.removeAttribute('search'); + } + } + + get search(): boolean { + return this.hasAttribute('search'); + } + + addSkinListener(handler: Function) { + this.skinChangeArray.push(handler); + } + + removeSkinListener(handler: Function) { + this.skinChangeArray.splice(this.skinChangeArray.indexOf(handler), 1); + } + + initHtml(): string { + return ` + +
+ +
+ + + +
+
+ + + + + + + + + + + + +
+
+ `; + } + + initElements() { + SpStatisticsHttpUtil.initStatisticsServerConfig(); + SpStatisticsHttpUtil.addUserVisitAction('visit'); + let that = this; + this.querySql = true; + this.rootEL = this.shadowRoot!.querySelector('.root'); + let spWelcomePage = this.shadowRoot!.querySelector('#sp-welcome') as SpWelcomePage; + let spMetrics = this.shadowRoot!.querySelector('#sp-metrics') as SpMetrics; // new SpMetrics(); + let spQuerySQL = this.shadowRoot!.querySelector('#sp-query-sql') as SpQuerySQL; // new SpQuerySQL(); + let spInfoAndStats = this.shadowRoot!.querySelector('#sp-info-and-stats') as SpInfoAndStats; // new SpInfoAndStats(); + let spSystemTrace = this.shadowRoot!.querySelector('#sp-system-trace'); + this.spHelp = this.shadowRoot!.querySelector('#sp-help'); + let spRecordTrace = this.shadowRoot!.querySelector('#sp-record-trace'); + let spRecordTemplate = this.shadowRoot!.querySelector('#sp-record-template'); + let spSchedulingAnalysis = this.shadowRoot!.querySelector( + '#sp-scheduling-analysis' + ) as SpSchedulingAnalysis; + let appContent = this.shadowRoot?.querySelector('#app-content') as HTMLDivElement; + let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu; + let menu = mainMenu.shadowRoot?.querySelector('.menu-button') as HTMLDivElement; + let progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + let litSearch = this.shadowRoot?.querySelector('#lit-search') as LitSearch; + let search = this.shadowRoot?.querySelector('.search-container') as HTMLElement; + let sidebarButton: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button'); + let childNodes = [ + spSystemTrace, + spRecordTrace, + spWelcomePage, + spMetrics, + spQuerySQL, + spSchedulingAnalysis, + spInfoAndStats, + this.spHelp, + spRecordTemplate, + ]; + let sideColor = mainMenu.shadowRoot?.querySelector('.color') as HTMLDivElement; + //修改侧边导航栏配色 + sideColor!.onclick = (e) => { + let backgroundColor = sessionStorage.getItem('backgroundColor'); + let menu: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#main-menu'); + let menuGroup = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + let menuItem = menu!.shadowRoot?.querySelectorAll('lit-main-menu-item'); + if (backgroundColor == 'white' || !backgroundColor) { + menu!.style.backgroundColor = '#262f3c'; + menu!.style.transition = '1s'; + menuGroup!.forEach((item) => { + let groupName = item!.shadowRoot!.querySelector('.group-name') as LitMainMenuGroup; + let groupDescribe = item!.shadowRoot!.querySelector('.group-describe') as LitMainMenuGroup; + groupName.style.color = 'white'; + groupDescribe.style.color = 'white'; + }); + menuItem!.forEach((item) => { + item.style.color = 'white'; + }); + ColorUtils.MD_PALETTE = ColorUtils.MD_PALETTE_A; + ColorUtils.FUNC_COLOR = ColorUtils.FUNC_COLOR_A; + } else { + menu!.style.backgroundColor = 'white'; + menu!.style.transition = '1s'; + menuGroup!.forEach((item) => { + let groupName = item!.shadowRoot!.querySelector('.group-name') as LitMainMenuGroup; + let groupDescribe = item!.shadowRoot!.querySelector('.group-describe') as LitMainMenuGroup; + groupName.style.color = 'black'; + groupDescribe.style.color = '#92959b'; + }); + menuItem!.forEach((item) => { + item.style.color = 'var(--dark-color,rgba(0,0,0,0.6))'; + }); + ColorUtils.MD_PALETTE = ColorUtils.MD_PALETTE_B; + ColorUtils.FUNC_COLOR = ColorUtils.FUNC_COLOR_B; + } + + sessionStorage.setItem('backgroundColor', menu!.style.backgroundColor); + if (this.colorTransiton) { + clearTimeout(this.colorTransiton); + } + this.colorTransiton = setTimeout(() => { + menu!.style.transition = '0s'; + }, 1000); + }; + + window.subscribe(window.SmartEvent.UI.MenuTrace, () => showContent(spSystemTrace!)); + window.subscribe(window.SmartEvent.UI.Loading, (loading) => { + litSearch.setPercent(loading ? 'Import So File' : '', loading ? -1 : 101); + progressEL.loading = loading + }); + litSearch.addEventListener('focus', () => { + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: false, + }); + }); + litSearch.addEventListener('blur', () => { + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: true, + }); + }); + litSearch.addEventListener('previous-data', (ev: any) => { + litSearch.index = spSystemTrace!.showStruct(true, litSearch.index, litSearch.list); + litSearch.blur(); + }); + litSearch.addEventListener('next-data', (ev: any) => { + litSearch.index = spSystemTrace!.showStruct(false, litSearch.index, litSearch.list); + litSearch.blur(); + }); + litSearch.valueChangeHandler = (value: string) => { + if (value.length > 0) { + let list = spSystemTrace!.searchCPU(value); + spSystemTrace!.searchFunction(list, value).then((mixedResults) => { + if (litSearch.searchValue != '') { + litSearch.list = spSystemTrace!.searchSdk(mixedResults, value); + } + }); + } else { + litSearch.list = []; + spSystemTrace?.visibleRows.forEach((it) => { + it.highlight = false; + it.draw(); + }); + spSystemTrace?.timerShaftEL?.removeTriangle('inverted'); + } + }; + spSystemTrace?.addEventListener('previous-data', (ev: any) => { + litSearch.index = spSystemTrace!.showStruct(true, litSearch.index, litSearch.list); + }); + spSystemTrace?.addEventListener('next-data', (ev: any) => { + litSearch.index = spSystemTrace!.showStruct(false, litSearch.index, litSearch.list); + }); + + let filterConfig = this.shadowRoot?.querySelector('.filter-config') as LitIcon; + let configClose = this.shadowRoot + ?.querySelector('.chart-filter')! + .shadowRoot?.querySelector('.config-close'); + filterConfig.addEventListener('click', (ev) => { + if (this!.hasAttribute('chart_filter')) { + this!.removeAttribute('chart_filter'); + } else { + this!.setAttribute('chart_filter', ''); + } + }); + configClose!.addEventListener('click', (ev) => { + if (this.hasAttribute('chart_filter')) { + this!.removeAttribute('chart_filter'); + } + }); + + //打开侧边栏 + sidebarButton!.onclick = (e) => { + let menu: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#main-menu'); + let menuButton: HTMLElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button'); + if (menu) { + menu.style.width = `248px`; + // @ts-ignore + menu.style.zIndex = 2000; + menu.style.display = `flex`; + } + if (menuButton) { + menuButton.style.width = `0px`; + } + }; + let icon: HTMLDivElement | undefined | null = this.shadowRoot + ?.querySelector('#main-menu') + ?.shadowRoot?.querySelector('div.header > div'); + icon!.style.pointerEvents = 'none'; + icon!.onclick = (e) => { + let menu: HTMLElement | undefined | null = this.shadowRoot?.querySelector('#main-menu'); + let menuButton: HTMLElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button'); + if (menu) { + menu.style.width = `0px`; + menu.style.display = `flex`; + // @ts-ignore + menu.style.zIndex = 0; + } + if (menuButton) { + menuButton.style.width = `48px`; + } + }; + + function showContent(showNode: HTMLElement) { + if (showNode === spSystemTrace) { + menu!.style.pointerEvents = 'auto'; + sidebarButton!.style.pointerEvents = 'auto'; + that.search = true; + litSearch.setPercent('', 101); + litSearch.clear(); + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: true, + }); + filterConfig.style.visibility = 'visible'; + } else { + menu!.style.pointerEvents = 'none'; + sidebarButton!.style.pointerEvents = 'none'; + that.search = litSearch.isLoading; + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: false, + }); + filterConfig.style.visibility = 'hidden'; + } + log('show pages' + showNode.id); + childNodes.forEach((node) => { + if (that.hasAttribute('chart_filter')) { + that!.removeAttribute('chart_filter'); + } + if (node === showNode) { + showNode.style.visibility = 'visible'; + } else { + node!.style.visibility = 'hidden'; + } + }); + } + + function postLog(filename: string, fileSize: string) { + log('postLog filename is: ' + filename + ' fileSize: ' + fileSize); + fetch(`https://${window.location.host.split(':')[0]}:9000/logger`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + fileName: filename, + fileSize: fileSize, + }), + }) + .then((response) => response.json()) + .then((data) => {}) + .catch((error) => {}); + } + + function getTraceOptionMenus( + showFileName: string, + fileSize: string, + fileName: string, + isServer: boolean, + dbName?: string + ) { + let menus = [ + { + title: `${showFileName} (${fileSize}M)`, + icon: 'file-fill', + clickHandler: function () { + that.search = true; + showContent(spSystemTrace!); + }, + }, + { + title: 'Scheduling Analysis', + icon: 'piechart-circle-fil', + clickHandler: function () { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'Scheduling Analysis', + action: 'scheduling_analysis', + }); + showContent(spSchedulingAnalysis!); + spSchedulingAnalysis.init(); + }, + }, + { + title: 'Download File', + icon: 'download', + clickHandler: function () { + if (that.vs) { + that.vsDownload(mainMenu, fileName, isServer, dbName); + } else { + that.download(mainMenu, fileName, isServer, dbName); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'download', + action: 'download', + }); + } + }, + }, + { + title: 'Download Database', + icon: 'download', + clickHandler: function () { + if (that.vs) { + that.vsDownloadDB(mainMenu, fileName); + } else { + that.downloadDB(mainMenu, fileName); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'download_db', + action: 'download', + }); + } + }, + }, + ]; + if (that.querySql) { + if (spQuerySQL) { + spQuerySQL.reset(); + menus.push({ + title: 'Query (SQL)', + icon: 'filesearch', + clickHandler: () => { + showContent(spQuerySQL); + }, + }); + } + + if (spMetrics) { + spMetrics.reset(); + menus.push({ + title: 'Metrics', + icon: 'metric', + clickHandler: () => { + showContent(spMetrics); + }, + }); + } + + if (spInfoAndStats) { + menus.push({ + title: 'Info and stats', + icon: 'info', + clickHandler: () => { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'info', + action: 'info_stats', + }); + showContent(spInfoAndStats); + }, + }); + } + } + if ((window as any).cpuCount === 0) { + //if cpu count > 1 then show Scheduling-Analysis menu else hide it + menus.splice(1, 1); + } + return menus; + } + + function setProgress(command: string) { + if (command == 'database ready' && SpApplication.loadingProgress < 50) { + SpApplication.progressStep = 6; + } + if (command == 'process' && SpApplication.loadingProgress < 92) { + SpApplication.loadingProgress = 92 + Math.round(Math.random() * SpApplication.progressStep); + } else { + SpApplication.loadingProgress += Math.round(Math.random() * SpApplication.progressStep + Math.random()); + } + if (SpApplication.loadingProgress > 99) { + SpApplication.loadingProgress = 99; + } + info('setPercent :' + command + 'percent :' + SpApplication.loadingProgress); + litSearch.setPercent(command + ' ', SpApplication.loadingProgress); + } + + function handleServerMode( + ev: any, + showFileName: string, + fileSize: string, + fileName: string, + isClickHandle?: boolean + ) { + threadPool.init('server').then(() => { + info('init server ok'); + litSearch.setPercent('parse trace', 1); + // Load the trace file and send it to the background parse to return the db file path + const fd = new FormData(); + if (that.vs && isClickHandle) { + fd.append('convertType', 'vsUpload'); + fd.append('filePath', ev as any); + } else { + fd.append('file', ev as any); + } + let uploadPath = `https://${window.location.host.split(':')[0]}:9000/upload`; + if (that.vs) { + uploadPath = `http://${window.location.host.split(':')[0]}:${window.location.port}/upload`; + } + info('upload trace'); + let dbName = ''; + fetch(uploadPath, { + method: 'POST', + body: fd, + }) + .then((res) => { + litSearch.setPercent('load database', 5); + if (res.ok) { + info(' server Parse trace file success'); + return res.text(); + } else { + if (res.status == 404) { + info(' server Parse trace file failed'); + litSearch.setPercent('This File is not supported!', -1); + progressEL.loading = false; + that.freshMenuDisable(false); + return Promise.reject(); + } + } + }) + .then((res) => { + if (res != undefined) { + dbName = res; + info('get trace db'); + let loadPath = `https://${window.location.host.split(':')[0]}:9000`; + if (that.vs) { + loadPath = `http://${window.location.host.split(':')[0]}:${window.location.port}`; + } + SpApplication.loadingProgress = 0; + SpApplication.progressStep = 3; + spSystemTrace!.loadDatabaseUrl( + loadPath + res, + (command: string, percent: number) => { + setProgress(command); + }, + (res) => { + info('loadDatabaseUrl success'); + mainMenu.menus!.splice(1, mainMenu.menus!.length > 2 ? 1 : 0, { + collapsed: false, + title: 'Current Trace', + describe: 'Actions on the current trace', + children: getTraceOptionMenus(showFileName, fileSize, fileName, true, dbName), + }); + litSearch.setPercent('', 101); + progressEL.loading = false; + that.freshMenuDisable(false); + } + ); + } else { + litSearch.setPercent('', 101); + progressEL.loading = false; + that.freshMenuDisable(false); + } + spInfoAndStats.initInfoAndStatsData(); + }); + }); + } + + function handleWasmMode(ev: any, showFileName: string, fileSize: string, fileName: string) { + litSearch.setPercent('', 1); + threadPool.init('wasm').then((res) => { + let reader = new FileReader(); + reader.readAsArrayBuffer(ev as any); + reader.onloadend = function (ev) { + info('read file onloadend'); + litSearch.setPercent('ArrayBuffer loaded ', 2); + let wasmUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; + if (that.vs) { + wasmUrl = `http://${window.location.host.split(':')[0]}:${window.location.port}/wasm.json`; + } + SpApplication.loadingProgress = 0; + SpApplication.progressStep = 3; + spSystemTrace!.loadDatabaseArrayBuffer( + this.result as ArrayBuffer, + wasmUrl, + (command: string, percent: number) => { + setProgress(command); + }, + (res) => { + mainMenu.menus!.splice(2, 1, { + collapsed: false, + title: 'Support', + describe: 'Support', + children: [ + { + title: 'Help Documents', + icon: 'smart-help', + clickHandler: function (item: MenuItem) { + that.search = false; + that.spHelp!.dark = that.dark; + showContent(that.spHelp!); + }, + }, + ], + }); + if (res.status) { + info('loadDatabaseArrayBuffer success'); + mainMenu.menus!.splice(1, mainMenu.menus!.length > 2 ? 1 : 0, { + collapsed: false, + title: 'Current Trace', + describe: 'Actions on the current trace', + children: getTraceOptionMenus(showFileName, fileSize, fileName, false), + }); + showContent(spSystemTrace!); + litSearch.setPercent('', 101); + progressEL.loading = false; + that.freshMenuDisable(false); + } else { + info('loadDatabaseArrayBuffer failed'); + litSearch.setPercent(res.msg || 'This File is not supported!', -1); + progressEL.loading = false; + that.freshMenuDisable(false); + mainMenu.menus!.splice(1, 1); + mainMenu.menus = mainMenu.menus!; + } + spInfoAndStats.initInfoAndStatsData(); + } + ); + }; + }); + } + + let openFileInit = () => { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'open_trace', + action: 'open_trace', + }); + info('openTraceFile'); + spSystemTrace!.clearPointPair(); + window.clearTraceRowComplete(); + that.freshMenuDisable(true); + SpSchedulingAnalysis.resetCpu(); + if (mainMenu.menus!.length > 2) { + mainMenu.menus!.splice(1, 1); + mainMenu.menus = mainMenu.menus!; + } + }; + + function openTraceFile(ev: any, isClickHandle?: boolean) { + openFileInit(); + if (that.vs && isClickHandle) { + Cmd.openFileDialog().then((res: string) => { + if (res != '') { + litSearch.clear(); + showContent(spSystemTrace!); + that.search = true; + progressEL.loading = true; + let openResult = JSON.parse(res); + let fileName = openResult.fileName; + let fileSize = (openResult.fileSize / 1048576).toFixed(1); + let showFileName = + fileName.lastIndexOf('.') == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.')); + document.title = `${showFileName} (${fileSize}M)`; + TraceRow.rangeSelectObject = undefined; + if (that.server) { + info('Parse trace using server mode '); + handleServerMode(openResult.filePath, showFileName, fileSize, fileName, isClickHandle); + return; + } + if (that.wasm) { + info('Parse trace using wasm mode '); + const vsUpload = new FormData(); + vsUpload.append('convertType', 'vsUpload'); + vsUpload.append('isTransform', ''); + vsUpload.append('filePath', openResult.filePath); + info('openResult.filePath ', openResult.filePath); + litSearch.setPercent('upload file ', 1); + Cmd.uploadFile(vsUpload, (response: Response) => { + if (response.ok) { + response.text().then((traceFile) => { + let traceFilePath = + `http://${window.location.host.split(':')[0]}:${window.location.port}` + traceFile; + fetch(traceFilePath).then((res) => { + res.arrayBuffer().then((arrayBuf) => { + handleWasmMode(new File([arrayBuf], fileName), showFileName, fileSize, fileName); + }); + }); + }); + } + }); + return; + } + } else { + return; + } + }); + } else { + litSearch.clear(); + showContent(spSystemTrace!); + that.search = true; + progressEL.loading = true; + let fileName = (ev as any).name; + let fileSize = ((ev as any).size / 1048576).toFixed(1); + postLog(fileName, fileSize); + let showFileName = + fileName.lastIndexOf('.') == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.')); + document.title = `${showFileName} (${fileSize}M)`; + TraceRow.rangeSelectObject = undefined; + if (that.server) { + info('Parse trace using server mode '); + handleServerMode(ev, showFileName, fileSize, fileName); + return; + } + if (that.sqlite) { + info('Parse trace using sql mode'); + litSearch.setPercent('', 0); + threadPool.init('sqlite').then((res) => { + let reader = new FileReader(); + reader.readAsArrayBuffer(ev as any); + reader.onloadend = function (ev) { + SpApplication.loadingProgress = 0; + SpApplication.progressStep = 3; + spSystemTrace!.loadDatabaseArrayBuffer( + this.result as ArrayBuffer, + '', + (command: string, percent: number) => { + setProgress(command); + }, + () => { + mainMenu.menus!.splice(1, mainMenu.menus!.length > 2 ? 1 : 0, { + collapsed: false, + title: 'Current Trace', + describe: 'Actions on the current trace', + children: getTraceOptionMenus(showFileName, fileSize, fileName, false), + }); + litSearch.setPercent('', 101); + progressEL.loading = false; + that.freshMenuDisable(false); + } + ); + }; + }); + return; + } + if (that.wasm) { + info('Parse trace using wasm mode '); + handleWasmMode(ev, showFileName, fileSize, fileName); + return; + } + } + } + + mainMenu.menus = [ + { + collapsed: false, + title: 'Navigation', + describe: 'Open or record a new trace', + children: [ + { + title: 'Open trace file', + icon: 'folder', + fileChoose: !that.vs, + fileHandler: function (ev: InputEvent) { + openTraceFile(ev.detail as any); + }, + clickHandler: function (hand: any) { + openTraceFile(hand, true); + }, + }, + { + title: 'Record new trace', + icon: 'copyhovered', + clickHandler: function (item: MenuItem) { + if (that.vs) { + spRecordTrace!.vs = true; + spRecordTrace!.startRefreshDeviceList(); + } + spRecordTrace!.synchronizeDeviceList(); + showContent(spRecordTrace!); + }, + }, + { + title: 'Record template', + icon: 'copyhovered', + clickHandler: function (item: MenuItem) { + if (that.vs) { + spRecordTemplate!.vs = true; + spRecordTemplate!.startRefreshDeviceList(); + } + spRecordTemplate!.synchronizeDeviceList(); + showContent(spRecordTemplate!); + }, + }, + ], + }, + { + collapsed: false, + title: 'Support', + describe: 'Support', + children: [ + { + title: 'Help Documents', + icon: 'smart-help', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'help_page', + action: 'help_doc', + }); + that.search = false; + that.spHelp!.dark = that.dark; + showContent(that.spHelp!); + }, + }, + ], + }, + ]; + + let body = document.querySelector('body'); + body!.addEventListener( + 'dragover', + (e: any) => { + e.preventDefault(); + e.stopPropagation(); + if (e.dataTransfer.items.length > 0 && e.dataTransfer.items[0].kind === 'file') { + e.dataTransfer.dropEffect = 'copy'; + if (!this.rootEL!.classList.contains('filedrag')) { + this.rootEL!.classList.add('filedrag'); + } + } + }, + false + ); + body!.addEventListener( + 'dragleave', + (e) => { + e.stopPropagation(); + e.preventDefault(); + if (this.rootEL!.classList.contains('filedrag')) { + this.rootEL!.classList.remove('filedrag'); + } + }, + false + ); + body!.addEventListener( + 'drop', + (e: any) => { + e.preventDefault(); + e.stopPropagation(); + if (this.rootEL!.classList.contains('filedrag')) { + this.rootEL!.classList.remove('filedrag'); + } + if (e.dataTransfer.items !== undefined && e.dataTransfer.items.length > 0) { + let item = e.dataTransfer.items[0]; + if (item.webkitGetAsEntry()?.isFile) { + openTraceFile(item.getAsFile()); + } else if (item.webkitGetAsEntry()?.isDirectory) { + litSearch.setPercent('This File is not supported!', -1); + progressEL.loading = false; + that.freshMenuDisable(false); + mainMenu.menus!.splice(1, 1); + mainMenu.menus = mainMenu.menus!; + spSystemTrace!.reset(null); + } + } + }, + false + ); + document.addEventListener('keydown', (event) => { + const e = event || window.event; + const ctrlKey = e.ctrlKey || e.metaKey; + if (ctrlKey && (this.keyCodeMap as any)[e.keyCode]) { + e.preventDefault(); + } else if (e.detail) { + // Firefox + event.returnValue = false; + } + }); + document.body.addEventListener( + 'wheel', + (e) => { + if (e.ctrlKey) { + if (e.deltaY < 0) { + e.preventDefault(); + return false; + } + if (e.deltaY > 0) { + e.preventDefault(); + return false; + } + } + }, + { passive: false } + ); + + const openMenu = (open: boolean) => { + if (mainMenu) { + mainMenu.style.width = open ? `248px` : '0px'; + mainMenu.style.zIndex = open ? '2000' : '0'; + } + if (sidebarButton) { + sidebarButton.style.width = open ? `0px` : '48px'; + } + } + + let urlParams = this.getUrlParams(window.location.href); + if (urlParams && urlParams.trace && urlParams.link) { + openFileInit(); + openMenu(false); + litSearch.clear(); + showContent(spSystemTrace!); + that.search = true; + progressEL.loading = true; + let downloadLineFile = false; + setProgress(downloadLineFile ? 'download trace file' : 'open trace file'); + this.downloadOnLineFile(urlParams.trace, downloadLineFile,(localPath) => { + let path = urlParams.trace as string; + let fileName = path.split('/').reverse()[0]; + let showFileName = + fileName.lastIndexOf('.') == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.')); + TraceRow.rangeSelectObject = undefined; + let localUrl = downloadLineFile ? `${window.location.origin}${localPath}` : urlParams.trace; + fetch(localUrl).then((res) => { + res.arrayBuffer().then((arrayBuf) => { + let fileSize = (arrayBuf.byteLength / 1048576).toFixed(1); + postLog(fileName, fileSize); + document.title = `${showFileName} (${fileSize}M)`; + info('Parse trace using wasm mode '); + handleWasmMode(new File([arrayBuf], fileName), showFileName, fileSize, fileName); + }); + }); + }); + } else { + openMenu(true); + } + } + + private downloadOnLineFile(url: string, download: boolean, openFileHandler: (path: string) => void) { + if (download) { + let api = `${window.location.origin}/download-file`; + fetch(api, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + url: url, + }), + }) + .then((response) => response.json()) + .then((res) => { + if (res.code === 0 && res.success) { + let resultUrl = res.data.url; + if (resultUrl) { + openFileHandler(resultUrl.toString().replace(/\\/g, '/')); + } + } + }); + } else { + openFileHandler(url); + } + } + + private getUrlParams(url: string) { + const _url = url || window.location.href; + const _urlParams = _url.match(/([?&])(.+?=[^&]+)/gim); + return _urlParams + ? _urlParams.reduce((a: any, b) => { + const value = b.slice(1).split('='); + a[`${value[0]}`] = decodeURIComponent(value[1]); + return a; + }, {}) + : {}; + } + + private downloadDB(mainMenu: LitMainMenu, fileDbName: string) { + let fileName = fileDbName?.substring(0, fileDbName?.lastIndexOf('.')) + '.db'; + threadPool.submit( + 'download-db', + '', + {}, + (reqBufferDB: any) => { + let a = document.createElement('a'); + a.href = URL.createObjectURL(new Blob([reqBufferDB])); + a.download = fileName; + a.click(); + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == 'Download Database') { + item!.setAttribute('icon', 'convert-loading'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.setAttribute('spin', ''); + } + }); + } + }); + window.URL.revokeObjectURL(a.href); + let timer = setInterval(function () { + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == 'Download Database') { + item!.setAttribute('icon', 'download'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.removeAttribute('spin'); + } + }); + clearInterval(timer); + } + }); + }, 4000); + }, + 'download-db' + ); + } + + private download(mainMenu: LitMainMenu, fileName: string, isServer: boolean, dbName?: string) { + let a = document.createElement('a'); + if (isServer) { + if (dbName != '') { + let file = dbName?.substring(0, dbName?.lastIndexOf('.')) + fileName.substring(fileName.lastIndexOf('.')); + a.href = `https://${window.location.host.split(':')[0]}:9000` + file; + } else { + return; + } + } else { + a.href = URL.createObjectURL(new Blob([DbPool.sharedBuffer!])); + } + a.download = fileName; + a.click(); + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == 'Download File') { + item!.setAttribute('icon', 'convert-loading'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.setAttribute('spin', ''); + } + }); + } + }); + window.URL.revokeObjectURL(a.href); + let timer = setInterval(function () { + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == 'Download File') { + item!.setAttribute('icon', 'download'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.removeAttribute('spin'); + } + }); + clearInterval(timer); + } + }); + }, 4000); + } + + private vsDownloadDB(mainMenu: LitMainMenu, fileDbName: string) { + let fileName = fileDbName?.substring(0, fileDbName?.lastIndexOf('.')) + '.db'; + threadPool.submit( + 'download-db', + '', + {}, + (reqBufferDB: any) => { + Cmd.showSaveFile((filePath: string) => { + if (filePath != '') { + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == 'Download Database') { + item!.setAttribute('icon', 'convert-loading'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.setAttribute('spin', ''); + } + }); + } + }); + const fd = new FormData(); + fd.append('convertType', 'download'); + fd.append('filePath', filePath); + fd.append('file', new File([reqBufferDB], fileName)); + Cmd.uploadFile(fd, (res: Response) => { + if (res.ok) { + this.stopDownLoading(mainMenu, 'Download Database'); + } + }); + } + }); + }, + 'download-db' + ); + } + + private vsDownload(mainMenu: LitMainMenu, fileName: string, isServer: boolean, dbName?: string) { + Cmd.showSaveFile((filePath: string) => { + if (filePath != '') { + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == 'DownLoad') { + item!.setAttribute('icon', 'convert-loading'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.setAttribute('spin', ''); + } + }); + } + }); + if (isServer) { + if (dbName != '') { + let file = dbName?.substring(0, dbName?.lastIndexOf('.')) + fileName.substring(fileName.lastIndexOf('.')); + Cmd.copyFile(file, filePath, (res: Response) => { + this.stopDownLoading(mainMenu); + }); + } + } else { + const fd = new FormData(); + fd.append('convertType', 'download'); + fd.append('filePath', filePath); + fd.append('file', new File([DbPool.sharedBuffer!], fileName)); + Cmd.uploadFile(fd, (res: Response) => { + if (res.ok) { + this.stopDownLoading(mainMenu); + } + }); + } + } + }); + } + + private stopDownLoading(mainMenu: LitMainMenu, title: string = 'Download File') { + let querySelectorAll = mainMenu.shadowRoot?.querySelectorAll('lit-main-menu-group'); + querySelectorAll!.forEach((menuGroup) => { + let attribute = menuGroup.getAttribute('title'); + if (attribute === 'Current Trace') { + let querySelectors = menuGroup.querySelectorAll('lit-main-menu-item'); + querySelectors.forEach((item) => { + if (item.getAttribute('title') == title) { + item!.setAttribute('icon', 'download'); + let querySelector1 = item!.shadowRoot?.querySelector('.icon') as LitIcon; + querySelector1.removeAttribute('spin'); + } + }); + } + }); + } + + freshMenuDisable(disable: boolean) { + let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu; + // @ts-ignore + mainMenu.menus[0].children[0].disabled = disable; + if (mainMenu.menus!.length > 2) { + // @ts-ignore + mainMenu.menus[1].children.map((it) => (it.disabled = disable)); + } + mainMenu.menus = mainMenu.menus; + let litIcon = this.shadowRoot?.querySelector('.filter-config') as LitIcon; + if (disable) { + litIcon.style.visibility = 'hidden'; + } else { + litIcon.style.visibility = 'visible'; + let chartFilter = this.shadowRoot?.querySelector('.chart-filter') as TraceRowConfig; + chartFilter!.setAttribute('mode', ''); + } + } +} diff --git a/ide/src/trace/bean/AbilityMonitor.ts b/ide/src/trace/bean/AbilityMonitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..34cc931dcd405a6b66c267299b4e550948d038b7 --- /dev/null +++ b/ide/src/trace/bean/AbilityMonitor.ts @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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. + */ + +export class SystemCpuSummary { + startTime: number = -1; + startTimeStr: string = ''; + duration: number = -1; + durationStr: string = ''; + totalLoad: number = -1; + totalLoadStr: string = ''; + userLoad: number = -1; + userLoadStr: string = ''; + systemLoad: number = -1; + systemLoadStr: string = ''; + threads: number = -1; + threadsStr: string = ''; +} + +export class SystemDiskIOSummary { + startTime: number = -1; + startTimeStr: string = ''; + duration: number = -1; + durationStr: string = ''; + dataRead: number = -1; + dataReadStr: string = ''; + dataReadSec: number = -1; + dataReadSecStr: string = ''; + dataWrite: number = -1; + dataWriteStr: string = ''; + dataWriteSec: number = -1; + dataWriteSecStr: string = ''; + readsIn: number = -1; + readsInStr: string = ''; + readsInSec: number = -1; + readsInSecStr: string = ''; + writeOut: number = -1; + writeOutStr: string = ''; + writeOutSec: number = -1; + writeOutSecStr: string = ''; +} + +export class ProcessHistory { + processId: number = -1; + alive: string = ''; // 0 alive and 1 dead + firstSeen: string = ''; + firstSeenNumber: number = -1; + lastSeen: string = ''; + lastSeenNumber: number = -1; + processName: string = ''; + responsibleProcess: string = ''; + userName: string = ''; + cpuTime: string = ''; + cpuTimeNumber: number = -1; + pss: number = -1; +} + +export class LiveProcess { + processId: number = -1; + processName: string = ''; + responsibleProcess: string = ''; + userName: string = ''; + cpu: string = ''; + threads: number = -1; + memory: string = ''; + memoryNumber: number = -1; + diskWrite: number = -1; + diskReads: number = -1; + cpuTime: string = ''; + cpuTimeNumber: number = -1; +} + +export class SystemNetworkSummary { + startTime: number = -1; + startTimeStr: string = ''; + duration: number = -1; + durationStr: string = ''; + dataReceived: number = -1; + dataReceivedStr: string = ''; + dataReceivedSec: number = -1; + dataReceivedSecStr: string = ''; + dataSend: number = -1; + dataSendStr: string = ''; + dataSendSec: number = -1; + dataSendSecStr: string = ''; + packetsIn: number = -1; + packetsInStr: string = ''; + packetsInSec: number = -1; + packetsInSecStr: string = ''; + packetsOut: number = -1; + packetsOutStr: string = ''; + packetsOutSec: number = -1; + packetsOutSecStr: string = ''; +} + +export class SystemMemorySummary { + startTimeStr: string = '0'; + durationStr: string = '0'; + durationNumber: number = -1; + memoryTotal: string = '0'; + memFree: string = '0'; + buffers: string = '0'; + cached: string = '0'; + shmem: string = '0'; + slab: string = '0'; + swapTotal: string = '0'; + swapFree: string = '0'; + mapped: string = '0'; + vmallocUsed: string = '0'; + pageTables: string = '0'; + kernelStack: string = '0'; + active: string = '0'; + inactive: string = '0'; + unevictable: string = '0'; + vmallocTotal: string = '0'; + sUnreclaim: string = '0'; + kReclaimable: string = '0'; + cmaTotal: string = '0'; + cmaFree: string = '0'; + zram: string = '0'; +} diff --git a/ide/src/trace/bean/BaseStruct.ts b/ide/src/trace/bean/BaseStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..303a1b3915dca7dcd2f919829d0d0c53fe1bd813 --- /dev/null +++ b/ide/src/trace/bean/BaseStruct.ts @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2022 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 { Rect } from '../component/trace/timer-shaft/Rect.js'; + +export class BaseStruct { + frame: Rect | undefined; + isHover: boolean = false; +} diff --git a/ide/src/trace/bean/BinderArgBean.ts b/ide/src/trace/bean/BinderArgBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b135433e86876edf29109104ec8351c588bd1dc --- /dev/null +++ b/ide/src/trace/bean/BinderArgBean.ts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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. + */ + +export class BinderArgBean { + argset: number | undefined; + keyName: string | undefined; + id: number | undefined; + desc: string | undefined; + strValue: string | undefined; +} diff --git a/ide/src/trace/bean/BoxSelection.ts b/ide/src/trace/bean/BoxSelection.ts new file mode 100644 index 0000000000000000000000000000000000000000..20b9f15755c7daa23991f791b760f1e654be5064 --- /dev/null +++ b/ide/src/trace/bean/BoxSelection.ts @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2022 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 { CpuFreqLimitsStruct } from '../database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; +import { ClockStruct } from '../database/ui-worker/ProcedureWorkerClock.js'; +import { IrqStruct } from '../database/ui-worker/ProcedureWorkerIrq.js'; + +export class SelectionParam { + recordStartNs: number = 0; + leftNs: number = 0; + rightNs: number = 0; + hasFps: boolean = false; + statisticsSelectData: any = undefined; + fileSystemVMData: any = undefined; + fileSystemIoData: any = undefined; + fileSystemFsData: any = undefined; + perfAll: boolean = false; + fileSysVirtualMemory: boolean = false; + diskIOLatency: boolean = false; + fsCount: number = 0; + vmCount: number = 0; + + cpus: Array = []; + cpuStateFilterIds: Array = []; + cpuFreqFilterIds: Array = []; + cpuFreqLimitDatas: Array> = []; + threadIds: Array = []; + processTrackIds: Array = []; + virtualTrackIds: Array = []; + clockMapData: Map> = new Map>(); + irqMapData: Map> = new Map>(); + funTids: Array = []; + funAsync: Array<{ name: string; pid: number }> = []; + nativeMemory: Array = []; + nativeMemoryStatistic: Array = []; + cpuAbilityIds: Array = []; + memoryAbilityIds: Array = []; + diskAbilityIds: Array = []; + networkAbilityIds: Array = []; + perfSampleIds: Array = []; + perfCpus: Array = []; + perfProcess: Array = []; + perfThread: Array = []; + fileSystemType: Array = []; + sdkCounterIds: Array = []; + sdkSliceIds: Array = []; + diskIOipids: Array = []; + diskIOReadIds: Array = []; + diskIOWriteIds: Array = []; + systemEnergy: Array = []; + powerEnergy: Array = []; + anomalyEnergy: Array = []; + smapsType: Array = []; + promiseList: Array> = []; + jankFramesData: Array = []; + jsMemory: Array = []; +} + +export class BoxJumpParam { + leftNs: number = 0; + rightNs: number = 0; + state: string = ''; + processId: number = 0; + threadId: number = 0; +} + +export class SelectionData { + name: string = ''; + process: string = ''; + pid: string = ''; + thread: string = ''; + tid: string = ''; + wallDuration: number = 0; + wallDurationFormat: string = ''; + avgDuration: string = ''; + occurrences: number = 0; + state: string = ''; + trackId: number = 0; + delta: string = ''; + rate: string = ''; + avgWeight: string = ''; + count: string = ''; + first: string = ''; + last: string = ''; + min: string = ''; + max: string = ''; + stateJX: string = ''; + cpu: number = 0; +} + +export class Counter { + id: number = 0; + trackId: number = 0; + name: string = ''; + value: number = 0; + startTime: number = 0; +} + +export class Fps { + startNS: number = 0; + timeStr: string = ''; + fps: number = 0; +} diff --git a/ide/src/trace/bean/CpuAbilityMonitorStruct.ts b/ide/src/trace/bean/CpuAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..4fc096881cf3e819b24e879b0933b4b6d4252b1d --- /dev/null +++ b/ide/src/trace/bean/CpuAbilityMonitorStruct.ts @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; + +export class CpuAbilityMonitorStruct extends BaseStruct { + static maxCpuUtilization: number = 0; + static maxCpuUtilizationName: string = '0 %'; + static hoverCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + static selectCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + + type: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; +} diff --git a/ide/src/trace/bean/CpuFreqStruct.ts b/ide/src/trace/bean/CpuFreqStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..a7e7a7b05ab4311b5c94f996cec14cb22a28e61e --- /dev/null +++ b/ide/src/trace/bean/CpuFreqStruct.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../component/trace/base/ColorUtils.js'; +import { BaseStruct } from './BaseStruct.js'; + +export class CpuFreqStruct extends BaseStruct { + static maxFreq: number = 0; + static maxFreqName: string = '0 GHz'; + static hoverCpuFreqStruct: CpuFreqStruct | undefined; + static selectCpuFreqStruct: CpuFreqStruct | undefined; + cpu: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; // Self-supplementing, the database is not returned + + static draw(ctx: any, data: CpuFreqStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = data.cpu || 0; + index += 2; + ctx.fillStyle = ColorUtils.colorForTid(index); + ctx.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === CpuFreqStruct.hoverCpuFreqStruct?.startNS) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / CpuFreqStruct.maxFreq + ); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / CpuFreqStruct.maxFreq); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} + +const textPadding = 2; diff --git a/ide/src/trace/bean/CpuStruct.ts b/ide/src/trace/bean/CpuStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..30f9c72f71c8ceeaa8ad18097f508d716305c765 --- /dev/null +++ b/ide/src/trace/bean/CpuStruct.ts @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../component/trace/base/ColorUtils.js'; +import { BaseStruct } from './BaseStruct.js'; +import { WakeupBean } from './WakeupBean.js'; + +export class CpuStruct extends BaseStruct { + static cpuCount: number; //最大cpu数量 + static hoverCpuStruct: CpuStruct | undefined; + static selectCpuStruct: CpuStruct | undefined; + static wakeupBean: WakeupBean | null | undefined = null; + cpu: number | undefined; + dur: number | undefined; + end_state: string | undefined; + id: number | undefined; + name: string | undefined; + priority: number | undefined; + processCmdLine: string | undefined; + processId: number | undefined; + processName: string | undefined; + schedId: number | undefined; + startTime: number | undefined; + tid: number | undefined; + type: string | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: CpuStruct) { + if (data.frame) { + let width = data.frame.width || 0; + if (data.processId === CpuStruct.hoverCpuStruct?.processId || !CpuStruct.hoverCpuStruct) { + ctx.fillStyle = ColorUtils.colorForTid((data.processId || 0) > 0 ? data.processId || 0 : data.tid || 0); + } else { + ctx.fillStyle = '#e0e0e0'; + } + ctx.fillRect(data.frame.x, data.frame.y, width, data.frame.height); + if (width > textPadding * 2) { + let process = `${data.processName || 'Process'} [${data.processId}]`; + let thread = `${data.name || 'Thread'} [${data.tid}]`; + let processMeasure = ctx.measureText(process); + let threadMeasure = ctx.measureText(thread); + let processCharWidth = Math.round(processMeasure.width / process.length); + let threadCharWidth = Math.round(threadMeasure.width / thread.length); + ctx.fillStyle = '#ffffff'; + let y = data.frame.height / 2 + data.frame.y; + if (processMeasure.width < width - textPadding * 2) { + let x1 = Math.floor(width / 2 - processMeasure.width / 2 + data.frame.x + textPadding); + ctx.textBaseline = 'bottom'; + ctx.fillText(process, x1, y, width - textPadding * 2); + } else if (width - textPadding * 2 > processCharWidth * 4) { + let chatNum = (width - textPadding * 2) / processCharWidth; + let x1 = data.frame.x + textPadding; + ctx.textBaseline = 'bottom'; + ctx.fillText(process.substring(0, chatNum - 4) + '...', x1, y, width - textPadding * 2); + } + if (threadMeasure.width < width - textPadding * 2) { + ctx.textBaseline = 'top'; + let x2 = Math.floor(width / 2 - threadMeasure.width / 2 + data.frame.x + textPadding); + ctx.fillText(thread, x2, y + 2, width - textPadding * 2); + } else if (width - textPadding * 2 > threadCharWidth * 4) { + let chatNum = (width - textPadding * 2) / threadCharWidth; + let x1 = data.frame.x + textPadding; + ctx.textBaseline = 'top'; + ctx.fillText(thread.substring(0, chatNum - 4) + '...', x1, y + 2, width - textPadding * 2); + } + } + if (CpuStruct.selectCpuStruct && CpuStruct.equals(CpuStruct.selectCpuStruct, data)) { + ctx.strokeStyle = '#232c5d'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y, width - 2, data.frame.height); + } + } + } + + static equals(d1: CpuStruct, d2: CpuStruct): boolean { + if ( + d1 && + d2 && + d1.cpu == d2.cpu && + d1.tid == d2.tid && + d1.processId == d2.processId && + d1.startTime == d2.startTime && + d1.dur == d2.dur + ) { + return true; + } else { + return false; + } + } +} + +const textPadding = 2; diff --git a/ide/src/trace/bean/CpuUsage.ts b/ide/src/trace/bean/CpuUsage.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5456f902467cdbfd8ef46b4b79e8cefdd26eefe --- /dev/null +++ b/ide/src/trace/bean/CpuUsage.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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. + */ + +export class CpuUsage { + cpu: number = 0; + usage: number = 0; + usageStr: string = ''; + top1: number = 0; + top2: number = 0; + top3: number = 0; + top1Percent: number = 0; + top1PercentStr: string = ''; + top2Percent: number = 0; + top2PercentStr: string = ''; + top3Percent: number = 0; + top3PercentStr: string = ''; +} + +export class Freq { + cpu: number = 0; + value: number = 0; + startNs: number = 0; + dur: number = 0; +} diff --git a/ide/src/trace/bean/DiskAbilityMonitorStruct.ts b/ide/src/trace/bean/DiskAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a9d9919ffdada3a96176432e325b47a75e36c71 --- /dev/null +++ b/ide/src/trace/bean/DiskAbilityMonitorStruct.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../component/trace/base/ColorUtils.js'; +import { BaseStruct } from './BaseStruct.js'; + +export class DiskAbilityMonitorStruct extends BaseStruct { + static maxDiskRate: number = 0; + static maxDiskRateName: string = '0 KB/S'; + static hoverDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + static selectDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + cpu: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; + + static draw(context2D: any, data: DiskAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = data.cpu || 0; + index += 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / DiskAbilityMonitorStruct.maxDiskRate + ); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0)) / DiskAbilityMonitorStruct.maxDiskRate + ); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/ide/src/trace/bean/EnergyStruct.ts b/ide/src/trace/bean/EnergyStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..48a5dc4c69d9612ecf9d8ec019f47de15c5f87d1 --- /dev/null +++ b/ide/src/trace/bean/EnergyStruct.ts @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; + +export class EnergyAnomalyStruct extends BaseStruct { + static hoverEnergyAnomalyStruct: EnergyAnomalyStruct | undefined; + static selectEnergyAnomalyStruct: EnergyAnomalyStruct | undefined; + type: number | undefined; + startNS: number | undefined; + height: number | undefined; + eventName: string | undefined; +} + +export class EnergySystemStruct extends BaseStruct { + static hoverEnergySystemStruct: EnergySystemStruct | undefined; + static selectEnergySystemStruct: EnergySystemStruct | undefined; + type: number | undefined; + startNs: number | undefined; + dur: number | undefined; + count: number | undefined; + workScheduler: string | undefined; + power: string | undefined; + location: string | undefined; +} + +export class EnergyPowerStruct extends BaseStruct { + static maxPower: number = 0; + static maxPowerName: string = '0 %'; + static powerItemNumber: number = 9; + static colorIndex: number = 2; + static currentTextWidth: number = 0; + static rowHeight: number = 200; + static appName: string | undefined; + static hoverEnergyPowerStruct: EnergyPowerStruct | undefined; + static selectEnergyPowerStruct: EnergyPowerStruct | undefined; + name: string | undefined; // appName + ts: number = 0; + cpu: number = 0; + location: number = 0; + gpu: number = 0; + display: number = 0; + camera: number = 0; + bluetooth: number = 0; + flashlight: number = 0; + audio: number = 0; + wifiscan: number = 0; +} + +export class EnergyStateStruct extends BaseStruct { + static maxState: number = 0; + static maxStateName: string = '0'; + static hoverEnergyStateStruct: EnergyStateStruct | undefined; + static selectEnergyStateStruct: EnergyStateStruct | undefined; + type: string | undefined; + value: number | undefined; + startNs: number | undefined; + dur: number | undefined; + + sensorType: number | undefined; + pkg_name: string | undefined; + deviceState: number | undefined; + deviceType: number | undefined; +} + +export class PowerDetailsEnergy { + constructor(eventName: string) { + this.event = eventName; + } + + event: string = ''; + charge: number = 0; + background_time: number = 0; + screen_on_time: number = 0; + screen_off_time: number = 0; + load: string = '-'; + usage: number = 0; + duration: number = 0; + camera_id: number = 0; + foreground_count: number = 0; + background_count: number = 0; + screen_on_count: number = 0; + screen_off_count: number = 0; + count: number = 0; + appName: string = ''; + uid: number = 0; + foreground_duration: number = 0; + foreground_energy: number = 0; + background_duration: number = 0; + background_energy: number = 0; + screen_on_duration: number = 0; + screen_on_energy: number = 0; + screen_off_duration: number = 0; + screen_off_energy: number = 0; + energy: number = 0; + energyConsumptionRatio: string = ''; + + getTotalEnergy(isSimpleEnergy: boolean): number { + if (isSimpleEnergy) { + return this.energy; + } + return this.foreground_energy + this.background_energy + this.screen_on_energy + this.screen_off_energy; + } +} + +export class PowerBatteryEnergy { + gasGauge: number = -1; + charge: number = -1; + screen: number = -1; + level: number = -1; + current: number = -1; + capacity: number = -1; + appName: string = ''; + uid: number = -1; +} + +export class SystemDetailsEnergy { + ts: number = 0; + eventName: string = ''; + type: string = ''; + pid: number = -1; + uid: number = -1; + state: number = -1; + workId: string = ''; + name: string = ''; + interval: number = -1; + level: number = -1; + tag: string = ''; + message: string = ''; + log_level: string = ''; +} diff --git a/ide/src/trace/bean/FpsStruct.ts b/ide/src/trace/bean/FpsStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f3c649df3a08257420591b666eba186a0f11d4e --- /dev/null +++ b/ide/src/trace/bean/FpsStruct.ts @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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 { Rect } from '../component/trace/timer-shaft/Rect.js'; +import { BaseStruct } from './BaseStruct.js'; + +import { ns2x } from '../component/trace/TimerShaftElement.js'; + +export class FpsStruct extends BaseStruct { + static maxFps: number = 0; + static maxFpsName: string = '0 FPS'; + static hoverFpsStruct: FpsStruct | undefined; + static selectFpsStruct: FpsStruct | undefined; + fps: number | undefined; + startNS: number | undefined = 0; + dur: number | undefined; //自补充,数据库没有返回 + + static draw(ctx: CanvasRenderingContext2D, data: FpsStruct) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = '#535da6'; + ctx.strokeStyle = '#535da6'; + if (data.startNS === FpsStruct.hoverFpsStruct?.startNS) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = ((data.fps || 0) * (data.frame.height || 0) * 1.0) / FpsStruct.maxFps; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = ((data.fps || 0) * (data.frame.height || 0) * 1.0) / FpsStruct.maxFps; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } + + static setFrame(node: FpsStruct, padding: number, startNS: number, endNS: number, totalNS: number, frame: Rect) { + let x1: number, x2: number; + if ((node.startNS || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startNS || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + let rectangle: Rect = new Rect( + Math.floor(x1), + Math.ceil(frame.y + padding), + Math.ceil(getV), + Math.floor(frame.height - padding * 2) + ); + node.frame = rectangle; + } +} + +const textPadding = 2; diff --git a/ide/src/trace/bean/FrameChartStruct.ts b/ide/src/trace/bean/FrameChartStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f21b167c2426e967e67acbb33a6a6ae789ec3d3 --- /dev/null +++ b/ide/src/trace/bean/FrameChartStruct.ts @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2022 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 { SpApplication } from '../SpApplication.js'; +import { BaseStruct } from './BaseStruct.js'; +import { Rect } from '../component/trace/timer-shaft/Rect.js'; +import { info, warn } from '../../log/Log.js'; + +const padding: number = 1; +const lightBlue = { + r: 82, + g: 145, + b: 255, + a: 0.9, +}; + +export class ChartStruct extends BaseStruct { + static hoverFuncStruct: ChartStruct | undefined; + static selectFuncStruct: ChartStruct | undefined; + static lastSelectFuncStruct: ChartStruct | undefined; + needShow = false; + isDraw = false; + depth: number = 0; + symbol: string = ''; + lib: string = ''; + size: number = 0; + count: number = 0; + dur: number = 0; + drawSize: number = 0; + drawCount: number = 0; + drawDur: number = 0; + parent: ChartStruct | undefined; + children: Array = []; + percent: number = 0; + addr: string = ''; + isSearch: boolean = false; + textMetricsWidth: number | undefined; +} + +export enum ChartMode { + Byte, // Native Memory + Count, // Perf + Duration, // eBpf +} + +export function setFuncFrame(node: ChartStruct, canvas_frame: Rect, total: number, mode: ChartMode) { + if (!node.frame) { + node.frame = new Rect(0, 0, 0, 0); + } + // filter depth is 0 + if (node.parent) { + let idx = node.parent.children.indexOf(node); + if (idx == 0) { + node.frame!.x = node.parent.frame!.x; + } else { + // set x by left frame. left frame is parent.children[idx - 1] + node.frame.x = node.parent.children[idx - 1].frame!.x + node.parent.children[idx - 1].frame!.width; + } + switch (mode) { + case ChartMode.Byte: + node.frame!.width = Math.floor(((node.drawSize || node.size) / total) * canvas_frame.width); + break; + case ChartMode.Count: + node.frame!.width = Math.floor(((node.drawCount || node.count) / total) * canvas_frame.width); + break; + case ChartMode.Duration: + node.frame!.width = Math.floor(((node.drawDur || node.dur) / total) * canvas_frame.width); + break; + default: + warn('not match ChartMode'); + } + node.frame!.y = node.parent.frame!.y + 20; + node.frame!.height = 20; + } +} + +/** + * draw rect + * @param ctx CanvasRenderingContext2D + * @param data rect which is need draw + * @param percent function size or count / total size or count + */ +export function draw(ctx: CanvasRenderingContext2D, data: ChartStruct) { + let spApplication = document.getElementsByTagName('sp-application')[0]; + if (data.frame) { + // draw rect + let miniHeight = 20; + if (isSelected(data)) { + ctx.fillStyle = `rgba(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b}, ${lightBlue.a})`; + } else { + let color = getHeatColor(data.percent); + ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, 0.9)`; + } + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + //draw border + ctx.lineWidth = 0.4; + if (isHover(data)) { + if (spApplication.dark) { + ctx.strokeStyle = '#fff'; + } else { + ctx.strokeStyle = '#000'; + } + } else { + if (spApplication.dark) { + ctx.strokeStyle = '#000'; + } else { + ctx.strokeStyle = '#fff'; + } + if (data.isSearch) { + ctx.strokeStyle = `rgb(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b})`; + ctx.lineWidth = 1; + } + } + ctx.strokeRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + + //draw symbol name + if (data.frame.width > 10) { + if (data.percent > 0.6 || isSelected(data)) { + ctx.fillStyle = '#fff'; + } else { + ctx.fillStyle = '#000'; + } + drawString(ctx, data.symbol || '', 5, data.frame, data); + } + data.isDraw = true; + } +} + +/** + * get frame chart color by percent + * @param widthPercentage proportion of function + * @returns rbg + */ +function getHeatColor(widthPercentage: number) { + return { + r: Math.floor(245 + 10 * (1 - widthPercentage)), + g: Math.floor(110 + 105 * (1 - widthPercentage)), + b: 100, + }; +} + +/** + * draw function string in rect + * @param ctx CanvasRenderingContext2D + * @param str function Name + * @param textPadding textPadding + * @param frame canvas area + * @returns is draw + */ +function drawString( + ctx: CanvasRenderingContext2D, + str: string, + textPadding: number, + frame: Rect, + struct: ChartStruct +): boolean { + if (!struct.textMetricsWidth) { + struct.textMetricsWidth = ctx.measureText(str).width; + } + + let charWidth = Math.round(struct.textMetricsWidth / str.length); + let fillTextWidth = frame.width - textPadding * 2; + if (struct.textMetricsWidth < frame.width - textPadding * 2) { + let x2 = Math.floor(frame.width / 2 - struct.textMetricsWidth / 2 + frame.x + textPadding); + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), fillTextWidth); + return true; + } else { + if (fillTextWidth >= charWidth) { + let chatNum = fillTextWidth / charWidth; + let x1 = frame.x + textPadding; + if (chatNum < 2) { + ctx.fillText(str.substring(0, 1), x1, Math.floor(frame.y + frame.height / 2 + 2), fillTextWidth); + } else { + ctx.fillText( + str.substring(0, chatNum - 1) + '...', + x1, + Math.floor(frame.y + frame.height / 2 + 2), + fillTextWidth + ); + } + return true; + } + } + return false; +} + +function isHover(data: ChartStruct): boolean { + return ChartStruct.hoverFuncStruct == data; +} + +function isSelected(data: ChartStruct): boolean { + return ChartStruct.lastSelectFuncStruct == data; +} diff --git a/ide/src/trace/bean/FuncStruct.ts b/ide/src/trace/bean/FuncStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..e282a4534357a6fa3add4a88c0ba07831e57f2b9 --- /dev/null +++ b/ide/src/trace/bean/FuncStruct.ts @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; +import { Rect } from '../component/trace/timer-shaft/Rect.js'; +import { ColorUtils } from '../component/trace/base/ColorUtils.js'; + +export class FuncStruct extends BaseStruct { + static hoverFuncStruct: FuncStruct | undefined; + static selectFuncStruct: FuncStruct | undefined; + argsetid: number | undefined; + depth: number | undefined; + dur: number | undefined; + funName: string | undefined; + id: number | undefined; + is_main_thread: number | undefined; + parent_id: number | undefined; + startTs: number | undefined; + threadName: string | undefined; + tid: number | undefined; + identify: number | undefined; + track_id: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: FuncStruct) { + if (data.frame) { + if (data.dur == undefined || data.dur == null || data.dur == 0 || FuncStruct.isBinder(data)) { + } else { + let width = data.frame.width || 0; + ctx.fillStyle = ColorUtils.FUNC_COLOR[data.depth || 0 % ColorUtils.FUNC_COLOR.length]; + let miniHeight = 20; + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + ctx.fillStyle = '#fff'; + FuncStruct.drawString(ctx, data.funName || '', 5, data.frame); + if (FuncStruct.isSelected(data)) { + ctx.strokeStyle = '#000'; + ctx.lineWidth = 1; + ctx.strokeRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + } + } + } + } + + static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect) { + let textMetrics = ctx.measureText(str); + let charWidth = Math.round(textMetrics.width / str.length); + if (textMetrics.width < frame.width - textPadding * 2) { + let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding); + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2); + return; + } + if (frame.width - textPadding * 2 > charWidth * 4) { + let chatNum = (frame.width - textPadding * 2) / charWidth; + let x1 = frame.x + textPadding; + ctx.fillText( + str.substring(0, chatNum - 4) + '...', + x1, + Math.floor(frame.y + frame.height / 2 + 2), + frame.width - textPadding * 2 + ); + return; + } + } + + static isSelected(data: FuncStruct): boolean { + return ( + FuncStruct.selectFuncStruct != undefined && + FuncStruct.selectFuncStruct.startTs == data.startTs && + FuncStruct.selectFuncStruct.dur == data.dur && + FuncStruct.selectFuncStruct.funName == data.funName + ); + } + + static isBinder(data: FuncStruct): boolean { + if ( + data.funName != null && + (data.funName.toLowerCase().startsWith('binder transaction') || + data.funName.toLowerCase().startsWith('binder async') || + data.funName.toLowerCase().startsWith('binder reply')) + ) { + return true; + } else { + return false; + } + } + + static isBinderAsync(data: FuncStruct): boolean { + if (data.funName != null && data.funName.toLowerCase().includes('async')) { + return true; + } else { + return false; + } + } +} + +const padding = 1; diff --git a/ide/src/trace/bean/HeapBean.ts b/ide/src/trace/bean/HeapBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a48b4fd348d65475739189f409379cb59e7b406 --- /dev/null +++ b/ide/src/trace/bean/HeapBean.ts @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 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. + */ + +export class HeapBean { + MoudleName: string | undefined; + AllocationFunction: string | undefined; + Allocations: number | string = 0; + Deallocations: number | string = 0; + AllocationSize: number | string = 0; + DeAllocationSize: number | string = 0; + Total: number | string = 0; + RemainingSize: number | string = 0; + children: HeapBean[] = []; + depth: number = 0; +} diff --git a/ide/src/trace/bean/HeapStruct.ts b/ide/src/trace/bean/HeapStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f5e812dc8e7a0e9a2d92ca536f2ee1769664e51 --- /dev/null +++ b/ide/src/trace/bean/HeapStruct.ts @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; +import { ns2x } from '../component/trace/TimerShaftElement.js'; +import { Rect } from '../component/trace/timer-shaft/Rect.js'; + +export class HeapStruct extends BaseStruct { + static hoverHeapStruct: HeapStruct | undefined; + startTime: number | undefined; + endTime: number | undefined; + dur: number | undefined; + eventType: string | undefined; + heapsize: number | undefined; + density: number | undefined; + maxHeapSize: number = 0; + minHeapSize: number = 0; + + static setFrame(node: HeapStruct, padding: number, startNS: number, endNS: number, totalNS: number, frame: Rect) { + let x1: number, x2: number; + if ((node.startTime || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startTime || 0, startNS, endNS, totalNS, frame); + } + if ((node.startTime || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x( + // @ts-ignore + node.startTime + node.dur, + startNS, + endNS, + totalNS, + frame + ); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + let rectangle: Rect = new Rect( + Math.floor(x1), + Math.ceil(frame.y + padding), + Math.ceil(getV), + Math.floor(frame.height - padding * 2) + ); + node.frame = rectangle; + } + + static draw(ctx: CanvasRenderingContext2D, data: HeapStruct) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = '#2db3aa'; + ctx.strokeStyle = '#2db3aa'; + if (data.startTime === HeapStruct.hoverHeapStruct?.startTime) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = Math.ceil(((data.heapsize || 0) * (data.frame.height || 0)) / data.maxHeapSize); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = Math.ceil(((data.heapsize || 0) * (data.frame.height || 0)) / data.maxHeapSize); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} diff --git a/ide/src/trace/bean/HeapTreeDataBean.ts b/ide/src/trace/bean/HeapTreeDataBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..4d590dace66074c591faafac05f9c3a6947adb22 --- /dev/null +++ b/ide/src/trace/bean/HeapTreeDataBean.ts @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 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. + */ + +export class HeapTreeDataBean { + MoudleName: string | undefined; + AllocationFunction: string | undefined; + symbolId: number = 0; + fileId: number = 0; + startTs: number = 0; + endTs: number = 0; + eventType: string | undefined; + depth: number = 0; + heapSize: number = 0; + eventId: string = ''; +} diff --git a/ide/src/trace/bean/JankFramesStruct.ts b/ide/src/trace/bean/JankFramesStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..f539d0a664131bf53c9219771f5e39e0d942262b --- /dev/null +++ b/ide/src/trace/bean/JankFramesStruct.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ + +export class JankFramesStruct { + jankType: string = ''; + minDuration: number = -1; + minDurationStr: string = ''; + maxDuration: number = -1; + maxDurationStr: string = ''; + meanDuration: number = -1; + meanDurationStr: string = ''; + occurrences: number = 0; + flag: boolean = false; +} diff --git a/ide/src/trace/bean/JanksStruct.ts b/ide/src/trace/bean/JanksStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..e905dfd430b1a8e140261433dcf0300595b2d79d --- /dev/null +++ b/ide/src/trace/bean/JanksStruct.ts @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; + +export class JanksStruct extends BaseStruct { + static hoverJankStruct: JanksStruct | undefined; + static selectJankStruct: JanksStruct | undefined; + static selectJankStructList: Array = new Array(); + static delJankLineFlag: boolean = true; + id: number | undefined; // sliceid + ts: number | undefined; + dur: number | undefined; + name: string | undefined; + depth: number | undefined; + jank_tag: boolean = false; + cmdline: string | undefined; // process + jank_type: string | undefined; + type: string | undefined; + pid: number | undefined; + frame_type: string | undefined; // app、renderService、FrameTime + app_dur: number | undefined; + src_slice: string | undefined; + dst_slice: string | undefined; + rs_ts: number | undefined; + rs_vsync: string | undefined; + rs_dur: number | undefined; + rs_pid: number | undefined; + rs_name: string | undefined; + gpu_dur: number | undefined; +} diff --git a/ide/src/trace/bean/MemoryAbilityMonitorStruct.ts b/ide/src/trace/bean/MemoryAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7fb700fb20d466c997de8cc55a668f37b345719 --- /dev/null +++ b/ide/src/trace/bean/MemoryAbilityMonitorStruct.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../component/trace/base/ColorUtils.js'; +import { BaseStruct } from './BaseStruct.js'; + +export class MemoryAbilityMonitorStruct extends BaseStruct { + static maxMemoryByte: number = 0; + static maxMemoryByteName: string = '0 MB'; + static hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + static selectMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + cpu: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; + + static draw(context2D: any, data: MemoryAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = data.cpu || 0; + index += 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / MemoryAbilityMonitorStruct.maxMemoryByte + ); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0)) / MemoryAbilityMonitorStruct.maxMemoryByte + ); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/ide/src/trace/bean/NativeHook.ts b/ide/src/trace/bean/NativeHook.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac38f7340d1a2a3fe8cb22a0095ccc1f3c559940 --- /dev/null +++ b/ide/src/trace/bean/NativeHook.ts @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2022 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 { Utils } from '../component/trace/base/Utils.js'; +import { ChartStruct } from '../bean/FrameChartStruct.js'; + +export class NativeHookStatistics { + eventId: number = 0; + eventType: string = ''; + subType: string = ''; + subTypeId: number = 0; + heapSize: number = 0; + addr: string = ''; + startTs: number = 0; + endTs: number = 0; + sumHeapSize: number = 0; + max: number = 0; + count: number = 0; + tid: number = 0; + threadName: string = ''; + isSelected: boolean = false; +} + +export class NativeHookMalloc { + eventType: string = ''; + subType: string = ''; + subTypeId: number = 0; + heapSize: number = 0; + allocByte: number = 0; + allocCount: number = 0; + freeByte: number = 0; + freeCount: number = 0; + max: number = 0; +} + +export class NativeEventHeap { + eventType: string = ''; + sumHeapSize: number = 0; +} + +export class NativeHookProcess { + ipid: number = 0; + pid: number = 0; + name: String = ''; +} + +export class NativeHookStatisticsTableData { + memoryTap: string = ''; + existing: number = 0; + existingString: string = ''; + freeByteString: string = ''; + allocCount: number = 0; + freeCount: number = 0; + freeByte: number = 0; + totalBytes: number = 0; + totalBytesString: string = ''; + maxStr: string = ''; + max: number = 0; + totalCount: number = 0; + existingValue: Array = []; +} + +export class NativeMemory { + index: number = 0; + eventId: number = 0; + eventType: string = ''; + subType: string = ''; + addr: string = ''; + startTs: number = 0; + endTs: number = 0; + timestamp: string = ''; + heapSize: number = 0; + heapSizeUnit: string = ''; + symbol: string = ''; + library: string = ''; + isSelected: boolean = false; + state: string = ''; + threadId: number = 0; + threadName: string = ''; +} + +export class NativeHookSamplerInfo { + current: string = ''; + currentSize: number = 0; + startTs: number = 0; + heapSize: number = 0; + snapshot: string = ''; + growth: string = ''; + total: number = 0; + totalGrowth: string = ''; + existing: number = 0; + children: Array = []; + tempList: Array = []; + timestamp: string = ''; + eventId: number = -1; + threadId: number = 0; + threadName: string = ''; + + merageObj(merageObj: NativeHookSamplerInfo) { + this.currentSize += merageObj.currentSize; + this.heapSize += merageObj.heapSize; + this.existing += merageObj.existing; + this.total += merageObj.total; + this.growth = Utils.getByteWithUnit(this.heapSize); + this.current = Utils.getByteWithUnit(this.currentSize); + this.totalGrowth = Utils.getByteWithUnit(this.total); + } +} + +export class NativeHookSampleQueryInfo { + eventId: number = -1; + current: number = 0; + eventType: string = ''; + subType: string = ''; + subTypeId: number = 0; + growth: number = 0; + existing: number = 0; + addr: string = ''; + startTs: number = 0; + endTs: number = 0; + total: number = 0; + threadId: number = 0; + threadName: string = ''; + children: Array = []; +} + +export class NativeHookCallInfo extends ChartStruct { + id: string = ''; + pid: string | undefined; + library: string = ''; + symbolId: number = 0; + title: string = ''; + count: number = 0; + countValue: string = ''; + countPercent: string = ''; + type: number = 0; + heapSize: number = 0; + heapPercent: string = ''; + heapSizeStr: string = ''; + eventId: number = 0; + threadId: number = 0; + threadName: string = ''; + isSelected: boolean = false; +} + +export class NativeEvent { + startTime: number = 0; + heapSize: number = 0; + eventType: string = ''; +} diff --git a/ide/src/trace/bean/NetworkAbilityMonitorStruct.ts b/ide/src/trace/bean/NetworkAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae96c8e13e3f2130774029b44a323cc58c3c9eee --- /dev/null +++ b/ide/src/trace/bean/NetworkAbilityMonitorStruct.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../component/trace/base/ColorUtils.js'; +import { BaseStruct } from './BaseStruct.js'; + +export class NetworkAbilityMonitorStruct extends BaseStruct { + static maxNetworkRate: number = 0; + static maxNetworkRateName: string = '0 KB/S'; + static hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + static selectNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; + + static draw(context2D: any, data: NetworkAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 0; + index += 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / NetworkAbilityMonitorStruct.maxNetworkRate + ); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0)) / NetworkAbilityMonitorStruct.maxNetworkRate + ); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/ide/src/trace/bean/PerfProfile.ts b/ide/src/trace/bean/PerfProfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6949b01211fb6da4c8209c31f96ea91ef270925 --- /dev/null +++ b/ide/src/trace/bean/PerfProfile.ts @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022 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 { Utils } from '../component/trace/base/Utils.js'; +import { ChartStruct } from '../../trace/bean/FrameChartStruct.js'; +import { SpHiPerf } from '../component/chart/SpHiPerf.js'; + +export class PerfFile { + fileId: number = 0; + symbol: string = ''; + path: string = ''; + fileName: string = ''; + + static setFileName(data: PerfFile) { + if (data.path) { + let number = data.path.lastIndexOf('/'); + if (number > 0) { + data.fileName = data.path.substring(number + 1); + return; + } + } + data.fileName = data.path; + } + + setFileName() { + if (this.path) { + let number = this.path.lastIndexOf('/'); + if (number > 0) { + this.fileName = this.path.substring(number + 1); + return; + } + } + this.fileName = this.path; + } +} + +export class PerfThread { + tid: number = 0; + pid: number = 0; + threadName: string = ''; + processName: string = ''; +} + +export class PerfCall { + sampleId: number = 0; + depth: number = 0; + name: string = ''; +} + +export class PerfCallChain { + tid: number = 0; + pid: number = 0; + name: string = ''; + fileName: string = ''; + threadState: string = ''; + startNS: number = 0; + dur: number = 0; + sampleId: number = 0; + callChainId: number = 0; + vaddrInFile: number = 0; + fileId: number = 0; + symbolId: number = 0; + path: string = ''; + parentId: string = ''; //合并之后区分的id + id: string = ''; + topDownMerageId: string = ''; //top down合并使用的id + topDownMerageParentId: string = ''; //top down合并使用的id + bottomUpMerageId: string = ''; //bottom up合并使用的id + bottomUpMerageParentId: string = ''; //bottom up合并使用的id + depth: number = 0; + canCharge: boolean = true; + previousNode: PerfCallChain | undefined = undefined; //将list转换为一个链表结构 + nextNode: PerfCallChain | undefined = undefined; + + static setNextNode(currentNode: PerfCallChain, nextNode: PerfCallChain) { + currentNode.nextNode = nextNode; + nextNode.previousNode = currentNode; + } + + static setPreviousNode(currentNode: PerfCallChain, prevNode: PerfCallChain) { + currentNode.previousNode = prevNode; + prevNode.nextNode = currentNode; + } + + static merageCallChain(currentNode: PerfCallChain, callChain: PerfCallChain) { + currentNode.startNS = callChain.startNS; + currentNode.tid = callChain.tid; + currentNode.pid = callChain.pid; + currentNode.sampleId = callChain.sampleId; + currentNode.dur = callChain.dur; + } +} + +export class PerfCallChainMerageData extends ChartStruct { + #parentNode: PerfCallChainMerageData | undefined = undefined; + #total = 0; + id: string = ''; + parentId: string = ''; + currentTreeParentNode: PerfCallChainMerageData | undefined = undefined; + symbolName: string = ''; + symbol: string = ''; + libName: string = ''; + path: string = ''; + self: string = '0s'; + weight: string = ''; + weightPercent: string = ''; + selfDur: number = 0; + dur: number = 0; + tid: number = 0; + pid: number = 0; + isStore = 0; + canCharge: boolean = true; + children: PerfCallChainMerageData[] = []; + initChildren: PerfCallChainMerageData[] = []; + type: number = 0; + vaddrInFile: number = 0; + isSelected: boolean = false; + searchShow: boolean = true; + + set parentNode(data: PerfCallChainMerageData | undefined) { + this.currentTreeParentNode = data; + this.#parentNode = data; + } + + get parentNode() { + return this.#parentNode; + } + + set total(data: number) { + this.#total = data; + this.weight = `${Utils.timeMsFormat2p(this.dur * (SpHiPerf.stringResult?.fValue || 1))}`; + this.weightPercent = `${((this.dur / data) * 100).toFixed(1)}%`; + } + + get total() { + return this.#total; + } + + static merageCallChain(currentNode: PerfCallChainMerageData, callChain: PerfCallChain, isTopDown: boolean) { + if (currentNode.symbolName == '') { + currentNode.symbol = `${callChain.name} ${callChain.fileName ? `(${callChain.fileName})` : ''}`; + currentNode.symbolName = callChain.name; + currentNode.pid = callChain.pid; + currentNode.tid = callChain.tid; + currentNode.libName = callChain.fileName; + currentNode.vaddrInFile = callChain.vaddrInFile; + currentNode.canCharge = callChain.canCharge; + if (callChain.path) { + currentNode.path = callChain.path; + } + } + if (callChain[isTopDown ? 'nextNode' : 'previousNode'] == undefined) { + currentNode.selfDur++; + currentNode.self = Utils.timeMsFormat2p(currentNode.selfDur); + } + currentNode.dur++; + currentNode.count++; + } +} + +export class PerfSample { + sampleId: number = 0; + time: number = 0; + timeString: string = ''; + core: number = 0; + coreName: string = ''; + state: string = ''; + pid: number = 0; + processName: string = ''; + tid: number = 0; + threadName: string = ''; + depth: number = 0; + addr: string = ''; + fileId: number = 0; + symbolId: number = 0; + backtrace: Array = []; +} + +export class PerfStack { + symbol: string = ''; + symbolId: number = 0; + path: string = ''; + fileId: number = 0; + type: number = 0; + vaddrInFile: number = 0; +} + +export class PerfCmdLine { + report_value: string = ''; +} diff --git a/ide/src/trace/bean/ProcessMemStruct.ts b/ide/src/trace/bean/ProcessMemStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..566e5b753e6bb462435de0679ef587e81b62d294 --- /dev/null +++ b/ide/src/trace/bean/ProcessMemStruct.ts @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; +import { ColorUtils } from '../component/trace/base/ColorUtils.js'; + +export class ProcessMemStruct extends BaseStruct { + static hoverProcessMemStruct: ProcessMemStruct | undefined; + trackId: number | undefined; + processName: string | undefined; + pid: number | undefined; + upid: number | undefined; + trackName: string | undefined; + type: string | undefined; + track_id: string | undefined; + value: number | undefined; + startTime: number | undefined; + duration: number | undefined; + maxValue: number | undefined; + delta: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: ProcessMemStruct) { + if (data.frame) { + let width = data.frame.width || 0; + if (data.startTime === ProcessMemStruct.hoverProcessMemStruct?.startTime) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / (data.maxValue || 0) + ); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.fillStyle = ColorUtils.colorForTid(data.maxValue || 0); + ctx.strokeStyle = ColorUtils.colorForTid(data.maxValue || 0); + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = ((data.value || 0) * (data.frame.height || 0) * 1.0) / (data.maxValue || 1); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} diff --git a/ide/src/trace/bean/ProcessStruct.ts b/ide/src/trace/bean/ProcessStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..32883880083882fe1a5daefcd341e826bbca0b1a --- /dev/null +++ b/ide/src/trace/bean/ProcessStruct.ts @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../component/trace/base/ColorUtils.js'; +import { BaseStruct } from './BaseStruct.js'; +import { CpuStruct } from '../database/ui-worker/ProcedureWorkerCPU.js'; + +const padding = 1; + +export class ProcessStruct extends BaseStruct { + cpu: number | undefined; + dur: number | undefined; + id: number | undefined; + pid: number | undefined; + process: string | undefined; + startTime: number | undefined; + state: string | undefined; + thread: string | undefined; + tid: number | undefined; + ts: number | undefined; + type: string | undefined; + utid: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: ProcessStruct) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = ColorUtils.colorForTid(data.pid || 0); + let miniHeight = Math.round(data.frame.height / CpuStruct.cpuCount); + ctx.fillRect( + data.frame.x, + data.frame.y + (data.cpu || 0) * miniHeight + padding, + data.frame.width, + miniHeight - padding * 2 + ); + } + } +} diff --git a/ide/src/trace/bean/SdkStruct.ts b/ide/src/trace/bean/SdkStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8376fe0404247ad807199b04e5fb3fa0d6c7442 --- /dev/null +++ b/ide/src/trace/bean/SdkStruct.ts @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; + +export class SdkSliceStruct extends BaseStruct { + static maxSdkSlice: number = 0; + static maxSdkSliceName: string = ''; + static hoverSdkSliceStruct: SdkSliceStruct | undefined; + static selectSdkSliceStruct: SdkSliceStruct | undefined; + static sdkName: number = 0; + + value: number | undefined; + start_ts: number | undefined; + end_ts: number | undefined; + slice_message: string | undefined; +} + +export class CounterStruct extends BaseStruct { + static maxCounter: number = 0; + static maxCounterName: string = ''; + static hoverCounterStruct: CounterStruct | undefined; + static selectCounterStruct: CounterStruct | undefined; + + value: number | undefined; + ts: number | undefined; + counter_id: number | undefined; +} diff --git a/ide/src/trace/bean/SdkSummary.ts b/ide/src/trace/bean/SdkSummary.ts new file mode 100644 index 0000000000000000000000000000000000000000..fffcc5118a8b0495a061529b48da285b10eb2d6f --- /dev/null +++ b/ide/src/trace/bean/SdkSummary.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 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. + */ + +export class CounterSummary { + value: number = 0; + ts: number = 0; + counter_id: number = 0; +} + +export class SdkSliceSummary { + start_ts: number = 0; + startTime: number = 0; + end_ts: number = 0; + endTime: number = 0; + value: number = 0; + slice_id: number = 0; + slice_name: string = ''; + slice_message: string = ''; +} diff --git a/ide/src/trace/bean/SearchFuncBean.ts b/ide/src/trace/bean/SearchFuncBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..38c69f8b9913733d54177b17423b621e6dffe8d2 --- /dev/null +++ b/ide/src/trace/bean/SearchFuncBean.ts @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import exp from 'constants'; + +export class SearchFuncBean { + depth: number | undefined; // 0 + dur: number | undefined; // 570000 + funName: string | undefined; //"binder transaction" + id: number | undefined; // 92749 + startTime: number | undefined; // 9729867000 + tid: number | undefined; // + pid: number | undefined; // 2785 + type: string | undefined; +} + +export class SearchThreadProcessBean { + type: string | undefined; + rowId: string | undefined | null; + name: string | undefined; + rowType: string | undefined | null; + rowParentId: string | undefined | null; +} + +export class SearchSdkBean { + type: string | undefined; + rowId: string | undefined | null; + startTime: number | undefined; + dur: number | undefined; + name: string | undefined; + rowType: string | undefined | null; + rowParentId: string | undefined | null; +} diff --git a/ide/src/trace/bean/SmapsShowStruct.ts b/ide/src/trace/bean/SmapsShowStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7882fef3faf1edffc8ec3fc2983d85e560868ca --- /dev/null +++ b/ide/src/trace/bean/SmapsShowStruct.ts @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; + +export class SmapsShowStruct extends BaseStruct { + static hoverStruct: SmapsShowStruct | undefined; + static selectStruct: SmapsShowStruct | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; +} diff --git a/ide/src/trace/bean/SmapsStruct.ts b/ide/src/trace/bean/SmapsStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..44862efd90cd58ff7e465cf02a1a82e10f3d80d6 --- /dev/null +++ b/ide/src/trace/bean/SmapsStruct.ts @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 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. + */ + +export class Smaps { + tsNS: number = -1; + start_addr: string = ''; + end_addr: string = ''; + permission: string = ''; + path: string = ''; + size: number = 0; + rss: number = 0; + pss: number = 0; + reside: number = 0; + dirty: number = 0; + swapper: number = 0; + + address: string = ''; + type: string = ''; + dirtyStr: string = ''; + swapperStr: string = ''; + rssStr: string = ''; + pssStr: string = ''; + sizeStr: string = ''; + resideStr: string = ''; +} + +export class SmapsTreeObj { + constructor(id: string, pid: string, type: string) { + this.id = id; + this.pid = pid; + this.type = type; + } + id: string = ''; + pid: string = ''; + rsspro: number = 0; + rssproStr: string = ''; + type: string = ''; + reg: number = 0; + regStr: string = ''; + path: string = ''; + rss: number = 0; + rssStr: string = ''; + dirty: number = 0; + dirtyStr: string = ''; + swapper: number = 0; + swapperStr: string = ''; + pss: number = 0; + pssStr: string = ''; + size: number = 0; + sizeStr: string = ''; + respro: number = 0; + resproStr: string = ''; + children: Array = []; +} diff --git a/ide/src/trace/bean/StateProcessThread.ts b/ide/src/trace/bean/StateProcessThread.ts new file mode 100644 index 0000000000000000000000000000000000000000..aaad55f10cca0a92555b0ecb708595e86fbd1333 --- /dev/null +++ b/ide/src/trace/bean/StateProcessThread.ts @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 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. + */ + +export class StateProcessThread { + id: string = ''; + pid: string = ''; + title: string | null | undefined = ''; + children: Array = []; + process: string = ''; + processId: number = -1; + thread: string = ''; + threadId: number = -1; + state: string = ''; + wallDuration: number = 0; + avgDuration: string = ''; + count: number = 0; + minDuration: number = 0; + maxDuration: number = 0; + stdDuration: string = ''; +} + +export class SPTChild { + process: string = ''; + processId: number = 0; + processName: string = ''; + thread: string = ''; + threadId: number = 0; + threadName: string = ''; + state: string = ''; + startNs: number = 0; + startTime: string = ''; + absoluteTime: number = 0; + duration: number = 0; + cpu: number | undefined = undefined; + core: string = ''; + priority: number = 0; + prior: string = ''; + note: string = '-'; +} + +export class SPT { + process: string = ''; + processId: number = 0; + thread: string = ''; + threadId: number = 0; + state: string = ''; + dur: number = 0; + start_ts: number = 0; + end_ts: number = 0; + cpu: number = 0; + priority: string = '-'; + note: string = '-'; +} + +export class ThreadState { + itid: number = 0; + state: string = ''; + dur: number = 0; + ts: number = 0; + end_ts: number = 0; + start_ts: number = 0; + cpu: number = 0; +} + +export class ThreadProcess { + id: number = 0; + threadId: number = 0; + thread: string = ''; + processId: number = 0; + process: string = ''; +} + +export class SptSlice { + itid: number = 0; + ts: number = 0; + priority: number = 0; +} diff --git a/ide/src/trace/bean/ThreadStruct.ts b/ide/src/trace/bean/ThreadStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..1bc2c349ce6b45cadf2301975ef952a055dd78a9 --- /dev/null +++ b/ide/src/trace/bean/ThreadStruct.ts @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from './BaseStruct.js'; +import { Rect } from '../component/trace/timer-shaft/Rect.js'; +import { Utils } from '../component/trace/base/Utils.js'; + +const padding = 1; + +export class ThreadStruct extends BaseStruct { + static runningColor: string = '#467b3b'; + static rColor = '#a0b84d'; + static uninterruptibleSleepColor = '#f19d38'; + static sColor = '#FBFBFB'; + static hoverThreadStruct: ThreadStruct | undefined; + static selectThreadStruct: ThreadStruct | undefined; + hasSched: number | undefined; + pid: number | undefined; + processName: string | undefined; + threadName: string | undefined; + tid: number | undefined; + upid: number | undefined; + utid: number | undefined; + cpu: number | undefined; + dur: number | undefined; + end_ts: number | undefined; + id: number | undefined; + is_main_thread: number | undefined; + name: string | undefined; + startTime: number | undefined; + start_ts: number | undefined; + state: string | undefined; + type: string | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: ThreadStruct) { + if (data.frame) { + ctx.globalAlpha = 1; + let stateText = data.state || ''; + if ('S' == data.state) { + ctx.fillStyle = ThreadStruct.sColor; + ctx.globalAlpha = 0.2; // transparency + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.globalAlpha = 1; // transparency + } else if ('R' == data.state) { + ctx.fillStyle = ThreadStruct.rColor; + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.fillStyle = '#fff'; + ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame); + } else if ('D' == data.state) { + ctx.fillStyle = ThreadStruct.uninterruptibleSleepColor; + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.fillStyle = '#fff'; + ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame); + } else if ('Running' == data.state) { + ctx.fillStyle = ThreadStruct.runningColor; + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.fillStyle = '#fff'; + ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame); + } else { + ctx.fillStyle = ThreadStruct.rColor; + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.fillStyle = '#fff'; + ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame); + } + if ( + ThreadStruct.selectThreadStruct && + ThreadStruct.equals(ThreadStruct.selectThreadStruct, data) && + ThreadStruct.selectThreadStruct.state != 'S' + ) { + ctx.strokeStyle = '#232c5d'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y + padding, data.frame.width - 2, data.frame.height - padding * 2); + } + } + } + + static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect) { + let textMetrics = ctx.measureText(str); + let charWidth = Math.round(textMetrics.width / str.length); + if (textMetrics.width < frame.width - textPadding * 2) { + let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding); + ctx.textBaseline = 'middle'; + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2), frame.width - textPadding * 2); + return; + } + if (frame.width - textPadding * 2 > charWidth * 4) { + let chatNum = (frame.width - textPadding * 2) / charWidth; + let x1 = frame.x + textPadding; + ctx.textBaseline = 'middle'; + ctx.fillText( + str.substring(0, chatNum - 4) + '...', + x1, + Math.floor(frame.y + frame.height / 2), + frame.width - textPadding * 2 + ); + return; + } + } + + static getEndState(state: string): string { + let statusMapElement = Utils.getEndState(state); + if (statusMapElement) { + return statusMapElement; + } else { + if ('' == statusMapElement || statusMapElement == null) { + return ''; + } + return 'Unknown State'; + } + } + + static equals(d1: ThreadStruct, d2: ThreadStruct): boolean { + if ( + d1 && + d2 && + d1.cpu == d2.cpu && + d1.tid == d2.tid && + d1.state == d2.state && + d1.startTime == d2.startTime && + d1.dur == d2.dur + ) { + return true; + } else { + return false; + } + } +} diff --git a/ide/src/trace/bean/WakeUpTimeBean.ts b/ide/src/trace/bean/WakeUpTimeBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..37c66843f2ced83210c1e05ce4c2626fe627bf29 --- /dev/null +++ b/ide/src/trace/bean/WakeUpTimeBean.ts @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2022 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. + */ + +export class WakeUpTimeBean { + wakeTs: number | undefined; + startTs: number | undefined; + preRow: number | undefined; +} diff --git a/ide/src/trace/bean/WakeupBean.ts b/ide/src/trace/bean/WakeupBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..6353d51387c15f3d7a522fc234edd85fc66de3b9 --- /dev/null +++ b/ide/src/trace/bean/WakeupBean.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ + +export class WakeupBean { + wakeupTime: number | undefined; + cpu: number | undefined; + process: string | undefined; + pid: number | undefined; + thread: string | undefined; + tid: number | undefined; + schedulingLatency: number | undefined; + schedulingDesc: string | undefined; + ts: number | undefined; +} diff --git a/ide/src/trace/component/DisassemblingWindow.ts b/ide/src/trace/component/DisassemblingWindow.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7a9b36871a63120e358e1631a7104889e4dbd60 --- /dev/null +++ b/ide/src/trace/component/DisassemblingWindow.ts @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; + +@element('tab-native-data-modal') +export class DisassemblingWindow extends BaseElement { + private canvas: HTMLCanvasElement | undefined | null; + private window: HTMLElement | undefined | null; + private loading: HTMLElement | undefined | null; + private ctx: CanvasRenderingContext2D | null | undefined; + private hintLine = 0; + private addrArray = new Array(); + private maxBinSize = 0; + private close: Function | undefined | null; + setCloseListener(callback: Function) { + this.close = callback; + } + + removeCloseListener() { + this.close = null; + } + + private getMap(content: string, hintAttr: string) { + let lines = content.split('\n'); + this.addrArray = new Array(); + let lineMap = new Map(); + let effectLint = 0; + this.maxBinSize = 0; + for (let line of lines) { + let lineContents = line.split(':'); + if (lineContents.length === 2) { + let addrHex = lineContents[0].trim(); + let addr = '0x' + addrHex; + let value = lineContents[1].split('\t'); + try { + let binary = value[0]; + let lineStruct = new Disassembling(); + if (binary === '') { + if (line.includes('Disassembly') || line.includes('file format')) { + continue; + } else { + if (addr.includes(' ')) { + let funcs = addr.split(' '); + lineStruct.addr = funcs[0]; + lineStruct.binary = funcs[1]; + } + } + } else { + lineStruct.addr = addr; + lineStruct.binary = value[0].trim(); + lineStruct.type = value.length > 1 ? value[1] : ''; + lineStruct.code = value.length > 2 ? value[2] : ''; + } + lineMap.set(addrHex, lineStruct); + this.maxBinSize = Math.max(this.ctx!.measureText(lineStruct.addr + lineStruct.binary).width, this.maxBinSize); + this.addrArray.push(addrHex); + if (addrHex === hintAttr) this.hintLine = effectLint; + effectLint++; + } catch (e) { + console.log(e); + } + } + } + return lineMap; + } + + public showContent(content: string, hintAddr: string): void { + this.loading!.style.display = 'none'; + this.window!.style.display = 'block'; + if (content.startsWith('error')) { + this.window!.innerHTML = `${content}`; + return; + } + let lineMap = this.getMap(content, hintAddr); + this.maxBinSize = this.maxBinSize * 1.7; + this.window!.innerHTML = ''; + for (let addr of this.addrArray) { + if (!lineMap.has(addr)) continue; + let struct = lineMap.get(addr); + if (this.addrArray[this.hintLine] == addr) { + this.window!.innerHTML += `
+ ${struct!.addr} : ${struct!.binary} + ${struct!.type} + ${struct!.code}
`; + (this.window!.querySelector('#emphasis') as HTMLElement)!.style.width = this.window!.scrollWidth + 'px'; + (this.window!.querySelector('#emphasis') as HTMLElement)!.style.background = '#0A59F7'; + } else { + this.window!.innerHTML += `
+ ${struct!.addr} : ${struct!.binary} + ${struct!.type} + ${struct!.code}
`; + } + } + this.window!.scrollTo( + 0, + (this.hintLine - 1) * this.shadowRoot!.querySelector('#window>.line')!.clientHeight - + this.window!.clientHeight / 2 + ); + } + + private resetCanvas(styleWidth: number, styleHeight: number, width: number, height: number): void { + this.canvas!.style.width = styleWidth + 'px'; + this.canvas!.style.height = styleHeight + 'px'; + this.canvas!.width = width; + this.canvas!.height = height; + } + + public showLoading(): void { + this.loading!.style.display = 'block'; + this.window!.style.display = 'none'; + this.style.display = 'block'; + this.style.position = 'absolute'; + this.style.left = '0px'; + this.style.border = '1px solid #d8d8d8'; + } + + initElements(): void { + this.canvas = this.shadowRoot?.querySelector('#canvas'); + let close = this.shadowRoot?.querySelector('#close'); + this.window = this.shadowRoot?.querySelector('#window'); + this.loading = this.shadowRoot?.querySelector('#loading'); + this.ctx = this.canvas!.getContext('2d'); + this.resetCanvas(0, 0, 0, 0); + close!.addEventListener('click', () => { + if (this.close) { + this.close(); + } + return true; + }); + } + + initHtml(): string { + return ` + + + `; + } +} + +class Disassembling { + addr = ''; + binary = ''; + type = ''; + code = ''; +} diff --git a/ide/src/trace/component/SpFilter.ts b/ide/src/trace/component/SpFilter.ts new file mode 100644 index 0000000000000000000000000000000000000000..cced4eb597c2d9176c971d4c13c8e501e810d75f --- /dev/null +++ b/ide/src/trace/component/SpFilter.ts @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; + +@element('sp-filter') +export class SpFilter extends BaseElement { + initElements(): void {} + + initHtml(): string { + return ` + +
+ Input Filter + +
+ `; + } +} diff --git a/ide/src/trace/component/SpHelp.ts b/ide/src/trace/component/SpHelp.ts new file mode 100644 index 0000000000000000000000000000000000000000..a54cbf892eeadfcfde34bca0affa1eeac4c02463 --- /dev/null +++ b/ide/src/trace/component/SpHelp.ts @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import { LitMainMenuGroup } from '../../base-ui/menu/LitMainMenuGroup.js'; +import { LitMainMenu, MenuItem } from '../../base-ui/menu/LitMainMenu.js'; +import { LitMainMenuItem } from '../../base-ui/menu/LitMainMenuItem'; +import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('sp-help') +export class SpHelp extends BaseElement { + private appContent: HTMLElement | undefined | null; + + get dark() { + return this.hasAttribute('dark'); + } + + set dark(dark: boolean) { + if (dark) { + this.setAttribute('dark', '' + dark); + } else { + this.removeAttribute('dark'); + } + this.appContent!.innerHTML = + ''; + } + + initElements(): void { + let that = this; + let parentElement = this.parentNode as HTMLElement; + parentElement.style.overflow = 'hidden'; + this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement; + let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu; + let header = mainMenu.shadowRoot?.querySelector('.header') as HTMLDivElement; + let color = mainMenu.shadowRoot?.querySelector('.color') as HTMLDivElement; + let version = mainMenu.shadowRoot?.querySelector('.version') as HTMLDivElement; + header.style.display = 'none'; + version.style.display = 'none'; + color.style.display = 'none'; + mainMenu.menus = [ + { + collapsed: false, + title: 'QuickStart', + describe: '', + children: [ + { + title: '设备端抓取trace说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'record', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'web端抓取trace说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'online_record', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'web端加载trace说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'load', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Native Memory抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'native', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Ability Monitor抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'ability', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'HiPerf的抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'perf', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Sql分析和Metrics说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'sql', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'FileSystem抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'file_system', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: '页内存抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'virtual_memory', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Bio抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'bio', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: '进程smaps抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'smaps', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'HiSystemEvent抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'hisys', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'sdk抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'sdk_record', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Frame timeline抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'frame_record', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Scheduling analysis抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'scheduling_record', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'Js Memory抓取和展示说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'js_memory', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + ], + }, + { + collapsed: false, + title: 'TraceStreamer', + describe: '', + children: [ + { + title: 'TraceStreamer数据库说明', + icon: '', + clickHandler: function (item: MenuItem) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'trace_streamer_explain', + action: 'help_doc', + }); + that.appContent!.innerHTML = + ''; + }, + }, + { + title: '编译Trace_streamer', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'TraceStreamer 解析数据状态表', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'TraceStreamer支持解析事件列表', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'trace_streamer工具说明', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'binder事件上下文如何关联', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + { + title: 'wakeup唤醒说明', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + ], + }, + { + collapsed: false, + title: 'SmartPerf', + describe: '', + children: [ + { + title: 'SmartPerf 编译指导', + icon: '', + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + ''; + }, + }, + ], + }, + ]; + mainMenu.style.width = '300px'; + let body = mainMenu.shadowRoot?.querySelector('.menu-body') as HTMLDivElement; + let groups = body.querySelectorAll('lit-main-menu-group'); + groups.forEach((value) => { + let items = value.querySelectorAll('lit-main-menu-item'); + items.forEach((item) => { + item.style.width = '300px'; + }); + if (value.title == 'TraceStreamer') { + let items = value.querySelectorAll('lit-main-menu-item'); + items.forEach((i) => { + if (i.title != 'TraceStreamer数据库说明') { + i.style.display = 'none'; + } + }); + } + if (value.title == 'SmartPerf') { + value.style.display = 'none'; + } + }); + } + + initHtml(): string { + return ` + +
+
+ +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/SpInfoAndStas.ts b/ide/src/trace/component/SpInfoAndStas.ts new file mode 100644 index 0000000000000000000000000000000000000000..a68a8e12390b60d789bf05f7f2b3ddbf01151cbb --- /dev/null +++ b/ide/src/trace/component/SpInfoAndStas.ts @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import { querySelectTraceStats, queryTraceMetaData } from '../database/SqlLite.js'; +import { LitTable } from '../../base-ui/table/lit-table.js'; +import '../../base-ui/table/lit-table.js'; +import { info } from '../../log/Log.js'; +import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar.js'; + +@element('sp-info-and-stats') +export class SpInfoAndStats extends BaseElement { + private metaData: Array = []; + private infoData: Array = []; + private metaTableEl: LitTable | undefined; + private infoTableEl: LitTable | undefined; + private th: HTMLElement | undefined; + private backgroundMetaTable: HTMLDivElement | undefined; + private backgroundInfoTable: HTMLDivElement | undefined; + private progressLoad: LitProgressBar | undefined; + + static get observedAttributes() { + return []; + } + + initElements(): void { + this.progressLoad = this.shadowRoot?.querySelector('.load-metric') as LitProgressBar; + this.metaTableEl = this.shadowRoot!.querySelector('#metaData-table') as LitTable; + this.infoTableEl = this.shadowRoot!.querySelector('#stats-table') as LitTable; + + this.infoTableEl.style.overflow = 'visible'; + this.metaTableEl.style.overflow = 'visible'; + this.infoTableEl.style.width = 'auto'; + this.metaTableEl.style.width = 'auto'; + this.th = this.shadowRoot!.querySelector('.th') as HTMLElement; + } + + initInfoAndStatsData() { + this.progressLoad!.loading = true; + let time = new Date().getTime(); + this.initMetricItemData().then(() => { + let durTime = new Date().getTime() - time; + info('InfoAndStatsData query time is: ' + durTime + 'ms'); + if (this.metaData.length > 0) { + this.metaTableEl!.recycleDataSource = this.metaData; + } else { + this.metaTableEl!.recycleDataSource = []; + } + new ResizeObserver(() => { + if (this.parentElement?.clientHeight != 0) { + this.metaTableEl!.style.height = '100%'; + this.metaTableEl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + info('metaData(metric) size is: ', this.metaData.length); + if (this.infoData.length > 0) { + this.infoTableEl!.recycleDataSource = this.infoData; + } else { + this.infoTableEl!.recycleDataSource = []; + } + new ResizeObserver(() => { + if (this.parentElement?.clientHeight != 0) { + this.infoTableEl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + info('infoData(metric) size is: ', this.infoData.length); + let metaDataStyle: HTMLDivElement | undefined | null = this.shadowRoot + ?.querySelector('#metaData-table') + ?.shadowRoot?.querySelector('div.body') as HTMLDivElement; + let metaDataHeadStyle: HTMLDivElement | undefined | null = this.shadowRoot + ?.querySelector('#metaData-table') + ?.shadowRoot?.querySelector('div.thead') as HTMLDivElement; + let statsStyle: HTMLDivElement | undefined | null = this.shadowRoot + ?.querySelector('#stats-table') + ?.shadowRoot?.querySelector('div.body') as HTMLDivElement; + let statsHeadStyle: HTMLDivElement | undefined | null = this.shadowRoot + ?.querySelector('#stats-table') + ?.shadowRoot?.querySelector('div.thead') as HTMLDivElement; + + setTimeout(() => { + this.initDataTableStyle(metaDataStyle!); + this.initDataTableStyle(metaDataHeadStyle!); + this.initDataTableStyle(statsStyle!); + this.initDataTableStyle(statsHeadStyle!); + }, 20); + + this.progressLoad!.loading = false; + }); + } + + initDataTableStyle(styleTable: HTMLDivElement): void { + for (let index = 0; index < styleTable.children.length; index++) { + // @ts-ignore + styleTable.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)'; + } + this.metaTableEl!.style.height = 'auto'; + this.metaTableEl!.style.minHeight = '80%'; + this.metaTableEl!.style.borderRadius = '16'; + this.infoTableEl!.style.height = 'auto'; + this.infoTableEl!.style.minHeight = '80%'; + this.infoTableEl!.style.borderRadius = '16'; + } + + async initMetricItemData() { + this.metaData = []; + this.infoData = []; + let mete = await queryTraceMetaData(); + if (mete) { + for (let index = 0; index < mete.length; index++) { + this.metaData.push({ + name: mete[index].name, + value: mete[index].valueText, + }); + } + } + let info = await querySelectTraceStats(); + if (info) { + for (let index = 0; index < info.length; index++) { + this.infoData.push({ + event_name: info[index].event_name, + stat_type: info[index].stat_type, + count: info[index].count, + }); + } + } + } + + connectedCallback() {} + + disconnectedCallback() {} + + attributeChangedCallback(name: string, oldValue: string, newValue: string) {} + + initHtml(): string { + return ` + + +
+ + +
+ `; + } +} + +export class MetaDataTable { + name: string | undefined; + value: string | undefined; + type?: string | undefined; +} + +export class InfoDataTable { + event_name: string | undefined; + stat_type: string | undefined; + count: number | undefined; + source?: string | undefined; + serverity?: string | undefined; +} diff --git a/ide/src/trace/component/SpMetrics.ts b/ide/src/trace/component/SpMetrics.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f24a945ee319271942db3419f179c32c489bd0c --- /dev/null +++ b/ide/src/trace/component/SpMetrics.ts @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; + +import { + queryDistributedTerm, + querySelectTraceStats, + querySystemCalls, + querySystemCallsTop, + queryTraceCpu, + queryTraceCpuTop, + queryTraceMemory, + queryTraceMemoryTop, + queryTraceMemoryUnAgg, + queryTraceMetaData, + queryTraceTaskName, +} from '../database/SqlLite.js'; + +import '../../base-ui/table/lit-table.js'; +import { initCpuStrategyData, initTest } from './metrics/CpuStrategy.js'; +import { initDistributedTermData } from './metrics/DistributeTermStrategy.js'; +import { initMemoryAggStrategy } from './metrics/MemAggStrategy.js'; +import { initMemoryStrategy } from './metrics/MemStrategy.js'; +import { initSysCallsStrategy } from './metrics/SysCallsStrategy.js'; +import { initSysCallsTopStrategy } from './metrics/SysCallsTopStrategy.js'; +import { initTraceStateStrategy } from './metrics/TraceStatsStrategy.js'; +import { initTraceTaskStrategy } from './metrics/TraceTaskStrategy.js'; +import { initMetaDataStrategy } from './metrics/MetaDataStrategy.js'; +import { PluginConvertUtils } from './setting/utils/PluginConvertUtils.js'; +import { info } from '../../log/Log.js'; +import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar.js'; +import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('sp-metrics') +export class SpMetrics extends BaseElement { + private _metric?: string; + private _metricResult?: string; + private selectMetricEl: HTMLSelectElement | undefined; + private runButtonEl: HTMLButtonElement | undefined | null; + private responseJson: HTMLPreElement | undefined | null; + private metricOptionalSelects: Array | undefined; + private progressLoad: LitProgressBar | undefined; + + static get observedAttributes() { + return ['metric', 'metricResult']; + } + + get metric(): string { + return this.getAttribute('metric') || ''; + } + + set metric(value: string) { + this._metric = value; + } + + get metricResult(): string { + return this.getAttribute('metricResult') || ''; + } + + set metricResult(value: string) { + this._metricResult = value; + this.setAttribute('metricResult', value); + } + + reset() { + this.selectMetricEl!.selectedIndex = 0; + this.responseJson!.textContent = ''; + } + + initElements(): void { + this.progressLoad = this.shadowRoot?.querySelector('.load-metric') as LitProgressBar; + this.selectMetricEl = this.shadowRoot?.querySelector('.sql-select') as HTMLSelectElement; + this.runButtonEl = this.shadowRoot?.querySelector('.sql-select-button') as HTMLButtonElement; + this.responseJson = this.shadowRoot?.querySelector('.response-json') as HTMLPreElement; + if (this.selectMetricEl) { + this.selectMetricEl.addEventListener('selectionchange', () => { + if (this.selectMetricEl) this.selectMetricEl.textContent = ''; + }); + } + this.initMetricDataHandle(); + this.initMetricSelectOption(); + } + + async initMetric(queryItem: MetricQueryItem) { + this.initMetricData(queryItem).then((item) => { + this.progressLoad!.loading = false; + }); + } + + async initMetricData(queryItem: MetricQueryItem) { + let metricQuery = queryItem.metricQuery; + let queryList = await metricQuery(); + info('current Metric Data size is: ', queryList!.length); + let metric = queryItem.metricResultHandle; + let resultData = metric(queryList); + let jsonText = PluginConvertUtils.BeanToCmdTxtWithObjName(resultData, true, queryItem.metricName, 4); + this.responseJson!.textContent = jsonText; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'metric': + if (this.selectMetricEl) this.selectMetricEl.textContent = newValue; + break; + case 'metricResult': + if (this.selectMetricEl) this.selectMetricEl.textContent = newValue; + break; + } + } + + runClickListener = (event: any) => { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'metrics', + action: 'metrics', + }); + this.progressLoad!.loading = true; + let selectedIndex = this.selectMetricEl!.selectedIndex; + let value = this.selectMetricEl!.options[selectedIndex].value; + let resultQuery = this.metricOptionalSelects?.filter((item) => { + return item.metricName == value; + }); + if (!resultQuery || resultQuery.length < 1) return; + this.initMetric(resultQuery[0]); + }; + + connectedCallback() { + // Run metric button to add listener + this.runButtonEl?.addEventListener('click', this.runClickListener); + } + + disconnectedCallback() { + this.runButtonEl?.removeEventListener('click', this.runClickListener); + } + + initMetricSelectOption() { + for (let index = 0; index < this.metricOptionalSelects!.length; index++) { + let htmlElement = document.createElement('option'); + if (this.metricOptionalSelects) { + htmlElement.textContent = this.metricOptionalSelects[index].metricName; + this.selectMetricEl?.appendChild(htmlElement); + } + } + } + + initMetricDataHandle() { + this.metricOptionalSelects = [ + { + metricName: 'trace_mem', + metricQuery: queryTraceMemory, + metricResultHandle: initMemoryStrategy, + }, + { + metricName: 'trace_mem_top10', + metricQuery: queryTraceMemoryTop, + metricResultHandle: initMemoryStrategy, + }, + { + metricName: 'trace_mem_unagg', + metricQuery: queryTraceMemoryUnAgg, + metricResultHandle: initMemoryAggStrategy, + }, + { + metricName: 'trace_task_names', + metricQuery: queryTraceTaskName, + metricResultHandle: initTraceTaskStrategy, + }, + { + metricName: 'trace_stats', + metricQuery: querySelectTraceStats, + metricResultHandle: initTraceStateStrategy, + }, + { + metricName: 'trace_metadata', + metricQuery: queryTraceMetaData, + metricResultHandle: initMetaDataStrategy, + }, + { + metricName: 'sys_calls', + metricQuery: querySystemCalls, + metricResultHandle: initSysCallsStrategy, + }, + ]; + } + + initHtml(): string { + return ` + + +
+
+

Select a metric

+ + + +
+
+ +
+
+ `; + } +} + +export interface MetricQueryItem { + metricName: string; + metricQuery: Function; + metricResultHandle: Function; +} + +export class SpMetricsItem { + itemTip: string | undefined; + itemValue: any[] | undefined; +} diff --git a/ide/src/trace/component/SpQuerySQL.ts b/ide/src/trace/component/SpQuerySQL.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ed8ab1b952924780f2e7cbb56f5c9567b84699a --- /dev/null +++ b/ide/src/trace/component/SpQuerySQL.ts @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import { queryCustomizeSelect, querySelectTraceStats } from '../database/SqlLite.js'; +import { LitTable } from '../../base-ui/table/lit-table.js'; +import '../../base-ui/table/lit-table.js'; +import { LitTableColumn } from '../../base-ui/table/lit-table-column.js'; +import { info } from '../../log/Log.js'; +import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar.js'; +import { PageNation } from '../../base-ui/chart/pagenation/PageNation.js'; +import { PaginationBox } from '../../base-ui/chart/pagenation/pagination-box.js'; +import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('sp-query-sql') +export class SpQuerySQL extends BaseElement { + private queryTableEl: LitTable | undefined; + private queryText: string | undefined; + private resultText: string | undefined; + private notSupportList: Array | undefined; + private querySize: HTMLElement | undefined; + private keyList: Array | undefined; + private selector: HTMLTextAreaElement | undefined; + private isSupportSql: boolean = true; + private querySelectTables: string = ''; + private response: HTMLDivElement | undefined; + private statDataArray: any = []; + private sliceData: any = []; + private querySqlErrorText: string = ''; + private progressLoad: LitProgressBar | undefined; + private pagination: PaginationBox | undefined; + private pageSize: number = 200000; + private maxPageSize: number = 500000; + + initElements(): void { + this.progressLoad = this.shadowRoot?.querySelector('.load-metric') as LitProgressBar; + this.selector = this.shadowRoot?.querySelector('.sql-select') as HTMLTextAreaElement; + this.queryTableEl = new LitTable(); + this.querySize = this.shadowRoot?.querySelector('.query_size') as HTMLElement; + this.response = this.shadowRoot?.querySelector('#dataResult') as HTMLDivElement; + this.pagination = this.shadowRoot?.querySelector('.pagination-box') as PaginationBox; + this.notSupportList?.push('insert', 'delete', 'update', 'drop', 'alter', 'truncate', 'create'); + let htmlDivElement = this.queryTableEl.shadowRoot?.querySelector('.table') as HTMLDivElement; + htmlDivElement.style.overflowX = 'scroll'; + + window.addEventListener('resize', () => { + this.freshTableHeadResizeStyle(); + }); + + let copyButtonEl = this.shadowRoot?.querySelector('#copy-button') as HTMLButtonElement; + copyButtonEl.addEventListener('click', () => { + this.copyTableData(); + }); + + let closeButtonEl = this.shadowRoot?.querySelector('#close-button') as HTMLButtonElement; + closeButtonEl.addEventListener('click', () => { + this.querySize!.textContent = 'Query result - 0 counts'; + this.queryTableEl!.dataSource = []; + this.response!.innerHTML = ''; + }); + } + + freshTableHeadResizeStyle() { + let th = this.queryTableEl!.shadowRoot?.querySelector('.th'); + if (th) { + let td = th.querySelectorAll('.td'); + let firstChild = this.queryTableEl!.shadowRoot?.querySelector('.body')!.firstElementChild; + if (firstChild) { + let bodyList = firstChild.querySelectorAll('.td'); + for (let index = 0; index < bodyList.length; index++) { + td[index].style.width = bodyList[index].offsetWidth + 'px'; + td[index].style.overflow = 'hidden'; + } + } + } + } + + async copyTableData() { + let copyResult = ''; + for (let keyListKey of this.keyList!) { + copyResult += keyListKey + '\t'; + } + copyResult += '\n'; + let copyData: any = []; + if (this.statDataArray.length > this.maxPageSize) { + copyData = this.sliceData; + } else { + copyData = this.statDataArray; + } + for (const value of copyData) { + this.keyList?.forEach((key) => { + copyResult += value[key] + '\t'; + }); + copyResult += '\n'; + } + await (navigator as any).clipboard.writeText(copyResult); + } + + selectEventListener = (event: any) => { + let that = this; + if (event.ctrlKey && event.keyCode == 13) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'query', + action: 'query', + }); + if (!this.isSupportSql) { + this.querySize!.textContent = this.querySqlErrorText; + this.queryTableEl!.dataSource = []; + this.response!.innerHTML = ''; + return; + } + this.progressLoad!.loading = true; + let startData = new Date().getTime(); + this.getInputSqlResult(this.selector!.value).then((resultList) => { + let dur = new Date().getTime() - startData; + this.statDataArray = []; + this.keyList = []; + for (let index = 0; index < resultList.length; index++) { + const dataResult = resultList[index]; + let keys = Object.keys(dataResult); + // @ts-ignore + let values = Object.values(dataResult); + let jsonText = '{'; + for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) { + let key = keys[keyIndex]; + if (this.keyList.indexOf(key) <= -1) { + this.keyList.push(key); + } + let value = values[keyIndex]; + if (typeof value == 'string') { + value = value.replace(//gi, '>'); + } + jsonText += '"' + key + '"' + ': ' + '"' + value + '"'; + if (keyIndex != keys.length - 1) { + jsonText += ','; + } else { + jsonText += '}'; + } + } + this.statDataArray.push(JSON.parse(jsonText)); + } + + this.queryTableEl!.innerHTML = ''; + this.queryText = this.selector!.value; + this.initDataElement(); + this.response!.appendChild(this.queryTableEl!); + setTimeout(() => { + let total = this.statDataArray.length; + if (total > this.maxPageSize) { + that.pagination!.style.opacity = '1'; + new PageNation(this.pagination, { + current: 1, + total: total, + pageSize: this.pageSize, + change(num: number) { + that.sliceData = that.statDataArray!.slice((num - 1) * that.pageSize, num * that.pageSize); + that.queryTableEl!.recycleDataSource = that.sliceData; + }, + }); + } else { + that.pagination!.style.opacity = '0'; + this.queryTableEl!.recycleDataSource = this.statDataArray; + } + + this.freshTableHeadResizeStyle(); + new ResizeObserver(() => { + if (this.parentElement?.clientHeight != 0) { + this.queryTableEl!.style.height = '100%'; + this.queryTableEl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + info('metric query Sql result Data size is: ', this.statDataArray!.length); + this.initData(); + this.progressLoad!.loading = false; + }, 200); + }); + } + }; + + reset() { + this.pagination!.style.opacity = '0'; + this.response!.innerHTML = ''; + this.keyList = []; + this.statDataArray = []; + this.selector!.value = ''; + this.querySize!.textContent = 'Query result - ' + ' 0 counts'; + this.resizeSqlHeight().then(() => {}); + } + + initDataTableStyle(styleTable: HTMLDivElement): void { + for (let index = 0; index < styleTable.children.length; index++) { + // @ts-ignore + styleTable.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)'; + } + } + + async initMetricData(): Promise { + if (!this.selector || this.selector.value == null) { + return []; + } + if (this.queryText == '' || this.queryText == null) { + let statList = await querySelectTraceStats(); + for (let index = 0; index < statList.length; index++) { + const statsResult = statList[index]; + let indexArray = { + event_name: statsResult.event_name, + start_type: statsResult.stat_type, + count: statsResult.count, + serverity: statsResult.serverity, + source: statsResult.source, + }; + } + if (this.querySize) { + this.querySize!.textContent = 'Query result - ' + statList.length + ' counts'; + } + this.resultText = 'Query result - ' + statList.length + ' counts'; + } else { + return this.statDataArray; + } + } + + checkSupportSqlAbility(): boolean { + let noSupportChart = ['insert', 'delete', 'update', 'drop', 'alter', 'truncate', 'create']; + let result = noSupportChart.filter((item) => { + return this.selector!.value.indexOf(item) > -1; + }); + if (result.length > 0) { + this.querySqlErrorText = + 'Error: Statement contains a change action keyword,The change operation is not supported.'; + this.isSupportSql = false; + return true; + } else { + return false; + } + } + + checkSafetySelectSql(): boolean { + let split = this.selector?.value.trim().split(' '); + if (split) { + this.querySqlErrorText = 'Error: Incomplete query statement: ' + this.selector!.value; + this.isSupportSql = false; + return !split[0].toLowerCase().startsWith('select'); + } + return false; + } + + getSelectSqlField(): string { + if (this.selector!.value.indexOf('from') < 0) { + return ''; + } + let splitSql = this.selector?.value.split('from'); + if (splitSql) { + if (splitSql[0].indexOf('*') > -1) { + return '*'; + } else { + let fields = splitSql[0].split(','); + return fields[0]; + } + } + return ''; + } + + getSelectSqlTableName(str: string): Array { + if (this.selector!.value.indexOf(str) < 0) { + return []; + } + let tableNameList = []; + let splitSql = this.selector?.value.split(str); + if (splitSql) { + for (let index = 1; index < splitSql?.length; index++) { + let splitSqlItem = splitSql[index].trim(); + let tableItem = splitSqlItem.split(' '); + let tableName = tableItem[0].trim(); + tableNameList.push(tableName); + if (tableName.indexOf('(') >= 0) { + tableNameList.pop(); + } else if (tableName.indexOf(')') >= 0) { + tableNameList.pop(); + let unitTableName = tableName.split(')'); + let tableNewName = unitTableName[0]; + tableNameList.push(tableNewName); + } + } + } + return tableNameList; + } + + initDataElement() { + if (this.keyList) { + info('Metric query Table Colum size is: ', this.keyList.length); + this.keyList.forEach((item) => { + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', item); + htmlElement.setAttribute('data-index', item); + htmlElement.setAttribute('key', item); + htmlElement.setAttribute('align', 'flex-start'); + htmlElement.setAttribute('height', '32px'); + this.queryTableEl!.appendChild(htmlElement); + }); + } + } + + connectedCallback() { + let selectQuery = this.shadowRoot?.querySelector('.query_select'); + if (selectQuery) { + let querySql = selectQuery.textContent; + } + // Listen to the sql execution of the query + this.addEventListener('keydown', this.selectEventListener); + this.selector!.addEventListener('input', this.inputSqlListener); + this.selector!.addEventListener('change', this.inputSqlListener); + this.selector!.addEventListener('keydown', this.deleteSqlListener); + } + + deleteSqlListener = (event: any) => { + if (event.key == 'Backspace') { + this.resizeSqlHeight().then(() => {}); + } + }; + + async resizeSqlHeight() { + let valueLength = this.selector?.value.split('\n').length; + let rowNumber = Number(valueLength) - 1; + let selectHeight = '3.2em'; + if (rowNumber > 0) { + if (rowNumber <= 10) { + let allLength = 1.2 * rowNumber + 2; + selectHeight = allLength + 'em'; + } else { + selectHeight = '14em'; + } + } + // @ts-ignore + this.selector?.style.height = selectHeight; + } + + inputSqlListener = async (event: any) => { + this.resizeSqlHeight().then(() => {}); + let startData = new Date().getTime(); + if (this.selector!.value.trim() == '') { + this.querySqlErrorText = 'Please enter a query'; + this.querySize!.textContent = this.querySqlErrorText; + return; + } + this.checkSafetySelectSql(); + this.checkSupportSqlAbility(); + if (this.selector!.value.length < 15) { + return; + } + this.querySelectTables = this.getSelectSqlTableName('from') + .concat(this.getSelectSqlTableName('join')) + .toLocaleString(); + info('metric query sql table size is: ', this.querySelectTables.length); + this.isSupportSql = true; + }; + + async getInputSqlResult(sql: string): Promise { + return await queryCustomizeSelect(sql); + } + + disconnectedCallback() { + this.removeEventListener('keydown', this.selectEventListener); + this.selector!.removeEventListener('input', this.inputSqlListener); + this.selector!.removeEventListener('change', this.inputSqlListener); + this.selector!.removeEventListener('keydown', this.deleteSqlListener); + } + + initData() { + if (this.statDataArray.length > 0) { + this.querySize!.textContent = 'Error: ' + this.selector?.value; + } + if (this.isSupportSql) { + let sqlField = this.keyList?.length == 0 ? '*' : this.keyList?.toLocaleString(); + this.querySize!.textContent = 'Query result - ' + this.statDataArray.length + ' counts'; + } else { + this.querySize!.textContent = this.querySqlErrorText; + } + + let queryHeadStyle: HTMLDivElement | undefined | null = this.queryTableEl?.shadowRoot?.querySelector( + 'div.th' + ) as HTMLDivElement; + if (queryHeadStyle && queryHeadStyle.hasChildNodes()) { + for (let index = 0; index < queryHeadStyle.children.length; index++) { + // @ts-ignore + queryHeadStyle.children[index].style.gridArea = null; + } + } + + this.queryTableEl!.style.height = '100%'; + } + + static get observedAttributes() { + return ['queryStr']; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + let queryDataSty: HTMLDivElement | undefined | null = this.queryTableEl?.shadowRoot?.querySelector( + 'div.tbody' + ) as HTMLDivElement; + if (queryDataSty && queryDataSty.hasChildNodes()) { + for (let index = 0; index < queryDataSty.children.length; index++) { + // @ts-ignore + queryDataSty.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)'; + } + } + } + + private _queryStr?: string; + + get queryStr(): string { + return this.queryStr; + } + + set queryStr(value: string) { + this._queryStr = value; + } + + initHtml(): string { + return ` + +
+
+

Enter query and press cmd/ctrl + Enter

+ + +
+
+
+

Query result - 0 counts

+
+ + +
+
+
+ +
+
+ `; + } +} diff --git a/ide/src/trace/component/SpRecordTrace.ts b/ide/src/trace/component/SpRecordTrace.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2920b5e0c0b2588cc01ccb7bfdbe0456ecae76b --- /dev/null +++ b/ide/src/trace/component/SpRecordTrace.ts @@ -0,0 +1,1937 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import '../../base-ui/popover/LitPopover.js'; +import '../../base-ui/button/LitButton.js'; +import { LitMainMenuGroup } from '../../base-ui/menu/LitMainMenuGroup.js'; +import { LitMainMenuItem } from '../../base-ui/menu/LitMainMenuItem.js'; +import { SpRecordSetting } from './setting/SpRecordSetting.js'; +import { LitMainMenu, MenuGroup, MenuItem } from '../../base-ui/menu/LitMainMenu.js'; +import { SpProbesConfig } from './setting/SpProbesConfig.js'; +import { SpTraceCommand } from './setting/SpTraceCommand.js'; + +import { + CpuConfig, + CreateSessionRequest, + DiskioConfig, + FileSystemConfig, + FpsConfig, + HilogConfig, + HiperfPluginConfig, + HiSystemEventConfig, + JsHeapConfig, + levelFromJSON, + MemoryConfig, + NativeHookConfig, + NetworkConfig, + ProcessConfig, + ProfilerPluginConfig, + ProfilerSessionConfig, + ProfilerSessionConfigBufferConfig, + ProfilerSessionConfigBufferConfigPolicy, + ProfilerSessionConfigMode, + sysMeminfoTypeFromJSON, + sysVMeminfoTypeFromJSON, + TracePluginConfig, + Type, +} from './setting/bean/ProfilerServiceTypes.js'; +import { PluginConvertUtils } from './setting/utils/PluginConvertUtils.js'; +import { SpAllocations } from './setting/SpAllocations.js'; +import { SpRecordPerf } from './setting/SpRecordPerf.js'; +import { HdcDeviceManager } from '../../hdc/HdcDeviceManager.js'; +import { LitButton } from '../../base-ui/button/LitButton.js'; +import { SpApplication } from '../SpApplication.js'; +import { LitSearch } from './trace/search/Search.js'; +import { LitProgressBar } from '../../base-ui/progress-bar/LitProgressBar.js'; +import { info, log } from '../../log/Log.js'; +import { CmdConstant } from '../../command/CmdConstant.js'; +import { Cmd } from '../../command/Cmd.js'; +import { SpFileSystem } from './setting/SpFileSystem.js'; +import { SpSdkConfig } from './setting/SpSdkConfig.js'; +import { SpVmTracker } from './setting/SpVmTracker.js'; +import { SpHisysEvent } from './setting/SpHisysEvent.js'; +import { SpRecordTemplate } from './setting/SpRecordTemplate.js'; +import { SpJsHeap } from './setting/SpJsHeap.js'; +import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('sp-record-trace') +export class SpRecordTrace extends BaseElement { + public static serialNumber: string = ''; + public static selectVersion: string | null; + // 1GB + public static MaxFileSize: number = 1024 * 1024 * 1024; + public static isVscode = false; + public static stopRecord = false; + static supportVersions = ['3.2', '4.0']; + + set record_template(re: boolean) { + if (re) { + this.setAttribute('record_template', ''); + } else { + this.removeAttribute('record_template'); + } + } + + get record_template() { + return this.hasAttribute('record_template'); + } + + set vs(vs: boolean) { + if (vs) { + SpRecordTrace.isVscode = true; + this.setAttribute('vs', ''); + } else { + SpRecordTrace.isVscode = false; + this.removeAttribute('vs'); + } + } + + get vs(): boolean { + return this.hasAttribute('vs'); + } + + static MEM_INFO = [ + 'MEMINFO_ACTIVE', + 'MEMINFO_ACTIVE_ANON', + 'MEMINFO_ACTIVE_FILE', + 'MEMINFO_ANON_PAGES', + 'MEMINFO_BUFFERS', + 'MEMINFO_CACHED', + 'MEMINFO_CMA_FREE', + 'MEMINFO_CMA_TOTAL', + 'MEMINFO_COMMIT_LIMIT', + 'MEMINFO_COMMITED_AS', + 'MEMINFO_DIRTY', + 'MEMINFO_INACTIVE', + 'MEMINFO_INACTIVE_ANON', + 'MEMINFO_INACTIVE_FILE', + 'MEMINFO_KERNEL_STACK', + 'MEMINFO_MAPPED', + 'MEMINFO_MEM_AVAILABLE', + 'MEMINFO_MEM_FREE', + 'MEMINFO_MEM_TOTAL', + 'MEMINFO_MLOCKED', + 'MEMINFO_PAGE_TABLES', + 'MEMINFO_SHMEM', + 'MEMINFO_SLAB', + 'MEMINFO_SLAB_RECLAIMABLE', + 'MEMINFO_SLAB_UNRECLAIMABLE', + 'MEMINFO_SWAP_CACHED', + 'MEMINFO_SWAP_FREE', + 'MEMINFO_SWAP_TOTAL', + 'MEMINFO_UNEVICTABLE', + 'MEMINFO_VMALLOC_CHUNK', + 'MEMINFO_VMALLOC_TOTAL', + 'MEMINFO_VMALLOC_USED', + 'MEMINFO_WRITEBACK', + 'MEMINFO_KERNEL_RECLAIMABLE', + ]; + static VMEM_INFO = [ + 'VMEMINFO_UNSPECIFIED', + 'VMEMINFO_NR_FREE_PAGES', + 'VMEMINFO_NR_ALLOC_BATCH', + 'VMEMINFO_NR_INACTIVE_ANON', + 'VMEMINFO_NR_ACTIVE_ANON', + 'VMEMINFO_NR_INACTIVE_FILE', + 'VMEMINFO_NR_ACTIVE_FILE', + 'VMEMINFO_NR_UNEVICTABLE', + 'VMEMINFO_NR_MLOCK', + 'VMEMINFO_NR_ANON_PAGES', + 'VMEMINFO_NR_MAPPED', + 'VMEMINFO_NR_FILE_PAGES', + 'VMEMINFO_NR_DIRTY', + 'VMEMINFO_NR_WRITEBACK', + 'VMEMINFO_NR_SLAB_RECLAIMABLE', + 'VMEMINFO_NR_SLAB_UNRECLAIMABLE', + 'VMEMINFO_NR_PAGE_TABLE_PAGES', + 'VMEMINFO_NR_KERNEL_STACK', + 'VMEMINFO_NR_OVERHEAD', + 'VMEMINFO_NR_UNSTABLE', + 'VMEMINFO_NR_BOUNCE', + 'VMEMINFO_NR_VMSCAN_WRITE', + 'VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM', + 'VMEMINFO_NR_WRITEBACK_TEMP', + 'VMEMINFO_NR_ISOLATED_ANON', + 'VMEMINFO_NR_ISOLATED_FILE', + 'VMEMINFO_NR_SHMEM', + 'VMEMINFO_NR_DIRTIED', + 'VMEMINFO_NR_WRITTEN', + 'VMEMINFO_NR_PAGES_SCANNED', + 'VMEMINFO_WORKINGSET_REFAULT', + 'VMEMINFO_WORKINGSET_ACTIVATE', + 'VMEMINFO_WORKINGSET_NODERECLAIM', + 'VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES', + 'VMEMINFO_NR_FREE_CMA', + 'VMEMINFO_NR_SWAPCACHE', + 'VMEMINFO_NR_DIRTY_THRESHOLD', + 'VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD', + 'VMEMINFO_PGPGIN', + 'VMEMINFO_PGPGOUT', + 'VMEMINFO_PGPGOUTCLEAN', + 'VMEMINFO_PSWPIN', + 'VMEMINFO_PSWPOUT', + 'VMEMINFO_PGALLOC_DMA', + ]; + static VMEM_INFO_SECOND = [ + 'VMEMINFO_PGALLOC_NORMAL', + 'VMEMINFO_PGALLOC_MOVABLE', + 'VMEMINFO_PGFREE', + 'VMEMINFO_PGACTIVATE', + 'VMEMINFO_PGDEACTIVATE', + 'VMEMINFO_PGFAULT', + 'VMEMINFO_PGMAJFAULT', + 'VMEMINFO_PGREFILL_DMA', + 'VMEMINFO_PGREFILL_NORMAL', + 'VMEMINFO_PGREFILL_MOVABLE', + 'VMEMINFO_PGSTEAL_KSWAPD_DMA', + 'VMEMINFO_PGSTEAL_KSWAPD_NORMAL', + 'VMEMINFO_PGSTEAL_KSWAPD_MOVABLE', + 'VMEMINFO_PGSTEAL_DIRECT_DMA', + 'VMEMINFO_PGSTEAL_DIRECT_NORMAL', + 'VMEMINFO_PGSTEAL_DIRECT_MOVABLE', + 'VMEMINFO_PGSCAN_KSWAPD_DMA', + 'VMEMINFO_PGSCAN_KSWAPD_NORMAL', + 'VMEMINFO_PGSCAN_KSWAPD_MOVABLE', + 'VMEMINFO_PGSCAN_DIRECT_DMA', + 'VMEMINFO_PGSCAN_DIRECT_NORMAL', + 'VMEMINFO_PGSCAN_DIRECT_MOVABLE', + 'VMEMINFO_PGSCAN_DIRECT_THROTTLE', + 'VMEMINFO_PGINODESTEAL', + 'VMEMINFO_SLABS_SCANNED', + 'VMEMINFO_KSWAPD_INODESTEAL', + 'VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY', + 'VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY', + 'VMEMINFO_PAGEOUTRUN', + 'VMEMINFO_ALLOCSTALL', + 'VMEMINFO_PGROTATED', + 'VMEMINFO_DROP_PAGECACHE', + 'VMEMINFO_DROP_SLAB', + 'VMEMINFO_PGMIGRATE_SUCCESS', + 'VMEMINFO_PGMIGRATE_FAIL', + 'VMEMINFO_COMPACT_MIGRATE_SCANNED', + 'VMEMINFO_COMPACT_FREE_SCANNED', + 'VMEMINFO_COMPACT_ISOLATED', + 'VMEMINFO_COMPACT_STALL', + 'VMEMINFO_COMPACT_FAIL', + 'VMEMINFO_COMPACT_SUCCESS', + 'VMEMINFO_COMPACT_DAEMON_WAKE', + 'VMEMINFO_UNEVICTABLE_PGS_CULLED', + 'VMEMINFO_UNEVICTABLE_PGS_SCANNED', + 'VMEMINFO_UNEVICTABLE_PGS_RESCUED', + 'VMEMINFO_UNEVICTABLE_PGS_MLOCKED', + 'VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED', + ]; + static VMEM_INFO_THIRD = [ + 'VMEMINFO_UNEVICTABLE_PGS_CLEARED', + 'VMEMINFO_UNEVICTABLE_PGS_STRANDED', + 'VMEMINFO_NR_ZSPAGES', + 'VMEMINFO_NR_ION_HEAP', + 'VMEMINFO_NR_GPU_HEAP', + 'VMEMINFO_ALLOCSTALL_DMA', + 'VMEMINFO_ALLOCSTALL_MOVABLE', + 'VMEMINFO_ALLOCSTALL_NORMAL', + 'VMEMINFO_COMPACT_DAEMON_FREE_SCANNED', + 'VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED', + 'VMEMINFO_NR_FASTRPC', + 'VMEMINFO_NR_INDIRECTLY_RECLAIMABLE', + 'VMEMINFO_NR_ION_HEAP_POOL', + 'VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE', + 'VMEMINFO_NR_SHADOW_CALL_STACK_BYTES', + 'VMEMINFO_NR_SHMEM_HUGEPAGES', + 'VMEMINFO_NR_SHMEM_PMDMAPPED', + 'VMEMINFO_NR_UNRECLAIMABLE_PAGES', + 'VMEMINFO_NR_ZONE_ACTIVE_ANON', + 'VMEMINFO_NR_ZONE_ACTIVE_FILE', + 'VMEMINFO_NR_ZONE_INACTIVE_ANON', + 'VMEMINFO_NR_ZONE_INACTIVE_FILE', + 'VMEMINFO_NR_ZONE_UNEVICTABLE', + 'VMEMINFO_NR_ZONE_WRITE_PENDING', + 'VMEMINFO_OOM_KILL', + 'VMEMINFO_PGLAZYFREE', + 'VMEMINFO_PGLAZYFREED', + 'VMEMINFO_PGREFILL', + 'VMEMINFO_PGSCAN_DIRECT', + 'VMEMINFO_PGSCAN_KSWAPD', + 'VMEMINFO_PGSKIP_DMA', + 'VMEMINFO_PGSKIP_MOVABLE', + 'VMEMINFO_PGSKIP_NORMAL', + 'VMEMINFO_PGSTEAL_DIRECT', + 'VMEMINFO_PGSTEAL_KSWAPD', + 'VMEMINFO_SWAP_RA', + 'VMEMINFO_SWAP_RA_HIT', + 'VMEMINFO_WORKINGSET_RESTORE', + ]; + // sys.mem.total sys.mem.free sys.mem.buffers sys.mem.cached sys.mem.shmem sys.mem.slab sys.mem.swap.total + // sys.mem.swap.free sys.mem.mapped sys.mem.vmalloc.used sys.mem.page.tables sys.mem.kernel.stack + // sys.mem.active sys.mem.inactive sys.mem.unevictable sys.mem.vmalloc.total sys.mem.slab.unreclaimable + // sys.mem.cma.total sys.mem.cma.free + static ABALITY_MEM_INFO = [ + 'MEMINFO_MEM_TOTAL', + 'MEMINFO_MEM_FREE', + 'MEMINFO_BUFFERS', + 'MEMINFO_CACHED', + 'MEMINFO_SHMEM', + 'MEMINFO_SLAB', + 'MEMINFO_SWAP_TOTAL', + 'MEMINFO_SWAP_FREE', + 'MEMINFO_MAPPED', + 'MEMINFO_VMALLOC_USED', + 'MEMINFO_PAGE_TABLES', + 'MEMINFO_KERNEL_STACK', + 'MEMINFO_ACTIVE', + 'MEMINFO_INACTIVE', + 'MEMINFO_UNEVICTABLE', + 'MEMINFO_VMALLOC_TOTAL', + 'MEMINFO_SLAB_UNRECLAIMABLE', + 'MEMINFO_CMA_TOTAL', + 'MEMINFO_CMA_FREE', + 'MEMINFO_KERNEL_RECLAIMABLE', + ]; + + schedulingEvents = [ + 'sched/sched_switch', + 'power/suspend_resume', + 'sched/sched_wakeup', + 'sched/sched_wakeup_new', + 'sched/sched_waking', + 'sched/sched_process_exit', + 'sched/sched_process_free', + 'task/task_newtask', + 'task/task_rename', + ]; + powerEvents = [ + 'regulator/regulator_set_voltage', + 'regulator/regulator_set_voltage_complete', + 'power/clock_enable', + 'power/clock_disable', + 'power/clock_set_rate', + 'power/suspend_resume', + ]; + cpuFreqEvents = ['power/cpu_frequency', 'power/cpu_idle', 'power/suspend_resume']; + sysCallsEvents = ['raw_syscalls/sys_enter', 'raw_syscalls/sys_exit']; + highFrequencyEvents = [ + 'mm_event/mm_event_record', + 'kmem/rss_stat', + 'ion/ion_stat', + 'dmabuf_heap/dma_heap_stat', + 'kmem/ion_heap_grow', + 'kmem/ion_heap_shrink', + ]; + advancedConfigEvents = [ + 'sched/sched_switch', + 'sched/sched_wakeup', + 'sched/sched_wakeup_new', + 'sched/sched_waking', + 'sched/sched_process_exit', + 'sched/sched_process_free', + 'irq/irq_handler_entry', + 'irq/irq_handler_exit', + 'irq/softirq_entry', + 'irq/softirq_exit', + 'irq/softirq_raise', + 'power/clock_disable', + 'power/clock_enable', + 'power/clock_set_rate', + 'power/cpu_frequency', + 'power/cpu_idle', + 'clk/clk_disable', + 'clk/clk_disable_complete', + 'clk/clk_enable', + 'clk/clk_enable_complete', + 'clk/clk_set_rate', + 'clk/clk_set_rate_complete', + 'binder/binder_transaction', + 'binder/binder_transaction_alloc_buf', + 'binder/binder_transaction_received', + 'binder/binder_lock', + 'binder/binder_locked', + 'binder/binder_unlock', + 'workqueue/workqueue_execute_start', + 'workqueue/workqueue_execute_end', + 'oom/oom_score_adj_update', + 'ftrace/print', + ]; + private _menuItems: Array | undefined; + + public deviceSelect: HTMLSelectElement | undefined; + public deviceVersion: HTMLSelectElement | undefined; + private stopButtonEl: HTMLButtonElement | null | undefined; + + private recordButton: LitButton | undefined; + private sp: SpApplication | undefined; + private progressEL: LitProgressBar | undefined; + private litSearch: LitSearch | undefined; + private addButton: LitButton | undefined | null; + private disconnectButton: LitButton | undefined | null; + + private recordSetting: SpRecordSetting | undefined; + private probesConfig: SpProbesConfig | undefined; + private traceCommand: SpTraceCommand | undefined; + private spAllocations: SpAllocations | undefined; + private spRecordPerf: SpRecordPerf | undefined; + private spFileSystem: SpFileSystem | undefined; + private spSdkConfig: SpSdkConfig | undefined; + private spVmTracker: SpVmTracker | undefined; + private spHisysEvent: SpHisysEvent | undefined; + private spRecordTemplate: SpRecordTemplate | undefined; + private spJsHeap: SpJsHeap | undefined; + + private menuGroup: LitMainMenuGroup | undefined | null; + private appContent: HTMLElement | undefined | null; + + compareArray(devs: Array): boolean { + let clearFlag: boolean = false; + if (devs.length != this.deviceSelect!.options.length) { + clearFlag = true; + } else { + let optionArray = new Array(); + for (let i = 0; i < this.deviceSelect!.options.length; i++) { + optionArray.push(this.deviceSelect!.options[i].value); + } + devs.forEach((value) => { + if (optionArray.indexOf(value) == -1) { + clearFlag = true; + } + }); + } + return clearFlag; + } + + refreshDeviceList() { + if (this.vs) { + Cmd.execHdcCmd(CmdConstant.CMD_HDC_DEVICES, (res: string) => { + let devs: string[] = res.trim().replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + if (devs.length == 1 && devs[0].indexOf('Empty') != -1) { + this.deviceSelect!.innerHTML = ''; + return; + } + let clearFlag = this.compareArray(devs); + if (clearFlag) { + this.deviceSelect!.innerHTML = ''; + if (devs.length == 0) { + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + } + for (let i = 0; i < devs.length; i++) { + let dev = devs[i]; + let option = document.createElement('option'); + option.className = 'select'; + option.textContent = dev; + this.deviceSelect!.appendChild(option); + if (i == 0) { + option.selected = true; + this.recordButton!.hidden = false; + this.disconnectButton!.hidden = false; + SpRecordTrace.serialNumber = option.value; + } + } + } + }); + } else { + this.deviceSelect!.innerHTML = ''; + // @ts-ignore + HdcDeviceManager.getDevices().then((devs: USBDevice[]) => { + if (devs.length == 0) { + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + } + for (let len = 0; len < devs.length; len++) { + let dev = devs[len]; + let option = document.createElement('option'); + option.className = 'select'; + if (typeof dev.serialNumber === 'string') { + option.value = dev.serialNumber; + } + option.textContent = dev!.serialNumber ? dev!.serialNumber!.toString() : 'hdc Device'; + this.deviceSelect!.appendChild(option); + if (len == 0) { + option.selected = true; + this.recordButton!.hidden = false; + this.disconnectButton!.hidden = false; + SpRecordTrace.serialNumber = option.value; + HdcDeviceManager.connect(option.value).then((result) => { + if (result) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_VERSION, false).then((version) => { + let deviceVersionItem = SpRecordTrace.supportVersions.filter((item) => version.indexOf(item) != -1); + if (deviceVersionItem.length > 0) { + SpRecordTrace.selectVersion = deviceVersionItem[0]; + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + } else { + SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + } + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + }); + } else { + SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + } + }); + } + } + }); + } + } + + freshMenuDisable(disable: boolean) { + let mainMenu = this.sp!.shadowRoot?.querySelector('#main-menu') as LitMainMenu; + mainMenu.menus?.forEach((men) => { + men.children.forEach((child) => { + // @ts-ignore + child.disabled = disable; + }); + }); + mainMenu.menus = mainMenu.menus; + } + + set showHint(bool: boolean) { + if (bool) { + if (this.hasAttribute('show_hint')) { + this.removeAttribute('show_hint'); + setTimeout(() => { + this.setAttribute('show_hint', ''); + }, 200); + } else { + this.setAttribute('show_hint', ''); + } + } else { + this.removeAttribute('show_hint'); + } + } + + private refreshDeviceTimer: any; + + initElements(): void { + let parentElement = this.parentNode as HTMLElement; + parentElement.style.overflow = 'hidden'; + this.recordSetting = new SpRecordSetting(); + this.probesConfig = new SpProbesConfig(); + this.traceCommand = new SpTraceCommand(); + this.spAllocations = new SpAllocations(); + this.spRecordPerf = new SpRecordPerf(); + this.spFileSystem = new SpFileSystem(); + this.spSdkConfig = new SpSdkConfig(); + this.spVmTracker = new SpVmTracker(); + this.spHisysEvent = new SpHisysEvent(); + this.spJsHeap = new SpJsHeap(); + this.spRecordTemplate = new SpRecordTemplate(this); + this.addButton = this.shadowRoot?.querySelector('.add'); + this.addButton!.addEventListener('click', () => { + if (this.vs) { + this.refreshDeviceList(); + } else { + // @ts-ignore + HdcDeviceManager.findDevice().then((usbDevices) => { + log(usbDevices); + this.refreshDeviceList(); + }); + } + }); + this.deviceSelect = this.shadowRoot?.querySelector('#device-select') as HTMLSelectElement; + this.deviceVersion = this.shadowRoot?.querySelector('#device-version') as HTMLSelectElement; + this.deviceSelect!.onchange = () => { + if (this.deviceSelect!.options.length > 0) { + this.recordButton!.hidden = false; + this.disconnectButton!.hidden = false; + } else { + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + } + let deviceItem = this.deviceSelect!.options[this.deviceSelect!.selectedIndex]; + let value = deviceItem.value; + SpRecordTrace.serialNumber = value; + if (this.vs) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_VERSION_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (deviceVersion: string) => { + let deviceVersionItem = SpRecordTrace.supportVersions.filter((item) => deviceVersion.indexOf(item) != -1); + if (deviceVersionItem.length > 0) { + SpRecordTrace.selectVersion = deviceVersionItem[0]; + } else { + SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; + } + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + }); + } else { + HdcDeviceManager.connect(value).then((result) => { + if (result) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_VERSION, true).then((deviceVersion) => { + let deviceVersionItem = SpRecordTrace.supportVersions.filter((item) => deviceVersion.indexOf(item) != -1); + if (deviceVersionItem.length > 0) { + SpRecordTrace.selectVersion = deviceVersionItem[0]; + } else { + SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; + } + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + }); + } else { + SpRecordTrace.selectVersion = SpRecordTrace.supportVersions[0]; + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + } + }); + } + }; + this.deviceVersion.onchange = () => { + let versionItem = this.deviceVersion!.options[this.deviceVersion!.selectedIndex]; + SpRecordTrace.selectVersion = versionItem.getAttribute('device-version'); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(this.makeRequest(), false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + }; + this.appendDeviceVersion(); + // @ts-ignore + if (navigator.usb) { + // @ts-ignore + navigator.usb.addEventListener( + 'connect', + // @ts-ignore + (ev: USBConnectionEvent) => { + this.usbConnectionListener(ev); + } + ); + // @ts-ignore + navigator.usb.addEventListener( + 'disconnect', + // @ts-ignore + (ev: USBConnectionEvent) => { + this.usbDisConnectionListener(ev); + } + ); + } + this.disconnectButton = this.shadowRoot?.querySelector('.disconnect'); + this.disconnectButton?.addEventListener('click', (evt) => { + let index = this.deviceSelect!.selectedIndex; + if (index != -1) { + let selectOption = this.deviceSelect!.options[index]; + let value = selectOption.value; + HdcDeviceManager.disConnect(value).then((re) => { + this.deviceSelect!.removeChild(selectOption); + if (this.deviceSelect!.selectedIndex != -1) { + let item = this.deviceSelect!.options[this.deviceSelect!.selectedIndex]; + SpRecordTrace.serialNumber = item.value; + } else { + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + this.sp!.search = false; + SpRecordTrace.serialNumber = ''; + } + }); + } + }); + + this.recordButton = this.shadowRoot?.querySelector('.record') as LitButton; + this.sp = document.querySelector('sp-application') as SpApplication; + this.progressEL = this.sp.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.litSearch = this.sp.shadowRoot?.querySelector('#lit-search') as LitSearch; + if (this.deviceSelect!.options && this.deviceSelect!.options.length > 0) { + this.disconnectButton!.hidden = false; + this.recordButton!.hidden = false; + } else { + this.disconnectButton!.hidden = true; + this.recordButton!.hidden = true; + } + this.recordButton!.addEventListener('click', () => { + this.recordButtonListener(); + }); + this.spRecordPerf!.addEventListener('addProbe', (event: any) => { + this.showHint = false; + }); + this.spAllocations!.addEventListener('addProbe', (event: any) => { + this.showHint = false; + }); + this.probesConfig!.addEventListener('addProbe', (event: any) => { + this.showHint = false; + }); + this.spRecordTemplate!.addEventListener('addProbe', (event: any) => { + this.showHint = false; + }); + this.stopButtonEl = this.traceCommand!.shadowRoot?.querySelector('#stop-button'); + this.stopButtonEl!.addEventListener('click', (ev) => { + this.stopRecordListener(); + }); + this.menuGroup = this.shadowRoot?.querySelector('#menu-group') as LitMainMenuGroup; + this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement; + if (this.record_template) { + this.appContent.append(this.spRecordTemplate); + } else { + this.appContent.append(this.recordSetting); + } + this.initMenuItems(); + } + + private appendDeviceVersion() { + SpRecordTrace.supportVersions.forEach((supportVersion) => { + let option = document.createElement('option'); + option.className = 'select'; + option.textContent = `OpenHarmony-${supportVersion}`; + option.setAttribute('device-version', supportVersion); + this.deviceVersion!.append(option); + }); + } + + private setDeviceVersionSelect(selected: string) { + let children = this.deviceVersion!.children; + for (let i = 0; i < children.length; i++) { + let child = children[i] as HTMLOptionElement; + if (child.getAttribute('device-version') === selected) { + child.selected = true; + break; + } + } + } + + stopRecordListener() { + if (this.vs) { + let cmd = Cmd.formatString(CmdConstant.CMS_HDC_STOP, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + this.freshMenuDisable(false); + this.freshConfigMenuDisable(false); + this.progressEL!.loading = false; + this.sp!.search = false; + this.litSearch!.clear(); + this.disconnectButton!.style.pointerEvents = 'auto'; + this.recordButton!.style.pointerEvents = 'auto'; + this.addButton!.style.pointerEvents = 'auto'; + this.deviceSelect!.style.pointerEvents = 'auto'; + this.traceCommand!.show = false; + }); + } else { + let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement; + HdcDeviceManager.connect(selectedOption.value).then((result) => { + if (result) { + this.freshMenuDisable(false); + this.freshConfigMenuDisable(false); + try { + this.progressEL!.loading = false; + this.sp!.search = false; + this.litSearch!.clear(); + this.disconnectButton!.style.pointerEvents = 'auto'; + this.recordButton!.style.pointerEvents = 'auto'; + this.addButton!.style.pointerEvents = 'auto'; + this.deviceSelect!.style.pointerEvents = 'auto'; + SpRecordTrace.stopRecord = true; + HdcDeviceManager.stopHiprofiler(CmdConstant.CMS_STOP, true).then((result) => {}); + } catch (exception) { + log(exception); + } + this.traceCommand!.show = false; + } + }); + } + } + + private initMenuItems() { + let that = this; + if (this.record_template) { + this._menuItems = [ + { + title: 'Record setting', + icon: 'properties', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.recordSetting!); + that.freshMenuItemsStatus('Record setting'); + }, + }, + { + title: 'Trace template', + icon: 'realIntentionBulb', + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spRecordTemplate!); + that.freshMenuItemsStatus('Trace template'); + }, + }, + { + title: 'Trace command', + icon: 'dbsetbreakpoint', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + let request = that.makeRequest(); + that.appContent!.innerHTML = ''; + that.appContent!.append(that.traceCommand!); + that.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(request, false), + that.recordSetting!.output, + that.recordSetting!.maxDur + ); + that.freshMenuItemsStatus('Trace command'); + }, + }, + ]; + } else { + this._menuItems = [ + { + title: 'Record setting', + icon: 'properties', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.recordSetting!); + that.freshMenuItemsStatus('Record setting'); + }, + }, + { + title: 'Trace command', + icon: 'dbsetbreakpoint', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.freshMenuItemsStatus('Trace command'); + let request = that.makeRequest(); + that.appContent!.innerHTML = ''; + that.appContent!.append(that.traceCommand!); + that.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(request, false), + that.recordSetting!.output, + that.recordSetting!.maxDur + ); + }, + }, + { + title: 'Probes config', + icon: 'realIntentionBulb', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.probesConfig!); + that.freshMenuItemsStatus('Probes config'); + }, + }, + { + title: 'Native Memory', + icon: 'externaltools', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spAllocations!); + that.freshMenuItemsStatus('Native Memory'); + }, + }, + { + title: 'Hiperf', + icon: 'realIntentionBulb', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spRecordPerf!); + that.freshMenuItemsStatus('Hiperf'); + }, + }, + { + title: 'eBPF Config', + icon: 'file-config', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spFileSystem!); + that.freshMenuItemsStatus('eBPF Config'); + }, + }, + { + title: 'VM Tracker', + icon: 'vm-tracker', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spVmTracker!); + that.freshMenuItemsStatus('VM Tracker'); + }, + }, + { + title: 'HiSystemEvent', + icon: 'externaltools', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spHisysEvent!); + that.freshMenuItemsStatus('HiSystemEvent'); + }, + }, + { + title: 'JS Heap', + icon: 'file-config', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spJsHeap!); + that.freshMenuItemsStatus('JS Heap'); + }, + }, + { + title: 'SDK Config', + icon: 'file-config', + fileChoose: false, + clickHandler: function (ev: InputEvent) { + that.appContent!.innerHTML = ''; + that.appContent!.append(that.spSdkConfig!); + that.freshMenuItemsStatus('SDK Config'); + }, + }, + ]; + } + + this._menuItems?.forEach((item) => { + let th = new LitMainMenuItem(); + th.setAttribute('icon', item.icon || ''); + th.setAttribute('title', item.title || ''); + th.style.height = '60px'; + th.style.fontFamily = 'Helvetica-Bold'; + th.style.fontSize = '16px'; + th.style.lineHeight = '28px'; + th.style.fontWeight = '700'; + th.removeAttribute('file'); + th.addEventListener('click', (e) => { + if (item.clickHandler) { + item.clickHandler(item); + } + }); + this.menuGroup!.appendChild(th); + }); + } + // @ts-ignore + usbConnectionListener(event: USBConnectionEvent) { + if (event.isTrusted) { + this.recordButton!.hidden = false; + this.disconnectButton!.hidden = false; + // @ts-ignore + let usbDevice: USBDevice = event.device; + let option = document.createElement('option'); + option.className = 'select'; + if (typeof usbDevice.serialNumber === 'string') { + option.value = usbDevice.serialNumber; + } + option.selected = true; + option.textContent = usbDevice!.serialNumber ? usbDevice!.serialNumber.replace(/"/g, '') : 'hdc Device'; + this.deviceSelect!.appendChild(option); + SpRecordTrace.serialNumber = option.value; + } + } + + // @ts-ignore + usbDisConnectionListener(event: USBConnectionEvent) { + // @ts-ignore + let disConnectDevice: USBDevice = event.device; + for (let index = 0; index < this.deviceSelect!.children.length; index++) { + let option = this.deviceSelect!.children[index] as HTMLOptionElement; + if (option.value == disConnectDevice.serialNumber) { + let optValue = option.value; + HdcDeviceManager.disConnect(optValue).then(() => {}); + this.deviceSelect!.removeChild(option); + if (SpRecordTrace.serialNumber == optValue) { + let options = this.deviceSelect!.options; + if (options.length > 0) { + let selectedOpt = options[this.deviceSelect!.selectedIndex]; + SpRecordTrace.serialNumber = selectedOpt.value; + } else { + this.recordButton!.hidden = true; + this.disconnectButton!.hidden = true; + SpRecordTrace.serialNumber = ''; + } + } + } + } + } + + recordButtonListener() { + SpRecordTrace.stopRecord = false; + let request = this.makeRequest(); + if (request.pluginConfigs.length == 0) { + this.showHint = true; + return; + } else { + this.showHint = false; + } + let traceCommandStr = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(request, false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + let pluginList: Array = []; + request.pluginConfigs.forEach((pluginConfig) => { + pluginList.push(pluginConfig.pluginName); + }); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + action: 'config_page', + event: 'online_record', + eventData: { + plugin: pluginList, + }, + }); + let selectedOption = this.deviceSelect!.options[this.deviceSelect!.selectedIndex] as HTMLOptionElement; + if (selectedOption) { + SpRecordTrace.serialNumber = selectedOption.value; + } else { + this.sp!.search = true; + this.litSearch!.clear(); + this.progressEL!.loading = false; + this.litSearch!.setPercent('please connect device', -2); + } + + if (this.vs) { + this.appContent!.innerHTML = ''; + this.appContent!.append(this.traceCommand!); + let config = this.makeRequest(); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(config, false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + this.freshMenuItemsStatus('Trace command'); + Cmd.execHdcCmd(Cmd.formatString(CmdConstant.CMS_HDC_STOP, [SpRecordTrace.serialNumber]), (stopRes: string) => { + let cmd = Cmd.formatString(CmdConstant.CMD_MOUNT_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + this.sp!.search = true; + this.progressEL!.loading = true; + this.litSearch!.clear(); + this.litSearch!.setPercent('tracing ' + this.recordSetting!.maxDur * 1000 + 'ms', -1); + this.buttonDisable(true); + this.traceCommand!.show = true; + this.freshMenuDisable(true); + this.freshConfigMenuDisable(true); + Cmd.execHdcTraceCmd(traceCommandStr, SpRecordTrace.serialNumber, (traceResult: string) => { + if (traceResult.indexOf('DestroySession done') != -1) { + this.litSearch!.setPercent('tracing htrace down', -1); + let cmd = Cmd.formatString(CmdConstant.CMD_FIEL_RECV_DEVICES, [ + SpRecordTrace.serialNumber, + this.recordSetting!.output, + ]); + Cmd.execFileRecv(cmd, this.recordSetting!.output, (rt: ArrayBuffer) => { + this.litSearch!.setPercent('downloading Hitrace file ', 101); + let fileName = this.recordSetting!.output.substring(this.recordSetting!.output.lastIndexOf('/') + 1); + let file = new File([rt], fileName); + let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; + let children = main.menus as Array; + let child = children[0].children as Array; + let fileHandler = child[0].fileHandler; + if (fileHandler && !SpRecordTrace.stopRecord) { + this.freshMenuDisable(false); + this.freshConfigMenuDisable(false); + fileHandler({ detail: file }); + } else { + SpRecordTrace.stopRecord = false; + } + }); + } else { + this.litSearch!.setPercent('tracing htrace failed, please check your config ', -2); + this.traceCommand!.show = false; + this.freshMenuDisable(false); + this.freshConfigMenuDisable(false); + this.progressEL!.loading = false; + } + this.buttonDisable(false); + }); + }); + }); + } else { + HdcDeviceManager.connect(selectedOption.value).then((result) => { + log('result is ' + result); + if (result) { + this.appContent!.innerHTML = ''; + this.appContent!.append(this.traceCommand!); + let config = this.makeRequest(); + this.traceCommand!.hdcCommon = PluginConvertUtils.createHdcCmd( + PluginConvertUtils.BeanToCmdTxt(config, false), + this.recordSetting!.output, + this.recordSetting!.maxDur + ); + this.freshMenuItemsStatus('Trace command'); + try { + HdcDeviceManager.stopHiprofiler(CmdConstant.CMS_STOP, true).then(() => { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_MOUNT, true).then(() => { + this.sp!.search = true; + this.progressEL!.loading = true; + this.litSearch!.clear(); + this.litSearch!.setPercent('tracing ' + this.recordSetting!.maxDur * 1000 + 'ms', -1); + this.buttonDisable(true); + this.traceCommand!.show = true; + this.freshMenuDisable(true); + this.freshConfigMenuDisable(true); + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_SHELL + traceCommandStr, false).then( + (traceResult) => { + let re = this.isSuccess(traceResult); + if (re == 0) { + this.traceCommand!.show = false; + this.litSearch!.setPercent('tracing htrace down', -1); + HdcDeviceManager.shellResultAsString( + CmdConstant.CMD_TRACE_FILE_SIZE + this.recordSetting!.output, + false + ).then((traceFileSize) => { + if (traceFileSize.indexOf('No such') != -1) { + this.litSearch!.setPercent('No such file or directory', -2); + } else if (Number(traceFileSize) <= SpRecordTrace.MaxFileSize) { + HdcDeviceManager.fileRecv(this.recordSetting!.output, (perNumber: number) => { + this.litSearch!.setPercent('downloading Hitrace file ', perNumber); + }).then((pullRes) => { + this.litSearch!.setPercent('downloading Hitrace file ', 101); + pullRes.arrayBuffer().then((buffer) => { + let fileName = this.recordSetting!.output.substring( + this.recordSetting!.output.lastIndexOf('/') + 1 + ); + let file = new File([buffer], fileName); + let main = this!.parentNode!.parentNode!.querySelector('lit-main-menu') as LitMainMenu; + let children = main.menus as Array; + let child = children[0].children as Array; + let fileHandler = child[0].fileHandler; + if (fileHandler && !SpRecordTrace.stopRecord) { + this.freshConfigMenuDisable(false); + this.freshMenuDisable(false); + this.buttonDisable(false); + fileHandler({ + detail: file, + }); + } else { + SpRecordTrace.stopRecord = false; + } + }); + }); + } else { + this.litSearch!.setPercent('htrace file is too big', -2); + } + }); + } else if (re == 2) { + this.litSearch!.setPercent('stop tracing htrace ', -1); + this.freshConfigMenuDisable(false); + this.freshMenuDisable(false); + this.buttonDisable(false); + } else if (re == -1) { + this.litSearch!.setPercent('The device is abnormal', -2); + this.progressEL!.loading = false; + this.freshConfigMenuDisable(false); + this.freshMenuDisable(false); + this.buttonDisable(false); + } else { + this.litSearch!.setPercent('tracing htrace failed, please check your config ', -2); + this.freshConfigMenuDisable(false); + this.freshMenuDisable(false); + this.buttonDisable(false); + } + } + ); + }); + }); + } catch (e) { + this.traceCommand!.show = false; + this.freshMenuDisable(false); + this.freshConfigMenuDisable(false); + this.buttonDisable(false); + } + } else { + this.sp!.search = true; + this.litSearch!.clear(); + this.litSearch!.setPercent('please kill other hdc-server !', -2); + } + }); + } + } + + private isSuccess(traceResult: string): number { + if (traceResult.indexOf('CreateSession FAIL') != -1 || traceResult.indexOf('failed') != -1) { + return 1; + } else if (traceResult.indexOf('Signal') != -1) { + return 2; + } else if (traceResult.indexOf('The device is abnormal') != -1) { + return -1; + } else { + return 0; + } + } + + private makeRequest = () => { + let request = this.createSessionRequest(); + if (this.record_template) { + let templateConfigs = this.spRecordTemplate?.getTemplateConfig(); + templateConfigs?.forEach((config) => { + request.pluginConfigs.push(config); + }); + } else { + let hasMonitorMemory = false; + let hasSamps = false; + if (this.probesConfig!.traceConfig.length > 0) { + if ( + this.probesConfig!.traceConfig.find((value) => { + return value != 'FPS'; + }) + ) { + request.pluginConfigs.push(this.createHtracePluginConfig()); + } + if (this.probesConfig!.traceConfig.indexOf('FPS') != -1) { + request.pluginConfigs.push(this.createFpsPluginConfig()); + } + } + if (this.probesConfig!.recordAbility) { + hasMonitorMemory = true; + this.createMonitorPlugin(this, request); + } + let reportingFrequency: number; + if (this.recordSetting!.maxDur > 20) { + reportingFrequency = 5; + } else { + reportingFrequency = 2; + } + if (this.spVmTracker!.startSamp && this.spVmTracker!.process != '') { + hasSamps = true; + } + if (this.probesConfig!.memoryConfig.length > 0 || hasMonitorMemory || hasSamps) { + request.pluginConfigs.push( + this.createMemoryPluginConfig( + reportingFrequency, + this.probesConfig!.memoryConfig.length > 0, + hasMonitorMemory, + hasSamps + ) + ); + } + if (this.spAllocations!.appProcess != '') { + request.pluginConfigs.push(this.createNativePluginConfig(reportingFrequency)); + } + if (this.spRecordPerf!.startSamp) { + request.pluginConfigs.push(this.createHiperConfig(reportingFrequency)); + } + if (this.spFileSystem!.startRecord) { + request.pluginConfigs.push(this.createSystemConfig()); + } + if (this.spSdkConfig!.startSamp && this.spSdkConfig!.getPlugName() != '') { + request.pluginConfigs.push(this.createSdkConfig()); + } + if (this.spHisysEvent?.startSamp) { + request.pluginConfigs.push(this.createHiSystemEventPluginConfig(this.spHisysEvent.process)); + } + if (this.spJsHeap!.process != '') { + request.pluginConfigs.push(this.createJsHeapConfig()); + } + } + return request; + }; + + private createSessionRequest() { + let bufferConfig: ProfilerSessionConfigBufferConfig = { + pages: this.recordSetting!.bufferSize * 256, + policy: ProfilerSessionConfigBufferConfigPolicy.RECYCLE, + }; + let sessionConfig: ProfilerSessionConfig = { + buffers: [bufferConfig], + sessionMode: ProfilerSessionConfigMode.OFFLINE, + resultFile: this.recordSetting!.output, + resultMaxSize: 0, + sampleDuration: this.recordSetting!.maxDur * 1000, + keepAliveTime: 0, + }; + let request: CreateSessionRequest = { + requestId: 1, + sessionConfig: sessionConfig, + pluginConfigs: [], + }; + return request; + } + + private createMonitorPlugin(that: this, request: CreateSessionRequest) { + let processPlugin = that.createProcessPlugin(); + let cpuPlugin = that.createCpuPlugin(); + let diskIoPlugin = that.createDiskIOPlugin(); + let netWorkPlugin = that.createNetworkPlugin(); + request.pluginConfigs.push(processPlugin); + request.pluginConfigs.push(cpuPlugin); + request.pluginConfigs.push(diskIoPlugin); + request.pluginConfigs.push(netWorkPlugin); + } + + private createNetworkPlugin() { + let netWorkConfig: NetworkConfig = { + testFile: '/data/local/tmp/', + }; + let netWorkPlugin: ProfilerPluginConfig = { + pluginName: 'network-plugin', + sampleInterval: 1000, + configData: netWorkConfig, + }; + SpRecordTrace.appendSerialize(netWorkPlugin); + return netWorkPlugin; + } + + private createDiskIOPlugin() { + let diskIoConfig: DiskioConfig = { + reportIoStats: 'IO_REPORT', + }; + let diskIoPlugin: ProfilerPluginConfig = { + pluginName: 'diskio-plugin', + sampleInterval: 1000, + configData: diskIoConfig, + }; + SpRecordTrace.appendSerialize(diskIoPlugin); + return diskIoPlugin; + } + + private createCpuPlugin() { + let cpuConfig: CpuConfig = { + pid: 0, + reportProcessInfo: true, + }; + let cpuPlugin: ProfilerPluginConfig = { + pluginName: 'cpu-plugin', + sampleInterval: 1000, + configData: cpuConfig, + }; + SpRecordTrace.appendSerialize(cpuPlugin); + return cpuPlugin; + } + + private createProcessPlugin() { + let processConfig: ProcessConfig = { + report_process_tree: true, + report_cpu: true, + report_diskio: true, + report_pss: true, + }; + let processPlugin: ProfilerPluginConfig = { + pluginName: 'process-plugin', + sampleInterval: 1000, + configData: processConfig, + }; + SpRecordTrace.appendSerialize(processPlugin); + return processPlugin; + } + + createTraceEvents(traceConfig: Array): Array { + let traceEvents = new Set(); + traceConfig.forEach((config) => { + switch (config) { + case 'Scheduling details': + this.schedulingEvents.forEach((eve: string) => { + traceEvents.add(eve); + }); + break; + case 'CPU Frequency and idle states': + this.cpuFreqEvents.forEach((eve: string) => { + traceEvents.add(eve); + }); + break; + case 'High frequency memory': + this.highFrequencyEvents.forEach((eve: string) => { + traceEvents.add(eve); + }); + break; + case 'Advanced ftrace config': + this.advancedConfigEvents.forEach((eve: string) => { + traceEvents.add(eve); + }); + break; + case 'Syscalls': + this.sysCallsEvents.forEach((eve: string) => { + traceEvents.add(eve); + }); + break; + case 'Board voltages & frequency': + this.powerEvents.forEach((eve: string) => { + traceEvents.add(eve); + }); + break; + } + }); + let ftraceEventsArray: string[] = []; + info('traceEvents length is: ', traceEvents.size); + for (const ftraceEvent of traceEvents) { + ftraceEventsArray.push(ftraceEvent); + } + return ftraceEventsArray; + } + + initHtml(): string { + return ` + +
+
+
+ Target Platform: + + + Add HDC Device +
+ Disconnect + Record +
+
+
+ It looks like you didn't add any probes. Please add at least one +
+
+ +
+ +
+
+
+
+ `; + } + + private createHilogConfig(probesConfig: SpProbesConfig, reportingFrequency: number) { + let hilogConfig: HilogConfig = { + deviceType: Type.HI3516, + logLevel: levelFromJSON(probesConfig.hilogConfig[0]), + needClear: true, + }; + let hilogConfigProfilerPluginConfig: ProfilerPluginConfig = { + pluginName: 'hilog-plugin', + sampleInterval: reportingFrequency * 1000, + configData: hilogConfig, + }; + SpRecordTrace.appendSerialize(hilogConfigProfilerPluginConfig); + return hilogConfigProfilerPluginConfig; + } + + private isNumber(str: string) { + return !isNaN(Number(str)); + } + + private createHiperConfig(reportingFrequency: number) { + let perfConfig = this.spRecordPerf!.getPerfConfig(); + let recordArgs = ''; + recordArgs = recordArgs + '-f ' + perfConfig?.frequency; + if (perfConfig?.process && !perfConfig?.process.includes('ALL') && perfConfig?.process.length > 0) { + let process = perfConfig.process; + if (this.isNumber(process)) { + recordArgs = recordArgs + ' -p ' + perfConfig?.process; + } else { + recordArgs = recordArgs + ' --app ' + perfConfig?.process; + } + } else { + recordArgs = recordArgs + ' -a '; + } + if (perfConfig?.cpu && !perfConfig?.cpu.includes('ALL') && perfConfig?.cpu.length > 0) { + recordArgs = recordArgs + ' -c ' + perfConfig?.cpu; + } + if (perfConfig?.cpuPercent != 0) { + recordArgs = recordArgs + ' --cpu-limit ' + perfConfig?.cpuPercent; + } + if (perfConfig?.eventList && !perfConfig?.eventList.includes('NONE') && perfConfig?.eventList.length > 0) { + recordArgs = recordArgs + ' -e ' + perfConfig?.eventList; + if (perfConfig?.isOffCpu) { + recordArgs = recordArgs + ',sched:sched_waking'; + } + } else { + recordArgs = recordArgs + ' -e hw-cpu-cycles'; + if (perfConfig?.isOffCpu) { + recordArgs = recordArgs + ',sched:sched_waking'; + } + } + if (perfConfig?.callStack != 'none') { + recordArgs = recordArgs + ' --call-stack ' + perfConfig?.callStack; + } + + if (perfConfig?.branch != 'none') { + recordArgs = recordArgs + ' -j ' + perfConfig?.branch; + } + + if (perfConfig?.clockType) { + recordArgs = recordArgs + ' --clockid ' + perfConfig?.clockType; + } + + if (perfConfig?.isOffCpu) { + recordArgs = recordArgs + ' --offcpu'; + } + + if (perfConfig?.noInherit) { + recordArgs = recordArgs + ' --no-inherit'; + } + + if (perfConfig?.mmap) { + recordArgs = recordArgs + ' -m ' + perfConfig.mmap; + } + info('record config Args is: ', recordArgs); + let hiPerf: HiperfPluginConfig = { + isRoot: false, + outfileName: '/data/local/tmp/perf.data', + recordArgs: recordArgs, + }; + let hiPerfPluginConfig: ProfilerPluginConfig = { + pluginName: 'hiperf-plugin', + sampleInterval: reportingFrequency * 1000, + configData: hiPerf, + }; + return hiPerfPluginConfig; + } + + private createSystemConfig() { + let systemConfig = this.spFileSystem!.getSystemConfig(); + let recordArgs = 'hiebpf'; + let recordEvent = []; + if (this.spFileSystem?.startFileSystem) { + recordEvent.push('fs'); + } + if (this.spFileSystem?.startVirtualMemory) { + recordEvent.push('ptrace'); + } + if (this.spFileSystem?.startIo) { + recordEvent.push('bio'); + } + if (recordEvent.length > 0) { + recordArgs += ' --events ' + recordEvent.toString(); + } + recordArgs += ' --duration ' + this.recordSetting?.maxDur; + if (systemConfig?.process && !systemConfig?.process.includes('ALL') && systemConfig?.process.length > 0) { + recordArgs = recordArgs + ' --pids ' + systemConfig?.process; + } + recordArgs += ' --max_stack_depth ' + systemConfig?.unWindLevel; + let systemPluginConfig: FileSystemConfig = { + cmdLine: recordArgs, + outfileName: '/data/local/tmp/ebpf.data', + }; + let ebpfPluginConfig: ProfilerPluginConfig = { + pluginName: 'hiebpf-plugin', + sampleInterval: 1000, + configData: systemPluginConfig, + }; + return ebpfPluginConfig; + } + + private createNativePluginConfig(reportingFrequency: number) { + let appProcess = this.spAllocations!.appProcess; + let re = /^[0-9]+.?[0-9]*/; + let pid = 0; + let processName = ''; + let processId = ''; + if (appProcess.indexOf('(') != -1) { + processId = appProcess.slice(appProcess.lastIndexOf('(') + 1, appProcess.lastIndexOf(')')); + } else { + processId = appProcess; + } + if (re.test(processId)) { + pid = Number(processId); + } else { + processName = appProcess; + } + let nativeConfig: NativeHookConfig = { + pid: pid, + saveFile: false, + fileName: '', + filterSize: this.spAllocations!.filter, + smbPages: this.spAllocations!.shared, + maxStackDepth: this.spAllocations!.unwind, + processName: processName, + mallocFreeMatchingInterval: 1000, + mallocFreeMatchingCnt: 1000, + stringCompressed: true, + fpUnwind: this.spAllocations!.fp_unwind, + blocked: true, + }; + if (Number(SpRecordTrace.selectVersion) >= 4.0) { + nativeConfig.callframeCompress = true; + nativeConfig.recordAccurately = this.spAllocations!.record_accurately; + nativeConfig.offlineSymbolization = this.spAllocations!.offline_symbolization; + if (this.spAllocations!.record_statistics) { + nativeConfig.statisticsInterval = this.spAllocations!.statistics_interval; + } + } + let nativePluginConfig: ProfilerPluginConfig = { + pluginName: 'nativehook', + sampleInterval: reportingFrequency * 1000, + configData: nativeConfig, + }; + return nativePluginConfig; + } + + private createMemoryPluginConfig( + reportingFrequency: number, + hasmemoryConfig: boolean, + hasMonitorMemory: boolean, + hasSmaps: boolean + ) { + let memoryconfig: MemoryConfig = { + reportProcessTree: false, + reportSysmemMemInfo: false, + sysMeminfoCounters: [], + reportSysmemVmemInfo: false, + sysVmeminfoCounters: [], + reportProcessMemInfo: false, + reportAppMemInfo: false, + reportAppMemByMemoryService: false, + pid: [], + }; + if (hasmemoryConfig || hasMonitorMemory) { + memoryconfig.reportProcessTree = true; + memoryconfig.reportSysmemMemInfo = true; + memoryconfig.reportSysmemVmemInfo = true; + memoryconfig.reportProcessMemInfo = true; + } + if (hasSmaps) { + memoryconfig.reportSmapsMemInfo = true; + let pid = Number(this.spVmTracker?.process); + memoryconfig.pid.push(pid); + } + if (hasMonitorMemory) { + SpRecordTrace.ABALITY_MEM_INFO.forEach((va) => { + memoryconfig.sysMeminfoCounters.push(sysMeminfoTypeFromJSON(va)); + }); + } + this.probesConfig!.memoryConfig.forEach((value) => { + if (value.indexOf('Kernel meminfo') != -1) { + if (hasMonitorMemory) { + memoryconfig.sysMeminfoCounters = []; + } + SpRecordTrace.MEM_INFO.forEach((va) => { + memoryconfig.sysMeminfoCounters.push(sysMeminfoTypeFromJSON(va)); + }); + } + if (value.indexOf('Virtual memory stats') != -1) { + SpRecordTrace.VMEM_INFO.forEach((me) => { + memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)); + }); + SpRecordTrace.VMEM_INFO_SECOND.forEach((me) => { + memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)); + }); + SpRecordTrace.VMEM_INFO_THIRD.forEach((me) => { + memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)); + }); + } + }); + let profilerPluginConfig: ProfilerPluginConfig = { + pluginName: 'memory-plugin', + sampleInterval: reportingFrequency * 1000, + configData: memoryconfig, + }; + SpRecordTrace.appendSerialize(profilerPluginConfig); + return profilerPluginConfig; + } + + private createJsHeapConfig() { + let process = this.spJsHeap!.process; + let re = /^[0-9]+.?[0-9]*/; + let pid = 0; + let processId = ''; + if (process.indexOf('(') != -1) { + processId = process.slice(process.lastIndexOf('(') + 1, process.lastIndexOf(')')); + } else { + processId = process; + } + if (re.test(processId)) { + pid = Number(processId); + } + let jsHeapConfig: JsHeapConfig = { + pid: pid, + type: this.spJsHeap!.radioBoxType, + interval: this.spJsHeap!.intervalValue, + capture_numeric_value: this.spJsHeap!.grabNumeric, + track_allocations: this.spJsHeap!.grabAllocations, + }; + let jsHeapPluginConfig: ProfilerPluginConfig = { + pluginName: 'js-memory', + sampleInterval: 5000, + configData: jsHeapConfig, + }; + + return jsHeapPluginConfig; + } + + private createFpsPluginConfig() { + let fpsConfig: FpsConfig = { + reportFps: true, + }; + let fpsPlugin: ProfilerPluginConfig = { + pluginName: 'hidump-plugin', + sampleInterval: 1000, + configData: fpsConfig, + }; + SpRecordTrace.appendSerialize(fpsPlugin); + return fpsPlugin; + } + + private createHiSystemEventPluginConfig(appName: string) { + let hiSystemEventConfig: HiSystemEventConfig = { + msg: 'hisysevent-plugin', + processName: appName, + }; + let hiSystemEventPlugin: ProfilerPluginConfig = { + pluginName: 'hisysevent-plugin', + configData: hiSystemEventConfig, + }; + SpRecordTrace.appendSerialize(hiSystemEventPlugin); + return hiSystemEventPlugin; + } + + private createHtracePluginConfig() { + let tracePluginConfig: TracePluginConfig = { + ftraceEvents: this.createTraceEvents(this.probesConfig!.traceConfig), + hitraceCategories: [], + hitraceApps: [], + bufferSizeKb: 2048, + flushIntervalMs: 1000, + flushThresholdKb: 4096, + parseKsyms: true, + clock: 'boot', + tracePeriodMs: 200, + rawDataPrefix: '', + traceDurationMs: 0, + debugOn: false, + hitraceTime: this.recordSetting!.maxDur, + }; + if (this.probesConfig!.traceEvents.length > 0) { + tracePluginConfig.hitraceCategories = this.probesConfig!.traceEvents; + } + let htraceProfilerPluginConfig: ProfilerPluginConfig = { + pluginName: 'ftrace-plugin', + sampleInterval: 1000, + configData: tracePluginConfig, + }; + SpRecordTrace.appendSerialize(htraceProfilerPluginConfig); + return htraceProfilerPluginConfig; + } + + static appendSerialize(profilerPluginConfig: ProfilerPluginConfig) { + if (Number(SpRecordTrace.selectVersion) >= 4.0) { + } + } + + private createSdkConfig() { + let gpuConfig = this.spSdkConfig!.getGpuConfig(); + let gpuPluginConfig: ProfilerPluginConfig = { + pluginName: this.spSdkConfig!.getPlugName(), + sampleInterval: this.spSdkConfig!.getSampleInterval(), + configData: gpuConfig, + }; + SpRecordTrace.appendSerialize(gpuPluginConfig); + return gpuPluginConfig; + } + + freshConfigMenuDisable(disable: boolean) { + let querySelectors = this.shadowRoot?.querySelectorAll('lit-main-menu-item'); + querySelectors!.forEach((item) => { + if (disable) { + item.style.pointerEvents = 'none'; + this.traceCommand!.show = true; + } else { + item.style.pointerEvents = 'auto'; + this.traceCommand!.show = false; + } + item.disabled = disable; + }); + } + + public startRefreshDeviceList() { + if (this.refreshDeviceTimer == null) { + this.refreshDeviceTimer = setInterval(() => { + this.refreshDeviceList(); + }, 5000); + } + } + + buttonDisable(disable: boolean) { + if (disable) { + this.disconnectButton!.style.pointerEvents = 'none'; + this.recordButton!.style.pointerEvents = 'none'; + this.addButton!.style.pointerEvents = 'none'; + this.deviceSelect!.style.pointerEvents = 'none'; + this.deviceVersion!.style.pointerEvents = 'none'; + } else { + this.disconnectButton!.style.pointerEvents = 'auto'; + this.recordButton!.style.pointerEvents = 'auto'; + this.addButton!.style.pointerEvents = 'auto'; + this.deviceSelect!.style.pointerEvents = 'auto'; + this.deviceVersion!.style.pointerEvents = 'auto'; + } + } + + freshMenuItemsStatus(currentValue: string) { + let litMainMenuGroup = this.shadowRoot?.querySelector('lit-main-menu-group'); + let litMainMenuItemNodeListOf = litMainMenuGroup!.querySelectorAll('lit-main-menu-item'); + litMainMenuItemNodeListOf.forEach((item) => { + item.back = item.title == currentValue; + }); + } + + synchronizeDeviceList() { + this.deviceSelect!.innerHTML = ''; + if (SpRecordTrace.serialNumber != '') { + let option = document.createElement('option'); + option.className = 'select'; + option.selected = true; + option.value = SpRecordTrace.serialNumber; + option.textContent = SpRecordTrace.serialNumber; + this.deviceSelect!.appendChild(option); + this.recordButton!.hidden = false; + this.disconnectButton!.hidden = false; + if (SpRecordTrace.selectVersion && SpRecordTrace.selectVersion != '') { + this.setDeviceVersionSelect(SpRecordTrace.selectVersion); + } + } + } +} diff --git a/ide/src/trace/component/SpRecyclerSystemTrace.ts b/ide/src/trace/component/SpRecyclerSystemTrace.ts new file mode 100644 index 0000000000000000000000000000000000000000..f61cf182c1193d1fd8b4b6d380b183cde58b9cbe --- /dev/null +++ b/ide/src/trace/component/SpRecyclerSystemTrace.ts @@ -0,0 +1,784 @@ +// @ts-nocheck +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import './trace/TimerShaftElement.js'; +import './trace/base/TraceRow.js'; +import './trace/base/TraceRowRecyclerView.js'; +import { + getAsyncEvents, + getCpuUtilizationRate, + getFps, + getFunDataByTid, + queryCpuData, + queryCpuFreq, + queryCpuFreqData, + queryCpuMax, + queryCpuMaxFreq, + queryProcess, + queryProcessData, + queryProcessMem, + queryProcessMemData, + queryProcessThreads, + queryThreadData, + queryTotalTime, + threadPool, +} from '../database/SqlLite.js'; +import { TraceRow } from './trace/base/TraceRow.js'; +import { TimerShaftElement } from './trace/TimerShaftElement.js'; +import { TimeRange } from './trace/timer-shaft/RangeRuler.js'; +import { CpuStruct } from '../bean/CpuStruct.js'; +import { CpuFreqStruct } from '../bean/CpuFreqStruct.js'; +import { ProcessStruct } from '../bean/ProcessStruct.js'; +import { ColorUtils } from './trace/base/ColorUtils.js'; +import './trace/base/TraceSheet.js'; +import { TraceSheet } from './trace/base/TraceSheet.js'; +import { ThreadStruct } from '../bean/ThreadStruct.js'; +import { ProcessMemStruct } from '../bean/ProcessMemStruct.js'; +import { FuncStruct } from '../bean/FuncStruct.js'; +import { FpsStruct } from '../bean/FpsStruct.js'; +import { RangeSelect } from './trace/base/RangeSelect.js'; +import { SelectionParam } from '../bean/BoxSelection.js'; +import { procedurePool } from '../database/Procedure.js'; +import { SportRuler } from './trace/timer-shaft/SportRuler.js'; +import { TraceRowRecyclerView } from './trace/base/TraceRowRecyclerView.js'; +import { TraceRowObject } from './trace/base/TraceRowObject.js'; +import { Rect } from './trace/timer-shaft/Rect.js'; + +@element('sp-recycler-system-trace') +export class SpRecyclerSystemTrace extends BaseElement { + static scrollViewWidth = 0; + rowsEL: TraceRowRecyclerView | undefined | null; + private timerShaftEL: TimerShaftElement | null | undefined; + private range: TimeRange | undefined; + private traceSheetEL: TraceSheet | undefined | null; + private rangeSelect!: RangeSelect; + private processThreads: Array = []; + private processAsyncEvent: Array = []; + private processMem: Array = []; + + initElements(): void { + this.rowsEL = this.shadowRoot?.querySelector('.rows'); + this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft'); + this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet'); + this.rangeSelect = new RangeSelect(this.timerShaftEL); + this.rangeSelect.rowsEL = this.rowsEL; + document?.addEventListener('flag-change', (event: any) => { + let flag = event.detail; + this.timerShaftEL?.modifyFlagList(event.detail.type, event.detail.flagObj); + if (flag.hidden) { + this.traceSheetEL?.setAttribute('mode', 'hidden'); + } + }); + SpRecyclerSystemTrace.scrollViewWidth = this.getScrollWidth(); + this.rangeSelect.selectHandler = (rows) => { + let selection = new SelectionParam(); + // 框选的 cpu ,无则不传 + selection.cpus = []; + // 框选的 线程 id,无则不传 + selection.threadIds = []; + // 款选的函数的 线程id ,无则不传 + selection.funTids = []; + // 框选的 内存 trackId ,无则不传 + selection.processTrackIds = []; + // 框选的起始时间 + selection.leftNs = 0; + // 框选的结束时间 + selection.rightNs = 0; + rows.forEach((it) => { + if (it.rowType == TraceRow.ROW_TYPE_CPU) { + selection.cpus.push(parseInt(it.rowId!)); + } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) { + selection.threadIds.push(parseInt(it.rowId!)); + } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) { + selection.funTids.push(parseInt(it.rowId!)); + } else if (it.rowType == TraceRow.ROW_TYPE_MEM) { + selection.trackIds.push(parseInt(it.rowId!)); + } else if (it.rowType == TraceRow.ROW_TYPE_FPS) { + selection.hasFps = true; + } else if (it.rowType == TraceRow.ROW_TYPE_HEAP) { + selection.nativeMemory.push(parseInt(it.rowId!)); + } + if (it.rangeSelect && it.rangeSelect.startNS) { + selection.leftNs = it.rangeSelect.startNS; + } + if (it.rangeSelect && it.rangeSelect.endNS) { + selection.rightNs = it.rangeSelect.endNS; + } + }); + this.traceSheetEL?.rangeSelect(selection); + }; + // @ts-ignore + new ResizeObserver((entries) => { + let width = entries[0].contentRect.width - 1 - SpRecyclerSystemTrace.scrollViewWidth; + requestAnimationFrame(() => { + this.timerShaftEL?.updateWidth(width); + this.shadowRoot!.querySelectorAll>('trace-row').forEach((it) => it.updateWidth(width)); + }); + }).observe(this); + // @ts-ignore + new ResizeObserver((entries) => { + let width = this.clientWidth - 1 - SpRecyclerSystemTrace.scrollViewWidth; + requestAnimationFrame(() => { + this.timerShaftEL?.updateWidth(width); + this.shadowRoot!.querySelectorAll>('trace-row').forEach((it) => it.updateWidth(width)); + }); + }).observe(window.document.body); + } + + getScrollWidth() { + let noScroll, + scroll, + oDiv = document.createElement('div'); + oDiv.style.cssText = 'position:absolute; top:-1000px; width:100px; height:100px; overflow:hidden;'; + noScroll = document.body.appendChild(oDiv).clientWidth; + oDiv.style.overflowY = 'scroll'; + scroll = oDiv.clientWidth; + document.body.removeChild(oDiv); + return noScroll - scroll + 1; + } + + getVisibleRows(): Array> { + return [...this.rowsEL!.shadowRoot!.querySelectorAll>('trace-row')]; + } + + timerShaftELRangeChange = (e: any) => { + this.range = e.detail; + TraceRow.range = this.range; + let scrollTop = this.rowsEL?.scrollTop || 0; + let scrollHeight = this.rowsEL?.clientHeight || 0; + //在rowsEL显示范围内的 trace-row组件将收到时间区间变化通知 + this.getVisibleRows().forEach((it) => { + it.dataListCache.length = 0; + this.hoverStructNull(); + it.drawObject(); + }); + }; + + rowsElOnScroll = (e: any) => { + this.hoverStructNull(); + let rows = this.getVisibleRows(); + rows.forEach((it, index) => { + if (index == 0 || index == rows.length - 1) { + it.dataListCache.length = 0; + it.drawObject(); + } + }); + }; + + documentOnMouseDown = (ev: MouseEvent) => { + this.rangeSelect.mouseDown(ev); + }; + + documentOnMouseUp = (ev: MouseEvent) => { + this.rangeSelect.mouseUp(ev); + }; + + documentOnMouseMove = (ev: MouseEvent) => { + let rows = this.getVisibleRows(); + this.rangeSelect.mouseMove(rows, ev); + rows.forEach((tr) => { + let x = ev.offsetX - (tr.canvasContainer?.offsetLeft || 0); + let y = ev.offsetY - (tr.canvasContainer?.offsetTop || 0) + (this.rowsEL?.scrollTop || 0); + //判断鼠标是否在当前 trace-row + if (x > tr.frame.x && x < tr.frame.x + tr.frame.width && y > tr.frame.y && y < tr.frame.y + tr.frame.height) { + this.hoverStructNull(); + if (tr.rowType === TraceRow.ROW_TYPE_CPU) { + CpuStruct.hoverCpuStruct = tr.onMouseHover(x, y); + if (CpuStruct.hoverCpuStruct) { + tr.tip = `P:${CpuStruct.hoverCpuStruct.processName || 'Process'} [${ + CpuStruct.hoverCpuStruct.processId + }]T:${CpuStruct.hoverCpuStruct.name} [${CpuStruct.hoverCpuStruct.tid}]`; + } + tr.setTipLeft(x, CpuStruct.hoverCpuStruct); + } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ) { + CpuFreqStruct.hoverCpuFreqStruct = tr.onMouseHover(x, y); + if (CpuFreqStruct.hoverCpuFreqStruct) { + tr.tip = `${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct.value!)} kHz`; + } + tr.setTipLeft(x, CpuFreqStruct.hoverCpuFreqStruct); + } else if (tr.rowType === TraceRow.ROW_TYPE_THREAD) { + ThreadStruct.hoverThreadStruct = tr.onMouseHover(x, y, false); + } else if (tr.rowType === TraceRow.ROW_TYPE_FUNC) { + FuncStruct.hoverFuncStruct = tr.onMouseHover(x, y, false); + } else if (tr.rowType === TraceRow.ROW_TYPE_HEAP) { + HeapStruct.hoverHeapStruct = tr.onMouseHover(x, y, false); + if (HeapStruct.hoverHeapStruct) { + tr.tip = `${ColorUtils.formatNumberComma(HeapStruct.hoverHeapStruct.heapsize!)} byte`; + } + tr.setTipLeft(x, HeapStruct.hoverHeapStruct); + } else { + this.hoverStructNull(); + } + } else { + tr.onMouseLeave(x, y); + } + tr.drawObject(); + }); + }; + + hoverStructNull() { + CpuStruct.hoverCpuStruct = undefined; + CpuFreqStruct.hoverCpuFreqStruct = undefined; + ThreadStruct.hoverThreadStruct = undefined; + FuncStruct.hoverFuncStruct = undefined; + } + + selectStructNull() { + CpuStruct.selectCpuStruct = undefined; + CpuFreqStruct.selectCpuFreqStruct = undefined; + ThreadStruct.selectThreadStruct = undefined; + FuncStruct.selectFuncStruct = undefined; + } + + documentOnClick = (ev: MouseEvent) => { + if (this.rangeSelect.isDrag()) { + return; + } + this.rowsEL?.querySelectorAll>('trace-row').forEach((it) => (it.rangeSelect = undefined)); + this.selectStructNull(); + if (CpuStruct.hoverCpuStruct) { + CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct; + this.traceSheetEL?.displayCpuData(CpuStruct.hoverCpuStruct); + } else if (ThreadStruct.hoverThreadStruct) { + ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct; + this.traceSheetEL?.displayThreadData(ThreadStruct.hoverThreadStruct); + } else if (FuncStruct.hoverFuncStruct) { + FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct; + this.traceSheetEL?.displayFuncData(FuncStruct.hoverFuncStruct); + } else if (SportRuler.rulerFlagObj) { + } else { + this.traceSheetEL?.setAttribute('mode', 'hidden'); + } + this.documentOnMouseMove(ev); + }; + + connectedCallback() { + /** + * 监听时间轴区间变化 + */ + this.timerShaftEL?.addEventListener('range-change', this.timerShaftELRangeChange); + /** + * 监听rowsEL的滚动时间,刷新可见区域的trace-row组件的时间区间(将触发trace-row组件重绘) + */ + this.rowsEL?.addEventListener('scroll', this.rowsElOnScroll); + /** + * 监听document的mousemove事件 坐标通过换算后找到当前鼠标所在的trace-row组件,将坐标传入 + */ + document.addEventListener('mousemove', this.documentOnMouseMove); + document.addEventListener('mousedown', this.documentOnMouseDown); + document.addEventListener('mouseup', this.documentOnMouseUp); + document.addEventListener('click', this.documentOnClick); + } + + disconnectedCallback() { + this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange); + this.rowsEL?.removeEventListener('scroll', this.rowsElOnScroll); + document.removeEventListener('mousemove', this.documentOnMouseMove); + document.removeEventListener('click', this.documentOnClick); + } + + loadDatabaseUrl(url: string, complete?: Function) { + this.init({ url: url }).then(() => { + let scrollTop = this.rowsEL?.scrollTop || 0; + let scrollHeight = this.rowsEL?.clientHeight || 0; + this.rowsEL?.querySelectorAll('trace-row').forEach((it: any) => { + let top = it.offsetTop - (this.rowsEL?.offsetTop || 0); + if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) { + (it as TraceRow).dataListCache.length = 0; + } + }); + if (complete) { + complete(); + } + }); + } + + loadDatabaseArrayBuffer(buf: ArrayBuffer, complete?: Function) { + this.init({ buf }).then(() => { + let scrollTop = this.rowsEL?.scrollTop || 0; + let scrollHeight = this.rowsEL?.clientHeight || 0; + this.rowsEL?.querySelectorAll('trace-row').forEach((it: any) => { + let top = it.offsetTop - (this.rowsEL?.offsetTop || 0); + if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) { + (it as TraceRow).dataListCache.length = 0; + } + }); + if (complete) { + complete(); + } + }); + } + + init = async (param: { buf?: ArrayBuffer; url?: string }) => { + if (this.rowsEL) this.rowsEL.innerHTML = ''; + this.traceSheetEL?.setAttribute('mode', 'hidden'); + this.timerShaftEL?.reset(); + procedurePool.clearCache(); + param.buf && (await threadPool.initSqlite(param.buf)); + param.url && (await threadPool.initServer(param.url)); + this.processThreads = await queryProcessThreads(); + this.processMem = await queryProcessMem(); + this.processAsyncEvent = await getAsyncEvents(); + await this.initTotalTime(); + let cpuObjs = await this.initCpu(); + await this.initCpuRate(); + let freqObjs = await this.initCpuFreq(); + let fpsObjs = await this.initFPS(); + let processObjs = await this.initProcess(); + this.rowsEL.dataSource = [...cpuObjs, ...freqObjs, ...fpsObjs, ...processObjs]; + this.getVisibleRows().forEach((it) => it.drawObject()); + }; + initCpuRate = async () => { + let rates = await getCpuUtilizationRate(0, this.timerShaftEL?.totalNS || 0); + if (this.timerShaftEL) this.timerShaftEL.cpuUsage = rates; + }; + initTotalTime = async () => { + let res = await queryTotalTime(); + if (this.timerShaftEL) { + this.timerShaftEL.totalNS = res[0].total; + this.timerShaftEL.loadComplete = true; + } + }; + initCpu = async () => { + let objs = []; + let array = await queryCpuMax(); + if (array && array.length > 0 && array[0]) { + let cpuMax = array[0].cpu; + CpuStruct.cpuCount = cpuMax + 1; + for (let i1 = 0; i1 < CpuStruct.cpuCount; i1++) { + const cpuId = i1; + let traceRow = new TraceRowObject(); + traceRow.rowId = `${cpuId}`; + traceRow.rowType = TraceRow.ROW_TYPE_CPU; + traceRow.rowParentId = ''; + traceRow.rowHeight = 40; + traceRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, traceRow.rowHeight); + traceRow.name = `Cpu ${cpuId}`; + traceRow.supplier = () => queryCpuData(cpuId, 0, this.timerShaftEL?.totalNS || 0); + traceRow.onThreadHandler = (row, ctx) => { + procedurePool.submitWithName( + 'cpu', + `cpu${cpuId}`, + { + list: traceRow.must ? traceRow.dataList : undefined, + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + frame: traceRow.frame, + }, + (res: any) => { + traceRow.dataListCache = res; + traceRow.must = false; + row.clearCanvas(); + row.c!.beginPath(); + row.drawLines(); + for (let i = 0; i < res.length; i++) { + CpuStruct.draw(ctx, res[i]); + } + row.drawSelection(); + row.c!.closePath(); + } + ); + }; + objs.push(traceRow); + } + } + return objs; + }; + + initCpuFreq = async () => { + let objs = []; + let freqList = await queryCpuFreq(); + let freqMaxList = await queryCpuMaxFreq(); + CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq; + let math = () => { + let units: Array = ['', 'K', 'M', 'G', 'T', 'E']; + let sb = ' '; + CpuFreqStruct.maxFreqName = ' '; + if (CpuFreqStruct.maxFreq > 0) { + let log10: number = Math.ceil(Math.log10(CpuFreqStruct.maxFreq)); + let pow10: number = Math.pow(10, log10); + let afterCeil: number = Math.ceil(CpuFreqStruct.maxFreq / (pow10 / 4)) * (pow10 / 4); + CpuFreqStruct.maxFreq = afterCeil; + let unitIndex: number = Math.floor(log10 / 3); + sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}hz`; + } + CpuFreqStruct.maxFreqName = sb.toString(); + }; + math(); + for (let i = 0; i < freqList.length; i++) { + const it = freqList[i]; + let traceRow = new TraceRowObject(); + traceRow.rowId = `${it.cpu}`; + traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ; + traceRow.rowParentId = ''; + traceRow.rowHeight = 40; + traceRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, traceRow.rowHeight); + traceRow.name = `Cpu ${it.cpu} Frequency`; + traceRow.supplier = () => queryCpuFreqData(it.cpu); + traceRow.onThreadHandler = (row, ctx) => { + procedurePool.submitWithName( + 'freq', + `freq${it.cpu}`, + { + list: traceRow.must ? traceRow.dataList : undefined, + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + frame: traceRow.frame, + }, + (res: any) => { + traceRow.dataListCache = res; + traceRow.must = false; + row.clearCanvas(); + row.drawLines(); + row.c!.beginPath(); + for (let i = 0; i < res.length; i++) { + CpuFreqStruct.draw(ctx, res[i]); + } + row.drawSelection(); + row.c!.closePath(); + let s = CpuFreqStruct.maxFreqName; + let textMetrics = ctx.measureText(s); + row.c!.globalAlpha = 0.8; + row.c!.fillStyle = '#f0f0f0'; + row.c!.fillRect(0, 5, textMetrics.width + 8, 18); + row.c!.globalAlpha = 1; + row.c!.fillStyle = '#333'; + ctx.textBaseline = 'middle'; + ctx.fillText(maxFps, 4, 5 + 9); + } + ); + }; + objs.push(traceRow); + } + return objs; + }; + + initFPS = async () => { + let objs = []; + let fpsRow = new TraceRowObject(); + fpsRow.rowId = `fps`; + fpsRow.rowType = TraceRow.ROW_TYPE_FPS; + fpsRow.rowParentId = ''; + FpsStruct.maxFps = 0; + fpsRow.rowHeight = 40; + fpsRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, fpsRow.rowHeight); + fpsRow.name = 'FPS'; + fpsRow.supplier = () => getFps(); + fpsRow.onDrawHandler = (row, ctx) => { + if (fpsRow.dataListCache.length > 0) { + for (let i = 0; i < fpsRow.dataListCache.length; i++) { + FpsStruct.draw(ctx, fpsRow.dataListCache[i]); + } + } else { + if (fpsRow.dataList) { + for (let i = 0; i < fpsRow.dataList.length; i++) { + let it = fpsRow.dataList[i]; + if ((it.fps || 0) > FpsStruct.maxFps) { + FpsStruct.maxFps = it.fps || 0; + } + if (i === fpsRow.dataList.length - 1) { + it.dur = (TraceRow.range?.endNS || 0) - (it.startNS || 0); + } else { + it.dur = (fpsRow.dataList[i + 1].startNS || 0) - (it.startNS || 0); + } + if ( + (it.startNS || 0) + (it.dur || 0) > (TraceRow.range?.startNS || 0) && + (it.startNS || 0) < (TraceRow.range?.endNS || 0) + ) { + FpsStruct.setFrame( + fpsRow.dataList[i], + 5, + TraceRow.range?.startNS || 0, + TraceRow.range?.endNS || 0, + TraceRow.range?.totalNS || 0, + fpsRow.frame + ); + if ( + i > 0 && + (fpsRow.dataList[i - 1].frame?.x || 0) == (fpsRow.dataList[i].frame?.x || 0) && + (fpsRow.dataList[i - 1].frame?.width || 0) == (fpsRow.dataList[i].frame?.width || 0) + ) { + } else { + fpsRow.dataListCache.push(fpsRow.dataList[i]); + FpsStruct.draw(ctx, fpsRow.dataList[i]); + } + } + } + } + } + if (ctx) { + let maxFps = FpsStruct.maxFps + 'FPS'; + let textMetrics = ctx.measureText(maxFps); + ctx.globalAlpha = 0.8; + ctx.fillStyle = '#f0f0f0'; + ctx.fillRect(0, 5, textMetrics.width + 8, 18); + ctx.globalAlpha = 1; + ctx.fillStyle = '#333'; + ctx.textBaseline = 'middle'; + ctx.fillText(maxFps, 4, 5 + 9); + } + }; + objs.push(fpsRow); + return objs; + }; + + /** + * 添加进程信息 + */ + initProcess = async () => { + let objs = []; + let processList = await queryProcess(); + for (let i = 0; i < processList.length; i++) { + const it = processList[i]; + let processRow = new TraceRowObject(); + processRow.rowId = `${it.pid}`; + processRow.rowType = TraceRow.ROW_TYPE_PROCESS; + processRow.rowParentId = ''; + processRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, processRow.rowHeight); + processRow.folder = true; + processRow.name = `${it.processName || 'Process'} ${it.pid}`; + processRow.supplier = () => queryProcessData(it.pid || -1, 0, TraceRow.range?.totalNS || 0); + processRow.onThreadHandler = (row, ctx) => { + procedurePool.submitWithName( + 'process', + `process ${it.pid} ${it.processName}`, + { + list: processRow.must ? processRow.dataList : undefined, + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + frame: processRow.frame, + }, + (res: any) => { + processRow.dataListCache = res; + processRow.must = false; + row.clearCanvas(); + row.drawLines(); + row.c!.beginPath(); + for (let i = 0; i < res.length; i++) { + ProcessStruct.draw(ctx, res[i]); + } + row.drawSelection(); + row.c!.closePath(); + } + ); + }; + objs.push(processRow); + + /** + * 添加进程内存信息 + */ + let processMem = this.processMem.filter((mem) => mem.pid === it.pid); + processMem.forEach((mem) => { + let row = new TraceRowObject(); + row.rowId = `${mem.trackId}`; + row.rowType = TraceRow.ROW_TYPE_MEM; + row.rowParentId = `${it.pid}`; + row.rowHidden = !processRow.expansion; + row.rowHeight = 40; + row.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, row.rowHeight); + row.name = `${mem.trackName}`; + row.children = true; + row.supplier = () => + queryProcessMemData(mem.trackId).then((res) => { + let maxValue = Math.max(...res.map((it) => it.value || 0)); + for (let j = 0; j < res.length; j++) { + res[j].maxValue = maxValue; + if (j == res.length - 1) { + res[j].duration = this.range?.totalNS || 0; + } else { + res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0); + } + if (j > 0) { + res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0); + } else { + res[j].delta = 0; + } + } + return res; + }); + row.onThreadHandler = (r, ctx) => { + procedurePool.submitWithName( + 'mem', + `mem ${mem.trackId} ${mem.trackName}`, + { + list: row.must ? row.dataList : undefined, + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + frame: row.frame, + }, + (res: any) => { + row.dataListCache = res; + row.must = false; + r.clearCanvas(); + r.drawLines(); + r.c!.beginPath(); + for (let i = 0; i < res.length; i++) { + ProcessMemStruct.draw(ctx, res[i]); + } + r.drawSelection(); + r.c!.closePath(); + } + ); + }; + objs.push(row); + }); + /** + * 添加进程线程信息 + */ + let threads = this.processThreads.filter( + (thread) => thread.pid === it.pid && thread.tid != 0 && thread.threadName != null + ); + threads.forEach((thread, i) => { + let threadRow = new TraceRowObject(); + threadRow.rowId = `${thread.tid}`; + threadRow.rowType = TraceRow.ROW_TYPE_THREAD; + threadRow.rowParentId = `${it.pid}`; + threadRow.rowHidden = !processRow.expansion; + threadRow.rowHeight = 40; + threadRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, threadRow.rowHeight); + threadRow.name = `${thread.threadName} ${thread.tid}`; + threadRow.children = true; + threadRow.supplier = () => + queryThreadData(thread.tid || 0).then((res) => { + getFunDataByTid(thread.tid || 0).then((funs) => { + if (funs.length > 0) { + let maxHeight = (Math.max(...funs.map((it) => it.depth || 0)) + 1) * 20 + 20; + let funcRow = new TraceRowObject(); + funcRow.rowId = `${thread.tid}`; + funcRow.rowType = TraceRow.ROW_TYPE_FUNC; + funcRow.rowParentId = `${it.pid}`; + funcRow.rowHidden = !processRow.expansion; + funcRow.rowHeight = maxHeight; + funcRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, funcRow.rowHeight); + funcRow.name = `${thread.threadName} ${thread.tid}`; + funcRow.children = true; + funcRow.supplier = () => new Promise((resolve, reject) => resolve(funs)); + funcRow.onThreadHandler = (r, ctx) => { + procedurePool.submitWithName( + 'func', + `func ${thread.tid} ${thread.threadName}`, + { + list: funcRow.must ? funcRow.dataList : undefined, + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + frame: threadRow.frame, + }, + (res: any) => { + funcRow.must = false; + funcRow.dataListCache = res; + r.clearCanvas(); + r.drawLines(); + r.c!.beginPath(); + for (let i = 0; i < res.length; i++) { + FuncStruct.draw(ctx, res[i]); + } + r.drawSelection(); + r.c!.closePath(); + } + ); + }; + } + }); + return res; + }); + threadRow.onThreadHandler = (r, ctx) => { + procedurePool.submitWithName( + 'thread', + `thread ${thread.tid} ${thread.threadName}`, + { + list: threadRow.must ? threadRow.dataList : undefined, + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + frame: threadRow.frame, + }, + (res: any) => { + threadRow.dataListCache = res; + threadRow.must = false; + r.clearCanvas(); + r.drawLines(); + r.c!.beginPath(); + for (let i = 0; i < res.length; i++) { + ThreadStruct.draw(ctx, res[i]); + } + r.drawSelection(); + r.c!.closePath(); + } + ); + }; + objs.push(threadRow); + }); + } + return objs; + }; + + insertAfter(newEl: HTMLElement, targetEl: HTMLElement) { + let parentEl = targetEl.parentNode; + if (parentEl!.lastChild == targetEl) { + parentEl!.appendChild(newEl); + } else { + parentEl!.insertBefore(newEl, targetEl.nextSibling); + } + } + + initHtml(): string { + return ` + +
+ + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/SpSystemTrace.ts b/ide/src/trace/component/SpSystemTrace.ts new file mode 100644 index 0000000000000000000000000000000000000000..41d3b82492edc58d3063a5f165e1b6cf5fb9d37b --- /dev/null +++ b/ide/src/trace/component/SpSystemTrace.ts @@ -0,0 +1,2889 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import './trace/TimerShaftElement.js'; +import './trace/base/TraceRow.js'; +import { queryEbpfSamplesCount, querySceneSearchFunc, querySearchFunc, threadPool } from '../database/SqlLite.js'; +import { RangeSelectStruct, TraceRow } from './trace/base/TraceRow.js'; +import { TimerShaftElement } from './trace/TimerShaftElement.js'; +import './trace/base/TraceSheet.js'; +import { TraceSheet } from './trace/base/TraceSheet.js'; +import { RangeSelect } from './trace/base/RangeSelect.js'; +import { SelectionParam } from '../bean/BoxSelection.js'; +import { procedurePool } from '../database/Procedure.js'; +import { SpApplication } from '../SpApplication.js'; +import { SPT } from '../bean/StateProcessThread.js'; +import { Flag } from './trace/timer-shaft/Flag.js'; +import { SportRuler } from './trace/timer-shaft/SportRuler.js'; +import { SpHiPerf } from './chart/SpHiPerf.js'; +import { SearchSdkBean, SearchThreadProcessBean } from '../bean/SearchFuncBean.js'; +import { error, info } from '../../log/Log.js'; +import { + drawFlagLineSegment, + drawLines, + drawLinkLines, + drawWakeUp, + isFrameContainPoint, + ns2x, + ns2xByTimeShaft, + PairPoint, + Rect, +} from '../database/ui-worker/ProcedureWorkerCommon.js'; +import { SpChartManager } from './chart/SpChartManager.js'; +import { CpuStruct } from '../database/ui-worker/ProcedureWorkerCPU.js'; +import { ProcessStruct } from '../database/ui-worker/ProcedureWorkerProcess.js'; +import { CpuFreqStruct } from '../database/ui-worker/ProcedureWorkerFreq.js'; +import { CpuFreqLimitsStruct } from '../database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; +import { ThreadStruct } from '../database/ui-worker/ProcedureWorkerThread.js'; +import { func, FuncStruct } from '../database/ui-worker/ProcedureWorkerFunc.js'; +import { CpuStateStruct } from '../database/ui-worker/ProcedureWorkerCpuState.js'; +import { HiPerfCpuStruct } from '../database/ui-worker/ProcedureWorkerHiPerfCPU.js'; +import { HiPerfProcessStruct } from '../database/ui-worker/ProcedureWorkerHiPerfProcess.js'; +import { HiPerfThreadStruct } from '../database/ui-worker/ProcedureWorkerHiPerfThread.js'; +import { HiPerfEventStruct } from '../database/ui-worker/ProcedureWorkerHiPerfEvent.js'; +import { HiPerfReportStruct } from '../database/ui-worker/ProcedureWorkerHiPerfReport.js'; +import { FpsStruct } from '../database/ui-worker/ProcedureWorkerFPS.js'; +import { CpuAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerCpuAbility.js'; +import { DiskAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerDiskIoAbility.js'; +import { MemoryAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerMemoryAbility.js'; +import { NetworkAbilityMonitorStruct } from '../database/ui-worker/ProcedureWorkerNetworkAbility.js'; +import { ClockStruct } from '../database/ui-worker/ProcedureWorkerClock.js'; +import { Utils } from './trace/base/Utils.js'; +import { IrqStruct } from '../database/ui-worker/ProcedureWorkerIrq.js'; +import { JanksStruct } from '../bean/JanksStruct.js'; +import { JankStruct } from '../database/ui-worker/ProcedureWorkerJank.js'; +import { HeapStruct } from '../database/ui-worker/ProcedureWorkerHeap.js'; +import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil.js'; +import { HeapSnapshotStruct } from '../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; +import { HeapDataInterface } from '../../js-heap/HeapDataInterface.js'; +import { TabPaneSummary } from './trace/sheet/snapshot/TabPaneSummary.js'; +import { LitTabs } from '../../base-ui/tabs/lit-tabs.js'; +import { SpJsMemoryChart } from './chart/SpJsMemoryChart.js'; + +function dpr() { + return window.devicePixelRatio || 1; +} + +@element('sp-system-trace') +export class SpSystemTrace extends BaseElement { + static mouseCurrentPosition = 0; + static offsetMouse = 0; + static moveable = true; + static scrollViewWidth = 0; + static isCanvasOffScreen = true; + static SPT_DATA: Array = []; + static DATA_DICT: Map = new Map(); + static SDK_CONFIG_MAP: any; + static sliceRangeMark: any; + intersectionObserver: IntersectionObserver | undefined; + tipEL: HTMLDivElement | undefined | null; + rowsEL: HTMLDivElement | undefined | null; + rowsPaneEL: HTMLDivElement | undefined | null; + spacerEL: HTMLDivElement | undefined | null; + favoriteRowsEL: HTMLDivElement | undefined | null; + visibleRows: Array> = []; + collectRows: Array> = []; + keyboardEnable = true; + currentRowType = ''; /*保存当前鼠标所在行的类型*/ + observerScrollHeightEnable: boolean = false; + observerScrollHeightCallback: Function | undefined; + // @ts-ignore + observer = new ResizeObserver((entries) => { + if (this.observerScrollHeightEnable && this.observerScrollHeightCallback) { + this.observerScrollHeightCallback(); + } + }); + isMousePointInSheet = false; + hoverFlag: Flag | undefined | null = undefined; + selectFlag: Flag | undefined | null = undefined; + public timerShaftEL: TimerShaftElement | null | undefined; + private traceSheetEL: TraceSheet | undefined | null; + private rangeSelect!: RangeSelect; + private chartManager: SpChartManager | undefined | null; + private loadTraceCompleted: boolean = false; + private rangeTraceRow: Array> | undefined = []; + canvasFavoritePanel: HTMLCanvasElement | null | undefined; //绘制收藏泳道图 + canvasFavoritePanelCtx: CanvasRenderingContext2D | null | undefined; + canvasPanel: HTMLCanvasElement | null | undefined; //绘制取消收藏后泳道图 + canvasPanelCtx: CanvasRenderingContext2D | undefined | null; + linkNodes: PairPoint[][] = []; + public currentClickRow: HTMLDivElement | undefined | null; + eventMap: any = {}; + private isSelectClick: boolean = false; + private selectionParam: SelectionParam | undefined; + + addPointPair(a: PairPoint, b: PairPoint) { + if (a.rowEL.collect) { + a.rowEL.translateY = a.rowEL.getBoundingClientRect().top - 195; + } else { + a.rowEL.translateY = a.rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + if (b.rowEL.collect) { + b.rowEL.translateY = b.rowEL.getBoundingClientRect().top - 195; + } else { + b.rowEL.translateY = b.rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + a.y = a.rowEL!.translateY! + a.offsetY; + b.y = b.rowEL!.translateY! + b.offsetY; + this.linkNodes.push([a, b]); + } + + clearPointPair() { + this.linkNodes.length = 0; + } + + appendFamilyRelationships(currentRow: TraceRow): string { + let relationships = ''; + if (currentRow.rowParentId !== '') { + let parentRow = this.rowsEL!.querySelector>( + `trace-row[row-id='${currentRow.rowParentId}'][folder]` + ); + if (parentRow) { + relationships = this.appendFamilyRelationships(parentRow) + ':' + parentRow.rowId; + } + } + if (relationships.startsWith(':')) { + return relationships.trim().substring(1); + } + return relationships.trim(); + } + + initElements(): void { + this.rowsEL = this.shadowRoot?.querySelector('.rows'); + this.tipEL = this.shadowRoot?.querySelector('.tip'); + this.rowsPaneEL = this.shadowRoot?.querySelector('.rows-pane'); + this.spacerEL = this.shadowRoot?.querySelector('.spacer'); + this.canvasFavoritePanel = this.shadowRoot?.querySelector('.panel-canvas-favorite'); + this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft'); + this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet'); + this.favoriteRowsEL = this.shadowRoot?.querySelector('.favorite-rows'); + this.rangeSelect = new RangeSelect(this); + document?.addEventListener('triangle-flag', (event: any) => { + let temporaryTime = this.timerShaftEL?.drawTriangle(event.detail.time, event.detail.type); + if (event.detail.timeCallback && temporaryTime) event.detail.timeCallback(temporaryTime); + }); + document?.addEventListener('flag-change', (event: any) => { + this.timerShaftEL?.modifyFlagList(event.detail); + if (event.detail.hidden) { + this.selectFlag = undefined; + this.traceSheetEL?.setAttribute('mode', 'hidden'); + this.refreshCanvas(true); + } + }); + if (this.timerShaftEL?.collecBtn) { + this.timerShaftEL.collecBtn.onclick = () => { + if (this.timerShaftEL!.collecBtn!.hasAttribute('close')) { + this.timerShaftEL!.collecBtn!.removeAttribute('close'); + } else { + this.timerShaftEL!.collecBtn!.setAttribute('close', ''); + } + if (this.collectRows.length > 0) { + this.collectRows.forEach((row) => { + row?.collectEL?.onclick?.(new MouseEvent('auto-collect', undefined)); + }); + } + }; + } + document?.addEventListener('collect', (event: any) => { + let currentRow = event.detail.row; + if (currentRow.collect) { + if ( + !this.collectRows.find((find) => { + return find === currentRow; + }) + ) { + this.collectRows.push(currentRow); + } + if (event.detail.type !== 'auto-collect' && this.timerShaftEL!.collecBtn!.hasAttribute('close')) { + currentRow.collect = false; + this.timerShaftEL!.collecBtn!.click(); + return; + } + let replaceRow = document.createElement('div'); + replaceRow.setAttribute('row-id', currentRow.rowId + '-' + currentRow.rowType); + replaceRow.setAttribute('type', 'replaceRow'); + replaceRow.setAttribute('row-parent-id', currentRow.rowParentId); + replaceRow.style.display = 'none'; + currentRow.rowHidden = !currentRow.hasAttribute('scene'); + currentRow.setAttribute('relationship', this.appendFamilyRelationships(currentRow)); + this.rowsEL!.replaceChild(replaceRow, currentRow); + this.favoriteRowsEL!.append(currentRow); + } else { + this.favoriteRowsEL!.removeChild(currentRow); + if (event.detail.type !== 'auto-collect') { + let rowIndex = this.collectRows.indexOf(currentRow); + if (rowIndex !== -1) { + this.collectRows.splice(rowIndex, 1); + } + } + let relationships = currentRow.getAttribute('relationship'); + relationships.split(':').forEach((relationship: string) => { + let parentRow = this.rowsEL!.querySelector>(`trace-row[row-id='${relationship}'][folder]`); + if (parentRow) { + parentRow.expansion = true; + } + }); + let replaceRow = this.rowsEL!.querySelector( + `div[row-id='${currentRow.rowId}-${currentRow.rowType}']` + ); + if (replaceRow != null) { + this.rowsEL!.replaceChild(currentRow, replaceRow); + currentRow.style.boxShadow = `0 10px 10px #00000000`; + } + this.canvasFavoritePanel!.style.transform = `translateY(${ + this.favoriteRowsEL!.scrollTop - currentRow.clientHeight + }px)`; + } + this.timerShaftEL?.displayCollect(this.collectRows.length !== 0); + this.refreshFavoriteCanvas(); + this.refreshCanvas(true); + this.linkNodes.forEach((itln) => { + if (itln[0].rowEL === currentRow) { + if (itln[0].rowEL.collect) { + itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195; + } else { + itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY; + } else if (itln[1].rowEL === currentRow) { + if (itln[1].rowEL.collect) { + itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195; + } else { + itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY; + } + }); + // 收藏夹元素拖动排序功能 + this.currentClickRow = null; + currentRow.setAttribute('draggable', 'true'); + currentRow.addEventListener('dragstart', () => { + this.currentClickRow = currentRow; + }); + currentRow.addEventListener('dragover', (ev: any) => { + ev.preventDefault(); + ev.dataTransfer.dropEffect = 'move'; + }); + currentRow.addEventListener('drop', (ev: any) => { + if (this.favoriteRowsEL != null && this.currentClickRow != null && this.currentClickRow !== currentRow) { + let rect = currentRow.getBoundingClientRect(); + if (ev.clientY >= rect.top && ev.clientY < rect.top + rect.height / 2) { + //向上移动 + this.favoriteRowsEL.insertBefore(this.currentClickRow, currentRow); + } else if (ev.clientY <= rect.bottom && ev.clientY > rect.top + rect.height / 2) { + //向下移动 + this.favoriteRowsEL.insertBefore(this.currentClickRow, currentRow.nextSibling); + } + this.refreshFavoriteCanvas(); + } + }); + currentRow.addEventListener('dragend', () => { + this.linkNodes.forEach((itln) => { + if (itln[0].rowEL.collect) { + itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195; + } else { + itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + if (itln[1].rowEL.collect) { + itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195; + } else { + itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY; + itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY; + }); + this.currentClickRow = null; + }); + }); + SpSystemTrace.scrollViewWidth = this.getScrollWidth(); + this.rangeSelect.selectHandler = (rows, refreshCheckBox) => { + rows.forEach((item) => { + this.setAttribute('clickRow', item.rowType!); + this.setAttribute('rowName', item.name); + this.setAttribute('rowId', item.rowId!); + }); + if (rows.length == 0) { + this.shadowRoot!.querySelectorAll>('trace-row').forEach((it) => { + it.checkType = '-1'; + if (it.folder) { + it.childrenList.forEach((item) => { + it.checkType = '-1'; + }); + } + }); + this.refreshCanvas(true); + this.traceSheetEL?.setAttribute('mode', 'hidden'); + return; + } + if (refreshCheckBox) { + if (rows.length > 0) { + this.shadowRoot?.querySelectorAll>('trace-row').forEach((row) => { + row.checkType = '0'; + if (row.folder) { + row.childrenList.forEach((ite) => { + ite.checkType = '0'; + }); + } + }); + rows.forEach((it) => { + it.checkType = '2'; + }); + } else { + this.shadowRoot?.querySelectorAll>('trace-row').forEach((row) => { + row.checkType = '-1'; + if (row.folder) { + row.childrenList.forEach((it) => { + it.checkType = '-1'; + }); + } + }); + return; + } + } + if (!this.isSelectClick) { + this.rangeTraceRow = []; + } + let selection = new SelectionParam(); + selection.leftNs = 0; + selection.rightNs = 0; + selection.recordStartNs = (window as any).recordStartNS; + let native_memory = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + rows.forEach((it) => { + if (it.rowType == TraceRow.ROW_TYPE_CPU) { + selection.cpus.push(parseInt(it.rowId!)); + info('load CPU traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_CPU_STATE) { + let filterId = parseInt(it.rowId!); + if (selection.cpuStateFilterIds.indexOf(filterId) == -1) { + selection.cpuStateFilterIds.push(filterId); + } + } else if (it.rowType == TraceRow.ROW_TYPE_CPU_FREQ) { + let filterId = parseInt(it.rowId!); + if (selection.cpuFreqFilterIds.indexOf(filterId) == -1) { + selection.cpuFreqFilterIds.push(filterId); + } + } else if (it.rowType == TraceRow.ROW_TYPE_CPU_FREQ_LIMIT) { + selection.cpuFreqLimitDatas.push(it.dataList!); + } else if (it.rowType == TraceRow.ROW_TYPE_PROCESS) { + let processChildRows: Array> = [ + ...this.shadowRoot!.querySelectorAll>(`trace-row[row-parent-id='${it.rowId}']`), + ]; + if (!it.expansion) { + processChildRows = [...it.childrenList]; + } + processChildRows.forEach((th) => { + th.rangeSelect = true; + th.checkType = '2'; + if (th.rowType == TraceRow.ROW_TYPE_THREAD) { + selection.threadIds.push(parseInt(th.rowId!)); + } else if (th.rowType == TraceRow.ROW_TYPE_FUNC) { + if (th.asyncFuncName) { + selection.funAsync.push({ + name: th.asyncFuncName, + pid: th.asyncFuncNamePID || 0, + }); + } else { + selection.funTids.push(parseInt(th.rowId!)); + } + } else if (th.rowType == TraceRow.ROW_TYPE_MEM) { + selection.processTrackIds.push(parseInt(th.rowId!)); + } + }); + info('load process traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY) { + let memoryRows: Array> = [ + ...this.shadowRoot!.querySelectorAll>(`trace-row[row-parent-id='${it.rowId}']`), + ]; + if (!it.expansion) { + memoryRows = [...it.childrenList]; + } + memoryRows.forEach((th) => { + th.rangeSelect = true; + th.checkType = '2'; + if (th.getAttribute('heap-type') === 'native_hook_statistic') { + selection.nativeMemoryStatistic.push(it.rowId!); + } else { + selection.nativeMemory.push(it.rowId!); + } + }); + info('load nativeMemory traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) { + selection.threadIds.push(parseInt(it.rowId!)); + info('load thread traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) { + if (it.asyncFuncName) { + selection.funAsync.push({ + name: it.asyncFuncName, + pid: it.asyncFuncNamePID || 0, + }); + } else { + selection.funTids.push(parseInt(it.rowId!)); + } + info('load func traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_MEM || it.rowType == TraceRow.ROW_TYPE_VIRTUAL_MEMORY) { + if (it.rowType == TraceRow.ROW_TYPE_MEM) { + selection.processTrackIds.push(parseInt(it.rowId!)); + } else { + selection.virtualTrackIds.push(parseInt(it.rowId!)); + } + info('load memory traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_FPS) { + selection.hasFps = true; + info('load FPS traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_HEAP) { + if (it.getAttribute('heap-type') === 'native_hook_statistic') { + selection.nativeMemoryStatistic.push(it.rowId!); + } else { + selection.nativeMemory.push(it.rowId!); + } + info('load nativeMemory traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_CPU_ABILITY) { + selection.cpuAbilityIds.push(it.rowId!); + info('load CPU Ability traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY) { + selection.memoryAbilityIds.push(it.rowId!); + info('load Memory Ability traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_DISK_ABILITY) { + selection.diskAbilityIds.push(it.rowId!); + info('load DiskIo Ability traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) { + selection.networkAbilityIds.push(it.rowId!); + info('load Network Ability traceRow id is : ', it.rowId); + } else if (it.rowType?.startsWith(TraceRow.ROW_TYPE_SDK)) { + if (it.rowType == TraceRow.ROW_TYPE_SDK) { + let sdkRows: Array> = [ + ...this.shadowRoot!.querySelectorAll>(`trace-row[row-parent-id='${it.rowId}']`), + ]; + if (!it.expansion) { + sdkRows = [...it.childrenList]; + } + sdkRows.forEach((th) => { + th.rangeSelect = true; + th.checkType = '2'; + }); + } + if (it.rowType == TraceRow.ROW_TYPE_SDK_COUNTER) { + selection.sdkCounterIds.push(it.rowId!); + } + if (it.rowType == TraceRow.ROW_TYPE_SDK_SLICE) { + selection.sdkSliceIds.push(it.rowId!); + } + } else if (it.rowType?.startsWith('hiperf')) { + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_EVENT || it.rowType == TraceRow.ROW_TYPE_HIPERF_REPORT) { + return; + } + selection.perfSampleIds.push(1); + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) { + let hiperfProcessRows: Array> = [ + ...this.shadowRoot!.querySelectorAll>(`trace-row[row-parent-id='${it.rowId}']`), + ]; + if (!it.expansion) { + hiperfProcessRows = [...it.childrenList]; + } + hiperfProcessRows.forEach((th) => { + th.rangeSelect = true; + th.checkType = '2'; + }); + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF || it.rowId == 'HiPerf-cpu-merge') { + selection.perfAll = true; + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_CPU) { + selection.perfCpus.push(it.index); + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) { + selection.perfProcess.push(parseInt(it.rowId!.split('-')[0])); + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_THREAD) { + selection.perfThread.push(parseInt(it.rowId!.split('-')[0])); + } + } else if (it.rowType == TraceRow.ROW_TYPE_FILE_SYSTEM) { + if (it.rowId == 'FileSystemLogicalWrite') { + if (selection.fileSystemType.length == 0) { + selection.fileSystemType = [0, 1, 3]; + } else { + if (selection.fileSystemType.indexOf(3) == -1) { + selection.fileSystemType.push(3); + } + } + } else if (it.rowId == 'FileSystemLogicalRead') { + if (selection.fileSystemType.length == 0) { + selection.fileSystemType = [0, 1, 2]; + } else { + if (selection.fileSystemType.indexOf(2) == -1) { + selection.fileSystemType.push(2); + } + } + } else if (it.rowId == 'FileSystemVirtualMemory') { + selection.fileSysVirtualMemory = true; + } else if (it.rowId == 'FileSystemDiskIOLatency') { + selection.diskIOLatency = true; + } else { + if (!selection.diskIOLatency) { + let arr = it.rowId!.split('-').reverse(); + let ipid = parseInt(arr[0]); + if (selection.diskIOipids.indexOf(ipid) == -1) { + selection.diskIOipids.push(ipid); + } + if (arr[1] == 'read') { + selection.diskIOReadIds.indexOf(ipid) == -1 ? selection.diskIOReadIds.push(ipid) : ''; + } else if (arr[1] == 'write') { + selection.diskIOWriteIds.indexOf(ipid) == -1 ? selection.diskIOWriteIds.push(ipid) : ''; + } + } + } + } else if (it.rowType == TraceRow.ROW_TYPE_POWER_ENERGY) { + selection.powerEnergy.push(it.rowId!); + } else if (it.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) { + selection.systemEnergy.push(it.rowId!); + } else if (it.rowType == TraceRow.ROW_TYPE_ANOMALY_ENERGY) { + selection.anomalyEnergy.push(it.rowId!); + } else if (it.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) { + info('load anomaly Energy traceRow id is : ', it.rowId); + } else if (it.rowType == TraceRow.ROW_TYPE_SMAPS) { + selection.smapsType.push(it.rowId!); + } else if (it.rowType == TraceRow.ROW_TYPE_CLOCK) { + selection.clockMapData.set( + it.rowId || '', + it.dataList.filter((clockData) => { + return Utils.getTimeIsCross( + clockData.startNS, + clockData.startNS + clockData.dur, + TraceRow.rangeSelectObject?.startNS || 0, + TraceRow.rangeSelectObject?.endNS || 0 + ); + }) + ); + } else if (it.rowType == TraceRow.ROW_TYPE_IRQ) { + it.dataList.forEach((irqData) => { + if ( + Utils.getTimeIsCross( + irqData.startNS, + irqData.startNS + irqData.dur, + TraceRow.rangeSelectObject?.startNS || 0, + TraceRow.rangeSelectObject?.endNS || 0 + ) + ) { + if (selection.irqMapData.has(irqData.name)) { + selection.irqMapData.get(irqData.name)?.push(irqData); + } else { + selection.irqMapData.set(irqData.name, [irqData]); + } + } + }); + } else if (it.rowType == TraceRow.ROW_TYPE_JANK && it.name == 'Actual Timeline') { + let isIntersect = (a: JanksStruct, b: RangeSelectStruct) => + Math.max(a.ts! + a.dur!, b!.endNS || 0) - Math.min(a.ts!, b!.startNS || 0) < + a.dur! + (b!.endNS || 0) - (b!.startNS || 0); + let jankDatas = it.dataList.filter((jankData: any) => { + return isIntersect(jankData, TraceRow.rangeSelectObject!); + }); + selection.jankFramesData.push(jankDatas); + } else if (it.rowType == TraceRow.ROW_TYPE_HEAP_TIMELINE) { + let endNS = TraceRow.rangeSelectObject?.endNS ? TraceRow.rangeSelectObject?.endNS : TraceRow.range?.endNS; + let startNS = TraceRow.rangeSelectObject?.startNS + ? TraceRow.rangeSelectObject?.startNS + : TraceRow.range?.startNS; + let minNodeId, maxNodeId; + for (let sample of it.dataList) { + if (sample.timestamp_us * 1000 <= startNS!) { + minNodeId = sample.last_assigned_id; + } + if (sample.timestamp_us * 1000 >= endNS!) { + if (maxNodeId == undefined) { + maxNodeId = sample.last_assigned_id; + } + } + } + // If the start time range of the selected box is greater than the end time of the sampled data + if (startNS! >= it.dataList[it.dataList.length - 1].timestamp_us * 1000) { + minNodeId = it.dataList[it.dataList.length - 1].last_assigned_id; + } + // If you select the box from the beginning + if (startNS === TraceRow.range?.startNS) { + minNodeId = HeapDataInterface.getInstance().getMinNodeId(SpJsMemoryChart.file.id); + } + //If you select the box from the ending + if (endNS === TraceRow.range?.endNS) { + maxNodeId = HeapDataInterface.getInstance().getMaxNodeId(SpJsMemoryChart.file.id); + } + let summary = (this.traceSheetEL?.shadowRoot?.querySelector('#tabs') as LitTabs) + ?.querySelector('#box-heap-summary') + ?.querySelector('tabpane-summary') as TabPaneSummary; + summary.initSummaryData(SpJsMemoryChart.file.id, maxNodeId, minNodeId); + selection.jsMemory.push(1); + } + if (this.rangeTraceRow!.length !== rows.length) { + let event = this.createPointEvent(it); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + action: 'trace_row', + event: event, + }); + } + }); + this.rangeTraceRow = rows; + this.isSelectClick = false; + if (selection.diskIOipids.length > 0 && !selection.diskIOLatency) { + selection.promiseList.push( + queryEbpfSamplesCount( + TraceRow.rangeSelectObject?.startNS || 0, + TraceRow.rangeSelectObject?.endNS || 0, + selection.diskIOipids + ).then((res) => { + if (res.length > 0) { + selection.fsCount = res[0].fsCount; + selection.vmCount = res[0].vmCount; + } + return new Promise((resolve) => resolve(1)); + }) + ); + } + selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0; + selection.rightNs = TraceRow.rangeSelectObject?.endNS || 0; + this.selectStructNull(); + this.timerShaftEL?.removeTriangle('inverted'); + if (selection.promiseList.length > 0) { + Promise.all(selection.promiseList).then(() => { + selection.promiseList = []; + this.traceSheetEL?.rangeSelect(selection); + }); + } else { + this.traceSheetEL?.rangeSelect(selection); + } + this.selectionParam = selection; + }; + // @ts-ignore + new ResizeObserver((entries) => { + let width = entries[0].contentRect.width - 1 - SpSystemTrace.scrollViewWidth; + requestAnimationFrame(() => { + this.timerShaftEL?.updateWidth(width); + this.shadowRoot!.querySelectorAll>('trace-row').forEach((it) => { + it.updateWidth(width); + }); + }); + }).observe(this); + + new ResizeObserver((entries) => { + this.canvasPanelConfig(); + if (this.traceSheetEL!.getAttribute('mode') == 'hidden') { + this.timerShaftEL?.removeTriangle('triangle'); + } + this.refreshFavoriteCanvas(); + this.refreshCanvas(true); + }).observe(this.rowsPaneEL!); + new MutationObserver((mutations, observer) => { + for (const mutation of mutations) { + if (mutation.type === 'attributes') { + if (this.style.visibility === 'visible') { + if (TraceRow.rangeSelectObject && SpSystemTrace.sliceRangeMark) { + this.timerShaftEL?.setSlicesMark( + TraceRow.rangeSelectObject.startNS || 0, + TraceRow.rangeSelectObject.endNS || 0 + ); + SpSystemTrace.sliceRangeMark = undefined; + window.publish(window.SmartEvent.UI.RefreshCanvas, {}); + } + } + } + } + }).observe(this, { + attributes: true, + childList: false, + subtree: false, + }); + + this.intersectionObserver = new IntersectionObserver((entries) => { + entries.forEach((it) => { + let tr = it.target as TraceRow; + if (!it.isIntersecting) { + tr.sleeping = true; + this.visibleRows = this.visibleRows.filter((it) => !it.sleeping); + } else { + this.visibleRows.push(tr); + tr.sleeping = false; + } + if (this.handler) clearTimeout(this.handler); + this.handler = setTimeout(() => this.refreshCanvas(false), 100); + }); + }); + window.addEventListener('keydown', (ev) => { + if (ev.key.toLocaleLowerCase() === 'escape') { + this.shadowRoot?.querySelectorAll>('trace-row').forEach((it) => { + it.checkType = '-1'; + }); + TraceRow.rangeSelectObject = undefined; + this.rangeSelect.rangeTraceRow = []; + this.selectStructNull(); + this.timerShaftEL?.setSlicesMark(); + this.traceSheetEL?.setAttribute('mode', 'hidden'); + this.clearPointPair(); + } + }); + this.chartManager = new SpChartManager(this); + this.canvasPanel = this.shadowRoot!.querySelector('#canvas-panel')!; + this.canvasFavoritePanel = this.shadowRoot!.querySelector('#canvas-panel-favorite')!; + this.canvasPanelCtx = this.canvasPanel.getContext('2d'); + + this.canvasFavoritePanelCtx = this.canvasFavoritePanel.getContext('2d'); + this.canvasPanelConfig(); + window.subscribe(window.SmartEvent.UI.SliceMark, (data) => { + this.sliceMarkEventHandler(data); + }); + window.subscribe(window.SmartEvent.UI.TraceRowComplete, (tr) => {}); + window.subscribe(window.SmartEvent.UI.RefreshCanvas, () => { + this.refreshCanvas(false); + }); + window.subscribe(window.SmartEvent.UI.KeyboardEnable, (tr) => { + this.keyboardEnable = tr.enable; + if (!this.keyboardEnable) { + this.stopWASD(); + } + }); + } + + private createPointEvent(it: TraceRow) { + let event = this.eventMap[it.rowType + '']; + if (event) { + return event; + } else { + if (it.rowType === TraceRow.ROW_TYPE_HEAP) { + event = it.name; + } else if (it.rowType === TraceRow.ROW_TYPE_HIPERF_CPU) { + event = 'HiPerf Cpu'; + if (it.rowId === 'HiPerf-cpu-merge') { + event = 'HiPerf'; + } + } else if (it.rowType === TraceRow.ROW_TYPE_FILE_SYSTEM) { + if (it.rowId === 'FileSystemLogicalWrite') { + event = 'FileSystem Logical Write'; + } else if (it.rowId === 'FileSystemLogicalRead') { + event = 'FileSystem Logical Read'; + } else if (it.rowId === 'FileSystemVirtualMemory') { + event = 'Page Fault Trace'; + } else if (it.rowId!.startsWith('FileSystemDiskIOLatency')) { + event = 'Disk I/O Latency'; + if (it.rowId!.startsWith('FileSystemDiskIOLatency-')) { + event = 'Bio Process'; + } + } + } else if (it.rowType === TraceRow.ROW_TYPE_STATE_ENERGY) { + event = it.name; + } else if (it.rowType === TraceRow.ROW_TYPE_SMAPS) { + if (it.rowParentId === '') { + event = 'VM Tracker'; + } else { + event = it.name; + } + } else if (it.rowType === TraceRow.ROW_TYPE_JANK) { + if (it.rowId === 'frameTime' || it.rowParentId === 'frameTime') { + event = 'FrameTimeLine'; + } else if (it.hasAttribute('frame_type')) { + event = it.getAttribute('frame_type') + ''; + } + } else if (it.rowType === TraceRow.ROW_TYPE_DELIVER_INPUT_EVENT) { + event = 'DeliverInputEvent'; + if (it.rowParentId === TraceRow.ROW_TYPE_DELIVER_INPUT_EVENT) { + event = 'DeliverInputEvent Func'; + } + } else { + event = it.name; + } + return event; + } + } + + refreshFavoriteCanvas() { + let collectList = this.favoriteRowsEL?.querySelectorAll>(`trace-row[collect-type]`) || []; + let height = 0; + collectList.forEach((row, index) => { + height += row.offsetHeight; + if (index == collectList.length - 1) { + row.style.boxShadow = `0 10px 10px #00000044`; + } else { + row.style.boxShadow = `0 10px 10px #00000000`; + } + }); + if (height > this.rowsPaneEL!.offsetHeight) { + this.favoriteRowsEL!.style.height = this.rowsPaneEL!.offsetHeight + 'px'; + } else { + this.favoriteRowsEL!.style.height = height + 'px'; + } + this.favoriteRowsEL!.style.width = this.canvasPanel?.offsetWidth + 'px'; + this.spacerEL!.style.height = height + 'px'; + this.canvasFavoritePanel!.style.height = this.favoriteRowsEL!.style.height; + this.canvasFavoritePanel!.style.width = this.canvasPanel?.offsetWidth + 'px'; + this.canvasFavoritePanel!.width = this.canvasFavoritePanel!.offsetWidth * dpr(); + this.canvasFavoritePanel!.height = this.canvasFavoritePanel!.offsetHeight * dpr(); + this.canvasFavoritePanel!.getContext('2d')!.scale(dpr(), dpr()); + } + + expansionAllParentRow(currentRow: TraceRow) { + let parentRow = this.rowsEL!.querySelector>( + `trace-row[row-id='${currentRow.rowParentId}'][folder][scene]` + ); + if (parentRow) { + parentRow.expansion = true; + if (this.rowsEL!.querySelector>(`trace-row[row-id='${parentRow.rowParentId}'][folder]`)) { + this.expansionAllParentRow(parentRow); + } + } + } + + canvasPanelConfig() { + this.canvasPanel!.style.left = `${this.timerShaftEL!.canvas!.offsetLeft!}px`; + this.canvasPanel!.width = this.canvasPanel!.offsetWidth * dpr(); + this.canvasPanel!.height = this.canvasPanel!.offsetHeight * dpr(); + this.canvasPanelCtx!.scale(dpr(), dpr()); + + this.canvasFavoritePanel!.style.left = `${this.timerShaftEL!.canvas!.offsetLeft!}px`; + this.canvasFavoritePanel!.width = this.canvasFavoritePanel!.offsetWidth * dpr(); + this.canvasFavoritePanel!.height = this.canvasFavoritePanel!.offsetHeight * dpr(); + this.canvasFavoritePanelCtx!.scale(dpr(), dpr()); + } + + getScrollWidth() { + let totalScrollDiv, + scrollDiv, + overflowDiv = document.createElement('div'); + overflowDiv.style.cssText = 'position:absolute; top:-2000px;width:200px; height:200px; overflow:hidden;'; + totalScrollDiv = document.body.appendChild(overflowDiv).clientWidth; + overflowDiv.style.overflowY = 'scroll'; + scrollDiv = overflowDiv.clientWidth; + document.body.removeChild(overflowDiv); + return totalScrollDiv - scrollDiv; + } + + timerShaftELFlagClickHandler = (flag: Flag | undefined | null) => { + if (flag) { + setTimeout(() => { + this.traceSheetEL?.displayFlagData(flag); + }, 100); + } + }; + + timerShaftELFlagChange = (hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => { + this.hoverFlag = hoverFlag; + this.selectFlag = selectFlag; + this.refreshCanvas(true, 'flagChange'); + }; + + timerShaftELRangeChange = (e: any) => { + TraceRow.range = e; + if (TraceRow.rangeSelectObject) { + TraceRow.rangeSelectObject!.startX = Math.floor( + ns2x( + TraceRow.rangeSelectObject!.startNS!, + TraceRow.range?.startNS!, + TraceRow.range?.endNS!, + TraceRow.range?.totalNS!, + this.timerShaftEL!.sportRuler!.frame + ) + ); + TraceRow.rangeSelectObject!.endX = Math.floor( + ns2x( + TraceRow.rangeSelectObject!.endNS!, + TraceRow.range?.startNS!, + TraceRow.range?.endNS!, + TraceRow.range?.totalNS!, + this.timerShaftEL!.sportRuler!.frame + ) + ); + } + //在rowsEL显示范围内的 trace-row组件将收到时间区间变化通知 + this.linkNodes.forEach((it) => { + it[0].x = ns2xByTimeShaft(it[0].ns, this.timerShaftEL!); + it[1].x = ns2xByTimeShaft(it[1].ns, this.timerShaftEL!); + }); + this.refreshCanvas(false, 'rangeChange'); + }; + tim: number = -1; + top: number = 0; + handler: any = undefined; + rowsElOnScroll = (e: any) => { + this.linkNodes.forEach((itln) => { + if (itln[0].rowEL.collect) { + itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195; + } else { + itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + if (itln[1].rowEL.collect) { + itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195; + } else { + itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - this.rowsPaneEL!.scrollTop; + } + itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY; + itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY; + }); + if (this.scrollTimer) { + clearTimeout(this.scrollTimer); + } + this.scrollTimer = setTimeout(() => { + TraceRow.range!.refresh = true; + requestAnimationFrame(() => this.refreshCanvas(false)); + }, 200); + requestAnimationFrame(() => this.refreshCanvas(false)); + }; + + private scrollTimer: any; + + favoriteRowsElOnScroll = (e: any) => { + this.rowsElOnScroll(e); + }; + + offset = 147; + + getRowsContentHeight(): number { + return [...this.rowsEL!.querySelectorAll>(`trace-row:not([sleeping])`)] + .map((it) => it.clientHeight) + .reduce((acr, cur) => acr + cur, 0); + } + + // refresh main canvas and favorite canvas + refreshCanvas(cache: boolean, from?: string) { + if (this.visibleRows.length == 0) { + return; + } + //clear main canvas + this.canvasPanelCtx?.clearRect(0, 0, this.canvasPanel!.offsetWidth, this.canvasPanel!.offsetHeight); + //clear favorite canvas + this.canvasFavoritePanelCtx?.clearRect( + 0, + 0, + this.canvasFavoritePanel!.offsetWidth, + this.canvasFavoritePanel!.offsetHeight + ); + //draw lines for main canvas + let rowsContentHeight = this.getRowsContentHeight(); + let canvasHeight = + rowsContentHeight > this.canvasPanel!.clientHeight ? this.canvasPanel!.clientHeight : rowsContentHeight; + canvasHeight += this.canvasFavoritePanel!.clientHeight; + drawLines(this.canvasPanelCtx!, TraceRow.range?.xs || [], canvasHeight, this.timerShaftEL!.lineColor()); + //draw lines for favorite canvas + drawLines( + this.canvasFavoritePanelCtx!, + TraceRow.range?.xs || [], + this.canvasFavoritePanel!.clientHeight, + this.timerShaftEL!.lineColor() + ); + //canvas translate + this.canvasPanel!.style.transform = `translateY(${this.rowsPaneEL!.scrollTop}px)`; + this.canvasFavoritePanel!.style.transform = `translateY(${this.favoriteRowsEL!.scrollTop}px)`; + //draw trace row + this.visibleRows.forEach((v, i) => { + if (v.collect) { + v.translateY = v.getBoundingClientRect().top - 195; + } else { + v.translateY = v.offsetTop - this.rowsPaneEL!.scrollTop; + } + v.draw(cache); + }); + //draw flag line segment for canvas + drawFlagLineSegment(this.canvasPanelCtx, this.hoverFlag, this.selectFlag, { + x: 0, + y: 0, + width: this.timerShaftEL?.canvas?.clientWidth, + height: this.canvasPanel?.clientHeight, + }); + //draw flag line segment for favorite canvas + drawFlagLineSegment(this.canvasFavoritePanelCtx, this.hoverFlag, this.selectFlag, { + x: 0, + y: 0, + width: this.timerShaftEL?.canvas?.clientWidth, + height: this.canvasFavoritePanel?.clientHeight, + }); + //draw wakeup for main canvas + drawWakeUp( + this.canvasPanelCtx, + CpuStruct.wakeupBean, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + { + x: 0, + y: 0, + width: this.timerShaftEL!.canvas!.clientWidth, + height: this.canvasPanel!.clientHeight!, + } as Rect + ); + //draw wakeup for favorite canvas + drawWakeUp( + this.canvasFavoritePanelCtx, + CpuStruct.wakeupBean, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + { + x: 0, + y: 0, + width: this.timerShaftEL!.canvas!.clientWidth, + height: this.canvasFavoritePanel!.clientHeight!, + } as Rect + ); + // Draw the connection curve + if (this.linkNodes) { + drawLinkLines(this.canvasPanelCtx!, this.linkNodes, this.timerShaftEL!, false); + drawLinkLines(this.canvasFavoritePanelCtx!, this.linkNodes, this.timerShaftEL!, true); + } + } + + documentOnMouseDown = (ev: MouseEvent) => { + if (!this.loadTraceCompleted) return; + if (this.isWASDKeyPress()) { + ev.preventDefault(); + ev.stopPropagation(); + return; + } + TraceRow.isUserInteraction = true; + if (this.isMouseInSheet(ev)) return; + this.observerScrollHeightEnable = false; + if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) { + let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft; + let y = ev.offsetY; + this.timerShaftEL?.documentOnMouseDown(ev); + if ( + this.timerShaftEL!.sportRuler!.frame.contains(x, y) && + x > (TraceRow.rangeSelectObject?.startX || 0) && + x < (TraceRow.rangeSelectObject?.endX || 0) + ) { + let time = Math.round( + (x * (TraceRow.range?.endNS! - TraceRow.range?.startNS!)) / this.timerShaftEL!.canvas!.offsetWidth + + TraceRow.range?.startNS! + ); + this.timerShaftEL!.sportRuler!.drawTriangle(time, 'triangle'); + } else { + this.rangeSelect.mouseDown(ev); + this.rangeSelect.drag = true; + } + } else { + this.rangeSelect.drag = false; + } + }; + + onContextMenuHandler = (e: Event) => { + setTimeout(() => { + for (let key of this.keyPressMap.keys()) { + if (this.keyPressMap.get(key)) { + this.timerShaftEL?.stopWASD({ key: key }); + this.keyPressMap.set(key, false); + } + } + }, 100); + }; + + documentOnMouseUp = (ev: MouseEvent) => { + if (!this.loadTraceCompleted) return; + if (this.isWASDKeyPress()) { + ev.preventDefault(); + ev.stopPropagation(); + return; + } + TraceRow.isUserInteraction = false; + this.rangeSelect.isMouseDown = false; + if ((window as any).isSheetMove) return; + if (this.isMouseInSheet(ev)) return; + let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft; + let y = ev.offsetY; + if ( + this.timerShaftEL!.sportRuler!.frame.contains(x, y) && + x > (TraceRow.rangeSelectObject?.startX || 0) && + x < (TraceRow.rangeSelectObject?.endX || 0) + ) { + } else { + this.rangeSelect.mouseUp(ev); + this.timerShaftEL?.documentOnMouseUp(ev); + } + ev.preventDefault(); + ev.stopPropagation(); + }; + + documentOnMouseOut = (ev: MouseEvent) => { + if (!this.loadTraceCompleted) return; + TraceRow.isUserInteraction = false; + if (this.isMouseInSheet(ev)) return; + if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) { + this.rangeSelect.mouseOut(ev); + this.timerShaftEL?.documentOnMouseOut(ev); + } + }; + + private keyPressMap: Map = new Map([ + ['w', false], + ['s', false], + ['a', false], + ['d', false], + ]); + documentOnKeyPress = (ev: KeyboardEvent) => { + if (!this.loadTraceCompleted) return; + let keyPress = ev.key.toLocaleLowerCase(); + TraceRow.isUserInteraction = true; + if (this.isMousePointInSheet) { + return; + } + this.observerScrollHeightEnable = false; + if (this.keyboardEnable) { + if (keyPress == 'm') { + this.setSLiceMark(); + } + let keyPressWASD = keyPress === 'w' || keyPress === 'a' || keyPress === 's' || keyPress === 'd'; + if (keyPressWASD) { + this.keyPressMap.set(keyPress, true); + this.hoverFlag = null; + } + this.timerShaftEL!.documentOnKeyPress(ev); + } else { + this.stopWASD(); + } + }; + + setSLiceMark() { + if (CpuStruct.selectCpuStruct) { + this.timerShaftEL?.setSlicesMark( + CpuStruct.selectCpuStruct.startTime || 0, + (CpuStruct.selectCpuStruct.startTime || 0) + (CpuStruct.selectCpuStruct.dur || 0) + ); + } else if (ThreadStruct.selectThreadStruct) { + this.timerShaftEL?.setSlicesMark( + ThreadStruct.selectThreadStruct.startTime || 0, + (ThreadStruct.selectThreadStruct.startTime || 0) + (ThreadStruct.selectThreadStruct.dur || 0) + ); + } else if (FuncStruct.selectFuncStruct) { + this.timerShaftEL?.setSlicesMark( + FuncStruct.selectFuncStruct.startTs || 0, + (FuncStruct.selectFuncStruct.startTs || 0) + (FuncStruct.selectFuncStruct.dur || 0) + ); + } else if (IrqStruct.selectIrqStruct) { + this.timerShaftEL?.setSlicesMark( + IrqStruct.selectIrqStruct.startNS || 0, + (IrqStruct.selectIrqStruct.startNS || 0) + (IrqStruct.selectIrqStruct.dur || 0) + ); + } else if (TraceRow.rangeSelectObject) { + this.timerShaftEL?.setSlicesMark(TraceRow.rangeSelectObject.startNS || 0, TraceRow.rangeSelectObject.endNS || 0); + } else if (JankStruct.selectJankStruct) { + this.timerShaftEL?.setSlicesMark( + JankStruct.selectJankStruct.ts || 0, + (JankStruct.selectJankStruct.ts || 0) + (JankStruct.selectJankStruct.dur || 0) + ); + } else { + this.timerShaftEL?.setSlicesMark(); + } + } + + stopWASD = () => { + setTimeout(() => { + for (let key of this.keyPressMap.keys()) { + if (this.keyPressMap.get(key)) { + this.timerShaftEL?.stopWASD({ key: key }); + this.keyPressMap.set(key, false); + } + } + }, 100); + }; + + documentOnKeyUp = (ev: KeyboardEvent) => { + if (!this.loadTraceCompleted) return; + let keyPress = ev.key.toLocaleLowerCase(); + if (keyPress === 'w' || keyPress === 'a' || keyPress === 's' || keyPress === 'd') { + this.keyPressMap.set(keyPress, false); + } + TraceRow.isUserInteraction = false; + this.observerScrollHeightEnable = false; + this.keyboardEnable && this.timerShaftEL!.documentOnKeyUp(ev); + if (ev.code == 'Enter') { + if (ev.shiftKey) { + this.dispatchEvent( + new CustomEvent('previous-data', { + detail: {}, + composed: false, + }) + ); + } else { + this.dispatchEvent( + new CustomEvent('next-data', { + detail: {}, + composed: false, + }) + ); + } + } + }; + + isMouseInSheet = (ev: MouseEvent) => { + this.isMousePointInSheet = + this.traceSheetEL?.getAttribute('mode') != 'hidden' && + ev.offsetX > this.traceSheetEL!.offsetLeft && + ev.offsetY > this.traceSheetEL!.offsetTop; + return this.isMousePointInSheet; + }; + + favoriteChangeHandler = (row: TraceRow) => { + info('favoriteChangeHandler', row.frame, row.offsetTop, row.offsetHeight); + }; + + selectChangeHandler = (rows: Array>) => { + this.isSelectClick = true; + this.rangeSelect.rangeTraceRow = rows; + let changeTraceRows: Array> = []; + if (this.rangeTraceRow!.length < rows.length) { + rows!.forEach((currentTraceRow: TraceRow) => { + let changeFilter = this.rangeTraceRow!.filter( + (prevTraceRow: TraceRow) => prevTraceRow === currentTraceRow + ); + if (changeFilter.length < 1) { + changeTraceRows.push(currentTraceRow); + } + }); + if (changeTraceRows.length > 0) { + changeTraceRows!.forEach((changeTraceRow: TraceRow) => { + let pointEvent = this.createPointEvent(changeTraceRow); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + action: 'trace_row', + event: pointEvent, + }); + }); + } + } + this.rangeTraceRow = rows; + console.log('-------', this.rangeSelect.rangeTraceRow); + this.rangeSelect.selectHandler?.(this.rangeSelect.rangeTraceRow, false); + }; + inFavoriteArea: boolean | undefined; + documentOnMouseMove = (ev: MouseEvent) => { + if (!this.loadTraceCompleted || (window as any).flagInputFocus) return; + if (this.isWASDKeyPress()) { + this.hoverFlag = null; + ev.preventDefault(); + return; + } + this.inFavoriteArea = this.favoriteRowsEL?.containPoint(ev); + if ((window as any).isSheetMove) return; + if (this.isMouseInSheet(ev)) { + this.hoverStructNull(); + return; + } + let isMouseInTimeShaft = this.timerShaftEL?.containPoint(ev); + if (isMouseInTimeShaft) { + this.tipEL!.style.display = 'none'; + this.hoverStructNull(); + } + let rows = this.visibleRows; + if (this.timerShaftEL?.isScaling()) { + return; + } + this.timerShaftEL?.documentOnMouseMove(ev); + if (isMouseInTimeShaft) { + return; + } + this.rangeSelect.mouseMove(rows, ev); + if (this.rangeSelect.isMouseDown) { + this.refreshCanvas(true); + } else { + if (!this.rowsPaneEL!.containPoint(ev, { left: 248 })) { + this.tipEL!.style.display = 'none'; + this.hoverStructNull(); + } + rows + .filter((it) => it.focusContain(ev) && it.collect === this.inFavoriteArea) + .filter((it) => { + if (it.collect) { + return true; + } else { + return ( + it.getBoundingClientRect().bottom + it.getBoundingClientRect().height > + this.favoriteRowsEL!.getBoundingClientRect().bottom + ); + } + }) + .forEach((tr) => { + if (this.currentRowType != tr.rowType) { + this.hoverStructNull(); + this.tipEL!.style.display = 'none'; + this.currentRowType = tr.rowType || ''; + } + if (tr.rowType == TraceRow.ROW_TYPE_CPU) { + CpuStruct.hoverCpuStruct = undefined; + for (let re of tr.dataListCache) { + if (re.frame && isFrameContainPoint(re.frame, tr.hoverX, tr.hoverY)) { + CpuStruct.hoverCpuStruct = re; + break; + } + } + } else { + CpuStruct.hoverCpuStruct = undefined; + } + tr.focusHandler?.(ev); + }); + requestAnimationFrame(() => this.refreshCanvas(true)); + } + }; + + hoverStructNull() { + CpuStruct.hoverCpuStruct = undefined; + CpuFreqStruct.hoverCpuFreqStruct = undefined; + ThreadStruct.hoverThreadStruct = undefined; + FuncStruct.hoverFuncStruct = undefined; + HiPerfCpuStruct.hoverStruct = undefined; + HiPerfProcessStruct.hoverStruct = undefined; + HiPerfThreadStruct.hoverStruct = undefined; + HiPerfEventStruct.hoverStruct = undefined; + HiPerfReportStruct.hoverStruct = undefined; + CpuStateStruct.hoverStateStruct = undefined; + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = undefined; + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = undefined; + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = undefined; + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = undefined; + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined; + FpsStruct.hoverFpsStruct = undefined; + ClockStruct.hoverClockStruct = undefined; + IrqStruct.hoverIrqStruct = undefined; + HeapStruct.hoverHeapStruct = undefined; + JankStruct.hoverJankStruct = undefined; + HeapSnapshotStruct.hoverSnapshotStruct = undefined; + } + + selectStructNull() { + CpuStruct.selectCpuStruct = undefined; + CpuStruct.wakeupBean = null; + CpuFreqStruct.selectCpuFreqStruct = undefined; + ThreadStruct.selectThreadStruct = undefined; + FuncStruct.selectFuncStruct = undefined; + SpHiPerf.selectCpuStruct = undefined; + CpuStateStruct.selectStateStruct = undefined; + CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = undefined; + ClockStruct.selectClockStruct = undefined; + IrqStruct.selectIrqStruct = undefined; + JankStruct.selectJankStruct = undefined; + HeapStruct.selectHeapStruct = undefined; + HeapSnapshotStruct.selectSnapshotStruct = undefined; + } + + isWASDKeyPress() { + return ( + this.keyPressMap.get('w') || this.keyPressMap.get('a') || this.keyPressMap.get('d') || this.keyPressMap.get('s') + ); + } + + documentOnClick = (ev: MouseEvent) => { + if (!this.loadTraceCompleted) return; + if (this.isWASDKeyPress()) { + this.hoverFlag = null; + ev.preventDefault(); + ev.stopPropagation(); + return; + } + if ((window as any).isSheetMove) return; + if (this.isMouseInSheet(ev)) return; + if ((window as any).isPackUpTable) { + (window as any).isPackUpTable = false; + return; + } + let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft; + let y = ev.offsetY; + if (this.timerShaftEL?.getRangeRuler()?.frame.contains(x, y)) { + this.clickEmptyArea(); + return; + } + if (this.rangeSelect.isDrag()) { + return; + } + if ( + this.timerShaftEL!.sportRuler!.frame.contains(x, y) && + x > (TraceRow.rangeSelectObject?.startX || 0) && + x < (TraceRow.rangeSelectObject?.endX || 0) + ) { + } else { + let inFavoriteArea = this.favoriteRowsEL?.containPoint(ev); + let rows = this.visibleRows.filter((it) => it.focusContain(ev) && it.collect == inFavoriteArea); + if (rows.length != 0) { + this.clearPointPair(); + } + if (rows && rows[0] && this.traceRowClickJudgmentConditions.get(rows[0]!.rowType!)?.()) { + this.onClickHandler(rows[0]!.rowType!, rows[0]); + this.documentOnMouseMove(ev); + } else { + this.clickEmptyArea(); + } + } + ev.preventDefault(); + }; + + clickEmptyArea() { + this.shadowRoot?.querySelectorAll>('trace-row').forEach((it) => { + it.checkType = '-1'; + it.rangeSelect = false; + }); + this.rangeSelect.rangeTraceRow = []; + TraceRow.rangeSelectObject = undefined; + this.selectStructNull(); + this.observerScrollHeightEnable = false; + this.selectFlag = null; + this.timerShaftEL?.removeTriangle('inverted'); + this.traceSheetEL?.setAttribute('mode', 'hidden'); + this.refreshCanvas(true); + } + + //泳道图点击判定条件 + private traceRowClickJudgmentConditions: Map boolean> = new Map boolean>([ + [TraceRow.ROW_TYPE_CPU, () => CpuStruct.hoverCpuStruct !== null && CpuStruct.hoverCpuStruct !== undefined], + [ + TraceRow.ROW_TYPE_THREAD, + () => ThreadStruct.hoverThreadStruct !== null && ThreadStruct.hoverThreadStruct !== undefined, + ], + [TraceRow.ROW_TYPE_FUNC, () => FuncStruct.hoverFuncStruct !== null && FuncStruct.hoverFuncStruct !== undefined], + [ + TraceRow.ROW_TYPE_CPU_FREQ, + () => CpuFreqStruct.hoverCpuFreqStruct !== null && CpuFreqStruct.hoverCpuFreqStruct !== undefined, + ], + [ + TraceRow.ROW_TYPE_CPU_STATE, + () => CpuStateStruct.hoverStateStruct !== null && CpuStateStruct.hoverStateStruct !== undefined, + ], + [ + TraceRow.ROW_TYPE_CPU_FREQ_LIMIT, + () => + CpuFreqLimitsStruct.selectCpuFreqLimitsStruct !== null && + CpuFreqLimitsStruct.selectCpuFreqLimitsStruct !== undefined, + ], + [ + TraceRow.ROW_TYPE_CLOCK, + () => ClockStruct.hoverClockStruct !== null && ClockStruct.hoverClockStruct !== undefined, + ], + [TraceRow.ROW_TYPE_IRQ, () => IrqStruct.hoverIrqStruct !== null && IrqStruct.hoverIrqStruct !== undefined], + [TraceRow.ROW_TYPE_JANK, () => JankStruct.hoverJankStruct !== null && JankStruct.hoverJankStruct !== undefined], + [TraceRow.ROW_TYPE_HEAP, () => HeapStruct.hoverHeapStruct !== null && HeapStruct.hoverHeapStruct !== undefined], + [ + TraceRow.ROW_TYPE_HEAP_SNAPSHOT, + () => HeapSnapshotStruct.hoverSnapshotStruct !== null && HeapSnapshotStruct.hoverSnapshotStruct !== undefined, + ], + ]); + + onClickHandler(clickRowType: string, row?: TraceRow) { + if (row) { + this.setAttribute('clickRow', clickRowType); + this.setAttribute('rowName', row.name!); + this.setAttribute('rowId', row.rowId!); + } + if (!this.loadTraceCompleted) return; + this.shadowRoot?.querySelectorAll>('trace-row').forEach((it) => (it.rangeSelect = false)); + this.selectStructNull(); + let threadClickHandler: any; + let cpuClickHandler: any; + let jankClickHandler: any; + let snapshotClickHandler: any; + threadClickHandler = (d: ThreadStruct) => { + this.observerScrollHeightEnable = false; + this.scrollToProcess(`${d.cpu}`, '', 'cpu-data', true); + let cpuRow = this.shadowRoot?.querySelectorAll>( + `trace-row[row-id='${d.cpu}'][row-type='cpu-data']` + )[0]; + let findEntry = cpuRow!.dataList!.find((dat: any) => dat.startTime === d.startTime); + if ( + findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || + findEntry!.startTime! > TraceRow.range!.endNS + ) { + this.timerShaftEL?.setRangeNS( + findEntry!.startTime! - findEntry!.dur! * 2, + findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2 + ); + } + this.hoverStructNull(); + this.selectStructNull(); + CpuStruct.hoverCpuStruct = findEntry; + CpuStruct.selectCpuStruct = findEntry; + this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, 'inverted'); + this.traceSheetEL?.displayCpuData( + CpuStruct.selectCpuStruct!, + (wakeUpBean) => { + CpuStruct.wakeupBean = wakeUpBean; + this.refreshCanvas(true); + }, + cpuClickHandler + ); + }; + + cpuClickHandler = (d: CpuStruct) => { + let traceRow = this.shadowRoot?.querySelector>(`trace-row[row-id='${d.processId}']`); + if (traceRow) { + traceRow.expansion = true; + } + this.observerScrollHeightEnable = true; + let threadRow = this.shadowRoot?.querySelectorAll>( + `trace-row[row-id='${d.tid}'][row-type='thread']` + )[0]; + let task = () => { + if (threadRow) { + let findEntry = threadRow!.dataList!.find((dat) => dat.startTime === d.startTime); + if ( + findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || + findEntry!.startTime! > TraceRow.range!.endNS + ) { + this.timerShaftEL?.setRangeNS( + findEntry!.startTime! - findEntry!.dur! * 2, + findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2 + ); + } + this.hoverStructNull(); + this.selectStructNull(); + ThreadStruct.hoverThreadStruct = findEntry; + ThreadStruct.selectThreadStruct = findEntry; + this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, 'inverted'); + this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler, cpuClickHandler); + this.scrollToProcess(`${d.tid}`, `${d.processId}`, 'thread', true); + } + }; + if (threadRow) { + this.scrollToProcess(`${d.tid}`, `${d.processId}`, 'process', false); + this.scrollToProcess(`${d.tid}`, `${d.processId}`, 'thread', true); + if (threadRow!.isComplete) { + task(); + } else { + threadRow!.onComplete = task; + } + } + }; + + jankClickHandler = (d: any) => { + this.observerScrollHeightEnable = true; + let jankRowParent: any; + if (d.rowId === 'actual frameTime') { + jankRowParent = this.shadowRoot?.querySelector>(`trace-row[row-id='frameTime']`); + } else { + jankRowParent = this.shadowRoot?.querySelector>(`trace-row[row-id='${d.pid}']`); + } + // jankRowParent!.expansion = true; + let jankRow: any; + jankRowParent.childrenList.forEach((item: TraceRow) => { + if (item.rowId === `${d.rowId}` && item.rowType === 'janks') { + jankRow = item; + } + }); + let task = () => { + if (jankRow) { + JankStruct.selectJankStructList.length = 0; + let findJankEntry = jankRow!.dataList!.find((dat: any) => dat.name == d.name && dat.pid == d.pid); + if (findJankEntry) { + if ( + findJankEntry!.ts! + findJankEntry!.dur! < TraceRow.range!.startNS || + findJankEntry!.ts! > TraceRow.range!.endNS + ) { + this.timerShaftEL?.setRangeNS( + findJankEntry!.ts! - findJankEntry!.dur! * 2, + findJankEntry!.ts! + findJankEntry!.dur! + findJankEntry!.dur! * 2 + ); + } + this.hoverStructNull(); + this.selectStructNull(); + JankStruct.hoverJankStruct = findJankEntry; + JankStruct.selectJankStruct = findJankEntry; + this.timerShaftEL?.drawTriangle(findJankEntry!.ts || 0, 'inverted'); + this.traceSheetEL?.displayJankData( + JankStruct.selectJankStruct!, + (datas) => { + this.clearPointPair(); + // 绘制跟自己关联的线 + datas.forEach((data) => { + let endParentRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='${data.pid}'][folder]` + ); + this.drawJankLine(endParentRow, JankStruct.selectJankStruct!, data); + }); + }, + jankClickHandler + ); + } + this.scrollToProcess(jankRow.rowId!, jankRow.rowParentId!, jankRow.rowType!, true); + } + }; + if (jankRow) { + this.scrollToProcess(jankRow.rowId!, jankRow.rowParentId!, jankRow.rowType!, false); + } + task(); + }; + + snapshotClickHandler = (d: HeapSnapshotStruct) => { + this.observerScrollHeightEnable = true; + let snapshotRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='heap_snapshot']` + ); + let task = () => { + if (snapshotRow) { + let findEntry = snapshotRow!.dataList!.find((dat) => dat.start_time === d.start_time); + this.hoverStructNull(); + this.selectStructNull(); + HeapSnapshotStruct.hoverSnapshotStruct = findEntry; + HeapSnapshotStruct.selectSnapshotStruct = findEntry; + } + }; + if (snapshotRow) { + if (snapshotRow!.isComplete) { + task(); + } else { + snapshotRow!.onComplete = task; + } + } + }; + if (clickRowType === TraceRow.ROW_TYPE_CPU && CpuStruct.hoverCpuStruct) { + CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct; + this.timerShaftEL?.drawTriangle(CpuStruct.selectCpuStruct!.startTime || 0, 'inverted'); + this.traceSheetEL?.displayCpuData( + CpuStruct.selectCpuStruct, + (wakeUpBean) => { + CpuStruct.wakeupBean = wakeUpBean; + this.refreshCanvas(false); + }, + cpuClickHandler + ); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_THREAD && ThreadStruct.hoverThreadStruct) { + ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct; + this.timerShaftEL?.drawTriangle(ThreadStruct.selectThreadStruct!.startTime || 0, 'inverted'); + this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct, threadClickHandler, cpuClickHandler); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_FUNC && FuncStruct.hoverFuncStruct) { + FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct; + let hoverFuncStruct = FuncStruct.hoverFuncStruct; + this.timerShaftEL?.drawTriangle(FuncStruct.selectFuncStruct!.startTs || 0, 'inverted'); + FuncStruct.selectFuncStruct = hoverFuncStruct; + this.traceSheetEL?.displayFuncData(FuncStruct.selectFuncStruct, (funcStract: any) => { + this.observerScrollHeightEnable = true; + this.moveRangeToCenter(funcStract.startTime!, funcStract.dur!); + this.scrollToActFunc(funcStract, false); + }); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_CPU_FREQ && CpuFreqStruct.hoverCpuFreqStruct) { + CpuFreqStruct.selectCpuFreqStruct = CpuFreqStruct.hoverCpuFreqStruct; + this.traceSheetEL?.displayFreqData(); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_CPU_STATE && CpuStateStruct.hoverStateStruct) { + CpuStateStruct.selectStateStruct = CpuStateStruct.hoverStateStruct; + this.traceSheetEL?.displayCpuStateData(); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_CPU_FREQ_LIMIT && CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct) { + CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct; + this.traceSheetEL?.displayFreqLimitData(); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_CLOCK && ClockStruct.hoverClockStruct) { + ClockStruct.selectClockStruct = ClockStruct.hoverClockStruct; + this.traceSheetEL?.displayClockData(ClockStruct.selectClockStruct); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_IRQ && IrqStruct.hoverIrqStruct) { + IrqStruct.selectIrqStruct = IrqStruct.hoverIrqStruct; + this.traceSheetEL?.displayIrqData(IrqStruct.selectIrqStruct); + this.timerShaftEL?.modifyFlagList(undefined); + } else if ( + clickRowType === TraceRow.ROW_TYPE_HEAP && + row && + row.getAttribute('heap-type') === 'native_hook_statistic' && + HeapStruct.hoverHeapStruct + ) { + HeapStruct.selectHeapStruct = HeapStruct.hoverHeapStruct; + this.traceSheetEL?.displayNativeHookData(HeapStruct.selectHeapStruct, row.rowId!); + this.timerShaftEL?.modifyFlagList(undefined); + } else if (clickRowType === TraceRow.ROW_TYPE_JANK && JankStruct.hoverJankStruct) { + JankStruct.selectJankStructList.length = 0; + this.clearPointPair(); + JankStruct.selectJankStruct = JankStruct.hoverJankStruct; + this.timerShaftEL?.drawTriangle(JankStruct.selectJankStruct!.ts || 0, 'inverted'); + this.traceSheetEL?.displayJankData( + JankStruct.selectJankStruct, + (datas) => { + datas.forEach((data) => { + let endParentRow; + if (data.frame_type == 'frameTime') { + endParentRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='frameTime'][row-type='janks']` + ); + } else { + endParentRow = this.shadowRoot?.querySelector>(`trace-row[row-id='${data.pid}'][folder]`); + } + this.drawJankLine(endParentRow, JankStruct.selectJankStruct!, data); + }); + }, + jankClickHandler + ); + } else if (clickRowType === TraceRow.ROW_TYPE_HEAP_SNAPSHOT && HeapSnapshotStruct.hoverSnapshotStruct) { + let snapshotRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='heap_snapshot']` + ); + HeapSnapshotStruct.selectSnapshotStruct = HeapSnapshotStruct.hoverSnapshotStruct; + this.traceSheetEL?.displaySnapshotData( + HeapSnapshotStruct.selectSnapshotStruct!, + snapshotRow!.dataList, + snapshotClickHandler + ); + } else { + if (!JankStruct.hoverJankStruct && JankStruct.delJankLineFlag) { + this.clearPointPair(); + } + this.observerScrollHeightEnable = false; + this.selectFlag = null; + this.timerShaftEL?.removeTriangle('inverted'); + if (!SportRuler.isMouseInSportRuler) { + this.traceSheetEL?.setAttribute('mode', 'hidden'); + this.refreshCanvas(true); + } + } + if (!JankStruct.selectJankStruct) { + this.clearPointPair(); + } + if (row) { + let pointEvent = this.createPointEvent(row); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + action: 'trace_row', + event: pointEvent, + }); + } + } + + drawJankLine(endParentRow: any, selectJankStruct: JankStruct, data: any) { + let startRow: any; + if (selectJankStruct == undefined || selectJankStruct == null) { + return; + } + if (selectJankStruct.frame_type == 'frameTime') { + startRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='actual frameTime'][row-type='janks']` + ); + } else { + startRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='${selectJankStruct?.type + '-' + selectJankStruct?.pid}'][row-type='janks']` + ); + } + if (endParentRow) { + //终点的父泳道过滤出选中的Struct + let endRowStruct: any; + //泳道展开的情况,查找endRowStruct + if (data.frame_type == 'frameTime') { + endRowStruct = this.shadowRoot?.querySelector>( + `trace-row[row-id='actual frameTime'][row-type='janks']` + ); + } else { + endRowStruct = this.shadowRoot?.querySelector>( + `trace-row[row-id='${data.type + '-' + data.pid}'][row-type='janks']` + ); + } + //泳道未展开的情况,查找endRowStruct + if (!endRowStruct) { + if (data.frame_type == 'frameTime') { + endParentRow.childrenList.forEach((item: TraceRow) => { + if (item.rowId === 'actual frameTime' && item.rowType === 'janks') { + endRowStruct = item; + } + }); + //frameTime未展开 + if (!endRowStruct) { + endParentRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='frameTime'][folder]` + ); + endParentRow.childrenList.forEach((item: TraceRow) => { + if (item.rowId === 'actual frameTime' && item.rowType === 'janks') { + endRowStruct = item; + } + }); + } + } else { + endParentRow.childrenList.forEach((item: TraceRow) => { + if (item.rowId === data.type + '-' + data.pid && item.rowType === 'janks') { + endRowStruct = item; + } + }); + } + } + if (endRowStruct) { + let findJankEntry = endRowStruct!.dataList!.find((dat: any) => dat.name == data.name && dat.pid == data.pid); + //连线规则:frametimeline的头----app的头,app的尾----renderservice的头 + let tts: number = 0; + if (findJankEntry) { + if (selectJankStruct.frame_type == 'app') { + tts = + findJankEntry.frame_type == 'frameTime' + ? selectJankStruct.ts! + : selectJankStruct.ts! + selectJankStruct.dur!; + let startParentRow: any; + // startRow为子泳道,子泳道不存在,使用父泳道 + if (startRow) { + startParentRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='${startRow.rowParentId}'][folder]` + ); + } else { + startRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='${selectJankStruct?.pid}'][folder]` + ); + } + let endY = endRowStruct!.translateY! + 20 * (findJankEntry!.depth! + 0.5); + let endRowEl = endRowStruct; + let endOffSetY = 20 * (findJankEntry!.depth! + 0.5); + if (!endParentRow.expansion) { + endY = endParentRow!.translateY! + 10 * (findJankEntry!.depth! + 0.5); + endRowEl = endParentRow; + endOffSetY = 10 * (findJankEntry!.depth! + 0.5); + } + let startY = startRow!.translateY! + 20 * (selectJankStruct!.depth! + 0.5); + let startRowEl = startRow; + let startOffSetY = 20 * (selectJankStruct!.depth! + 0.5); + if (startParentRow && !startParentRow.expansion) { + startY = startParentRow!.translateY! + 10 * (selectJankStruct!.depth! + 0.5); + startRowEl = startParentRow; + startOffSetY = 10 * (selectJankStruct!.depth! + 0.5); + } + this.addPointPair( + { + x: ns2xByTimeShaft(tts, this.timerShaftEL!), + y: startY, + offsetY: startOffSetY, + ns: tts, + rowEL: startRowEl!, + isRight: selectJankStruct.ts == tts, + }, + { + x: ns2xByTimeShaft(findJankEntry.ts!, this.timerShaftEL!), + y: endY, + offsetY: endOffSetY, + ns: findJankEntry.ts!, + rowEL: endRowEl, + isRight: true, + } + ); + } + if (findJankEntry.frame_type == 'app') { + tts = + selectJankStruct.frame_type == 'frameTime' ? findJankEntry.ts : findJankEntry.ts! + findJankEntry.dur!; + let endY = endRowStruct!.translateY! + 20 * (findJankEntry!.depth! + 0.5); + let endRowEl = endRowStruct; + let endOffSetY = 20 * (findJankEntry!.depth! + 0.5); + if (!endParentRow.expansion) { + endY = endParentRow!.translateY! + 10 * (findJankEntry!.depth! + 0.5); + endRowEl = endParentRow; + endOffSetY = 10 * (findJankEntry!.depth! + 0.5); + } + let startY = startRow!.translateY! + 20 * (selectJankStruct!.depth! + 0.5); + let startRowEl = startRow; + let startOffsetY = 20 * (selectJankStruct!.depth! + 0.5); + let startParentRow = this.shadowRoot?.querySelector>( + `trace-row[row-id='${startRow.rowParentId}'][folder]` + ); + if (startParentRow && !startParentRow.expansion) { + startY = startParentRow!.translateY! + 10 * (selectJankStruct!.depth! + 0.5); + startRowEl = startParentRow; + startOffsetY = 10 * (selectJankStruct!.depth! + 0.5); + } + this.addPointPair( + { + x: ns2xByTimeShaft(selectJankStruct.ts!, this.timerShaftEL!), + y: startY, + offsetY: startOffsetY, + ns: selectJankStruct.ts!, + rowEL: startRowEl!, + isRight: true, + }, + { + x: ns2xByTimeShaft(tts, this.timerShaftEL!), + y: endY, + offsetY: endOffSetY, + ns: tts, + rowEL: endRowEl!, + isRight: selectJankStruct.ts == tts, + } + ); + } + if (data.children.length >= 1) { + let endP; + if (data.children[0].frame_type == 'frameTime') { + endP = this.shadowRoot?.querySelector>(`trace-row[row-id='frameTime']`); + } else { + endP = this.shadowRoot?.querySelector>( + `trace-row[row-id='${data.children[0].pid}'][folder]` + ); + } + this.drawJankLine(endP, findJankEntry, data.children[0]); + } + this.refreshCanvas(true); + } + } + } + } + + connectedCallback() { + this.initPointToEvent(); + /** + * 监听时间轴区间变化 + */ + this.timerShaftEL!.rangeChangeHandler = this.timerShaftELRangeChange; + this.timerShaftEL!.flagChangeHandler = this.timerShaftELFlagChange; + this.timerShaftEL!.flagClickHandler = this.timerShaftELFlagClickHandler; + /** + * 监听rowsEL的滚动时间,刷新可见区域的trace-row组件的时间区间(将触发trace-row组件重绘) + */ + this.rowsPaneEL?.addEventListener('scroll', this.rowsElOnScroll, { + passive: true, + }); + this.favoriteRowsEL?.addEventListener('scroll', this.favoriteRowsElOnScroll, { passive: true }); + /** + * 监听document的mousemove事件 坐标通过换算后找到当前鼠标所在的trace-row组件,将坐标传入 + */ + this.addEventListener('mousemove', this.documentOnMouseMove); + this.addEventListener('click', this.documentOnClick); + this.addEventListener('mousedown', this.documentOnMouseDown); + this.addEventListener('mouseup', this.documentOnMouseUp); + this.addEventListener('mouseout', this.documentOnMouseOut); + + document.addEventListener('keypress', this.documentOnKeyPress); + document.addEventListener('keyup', this.documentOnKeyUp); + document.addEventListener('contextmenu', this.onContextMenuHandler); + + /** + * 获取并保存鼠标当前的x轴坐标位置,配合ctrl+鼠标左键拖动完成泳道图的左移或右移 + */ + this.addEventListener( + 'mousedown', + (e) => { + if (e.ctrlKey) { + e.preventDefault(); + this.removeEventListener('mousemove', this.documentOnMouseMove); + this.removeEventListener('click', this.documentOnClick); + this.removeEventListener('mousedown', this.documentOnMouseDown); + this.removeEventListener('mouseup', this.documentOnMouseUp); + this.style.cursor = 'move'; + SpSystemTrace.moveable = true; + SpSystemTrace.mouseCurrentPosition = e.clientX; + } + }, + { passive: false } + ); + + /** + * ctrl+鼠标移动,实现泳道图左移或者右移。 + */ + this.addEventListener( + 'mousemove', + (e) => { + if (e.ctrlKey) { + e.preventDefault(); + SpSystemTrace.offsetMouse = e.clientX - SpSystemTrace.mouseCurrentPosition; + let eventA = new KeyboardEvent('keypress', { + key: 'a', + code: '65', + keyCode: 65, + }); + let eventD = new KeyboardEvent('keypress', { + key: 'd', + code: '68', + keyCode: 68, + }); + if (e.button == 0) { + if (SpSystemTrace.offsetMouse < 0 && SpSystemTrace.moveable) { + // 向右拖动,则泳道图右移 + this.timerShaftEL!.documentOnKeyPress(eventD); + setTimeout(() => { + this.timerShaftEL!.documentOnKeyUp(eventD); + }, 350); + } + if (SpSystemTrace.offsetMouse > 0 && SpSystemTrace.moveable) { + // 向左拖动,则泳道图左移 + this.timerShaftEL!.documentOnKeyPress(eventA); + setTimeout(() => { + this.timerShaftEL!.documentOnKeyUp(eventA); + }, 350); + } + } + SpSystemTrace.moveable = false; + } + }, + { passive: false } + ); + + this.addEventListener( + 'mouseup', + (e) => { + if (e.ctrlKey) { + e.preventDefault(); + SpSystemTrace.offsetMouse = 0; + SpSystemTrace.mouseCurrentPosition = 0; + SpSystemTrace.moveable = false; + this.style.cursor = 'default'; + this.addEventListener('mousemove', this.documentOnMouseMove); + this.addEventListener('click', this.documentOnClick); + this.addEventListener('mousedown', this.documentOnMouseDown); + this.addEventListener('mouseup', this.documentOnMouseUp); + } + }, + { passive: false } + ); + + /** + * 泳道图中添加ctrl+鼠标滚轮事件,对泳道图进行放大缩小。 + * 鼠标滚轮事件转化为键盘事件,keyPress和keyUp两个事件需要配合使用, + * 否则泳道图会一直放大或一直缩小。 + * setTimeout()函数中的时间参数可以控制鼠标滚轮的频率。 + */ + document.addEventListener( + 'wheel', + (e) => { + if (e.ctrlKey) { + if (e.deltaY > 0) { + e.preventDefault(); + e.stopPropagation(); + let eventS = new KeyboardEvent('keypress', { + key: 's', + code: '83', + keyCode: 83, + }); + this.timerShaftEL!.documentOnKeyPress(eventS); + setTimeout(() => { + this.timerShaftEL!.documentOnKeyUp(eventS); + }, 200); + } + if (e.deltaY < 0) { + e.preventDefault(); + e.stopPropagation(); + let eventW = new KeyboardEvent('keypress', { + key: 'w', + code: '87', + keyCode: 87, + }); + this.timerShaftEL!.documentOnKeyPress(eventW); + setTimeout(() => { + this.timerShaftEL!.documentOnKeyUp(eventW); + }, 200); + } + } + }, + { passive: false } + ); + + SpApplication.skinChange2 = (val: boolean) => { + this.timerShaftEL?.render(); + }; + window.subscribe(window.SmartEvent.UI.UploadSOFile, (data) => { + this.chartManager?.importSoFileUpdate().then(() => { + window.publish(window.SmartEvent.UI.Loading, false); + if ( + this.selectionParam && + (this.selectionParam.nativeMemory.length > 0 || + this.selectionParam.nativeMemoryStatistic.length > 0 || + this.selectionParam.perfSampleIds.length > 0 || + this.selectionParam.fileSystemType.length > 0 || + this.selectionParam.fsCount > 0 || + this.selectionParam.fileSysVirtualMemory || + this.selectionParam.vmCount > 0 || + this.selectionParam.diskIOLatency || + this.selectionParam.diskIOipids.length > 0) + ) { + this.refreshCanvas(true); + let param: SelectionParam = new SelectionParam(); + Object.assign(param, this.selectionParam); + this.traceSheetEL?.rangeSelect(param); + } + }); + }); + } + + scrollToProcess(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true) { + let rootRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`); + if (rootRow?.collect) { + this.favoriteRowsEL!.scroll({ + top: (rootRow?.offsetTop || 0) - this.canvasFavoritePanel!.offsetHeight + (rootRow?.offsetHeight || 0), + left: 0, + behavior: smooth ? 'smooth' : undefined, + }); + } else { + let row = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowParentId}'][folder]`); + if (row) { + row.expansion = true; + } + this.rowsPaneEL!.scroll({ + top: (rootRow?.offsetTop || 0) - this.canvasPanel!.offsetHeight + (rootRow?.offsetHeight || 0), + left: 0, + behavior: smooth ? 'smooth' : undefined, + }); + } + } + + scrollToDepth(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true, depth: number) { + let rootRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`); + if (rootRow && rootRow!.collect) { + this.favoriteRowsEL!.scroll({ + top: (rootRow?.offsetTop || 0) - this.canvasFavoritePanel!.offsetHeight + (++depth * 20 || 0), + left: 0, + behavior: smooth ? 'smooth' : undefined, + }); + } else { + let row = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowParentId}'][folder]`); + if (row) { + row.expansion = true; + } + this.rowsPaneEL!.scroll({ + top: (rootRow?.offsetTop || 0) - this.canvasPanel!.offsetHeight + (++depth * 20 || 0), + left: 0, + behavior: smooth ? 'smooth' : undefined, + }); + } + } + + scrollToFunction(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true, afterScroll: any) { + let row = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowParentId}'][folder]`); + if (row) { + row.expansion = true; + } + let funcRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`); + if (funcRow == null) { + let threadRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='thread']`); + this.rowsPaneEL!.scroll({ + top: threadRow!.offsetTop - this.canvasPanel!.offsetHeight + threadRow!.offsetHeight + threadRow!.offsetHeight, + left: 0, + behavior: undefined, + }); + if (threadRow != null) { + if (threadRow.isComplete) { + afterScroll(); + } else { + threadRow.onComplete = () => { + funcRow = this.shadowRoot!.querySelector>( + `trace-row[row-id='${rowId}'][row-type='${rowType}']` + ); + afterScroll(); + }; + } + } + } else { + afterScroll(); + } + } + + rowScrollTo(offset: number, callback: Function) { + const fixedOffset = offset; + const onScroll = () => { + if (this.rowsPaneEL!.scrollTop === fixedOffset) { + this.rowsEL!.removeEventListener('scroll', onScroll); + callback(); + } + }; + + this.rowsEL!.addEventListener('scroll', onScroll); + onScroll(); + this.rowsPaneEL!.scrollTo({ + top: offset, + behavior: 'smooth', + }); + } + + disconnectedCallback() { + this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange); + this.rowsPaneEL?.removeEventListener('scroll', this.rowsElOnScroll); + this.favoriteRowsEL?.removeEventListener('scroll', this.favoriteRowsElOnScroll); + this.removeEventListener('mousemove', this.documentOnMouseMove); + this.removeEventListener('click', this.documentOnClick); + this.removeEventListener('mousedown', this.documentOnMouseDown); + this.removeEventListener('mouseup', this.documentOnMouseUp); + this.removeEventListener('mouseout', this.documentOnMouseOut); + document.removeEventListener('keypress', this.documentOnKeyPress); + document.removeEventListener('keyup', this.documentOnKeyUp); + document.removeEventListener('contextmenu', this.onContextMenuHandler); + window.unsubscribe(window.SmartEvent.UI.SliceMark, this.sliceMarkEventHandler.bind(this)); + } + + sliceMarkEventHandler(ev: any) { + SpSystemTrace.sliceRangeMark = ev; + let startNS = ev.timestamp - (window as any).recordStartNS; + let endNS = ev.maxDuration + startNS; + TraceRow.rangeSelectObject = { + startX: 0, + startNS: startNS, + endNS: endNS, + endX: 0, + }; + window.publish(window.SmartEvent.UI.MenuTrace, {}); + window.publish(window.SmartEvent.UI.TimeRange, { + startNS: startNS - ev.maxDuration, + endNS: endNS + ev.maxDuration, + }); + this.shadowRoot?.querySelectorAll>('trace-row').forEach((it) => { + it.checkType = '-1'; + }); + this.rangeSelect.rangeTraceRow = []; + this.selectStructNull(); + this.traceSheetEL?.setAttribute('mode', 'hidden'); + this.clearPointPair(); + TraceRow.range!.refresh = true; + this.refreshCanvas(false); + } + + loadDatabaseUrl( + url: string, + progress: Function, + complete?: ((res: { status: boolean; msg: string }) => void) | undefined + ) { + this.observerScrollHeightEnable = false; + this.init({ url: url }, '', progress).then((res) => { + if (complete) { + complete(res); + } + }); + } + + loadDatabaseArrayBuffer( + buf: ArrayBuffer, + thirdPartyWasmConfigUrl: string, + progress: (name: string, percent: number) => void, + complete?: ((res: { status: boolean; msg: string }) => void) | undefined + ) { + this.observerScrollHeightEnable = false; + this.init({ buf }, thirdPartyWasmConfigUrl, progress).then((res) => { + let scrollTop = this.rowsEL?.scrollTop || 0; + let scrollHeight = this.rowsEL?.clientHeight || 0; + this.rowsEL?.querySelectorAll('trace-row').forEach((it: any) => this.observer.observe(it)); + if (complete) { + complete(res); + } + }); + } + + search(query: string) { + this.shadowRoot?.querySelectorAll>('trace-row').forEach((item) => { + if (query == null || query == undefined || query == '') { + if ( + item.rowType == TraceRow.ROW_TYPE_CPU || + item.rowType == TraceRow.ROW_TYPE_CPU_FREQ || + item.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY || + item.rowType == TraceRow.ROW_TYPE_FPS || + item.rowType == TraceRow.ROW_TYPE_PROCESS || + item.rowType == TraceRow.ROW_TYPE_CPU_ABILITY || + item.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY || + item.rowType == TraceRow.ROW_TYPE_DISK_ABILITY || + item.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY + ) { + item.expansion = false; + item.rowHidden = false; + } else { + item.rowHidden = true; + } + } else { + if (item.name.toLowerCase().indexOf(query.toLowerCase()) >= 0) { + item.rowHidden = false; + } else { + item.rowHidden = true; + } + } + }); + this.visibleRows.forEach((it) => (it.rowHidden = false && it.draw(true))); + } + + searchCPU(query: string): Array { + let traceRow = this.shadowRoot!.querySelector>(`trace-row[scene]`); + let dataAll = `trace-row[row-type='cpu-data']`; + if (traceRow) { + dataAll = `trace-row[row-type='cpu-data'][scene]`; + } + let searchResults: Array = []; + this.shadowRoot!.querySelectorAll>(`${dataAll}`).forEach((item) => { + let res = item!.dataList!.filter( + (it) => + (it.name && it.name.indexOf(query) >= 0) || + it.tid == query || + it.processId == query || + (it.processName && it.processName.indexOf(query) >= 0) + ); + searchResults.push(...res); + }); + searchResults.sort((a, b) => (a.startTime || 0) - (b.startTime || 0)); + return searchResults; + } + + async searchFunction(cpuList: Array, query: string): Promise> { + let processList: Array = []; + let traceRow = this.shadowRoot!.querySelector>(`trace-row[scene]`); + if (traceRow) { + this.shadowRoot!.querySelectorAll>(`trace-row[row-type='process'][scene]`).forEach((row) => { + processList.push(row.rowId!); + }); + let list = await querySceneSearchFunc(query, processList); + cpuList = cpuList.concat(list); + cpuList.sort((a, b) => (a.startTime || 0) - (b.startTime || 0)); + return cpuList; + } else { + let list = await querySearchFunc(query); + cpuList = cpuList.concat(list); + cpuList.sort((a, b) => (a.startTime || 0) - (b.startTime || 0)); + return cpuList; + } + } + + searchSdk(dataList: Array, query: string): Array { + let traceRow = this.shadowRoot!.querySelector>(`trace-row[scene]`); + let dataAll = `trace-row[row-type^='sdk']`; + if (traceRow) { + dataAll = `trace-row[row-type^='sdk'][scene]`; + } + let allTraceRow: any = []; + let parentRows = this.shadowRoot!.querySelectorAll>(`${dataAll}`); + parentRows.forEach((parentRow: TraceRow) => { + allTraceRow.push(parentRow); + if (parentRow.childrenList && parentRow.childrenList.length > 0) { + allTraceRow.push(...parentRow.childrenList); + } + }); + allTraceRow.forEach((row: any) => { + if (row!.name.indexOf(query) >= 0) { + let searchSdkBean = new SearchSdkBean(); + searchSdkBean.startTime = TraceRow.range!.startNS; + searchSdkBean.dur = TraceRow.range!.totalNS; + searchSdkBean.name = row.name; + searchSdkBean.rowId = row.rowId; + searchSdkBean.type = 'sdk'; + searchSdkBean.rowType = row.rowType; + searchSdkBean.rowParentId = row.rowParentId; + dataList.push(searchSdkBean); + } + }); + return dataList; + } + + searchThreadsAndProcesses(query: string): Array { + let searchResults: Array = []; + this.rowsEL!.querySelectorAll>(`trace-row[row-type='thread'][row-type='process']`).forEach((item) => { + if (item!.name.indexOf(query) >= 0) { + let searchBean = new SearchThreadProcessBean(); + searchBean.name = item.name; + searchBean.rowId = item.rowId; + searchBean.type = 'thread||process'; + searchBean.rowType = item.rowType; + searchBean.rowParentId = item.rowParentId; + searchResults.push(searchBean); + } + }); + return searchResults; + } + + showStruct(previous: boolean, currentIndex: number, structs: Array) { + if (structs.length == 0) { + return 0; + } + let findIndex = -1; + if (previous) { + for (let i = structs.length - 1; i >= 0; i--) { + let it = structs[i]; + if ( + i < currentIndex && + it.startTime! >= TraceRow.range!.startNS && + it.startTime! + it.dur! <= TraceRow.range!.endNS + ) { + findIndex = i; + break; + } + } + } else { + findIndex = structs.findIndex((it, idx) => { + return ( + idx > currentIndex && + it.startTime! >= TraceRow.range!.startNS && + it.startTime! + it.dur! <= TraceRow.range!.endNS + ); + }); + } + let findEntry: any; + if (findIndex >= 0) { + findEntry = structs[findIndex]; + } else { + if (previous) { + for (let i = structs.length - 1; i >= 0; i--) { + let it = structs[i]; + if (it.startTime! + it.dur! < TraceRow.range!.startNS) { + findIndex = i; + break; + } + } + if (findIndex == -1) { + findIndex = structs.length - 1; + } + } else { + findIndex = structs.findIndex((it) => it.startTime! > TraceRow.range!.endNS); + if (findIndex == -1) { + findIndex = 0; + } + } + findEntry = structs[findIndex]; + } + this.moveRangeToCenter(findEntry.startTime!, findEntry.dur!); + this.shadowRoot!.querySelectorAll>(`trace-row`).forEach((item) => { + item.highlight = false; + }); + if (findEntry.type == 'thread') { + CpuStruct.selectCpuStruct = findEntry; + CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; + this.shadowRoot!.querySelectorAll>(`trace-row[row-type='cpu-data']`).forEach((item) => { + item.highlight = item.rowId == `${findEntry.cpu}`; + item.draw(true); + }); + this.scrollToProcess(`${findEntry.cpu}`, '', 'cpu-data', true); + this.onClickHandler(TraceRow.ROW_TYPE_CPU); + } else if (findEntry.type == 'func') { + this.observerScrollHeightEnable = true; + this.scrollToActFunc(findEntry, true); + } else if (findEntry.type == 'thread||process') { + let threadProcessRow = this.rowsEL?.querySelectorAll>('trace-row')[0]; + if (threadProcessRow) { + let filterRow = threadProcessRow.childrenList.filter( + (row) => row.rowId === findEntry.rowId && row.rowId === findEntry.rowType + )[0]; + filterRow!.highlight = true; + this.closeAllExpandRows(findEntry.rowParentId); + this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); + let completeEntry = () => { + let searchEntry = filterRow!.dataList!.find((dat) => dat.startTime === findEntry.startTime); + this.hoverStructNull(); + this.selectStructNull(); + ThreadStruct.hoverThreadStruct = searchEntry; + ThreadStruct.selectThreadStruct = searchEntry; + this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); + }; + if (filterRow!.isComplete) { + completeEntry(); + } else { + filterRow!.onComplete = completeEntry; + } + } + } else if (findEntry.type == 'sdk') { + let parentRow = this.shadowRoot!.querySelector>(`trace-row[row-type='sdk'][folder]`); + if (parentRow) { + let sdkRow = parentRow.childrenList.filter( + (child) => child.rowId === findEntry.rowId && child.rowType === findEntry.rowType + )[0]; + sdkRow!.highlight = true; + } + this.hoverStructNull(); + this.selectStructNull(); + this.onClickHandler(findEntry.rowType!); + this.closeAllExpandRows(findEntry.rowParentId); + this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); + } + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted'); + return findIndex; + } + + scrollToActFunc(funcStract: any, highlight: boolean) { + let funcRowID = funcStract.cookie == null ? funcStract.tid : `${funcStract.funName}-${funcStract.pid}`; + let parentRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${funcStract.pid}'][folder]`); + if (!parentRow) { + return; + } + let filterRow = parentRow.childrenList.filter((child) => child.rowId == funcRowID && child.rowType == 'func')[0]; + if (filterRow == null) return; + filterRow!.highlight = highlight; + this.closeAllExpandRows(funcStract.pid); + let row = this.shadowRoot!.querySelector>(`trace-row[row-id='${funcStract.pid}'][folder]`); + if (row && !row.expansion) { + row.expansion = true; + } + if (funcStract.cookie == null) { + this.scrollToProcess(`${funcStract.tid}`, `${funcStract.pid}`, 'thread', false); + } + this.scrollToDepth(`${funcRowID}`, `${funcStract.pid}`, funcStract.type, true, funcStract.depth || 0); + let completeEntry = () => { + let searchEntry = filterRow!.dataList!.find((dat) => dat.startTs === funcStract.startTime); + this.hoverStructNull(); + this.selectStructNull(); + FuncStruct.hoverFuncStruct = searchEntry; + FuncStruct.selectFuncStruct = searchEntry; + this.onClickHandler(TraceRow.ROW_TYPE_FUNC); + this.scrollToDepth(`${funcRowID}`, `${funcStract.pid}`, funcStract.type, true, funcStract.depth || 0); + }; + if (filterRow!.isComplete) { + completeEntry(); + } else { + filterRow!.onComplete = completeEntry; + } + } + + closeAllExpandRows(pid: string) { + let expandRows = this.rowsEL?.querySelectorAll>(`trace-row[row-type='process'][expansion]`); + expandRows?.forEach((row) => { + if (row.rowId != pid) { + row.expansion = false; + } + }); + } + + moveRangeToCenter(startTime: number, dur: number) { + let startNS = this.timerShaftEL?.getRange()?.startNS || 0; + let endNS = this.timerShaftEL?.getRange()?.endNS || 0; + let harfDur = Math.trunc((endNS - startNS) / 2 - dur / 2); + let leftNs = startTime - harfDur; + let rightNs = startTime + dur + harfDur; + if (startTime - harfDur < 0) { + leftNs = 0; + rightNs += harfDur - startTime; + } + this.timerShaftEL?.setRangeNS(leftNs, rightNs); + TraceRow.range!.refresh = true; + this.refreshCanvas(true); + } + + showPreCpuStruct(currentIndex: number, cpuStructs: Array): number { + if (cpuStructs.length == 0) { + return 0; + } + let findIndex = -1; + for (let i = cpuStructs.length - 1; i >= 0; i--) { + let it = cpuStructs[i]; + if ( + i < currentIndex && + it.startTime! >= TraceRow.range!.startNS && + it.startTime! + it.dur! <= TraceRow.range!.endNS + ) { + findIndex = i; + break; + } + } + if (findIndex >= 0) { + let findEntry = cpuStructs[findIndex]; + CpuStruct.selectCpuStruct = findEntry; + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu-data']`).forEach((item) => { + item.highlight = item.rowId == `${findEntry.cpu}`; + item.draw(true); + }); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted'); + } else { + for (let i = cpuStructs.length - 1; i >= 0; i--) { + let it = cpuStructs[i]; + if (it.startTime! + it.dur! < TraceRow.range!.startNS) { + findIndex = i; + break; + } + } + let findEntry: CpuStruct; + if (findIndex == -1) { + findIndex = cpuStructs.length - 1; + } + findEntry = cpuStructs[findIndex]; + CpuStruct.selectCpuStruct = findEntry; + let startNS = this.timerShaftEL?.getRange()?.startNS || 0; + let endNS = this.timerShaftEL?.getRange()?.endNS || 0; + let harfDur = Math.trunc((endNS - startNS) / 2 - findEntry.dur! / 2); + this.timerShaftEL?.setRangeNS(findEntry.startTime! - harfDur, findEntry.startTime! + findEntry.dur! + harfDur); + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu-data']`).forEach((item) => { + item.highlight = item.rowId == `${findEntry.cpu}`; + item.draw(true); + }); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted'); + } + CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; + this.onClickHandler(TraceRow.ROW_TYPE_CPU); + return findIndex; + } + + showNextCpuStruct(currentIndex: number, cpuStructs: Array): number { + if (cpuStructs.length == 0) { + return 0; + } + let findIndex = cpuStructs.findIndex((it, idx) => { + return ( + idx > currentIndex && + it.startTime! >= TraceRow.range!.startNS && + it.startTime! + it.dur! <= TraceRow.range!.endNS + ); + }); + if (findIndex >= 0) { + let findEntry = cpuStructs[findIndex]; + CpuStruct.selectCpuStruct = findEntry; + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu-data']`).forEach((item) => { + item.highlight = item.rowId == `${findEntry.cpu}`; + item.draw(true); + }); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted'); + } else { + findIndex = cpuStructs.findIndex((it) => it.startTime! > TraceRow.range!.endNS); + let findEntry: CpuStruct; + if (findIndex == -1) { + findIndex = 0; + } + findEntry = cpuStructs[findIndex]; + CpuStruct.selectCpuStruct = findEntry; + let startNS = this.timerShaftEL?.getRange()?.startNS || 0; + let endNS = this.timerShaftEL?.getRange()?.endNS || 0; + let harfDur = Math.trunc((endNS - startNS) / 2 - findEntry.dur! / 2); + this.timerShaftEL?.setRangeNS(findEntry.startTime! - harfDur, findEntry.startTime! + findEntry.dur! + harfDur); + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu-data']`).forEach((item) => { + item.highlight = item.rowId == `${findEntry.cpu}`; + item.draw(true); + }); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, 'inverted'); + } + CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; + this.onClickHandler(TraceRow.ROW_TYPE_CPU); + return findIndex; + } + + reset(progress: Function | undefined | null) { + this.visibleRows.length = 0; + this.tipEL!.style.display = 'none'; + this.canvasPanelCtx?.clearRect(0, 0, this.canvasPanel!.clientWidth, this.canvasPanel!.offsetHeight); + this.canvasFavoritePanelCtx?.clearRect( + 0, + 0, + this.canvasFavoritePanel!.clientWidth, + this.canvasFavoritePanel!.clientHeight + ); + this.favoriteRowsEL!.style.height = '0'; + this.canvasFavoritePanel!.style.height = '0'; + this.loadTraceCompleted = false; + if (this.favoriteRowsEL) { + this.favoriteRowsEL.querySelectorAll(`trace-row`).forEach((row) => { + this.favoriteRowsEL!.removeChild(row); + }); + } + if (this.rowsEL) this.rowsEL.innerHTML = ''; + this.spacerEL!.style.height = '0px'; + this.rangeSelect.rangeTraceRow = []; + this.collectRows = []; + this.timerShaftEL?.displayCollect(false); + this.timerShaftEL!.collecBtn!.removeAttribute('close'); + CpuStruct.wakeupBean = undefined; + this.selectStructNull(); + this.hoverStructNull(); + this.traceSheetEL?.setAttribute('mode', 'hidden'); + progress && progress('rest timershaft', 8); + this.timerShaftEL?.reset(); + progress && progress('clear cache', 10); + procedurePool.clearCache(); + } + + init = async (param: { buf?: ArrayBuffer; url?: string }, wasmConfigUri: string, progress: Function) => { + progress('Load database', 6); + this.rowsPaneEL!.scroll({ + top: 0, + left: 0, + }); + this.reset(progress); + if (param.buf) { + let configJson = ''; + try { + configJson = await fetch(wasmConfigUri).then((res) => res.text()); + } catch (e) { + error('getWasmConfigFailed', e); + } + let { status, msg, sdkConfigMap } = await threadPool.initSqlite(param.buf, configJson, progress); + if (!status) { + return { status: false, msg: msg }; + } + SpSystemTrace.SDK_CONFIG_MAP = sdkConfigMap == undefined ? undefined : sdkConfigMap; + } + if (param.url) { + let { status, msg } = await threadPool.initServer(param.url, progress); + if (!status) { + return { status: false, msg: msg }; + } + } + await this.chartManager?.init(progress); + this.rowsEL?.querySelectorAll>('trace-row').forEach((it: any) => { + it.addEventListener('expansion-change', this.extracted(it)); + }); + progress('completed', 100); + info('All TraceRow Data initialized'); + this.loadTraceCompleted = true; + this.rowsEL!.querySelectorAll>('trace-row').forEach((it) => { + this.intersectionObserver?.observe(it); + }); + return { status: true, msg: 'success' }; + }; + + private extracted(it: any) { + return () => { + if (it.hasAttribute('expansion')) { + this.shadowRoot?.querySelectorAll(`[row-parent-id='${it.rowId}']`).forEach((child) => { + if (child.folder) { + child.addEventListener('expansion-change', this.extracted(child)); + } + this.intersectionObserver?.observe(child); + }); + } else { + this.shadowRoot?.querySelectorAll(`[row-parent-id='${it.rowId}']`).forEach((child) => { + this.intersectionObserver?.unobserve(child); + }); + } + this.refreshCanvas(false); + }; + } + + displayTip(row: TraceRow, struct: any, html: string) { + let x = row.hoverX + 248; + let y = row.getBoundingClientRect().top - 195 + (this.rowsPaneEL?.scrollTop ?? 0); + if ((struct == undefined || struct == null) && this.tipEL) { + this.tipEL.style.display = 'none'; + return; + } + if (this.tipEL) { + this.tipEL.innerHTML = html; + this.tipEL.style.display = 'flex'; + this.tipEL.style.height = row.style.height; + if (x + this.tipEL.clientWidth > (this.canvasPanel!.clientWidth ?? 0)) { + this.tipEL.style.transform = `translateX(${x - this.tipEL.clientWidth - 1}px) translateY(${y}px)`; + } else { + this.tipEL.style.transform = `translateX(${x}px) translateY(${y}px)`; + } + } + } + + initPointToEvent() { + this.eventMap = { + 'cpu-data': 'Cpu', + 'cpu-state': 'Cpu State', + 'cpu-freq': 'Cpu Frequency', + 'cpu-limit-freq': 'Cpu Freq Limit', + process: 'Process', + 'native-memory': 'Native Memory', + thread: 'Thread', + func: 'Func', + mem: 'Memory', + 'virtual-memory-cell': 'Virtual Memory', + 'virtual-memory-group': 'Virtual Memory', + fps: 'FPS', + 'ability-monitor': 'Ability Monitor', + 'cpu-ability': 'Cpu Ability', + 'memory-ability': 'Memory Ability', + 'disk-ability': 'DiskIO Ability', + 'network-ability': 'Network Ability', + sdk: 'Sdk', + 'sdk-counter': 'SDK Counter', + 'sdk-slice': 'Sdk Slice', + energy: 'Energy', + 'power-energy': 'Power Event', + 'system-energy': 'System Event', + 'anomaly-energy': 'Anomaly Event', + 'clock-group': 'Clocks', + clock: 'clock', + 'irq-group': 'Irqs', + irq: 'irq', + hiperf: 'HiPerf (All)', + 'hiperf-event': 'HiPerf Event', + 'hiperf-report': 'HiPerf Report', + 'hiperf-process': 'HiPerf Process', + 'hiperf-thread': 'HiPerf Thread', + 'js-memory': 'Js Memory', + }; + } + + initHtml(): string { + return ` + +
+ +
+
+ +
+ +
+
+
+
+ +
+ `; + } +} diff --git a/ide/src/trace/component/SpWelcomePage.ts b/ide/src/trace/component/SpWelcomePage.ts new file mode 100644 index 0000000000000000000000000000000000000000..59d9e29a342c59e0c9e15ab1b7e7bdcf25f86a06 --- /dev/null +++ b/ide/src/trace/component/SpWelcomePage.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; + +@element('sp-welcome') +export class SpWelcomePage extends BaseElement { + initElements(): void {} + + initHtml(): string { + return ` + +
+ +
+ `; + } +} diff --git a/ide/src/trace/component/Sptext.ts b/ide/src/trace/component/Sptext.ts new file mode 100644 index 0000000000000000000000000000000000000000..ce64d8739640037c0e9c720d4b4d1f6532826b2b --- /dev/null +++ b/ide/src/trace/component/Sptext.ts @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import '../../base-ui/popover/LitPopover.js'; +import { LitPopover } from '../../base-ui/popover/LitPopover.js'; + +@element('sp-text') +export class SpText extends BaseElement { + initElements(): void { + let litPopover = this.shadowRoot?.querySelector('lit-popover'); + litPopover!.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + } + + initHtml(): string { + return ` + +
+
+ + + + +
+
+ `; + } +} diff --git a/ide/src/trace/component/StackBar.ts b/ide/src/trace/component/StackBar.ts new file mode 100644 index 0000000000000000000000000000000000000000..c01643a3e61bb66416dc2e99ea29532ad948955a --- /dev/null +++ b/ide/src/trace/component/StackBar.ts @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../base-ui/BaseElement.js'; +import { SelectionData } from '../bean/BoxSelection.js'; +import { Utils } from './trace/base/Utils.js'; + +@element('stack-bar') +export class StackBar extends BaseElement { + private container: HTMLDivElement | undefined | null; + + static get observedAttributes() { + return ['mode']; // max min hidden show 三种状态 + } + + set data(val: Array) { + let map = new Map(); + for (let v of val) { + if (map.has(v.state)) { + let sv = map.get(v.state); + sv!.value = sv!.value + v.wallDuration; + sv!.state = v.state + ' : ' + sv!.value.toFixed(7) + 'ms'; + } else { + let sv = new StackValue(); + sv.value = v.wallDuration; + sv.state = v.state + ' : ' + sv.value.toFixed(7) + 'ms'; + sv.color = Utils.getStateColor(v.stateJX); + map.set(v.state, sv); + } + } + let totalDuration = 0; + let arr: Array = []; + for (let key of map.keys()) { + if (key == ' ') { + totalDuration = map.get(key)!.value; + } else { + arr.push(map.get(key)!); + } + } + arr.sort((a, b) => a.value - b.value); + this.container!.innerHTML = ''; + for (let stackValue of arr) { + this.container!.appendChild(this.createBarElement(stackValue, totalDuration)); + } + } + + initElements(): void { + this.container = this.shadowRoot?.querySelector('#container'); + } + + initHtml(): string { + return ` + +
+
+ `; + } + + getStateWidth(state: string): number { + let canvas = document.createElement('canvas'); + let context = canvas.getContext('2d'); + context!.font = '9pt'; + let metrics = context!.measureText(state); + return metrics.width; + } + + createBarElement(sv: StackValue, total: number): HTMLDivElement { + let bar = document.createElement('div'); + bar.setAttribute('class', 'state-text'); + bar.setAttribute('need-width', this.getStateWidth(sv.state) + ''); + bar.style.backgroundColor = sv.color; + bar.textContent = sv.state; + if (sv.state.startsWith('Sleeping')) { + bar.style.color = '#555555'; + } else { + bar.style.color = '#ffffff'; + } + let weight = ((sv.value * 1.0) / total) * 100.0; + if (weight < 1) { + weight = 1; + } + bar.style.width = weight + '%'; + bar.addEventListener('mouseover', (event) => { + let needWidth = parseFloat(bar.getAttribute('need-width')!); + let trueWidth = parseFloat(window.getComputedStyle(bar).width); + if (trueWidth < needWidth) { + bar.style.width = needWidth + 100 + 'px'; + } + }); + bar.addEventListener('mouseleave', (event) => { + let weight = ((sv.value * 1.0) / total) * 100.0; + if (weight < 1) { + weight = 1; + } + bar.style.width = weight + '%'; + }); + return bar; + } +} + +export class StackValue { + state: string = ''; + color: string = ''; + value: number = 0; +} diff --git a/ide/src/trace/component/chart/FrameChart.ts b/ide/src/trace/component/chart/FrameChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..602ec8989a54795f7427c18b2c16273bfc89143b --- /dev/null +++ b/ide/src/trace/component/chart/FrameChart.ts @@ -0,0 +1,839 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { Rect } from '../trace/timer-shaft/Rect.js'; +import { ChartMode, ChartStruct, draw, setFuncFrame } from '../../bean/FrameChartStruct.js'; +import { SpApplication } from '../../SpApplication.js'; +import { Utils } from '../trace/base/Utils.js'; + +const TAG: string = 'FrameChart'; +const scaleHeight = 30; +const depthHeight = 20; +const filterPixel = 2; +const sideLength = 8; + +class Module { + size: number; + count: number; + dur: number; + constructor() { + this.size = 0; + this.count = 0; + this.dur = 0; + } +} + +@element('tab-framechart') +export class FrameChart extends BaseElement { + private canvas: HTMLCanvasElement | undefined | null; + private canvasContext: CanvasRenderingContext2D | undefined | null; + private floatHint: HTMLDivElement | undefined | null; + + private rect: Rect = new Rect(0, 0, 0, 0); + private _mode = ChartMode.Byte; + private startX = 0; // canvas start x coord + private startY = 0; // canvas start y coord + private canvasX = -1; // canvas current x + private canvasY = -1; // canvas current y + private hintContent = ''; // float hint inner html content + + private historyList: Array> = []; + private currentSize = 0; + private currentCount = 0; + private currentDuration = 0; + + private currentData: Array = []; + private xPoint = 0; // x in rect + private isFocusing = false; + private canvasScrollTop = 0; + private _maxDepth = 0; + private chartClickListenerList: Array = []; + private isUpdateCanvas = false; + + static get observedAttributes() { + return []; + } + + /** + * set chart mode + * @param mode chart format for data mode + */ + set mode(mode: ChartMode) { + this._mode = mode; + } + + set data(val: Array | any) { + this.historyList = []; + ChartStruct.lastSelectFuncStruct = undefined; + this.currentData = val; + this.resetTrans(); + this.calDrawArgs(true); + for (let callback of this.chartClickListenerList) { + callback(true); + } + } + + set tabPaneScrollTop(scrollTop: number) { + this.canvasScrollTop = scrollTop; + this.hideFloatHint(); + } + + /** + * add callback of chart click + * @param callback function of chart click + */ + public addChartClickListener(callback: Function) { + if (this.chartClickListenerList.indexOf(callback) < 0) { + this.chartClickListenerList.push(callback); + } + } + + /** + * remove callback of chart click + * @param callback function of chart click + */ + public removeChartClickListener(callback: Function) { + let index = this.chartClickListenerList.indexOf(callback); + if (index > -1) { + this.chartClickListenerList.splice(index, 1); + } + } + + /** + * cal total count size and max Depth + * @param isCalRoot use depth 1 node to cal depth 0 node size/count/dur + */ + private calDrawArgs(isCalRoot: boolean): void { + this.currentCount = 0; + this.currentSize = 0; + this.currentDuration = 0; + this._maxDepth = 0; + for (let rootNode of this.currentData!) { + let depth = 0; + this.calMaxDepth(rootNode, depth, isCalRoot, true); + this.currentCount += rootNode.drawCount || rootNode.count; + this.currentSize += rootNode.drawSize || rootNode.size; + this.currentDuration += rootNode.drawDur || rootNode.dur; + } + this.rect.width = this.canvas!.width; + this.rect.height = (this._maxDepth + 1) * 20 + scaleHeight; // 20px/depth and 30 is scale height + this.canvas!.style.height = this.rect!.height + 'px'; + this.canvas!.height = Math.ceil(this.rect!.height); + } + + /** + * cal max Depth + * @param node every child node + * @param depth current depth + * @param isCalRoot use depth 1 node to cal depth 0 node size/count/dur + */ + private calMaxDepth(node: ChartStruct, depth: number, isCalRoot: boolean, isCalDisplay: boolean): void { + node.depth = depth; + this.clearDisplayInfo(node); + if (node.isSearch && isCalDisplay) { + let module = new Module(); + module.count = node.drawCount = node.count; + module.dur = node.drawDur = node.dur; + module.size = node.drawSize = node.size; + this.setParentDisplayInfo(node, module); + isCalDisplay = false; + } + + depth++; + if (node.children && node.children.length > 0) { + let parentSize, parentCount, parentDuration; + parentSize = parentCount = parentDuration = 0; + for (let children of node.children) { + children.parent = node; + if (node.depth == 0 && isCalRoot) { + parentSize += children.size; + parentCount += children.count; + parentDuration += children.dur; + } + this.calMaxDepth(children, depth, isCalRoot, isCalDisplay); + } + if (node.depth == 0 && isCalRoot) { + node.size = parentSize; + node.count = parentCount; + node.dur = parentDuration; + } + } else { + this._maxDepth = Math.max(depth, this._maxDepth); + } + } + + private setParentDisplayInfo(node: ChartStruct, module: Module): void { + if (node.parent) { + node.parent.drawCount += module.count; + node.parent.drawDur += module.dur; + node.parent.drawSize += module.size; + this.setParentDisplayInfo(node.parent, module); + } + } + + private clearDisplayInfo(node: ChartStruct): void { + node.drawCount = 0; + node.drawDur = 0; + node.drawSize = 0; + } + + /** + * calculate Data and draw chart + */ + public async calculateChartData() { + this.clearCanvas(); + this.canvasContext?.beginPath(); + this.drawScale(); + let x = this.xPoint; + switch (this._mode) { + case ChartMode.Byte: + for (let node of this.currentData!) { + let nodeSize = node.drawSize || node.size; + let width = Math.round((nodeSize / this.currentSize) * this.rect!.width); + let height = depthHeight; // 20px / depth + // ensure the data for first depth frame + if (!node.frame) { + node.frame = new Rect(x, scaleHeight, width, height); + } else { + node.frame!.x = x; + node.frame!.y = scaleHeight; + node.frame!.width = width; + node.frame!.height = height; + } + // not draw when rect not in canvas + if (x + width >= 0 && x < this.canvas!.width) { + node.percent = nodeSize / this.currentSize; + draw(this.canvasContext!, node); + } + this.setStructFuncFrame(node); + this.drawFrameChart(node); + x += width; + } + break; + case ChartMode.Count: + for (let node of this.currentData!) { + let nodeCount = node.drawCount || node.count; + let width = Math.round((nodeCount / this.currentCount) * this.rect!.width); + let height = depthHeight; // 20px / depth + // ensure the data for first depth frame + if (!node.frame) { + node.frame = new Rect(x, scaleHeight, width, height); + } else { + node.frame!.x = x; + node.frame!.y = scaleHeight; + node.frame!.width = width; + node.frame!.height = height; + } + // not draw when rect not in canvas + if (x + width >= 0 && x < this.canvas!.width) { + node.percent = nodeCount / this.currentCount; + draw(this.canvasContext!, node); + } + this.setStructFuncFrame(node); + this.drawFrameChart(node); + x += width; + } + break; + case ChartMode.Duration: + for (let node of this.currentData!) { + let nodeDur = node.drawDur || node.dur; + let width = Math.round((nodeDur / this.currentDuration) * this.rect!.width); + let height = depthHeight; // 20px / depth + // ensure the data for first depth frame + if (!node.frame) { + node.frame = new Rect(x, scaleHeight, width, height); + } else { + node.frame!.x = x; + node.frame!.y = scaleHeight; + node.frame!.width = width; + node.frame!.height = height; + } + // not draw when rect not in canvas + if (x + width >= 0 && x < this.canvas!.width) { + node.percent = nodeDur / this.currentDuration; + draw(this.canvasContext!, node); + } + this.setStructFuncFrame(node); + this.drawFrameChart(node); + x += width; + } + break; + } + this.drawTriangleOnScale(); + this.canvasContext?.closePath(); + } + + /** + * draw last selected reset position on scale + */ + private drawTriangleOnScale(): void { + if (ChartStruct.lastSelectFuncStruct) { + this.canvasContext!.fillStyle = `rgba(${82}, ${145}, ${255})`; + let x = Math.ceil(ChartStruct.lastSelectFuncStruct.frame!.x + ChartStruct.lastSelectFuncStruct.frame!.width / 2); + if (x < 0) x = sideLength / 2; + if (x > this.canvas!.width) x = this.canvas!.width - sideLength; + this.canvasContext!.moveTo(x - sideLength / 2, scaleHeight - sideLength); + this.canvasContext!.lineTo(x + sideLength / 2, scaleHeight - sideLength); + this.canvasContext!.lineTo(x, scaleHeight); + this.canvasContext!.lineTo(x - sideLength / 2, scaleHeight - sideLength); + this.canvasContext?.fill(); + } + } + + /** + * clear canvas all data + */ + public clearCanvas(): void { + this.canvasContext?.clearRect(0, 0, this.canvas!.width, this.canvas!.height); + } + + /** + * update canvas size + */ + public updateCanvas(updateWidth: boolean, newWidth?: number): void { + if (this.canvas instanceof HTMLCanvasElement) { + this.canvas.style.width = 100 + '%'; + this.canvas.style.height = this.rect!.height + 'px'; + if (this.canvas.clientWidth == 0 && newWidth) { + this.canvas.width = newWidth - 40; + } else { + this.canvas.width = this.canvas.clientWidth; + } + this.canvas.height = Math.ceil(this.rect!.height); + this.updateCanvasCoord(); + } + if ( + this.rect.width == 0 || + updateWidth || + Math.round(newWidth!) != this.canvas!.width + 40 || + newWidth! > this.rect.width + ) { + this.rect.width = this.canvas!.width; + } + } + + /** + * updateCanvasCoord + */ + private updateCanvasCoord(): void { + if (this.canvas instanceof HTMLCanvasElement) { + this.isUpdateCanvas = this.canvas.clientWidth != 0; + if (this.canvas.getBoundingClientRect()) { + let box = this.canvas.getBoundingClientRect(); + let D = document.documentElement; + this.startX = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft; + this.startY = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop + this.canvasScrollTop; + } + } + } + + /** + * draw top Scale Into 100 piece + */ + private drawScale(): void { + let spApplication = document.getElementsByTagName('sp-application')[0]; + // line + this.canvasContext!.lineWidth = 0.5; + this.canvasContext?.moveTo(0, 0); + this.canvasContext?.lineTo(this.canvas!.width, 0); + + for (let i = 0; i <= 10; i++) { + let startX = Math.floor((this.canvas!.width / 10) * i); + for (let j = 0; j < 10; j++) { + // children scale + this.canvasContext!.lineWidth = 0.5; + let startItemX = startX + Math.floor((this.canvas!.width / 100) * j); + this.canvasContext?.moveTo(startItemX, 0); + this.canvasContext?.lineTo(startItemX, 10); + } + if (i == 0) continue; // skip first Size is 0 + // long line every 10 count + this.canvasContext!.lineWidth = 1; + let sizeRatio = this.canvas!.width / this.rect.width; // scale ratio + if (spApplication.dark) { + this.canvasContext!.strokeStyle = '#888'; + } else { + this.canvasContext!.strokeStyle = '#ddd'; + } + this.canvasContext?.moveTo(startX, 0); + this.canvasContext?.lineTo(startX, this.canvas!.height); + if (spApplication.dark) { + this.canvasContext!.fillStyle = '#fff'; + } else { + this.canvasContext!.fillStyle = '#000'; + } + let scale = ''; + switch (this._mode) { + case ChartMode.Byte: + scale = Utils.getByteWithUnit(((this.currentSize * sizeRatio) / 10) * i); + break; + case ChartMode.Count: + scale = (((this.currentCount * sizeRatio) / 10) * i).toFixed(0) + ''; + break; + case ChartMode.Duration: + scale = Utils.getProbablyTime(((this.currentDuration * sizeRatio) / 10) * i); + break; + } + let size = this.canvasContext!.measureText(scale).width; + this.canvasContext?.fillText(scale, startX - size - 5, depthHeight, 50); // 50 is Text max Length + this.canvasContext?.stroke(); + } + } + + private setStructFuncFrame(node: ChartStruct) { + if (node.children && node.children.length > 0) { + for (let children of node.children) { + node.isDraw = false; + children.parent = node; + switch (this._mode) { + case ChartMode.Byte: + let childrenSize = children.drawSize || children.size; + setFuncFrame(children, this.rect, this.currentSize, this._mode); + children.percent = childrenSize / this.currentSize; + break; + case ChartMode.Count: + let childrenCount = children.drawCount || children.count; + setFuncFrame(children, this.rect, this.currentCount, this._mode); + children.percent = childrenCount / this.currentCount; + break; + case ChartMode.Duration: + let childrenDur = children.drawDur || children.dur; + setFuncFrame(children, this.rect, this.currentDuration, this._mode); + children.percent = childrenDur / this.currentDuration; + break; + } + this.setStructFuncFrame(children); + } + } + } + + /** + * draw chart + * @param node draw chart by every piece + */ + private drawFrameChart(node: ChartStruct) { + let effectChildList = []; + let nodeSize = node.drawSize || node.size; + let nodeCount = node.drawCount || node.count; + let nodeDur = node.drawDur || node.dur; + let ignoreSize, ignoreCount, ignoreDur; + ignoreSize = ignoreCount = ignoreDur = 0; + + if (node.children && node.children.length > 0) { + for (let children of node.children) { + // not draw when rect not in canvas + if ( + (children.frame!.x + children.frame!.width >= 0 && //less than canvas left + children.frame!.x < this.canvas!.width && // more than canvas right + children.frame!.width > filterPixel) || // filter px + children.needShow + ) { + // click and back + effectChildList.push(children); + } else { + ignoreSize += children.drawSize || children.size; + ignoreCount += children.drawCount || children.count; + ignoreDur += children.drawDur || children.dur; + } + } + let x = node.frame!.x; + if (effectChildList.length > 0) { + for (let children of effectChildList) { + children.frame!.x = x; + switch (this._mode) { + case ChartMode.Byte: + let childSize = children.drawSize || children.size; + children.frame!.width = (childSize / (nodeSize - ignoreSize)) * node.frame!.width; + break; + case ChartMode.Count: + let childCount = children.drawCount || children.count; + children.frame!.width = (childCount / (nodeCount - ignoreCount)) * node.frame!.width; + break; + case ChartMode.Duration: + let childDur = children.drawDur || children.dur; + children.frame!.width = (childDur / (nodeDur - ignoreDur)) * node.frame!.width; + break; + } + x += children.frame!.width; + draw(this.canvasContext!, children); + this.drawFrameChart(children); + } + } else { + let firstChildren = node.children[0]; + firstChildren.frame!.x = node.frame!.x; + firstChildren.frame!.width = node.frame!.width; + draw(this.canvasContext!, firstChildren); + this.drawFrameChart(firstChildren); + } + } + } + + /** + * find target node from tree by mouse position + * + * @param nodes tree nodes + * @param canvasX x coord of canvas + * @param canvasY y coord of canvas + * @returns target node + */ + private searchData(nodes: Array, canvasX: number, canvasY: number): any { + for (let node of nodes) { + if (node.frame?.contains(canvasX, canvasY)) { + return node; + } else { + let result = this.searchData(node.children, canvasX, canvasY); + if (!result) continue; // if not found in this branch;search another branch + return result; + } + } + return null; + } + + /** + * show float hint and update position + */ + private updateFloatHint(): void { + this.floatHint!.innerHTML = this.hintContent; + this.floatHint!.style.display = 'block'; + let x = this.canvasX; + let y = this.canvasY - this.canvasScrollTop; + //right rect hint show left + if (this.canvasX + this.floatHint!.clientWidth > (this.canvas?.clientWidth || 0)) { + x -= this.floatHint!.clientWidth - 1; + } else { + x += scaleHeight; + } + //bottom rect hint show top + y -= this.floatHint!.clientHeight - 1; + + this.floatHint!.style.transform = `translate(${x}px,${y}px)`; + } + + /** + * redraw Chart while click to scale chart + * @param selectData select Rect data as array + */ + private redrawChart(selectData: Array): void { + this.currentData = selectData; + if (selectData.length == 0) return; + this.calDrawArgs(false); + this.calculateChartData(); + } + + /** + * press w to zoom in, s to zoom out + * @param index < 0 zoom out , > 0 zoom in + */ + private scale(index: number): void { + let newWidth = 0; + // zoom in + let deltaWidth = this.rect!.width * 0.2; + if (index > 0) { + newWidth = this.rect!.width + deltaWidth; + // max scale + let sizeRatio = this.canvas!.width / this.rect.width; + switch (this._mode) { + case ChartMode.Byte: + //limit 10 byte + if (Math.round((this.currentSize * sizeRatio) / 1.2) <= 10) { + if (this.xPoint == 0) { + return; + } + newWidth = this.canvas!.width / (10 / this.currentSize); + } + break; + case ChartMode.Count: + //limit 10 counts + if (Math.round((this.currentCount * sizeRatio) / 1.2) <= 10) { + if (this.xPoint == 0) { + return; + } + newWidth = this.canvas!.width / (10 / this.currentCount); + } + break; + case ChartMode.Duration: + //limit 10ms + if (Math.round((this.currentDuration * sizeRatio) / 1.2) <= 10_000_000) { + if (this.xPoint == 0) { + return; + } + newWidth = this.canvas!.width / (10_000_000 / this.currentDuration); + } + break; + } + deltaWidth = newWidth - this.rect!.width; + } else { + // zoom out + newWidth = this.rect!.width - deltaWidth; + // min scale + if (newWidth < this.canvas!.width) { + newWidth = this.canvas!.width; + this.resetTrans(); + } + deltaWidth = this.rect!.width - newWidth; + } + // width not change + if (newWidth == this.rect.width) return; + this.translationByScale(index, deltaWidth, newWidth); + } + + private resetTrans() { + this.xPoint = 0; + } + + /** + * translation after scale + * @param index is zoom in + * @param deltaWidth scale delta width + * @param newWidth rect width after scale + */ + private translationByScale(index: number, deltaWidth: number, newWidth: number): void { + let translationValue = (deltaWidth * (this.canvasX - this.xPoint)) / this.rect.width; + if (index > 0) { + this.xPoint -= translationValue; + } else { + this.xPoint += translationValue; + } + this.rect!.width = newWidth; + this.translationDraw(); + } + + /** + * press a/d to translate rect + * @param index left or right + */ + private translation(index: number): void { + let offset = this.canvas!.width / 10; + if (index < 0) { + this.xPoint += offset; + } else { + this.xPoint -= offset; + } + this.translationDraw(); + } + + /** + * judge position ro fit canvas and draw + */ + private translationDraw(): void { + // right trans limit + if (this.xPoint > 0) { + this.xPoint = 0; + } + // left trans limit + if (this.rect.width + this.xPoint < this.canvas!.width) { + this.xPoint = this.canvas!.width - this.rect.width; + } + this.calculateChartData(); + } + + /** + * canvas click + * @param e MouseEvent + */ + private onMouseClick(e: MouseEvent): void { + if (e.button == 0) { + // mouse left button + if (ChartStruct.hoverFuncStruct && ChartStruct.hoverFuncStruct != ChartStruct.selectFuncStruct) { + this.drawDataSet(ChartStruct.lastSelectFuncStruct!, false); + ChartStruct.lastSelectFuncStruct = undefined; + ChartStruct.selectFuncStruct = ChartStruct.hoverFuncStruct; + this.historyList.push(this.currentData!); + let selectData = new Array(); + selectData.push(ChartStruct.selectFuncStruct!); + // reset scale and translation + this.rect.width = this.canvas!.clientWidth; + this.resetTrans(); + this.redrawChart(selectData); + for (let callback of this.chartClickListenerList) { + callback(false); + } + } + } else if (e.button == 2) { + // mouse right button + ChartStruct.selectFuncStruct = undefined; + ChartStruct.hoverFuncStruct = undefined; + if (this.currentData.length == 1 && this.historyList.length > 0) { + ChartStruct.lastSelectFuncStruct = this.currentData[0]; + this.drawDataSet(ChartStruct.lastSelectFuncStruct, true); + } + if (this.historyList.length > 0) { + // reset scale and translation + this.rect.width = this.canvas!.clientWidth; + this.resetTrans(); + this.redrawChart(this.historyList.pop()!); + } + if (this.historyList.length === 0) { + for (let callback of this.chartClickListenerList) { + callback(true); + } + } + } + this.hideFloatHint(); + } + + private hideFloatHint() { + if (this.floatHint) { + this.floatHint.style.display = 'none'; + } + } + + /** + * set current select rect parents will show + * @param data current node + * @param isShow is show in chart + */ + private drawDataSet(data: ChartStruct, isShow: boolean): void { + if (data) { + data.needShow = isShow; + if (data.parent) { + this.drawDataSet(data.parent, isShow); + } + } + } + + /** + * mouse on canvas move event + */ + private onMouseMove(): void { + let lastNode = ChartStruct.hoverFuncStruct; + let searchResult = this.searchData(this.currentData!, this.canvasX, this.canvasY); + if (searchResult && (searchResult.isDraw || searchResult.needShow || searchResult.depth == 0)) { + ChartStruct.hoverFuncStruct = searchResult; + // judge current node is hover redraw chart + if (searchResult != lastNode) { + let name = ChartStruct.hoverFuncStruct?.symbol; + switch (this._mode) { + case ChartMode.Byte: + let size = Utils.getByteWithUnit( + ChartStruct.hoverFuncStruct!.drawSize || ChartStruct.hoverFuncStruct!.size + ); + this.hintContent = ` + Symbol: ${name}
+ Lib: ${ChartStruct.hoverFuncStruct?.lib}
+ Addr: ${ChartStruct.hoverFuncStruct?.addr}
+ Size: ${size}
+ Count: ${ChartStruct.hoverFuncStruct?.count}`; + break; + case ChartMode.Count: + let count = ChartStruct.hoverFuncStruct!.count; + this.hintContent = ` + Name: ${name}
+ Count: ${count}`; + break; + case ChartMode.Duration: + let duration = Utils.getProbablyTime(ChartStruct.hoverFuncStruct!.dur); + this.hintContent = ` + Name: ${name}
+ Duration: ${duration}`; + break; + } + this.calculateChartData(); + } + // prevent float hint trigger onmousemove event + this.updateFloatHint(); + } else { + this.hideFloatHint(); + ChartStruct.hoverFuncStruct = undefined; + } + } + + initElements(): void { + this.canvas = this.shadowRoot?.querySelector('#canvas'); + this.canvasContext = this.canvas?.getContext('2d'); + this.floatHint = this.shadowRoot?.querySelector('#float_hint'); + + this.canvas!.oncontextmenu = () => { + return false; + }; + this.canvas!.onmouseup = (e) => { + this.onMouseClick(e); + }; + + this.canvas!.onmousemove = (e) => { + if (!this.isUpdateCanvas) { + this.updateCanvasCoord(); + } + this.canvasX = e.clientX - this.startX; + this.canvasY = e.clientY - this.startY + this.canvasScrollTop; + this.isFocusing = true; + this.onMouseMove(); + }; + + this.canvas!.onmouseleave = () => { + ChartStruct.selectFuncStruct = undefined; + this.isFocusing = false; + this.hideFloatHint(); + }; + + document.addEventListener('keydown', (e) => { + if (!this.isFocusing) return; + switch (e.key.toLocaleLowerCase()) { + case 'w': + this.scale(1); + break; + case 's': + this.scale(-1); + break; + case 'a': + this.translation(-1); + break; + case 'd': + this.translation(1); + break; + } + }); + new ResizeObserver((entries) => { + if (this.canvas!.getBoundingClientRect()) { + let box = this.canvas!.getBoundingClientRect(); + let D = document.documentElement; + this.startX = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft; + this.startY = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop + this.canvasScrollTop; + } + }).observe(document.documentElement); + } + + initHtml(): string { + return ` + + +
`; + } +} diff --git a/ide/src/trace/component/chart/PerfDataQuery.ts b/ide/src/trace/component/chart/PerfDataQuery.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef7d6acb24114914a9bf7261dd1a29dd3605c955 --- /dev/null +++ b/ide/src/trace/component/chart/PerfDataQuery.ts @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2022 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 { queryPerfFiles, query, threadPool } from '../../database/SqlLite.js'; +import { PerfCall, PerfCallChain, PerfCallChainMerageData, PerfFile } from '../../bean/PerfProfile.js'; +import { info } from '../../../log/Log.js'; +import { SpHiPerf } from './SpHiPerf.js'; +import { procedurePool } from '../../database/Procedure.js'; + +export class PerfDataQuery { + filesData: any = {}; + samplesData: any = {}; + threadData: any = {}; + callChainData: any = {}; + splitMapData: any = {}; + currentTreeMapData: any = {}; + currentTreeList: any[] = []; + searchValue: string = ''; + callChainMap: Map = new Map(); + + async initPerfCache() { + await this.initPerfCallChainMap(); + await this.initPerfFiles(); + } + + async initPerfCallChainMap() { + this.callChainMap.clear(); + } + + async initPerfFiles() { + let files = await queryPerfFiles(); + info('PerfFiles Data size is: ', files!.length); + files.forEach((file) => { + this.filesData[file.fileId] = this.filesData[file.fileId] || []; + PerfFile.setFileName(file); + this.filesData[file.fileId].push(file); + }); + let results = await new Promise((resolve, reject) => { + procedurePool.submitWithName('logic0', 'perf-init', SpHiPerf.stringResult, undefined, (res: any) => { + resolve(res); + }); + }); + this.callChainMap = results as any; + info('Perf Files Data initialized'); + } + + initCallChainBottomUp(callChains: PerfCallChain[]) { + callChains.forEach((callChain, index) => { + if (this.threadData[callChain.tid] == undefined) { + return; + } + callChain.name = this.setCallChainName(callChain); + this.addGroupData(callChain); + if (index + 1 < callChains.length && callChains[index + 1].sampleId == callChain.sampleId) { + PerfCallChain.setPreviousNode(callChain, callChains[index + 1]); + } + if (callChains.length == index + 1 || callChains[index + 1].sampleId != callChain.sampleId) { + this.addProcessThreadStateData(callChain); + } + }); + } + + setCallChainName(callChain: PerfCallChain): string { + //设置调用栈的名称 + callChain.pid = this.threadData[callChain.tid]?.pid; + callChain.canCharge = true; + if (callChain.symbolId == -1) { + if (this.filesData[callChain.fileId] && this.filesData[callChain.fileId].length > 0) { + callChain.fileName = this.filesData[callChain.fileId][0].fileName; + callChain.path = this.filesData[callChain.fileId][0].path; + return this.filesData[callChain.fileId][0].fileName + '+0x' + callChain.vaddrInFile; + } else { + callChain.fileName = 'unkown'; + return '+0x' + callChain.vaddrInFile; + } + } else { + if (this.filesData[callChain.fileId] && this.filesData[callChain.fileId].length > callChain.symbolId) { + callChain.fileName = this.filesData[callChain.fileId][callChain.symbolId].fileName; + callChain.path = this.filesData[callChain.fileId][callChain.symbolId].path; + return this.filesData[callChain.fileId][callChain.symbolId].symbol; + } else { + callChain.fileName = 'unkown'; + return '+0x' + callChain.vaddrInFile; + } + } + } + + addProcessThreadStateData(callChain: PerfCallChain) { + //当调用栈为调用的根节点时 + let threadCallChain = new PerfCallChain(); //新增的线程数据 + threadCallChain.depth = 0; + PerfCallChain.merageCallChain(threadCallChain, callChain); + threadCallChain.canCharge = false; + threadCallChain.name = this.threadData[callChain.tid].threadName || 'Thead' + '(' + callChain.tid + ')'; + let threadStateCallChain = new PerfCallChain(); //新增的线程状态数据 + PerfCallChain.merageCallChain(threadStateCallChain, callChain); + threadStateCallChain.name = callChain.threadState || 'Unkown State'; + threadStateCallChain.fileName = threadStateCallChain.name == '-' ? 'Unkown Thead State' : ''; + threadStateCallChain.canCharge = false; + this.addGroupData(threadStateCallChain); + this.addGroupData(threadCallChain); + PerfCallChain.setNextNode(threadCallChain, threadStateCallChain); + PerfCallChain.setNextNode(threadStateCallChain, callChain); + } + + addGroupData(callChain: PerfCallChain) { + this.callChainData[callChain.sampleId] = this.callChainData[callChain.sampleId] || []; + this.callChainData[callChain.sampleId].push(callChain); + } + + getCallChainsBySampleIds(sampleIds: string[], isTopDown: boolean) { + return this.groupNewTreeNoId(sampleIds, isTopDown); + } + + groupNewTreeNoId(sampleIds: string[], isTopDown: boolean) { + this.currentTreeMapData = {}; + this.currentTreeList = []; + for (let i = 0; i < sampleIds.length; i++) { + let callChains = this.callChainData[sampleIds[i]]; + if (callChains == undefined) continue; + let topIndex = isTopDown ? callChains.length - 1 : 0; + if (callChains.length > 0) { + let root = this.currentTreeMapData[callChains[topIndex].name + callChains[topIndex].pid]; + if (root == undefined) { + root = new PerfCallChainMerageData(); + this.currentTreeMapData[callChains[topIndex].name + callChains[topIndex].pid] = root; + this.currentTreeList.push(root); + } + PerfCallChainMerageData.merageCallChain(root, callChains[topIndex], isTopDown); + this.merageChildren(root, callChains[topIndex], isTopDown); + } + } + let rootMerageMap: any = {}; + // @ts-ignore + Object.values(this.currentTreeMapData).forEach((merageData: any) => { + if (rootMerageMap[merageData.pid] == undefined) { + let processMerageData = new PerfCallChainMerageData(); //新增进程的节点数据 + processMerageData.canCharge = false; + processMerageData.symbolName = this.threadData[merageData.tid].processName || `Process(${merageData.pid})`; + processMerageData.symbol = processMerageData.symbolName; + processMerageData.tid = merageData.tid; + processMerageData.children.push(merageData); + processMerageData.initChildren.push(merageData); + processMerageData.dur = merageData.dur; + processMerageData.count = merageData.dur; + processMerageData.total = sampleIds.length; + rootMerageMap[merageData.pid] = processMerageData; + } else { + rootMerageMap[merageData.pid].children.push(merageData); + rootMerageMap[merageData.pid].initChildren.push(merageData); + rootMerageMap[merageData.pid].dur += merageData.dur; + rootMerageMap[merageData.pid].count += merageData.dur; + rootMerageMap[merageData.pid].total = sampleIds.length; + } + merageData.parentNode = rootMerageMap[merageData.pid]; //子节点添加父节点的引用 + }); + let id = 0; + this.currentTreeList.forEach((node) => { + node.total = sampleIds.length; + if (node.id == '') { + node.id = id + ''; + id++; + } + if (node.parentNode) { + if (node.parentNode.id == '') { + node.parentNode.id = id + ''; + id++; + } + node.parentId = node.parentNode.id; + } + }); + // @ts-ignore + return Object.values(rootMerageMap); + } + + merageChildren(currentNode: PerfCallChainMerageData, callChain: any, isTopDown: boolean) { + let nextNodeKey = isTopDown ? 'nextNode' : 'previousNode'; + if (callChain[nextNodeKey] == undefined) return; + let node; + if ( + currentNode.initChildren.filter((child: PerfCallChainMerageData) => { + if (child.symbolName == callChain[nextNodeKey]?.name) { + node = child; + PerfCallChainMerageData.merageCallChain(child, callChain[nextNodeKey], isTopDown); + return true; + } + return false; + }).length == 0 + ) { + node = new PerfCallChainMerageData(); + PerfCallChainMerageData.merageCallChain(node, callChain[nextNodeKey], isTopDown); + currentNode.children.push(node); + currentNode.initChildren.push(node); + this.currentTreeList.push(node); + node.parentNode = currentNode; + } + if (node) this.merageChildren(node, callChain[nextNodeKey], isTopDown); + } + + //所有的操作都是针对整个树结构的 不区分特定的数据 + splitTree(data: PerfCallChainMerageData[], name: string, isCharge: boolean, isSymbol: boolean) { + data.forEach((process) => { + process.children = []; + if (isCharge) { + this.recursionChargeInitTree(process, name, isSymbol); + } else { + this.recursionPruneInitTree(process, name, isSymbol); + } + }); + this.resetAllNode(data); + } + + recursionChargeInitTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(node); + node.isStore++; + } + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionChargeInitTree(child, symbolName, isSymbol); + }); + } + } + + //symbol lib charge + recursionChargeTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && + node.currentTreeParentNode.children.splice( + node.currentTreeParentNode.children.indexOf(node), + 1, + ...node.children + ); + node.children.forEach((child) => { + child.currentTreeParentNode = node.currentTreeParentNode; + }); + } + if (node.children.length > 0) { + node.children.forEach((child) => { + this.recursionChargeTree(child, symbolName, isSymbol); + }); + } + } + + recursionPruneInitTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(node); + node.isStore++; + this.pruneChildren(node, symbolName); + } else if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionPruneInitTree(child, symbolName, isSymbol); + }); + } + } + + //symbol lib prune + recursionPruneTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && + node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1); + } else { + node.children.forEach((child) => { + this.recursionPruneTree(child, symbolName, isSymbol); + }); + } + } + + recursionChargeByRule( + node: PerfCallChainMerageData, + ruleName: string, + rule: (node: PerfCallChainMerageData) => boolean + ) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + if (rule(child)) { + (this.splitMapData[ruleName] = this.splitMapData[ruleName] || []).push(child); + child.isStore++; + } + this.recursionChargeByRule(child, ruleName, rule); + }); + } + } + + pruneChildren(node: PerfCallChainMerageData, symbolName: string) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + child.isStore++; + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(child); + this.pruneChildren(child, symbolName); + }); + } + } + + clearSplitMapData(symbolName: string) { + delete this.splitMapData[symbolName]; + } + + resotreAllNode(symbols: string[]) { + symbols.forEach((symbol) => { + let list = this.splitMapData[symbol]; + if (list != undefined) { + list.forEach((item: any) => { + item.isStore--; + }); + } + }); + } + + resetAllNode(data: PerfCallChainMerageData[]) { + this.clearSearchNode(); + data.forEach((process) => { + process.searchShow = true; + }); + this.resetNewAllNode(data); + if (this.searchValue != '') { + this.findSearchNode(data, this.searchValue, false); + this.resetNewAllNode(data); + } + } + + resetNewAllNode(data: PerfCallChainMerageData[]) { + data.forEach((process) => { + process.children = []; + }); + let values = this.currentTreeList.map((item: any) => { + item.children = []; + return item; + }); + values.forEach((item: any) => { + if (item.parentNode != undefined) { + if (item.isStore == 0 && item.searchShow) { + let parentNode = item.parentNode; + while (parentNode != undefined && !(parentNode.isStore == 0 && parentNode.searchShow)) { + parentNode = parentNode.parentNode; + } + if (parentNode) { + item.currentTreeParentNode = parentNode; + parentNode.children.push(item); + } + } + } + }); + } + + findSearchNode(data: PerfCallChainMerageData[], search: string, parentSearch: boolean) { + data.forEach((node) => { + if ((node.symbol && node.symbol.includes(search)) || parentSearch) { + node.searchShow = true; + let parentNode = node.currentTreeParentNode; + while (parentNode != undefined && !parentNode.searchShow) { + parentNode.searchShow = true; + parentNode = parentNode.currentTreeParentNode; + } + } else { + node.searchShow = false; + } + if (node.children.length > 0) { + this.findSearchNode(node.children, search, node.searchShow); + } + }); + } + + clearSearchNode() { + this.currentTreeList.forEach((node) => { + node.searchShow = true; + }); + } +} + +export const perfDataQuery = new PerfDataQuery(); diff --git a/ide/src/trace/component/chart/SmapsChart.ts b/ide/src/trace/component/chart/SmapsChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..206f16de0faa565d3405a7479db13411edd95a24 --- /dev/null +++ b/ide/src/trace/component/chart/SmapsChart.ts @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { querySmapsData, querySmapsDataMax, querySmapsExits } from '../../database/SqlLite.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { BaseStruct } from '../../bean/BaseStruct.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { SmapsRender, SmapsStruct } from '../../database/ui-worker/ProcedureWorkerSmaps.js'; +import { Utils } from '../trace/base/Utils.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class SmapsChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let result = await querySmapsExits(); + if (result.length <= 0) return; + let smapsRow = this.initSmapsRow(); + let rowNameList: Array = ['Dirty Size', 'Swapped Size', 'Resident Size']; + for (let rowName of rowNameList) { + await this.initRows(smapsRow, rowName); + } + } + + private initSmapsRow = () => { + let smapsRow = TraceRow.skeleton(); + smapsRow.rowId = `smapsRow`; + smapsRow.rowType = TraceRow.ROW_TYPE_SMAPS; + smapsRow.rowParentId = ''; + smapsRow.style.height = '40px'; + smapsRow.folder = true; + smapsRow.name = 'VM Tracker'; + smapsRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + smapsRow.selectChangeHandler = this.trace.selectChangeHandler; + smapsRow.supplier = () => new Promise>((resolve) => resolve([])); + smapsRow.onThreadHandler = (useCache) => { + smapsRow.canvasSave(this.trace.canvasPanelCtx!); + if (smapsRow.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, smapsRow.frame.width, smapsRow.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + smapsRow + ); + } + smapsRow.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(smapsRow); + return smapsRow; + }; + + private initRows = async (nodeRow: TraceRow, rowName: string) => { + let traceRow = TraceRow.skeleton(); + traceRow.rowParentId = `smapsRow`; + traceRow.rowHidden = !nodeRow.expansion; + traceRow.rowId = rowName; + traceRow.rowType = TraceRow.ROW_TYPE_SMAPS; + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.style.height = '40px'; + traceRow.style.width = `100%`; + traceRow.setAttribute('children', ''); + traceRow.name = rowName; + let columnName = ''; + if (rowName == 'Dirty Size') { + columnName = 'dirty'; + } else if (rowName == 'Swapped Size') { + columnName = 'swapper'; + } else { + columnName = 'resident_size'; + } + traceRow.supplier = () => querySmapsData(columnName); + let maxList = await querySmapsDataMax(columnName); + let maxValue = maxList[0].max_value; + traceRow.focusHandler = (ev) => { + this.trace?.displayTip( + traceRow, + SmapsStruct.hoverSmapsStruct, + `${Utils.getBinaryByteWithUnit((SmapsStruct.hoverSmapsStruct?.value || 0) * 1024)}` + ); + }; + traceRow.onThreadHandler = (useCache) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders['smaps'] as SmapsRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `smaps`, + rowName: columnName, + maxValue: maxValue, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + nodeRow.addChildTraceRow(traceRow); + }; +} diff --git a/ide/src/trace/component/chart/SpAbilityMonitorChart.ts b/ide/src/trace/component/chart/SpAbilityMonitorChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c058e2f7ce87146011bf3b3f1ce31553919858d --- /dev/null +++ b/ide/src/trace/component/chart/SpAbilityMonitorChart.ts @@ -0,0 +1,714 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { + queryAbilityExits, + queryBytesInAbilityData, + queryBytesOutAbilityData, + queryBytesReadAbilityData, + queryBytesWrittenAbilityData, + queryCachedFilesAbilityData, + queryCompressedAbilityData, + queryCpuAbilityData, + queryCPuAbilityMaxData, + queryCpuAbilitySystemData, + queryCpuAbilityUserData, + queryDiskIoMaxData, + queryMemoryMaxData, + queryMemoryUsedAbilityData, + queryNetWorkMaxData, + queryPacketsInAbilityData, + queryPacketsOutAbilityData, + queryReadAbilityData, + queryWrittenAbilityData, +} from '../../database/SqlLite.js'; +import { info } from '../../../log/Log.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { Utils } from '../trace/base/Utils.js'; +import { CpuStruct, EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { ProcessRender, ProcessStruct } from '../../database/ui-worker/ProcedureWorkerProcess.js'; +import { CpuFreqStruct, FreqRender } from '../../database/ui-worker/ProcedureWorkerFreq.js'; +import { CpuAbilityMonitorStruct, CpuAbilityRender } from '../../database/ui-worker/ProcedureWorkerCpuAbility.js'; +import { + MemoryAbilityMonitorStruct, + MemoryAbilityRender, +} from '../../database/ui-worker/ProcedureWorkerMemoryAbility.js'; +import { + DiskAbilityMonitorStruct, + DiskIoAbilityRender, +} from '../../database/ui-worker/ProcedureWorkerDiskIoAbility.js'; +import { + NetworkAbilityMonitorStruct, + NetworkAbilityRender, +} from '../../database/ui-worker/ProcedureWorkerNetworkAbility.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { ColorUtils } from '../trace/base/ColorUtils.js'; + +export class SpAbilityMonitorChart { + private trace: SpSystemTrace; + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + memoryMath = (maxByte: number) => { + let maxByteName = ''; + if (maxByte > 0) { + maxByteName = Utils.getBinaryKBWithUnit(maxByte); + } + return maxByteName; + }; + + diskIOMath = (maxByte: number) => { + let maxByteName = ''; + if (maxByte > 0) { + maxByteName = maxByte + 'KB/S'; + } + return maxByteName; + }; + + networkMath = (maxValue: number) => { + let maxByteName = ''; + if (maxValue > 0) { + maxByteName = Utils.getBinaryByteWithUnit(maxValue); + } + return maxByteName; + }; + + async init() { + let time = new Date().getTime(); + let result = await queryAbilityExits(); + info('Ability Monitor Exits Tables size is: ', result!.length); + if (result.length <= 0) return; + let processRow = this.initAbilityRow(); + if (this.hasTable(result, 'trace_cpu_usage')) { + await this.initCpuAbility(processRow); + } + if (this.hasTable(result, 'sys_memory')) { + await this.initMemoryAbility(processRow); + } + if (this.hasTable(result, 'trace_diskio')) { + await this.initDiskAbility(processRow); + } + if (this.hasTable(result, 'trace_network')) { + await this.initNetworkAbility(processRow); + } + let durTime = new Date().getTime() - time; + info('The time to load the AbilityMonitor data is: ', durTime); + } + + private hasTable(result: Array, tableName: string) { + return result.find((o) => { + return o.event_name === tableName; + }); + } + + private initAbilityRow = () => { + let processRow = TraceRow.skeleton(); + processRow.rowId = `abilityMonitor`; + processRow.rowType = TraceRow.ROW_TYPE_MONITOR; + processRow.style.height = '40px'; + processRow.rowParentId = ''; + processRow.folder = true; + processRow.name = 'Ability Monitor'; + processRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + processRow.selectChangeHandler = this.trace.selectChangeHandler; + processRow.supplier = () => new Promise>((resolve) => resolve([])); + processRow.onThreadHandler = (useCache) => { + processRow.canvasSave(this.trace.canvasPanelCtx!); + if (processRow.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, processRow.frame.width, processRow.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + processRow + ); + } + processRow.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(processRow); + return processRow; + }; + + private initCpuAbility = async (processRow: TraceRow) => { + let time = new Date().getTime(); + let cpuMaxData = await queryCPuAbilityMaxData(); + let hasTotal = false; + let hasUserLoad = false; + let hasSystemLoad = false; + let userLoad = cpuMaxData[0].userLoad; + if (userLoad > 0) { + hasUserLoad = true; + } + let systemLoad = cpuMaxData[0].systemLoad; + if (systemLoad > 0) { + hasSystemLoad = true; + } + let totalLoad = cpuMaxData[0].totalLoad; + if (totalLoad > 0) { + hasTotal = true; + } + let cpuNameList: Array = ['Total', 'User', 'System']; + let traceRow = TraceRow.skeleton(); + traceRow.rowParentId = `abilityMonitor`; + traceRow.rowHidden = !processRow.expansion; + traceRow.rowId = cpuNameList[0]; + traceRow.rowType = TraceRow.ROW_TYPE_CPU_ABILITY; + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.style.height = '40px'; + traceRow.style.width = `100%`; + traceRow.setAttribute('children', ''); + traceRow.name = `CPU ${cpuNameList[0]} Load`; + traceRow.supplier = () => queryCpuAbilityData(); + traceRow.focusHandler = (ev) => { + let monitorCpuTip = (CpuAbilityMonitorStruct.hoverCpuAbilityStruct?.value || 0).toFixed(2) + '%'; + this.trace?.displayTip(traceRow, CpuAbilityMonitorStruct.hoverCpuAbilityStruct, `${monitorCpuTip}`); + }; + traceRow.onThreadHandler = (useCache) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders['monitorCpu'] as CpuAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorCpu0`, + maxCpuUtilization: 100, + maxCpuUtilizationName: hasTotal ? '100%' : '0%', + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(traceRow); + let userTraceRow = TraceRow.skeleton(); + userTraceRow.rowParentId = `abilityMonitor`; + userTraceRow.rowHidden = !processRow.expansion; + userTraceRow.rowId = cpuNameList[1]; + userTraceRow.rowType = TraceRow.ROW_TYPE_CPU_ABILITY; + userTraceRow.style.height = '40px'; + userTraceRow.style.width = `100%`; + userTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + userTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + userTraceRow.setAttribute('children', ''); + userTraceRow.name = `CPU ${cpuNameList[1]} Load`; + userTraceRow.supplier = () => queryCpuAbilityUserData(); + userTraceRow.focusHandler = (ev) => { + let monitorCpuTip = (CpuAbilityMonitorStruct.hoverCpuAbilityStruct?.value || 0).toFixed(2) + '%'; + this.trace?.displayTip( + userTraceRow, + CpuAbilityMonitorStruct.hoverCpuAbilityStruct, + `${monitorCpuTip}` + ); + }; + userTraceRow.onThreadHandler = (useCache) => { + let context = userTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + userTraceRow.canvasSave(context); + (renders['monitorCpu'] as CpuAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorCpu1`, + maxCpuUtilization: 100, + maxCpuUtilizationName: hasUserLoad ? '100%' : '0%', + }, + userTraceRow + ); + userTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(userTraceRow); + let sysTraceRow = TraceRow.skeleton(); + sysTraceRow.rowParentId = `abilityMonitor`; + sysTraceRow.rowHidden = !processRow.expansion; + sysTraceRow.rowId = cpuNameList[2]; + sysTraceRow.rowType = TraceRow.ROW_TYPE_CPU_ABILITY; + sysTraceRow.style.height = '40px'; + sysTraceRow.style.width = `100%`; + sysTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + sysTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + sysTraceRow.setAttribute('children', ''); + sysTraceRow.name = `CPU ${cpuNameList[2]} Load`; + sysTraceRow.supplier = () => queryCpuAbilitySystemData(); + sysTraceRow.focusHandler = (ev) => { + let monitorCpuTip = (CpuAbilityMonitorStruct.hoverCpuAbilityStruct?.value || 0).toFixed(2) + '%'; + this.trace?.displayTip( + sysTraceRow, + CpuAbilityMonitorStruct.hoverCpuAbilityStruct, + `${monitorCpuTip}` + ); + }; + sysTraceRow.onThreadHandler = (useCache) => { + let context = sysTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + sysTraceRow.canvasSave(context); + (renders['monitorCpu'] as CpuAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorCpu2`, + maxCpuUtilization: 100, + maxCpuUtilizationName: hasSystemLoad ? '100%' : '0%', + }, + sysTraceRow + ); + sysTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(sysTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the Ability Cpu is: ', durTime); + }; + + private initMemoryAbility = async (processRow: TraceRow) => { + let time = new Date().getTime(); + // sys.mem.total sys.mem.cached sys.mem.swap.total + let memoryNameList: Array = ['MemoryTotal', 'Cached', 'SwapTotal']; + let memoryTotal = await queryMemoryMaxData('sys.mem.total'); + let memoryTotalValue = memoryTotal[0].maxValue; + let memoryTotalId = memoryTotal[0].filter_id; + let memoryTotalValueName = this.memoryMath(memoryTotalValue); + let memoryUsedTraceRow = TraceRow.skeleton(); + memoryUsedTraceRow.rowParentId = `abilityMonitor`; + memoryUsedTraceRow.rowHidden = !processRow.expansion; + memoryUsedTraceRow.rowId = memoryNameList[0]; + memoryUsedTraceRow.rowType = TraceRow.ROW_TYPE_MEMORY_ABILITY; + memoryUsedTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + memoryUsedTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + memoryUsedTraceRow.style.height = '40px'; + memoryUsedTraceRow.style.width = `100%`; + memoryUsedTraceRow.setAttribute('children', ''); + memoryUsedTraceRow.name = memoryNameList[0]; + memoryUsedTraceRow.supplier = () => queryMemoryUsedAbilityData(memoryTotalId); + memoryUsedTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + memoryUsedTraceRow, + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + `${Utils.getBinaryKBWithUnit(MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.value || 0)}` + ); + }; + memoryUsedTraceRow.onThreadHandler = (useCache) => { + let context = memoryUsedTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + memoryUsedTraceRow.canvasSave(context); + (renders['monitorMemory'] as MemoryAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorMemory0`, + maxMemoryByte: memoryTotalValue, + maxMemoryByteName: memoryTotalValueName, + }, + memoryUsedTraceRow + ); + memoryUsedTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(memoryUsedTraceRow); + let cached = await queryMemoryMaxData('sys.mem.cached'); + let cachedValue = cached[0].maxValue; + let cachedValueName = this.memoryMath(cachedValue); + let cachedId = cached[0].filter_id; + let cachedFilesTraceRow = TraceRow.skeleton(); + cachedFilesTraceRow.rowParentId = `abilityMonitor`; + cachedFilesTraceRow.rowHidden = !processRow.expansion; + cachedFilesTraceRow.rowId = memoryNameList[1]; + cachedFilesTraceRow.rowType = TraceRow.ROW_TYPE_MEMORY_ABILITY; + cachedFilesTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + cachedFilesTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + cachedFilesTraceRow.style.height = '40px'; + cachedFilesTraceRow.style.width = `100%`; + cachedFilesTraceRow.setAttribute('children', ''); + cachedFilesTraceRow.name = memoryNameList[1]; + cachedFilesTraceRow.supplier = () => queryCachedFilesAbilityData(cachedId); + cachedFilesTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + cachedFilesTraceRow, + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + `${Utils.getBinaryKBWithUnit(MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.value || 0)}` + ); + }; + cachedFilesTraceRow.onThreadHandler = (useCache) => { + let context = cachedFilesTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + cachedFilesTraceRow.canvasSave(context); + (renders['monitorMemory'] as MemoryAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorMemory1`, + maxMemoryByte: cachedValue, + maxMemoryByteName: cachedValueName, + }, + cachedFilesTraceRow + ); + cachedFilesTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(cachedFilesTraceRow); + let swap = await queryMemoryMaxData('sys.mem.swap.total'); + let swapValue = swap[0].maxValue; + let swapValueName = this.memoryMath(swapValue); + let swapId = swap[0].filter_id; + let compressedTraceRow = TraceRow.skeleton(); + compressedTraceRow.rowParentId = `abilityMonitor`; + compressedTraceRow.rowHidden = !processRow.expansion; + compressedTraceRow.rowId = memoryNameList[2]; + compressedTraceRow.rowType = TraceRow.ROW_TYPE_MEMORY_ABILITY; + compressedTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + compressedTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + compressedTraceRow.style.height = '40px'; + compressedTraceRow.style.width = `100%`; + compressedTraceRow.setAttribute('children', ''); + compressedTraceRow.name = memoryNameList[2]; + compressedTraceRow.supplier = () => queryCompressedAbilityData(swapId); + compressedTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + compressedTraceRow, + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + `${Utils.getBinaryKBWithUnit(MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.value || 0)}` + ); + }; + compressedTraceRow.onThreadHandler = (useCache) => { + let context = compressedTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + compressedTraceRow.canvasSave(context); + (renders['monitorMemory'] as MemoryAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorMemory2`, + maxMemoryByte: swapValue, + maxMemoryByteName: swapValueName, + }, + compressedTraceRow + ); + compressedTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(compressedTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the Ability Memory is: ', durTime); + }; + + private initDiskAbility = async (processRow: TraceRow) => { + let time = new Date().getTime(); + let maxList = await queryDiskIoMaxData(); + let maxBytesRead = maxList[0].bytesRead; + let maxBytesReadName = this.diskIOMath(maxBytesRead); + let diskIONameList: Array = ['Bytes Read/Sec', 'Bytes Written/Sec', 'Read Ops/Sec', 'Written Ops/Sec']; + let bytesReadTraceRow = TraceRow.skeleton(); + bytesReadTraceRow.rowParentId = `abilityMonitor`; + bytesReadTraceRow.rowHidden = !processRow.expansion; + bytesReadTraceRow.rowId = diskIONameList[0]; + bytesReadTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY; + bytesReadTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + bytesReadTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + bytesReadTraceRow.style.height = '40px'; + bytesReadTraceRow.style.width = `100%`; + bytesReadTraceRow.setAttribute('children', ''); + bytesReadTraceRow.name = 'Disk ' + diskIONameList[0]; + bytesReadTraceRow.supplier = () => queryBytesReadAbilityData(); + bytesReadTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + bytesReadTraceRow, + DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + `${DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.value || '0'} KB/S` + ); + }; + bytesReadTraceRow.onThreadHandler = (useCache) => { + let context = bytesReadTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + bytesReadTraceRow.canvasSave(context); + (renders['monitorDiskIo'] as DiskIoAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorDiskIo0`, + maxDiskRate: maxBytesRead, + maxDiskRateName: maxBytesReadName, + }, + bytesReadTraceRow + ); + bytesReadTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(bytesReadTraceRow); + let maxBytesWrite = maxList[0].bytesWrite; + let maxBytesWriteName = this.diskIOMath(maxBytesWrite); + let bytesWrittenTraceRow = TraceRow.skeleton(); + bytesWrittenTraceRow.rowParentId = `abilityMonitor`; + bytesWrittenTraceRow.rowHidden = !processRow.expansion; + bytesWrittenTraceRow.rowId = diskIONameList[1]; + bytesWrittenTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY; + bytesWrittenTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + bytesWrittenTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + bytesWrittenTraceRow.style.height = '40px'; + bytesWrittenTraceRow.style.width = `100%`; + bytesWrittenTraceRow.setAttribute('children', ''); + bytesWrittenTraceRow.name = 'Disk ' + diskIONameList[1]; + bytesWrittenTraceRow.supplier = () => queryBytesWrittenAbilityData(); + bytesWrittenTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + bytesWrittenTraceRow, + DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + `${DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.value || '0'} KB/S` + ); + }; + bytesWrittenTraceRow.onThreadHandler = (useCache) => { + let context = bytesWrittenTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + bytesWrittenTraceRow.canvasSave(context); + (renders['monitorDiskIo'] as DiskIoAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorDiskIo1`, + maxDiskRate: maxBytesWrite, + maxDiskRateName: maxBytesWriteName, + }, + bytesWrittenTraceRow + ); + bytesWrittenTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(bytesWrittenTraceRow); + let maxReadOps = maxList[0].readOps; + let maxReadOpsName = this.diskIOMath(maxReadOps); + let readOpsTraceRow = TraceRow.skeleton(); + readOpsTraceRow.rowParentId = `abilityMonitor`; + readOpsTraceRow.rowHidden = !processRow.expansion; + readOpsTraceRow.rowId = diskIONameList[2]; + readOpsTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY; + readOpsTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + readOpsTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + readOpsTraceRow.style.height = '40px'; + readOpsTraceRow.style.width = `100%`; + readOpsTraceRow.setAttribute('children', ''); + readOpsTraceRow.name = 'Disk ' + diskIONameList[2]; + readOpsTraceRow.supplier = () => queryReadAbilityData(); + readOpsTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + readOpsTraceRow, + DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + `${DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.value || '0'} KB/S` + ); + }; + readOpsTraceRow.onThreadHandler = (useCache) => { + let context = readOpsTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + readOpsTraceRow.canvasSave(context); + (renders['monitorDiskIo'] as DiskIoAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorDiskIo2`, + maxDiskRate: maxReadOps, + maxDiskRateName: maxReadOpsName, + }, + readOpsTraceRow + ); + readOpsTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(readOpsTraceRow); + let maxWriteOps = maxList[0].writeOps; + let maxWriteOpsName = this.diskIOMath(maxWriteOps); + let writtenOpsTraceRow = TraceRow.skeleton(); + writtenOpsTraceRow.rowParentId = `abilityMonitor`; + writtenOpsTraceRow.rowHidden = !processRow.expansion; + writtenOpsTraceRow.rowId = diskIONameList[3]; + writtenOpsTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY; + writtenOpsTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + writtenOpsTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + writtenOpsTraceRow.style.height = '40px'; + writtenOpsTraceRow.style.width = `100%`; + writtenOpsTraceRow.setAttribute('children', ''); + writtenOpsTraceRow.name = 'Disk ' + diskIONameList[3]; + writtenOpsTraceRow.supplier = () => queryWrittenAbilityData(); + writtenOpsTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + writtenOpsTraceRow, + DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + `${DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.value || '0'} KB/S` + ); + }; + writtenOpsTraceRow.onThreadHandler = (useCache) => { + let context = writtenOpsTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + writtenOpsTraceRow.canvasSave(context); + (renders['monitorDiskIo'] as DiskIoAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorDiskIo3`, + maxDiskRate: maxWriteOps, + maxDiskRateName: maxWriteOpsName, + }, + writtenOpsTraceRow + ); + writtenOpsTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(writtenOpsTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the Ability DiskIO is: ', durTime); + }; + + private initNetworkAbility = async (processRow: TraceRow) => { + let time = new Date().getTime(); + let maxList = await queryNetWorkMaxData(); + let maxBytesIn = maxList[0].maxIn; + let maxInByteName = this.networkMath(maxBytesIn); + let networkNameList: Array = ['Bytes In/Sec', 'Bytes Out/Sec', 'Packets In/Sec', 'Packets Out/Sec']; + let bytesInTraceRow = TraceRow.skeleton(); + bytesInTraceRow.rowParentId = `abilityMonitor`; + bytesInTraceRow.rowHidden = !processRow.expansion; + bytesInTraceRow.rowId = networkNameList[0]; + bytesInTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY; + bytesInTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + bytesInTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + bytesInTraceRow.style.height = '40px'; + bytesInTraceRow.style.width = `100%`; + bytesInTraceRow.setAttribute('children', ''); + bytesInTraceRow.name = 'Network ' + networkNameList[0]; + bytesInTraceRow.supplier = () => queryBytesInAbilityData(); + bytesInTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + bytesInTraceRow, + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + `${Utils.getBinaryByteWithUnit(NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.value || 0)}` + ); + }; + bytesInTraceRow.onThreadHandler = (useCache) => { + let context = bytesInTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + bytesInTraceRow.canvasSave(context); + (renders['monitorNetwork'] as NetworkAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorNetwork0`, + maxNetworkRate: maxBytesIn, + maxNetworkRateName: maxInByteName, + }, + bytesInTraceRow + ); + bytesInTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(bytesInTraceRow); + let bytesOutTraceRow = TraceRow.skeleton(); + let maxBytesOut = maxList[0].maxOut; + let maxOutByteName = this.networkMath(maxBytesOut); + bytesOutTraceRow.rowParentId = `abilityMonitor`; + bytesOutTraceRow.rowHidden = !processRow.expansion; + bytesOutTraceRow.rowId = networkNameList[1]; + bytesOutTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY; + bytesOutTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + bytesOutTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + bytesOutTraceRow.style.height = '40px'; + bytesOutTraceRow.style.width = `100%`; + bytesOutTraceRow.setAttribute('children', ''); + bytesOutTraceRow.name = 'Network ' + networkNameList[1]; + bytesOutTraceRow.supplier = () => queryBytesOutAbilityData(); + bytesOutTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + bytesOutTraceRow, + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + `${Utils.getBinaryByteWithUnit(NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.value || 0)}` + ); + }; + bytesOutTraceRow.onThreadHandler = (useCache) => { + let context = bytesOutTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + bytesOutTraceRow.canvasSave(context); + (renders['monitorNetwork'] as NetworkAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorNetwork1`, + maxNetworkRate: maxBytesOut, + maxNetworkRateName: maxOutByteName, + }, + bytesOutTraceRow + ); + bytesOutTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(bytesOutTraceRow); + let packetInTraceRow = TraceRow.skeleton(); + let maxPacketIn = maxList[0].maxPacketIn; + let maxInPacketName = this.networkMath(maxPacketIn); + packetInTraceRow.rowParentId = `abilityMonitor`; + packetInTraceRow.rowHidden = !processRow.expansion; + packetInTraceRow.rowId = networkNameList[2]; + packetInTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY; + packetInTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + packetInTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + packetInTraceRow.style.height = '40px'; + packetInTraceRow.style.width = `100%`; + packetInTraceRow.setAttribute('children', ''); + packetInTraceRow.name = 'Network ' + networkNameList[2]; + packetInTraceRow.supplier = () => queryPacketsInAbilityData(); + packetInTraceRow.focusHandler = (ev) => { + this.trace?.displayTip( + packetInTraceRow, + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + `${Utils.getBinaryByteWithUnit(NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.value || 0)}` + ); + }; + packetInTraceRow.onThreadHandler = (useCache) => { + let context = packetInTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + packetInTraceRow.canvasSave(context); + (renders['monitorNetwork'] as NetworkAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorNetwork-Packet2`, + maxNetworkRate: maxPacketIn, + maxNetworkRateName: maxInPacketName, + }, + packetInTraceRow + ); + packetInTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(packetInTraceRow); + let packetOutTraceRow = TraceRow.skeleton(); + let maxPacketOut = maxList[0].maxPacketOut; + let maxOutPacketName = this.networkMath(maxPacketOut); + packetOutTraceRow.rowParentId = `abilityMonitor`; + packetOutTraceRow.rowHidden = !processRow.expansion; + packetOutTraceRow.rowId = networkNameList[3]; + packetOutTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY; + packetOutTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + packetOutTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + packetOutTraceRow.style.height = '40px'; + packetOutTraceRow.style.width = `100%`; + packetOutTraceRow.setAttribute('children', ''); + packetOutTraceRow.name = 'Network ' + networkNameList[3]; + packetOutTraceRow.supplier = () => queryPacketsOutAbilityData(); + packetOutTraceRow.focusHandler = (ev) => { + if (NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct) { + this.trace?.displayTip( + packetOutTraceRow, + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + `${Utils.getBinaryByteWithUnit(NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct!.value!)}` + ); + } + }; + packetOutTraceRow.onThreadHandler = (useCache) => { + let context = packetOutTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + packetOutTraceRow.canvasSave(context); + (renders['monitorNetwork'] as NetworkAbilityRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `monitorNetwork3`, + maxNetworkRate: maxPacketOut, + maxNetworkRateName: maxOutPacketName, + }, + packetOutTraceRow + ); + packetOutTraceRow.canvasRestore(context); + }; + processRow.addChildTraceRow(packetOutTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the Ability Network is: ', durTime); + }; +} diff --git a/ide/src/trace/component/chart/SpChartManager.ts b/ide/src/trace/component/chart/SpChartManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0512d73de93be5154f916cdbbdc29cf5ecc295c --- /dev/null +++ b/ide/src/trace/component/chart/SpChartManager.ts @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { SpHiPerf } from './SpHiPerf.js'; +import { SpCpuChart } from './SpCpuChart.js'; +import { SpFreqChart } from './SpFreqChart.js'; +import { SpFpsChart } from './SpFpsChart.js'; +import { + getCpuUtilizationRate, + queryDataDICT, + queryThreadAndProcessName, + queryTotalTime, +} from '../../database/SqlLite.js'; +import { info } from '../../../log/Log.js'; +import { SpNativeMemoryChart } from './SpNativeMemoryChart.js'; +import { SpAbilityMonitorChart } from './SpAbilityMonitorChart.js'; +import { SpProcessChart } from './SpProcessChart.js'; +import { perfDataQuery } from './PerfDataQuery.js'; +import { SpVirtualMemChart } from './SpVirtualMemChart.js'; +import { SpFileSystemChart } from './SpFileSystemChart.js'; +import { SpSdkChart } from './SpSdkChart.js'; +import { SpHiSysEventChart } from './SpHiSysEventChart.js'; +import { SmapsChart } from './SmapsChart.js'; +import { SpClockChart } from './SpClockChart.js'; +import { SpIrqChart } from './SpIrqChart.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { SpFrameTimeChart } from './SpFrameTimeChart.js'; +import { Utils } from '../trace/base/Utils.js'; +import { SpJsMemoryChart } from './SpJsMemoryChart.js'; + +export class SpChartManager { + private trace: SpSystemTrace; + public perf: SpHiPerf; + private cpu: SpCpuChart; + private freq: SpFreqChart; + private virtualMemChart: SpVirtualMemChart; + private fps: SpFpsChart; + private nativeMemory: SpNativeMemoryChart; + private abilityMonitor: SpAbilityMonitorChart; + private process: SpProcessChart; + private fileSystem: SpFileSystemChart; + private sdkChart: SpSdkChart; + private hiSyseventChart: SpHiSysEventChart; + private smapsChart: SmapsChart; + private clockChart: SpClockChart; + private irqChart: SpIrqChart; + private frameTimeChart: SpFrameTimeChart; + private jsMemory: SpJsMemoryChart; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + this.perf = new SpHiPerf(trace); + this.fileSystem = new SpFileSystemChart(trace); + this.cpu = new SpCpuChart(trace); + this.freq = new SpFreqChart(trace); + this.virtualMemChart = new SpVirtualMemChart(trace); + this.fps = new SpFpsChart(trace); + this.nativeMemory = new SpNativeMemoryChart(trace); + this.abilityMonitor = new SpAbilityMonitorChart(trace); + this.process = new SpProcessChart(trace); + this.sdkChart = new SpSdkChart(trace); + this.hiSyseventChart = new SpHiSysEventChart(trace); + this.smapsChart = new SmapsChart(trace); + this.clockChart = new SpClockChart(trace); + this.irqChart = new SpIrqChart(trace); + this.frameTimeChart = new SpFrameTimeChart(trace); + this.jsMemory = new SpJsMemoryChart(trace); + } + + async init(progress: Function) { + progress('load data dict', 50); + SpSystemTrace.DATA_DICT.clear(); + let dict = await queryDataDICT(); + dict.map((d) => SpSystemTrace.DATA_DICT.set(d['id'], d['data'])); + progress('time range', 65); + await this.initTotalTime(); + let ptArr = await queryThreadAndProcessName(); + this.handleProcessThread(ptArr); + info('timerShaftEL Data initialized'); + progress('cpu', 70); + await this.cpu.init(); + info('cpu Data initialized'); + progress('process/thread state', 73); + await this.cpu.initProcessThreadStateData(progress); + await this.cpu.initCpuIdle0Data(progress); + await this.cpu.initSchedulingPTData(progress); + await this.cpu.initSchedulingFreqData(progress); + info('ProcessThreadState Data initialized'); + progress('cpu rate', 75); + await this.initCpuRate(); + info('Cpu Rate Data initialized'); + progress('cpu freq', 80); + await this.freq.init(); + progress('Clock init', 82); + await this.clockChart.init(); + progress('Irq init', 84); + await this.irqChart.init(); + info('Cpu Freq Data initialized'); + await this.virtualMemChart.init(); + progress('fps', 85); + await this.fps.init(); + info('FPS Data initialized'); + progress('native memory', 86); + await this.nativeMemory.initNativeMemory(); + progress('native memory', 87); + await this.nativeMemory.initChart(); + info('Native Memory Data initialized'); + progress('js memory', 87.5); + await this.jsMemory.initChart(); + info('js Memory Data initialized'); + progress('ability monitor', 88); + await this.abilityMonitor.init(); + progress('hiSysevent', 88.2); + await this.hiSyseventChart.init(); + info('Perf Files Data initialized'); + progress('vm tracker', 88.4); + await this.smapsChart.init(); + progress('sdk', 88.6); + await this.sdkChart.init(); + progress('perf', 88.8); + await this.perf!.init(); + progress('file system', 89); + await this.fileSystem!.init(); + info('Ability Monitor Data initialized'); + await perfDataQuery.initPerfCache(); + info('HiPerf Data initialized'); + await this.frameTimeChart.init(); + progress('process', 90); + await this.process.initAsyncFuncData(); + await this.process.initDeliverInputEvent(); + await this.process.init(); + info('Process Data initialized'); + progress('display', 95); + } + + async importSoFileUpdate() { + SpSystemTrace.DATA_DICT.clear(); + let dict = await queryDataDICT(); + dict.map((d) => SpSystemTrace.DATA_DICT.set(d['id'], d['data'])); + await perfDataQuery.initPerfCache(); + await this.nativeMemory.initNativeMemory(); + await this.fileSystem.initFileCallchain(); + this.perf.updateChartData(); + } + + handleProcessThread(arr: { id: number; name: string; type: string }[]) { + Utils.PROCESS_MAP.clear(); + Utils.THREAD_MAP.clear(); + for (let pt of arr) { + if (pt.type === 'p') { + Utils.PROCESS_MAP.set(pt.id, pt.name); + } else { + Utils.THREAD_MAP.set(pt.id, pt.name); + } + } + } + + initTotalTime = async () => { + let res = await queryTotalTime(); + if (this.trace.timerShaftEL) { + let total = res[0].total; + let startNS = res[0].recordStartNS; + let endNS = res[0].recordEndNS; + if (total === 0 && startNS === endNS) { + total = 1; + endNS = startNS + 1; + } + this.trace.timerShaftEL.totalNS = total; + (window as any).recordStartNS = startNS; + (window as any).recordEndNS = endNS; + (window as any).totalNS = total; + this.trace.timerShaftEL.loadComplete = true; + } + }; + + initCpuRate = async () => { + let rates = await getCpuUtilizationRate(0, this.trace.timerShaftEL?.totalNS || 0); + if (this.trace.timerShaftEL) this.trace.timerShaftEL.cpuUsage = rates; + info('Cpu UtilizationRate data size is: ', rates.length); + }; +} + +export const FolderSupplier = () => { + return () => new Promise>((resolve) => resolve([])); +}; +export const FolderThreadHandler = (row: TraceRow, trace: SpSystemTrace) => { + return (useCache: boolean) => { + row.canvasSave(trace.canvasPanelCtx!); + if (row.expansion) { + trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + row + ); + } + row.canvasRestore(trace.canvasPanelCtx!); + }; +}; diff --git a/ide/src/trace/component/chart/SpClockChart.ts b/ide/src/trace/component/chart/SpClockChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..22503d0a3815f9ea2f9046927f6aa11eb1e38bec --- /dev/null +++ b/ide/src/trace/component/chart/SpClockChart.ts @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { queryClockData, queryClockFrequency, queryClockState, queryScreenState } from '../../database/SqlLite.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { info } from '../../../log/Log.js'; +import { ClockRender, ClockStruct } from '../../database/ui-worker/ProcedureWorkerClock.js'; +import { ColorUtils } from '../trace/base/ColorUtils.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { Utils } from '../trace/base/Utils.js'; + +export class SpClockChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let folder = await this.initFolder(); + await this.initData(folder); + } + + async initData(folder: TraceRow) { + let clockStartTime = new Date().getTime(); + let clockList = await queryClockData(); + if (clockList.length == 0) { + return; + } + info('clockList data size is: ', clockList!.length); + this.trace.rowsEL?.appendChild(folder); + ClockStruct.maxValue = clockList.map((item) => item.num).reduce((a, b) => Math.max(a, b)); + for (let i = 0; i < clockList.length; i++) { + const it = clockList[i]; + let maxValue = 0; + let traceRow = TraceRow.skeleton(); + let isState = it.name.endsWith(' State'); + let isScreenState = it.name.endsWith('ScreenState'); + traceRow.rowId = it.name; + traceRow.rowType = TraceRow.ROW_TYPE_CLOCK; + traceRow.rowParentId = folder.rowId; + traceRow.style.height = '40px'; + traceRow.name = it.name; + traceRow.rowHidden = !folder.expansion; + traceRow.setAttribute('children', ''); + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.supplier = () => { + let promiseData = null; + if (it.name.endsWith(' Frequency')) { + promiseData = queryClockFrequency(it.srcname); + } else if (isState) { + promiseData = queryClockState(it.srcname); + } else if (isScreenState) { + promiseData = queryScreenState(); + } + if (promiseData == null) { + return new Promise>((resolve) => resolve([])); + } else { + return promiseData.then((res) => { + for (let j = 0; j < res.length; j++) { + if (!isState) { + if (j == res.length - 1) { + res[j].dur = (TraceRow.range?.totalNS || 0) - (res[j].startNS || 0); + } else { + res[j].dur = (res[j + 1].startNS || 0) - (res[j].startNS || 0); + } + } + if ((res[j].value || 0) > maxValue) { + maxValue = res[j].value || 0; + } + if (j > 0) { + res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0); + } else { + res[j].delta = 0; + } + } + return res; + }); + } + }; + traceRow.focusHandler = (ev) => { + this.trace?.displayTip( + traceRow, + ClockStruct.hoverClockStruct, + `${ColorUtils.formatNumberComma(ClockStruct.hoverClockStruct?.value!)}` + ); + }; + traceRow.onThreadHandler = (useCache) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders['clock'] as ClockRender).renderMainThread( + { + context: context, + useCache: useCache, + type: it.name, + maxValue: maxValue === 0 ? 1 : maxValue, + index: i, + maxName: + isState || isScreenState ? maxValue.toString() : Utils.getFrequencyWithUnit(maxValue / 1000).maxFreqName, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + folder.addChildTraceRow(traceRow); + } + let durTime = new Date().getTime() - clockStartTime; + info('The time to load the ClockData is: ', durTime); + } + + async initFolder(): Promise> { + let folder = TraceRow.skeleton(); + folder.rowId = `Clocks`; + folder.index = 0; + folder.rowType = TraceRow.ROW_TYPE_CLOCK_GROUP; + folder.rowParentId = ''; + folder.style.height = '40px'; + folder.folder = true; + folder.name = `Clocks`; /* & I/O Latency */ + folder.favoriteChangeHandler = this.trace.favoriteChangeHandler; + folder.selectChangeHandler = this.trace.selectChangeHandler; + folder.supplier = () => new Promise>((resolve) => resolve([])); + folder.onThreadHandler = (useCache) => { + folder.canvasSave(this.trace.canvasPanelCtx!); + if (folder.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + folder + ); + } + folder.canvasRestore(this.trace.canvasPanelCtx!); + }; + return folder; + } +} diff --git a/ide/src/trace/component/chart/SpCpuChart.ts b/ide/src/trace/component/chart/SpCpuChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..366848796e2a95e6c592e72c97e61b4bed8d8e25 --- /dev/null +++ b/ide/src/trace/component/chart/SpCpuChart.ts @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { queryCpuCount, queryCpuData, queryCpuMax, queryCpuSchedSlice } from '../../database/SqlLite.js'; +import { info } from '../../../log/Log.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { CpuRender, CpuStruct } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { Utils } from '../trace/base/Utils.js'; + +export class SpCpuChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let CpuStartTime = new Date().getTime(); + let array = await queryCpuMax(); + let cpuCountResult = await queryCpuCount(); + if (cpuCountResult && cpuCountResult.length > 0 && cpuCountResult[0]) { + (window as any).cpuCount = cpuCountResult[0].cpuCount; + } else { + (window as any).cpuCount = 0; + } + let cpuSchedSlice = await queryCpuSchedSlice(); + this.initSchedSliceData(cpuSchedSlice); + info('Cpu trace row data size is: ', array.length); + if (array && array.length > 0 && array[0]) { + let cpuMax = array[0].cpu; + CpuStruct.cpuCount = cpuMax + 1; + for (let i1 = 0; i1 < CpuStruct.cpuCount; i1++) { + const cpuId = i1; + let traceRow = TraceRow.skeleton(); + traceRow.rowId = `${cpuId}`; + traceRow.rowType = TraceRow.ROW_TYPE_CPU; + traceRow.rowParentId = ''; + traceRow.style.height = '40px'; + traceRow.name = `Cpu ${cpuId}`; + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.supplier = () => + queryCpuData(cpuId, TraceRow.range?.startNS || 0, TraceRow.range?.endNS || 0).then((res) => { + res.forEach((it, i, arr) => { + let p = Utils.PROCESS_MAP.get(it.processId!); + let t = Utils.THREAD_MAP.get(it.tid!); + let slice = Utils.SCHED_SLICE_MAP.get(`${it.id}-${it.startTime}`); + if (slice) { + it.end_state = slice.endState; + it.priority = slice.priority; + } + it.processName = p; + it.processCmdLine = p; + it.name = t; + it.type = 'thread'; + if (i !== arr.length - 1) { + if (it.startTime! + it.dur! > arr[i + 1]!.startTime! || it.dur == -1) { + it.dur = arr[i + 1]!.startTime! - it.startTime!; + it.nofinish = true; + } + } else { + if (it.dur == -1) { + it.dur = TraceRow.range!.endNS - it.startTime!; + it.nofinish = true; + } + } + }); + return res; + }); + traceRow.focusHandler = () => { + this.trace?.displayTip( + traceRow, + CpuStruct.hoverCpuStruct, + `P:${CpuStruct.hoverCpuStruct?.processName || 'Process'} [${ + CpuStruct.hoverCpuStruct?.processId + }]T:${CpuStruct.hoverCpuStruct?.name} [${CpuStruct.hoverCpuStruct?.tid}] [Prio:${ + CpuStruct.hoverCpuStruct?.priority || 0 + }]` + ); + }; + traceRow.onThreadHandler = (useCache: boolean, buf: ArrayBuffer | undefined | null) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders['cpu-data'] as CpuRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `cpu-data-${i1}`, + translateY: traceRow.translateY, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(traceRow); + } + } + let CpuDurTime = new Date().getTime() - CpuStartTime; + info('The time to load the Cpu data is: ', CpuDurTime); + } + + initProcessThreadStateData = async (progress: Function) => { + let time = new Date().getTime(); + SpSystemTrace.SPT_DATA = []; + progress('StateProcessThread', 93); + procedurePool.submitWithName('logic1', 'spt-init', {}, undefined, (res: any) => { + SpSystemTrace.SPT_DATA = Array.from(res); + }); + let durTime = new Date().getTime() - time; + info('The time to load the first ProcessThreadState data is: ', durTime); + }; + + initCpuIdle0Data = async (progress: Function) => { + let time = new Date().getTime(); + progress('CPU Idle', 94); + procedurePool.submitWithName( + 'logic1', + 'scheduling-getCpuIdle0', + { + endTs: (window as any).recordEndNS, + total: (window as any).totalNS, + }, + undefined, + (res: any) => {} + ); + let durTime = new Date().getTime() - time; + info('The time to load the first CPU Idle0 data is: ', durTime); + }; + + initSchedSliceData(arr: any[]) { + Utils.SCHED_SLICE_MAP.clear(); + arr.forEach((value) => { + Utils.SCHED_SLICE_MAP.set(`${value.itid}-${value.ts}`, { endState: value.endState, priority: value.priority }); + }); + } + + initSchedulingPTData = async (progress: Function) => { + let time = new Date().getTime(); + progress('CPU Idle', 94); + procedurePool.submitWithName('logic1', 'scheduling-getProcessAndThread', {}, undefined, (res: any) => {}); + let durTime = new Date().getTime() - time; + info('The time to load the first CPU Idle0 data is: ', durTime); + }; + + initSchedulingFreqData = async (progress: Function) => { + let time = new Date().getTime(); + progress('CPU Scheduling Freq', 94); + procedurePool.submitWithName('logic1', 'scheduling-initFreqData', {}, undefined, (res: any) => {}); + let durTime = new Date().getTime() - time; + info('The time to load the first CPU Idle0 data is: ', durTime); + }; +} diff --git a/ide/src/trace/component/chart/SpFileSystemChart.ts b/ide/src/trace/component/chart/SpFileSystemChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..461ea7614d97e3ff7f40f36f738b439634b747be --- /dev/null +++ b/ide/src/trace/component/chart/SpFileSystemChart.ts @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { + getDiskIOLatencyChartDataByProcess, + getDiskIOProcess, + getFileSysChartDataByType, + getFileSysVirtualMemoryChartData, + hasFileSysData, +} from '../../database/SqlLite.js'; +import { FileSysChartStruct, FileSystemRender } from '../../database/ui-worker/ProcedureWorkerFileSystem.js'; +import { ColorUtils } from '../trace/base/ColorUtils.js'; +import { Utils } from '../trace/base/Utils.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class SpFileSystemChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let sys = await hasFileSysData(); + if (sys.length > 0) { + let fsCount = sys[0]['fsCount'] ?? 0; + let vmCount = sys[0]['vmCount'] ?? 0; + let ioCount = sys[0]['ioCount'] ?? 0; + if (sys && sys.length > 0 && (fsCount > 0 || vmCount > 0 || ioCount > 0)) { + let folder = await this.initFolder(); + await this.initFileCallchain(); + if (fsCount > 0) { + await this.initLogicalRead(folder); + await this.initLogicalWrite(folder); + } + if (vmCount > 0) { + await this.initVirtualMemoryTrace(folder); + } + if (ioCount > 0) { + await this.initDiskIOLatency(folder); + await this.initProcessDiskIOLatency(folder); + } + } + } + } + + async initFileCallchain() { + return new Promise((resolve, reject) => { + procedurePool.submitWithName('logic0', 'fileSystem-init', SpSystemTrace.DATA_DICT, undefined, (res: any) => { + resolve(res); + }); + }); + } + + async initFolder(): Promise> { + let folder = TraceRow.skeleton(); + folder.rowId = `FileSystem`; + folder.index = 0; + folder.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM_GROUP; + folder.rowParentId = ''; + folder.style.height = '40px'; + folder.folder = true; + folder.name = `EBPF`; /* & I/O Latency */ + folder.favoriteChangeHandler = this.trace.favoriteChangeHandler; + folder.selectChangeHandler = this.trace.selectChangeHandler; + folder.supplier = () => new Promise>((resolve) => resolve([])); + folder.onThreadHandler = (useCache) => { + folder.canvasSave(this.trace.canvasPanelCtx!); + if (folder.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + folder + ); + } + folder.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(folder); + return folder; + } + + async initLogicalRead(folder: TraceRow) { + let row = TraceRow.skeleton(); + row.rowId = `FileSystemLogicalRead`; + row.index = 1; + row.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM; + row.rowParentId = folder.rowId; + row.rowHidden = !folder.expansion; + row.style.height = '40px'; + row.setAttribute('children', ''); + row.name = `FileSystem Logical Read`; + row.supplier = () => getFileSysChartDataByType(2); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.focusHandler = () => this.focusHandler(row); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-logical-read`, + chartColor: ColorUtils.MD_PALETTE[0], + }, + row + ); + row.canvasRestore(context); + }; + folder.addChildTraceRow(row); + } + + async initLogicalWrite(folder: TraceRow) { + let row = TraceRow.skeleton(); + row.rowId = `FileSystemLogicalWrite`; + row.index = 2; + row.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM; + row.rowParentId = folder.rowId; + row.rowHidden = !folder.expansion; + row.style.height = '40px'; + row.setAttribute('children', ''); + row.name = `FileSystem Logical Write`; + row.supplier = () => getFileSysChartDataByType(3); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.focusHandler = () => this.focusHandler(row); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-logical-write`, + chartColor: ColorUtils.MD_PALETTE[8], + }, + row + ); + row.canvasRestore(context); + }; + folder.addChildTraceRow(row); + } + + async initDiskIOLatency(folder: TraceRow) { + let row = TraceRow.skeleton(); + row.rowId = `FileSystemDiskIOLatency`; + row.index = 4; + row.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM; + row.rowParentId = folder.rowId; + row.rowHidden = !folder.expansion; + row.style.height = '40px'; + row.style.width = `100%`; + row.setAttribute('children', ''); + row.name = `Disk I/O Latency`; + row.supplier = () => getDiskIOLatencyChartDataByProcess(true, 0, [1, 2, 3, 4]); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.focusHandler = () => this.focusHandler(row); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io`, + chartColor: ColorUtils.MD_PALETTE[0], + }, + row + ); + row.canvasRestore(context); + }; + folder.addChildTraceRow(row); + } + + async initProcessDiskIOLatency(folder: TraceRow) { + let processes = (await getDiskIOProcess()) || []; + for (let i = 0, len = processes.length; i < len; i++) { + let process = processes[i]; + let rowRead = TraceRow.skeleton(); + rowRead.index = 5 + 2 * i; + rowRead.rowId = `FileSystemDiskIOLatency-read-${process['ipid']}`; + rowRead.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM; + rowRead.rowParentId = folder.rowId; + rowRead.rowHidden = !folder.expansion; + rowRead.style.height = '40px'; + rowRead.style.width = `100%`; + rowRead.setAttribute('children', ''); + rowRead.name = `${process['name'] ?? 'Process'}(${process['pid']}) Max Read Latency`; + rowRead.supplier = () => getDiskIOLatencyChartDataByProcess(false, process['ipid'], [1, 3]); + rowRead.favoriteChangeHandler = this.trace.favoriteChangeHandler; + rowRead.selectChangeHandler = this.trace.selectChangeHandler; + rowRead.focusHandler = () => this.focusHandler(rowRead); + rowRead.onThreadHandler = (useCache) => { + let context = rowRead.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + rowRead.canvasSave(context); + (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io-process-read-${process['pid']}`, + chartColor: ColorUtils.MD_PALETTE[0], + }, + rowRead + ); + rowRead.canvasRestore(context); + }; + folder.addChildTraceRow(rowRead); + let rowWrite = TraceRow.skeleton(); + rowWrite.index = 5 + 2 * i + 1; + rowWrite.rowId = `FileSystemDiskIOLatency-write-${process['ipid']}`; + rowWrite.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM; + rowWrite.rowParentId = folder.rowId; + rowWrite.rowHidden = !folder.expansion; + rowWrite.style.height = '40px'; + rowWrite.style.width = `100%`; + rowWrite.setAttribute('children', ''); + rowWrite.name = `${process['name'] ?? 'Process'}(${process['pid']}) Max Write Latency`; + rowWrite.supplier = () => getDiskIOLatencyChartDataByProcess(false, process['ipid'], [2, 4]); + rowWrite.favoriteChangeHandler = this.trace.favoriteChangeHandler; + rowWrite.selectChangeHandler = this.trace.selectChangeHandler; + rowWrite.focusHandler = () => this.focusHandler(rowWrite); + rowWrite.onThreadHandler = (useCache) => { + let context = rowWrite.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + rowWrite.canvasSave(context); + (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-disk-io-process-write-${process['pid']}`, + chartColor: ColorUtils.MD_PALETTE[8], + }, + rowWrite + ); + rowWrite.canvasRestore(context); + }; + folder.addChildTraceRow(rowWrite); + } + } + + async initVirtualMemoryTrace(folder: TraceRow) { + let row = TraceRow.skeleton(); + row.rowId = `FileSystemVirtualMemory`; + row.index = 3; + row.rowType = TraceRow.ROW_TYPE_FILE_SYSTEM; + row.rowParentId = folder.rowId; + row.rowHidden = !folder.expansion; + row.rangeSelect = true; + row.style.height = '40px'; + row.style.width = `100%`; + row.setAttribute('children', ''); + row.name = `Page Fault Trace`; + row.supplier = () => getFileSysVirtualMemoryChartData(); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.focusHandler = () => this.focusHandler(row); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders[TraceRow.ROW_TYPE_FILE_SYSTEM] as FileSystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `${TraceRow.ROW_TYPE_FILE_SYSTEM}-virtual-memory`, + chartColor: ColorUtils.MD_PALETTE[0], + }, + row + ); + row.canvasRestore(context); + }; + folder.addChildTraceRow(row); + } + + focusHandler(row: TraceRow) { + let num = 0; + let tip = ''; + if (FileSysChartStruct.hoverFileSysStruct) { + num = FileSysChartStruct.hoverFileSysStruct.size ?? 0; + let group10Ms = FileSysChartStruct.hoverFileSysStruct.group10Ms ?? false; + if (row.rowId!.startsWith('FileSystemDiskIOLatency')) { + if (num > 0) { + let tipStr = Utils.getProbablyTime(num); + if (group10Ms) { + tip = `${tipStr} (10.00ms)`; + } else { + tip = `${tipStr}`; + } + } + } else { + if (num > 0) { + if (group10Ms) { + tip = `${num} (10.00ms)`; + } else { + tip = `${num}`; + } + } + } + } + this.trace?.displayTip(row, FileSysChartStruct.hoverFileSysStruct, tip); + } +} diff --git a/ide/src/trace/component/chart/SpFpsChart.ts b/ide/src/trace/component/chart/SpFpsChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..15916cedf4799d8d4b73a989cde0fb18bb5ca59f --- /dev/null +++ b/ide/src/trace/component/chart/SpFpsChart.ts @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { getFps } from '../../database/SqlLite.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { info } from '../../../log/Log.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { FpsRender, FpsStruct } from '../../database/ui-worker/ProcedureWorkerFPS.js'; + +export class SpFpsChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let res = await getFps(); + if (res.length == 0) { + return; + } + let startTime = new Date().getTime(); + let fpsRow = TraceRow.skeleton(); + fpsRow.rowId = `fps`; + fpsRow.rowType = TraceRow.ROW_TYPE_FPS; + fpsRow.rowParentId = ''; + FpsStruct.maxFps = 0; + fpsRow.style.height = '40px'; + fpsRow.name = 'FPS'; + fpsRow.supplier = () => new Promise>((resolve, reject) => resolve(res)); + fpsRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + fpsRow.selectChangeHandler = this.trace.selectChangeHandler; + fpsRow.focusHandler = (ev) => { + let tip = ''; + if (FpsStruct.hoverFpsStruct) { + tip = `${FpsStruct.hoverFpsStruct.fps || 0} `; + } + this.trace?.displayTip(fpsRow, FpsStruct.hoverFpsStruct, tip); + }; + + fpsRow.onThreadHandler = (useCache) => { + let context = fpsRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + fpsRow.canvasSave(context); + (renders['fps'] as FpsRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `fps0`, + }, + fpsRow + ); + fpsRow.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(fpsRow); + let durTime = new Date().getTime() - startTime; + info('The time to load the FPS data is: ', durTime); + } +} diff --git a/ide/src/trace/component/chart/SpFrameTimeChart.ts b/ide/src/trace/component/chart/SpFrameTimeChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..2284e86fb17924d4dc0ced09a609b4055dceceb2 --- /dev/null +++ b/ide/src/trace/component/chart/SpFrameTimeChart.ts @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2022 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 { TraceRow } from '../trace/base/TraceRow.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { JankRender, JankStruct } from '../../database/ui-worker/ProcedureWorkerJank.js'; +import { SpSystemTrace } from '../SpSystemTrace.js'; +import { queryActualFrameDate, queryExpectedFrameDate, queryFrameTimeData } from '../../database/SqlLite.js'; +import { JanksStruct } from '../../bean/JanksStruct.js'; +import { ns2xByTimeShaft } from '../../database/ui-worker/ProcedureWorkerCommon.js'; + +export class SpFrameTimeChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let frameTimeData = await queryFrameTimeData(); + if (frameTimeData.length > 0) { + let frameTimeLineRow = await this.initFrameTimeLine(); + await this.initExpectedChart(frameTimeLineRow); + await this.initActualChart(frameTimeLineRow); + } + } + + async initFrameTimeLine() { + let frameTimeLineRow = TraceRow.skeleton(); + frameTimeLineRow.rowId = `frameTime`; + frameTimeLineRow.rowType = TraceRow.ROW_TYPE_JANK; + frameTimeLineRow.rowParentId = ``; + frameTimeLineRow.style.width = `100%`; + frameTimeLineRow.style.height = `40px`; + frameTimeLineRow.folder = true; + frameTimeLineRow.name = `FrameTimeline`; + frameTimeLineRow.setAttribute('children', ''); + frameTimeLineRow.supplier = () => + new Promise((resolve) => { + resolve([]); + }); + frameTimeLineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + frameTimeLineRow.selectChangeHandler = this.trace.selectChangeHandler; + frameTimeLineRow.onThreadHandler = (useCache) => { + let context = frameTimeLineRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + frameTimeLineRow!.canvasSave(context); + (renders['jank'] as JankRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `expected_frame_timeline_slice`, + }, + frameTimeLineRow! + ); + frameTimeLineRow!.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(frameTimeLineRow); + return frameTimeLineRow; + } + + async initExpectedChart(frameTimeLineRow: TraceRow) { + let frameExpectedData = await queryExpectedFrameDate(); + if (frameExpectedData.length > 0) { + let isIntersect = (a: JanksStruct, b: JanksStruct) => + Math.max(a.ts! + a.dur!, b.ts! + b.dur!) - Math.min(a.ts!, b.ts!) < a.dur! + b.dur!; + let depthArray: any = []; + for (let i = 0; i < frameExpectedData.length; i++) { + let it = frameExpectedData[i]; + if (!it.dur || it.dur < 0) { + continue; + } + if (depthArray.length == 0) { + it.depth = 0; + depthArray[0] = it; + } else { + let index = 0; + let isContinue = true; + while (isContinue) { + if (isIntersect(depthArray[index], it)) { + if (depthArray[index + 1] == undefined || !depthArray[index + 1]) { + it.depth = index + 1; + depthArray[index + 1] = it; + isContinue = false; + } + } else { + it.depth = index; + depthArray[index] = it; + isContinue = false; + } + index++; + } + } + } + } + let max = Math.max(...frameExpectedData.map((it) => it.depth || 0)) + 1; + let maxHeight = max * 20; + let expectedTimeLineRow = TraceRow.skeleton(); + expectedTimeLineRow.rowId = `expected frameTime`; + expectedTimeLineRow.rowType = TraceRow.ROW_TYPE_JANK; + expectedTimeLineRow.rowHidden = !frameTimeLineRow.expansion; + expectedTimeLineRow.rowParentId = `frameTime`; + expectedTimeLineRow.style.width = `100%`; + expectedTimeLineRow.style.height = `40px`; + expectedTimeLineRow.style.height = `${maxHeight}px`; + expectedTimeLineRow.name = `Expected Timeline`; + expectedTimeLineRow.setAttribute('height', `${maxHeight}`); + expectedTimeLineRow.setAttribute('children', ''); + expectedTimeLineRow.supplier = () => + new Promise((resolve) => { + resolve(frameExpectedData); + }); + expectedTimeLineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + expectedTimeLineRow.selectChangeHandler = this.trace.selectChangeHandler; + expectedTimeLineRow.onThreadHandler = (useCache) => { + let context = expectedTimeLineRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + expectedTimeLineRow!.canvasSave(context); + (renders['jank'] as JankRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `expected_frame_timeline_slice`, + }, + expectedTimeLineRow! + ); + expectedTimeLineRow!.canvasRestore(context); + }; + frameTimeLineRow.addChildTraceRow(expectedTimeLineRow); + } + + async initActualChart(frameTimeLineRow: TraceRow) { + let frameActualData = await queryActualFrameDate(); + if (frameActualData.length > 0) { + let isIntersect = (a: JanksStruct, b: JanksStruct) => + Math.max(a.ts! + a.dur!, b.ts! + b.dur!) - Math.min(a.ts!, b.ts!) < a.dur! + b.dur!; + let depthArray: any = []; + for (let i = 0; i < frameActualData.length; i++) { + let it = frameActualData[i]; + if (!it.dur || it.dur < 0) { + continue; + } + if (depthArray.length == 0) { + it.depth = 0; + depthArray[0] = it; + } else { + let index = 0; + let isContinue = true; + while (isContinue) { + if (isIntersect(depthArray[index], it)) { + if (depthArray[index + 1] == undefined || !depthArray[index + 1]) { + it.depth = index + 1; + depthArray[index + 1] = it; + isContinue = false; + } + } else { + it.depth = index; + depthArray[index] = it; + isContinue = false; + } + index++; + } + } + } + } + + let max = Math.max(...frameActualData.map((it) => it.depth || 0)) + 1; + let maxHeight = max * 20; + let actualTimeLineRow = TraceRow.skeleton(); + actualTimeLineRow.rowId = `actual frameTime`; + actualTimeLineRow.rowType = TraceRow.ROW_TYPE_JANK; + actualTimeLineRow.rowHidden = !frameTimeLineRow.expansion; + actualTimeLineRow.rowParentId = `frameTime`; + actualTimeLineRow.style.width = `100%`; + actualTimeLineRow.style.height = `${maxHeight}px`; + actualTimeLineRow.name = `Actual Timeline`; + actualTimeLineRow.setAttribute('height', `${maxHeight}`); + actualTimeLineRow.setAttribute('children', ''); + actualTimeLineRow.dataList = frameActualData; + actualTimeLineRow.supplier = () => + new Promise((resolve) => { + resolve(frameActualData); + }); + actualTimeLineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + actualTimeLineRow.selectChangeHandler = this.trace.selectChangeHandler; + actualTimeLineRow.onThreadHandler = (useCache) => { + let context = actualTimeLineRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + actualTimeLineRow!.canvasSave(context); + (renders['jank'] as JankRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `expected_frame_timeline_slice`, + }, + actualTimeLineRow! + ); + actualTimeLineRow!.canvasRestore(context); + }; + frameTimeLineRow.addChildTraceRow(actualTimeLineRow); + let offsetYTimeOut: any = undefined; + frameTimeLineRow.addEventListener('expansion-change', (e: any) => { + if (offsetYTimeOut) { + clearTimeout(offsetYTimeOut); + } + if (e.detail.expansion) { + if (JankStruct!.selectJankStruct) { + JankStruct.delJankLineFlag = true; + } else { + JankStruct.delJankLineFlag = false; + } + offsetYTimeOut = setTimeout(() => { + this.trace.linkNodes.forEach((linkNode) => { + JankStruct.selectJankStructList?.forEach((dat: any) => { + if (e.detail.rowId == dat.pid) { + JankStruct.selectJankStruct = dat; + JankStruct.hoverJankStruct = dat; + } + }); + if (linkNode[0].rowEL.collect) { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY; + if (linkNode[1].rowEL.collect) { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY; + if (linkNode[0].rowEL.rowId == e.detail.rowId) { + linkNode[0].x = ns2xByTimeShaft(linkNode[0].ns, this.trace.timerShaftEL!); + linkNode[0].y = actualTimeLineRow!.translateY! + linkNode[0].offsetY * 2; + linkNode[0].offsetY = linkNode[0].offsetY * 2; + linkNode[0].rowEL = actualTimeLineRow; + } else if (linkNode[1].rowEL.rowId == e.detail.rowId) { + linkNode[1].x = ns2xByTimeShaft(linkNode[1].ns, this.trace.timerShaftEL!); + linkNode[1].y = actualTimeLineRow!.translateY! + linkNode[1].offsetY * 2; + linkNode[1].offsetY = linkNode[1].offsetY * 2; + linkNode[1].rowEL = actualTimeLineRow!; + } + }); + }, 300); + } else { + JankStruct.delJankLineFlag = false; + if (JankStruct!.selectJankStruct) { + JankStruct.selectJankStructList?.push(JankStruct!.selectJankStruct); + } + offsetYTimeOut = setTimeout(() => { + this.trace.linkNodes.forEach((linkNode) => { + if (linkNode[0].rowEL.collect) { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY; + if (linkNode[1].rowEL.collect) { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY; + if (linkNode[0].rowEL.rowParentId == e.detail.rowId) { + linkNode[0].x = ns2xByTimeShaft(linkNode[0].ns, this.trace.timerShaftEL!); + linkNode[0].y = frameTimeLineRow!.translateY! + linkNode[0].offsetY / 2; + linkNode[0].offsetY = linkNode[0].offsetY / 2; + linkNode[0].rowEL = frameTimeLineRow; + } else if (linkNode[1].rowEL.rowParentId == e.detail.rowId) { + linkNode[1].x = ns2xByTimeShaft(linkNode[1].ns, this.trace.timerShaftEL!); + linkNode[1].y = frameTimeLineRow!.translateY! + linkNode[1].offsetY / 2; + linkNode[1].offsetY = linkNode[1].offsetY / 2; + linkNode[1].rowEL = frameTimeLineRow!; + } + }); + }, 300); + } + let refreshTimeOut = setTimeout(() => { + this.trace.refreshCanvas(true); + clearTimeout(refreshTimeOut); + }, 360); + }); + } +} diff --git a/ide/src/trace/component/chart/SpFreqChart.ts b/ide/src/trace/component/chart/SpFreqChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..d869a822f5aca7bf4839624c50631f06d1ef8c93 --- /dev/null +++ b/ide/src/trace/component/chart/SpFreqChart.ts @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { + getCpuLimitFreq, + getCpuLimitFreqId, + getCpuLimitFreqMax, + queryCpuFreq, + queryCpuFreqData, + queryCpuMaxFreq, + queryCpuState, + queryCpuStateFilter, +} from '../../database/SqlLite.js'; +import { info } from '../../../log/Log.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { ColorUtils } from '../trace/base/ColorUtils.js'; +import { CpuFreqLimitRender, CpuFreqLimitsStruct } from '../../database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { CpuStruct } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { CpuFreqStruct, FreqRender } from '../../database/ui-worker/ProcedureWorkerFreq.js'; +import { CpuStateRender, CpuStateStruct } from '../../database/ui-worker/ProcedureWorkerCpuState.js'; + +export class SpFreqChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let cpuFreqStartTime = new Date().getTime(); + let freqList = await queryCpuFreq(); + let cpuStateFilterIds = await queryCpuStateFilter(); + let cpuFreqLimits = await getCpuLimitFreqId(); + let cpuFreqLimitsMax = await getCpuLimitFreqMax( + cpuFreqLimits + .map((limit) => { + return limit.maxFilterId; + }) + .join(',') + ); + info('Cpu Freq data size is: ', freqList!.length); + let freqMaxList = await queryCpuMaxFreq(); + CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq; + let maxFreqObj = this.math(freqMaxList[0].maxFreq); + CpuFreqStruct.maxFreq = maxFreqObj.maxFreq; + CpuFreqStruct.maxFreqName = maxFreqObj.maxFreqName; + for (let i = 0; i < freqList.length; i++) { + const it = freqList[i]; + let traceRow = TraceRow.skeleton(); + traceRow.rowId = `${it.filterId}`; + traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ; + traceRow.rowParentId = ''; + traceRow.style.height = '40px'; + traceRow.name = `Cpu ${it.cpu} Frequency`; + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.supplier = () => queryCpuFreqData(it.cpu); + traceRow.focusHandler = (ev) => { + this.trace?.displayTip( + traceRow, + CpuFreqStruct.hoverCpuFreqStruct, + `${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct?.value!)} kHz` + ); + }; + traceRow.onThreadHandler = (useCache) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders['freq'] as FreqRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `freq${it.cpu}`, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(traceRow); + } + let heights = [4, 12, 21, 30]; + for (let it of cpuStateFilterIds) { + let cpuStateRow = TraceRow.skeleton(); + cpuStateRow.rowId = `${it.filterId}`; + cpuStateRow.rowType = TraceRow.ROW_TYPE_CPU_STATE; + cpuStateRow.rowParentId = ''; + cpuStateRow.style.height = '40px'; + cpuStateRow.name = `Cpu ${it.cpu} State`; + cpuStateRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + cpuStateRow.selectChangeHandler = this.trace.selectChangeHandler; + cpuStateRow.isHover = true; + cpuStateRow.supplier = () => + queryCpuState(it.filterId).then((res) => { + res.forEach((r) => { + r.height = heights[it.value]; + r.cpu = it.cpu; + }); + return res; + }); + cpuStateRow.focusHandler = (ev) => { + this.trace.displayTip( + cpuStateRow, + CpuStateStruct.hoverStateStruct, + `State: ${CpuStateStruct.hoverStateStruct?.value}` + ); + }; + cpuStateRow.onThreadHandler = (useCache: boolean) => { + let context = cpuStateRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + cpuStateRow.canvasSave(context); + (renders['cpu-state'] as CpuStateRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `cpu-state-${it.cpu}`, + cpu: it.cpu, + }, + cpuStateRow + ); + cpuStateRow.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(cpuStateRow); + } + let durTime = new Date().getTime() - cpuFreqStartTime; + info('The time to load the CpuFreq data is: ', durTime); + for (let limit of cpuFreqLimits) { + let findMax = this.math( + cpuFreqLimitsMax.find((maxLimit) => { + return maxLimit.filterId == limit.maxFilterId; + })?.maxValue || 0 + ); + let cpuFreqLimitRow = TraceRow.skeleton(); + cpuFreqLimitRow.rowId = `${limit.cpu}`; + cpuFreqLimitRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ_LIMIT; + cpuFreqLimitRow.rowParentId = ''; + cpuFreqLimitRow.style.height = '40px'; + cpuFreqLimitRow.name = `Cpu ${limit.cpu} Freq Limit`; + cpuFreqLimitRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + cpuFreqLimitRow.selectChangeHandler = this.trace.selectChangeHandler; + cpuFreqLimitRow.isHover = true; + cpuFreqLimitRow.supplier = () => getCpuLimitFreq(limit.maxFilterId, limit.minFilterId, limit.cpu); + cpuFreqLimitRow.focusHandler = (ev) => { + this.trace.displayTip( + cpuFreqLimitRow, + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct, + `Max Freq: ${ColorUtils.formatNumberComma( + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct?.max || 0 + )} kHzMin Freq: ${ColorUtils.formatNumberComma( + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct?.min || 0 + )} kHz` + ); + }; + cpuFreqLimitRow.onThreadHandler = (useCache: boolean) => { + let context = cpuFreqLimitRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + cpuFreqLimitRow.canvasSave(context); + (renders['cpu-limit-freq'] as CpuFreqLimitRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `cpu-limit-freq-${limit.cpu}`, + cpu: limit.cpu, + maxFreq: findMax?.maxFreq || 0, + maxFreqName: findMax?.maxFreqName || '', + }, + cpuFreqLimitRow + ); + cpuFreqLimitRow.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(cpuFreqLimitRow); + } + } + + math = (maxFreq: number) => { + let maxFreqObj = { + maxFreqName: ' ', + maxFreq: 0, + }; + let units: Array = ['', 'K', 'M', 'G', 'T', 'E']; + let sb = ' '; + if (maxFreq > 0) { + let log10: number = Math.ceil(Math.log10(maxFreq)); + let pow10: number = Math.pow(10, log10); + let afterCeil: number = Math.ceil(maxFreq / (pow10 / 4)) * (pow10 / 4); + maxFreqObj.maxFreq = afterCeil; + let unitIndex: number = Math.floor(log10 / 3); + sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}hz`; + } + maxFreqObj.maxFreqName = sb.toString(); + return maxFreqObj; + }; +} + +export class CpuFreqRowLimit { + cpu: number = 0; + maxFilterId: number = 0; + minFilterId: number = 0; +} diff --git a/ide/src/trace/component/chart/SpHiPerf.ts b/ide/src/trace/component/chart/SpHiPerf.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f678eb472ef605920b0f83359ea3a6e25e1402c --- /dev/null +++ b/ide/src/trace/component/chart/SpHiPerf.ts @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { + queryHiPerfCpuData, + queryHiPerfCpuMergeData, + queryHiPerfCpuMergeData2, + queryHiPerfEventData, + queryHiPerfEventList, + queryHiPerfEventListData, + queryHiPerfProcessData, + queryHiPerfThreadData, + queryPerfCmdline, + queryPerfThread, +} from '../../database/SqlLite.js'; +import { Utils } from '../trace/base/Utils.js'; +import { PerfThread } from '../../bean/PerfProfile.js'; +import { HiperfCpuRender, HiPerfCpuStruct } from '../../database/ui-worker/ProcedureWorkerHiPerfCPU.js'; +import { HiperfThreadRender, HiPerfThreadStruct } from '../../database/ui-worker/ProcedureWorkerHiPerfThread.js'; +import { HiperfProcessRender, HiPerfProcessStruct } from '../../database/ui-worker/ProcedureWorkerHiPerfProcess.js'; +import { info } from '../../../log/Log.js'; +import { HiperfEventRender, HiPerfEventStruct } from '../../database/ui-worker/ProcedureWorkerHiPerfEvent.js'; +import { perfDataQuery } from './PerfDataQuery.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { CpuRender, EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { HiperfReportRender, HiPerfReportStruct } from '../../database/ui-worker/ProcedureWorkerHiPerfReport.js'; +import { BaseStruct } from '../../database/ui-worker/ProcedureWorkerCommon.js'; +import { ProcessRender } from '../../database/ui-worker/ProcedureWorkerProcess.js'; + +export interface ResultData { + existA: boolean | null | undefined; + existF: boolean | null | undefined; + fValue: number; +} + +export class SpHiPerf { + static selectCpuStruct: HiPerfCpuStruct | undefined; + static selectProcessStruct: HiPerfProcessStruct | undefined; + static selectThreadStruct: HiPerfThreadStruct | undefined; + static stringResult: ResultData | undefined; + + private cpuData: Array | undefined; + public maxCpuId: number = 0; + private rowFolder!: TraceRow; + private perfThreads: Array | undefined; + private trace: SpSystemTrace; + private group: any; + private rowList: TraceRow[] | undefined; + private eventTypeList: Array<{ id: number; report_value: string }> = []; + + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + await this.initCmdLine(); + this.rowList = []; + this.perfThreads = await queryPerfThread(); + this.eventTypeList = await queryHiPerfEventList(); + info('PerfThread Data size is: ', this.perfThreads!.length); + this.group = Utils.groupBy(this.perfThreads || [], 'pid'); + this.cpuData = await queryHiPerfCpuMergeData2(); + this.maxCpuId = this.cpuData.length > 0 ? this.cpuData[0].cpu_id : -Infinity; + if (this.cpuData.length > 0) { + await this.initFolder(); + await this.initCpuMerge(); + await this.initCpu(); + await this.initProcess(); + } + info('HiPerf Data initialized'); + } + + getStringResult(s: string = '') { + let list = s.split(' ').filter((e) => e); + let sA = list.findIndex((item) => item == '-a'); + let sF = list.findIndex((item) => item == '-f'); + SpHiPerf.stringResult = { + existA: sA !== -1, + existF: sF !== -1, + fValue: Number((1000 / (sF !== -1 ? parseInt(list[sF + 1]) : 1000)).toFixed(1)), + }; + } + + async initCmdLine() { + let perfCmdLines = await queryPerfCmdline(); + if (perfCmdLines.length > 0) { + this.getStringResult(perfCmdLines[0].report_value); + } else { + SpHiPerf.stringResult = { + existA: true, + existF: false, + fValue: 1, + }; + } + } + + async initFolder() { + let row = TraceRow.skeleton(); + row.setAttribute('disabled-check', ''); + row.rowId = `HiPerf`; + row.index = 0; + row.rowType = TraceRow.ROW_TYPE_HIPERF; + row.rowParentId = ''; + row.folder = true; + row.style.height = '40px'; + if (SpHiPerf.stringResult?.existA === true) { + row.name = `HiPerf (All)`; + } else { + let names = Reflect.ownKeys(this.group) + .map((pid: any) => { + let array = this.group[pid] as Array; + let process = array.filter((th) => th.pid === th.tid)[0]; + return process.processName; + }) + .join(','); + row.name = `HiPerf (${names})`; + } + row.supplier = () => new Promise>((resolve) => resolve([])); + row.onThreadHandler = (useCache) => { + row.canvasSave(this.trace.canvasPanelCtx!); + if (row.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + row + ); + } + row.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.rowFolder = row; + this.trace.rowsEL?.appendChild(row); + } + + async initCpuMerge() { + let row = TraceRow.skeleton(); + row.rowId = `HiPerf-cpu-merge`; + row.index = 0; + row.rowType = TraceRow.ROW_TYPE_HIPERF_CPU; + row.rowParentId = 'HiPerf'; + row.rowHidden = !this.rowFolder.expansion; + row.folder = false; + row.name = `HiPerf`; + row.style.height = '40px'; + row.setAttribute('children', ''); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.supplier = () => queryHiPerfCpuMergeData(); + row.focusHandler = () => this.hoverTip(row, HiPerfCpuStruct.hoverStruct); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders['HiPerf-Cpu'] as HiperfCpuRender).renderMainThread( + { + context: context, + useCache: useCache, + scale: TraceRow.range?.scale || 50, + type: `HiPerf-Cpu-Merge`, + maxCpu: this.maxCpuId + 1, + intervalPerf: SpHiPerf.stringResult?.fValue || 1, + range: TraceRow.range, + }, + row + ); + row.canvasRestore(context); + }; + this.rowFolder.addChildTraceRow(row); + this.rowList?.push(row); + } + + async initCpu() { + for (let i = 0; i <= this.maxCpuId; i++) { + let row = TraceRow.skeleton(); + row.rowId = `HiPerf-cpu-${i}`; + row.index = i; + row.rowType = TraceRow.ROW_TYPE_HIPERF_CPU; + row.rowParentId = 'HiPerf'; + row.rowHidden = !this.rowFolder.expansion; + row.folder = false; + row.name = `Cpu ${i}`; + row.setAttribute('children', ''); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.style.height = '40px'; + row.supplier = () => queryHiPerfCpuData(i); + row.focusHandler = () => this.hoverTip(row, HiPerfCpuStruct.hoverStruct); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders['HiPerf-Cpu'] as HiperfCpuRender).renderMainThread( + { + context: context, + useCache: useCache, + scale: TraceRow.range?.scale || 50, + type: `HiPerf-Cpu-${i}`, + maxCpu: this.maxCpuId + 1, + intervalPerf: SpHiPerf.stringResult?.fValue || 1, + range: TraceRow.range, + }, + row + ); + row.canvasRestore(context); + }; + this.rowFolder.addChildTraceRow(row); + this.rowList?.push(row); + } + } + + async initReport() { + this.eventTypeList.forEach((it, index) => { + let fold = TraceRow.skeleton(); + fold.rowId = `Perf-Report-${it.id}-${it.report_value}`; + fold.index = index; + fold.rowType = TraceRow.ROW_TYPE_HIPERF_REPORT; + fold.rowParentId = 'HiPerf'; + fold.rowHidden = !this.rowFolder.expansion; + fold.folder = true; + fold.name = `Event :${it.report_value}`; + fold.folderPaddingLeft = 30; + fold.favoriteChangeHandler = this.trace.favoriteChangeHandler; + fold.selectChangeHandler = this.trace.selectChangeHandler; + fold.supplier = () => queryHiPerfEventListData(it.id); + fold.onThreadHandler = (useCache) => { + let context = fold.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + fold.canvasSave(context); + (renders['HiPerf-Report-Fold'] as HiperfReportRender).renderMainThread( + { + context: context, + useCache: useCache, + scale: TraceRow.range?.scale || 50, + type: `HiPerf-Report-Fold-${it.report_value}-${it.id}`, + maxCpu: this.maxCpuId + 1, + intervalPerf: SpHiPerf.stringResult?.fValue || 1, + range: TraceRow.range, + }, + fold + ); + fold.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(fold); + this.rowList?.push(fold); + for (let i = 0; i <= this.maxCpuId; i++) { + let row = TraceRow.skeleton(); + row.rowId = `HiPerf-Report-Event-${it.report_value}-${i}`; + row.index = i; + row.rowType = TraceRow.ROW_TYPE_HIPERF_EVENT; + row.rowParentId = fold.rowId; + row.rowHidden = !fold.expansion; + row.folder = false; + row.name = `Cpu ${i}`; + row.style.height = '40px'; + row.setAttribute('children', ''); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.supplier = () => queryHiPerfEventData(it.id, row.index); + row.focusHandler = () => this.hoverTip(row, HiPerfEventStruct.hoverStruct); + row.onThreadHandler = (useCache) => { + let context = fold.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + fold.canvasSave(context); + (renders['HiPerf-Report-Event'] as HiperfEventRender).renderMainThread( + { + context: context, + useCache: useCache, + scale: TraceRow.range?.scale || 50, + type: `HiPerf-Report-Event-${it.report_value}-${i}`, + maxCpu: this.maxCpuId + 1, + intervalPerf: SpHiPerf.stringResult?.fValue || 1, + range: TraceRow.range, + }, + row + ); + fold.canvasRestore(context); + }; + this.trace.rowsEL?.appendChild(row); + this.rowList?.push(row); + } + }); + } + + async initProcess() { + Reflect.ownKeys(this.group).forEach((key, index) => { + let array = this.group[key] as Array; + let process = array.filter((th) => th.pid === th.tid)[0]; + let row = TraceRow.skeleton(); + row.rowId = `${process.pid}-Perf-Process`; + row.index = index; + row.rowType = TraceRow.ROW_TYPE_HIPERF_PROCESS; + row.rowParentId = 'HiPerf'; + row.rowHidden = !this.rowFolder.expansion; + row.folder = true; + row.name = `${process.processName || 'Process'} [${process.pid}]`; + row.folderPaddingLeft = 30; + row.style.height = '40px'; + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.supplier = () => queryHiPerfProcessData(process.pid); + row.focusHandler = () => this.hoverTip(row, HiPerfProcessStruct.hoverStruct); + row.onThreadHandler = (useCache) => { + let context = this.trace.canvasPanelCtx!; + row.canvasSave(context); + if (row.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height); + } else { + (renders['HiPerf-Process'] as HiperfProcessRender).renderMainThread( + { + context: context, + useCache: useCache, + scale: TraceRow.range?.scale || 50, + type: `HiPerf-Process-${row.index}`, + intervalPerf: SpHiPerf.stringResult?.fValue || 1, + range: TraceRow.range, + }, + row + ); + } + row.canvasRestore(context); + }; + this.rowFolder.addChildTraceRow(row); + this.rowList?.push(row); + array.forEach((thObj, thIdx) => { + let thread = TraceRow.skeleton(); + thread.rowId = `${thObj.tid}-Perf-Thread`; + thread.index = thIdx; + thread.rowType = TraceRow.ROW_TYPE_HIPERF_THREAD; + thread.rowParentId = row.rowId; + thread.rowHidden = !row.expansion; + thread.folder = false; + thread.name = `${thObj.threadName || 'Thread'} [${thObj.tid}]`; + thread.setAttribute('children', ''); + thread.folderPaddingLeft = 30; + thread.style.height = '40px'; + thread.favoriteChangeHandler = this.trace.favoriteChangeHandler; + thread.selectChangeHandler = this.trace.selectChangeHandler; + thread.supplier = () => queryHiPerfThreadData(thObj.tid); + thread.focusHandler = () => this.hoverTip(thread, HiPerfThreadStruct.hoverStruct); + thread.onThreadHandler = (useCache) => { + let context = thread.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + thread.canvasSave(context); + (renders['HiPerf-Thread'] as HiperfThreadRender).renderMainThread( + { + context: context, + useCache: useCache, + scale: TraceRow.range?.scale || 50, + type: `HiPerf-Thread-${row.index}-${thread.index}`, + intervalPerf: SpHiPerf.stringResult?.fValue || 1, + range: TraceRow.range, + }, + thread + ); + thread.canvasRestore(context); + }; + row.addChildTraceRow(thread); + this.rowList?.push(thread); + }); + }); + } + + updateChartData() { + this.rowList?.forEach((it)=>{ + it.dataList = []; + it.dataList2 = []; + it.dataListCache = []; + it.isComplete = false; + }) + } + + hoverTip( + row: TraceRow, + struct: + | HiPerfThreadStruct + | HiPerfProcessStruct + | HiPerfEventStruct + | HiPerfReportStruct + | HiPerfCpuStruct + | undefined + ) { + let tip = ''; + if (struct) { + let num = 0; + if (struct instanceof HiPerfEventStruct) { + num = Math.trunc(((struct.sum || 0) / (struct.max || 0)) * 100); + } else { + num = Math.trunc(((struct.height || 0) / 40) * 100); + } + if (num > 0) { + tip = `${num * (this.maxCpuId + 1)}% (10.00ms)`; + } else { + let perfCall = perfDataQuery.callChainMap.get(struct.callchain_id || 0); + tip = `${perfCall ? perfCall.name : ''} (${perfCall ? perfCall.depth : '0'} other frames)`; + } + } + this.trace?.displayTip(row, struct, tip); + } +} diff --git a/ide/src/trace/component/chart/SpHiSysEventChart.ts b/ide/src/trace/component/chart/SpHiSysEventChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b25805fa17a1ceae9419658881b80e436d9fac8 --- /dev/null +++ b/ide/src/trace/component/chart/SpHiSysEventChart.ts @@ -0,0 +1,646 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { + queryAnomalyData, + queryConfigSysEventAppName, + queryHisystemEventExits, + queryMaxStateValue, + queryPowerData, + queryStateData, + queryStateInitValue, + querySyseventAppName, + querySystemLocationData, + querySystemLockData, + querySystemSchedulerData, +} from '../../database/SqlLite.js'; +import { info } from '../../../log/Log.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { BaseStruct } from '../../bean/BaseStruct.js'; +import { LitPopover } from '../../../base-ui/popover/LitPopoverV.js'; +import { EnergyAnomalyRender, EnergyAnomalyStruct } from '../../database/ui-worker/ProcedureWorkerEnergyAnomaly.js'; +import { EnergySystemStruct, EnergySystemRender } from '../../database/ui-worker/ProcedureWorkerEnergySystem.js'; +import { EnergyPowerStruct, EnergyPowerRender } from '../../database/ui-worker/ProcedureWorkerEnergyPower.js'; +import { EnergyStateStruct, EnergyStateRender } from '../../database/ui-worker/ProcedureWorkerEnergyState.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class SpHiSysEventChart { + static app_name: string | null; + private trace: SpSystemTrace; + private energyTraceRow: TraceRow | undefined; + private timer: any; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let result = await queryHisystemEventExits(); + if (result.length <= 0) return; + await this.initEnergyRow(); + await this.initAnomaly(); + await this.initSystem(); + await this.initPower(); + await this.initState(); + } + + private initEnergyRow = async () => { + SpHiSysEventChart.app_name = ''; + let appNameFromTable = await querySyseventAppName(); + let configAppName = await queryConfigSysEventAppName(); + if (configAppName.length > 0 && appNameFromTable.length > 0) { + let name = configAppName[0].process_name; + if (name != null) { + let filterList = appNameFromTable.filter((appNameFromTableElement) => { + return appNameFromTableElement.string_value?.trim() == name; + }); + if (filterList.length > 0) { + SpHiSysEventChart.app_name = name; + } + } + } + if (appNameFromTable.length > 0 && SpHiSysEventChart.app_name == '') { + SpHiSysEventChart.app_name = appNameFromTable[0].string_value; + } + this.energyTraceRow = TraceRow.skeleton(); + let appNameList = this.energyTraceRow?.shadowRoot!.querySelector('#appNameList'); + let addFlag = false; + appNameList?.addEventListener('click', () => { + let itemDiv = appNameList!.querySelector('div'); + if (!addFlag) { + for (let index = 0; index < appNameFromTable.length; index++) { + let div = document.createElement('div'); + div.setAttribute('style', 'margin-bottom: 5px'); + let appName = appNameFromTable[index].string_value; + // @ts-ignore + let formatAppName = 'appName' + index; + div.setAttribute('id', formatAppName); + let inputId = 'appName' + index + 1; + div.innerHTML = + " '; + itemDiv!.append(div); + let appList = this.energyTraceRow?.shadowRoot!.querySelectorAll( + 'input[type=radio][name=processoption]' + ); + appList!.forEach((appName) => [ + (appName.onclick = (e: MouseEvent) => { + if (appName.checked) { + SpHiSysEventChart.app_name = appName.getAttribute('value'); + TraceRow.range!.refresh = true; + // @ts-ignore + appNameList!.visible = false; + this.trace.refreshCanvas(false); + } + }), + ]); + } + addFlag = true; + } + }); + + this.energyTraceRow.rowId = `energy`; + this.energyTraceRow.rowType = TraceRow.ROW_TYPE_ENERGY; + this.energyTraceRow.rowParentId = ''; + this.energyTraceRow.folder = true; + this.energyTraceRow.name = 'Energy'; + this.energyTraceRow.style.height = '40px'; + this.energyTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + this.energyTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + this.energyTraceRow.supplier = () => new Promise>((resolve) => resolve([])); + this.energyTraceRow.onThreadHandler = (useCache) => { + this.energyTraceRow?.canvasSave(this.trace.canvasPanelCtx!); + if (this.energyTraceRow!.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, this.energyTraceRow!.frame.width, this.energyTraceRow!.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + this.energyTraceRow! + ); + } + this.energyTraceRow?.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.energyTraceRow.addEventListener('expansion-change', () => { + TraceRow.range!.refresh = true; + this.trace.refreshCanvas(false); + if (this.timer) { + clearTimeout(this.timer); + } + this.timer = setTimeout(() => { + TraceRow.range!.refresh = false; + }, 200); + }); + this.trace.rowsEL?.appendChild(this.energyTraceRow!); + }; + + private initAnomaly = async () => { + let time = new Date().getTime(); + let anomalyTraceRow = TraceRow.skeleton(); + anomalyTraceRow.rowParentId = `energy`; + anomalyTraceRow.rowHidden = true; + anomalyTraceRow.rowId = 'energy-anomaly'; + anomalyTraceRow.rowType = TraceRow.ROW_TYPE_ANOMALY_ENERGY; + anomalyTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + anomalyTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + anomalyTraceRow.setAttribute('height', `55px`); + let element = anomalyTraceRow.shadowRoot?.querySelector('.root') as HTMLDivElement; + element!.style.height = `55px`; + anomalyTraceRow.style.width = `100%`; + anomalyTraceRow.setAttribute('children', ''); + anomalyTraceRow.name = 'Anomaly Event'; + anomalyTraceRow.supplier = () => queryAnomalyData(); + anomalyTraceRow.focusHandler = () => { + this.trace?.displayTip( + anomalyTraceRow, + EnergyAnomalyStruct.hoverEnergyAnomalyStruct, + `AnomalyName:${EnergyAnomalyStruct.hoverEnergyAnomalyStruct?.eventName || ''}` + ); + }; + anomalyTraceRow.onThreadHandler = (useCache) => { + let context = anomalyTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + anomalyTraceRow.canvasSave(context); + (renders['energyAnomaly'] as EnergyAnomalyRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `energyAnomaly`, + appName: SpHiSysEventChart.app_name || '', + canvasWidth: this.trace.canvasPanel?.width || 0, + }, + anomalyTraceRow + ); + anomalyTraceRow.canvasRestore(context); + }; + this.energyTraceRow?.addChildTraceRow(anomalyTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the anomaly is: ', durTime); + }; + + private initSystem = async () => { + let time = new Date().getTime(); + let systemTraceRow = TraceRow.skeleton(); + systemTraceRow.rowParentId = `energy`; + systemTraceRow.rowHidden = true; + systemTraceRow.rowId = 'energy-system'; + systemTraceRow.rowType = TraceRow.ROW_TYPE_SYSTEM_ENERGY; + systemTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + systemTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + systemTraceRow.setAttribute('height', `80px`); + let element = systemTraceRow.shadowRoot?.querySelector('.root') as HTMLDivElement; + element!.style.height = `90px`; + systemTraceRow.style.width = `100%`; + systemTraceRow.setAttribute('children', ''); + systemTraceRow.name = 'System Event'; + systemTraceRow.supplier = () => + Promise.all([querySystemLocationData(), querySystemLockData(), querySystemSchedulerData()]).then((result) => { + return this.getSystemData(result); + }); + systemTraceRow.focusHandler = () => { + this.trace?.displayTip( + systemTraceRow, + EnergySystemStruct.hoverEnergySystemStruct, + `
+
WORKSCHEDULER:
${ + EnergySystemStruct.hoverEnergySystemStruct?.workScheduler! || 0 + }
+
POWER_RUNNINGLOCK:
${ + EnergySystemStruct.hoverEnergySystemStruct?.power! || 0 + }
+
LOCATION:
${ + EnergySystemStruct.hoverEnergySystemStruct?.location! || 0 + }
+
` + ); + }; + systemTraceRow.onThreadHandler = (useCache) => { + let context = systemTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + systemTraceRow.canvasSave(context); + (renders['energySystem'] as EnergySystemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `energySystem`, + }, + systemTraceRow + ); + systemTraceRow.canvasRestore(context); + }; + this.energyTraceRow?.addChildTraceRow(systemTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the Ability Memory is: ', durTime); + }; + + getSystemData(result: any): Promise { + let systemDataList: any = {}; + if (result.length == 0) { + return Promise.resolve([]); + } + systemDataList[0] = this.handleLockData(result); + systemDataList[1] = this.handleLocationData(result); + systemDataList[2] = this.handleWorkData(result); + return systemDataList; + } + + private handleLocationData(result: Array>) { + let locationIndex = -1; + let locationCount = 0; + let locationData: any[] = []; + result[0].forEach((item: any) => { + let da: any = {}; + if (item.Value == 'stop') { + if (locationIndex == -1) { + da.startNs = 0; + da.count = 1; + } else { + da.startNs = item.ts; + locationCount--; + da.count = locationCount; + } + da.state = 'stop'; + } else { + da.startNs = item.ts; + locationCount++; + da.count = locationCount; + da.state = 'start'; + } + locationIndex = 0; + da.type = 2; + locationData.push(da); + }); + return locationData; + } + + private handleLockData(result: Array>) { + let lockCount = 0; + let tokedIds: Array = []; + let lockData: any[] = []; + result[1].forEach((item: any) => { + let running: any = {}; + let split = item.Value.split(','); + if (item.Value.indexOf('ADD') > -1) { + running.startNs = item.ts; + lockCount++; + running.count = lockCount; + running.token = split[0].split('=')[1]; + running.type = 1; + tokedIds.push(running.token); + lockData.push(running); + } else { + running.startNs = item.ts; + let toked = split[0].split('=')[1]; + let number = tokedIds.indexOf(toked); + if (number > -1) { + lockCount--; + running.count = lockCount; + running.token = split[0].split('=')[1]; + running.type = 1; + lockData.push(running); + delete tokedIds[number]; + } + } + }); + + return lockData; + } + + private handleWorkData(result: Array>) { + let workDataArray = result[2]; + let workCountMap: Map = new Map(); + let nameIdMap: Map> = new Map(); + let workData: any[] = []; + for (let i = 0; i < workDataArray.length; i++) { + let dd: any = {}; + let item = workDataArray[i]; + let keys = item.appKey.split(','); + let values = item.Value.split(','); + for (let j = 0; j < keys.length; j++) { + let key = keys[j]; + switch (key) { + case 'NAME': + dd.appName = values[j]; + break; + case 'WORKID': + dd.workId = values[j]; + break; + } + } + if (item.eventName == 'WORK_START') { + let nameIdList = nameIdMap.get(dd.appName); + let workCount = 0; + if (nameIdList == undefined) { + workCount = 1; + nameIdMap.set(dd.appName, [dd.workId]); + } else { + nameIdList.push(dd.workId); + workCount = nameIdList.length; + } + let count = workCountMap.get(dd.appName); + if (count == undefined) { + workCountMap.set(dd.appName, 1); + } else { + workCountMap.set(dd.appName, count + 1); + } + dd.startNs = item.ts; + dd.count = workCount; + dd.type = 0; + workData.push(dd); + } else if (item.eventName == 'WORK_STOP') { + let nameIdList: any = nameIdMap.get(dd.appName); + let index = nameIdList.indexOf(dd.workId); + if (nameIdList != undefined && index > -1) { + delete nameIdList[index]; + let workCount = workCountMap.get(dd.appName); + if (workCount != undefined) { + workCount = workCount - 1; + workCountMap.set(dd.appName, workCount); + dd.startNs = item.startNS; + dd.count = workCount; + dd.type = 0; + workData.push(dd); + } + } + } + } + return workData; + } + + private initPower = async () => { + let time = new Date().getTime(); + let powerTraceRow = TraceRow.skeleton(); + powerTraceRow.rowParentId = `energy`; + powerTraceRow.rowHidden = true; + powerTraceRow.rowId = 'energy-power'; + powerTraceRow.rowType = TraceRow.ROW_TYPE_POWER_ENERGY; + powerTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + powerTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + powerTraceRow.setAttribute('height', `200px`); + let element = powerTraceRow.shadowRoot?.querySelector('.root') as HTMLDivElement; + element!.style.height = `200px`; + powerTraceRow.style.width = `100%`; + powerTraceRow.setAttribute('children', ''); + powerTraceRow.name = 'Power'; + powerTraceRow.supplier = () => + queryPowerData().then((items) => { + return this.getPowerData(items); + }); + powerTraceRow.focusHandler = () => { + this.trace?.displayTip( + powerTraceRow, + EnergyPowerStruct.hoverEnergyPowerStruct, + `
+
CPU:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.cpu! || 0 + }
+
location:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.location! || 0 + }
+
GPU:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.gpu! || 0 + }
+
display:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.display! || 0 + }
+
camera:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.camera! || 0 + }
+
bluetooth:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.bluetooth! || 0 + }
+
flashlight:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.flashlight! || 0 + }
+
audio:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.audio! || 0 + }
+
wifiScan:
${ + EnergyPowerStruct.hoverEnergyPowerStruct?.wifiscan! || 0 + }
+
` + ); + }; + powerTraceRow.onThreadHandler = (useCache) => { + let context = powerTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + powerTraceRow.canvasSave(context); + (renders['energyPower'] as EnergyPowerRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `energyPower`, + appName: SpHiSysEventChart.app_name || '', + }, + powerTraceRow! + ); + powerTraceRow!.canvasRestore(context); + }; + this.energyTraceRow?.addChildTraceRow(powerTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the energy power is: ', durTime); + }; + + async getPowerData(items: any): Promise { + let powerDataMap: any = {}; + let appNameList: any = []; + items.forEach((item: any) => { + let dataItem = powerDataMap[item.startNS]; + if (dataItem == undefined) { + if (item.appKey == 'APPNAME') { + let appMap: any = {}; + let appNames = item.eventValue.split(','); + appNameList = appNames; + if (appNames.length > 0) { + for (let appNamesKey of appNames) { + appMap[appNamesKey] = new EnergyPowerStruct(); + appMap[appNamesKey].name = appNamesKey; + appMap[appNamesKey].ts = item.startNS; + } + powerDataMap[item.startNS] = appMap; + } + } + } else { + if (item.appKey != 'APPNAME') { + let values = item.eventValue.split(','); + for (let i = 0; i < values.length; i++) { + let appName = appNameList[i]; + let obj = dataItem[appName]; + if (obj != undefined) { + let eventName = item.eventName.split('_'); + let s = eventName[eventName.length - 1].toLocaleLowerCase(); + if (obj[s] == undefined) { + obj[s] = parseInt(values[i]); + } else { + obj[s] += parseInt(values[i]); + } + } + } + } else { + let dataMap = powerDataMap[item.startNS]; + let appNames = item.eventValue.split(','); + appNameList = appNames; + if (appNames.length > 0) { + for (let appNamesKey of appNames) { + dataMap[appNamesKey] = new EnergyPowerStruct(); + dataMap[appNamesKey].name = appNamesKey; + dataMap[appNamesKey].ts = item.startNS; + } + } + } + } + }); + // @ts-ignore + return Object.values(powerDataMap); + } + + private initState = async () => { + let time = new Date().getTime(); + let stateList = [ + 'Brightness Nit', + 'Signal Level', + 'Wifi Event Received', + 'Audio Stream Change', + 'Audio Volume Change', + 'Wifi State', + 'Bluetooth Br Switch State', + 'Location Switch State', + 'Sensor State', + ]; + let stateName = [ + 'BRIGHTNESS_NIT', + 'SIGNAL_LEVEL', + 'WIFI_EVENT_RECEIVED', + 'AUDIO_STREAM_CHANGE', + 'AUDIO_VOLUME_CHANGE', + 'WIFI_STATE', + 'BLUETOOTH_BR_SWITCH_STATE', + 'LOCATION_SWITCH_STATE', + 'SENSOR_STATE', + ]; + let initValueList = [ + 'brightness', + 'nocolumn', + 'nocolumn', + 'nocolumn', + 'nocolumn', + 'wifi', + 'bt_state', + 'location', + 'nocolumn', + ]; + + for (let index = 0; index < stateList.length; index++) { + let maxStateData = await queryMaxStateValue(stateName[index]); + if (!maxStateData[0]) { + continue; + } + let maxStateTotal = maxStateData[0].maxValue.toString(); + if ( + maxStateData[0].type.toLocaleLowerCase().includes('state') && + maxStateData[0].type.toLocaleLowerCase() != 'bluetooth_br_switch_state' + ) { + if (maxStateData[0].maxValue == 0) { + maxStateTotal = 'enable'; + } else { + maxStateTotal = 'disable'; + } + } + let stateTraceRow = TraceRow.skeleton(); + stateTraceRow.rowParentId = `energy`; + stateTraceRow.rowHidden = true; + stateTraceRow.rowId = 'energy-state'; + stateTraceRow.rowType = TraceRow.ROW_TYPE_STATE_ENERGY; + stateTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + stateTraceRow.selectChangeHandler = this.trace.selectChangeHandler; + stateTraceRow.style.height = '40px'; + stateTraceRow.style.width = `100%`; + stateTraceRow.setAttribute('children', ''); + stateTraceRow.name = `${stateList[index]}`; + stateTraceRow.supplier = () => + Promise.all([ + queryStateInitValue(stateName[index], initValueList[index]), + queryStateData(stateName[index]), + ]).then((result) => { + let stateInitValue = initValueList[index] == 'nocolumn' ? [] : result[0]; + return stateInitValue.concat(result[1]); + }); + stateTraceRow.focusHandler = () => { + let tip = ''; + if (EnergyStateStruct.hoverEnergyStateStruct?.type!.toLocaleLowerCase().includes('state')) { + tip = `Switch Status: ${ + EnergyStateStruct.hoverEnergyStateStruct?.value == 1 ? 'disable' : 'enable' + }`; + if (EnergyStateStruct.hoverEnergyStateStruct?.type!.toLocaleLowerCase() == 'bluetooth_br_switch_state') { + tip = `${SpHiSysEventChart.getBlueToothState( + EnergyStateStruct.hoverEnergyStateStruct?.value + )}`; + } + } else { + tip = `value: ${EnergyStateStruct.hoverEnergyStateStruct?.value || 0}`; + } + this.trace?.displayTip(stateTraceRow, EnergyStateStruct.hoverEnergyStateStruct, tip); + }; + stateTraceRow.onThreadHandler = (useCache) => { + let context = stateTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + stateTraceRow.canvasSave(context); + (renders['energyState'] as EnergyStateRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `energyState${index}`, + maxState: maxStateData[0].maxValue, + maxStateName: + maxStateData[0].type.toLocaleLowerCase() == 'bluetooth_br_switch_state' ? '-1' : maxStateTotal.toString(), + }, + stateTraceRow + ); + stateTraceRow.canvasRestore(context); + }; + this.energyTraceRow?.addChildTraceRow(stateTraceRow); + let durTime = new Date().getTime() - time; + info('The time to load the Ability Memory is: ', durTime); + } + }; + + public static getBlueToothState(num: number | undefined): string { + switch (num) { + case 0: + return 'STATE_TURNING_ON'; + case 1: + return 'STATE_TURN_ON'; + case 2: + return 'STATE_TURNING_OFF'; + case 3: + return 'STATE_TURN_OFF'; + default: + return 'UNKNOWN_STATE'; + } + } +} diff --git a/ide/src/trace/component/chart/SpIrqChart.ts b/ide/src/trace/component/chart/SpIrqChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..06bc0197ee4fd839819b113ca56e46ec5f85c476 --- /dev/null +++ b/ide/src/trace/component/chart/SpIrqChart.ts @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { queryIrqData, queryIrqList } from '../../database/SqlLite.js'; +import { info } from '../../../log/Log.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { IrqRender, IrqStruct } from '../../database/ui-worker/ProcedureWorkerIrq.js'; + +export class SpIrqChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let folder = await this.initFolder(); + await this.initData(folder); + } + + async initData(folder: TraceRow) { + let irqStartTime = new Date().getTime(); + let irqList = await queryIrqList(); + if (irqList.length == 0) { + return; + } + info('irqList data size is: ', irqList!.length); + this.trace.rowsEL?.appendChild(folder); + for (let i = 0; i < irqList.length; i++) { + const it = irqList[i]; + let traceRow = TraceRow.skeleton(); + traceRow.rowId = it.name + it.cpu; + traceRow.rowType = TraceRow.ROW_TYPE_IRQ; + traceRow.rowParentId = folder.rowId; + traceRow.style.height = '40px'; + traceRow.name = `${it.name} Cpu ${it.cpu}`; + traceRow.rowHidden = !folder.expansion; + traceRow.setAttribute('children', ''); + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.supplier = () => queryIrqData(it.cpu, it.name); + traceRow.focusHandler = (ev) => { + this.trace?.displayTip( + traceRow, + IrqStruct.hoverIrqStruct, + `${IrqStruct.hoverIrqStruct?.name || ''}` + ); + }; + traceRow.onThreadHandler = (useCache) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders['irq'] as IrqRender).renderMainThread( + { + context: context, + useCache: useCache, + type: it.name, + index: i, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + folder.addChildTraceRow(traceRow); + } + let durTime = new Date().getTime() - irqStartTime; + info('The time to load the ClockData is: ', durTime); + } + + async initFolder(): Promise> { + let folder = TraceRow.skeleton(); + folder.rowId = `Irqs`; + folder.index = 0; + folder.rowType = TraceRow.ROW_TYPE_IRQ_GROUP; + folder.rowParentId = ''; + folder.style.height = '40px'; + folder.folder = true; + folder.name = `Irqs`; /* & I/O Latency */ + folder.favoriteChangeHandler = this.trace.favoriteChangeHandler; + folder.selectChangeHandler = this.trace.selectChangeHandler; + folder.supplier = () => new Promise>((resolve) => resolve([])); + folder.onThreadHandler = (useCache) => { + folder.canvasSave(this.trace.canvasPanelCtx!); + if (folder.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + folder + ); + } + folder.canvasRestore(this.trace.canvasPanelCtx!); + }; + return folder; + } +} diff --git a/ide/src/trace/component/chart/SpJsMemoryChart.ts b/ide/src/trace/component/chart/SpJsMemoryChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..12626f6c9c8a24726daa237198baab5bbaba0106 --- /dev/null +++ b/ide/src/trace/component/chart/SpJsMemoryChart.ts @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { queryHeapFile, queryHeapSample, queryTraceRange } from '../../database/SqlLite.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { info } from '../../../log/Log.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; +import { HeapTimelineRender, HeapTimelineStruct } from '../../database/ui-worker/ProcedureWorkerHeapTimeline.js'; +import { HeapDataInterface, ParseListener } from '../../../js-heap/HeapDataInterface.js'; +import { LoadDatabase } from '../../../js-heap/LoadDatabase.js'; +import { FileInfo } from '../../../js-heap/model/UiStruct.js'; +import { HeapSnapshotRender, HeapSnapshotStruct } from '../../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; +export class SpJsMemoryChart implements ParseListener { + private trace: SpSystemTrace; + private loadJsDatabase: LoadDatabase; + static file: any; + constructor(trace: SpSystemTrace) { + this.trace = trace; + this.loadJsDatabase = LoadDatabase.getInstance(); + } + async parseDone(fileModule: Array): Promise { + if (fileModule.length > 0) { + let jsHeapRow = TraceRow.skeleton(); + let process = ''; + let heapFile = await queryHeapFile(); + process = heapFile[0].pid; + jsHeapRow.rowId = `js-memory`; + jsHeapRow.index = 0; + jsHeapRow.rowType = TraceRow.ROW_TYPE_JS_MEMORY; + jsHeapRow.drawType = 0; + jsHeapRow.style.height = '40px'; + jsHeapRow.rowParentId = ''; + jsHeapRow.folder = true; + jsHeapRow.name = `Js Memory ` + process; + jsHeapRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + jsHeapRow.selectChangeHandler = this.trace.selectChangeHandler; + jsHeapRow.onDrawTypeChangeHandler = (type) => {}; + jsHeapRow.supplier = () => new Promise>((resolve) => resolve([])); + jsHeapRow.onThreadHandler = (useCache) => { + jsHeapRow.canvasSave(this.trace.canvasPanelCtx!); + if (jsHeapRow.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, jsHeapRow.frame.width, jsHeapRow.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + jsHeapRow + ); + } + jsHeapRow.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(jsHeapRow); + let file = heapFile[0]; + SpJsMemoryChart.file = file; + if (file.file_name.includes('Timeline')) { + let samples = HeapDataInterface.getInstance().getSamples(file.id); + let heapTimelineRow = TraceRow.skeleton(); + heapTimelineRow.index = 0; + heapTimelineRow.rowParentId = `js-memory`; + heapTimelineRow.rowHidden = !jsHeapRow.expansion; + heapTimelineRow.style.height = '40px'; + heapTimelineRow.name = `Heaptimeline`; + heapTimelineRow.rowId = `heap_timeline` + file.id; + heapTimelineRow.drawType = 0; + heapTimelineRow.isHover = true; + heapTimelineRow.folder = false; + heapTimelineRow.rowType = TraceRow.ROW_TYPE_HEAP_TIMELINE; + heapTimelineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + heapTimelineRow.selectChangeHandler = this.trace.selectChangeHandler; + heapTimelineRow.setAttribute('children', ''); + heapTimelineRow.focusHandler = () => {}; + heapTimelineRow.supplier = () => queryHeapSample(file.id); + heapTimelineRow.onThreadHandler = (useCache) => { + let context = heapTimelineRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + heapTimelineRow.canvasSave(context); + (renders['heapTimeline'] as HeapTimelineRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `heapTimeline`, + samples: samples, + }, + heapTimelineRow + ); + heapTimelineRow.canvasRestore(context); + }; + jsHeapRow.addChildTraceRow(heapTimelineRow); + } else { + let traceRange = await queryTraceRange(); + let heapSnapshotRow = TraceRow.skeleton(); + heapSnapshotRow.rowParentId = `js-memory`; + heapSnapshotRow.rowHidden = !jsHeapRow.expansion; + heapSnapshotRow.style.height = '40px'; + heapSnapshotRow.name = `Heapsnapshot`; + heapSnapshotRow.rowId = `heap_snapshot`; + heapSnapshotRow.isHover = true; + heapSnapshotRow.folder = false; + heapSnapshotRow.rowType = TraceRow.ROW_TYPE_HEAP_SNAPSHOT; + heapSnapshotRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + heapSnapshotRow.selectChangeHandler = this.trace.selectChangeHandler; + heapSnapshotRow.setAttribute('children', ''); + heapSnapshotRow.focusHandler = () => {}; + heapSnapshotRow.supplier = () => queryHeapFile(); + heapSnapshotRow.onThreadHandler = (useCache) => { + let context = heapSnapshotRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + heapSnapshotRow.canvasSave(context); + (renders['heapSnapshot'] as HeapSnapshotRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `heapSnapshot`, + traceRange: traceRange, + }, + heapSnapshotRow + ); + heapSnapshotRow.canvasRestore(context); + }; + jsHeapRow.addChildTraceRow(heapSnapshotRow); + } + } + } + + process(info: string, process: number): void {} + + initChart = async () => { + let time = new Date().getTime(); + await this.loadJsDatabase.loadDatabase(this); + let durTime = new Date().getTime() - time; + info('The time to load the js Memory data is: ', durTime); + }; +} diff --git a/ide/src/trace/component/chart/SpNativeMemoryChart.ts b/ide/src/trace/component/chart/SpNativeMemoryChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..0562b5d5ae00279bcee23d7d1e62ef7d565e56d6 --- /dev/null +++ b/ide/src/trace/component/chart/SpNativeMemoryChart.ts @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { + queryBootTime, + queryHeapGroupByEvent, + queryNativeHookProcess, + queryNativeHookStatisticsCount, + queryNativeMemoryRealTime, +} from '../../database/SqlLite.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { info } from '../../../log/Log.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { NativeEventHeap } from '../../bean/NativeHook.js'; +import { HeapRender, HeapStruct } from '../../database/ui-worker/ProcedureWorkerHeap.js'; +import { Utils } from '../trace/base/Utils.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class SpNativeMemoryChart { + static EVENT_HEAP: Array = []; + static REAL_TIME_DIF: number = 0; + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + initChart = async () => { + let time = new Date().getTime(); + let nativeMemoryType = 'native_hook'; + let nmsCount = await queryNativeHookStatisticsCount(); + if (nmsCount && nmsCount[0] && (nmsCount[0] as any).num > 0) { + nativeMemoryType = 'native_hook_statistic'; + } + let nativeProcess = await queryNativeHookProcess(nativeMemoryType); + info('NativeHook Process data size is: ', nativeProcess!.length); + if (nativeProcess.length == 0) { + return; + } + SpNativeMemoryChart.EVENT_HEAP = await queryHeapGroupByEvent(nativeMemoryType); + let nativeRow = TraceRow.skeleton(); + let process = ''; + if (nativeProcess.length > 0) { + process = ` ${nativeProcess[0].pid}`; + } + nativeRow.rowId = `native-memory`; + nativeRow.index = 0; + nativeRow.rowType = TraceRow.ROW_TYPE_NATIVE_MEMORY; + nativeRow.drawType = 0; + nativeRow.style.height = '40px'; + nativeRow.rowParentId = ''; + nativeRow.folder = true; + nativeRow.name = `Native Memory` + process; + nativeRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + nativeRow.selectChangeHandler = this.trace.selectChangeHandler; + nativeRow.onDrawTypeChangeHandler = (type) => { + this.trace.rowsEL?.querySelectorAll>(`trace-row[row-type='heap']`).forEach((it) => { + it.drawType = type; + this.trace.refreshCanvas(false); + }); + this.trace.favoriteRowsEL?.querySelectorAll>(`trace-row[row-type='heap']`).forEach((it) => { + it.drawType = type; + }); + }; + nativeRow.supplier = () => new Promise>((resolve) => resolve([])); + nativeRow.onThreadHandler = (useCache) => { + nativeRow.canvasSave(this.trace.canvasPanelCtx!); + if (nativeRow.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, nativeRow.frame.width, nativeRow.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + nativeRow + ); + } + nativeRow.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(nativeRow); + /** + * 添加heap信息 + */ + let native_memory = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + for (let i = 0; i < native_memory.length; i++) { + let nm = native_memory[i]; + let allHeapRow = TraceRow.skeleton(); + allHeapRow.index = i; + allHeapRow.rowParentId = `native-memory`; + allHeapRow.rowHidden = !nativeRow.expansion; + allHeapRow.style.height = '40px'; + allHeapRow.name = nm; + allHeapRow.rowId = nm; + allHeapRow.drawType = 0; + allHeapRow.isHover = true; + allHeapRow.folder = false; + allHeapRow.rowType = TraceRow.ROW_TYPE_HEAP; + allHeapRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + allHeapRow.selectChangeHandler = this.trace.selectChangeHandler; + allHeapRow.setAttribute('heap-type', nativeMemoryType); + allHeapRow.setAttribute('children', ''); + allHeapRow.focusHandler = () => { + let tip = ''; + if (HeapStruct.hoverHeapStruct) { + if (allHeapRow.drawType === 1) { + tip = `${HeapStruct.hoverHeapStruct.density}`; + } else { + tip = `${Utils.getByteWithUnit(HeapStruct.hoverHeapStruct.heapsize!)}`; + } + } + this.trace?.displayTip(allHeapRow, HeapStruct.hoverHeapStruct, tip); + }; + allHeapRow.supplier = () => { + return nativeMemoryType === 'native_hook' + ? this.getNativeMemoryDataByChartType(i, allHeapRow.drawType) + : this.getNativeMemoryStatisticByChartType(i - 1); + }; + allHeapRow.onThreadHandler = (useCache) => { + let context = allHeapRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + allHeapRow.canvasSave(context); + (renders['heap'] as HeapRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `heap`, + }, + allHeapRow + ); + allHeapRow.canvasRestore(context); + }; + nativeRow.addChildTraceRow(allHeapRow); + } + let durTime = new Date().getTime() - time; + info('The time to load the Native Memory data is: ', durTime); + }; + + getNativeMemoryStatisticByChartType = async (chartType: number): Promise> => { + let arr: Array = []; + await new Promise>((resolve, reject) => { + procedurePool.submitWithName( + 'logic1', + 'native-memory-queryNativeHookStatistic', + { type: chartType, totalNS: TraceRow.range?.totalNS! }, + undefined, + (res: any) => { + arr = arr.concat(res.data); + res.data = null; + if (res.tag == 'end') { + resolve(arr); + } + } + ); + }); + return arr; + }; + + getNativeMemoryDataByChartType = async (nativeMemoryType: number, chartType: number): Promise> => { + let args = new Map(); + args.set('nativeMemoryType', nativeMemoryType); + args.set('chartType', chartType); + args.set('totalNS', TraceRow.range?.totalNS!); + args.set('actionType', 'memory-chart'); + let arr: Array = []; + await new Promise>((resolve, reject) => { + procedurePool.submitWithName('logic1', 'native-memory-chart-action', args, undefined, (res: any) => { + arr = arr.concat(res.data); + res.data = null; + if (res.tag == 'end') { + resolve(arr); + } + }); + }); + return arr; + }; + + initNativeMemory = async () => { + let time = new Date().getTime(); + let isRealtime = false; + let realTimeDif = 0; + SpNativeMemoryChart.REAL_TIME_DIF = 0; + let queryTime = await queryNativeMemoryRealTime(); + let bootTime = await queryBootTime(); + if (queryTime.length > 0) { + isRealtime = queryTime[0].clock_name == 'realtime'; + } + if (bootTime.length > 0 && isRealtime) { + realTimeDif = queryTime[0].ts - bootTime[0].ts; + SpNativeMemoryChart.REAL_TIME_DIF = realTimeDif; + } + await new Promise((resolve, reject) => { + procedurePool.submitWithName( + 'logic1', + 'native-memory-init', + { isRealtime, realTimeDif }, + undefined, + (res: any) => { + resolve(res); + } + ); + }); + let durTime = new Date().getTime() - time; + info('The time to init the native memory data is: ', durTime); + }; +} diff --git a/ide/src/trace/component/chart/SpProcessChart.ts b/ide/src/trace/component/chart/SpProcessChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d0e32dc380200d2cf0f90218ab8cbf50f9b3af6 --- /dev/null +++ b/ide/src/trace/component/chart/SpProcessChart.ts @@ -0,0 +1,701 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { + getAsyncEvents, + getFunDataByTid, + getMaxDepthByTid, + queryAllActualData, + queryAllExpectedData, + queryAllJankProcess, + queryEventCountMap, + queryProcess, + queryProcessAsyncFunc, + queryProcessByTable, + queryProcessContentCount, + queryProcessData, + queryProcessMem, + queryProcessMemData, + queryProcessThreads, + queryProcessThreadsByTable, + queryThreadData, +} from '../../database/SqlLite.js'; +import { Utils } from '../trace/base/Utils.js'; +import { info } from '../../../log/Log.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { ProcessRender, ProcessStruct } from '../../database/ui-worker/ProcedureWorkerProcess.js'; +import { ThreadRender, ThreadStruct } from '../../database/ui-worker/ProcedureWorkerThread.js'; +import { FuncRender, FuncStruct } from '../../database/ui-worker/ProcedureWorkerFunc.js'; +import { MemRender, ProcessMemStruct } from '../../database/ui-worker/ProcedureWorkerMem.js'; +import { FolderSupplier, FolderThreadHandler } from './SpChartManager.js'; +import { JankRender, JankStruct } from '../../database/ui-worker/ProcedureWorkerJank.js'; +import { ns2xByTimeShaft } from '../../database/ui-worker/ProcedureWorkerCommon.js'; + +export class SpProcessChart { + private readonly trace: SpSystemTrace; + private processAsyncFuncMap: any = {}; + private processAsyncFuncArray: any[] = []; + private eventCountMap: any; + private processThreads: Array = []; + private processAsyncEvent: Array = []; + private processMem: Array = []; + private processThreadCountMap: Map = new Map(); + private processThreadDataCountMap: Map = new Map(); + private processFuncDataCountMap: Map = new Map(); + private processMemDataCountMap: Map = new Map(); + private threadFuncMaxDepthMap: Map = new Map(); + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + initAsyncFuncData = async () => { + let asyncFuncList: any[] = await queryProcessAsyncFunc(); + info('AsyncFuncData Count is: ', asyncFuncList!.length); + this.processAsyncFuncArray = asyncFuncList; + this.processAsyncFuncMap = Utils.groupBy(asyncFuncList, 'pid'); + }; + + initDeliverInputEvent = async () => { + let row = TraceRow.skeleton(); + row.setAttribute('disabled-check', ''); + row.rowId = `DeliverInputEvent`; + row.index = 0; + row.rowType = TraceRow.ROW_TYPE_DELIVER_INPUT_EVENT; + row.rowParentId = ''; + row.folder = true; + row.style.height = '40px'; + row.name = `DeliverInputEvent`; + row.supplier = FolderSupplier(); + row.onThreadHandler = FolderThreadHandler(row, this.trace); + + let asyncFuncGroup = Utils.groupBy( + this.processAsyncFuncArray.filter((it) => it.funName === 'deliverInputEvent'), + 'tid' + ); + if (Reflect.ownKeys(asyncFuncGroup).length > 0) { + this.trace.rowsEL?.appendChild(row); + } + Reflect.ownKeys(asyncFuncGroup).map((key: any) => { + let asyncFunctions: Array = asyncFuncGroup[key]; + if (asyncFunctions.length > 0) { + let isIntersect = (a: any, b: any) => + Math.max(a.startTs + a.dur, b.startTs + b.dur) - Math.min(a.startTs, b.startTs) < a.dur + b.dur; + let depthArray: any = []; + let createDepth = (currentDepth: number, index: number) => { + if (depthArray[currentDepth] == undefined || !isIntersect(depthArray[currentDepth], asyncFunctions[index])) { + asyncFunctions[index].depth = currentDepth; + depthArray[currentDepth] = asyncFunctions[index]; + } else { + createDepth(++currentDepth, index); + } + }; + asyncFunctions.forEach((it, i) => { + if (it.dur == -1) { + it.dur = (TraceRow.range?.endNS || 0) - it.startTs; + it.flag = 'Did not end'; + } + createDepth(0, i); + }); + let max = Math.max(...asyncFunctions.map((it) => it.depth || 0)) + 1; + let maxHeight = max * 20; + let funcRow = TraceRow.skeleton(); + funcRow.rowId = `${asyncFunctions[0].funName}-${key}`; + funcRow.asyncFuncName = asyncFunctions[0].funName; + funcRow.asyncFuncNamePID = key; + funcRow.rowType = TraceRow.ROW_TYPE_FUNC; + funcRow.rowParentId = `${row.rowId}`; + funcRow.rowHidden = !row.expansion; + funcRow.style.width = `100%`; + funcRow.style.height = `${maxHeight}px`; + funcRow.setAttribute('height', `${maxHeight}`); + funcRow.name = `${asyncFunctions[0].funName} ${key}`; + funcRow.setAttribute('children', ''); + funcRow.supplier = () => new Promise((resolve) => resolve(asyncFunctions)); + funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + funcRow.selectChangeHandler = this.trace.selectChangeHandler; + funcRow.onThreadHandler = (useCache) => { + let context = funcRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + funcRow.canvasSave(context); + (renders['func'] as FuncRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `func-${asyncFunctions[0].funName}-${key}`, + }, + funcRow + ); + funcRow.canvasRestore(context); + }; + row.addChildTraceRow(funcRow); + } + }); + }; + + async init() { + let threadFuncMaxDepthArray = await getMaxDepthByTid(); + info('Gets the maximum tier per thread , tid and maxDepth'); + threadFuncMaxDepthArray.forEach((it) => { + this.threadFuncMaxDepthMap.set(it.tid, it.maxDepth); + }); + info('convert tid and maxDepth array to map'); + let pidCountArray = await queryProcessContentCount(); + info('fetch per process pid,switch_count,thread_count,slice_count,mem_count'); + pidCountArray.forEach((it) => { + this.processThreadDataCountMap.set(it.pid, it.switch_count); + this.processThreadCountMap.set(it.pid, it.thread_count); + this.processFuncDataCountMap.set(it.pid, it.slice_count); + this.processMemDataCountMap.set(it.pid, it.mem_count); + }); + let queryProcessThreadResult = await queryProcessThreads(); + let queryProcessThreadsByTableResult = await queryProcessThreadsByTable(); + this.processAsyncEvent = await getAsyncEvents(); + info('The amount of initialized process Event data is : ', this.processAsyncEvent!.length); + this.processMem = await queryProcessMem(); + info('The amount of initialized process memory data is : ', this.processMem!.length); + let eventCountList: Array = await queryEventCountMap(); + this.eventCountMap = eventCountList.reduce((pre, current) => { + pre[`${current.eventName}`] = current.count; + return pre; + }, {}); + this.processThreads = Utils.removeDuplicates(queryProcessThreadResult, queryProcessThreadsByTableResult, 'tid'); + + info('The amount of initialized process threads data is : ', this.processThreads!.length); + if ( + this.eventCountMap['print'] == 0 && + this.eventCountMap['tracing_mark_write'] == 0 && + this.eventCountMap['sched_switch'] == 0 + ) { + return; + } + let time = new Date().getTime(); + let processes = await queryProcess(); + let processFromTable = await queryProcessByTable(); + let processList = Utils.removeDuplicates(processes, processFromTable, 'pid'); + let allJankProcessData = await queryAllJankProcess(); + let allJankProcess: Array = []; + let allExpectedProcess: Array = []; + let allActualProcess: Array = []; + if (allJankProcessData.length > 0) { + allJankProcessData.forEach((name, index) => { + allJankProcess.push(name.pid!); + }); + allExpectedProcess = await queryAllExpectedData(); + allActualProcess = await queryAllActualData(); + } + info('ProcessList Data size is: ', processList!.length); + for (let i = 0; i < processList.length; i++) { + const it = processList[i]; + if ( + (this.processThreadDataCountMap.get(it.pid) || 0) == 0 && + (this.processThreadCountMap.get(it.pid) || 0) == 0 && + (this.processFuncDataCountMap.get(it.pid) || 0) == 0 && + (this.processMemDataCountMap.get(it.pid) || 0) == 0 + ) { + continue; + } + let processRow = TraceRow.skeleton(); + processRow.rowId = `${it.pid}`; + processRow.index = i; + processRow.rowType = TraceRow.ROW_TYPE_PROCESS; + processRow.rowParentId = ''; + processRow.style.height = '40px'; + processRow.folder = true; + processRow.name = `${it.processName || 'Process'} ${it.pid}`; + processRow.supplier = () => queryProcessData(it.pid || -1, 0, TraceRow.range?.totalNS || 0); + processRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + processRow.selectChangeHandler = this.trace.selectChangeHandler; + processRow.onThreadHandler = (useCache) => { + processRow.canvasSave(this.trace.canvasPanelCtx!); + if (processRow.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, processRow.frame.width, processRow.frame.height); + } else { + (renders['process'] as ProcessRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + pid: it.pid, + useCache: useCache, + type: `process ${processRow.index} ${it.processName}`, + }, + processRow + ); + } + processRow.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(processRow); + /** + * Janks Frames + */ + let actualRow: TraceRow | null = null; + let expectedRow: TraceRow | null = null; + if (allJankProcess.indexOf(it.pid) > -1 && allExpectedProcess.length > 0) { + let expectedData = allExpectedProcess.filter((ite) => ite.pid == it.pid); + if (expectedData.length > 0) { + // @ts-ignore + let isIntersect = (a: JanksStruct, b: JanksStruct) => + Math.max(a.ts + a.dur, b.ts + b.dur) - Math.min(a.ts, b.ts) < a.dur + b.dur; + let depthArray: any = []; + for (let j = 0; j < expectedData.length; j++) { + let it = expectedData[j]; + if (it.cmdline != 'render_service') { + it.frame_type = 'app'; + } else { + it.frame_type = it.cmdline; + } + if (!it.dur || it.dur < 0) { + continue; + } + if (depthArray.length === 0) { + it.depth = 0; + depthArray.push(it); + } else { + if (isIntersect(depthArray[0], it)) { + if (isIntersect(depthArray[depthArray.length - 1], it)) { + it.depth = depthArray.length; + depthArray.push(it); + } + } else { + it.depth = 0; + depthArray = [it]; + } + } + } + let max = Math.max(...expectedData.map((it) => it.depth || 0)) + 1; + let maxHeight = max * 20; + expectedRow = TraceRow.skeleton(); + let timeLineType = expectedData[0].type; + expectedRow.rowId = `${timeLineType}-${it.pid}`; + expectedRow.asyncFuncName = it.processName; + expectedRow.asyncFuncNamePID = it.pid; + expectedRow.rowType = TraceRow.ROW_TYPE_JANK; + expectedRow.rowParentId = `${it.pid}`; + expectedRow.rowHidden = !processRow.expansion; + expectedRow.style.width = `100%`; + expectedRow.style.height = `${maxHeight}px`; + expectedRow.setAttribute('height', `${maxHeight}`); + expectedRow.setAttribute('frame_type', expectedData[0].frame_type); + expectedRow.name = `Expected Timeline`; + expectedRow.setAttribute('children', ''); + expectedRow.supplier = () => + new Promise((resolve) => { + resolve(expectedData); + }); + expectedRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + expectedRow.selectChangeHandler = this.trace.selectChangeHandler; + expectedRow.onThreadHandler = (useCache) => { + let context = expectedRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + expectedRow!.canvasSave(context); + (renders['jank'] as JankRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `expected_frame_timeline_slice`, + }, + expectedRow! + ); + expectedRow!.canvasRestore(context); + }; + processRow.addChildTraceRow(expectedRow); + let actualData = allActualProcess.filter((ite) => ite.pid == it.pid); + if (actualData.length > 0) { + let isIntersect = (a: any, b: any) => + Math.max(a.ts + a.dur, b.ts + b.dur) - Math.min(a.ts, b.ts) < a.dur + b.dur; + let depthArray: any = []; + for (let j = 0; j < actualData.length; j++) { + let it = actualData[j]; + if (it.cmdline != 'render_service') { + it.frame_type = 'app'; + } else { + it.frame_type = it.cmdline; + } + if (!it.dur || it.dur < 0) { + continue; + } + if (depthArray.length === 0) { + it.depth = 0; + depthArray.push(it); + } else { + if (isIntersect(depthArray[0], it)) { + if (isIntersect(depthArray[depthArray.length - 1], it)) { + it.depth = depthArray.length; + depthArray.push(it); + } + } else { + it.depth = 0; + depthArray = [it]; + } + } + } + let max = Math.max(...actualData.map((it) => it.depth || 0)) + 1; + let maxHeight = max * 20; + actualRow = TraceRow.skeleton(); + let timeLineType = actualData[0].type; + actualRow.rowId = `${timeLineType}-${it.pid}`; + actualRow.rowType = TraceRow.ROW_TYPE_JANK; + actualRow.rowParentId = `${it.pid}`; + actualRow.rowHidden = !processRow.expansion; + actualRow.style.width = `100%`; + actualRow.style.height = `${maxHeight}px`; + actualRow.setAttribute('height', `${maxHeight}`); + actualRow.name = `Actual Timeline`; + actualRow.setAttribute('frame_type', actualData[0].frame_type); + actualRow.setAttribute('children', ''); + actualRow.dataList = actualData; + actualRow.supplier = () => new Promise((resolve) => resolve(actualData)); + actualRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + actualRow.selectChangeHandler = this.trace.selectChangeHandler; + actualRow.onThreadHandler = (useCache) => { + let context = actualRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + actualRow!.canvasSave(context); + (renders['jank'] as JankRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `actual_frame_timeline_slice`, + }, + actualRow! + ); + actualRow!.canvasRestore(context); + }; + processRow.addChildTraceRow(actualRow); + } + } + } + let offsetYTimeOut: any = undefined; + processRow.addEventListener('expansion-change', (e: any) => { + if (offsetYTimeOut) { + clearTimeout(offsetYTimeOut); + } + if (e.detail.expansion) { + if (JankStruct!.selectJankStruct) { + JankStruct.delJankLineFlag = true; + } else { + JankStruct.delJankLineFlag = false; + } + offsetYTimeOut = setTimeout(() => { + this.trace.linkNodes.forEach((linkNode) => { + JankStruct.selectJankStructList?.forEach((dat: any) => { + if (e.detail.rowId == dat.pid) { + JankStruct.selectJankStruct = dat; + JankStruct.hoverJankStruct = dat; + } + }); + if (linkNode[0].rowEL.collect) { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY; + if (linkNode[1].rowEL.collect) { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY; + if (linkNode[0].rowEL.rowId == e.detail.rowId) { + linkNode[0].x = ns2xByTimeShaft(linkNode[0].ns, this.trace.timerShaftEL!); + linkNode[0].y = actualRow!.translateY! + linkNode[0].offsetY * 2; + linkNode[0].offsetY = linkNode[0].offsetY * 2; + linkNode[0].rowEL = actualRow!; + } else if (linkNode[1].rowEL.rowId == e.detail.rowId) { + linkNode[1].x = ns2xByTimeShaft(linkNode[1].ns, this.trace.timerShaftEL!); + linkNode[1].y = actualRow!.translateY! + linkNode[1].offsetY * 2; + linkNode[1].offsetY = linkNode[1].offsetY * 2; + linkNode[1].rowEL = actualRow!; + } + }); + }, 300); + } else { + JankStruct.delJankLineFlag = false; + if (JankStruct!.selectJankStruct) { + JankStruct.selectJankStructList?.push(JankStruct!.selectJankStruct); + } + offsetYTimeOut = setTimeout(() => { + this.trace.linkNodes?.forEach((linkNode) => { + if (linkNode[0].rowEL.collect) { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[0].rowEL.translateY = linkNode[0].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[0].y = linkNode[0].rowEL!.translateY! + linkNode[0].offsetY; + if (linkNode[1].rowEL.collect) { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.getBoundingClientRect().top - 195; + } else { + linkNode[1].rowEL.translateY = linkNode[1].rowEL.offsetTop - this.trace.rowsPaneEL!.scrollTop; + } + linkNode[1].y = linkNode[1].rowEL!.translateY! + linkNode[1].offsetY; + if (linkNode[0].rowEL.rowParentId == e.detail.rowId) { + linkNode[0].x = ns2xByTimeShaft(linkNode[0].ns, this.trace.timerShaftEL!); + linkNode[0].y = processRow!.translateY! + linkNode[0].offsetY / 2; + linkNode[0].offsetY = linkNode[0].offsetY / 2; + linkNode[0].rowEL = processRow!; + } else if (linkNode[1].rowEL.rowParentId == e.detail.rowId) { + linkNode[1].x = ns2xByTimeShaft(linkNode[1].ns, this.trace.timerShaftEL!); + linkNode[1].y = processRow!.translateY! + linkNode[1].offsetY / 2; + linkNode[1].offsetY = linkNode[1].offsetY / 2; + linkNode[1].rowEL = processRow!; + } + }); + }, 300); + } + let refreshTimeOut = setTimeout(() => { + this.trace.refreshCanvas(true); + clearTimeout(refreshTimeOut); + }, 360); + }); + /** + * Async Function + */ + let asyncFuncList = this.processAsyncFuncMap[it.pid] || []; + let asyncFuncGroup = Utils.groupBy(asyncFuncList, 'funName'); + Reflect.ownKeys(asyncFuncGroup).map((key: any) => { + let asyncFunctions: Array = asyncFuncGroup[key]; + if (asyncFunctions.length > 0) { + let isIntersect = (a: any, b: any) => + Math.max(a.startTs + a.dur, b.startTs + b.dur) - Math.min(a.startTs, b.startTs) < a.dur + b.dur; + let depthArray: any = []; + let createDepth = (currentDepth: number, index: number) => { + if ( + depthArray[currentDepth] == undefined || + !isIntersect(depthArray[currentDepth], asyncFunctions[index]) + ) { + asyncFunctions[index].depth = currentDepth; + depthArray[currentDepth] = asyncFunctions[index]; + } else { + createDepth(++currentDepth, index); + } + }; + asyncFunctions.forEach((it, i) => { + if (it.dur == -1) { + it.dur = (TraceRow.range?.endNS || 0) - it.startTs; + it.flag = 'Did not end'; + } + createDepth(0, i); + }); + let max = Math.max(...asyncFunctions.map((it) => it.depth || 0)) + 1; + let maxHeight = max * 20; + let funcRow = TraceRow.skeleton(); + funcRow.rowId = `${asyncFunctions[0].funName}-${it.pid}`; + funcRow.asyncFuncName = asyncFunctions[0].funName; + funcRow.asyncFuncNamePID = it.pid; + funcRow.rowType = TraceRow.ROW_TYPE_FUNC; + funcRow.rowParentId = `${it.pid}`; + funcRow.rowHidden = !processRow.expansion; + funcRow.style.width = `100%`; + funcRow.style.height = `${maxHeight}px`; + funcRow.setAttribute('height', `${maxHeight}`); + funcRow.name = `${asyncFunctions[0].funName}`; + funcRow.setAttribute('children', ''); + funcRow.supplier = () => new Promise((resolve) => resolve(asyncFunctions)); + funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + funcRow.selectChangeHandler = this.trace.selectChangeHandler; + funcRow.onThreadHandler = (useCache) => { + let context = funcRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + funcRow.canvasSave(context); + (renders['func'] as FuncRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `func-${asyncFunctions[0].funName}-${it.pid}`, + }, + funcRow + ); + funcRow.canvasRestore(context); + }; + processRow.addChildTraceRow(funcRow); + } + }); + + /** + * 添加进程内存信息 + */ + let processMem = this.processMem.filter((mem) => mem.pid === it.pid); + processMem.forEach((mem) => { + let row = TraceRow.skeleton(); + row.rowId = `${mem.trackId}`; + row.rowType = TraceRow.ROW_TYPE_MEM; + row.rowParentId = `${it.pid}`; + row.rowHidden = !processRow.expansion; + row.style.height = '40px'; + row.style.width = `100%`; + row.name = `${mem.trackName}`; + row.setAttribute('children', ''); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.focusHandler = () => { + this.trace.displayTip( + row, + ProcessMemStruct.hoverProcessMemStruct, + `${ProcessMemStruct.hoverProcessMemStruct?.value || '0'}` + ); + }; + row.supplier = () => + queryProcessMemData(mem.trackId).then((res) => { + let maxValue = Math.max(...res.map((it) => it.value || 0)); + for (let j = 0; j < res.length; j++) { + res[j].maxValue = maxValue; + if (j == res.length - 1) { + res[j].duration = (TraceRow.range?.totalNS || 0) - (res[j].startTime || 0); + } else { + res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0); + } + if (j > 0) { + res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0); + } else { + res[j].delta = 0; + } + } + return res; + }); + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders['mem'] as MemRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `mem ${mem.trackId} ${mem.trackName}`, + }, + row + ); + row.canvasRestore(context); + }; + processRow.addChildTraceRow(row); + }); + /** + * add thread list + */ + let threads = this.processThreads.filter((thread) => thread.pid === it.pid && thread.tid != 0); + for (let j = 0; j < threads.length; j++) { + let thread = threads[j]; + let threadRow = TraceRow.skeleton(); + threadRow.rowId = `${thread.tid}`; + threadRow.rowType = TraceRow.ROW_TYPE_THREAD; + threadRow.rowParentId = `${it.pid}`; + threadRow.rowHidden = !processRow.expansion; + threadRow.index = j; + threadRow.style.height = '30px'; + threadRow.style.width = `100%`; + threadRow.name = `${thread.threadName || 'Thread'} ${thread.tid}`; + threadRow.setAttribute('children', ''); + threadRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + threadRow.selectChangeHandler = this.trace.selectChangeHandler; + threadRow.supplier = () => + queryThreadData(thread.tid || 0).then((res) => { + if (res.length <= 0) { + threadRow.rowDiscard = true; + this.trace.refreshCanvas(true); + } + return res; + }); + threadRow.focusHandler = (ev) => {}; + threadRow.onThreadHandler = (useCache) => { + let context = threadRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + threadRow.canvasSave(context); + (renders['thread'] as ThreadRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `thread ${thread.tid} ${thread.threadName}`, + translateY: threadRow.translateY, + }, + threadRow + ); + threadRow.canvasRestore(context); + }; + if (threadRow.rowId == threadRow.rowParentId) { + if (actualRow != null) { + processRow.addChildTraceRowAfter(threadRow, actualRow); + } else if (expectedRow != null) { + processRow.addChildTraceRowAfter(threadRow, expectedRow); + } else { + processRow.addChildTraceRowSpecifyLocation(threadRow, 0); + } + } else { + processRow.addChildTraceRow(threadRow); + } + if (this.threadFuncMaxDepthMap.get(thread.tid!) != undefined) { + let max = this.threadFuncMaxDepthMap.get(thread.tid!) || 1; + let maxHeight = max * 20; + let funcRow = TraceRow.skeleton(); + funcRow.rowId = `${thread.tid}`; + funcRow.rowType = TraceRow.ROW_TYPE_FUNC; + funcRow.rowParentId = `${it.pid}`; + funcRow.rowHidden = !processRow.expansion; + funcRow.checkType = threadRow.checkType; + funcRow.style.width = `100%`; + funcRow.style.height = `${maxHeight}px`; + funcRow.name = `${thread.threadName || 'Thread'} ${thread.tid}`; + funcRow.setAttribute('children', ''); + funcRow.supplier = () => + getFunDataByTid(thread.tid || 0).then((funs: Array) => { + if (funs.length > 0) { + let isBinder = (data: FuncStruct): boolean => { + return ( + data.funName != null && + (data.funName.toLowerCase().startsWith('binder transaction async') || //binder transaction + data.funName.toLowerCase().startsWith('binder async') || + data.funName.toLowerCase().startsWith('binder reply')) + ); + }; + funs.forEach((fun) => { + if (isBinder(fun)) { + } else { + if (fun.dur == -1) { + fun.dur = (TraceRow.range?.totalNS || 0) - (fun.startTs || 0); + fun.flag = 'Did not end'; + } + } + }); + } else { + funcRow.rowDiscard = true; + this.trace.refreshCanvas(true); + } + return funs; + }); + funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + funcRow.selectChangeHandler = this.trace.selectChangeHandler; + funcRow.onThreadHandler = (useCache) => { + let context = funcRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + funcRow.canvasSave(context); + (renders['func'] as FuncRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `func${thread.tid}${thread.threadName}`, + }, + funcRow + ); + funcRow.canvasRestore(context); + }; + processRow.addChildTraceRowAfter(funcRow, threadRow); + } + } + } + let durTime = new Date().getTime() - time; + info('The time to load the Process data is: ', durTime); + } + + insertAfter(newEl: HTMLElement, targetEl: HTMLElement) { + let parentEl = targetEl.parentNode; + if (parentEl!.lastChild == targetEl) { + parentEl!.appendChild(newEl); + } else { + parentEl!.insertBefore(newEl, targetEl.nextSibling); + } + } +} diff --git a/ide/src/trace/component/chart/SpSdkChart.ts b/ide/src/trace/component/chart/SpSdkChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..76eaef6e62cae3519a947f857fd811715a46bd99 --- /dev/null +++ b/ide/src/trace/component/chart/SpSdkChart.ts @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; + +import { BaseStruct } from '../../bean/BaseStruct.js'; +import { + queryCounterMax, + querySdkCount, + querySdkCounterData, + querySdkSliceData, + queryStartTime, +} from '../../database/SqlLite.js'; +import { CounterStruct, SdkCounterRender } from '../../database/ui-worker/ProduceWorkerSdkCounter.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { SdkSliceRender, SdkSliceStruct } from '../../database/ui-worker/ProduceWorkerSdkSlice.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class SpSdkChart { + private trace: SpSystemTrace; + private pluginName = 'dubai-plugin'; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + parseJson(startTime: number, map: Map) { + let tablesMap = new Map(); + let keys = map.keys(); + for (let key of keys) { + let table = []; + let configObj: any = map.get(key); + if (configObj != undefined) { + let configStr = configObj.jsonConfig; + let json = JSON.parse(configStr); + let tableConfig = json.tableConfig; + if (tableConfig != null) { + let showTypes = tableConfig.showType; + for (let i = 0; i < showTypes.length; i++) { + let showType = showTypes[i]; + let type = this.getTableType(showType); + if (type == 'counter') { + let chartSql = this.createSql( + startTime, + showType.tableName, + showType.columns, + 'where counter_id' + ' = $counter_id' + ); + let maxValue = this.createMaxValueSql(showType.tableName, 'where counter_id = $counter_id'); + let innerTable = showType.inner; + let countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns); + table.push({ + countSql: countSql, + chartSql: chartSql, + maxSql: maxValue, + type: 'counter', + name: configObj.disPlayName, + pluginName: configObj.pluginName, + }); + } else if (type == 'slice') { + let chartSql = this.createSliceSql( + startTime, + showType.tableName, + showType.columns, + 'where' + ' slice_id = $column_id and (start_ts - ' + startTime + ') between $startNS and $endNS;' + ); + let innerTable = showType.inner; + let countSql; + let countOtherSql = ''; + if (configObj.pluginName == this.pluginName) { + countSql = this.createSql( + startTime, + innerTable.tableName, + innerTable.columns, + 'where slice_name like $suffix' + ); + countOtherSql = this.createSql( + startTime, + innerTable.tableName, + innerTable.columns, + '' + + "where slice_name not like '%_cpu' and slice_name not like '%_display' and slice_name not like '%_gpu'" + + "and slice_name not like '%_System_idle' and slice_name not like '%_wifi_data' " + + "and slice_name not like '%_sensor' and slice_name not like '%_audio' " + ); + } else { + countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns); + } + table.push({ + countSql: countSql, + chartSql: chartSql, + type: 'slice', + name: configObj.disPlayName, + pluginName: configObj.pluginName, + countOtherSql: countOtherSql, + }); + } + } + tablesMap.set(key, table); + } + } + } + return tablesMap; + } + + private getTableType(showType: any) { + let columns = showType.columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + let showType = column.showType; + if (showType != null) { + if (showType.indexOf(1) != -1) { + return 'counter'; + } + if (showType.indexOf(2) != -1) { + return 'slice'; + } + } + } + return ''; + } + + private createSliceSql(startTime: number, tableName: string, columns: Array, where?: string): string { + let selectSql = 'select '; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + if (column.column == 'start_ts') { + column.column = '(start_ts - ' + startTime + ') AS start_ts'; + } + if (column.column == 'end_ts') { + column.column = '(end_ts - ' + startTime + ') AS end_ts'; + } + if (i == columns.length - 1) { + selectSql = selectSql + column.column + ' '; + } else { + selectSql = selectSql + column.column + ', '; + } + } + selectSql = selectSql + 'from ' + tableName; + if (where != undefined) { + selectSql = selectSql + ' ' + where; + } + return selectSql; + } + + private createMaxValueSql(tableName: string, where?: string): string { + let selectSql = 'select max(value) as max_value from ' + tableName; + if (where != undefined) { + selectSql = selectSql + ' ' + where; + } + return selectSql; + } + + private createSql(startTime: number, tableName: string, columns: Array, where?: string): string { + let selectSql = 'select '; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + if (column.column == 'ts') { + column.column = 'ts - ' + startTime + ' AS ts'; + } + if (i == columns.length - 1) { + selectSql = selectSql + column.column + ' '; + } else { + selectSql = selectSql + column.column + ', '; + } + } + selectSql = selectSql + 'from ' + tableName; + if (where != undefined) { + selectSql = selectSql + ' ' + where; + } + return selectSql; + } + + async init() { + let configMap = SpSystemTrace.SDK_CONFIG_MAP; + if (configMap == undefined) return; + let res = await queryStartTime(); + let startTime = res[0].start_ts; + let tablesMap = this.parseJson(startTime, configMap); + let tableKeys = tablesMap.keys(); + for (let componentId of tableKeys) { + let table = tablesMap.get(componentId); + if (table != null) { + let nodeRow = this.initNodeRow(componentId, table[0].name); + for (let index = 0; index < table.length; index++) { + let sqlMap = table[index]; + if (sqlMap.type == 'counter') { + let result = await querySdkCount(sqlMap.countSql, componentId); + for (let i = 0; i < result.length; i++) { + await this.initCounter(nodeRow, i, result[i], sqlMap, componentId); + } + } else if (sqlMap.type == 'slice' && sqlMap.pluginName == this.pluginName) { + let suffixList = ['cpu', 'display', 'gpu', 'System_idle', 'wifi_data', 'sensor', 'audio']; + for (let i = 0; i < suffixList.length; i++) { + let result = await querySdkCount(sqlMap.countSql, componentId, { $suffix: '%' + suffixList[i] }); + if (result.length > 0) { + let groupNodeRow = await this.initSecondaryRow(nodeRow, i, suffixList[i]); + for (let i = 0; i < result.length; i++) { + await this.initSlice(groupNodeRow, i, result[i], sqlMap, componentId); + } + } + } + let result = await querySdkCount(sqlMap.countOtherSql, componentId); + if (result.length > 0) { + let groupNodeRow = await this.initSecondaryRow(nodeRow, 7, 'other'); + for (let i = 0; i < result.length; i++) { + await this.initSlice(groupNodeRow, i, result[i], sqlMap, componentId); + } + } + } else if (sqlMap.type == 'slice') { + let result = await querySdkCount(sqlMap.countSql, componentId, {}); + for (let i = 0; i < result.length; i++) { + await this.initSlice(nodeRow, i, result[i], sqlMap, componentId); + } + } + } + } + } + } + + private initCounter = async ( + nodeRow: TraceRow, + index: number, + result: any, + sqlMap: any, + componentId: number + ) => { + let traceRow = TraceRow.skeleton(); + traceRow.rowParentId = `Sdk-${componentId}`; + traceRow.rowHidden = !nodeRow.expansion; + traceRow.rowId = result.counter_id + '-' + componentId; + traceRow.rowType = TraceRow.ROW_TYPE_SDK_COUNTER; + traceRow.folderPaddingLeft = 30; + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.style.height = '40px'; + traceRow.style.width = `100%`; + traceRow.setAttribute('children', ''); + traceRow.name = `${result.counter_name}`; + traceRow.supplier = () => querySdkCounterData(sqlMap.chartSql, result.counter_id, componentId); + traceRow.focusHandler = () => { + this.trace?.displayTip( + traceRow, + CounterStruct.hoverCounterStruct, + `${CounterStruct.hoverCounterStruct?.value?.toFixed(2)}` + ); + }; + let maxList = await queryCounterMax(sqlMap.maxSql, result.counter_id, componentId); + let maxCounter = maxList[0].max_value; + traceRow.onThreadHandler = (useCache) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders[TraceRow.ROW_TYPE_SDK_COUNTER] as SdkCounterRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `sdk-counter-${index}`, + maxName: `${maxCounter}`, + maxValue: maxCounter, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + nodeRow.addChildTraceRow(traceRow); + }; + + private initNodeRow = (index: number, name: string) => { + let folder = TraceRow.skeleton(); + folder.rowId = `Sdk-${index}`; + folder.index = index; + folder.rowType = TraceRow.ROW_TYPE_SDK; + folder.rowParentId = ''; + folder.style.height = '40px'; + folder.folder = true; + folder.name = `${name}`; + folder.favoriteChangeHandler = this.trace.favoriteChangeHandler; + folder.selectChangeHandler = this.trace.selectChangeHandler; + folder.supplier = () => new Promise>((resolve) => resolve([])); + folder.onThreadHandler = (useCache) => { + folder.canvasSave(this.trace.canvasPanelCtx!); + if (folder.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + folder + ); + } + folder.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(folder); + return folder; + }; + + private initSecondaryRow = async (nodeRow: TraceRow, index: number, name: string) => { + let folder = TraceRow.skeleton(); + folder.rowId = `Sdk-${name}-${index}`; + folder.index = index; + folder.rowType = TraceRow.ROW_TYPE_SDK; + folder.rowParentId = nodeRow.rowId; + folder.rowHidden = !nodeRow.expansion; + folder.style.height = '40px'; + folder.folder = true; + folder.folderPaddingLeft = 30; + folder.name = `${name}`; + folder.favoriteChangeHandler = this.trace.favoriteChangeHandler; + folder.selectChangeHandler = this.trace.selectChangeHandler; + folder.supplier = () => new Promise>((resolve) => resolve([])); + folder.onThreadHandler = (useCache) => { + folder.canvasSave(this.trace.canvasPanelCtx!); + if (folder.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + folder + ); + } + folder.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(folder); + return folder; + }; + + private initSlice = async ( + nodeRow: TraceRow, + index: number, + result: any, + sqlMap: any, + componentId: number + ) => { + let traceRow = TraceRow.skeleton(); + traceRow.rowType = TraceRow.ROW_TYPE_SDK_SLICE; + traceRow.rowHidden = !nodeRow.expansion; + traceRow.rowParentId = nodeRow.rowId; + traceRow.folderPaddingLeft = 30; + traceRow.style.height = '40px'; + traceRow.style.width = `100%`; + traceRow.name = `${result.slice_name}`; + traceRow.setAttribute('children', ''); + traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; + traceRow.selectChangeHandler = this.trace.selectChangeHandler; + traceRow.rowId = result.slice_id + '-' + componentId; + traceRow.supplier = () => + querySdkSliceData( + sqlMap.chartSql, + result.slice_id, + TraceRow.range?.startNS || 0, + TraceRow.range?.endNS || 0, + componentId + ); + traceRow.focusHandler = () => { + this.trace?.displayTip( + traceRow, + SdkSliceStruct.hoverSdkSliceStruct, + `${SdkSliceStruct.hoverSdkSliceStruct?.value}` + ); + }; + traceRow.onThreadHandler = (useCache: boolean) => { + let context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + traceRow.canvasSave(context); + (renders[TraceRow.ROW_TYPE_SDK_SLICE] as SdkSliceRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `sdk-slice-${index}`, + maxName: '', + maxValue: 0, + }, + traceRow + ); + traceRow.canvasRestore(context); + }; + nodeRow.addChildTraceRow(traceRow); + }; +} diff --git a/ide/src/trace/component/chart/SpVirtualMemChart.ts b/ide/src/trace/component/chart/SpVirtualMemChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa52e71d49285c5bb60328d0c6ee99b8c8f62d8b --- /dev/null +++ b/ide/src/trace/component/chart/SpVirtualMemChart.ts @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 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 { SpSystemTrace } from '../SpSystemTrace.js'; +import { TraceRow } from '../trace/base/TraceRow.js'; +import { queryVirtualMemory, queryVirtualMemoryData } from '../../database/SqlLite.js'; +import { VirtualMemoryRender, VirtualMemoryStruct } from '../../database/ui-worker/ProcedureWorkerVirtualMemory.js'; +import { renders } from '../../database/ui-worker/ProcedureWorker.js'; +import { EmptyRender } from '../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class SpVirtualMemChart { + private trace: SpSystemTrace; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + let array = await queryVirtualMemory(); + if (array.length == 0) { + return; + } + let folder = TraceRow.skeleton(); + folder.rowId = `VirtualMemory`; + folder.index = 0; + folder.rowType = TraceRow.ROW_TYPE_VIRTUAL_MEMORY_GROUP; + folder.rowParentId = ''; + folder.folder = true; + folder.name = `Virtual Memory`; + folder.style.height = '40px'; + folder.favoriteChangeHandler = this.trace.favoriteChangeHandler; + folder.selectChangeHandler = this.trace.selectChangeHandler; + folder.supplier = () => new Promise>((resolve) => resolve([])); + folder.onThreadHandler = (useCache) => { + folder.canvasSave(this.trace.canvasPanelCtx!); + if (folder.expansion) { + this.trace.canvasPanelCtx?.clearRect(0, 0, folder.frame.width, folder.frame.height); + } else { + (renders['empty'] as EmptyRender).renderMainThread( + { + context: this.trace.canvasPanelCtx, + useCache: useCache, + type: ``, + }, + folder + ); + } + folder.canvasRestore(this.trace.canvasPanelCtx!); + }; + this.trace.rowsEL?.appendChild(folder); + array.forEach((it, idx) => this.initVirtualMemoryRow(folder, it.id, it.name, idx)); + } + + initVirtualMemoryRow(folder: TraceRow, id: number, name: string, idx: number) { + let row = TraceRow.skeleton(); + row.rowId = `${id}`; + row.rowType = TraceRow.ROW_TYPE_VIRTUAL_MEMORY; + row.rowParentId = folder.rowId; + row.rowHidden = !folder.expansion; + row.style.height = '40px'; + row.name = `${name.substring(16)}`; + row.setAttribute('children', ''); + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + row.supplier = () => + queryVirtualMemoryData(id).then((res) => { + let maxValue = Math.max(...res.map((it) => it.value || 0)); + for (let j = 0; j < res.length; j++) { + res[j].maxValue = maxValue; + if (j == res.length - 1) { + res[j].duration = (TraceRow.range?.totalNS || 0) - (res[j].startTime || 0); + } else { + res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0); + } + if (j > 0) { + res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0); + } else { + res[j].delta = 0; + } + } + return res; + }); + row.focusHandler = () => { + this.trace?.displayTip( + row, + VirtualMemoryStruct.hoverStruct, + `value:${VirtualMemoryStruct.hoverStruct?.value}` + ); + }; + row.onThreadHandler = (useCache) => { + let context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; + row.canvasSave(context); + (renders['virtual-memory-cell'] as VirtualMemoryRender).renderMainThread( + { + context: context, + useCache: useCache, + type: `virtual-memory-cell-${id}`, + }, + row + ); + row.canvasRestore(context); + }; + folder.addChildTraceRow(row); + } +} diff --git a/ide/src/trace/component/metrics/CpuStrategy.ts b/ide/src/trace/component/metrics/CpuStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..42ab450fb0430c7dae9c84f2afe479cdfc4be946 --- /dev/null +++ b/ide/src/trace/component/metrics/CpuStrategy.ts @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initTest = (metricData: Array): ProcessInfoListItem => { + let processInfoListItems: Array = []; + for (let index = 0; index < metricData.length; index++) { + let eventName = metricData[index].event_name; + let stat_type = metricData[index].stat_type; + let count = metricData[index].count; + let source = metricData[index].source; + let serverity = metricData[index].serverity; + + let processInfoSource: ProcessInfoItem = { + // @ts-ignore + processName: eventName, + threads: { + // @ts-ignore + threadName: stat_type, + cpu: [ + { + cpu: eventName, + minFreq: stat_type, + maxFreq: count, + avgFrequency: source, + duration: serverity, + }, + ], + }, + }; + processInfoListItems?.push(processInfoSource); + } + return { + processInfo: processInfoListItems, + }; +}; + +export const initCpuStrategyData = (metricData: Array): ProcessInfoListItem => { + info('Cpu Strategy data length is:', metricData.length); + let processInfoListItems: Array = []; + if (metricData.length == 10) { + } else { + } + const splitChar: string = ','; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + if (metricData[sqlIndex].avg_frequency == null) { + continue; + } + let cpus = metricData[sqlIndex].cpu.split(splitChar); + let minFrequencies = metricData[sqlIndex].min_freq.split(splitChar); + let maxFrequencies = metricData[sqlIndex].max_freq.split(splitChar); + let avgFrequencies = metricData[sqlIndex].avg_frequency.split(splitChar); + let durations = metricData[sqlIndex].dur.split(splitChar); + + let arrayCpu = []; + for (let index = 0; index < cpus.length; index++) { + let cpuIndex: CpuItem = { + cpu: cpus[index], + minFreq: minFrequencies[index], + maxFreq: maxFrequencies[index], + avgFrequency: avgFrequencies[index], + duration: durations[index], + }; + arrayCpu.push(cpuIndex); + } + let processInfoSource: ProcessInfoItem = { + threads: { + cpu: arrayCpu, + }, + }; + processInfoListItems?.push(processInfoSource); + } + return { + processInfo: processInfoListItems, + }; +}; + +export interface ProcessInfoListItem { + processInfo: Array; +} + +export interface ProcessInfoItem { + threads: ThreadsItem; +} + +export interface ThreadsItem { + cpu: Array; +} + +export interface CpuItem { + cpu: string; + minFreq: string; + maxFreq: string; + avgFrequency: string; + duration: string; +} diff --git a/ide/src/trace/component/metrics/DistributeTermStrategy.ts b/ide/src/trace/component/metrics/DistributeTermStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..67bc60e8afae758fccc82a5561e5a01459366ef5 --- /dev/null +++ b/ide/src/trace/component/metrics/DistributeTermStrategy.ts @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initDistributedTermData = (metricData: Array): DistributedTermListItem => { + info('Distributed Term data length is:', metricData.length); + let distributedTermListItems: Array = []; + const splitChar = ','; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let threadIdsList = metricData[sqlIndex].threadId.split(splitChar); + let threadNamesList = metricData[sqlIndex].threadName.split(splitChar); + let processIdList = metricData[sqlIndex].processId.split(splitChar); + let processNameList = + metricData[sqlIndex].processName === null + ? threadIdsList.length + '' + : metricData[sqlIndex].processName.split(splitChar); + + let funNameList = metricData[sqlIndex].funName.split(splitChar); + let timeList = metricData[sqlIndex].ts.split(splitChar); + let durList = metricData[sqlIndex].dur.split(splitChar); + let flag = metricData[sqlIndex].flag; + let flagList = flag.split(splitChar); + let traceNameList = metricData[sqlIndex].trace_name; + let chainIdList = metricData[sqlIndex].chainId; + let spanIdList = metricData[sqlIndex].spanId; + let parentSpanIdList = metricData[sqlIndex].parentSpanId; + + let distributedTermListItem: DistributedTermItem = {}; + for (let index = 0; index < flagList.length; index++) { + let across: boolean = true; + let receiverTime: number = 0; + let senderTime: number = 0; + let delay: number = 0; + if (flag.indexOf('S,C') > -1 || flag.indexOf('C,S') > -1) { + across = false; + if (flagList[index] == 'S') receiverTime = timeList[index]; + if (flagList[index] == 'C') senderTime = timeList[index]; + delay = receiverTime - senderTime; + } + + let type = { + acrossTheDevice: across, + traceName: traceNameList, + traceId: { + chainID: chainIdList, + spanID: spanIdList, + parentSpanID: parentSpanIdList, + }, + functionName: funNameList[index], + processInfo: { + processId: processIdList[index], + processName: processNameList[index], + }, + threadInfoItem: { + threadId: threadIdsList[index], + threadName: threadNamesList[index], + }, + dur: durList[index], + delay: delay, + }; + if ('C' == flagList[index]) { + distributedTermListItem.sender = type; + } else { + distributedTermListItem.receiver = type; + } + } + distributedTermListItems?.push(distributedTermListItem); + } + return { + distributedTermItem: distributedTermListItems, + }; +}; + +export interface DistributedTermListItem { + distributedTermItem: Array; +} + +export interface DistributedTermItem { + sender?: SenderOrReceiverItem; + receiver?: SenderOrReceiverItem; +} + +export interface SenderOrReceiverItem { + acrossTheDevice?: boolean; + traceName: string; + traceId: TraceIdItem; + functionName: string; + processInfo: ProcessInfoItem; + threadInfoItem: ThreadInfoItem; + dur: string; + delay: number; +} + +export interface TraceIdItem { + chainID: string; + spanID: string; + parentSpanID: string; +} + +export interface ProcessInfoItem { + processId: string; + processName: string; +} + +export interface ThreadInfoItem { + threadId: string; + threadName: string; +} diff --git a/ide/src/trace/component/metrics/MemAggStrategy.ts b/ide/src/trace/component/metrics/MemAggStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..0d7a24125d730dc85b6bbd2087c24b276ed61577 --- /dev/null +++ b/ide/src/trace/component/metrics/MemAggStrategy.ts @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initMemoryAggStrategy = (metricData: Array): ProcessValuesListItem => { + info('Memory Agg Strategy data length is:', metricData.length); + let processValuesListItems: Array = []; + const splitChar: string = ','; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let processNames = metricData[sqlIndex].processName; + let processInfoSource: ProcessValuesItem = { + processName: processNames, + }; + if (metricData[sqlIndex].name == null) { + let values = metricData[sqlIndex].value.split(splitChar); + let times = metricData[sqlIndex].ts.split(splitChar); + let oomScoreValue = 0; + for (let index = 0; index < values.length; index++) { + if (!processInfoSource) continue; + processValuesListItems?.push(processInfoSource); + } + } else { + let names = metricData[sqlIndex].name.split(splitChar); + let values = metricData[sqlIndex].value.split(splitChar); + let times = metricData[sqlIndex].ts.split(splitChar); + let oomScoreValue = 0; + for (let indexScore = 0; indexScore < names.length; indexScore++) { + if ('oom_score_adj' === names[indexScore]) { + oomScoreValue = values[indexScore]; + break; + } + } + for (let index = 0; index < names.length; index++) { + let typeItem: TypeItem = { + ts: times[index], + oom_score: oomScoreValue, + value: values[index], + }; + if (!processInfoSource) continue; + if ('mem.rss.anon' === names[index]) { + processInfoSource.anonRss = typeItem; + } + if ('mem.swap' === names[index]) { + processInfoSource.swap = typeItem; + } + if ('mem.rss.file' === names[index]) { + processInfoSource.fileRss = typeItem; + } + if ('oom_score_adj' === names[index]) { + processInfoSource.anonAndSwap = typeItem; + } + } + } + processValuesListItems?.push(processInfoSource); + } + return { + processValues: processValuesListItems, + }; +}; + +export interface ProcessValuesListItem { + processValues: Array; +} + +export interface ProcessValuesItem { + processName: string; + anonRss?: TypeItem; + swap?: TypeItem; + fileRss?: TypeItem; + anonAndSwap?: TypeItem; +} + +export interface TypeItem { + ts: number; + oom_score: number; + value: number; +} diff --git a/ide/src/trace/component/metrics/MemStrategy.ts b/ide/src/trace/component/metrics/MemStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7ad94fd34fe572e004c97a11fab2ab03d2b0aa2 --- /dev/null +++ b/ide/src/trace/component/metrics/MemStrategy.ts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initMemoryStrategy = (metricData: Array): ProcessMetricsListItems => { + info('Memory Strategy data length is:', metricData.length); + let processMetricsListItems: Array = []; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let processName = metricData[sqlIndex].processName; + let minNum = metricData[sqlIndex].minNum < 0 ? 0 : metricData[sqlIndex].minNum; + let maxNum = metricData[sqlIndex].maxNum; + let avgNum = metricData[sqlIndex].avgNum; + let processInfoSource: ProcessMetricsItems = { + processName: processName, + overallCounters: { + anonRss: { + min: minNum, + max: maxNum, + avg: avgNum, + }, + }, + }; + processMetricsListItems?.push(processInfoSource); + } + return { + processMetrics: processMetricsListItems, + }; +}; + +export interface ProcessMetricsListItems { + processMetrics: Array; +} + +export interface ProcessMetricsItems { + processName: string; + overallCounters: AnonRssItem; +} + +export interface AnonRssItem { + anonRss: TypeItem; +} + +export interface TypeItem { + min: number; + max: number; + avg: number; +} diff --git a/ide/src/trace/component/metrics/MetaDataStrategy.ts b/ide/src/trace/component/metrics/MetaDataStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..70e75a90d15fa7a36fa4ab11ecd6200314d23bf5 --- /dev/null +++ b/ide/src/trace/component/metrics/MetaDataStrategy.ts @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initMetaDataStrategy = (metricData: Array): TraceMetadata => { + info('Meta Strategy data length is:', metricData.length); + let traceMetaDataList: Array = []; + let statDataArray = []; + let jsonText = `{`; + for (let index = 0; index < metricData.length; index++) { + let name = metricData[index].name; + let value = metricData[index].valueText; + if (!value.match('^-?\\d+$')) { + value = '"' + value.replace('\r|\n', '') + '"'; + } + jsonText += `'` + name + `'` + `: ` + `'` + value.toString() + `'` + `,`; + if (index >= metricData.length - 1) { + jsonText += `}`; + } + } + + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let name = metricData[sqlIndex].name; + let value = metricData[sqlIndex].valueText; + if (!value.match('^-?\\d+$')) { + value = '"' + value.replace('\r|\n', '') + '"'; + } + let traceMetaData = { + name: name, + value: value, + }; + traceMetaDataList?.push(traceMetaData); + } + return { + traceMetadata: traceMetaDataList, + }; +}; + +export interface TraceMetadata { + traceMetadata: Array; +} + +export interface TraceMetadataItem { + name: string; + value: string; +} diff --git a/ide/src/trace/component/metrics/SysCallsStrategy.ts b/ide/src/trace/component/metrics/SysCallsStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..b57d6cb0a87cad8d00c55021487e1fc137a755ea --- /dev/null +++ b/ide/src/trace/component/metrics/SysCallsStrategy.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initSysCallsStrategy = (metricData: Array): FunctionListItem => { + info('System Calls Strategy data length is:', metricData.length); + let functionListItems: Array = []; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let functionNames = metricData[sqlIndex].funName; + let durMaxes = metricData[sqlIndex].maxDur; + let durMines = metricData[sqlIndex].minDur; + let durAvgs = Math.floor(metricData[sqlIndex].avgDur).toString(); + let functionItem: FunctionItem = { + functionName: functionNames, + durMax: durMaxes, + durMin: durMines, + durAvg: durAvgs, + }; + functionListItems?.push(functionItem); + } + return { + function: functionListItems, + }; +}; + +export interface FunctionListItem { + function: Array; +} + +export interface FunctionItem { + functionName: string; + durMax: string; + durMin: string; + durAvg: string; +} diff --git a/ide/src/trace/component/metrics/SysCallsTopStrategy.ts b/ide/src/trace/component/metrics/SysCallsTopStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..a78a726dcb24f0fbce99c9428e5d60de243a5c26 --- /dev/null +++ b/ide/src/trace/component/metrics/SysCallsTopStrategy.ts @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initSysCallsTopStrategy = (metricData: Array): ProcessInfoListItem => { + info('System Calls Strategy data length is:', metricData.length); + let ProcessInfoListItems: Array = []; + + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let pidList = metricData[sqlIndex].pid; + let tidList = metricData[sqlIndex].tid; + let functionNames = metricData[sqlIndex].funName; + let durMaxes = metricData[sqlIndex].maxDur; + let durMines = metricData[sqlIndex].minDur < 0 ? 0 : metricData[sqlIndex].minDur; + let durAvgs = Math.floor(metricData[sqlIndex].avgDur).toString(); + + let processInfoItem: ProcessInfoItem = { + pid: pidList, + threads: { + tid: tidList, + function: { + functionName: functionNames, + durMax: durMaxes, + durMin: durMines, + durAvg: durAvgs, + }, + }, + }; + ProcessInfoListItems?.push(processInfoItem); + } + return { + processInfo: ProcessInfoListItems, + }; +}; + +export interface ProcessInfoListItem { + processInfo: Array; +} + +export interface ProcessInfoItem { + pid: string; + threads: ThreadsItem; +} + +export interface ThreadsItem { + tid: string; + function: FunctionItem; +} + +export interface FunctionItem { + functionName: string; + durMax: string; + durMin: string; + durAvg: string; +} diff --git a/ide/src/trace/component/metrics/TraceStatsStrategy.ts b/ide/src/trace/component/metrics/TraceStatsStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..dee35e8681ea42bd7c9ee53aed5ae296e09162a3 --- /dev/null +++ b/ide/src/trace/component/metrics/TraceStatsStrategy.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initTraceStateStrategy = (metricData: Array): StatListItem => { + info('Trace State Strategy data length is:', metricData.length); + let statListItems: Array = []; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let names = metricData[sqlIndex].event_name; + let counts = metricData[sqlIndex].count; + let sources = metricData[sqlIndex].source; + let severities = metricData[sqlIndex].serverity; + let statListItem: StatItem = { + name: names, + count: counts, + source: sources, + severity: severities, + }; + statListItems?.push(statListItem); + } + return { + stat: statListItems, + }; +}; + +export interface StatListItem { + stat: Array; +} + +export interface StatItem { + name: string; + count: string; + source: string; + severity: string; +} diff --git a/ide/src/trace/component/metrics/TraceTaskStrategy.ts b/ide/src/trace/component/metrics/TraceTaskStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c498cab66c5429b2d9440a233e8b10098b7c870 --- /dev/null +++ b/ide/src/trace/component/metrics/TraceTaskStrategy.ts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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 { info } from '../../../log/Log.js'; + +export const initTraceTaskStrategy = (metricData: Array): ProcessListItem => { + info('Trace Task Strategy data length is:', metricData.length); + let statListItems = []; + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let pidList = metricData[sqlIndex].pid; + let processNameList = metricData[sqlIndex].process_name; + let threadNameList = metricData[sqlIndex].thread_name; + let threadNames = []; + let newArr = ''; + if (threadNameList != null) { + threadNames = threadNameList.split(','); + newArr = threadNames.reduce((prev: any, item: any) => (prev.includes(item) ? prev : prev.concat(item)), []); + } + + let statListItem = { + pid: pidList, + processName: processNameList, + threadName: newArr, + }; + statListItems?.push(statListItem); + } + return { + process: statListItems, + }; +}; + +export interface ProcessListItem { + process: Array; +} + +export interface ProcessItem { + pid: string; + processName: string; + threadName: string; +} diff --git a/ide/src/trace/component/schedulingAnalysis/CheckCpuSetting.ts b/ide/src/trace/component/schedulingAnalysis/CheckCpuSetting.ts new file mode 100644 index 0000000000000000000000000000000000000000..4643a5e04549199a58a86b2168421773ce7aa42c --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/CheckCpuSetting.ts @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitCheckBox } from '../../../base-ui/checkbox/LitCheckBox.js'; +import '../../../base-ui/checkbox/LitCheckBox.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; +import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil.js'; + +export class CpuSetting { + cpu: number = 0; + big: boolean = false; + middle: boolean = true; + small: boolean = false; +} + +@element('check-cpu-setting') +export class CheckCpuSetting extends BaseElement { + static mid_cores: number[] = []; + static big_cores: number[] = []; + static small_cores: number[] = []; + static init_setting: boolean = false; + + private table: HTMLDivElement | null | undefined; + private setUpload: HTMLDivElement | null | undefined; + private listener?: () => void | undefined; + + initElements(): void { + this.table = this.shadowRoot!.querySelector('#tb_cpu_setting'); + this.setUpload = this.shadowRoot!.querySelector('#set_upload'); + this.setUpload!.addEventListener('click', (e) => { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'Analysis Upload', + action: 'scheduling_analysis', + }); + CheckCpuSetting.init_setting = true; + this.listener?.(); + }); + } + + set cpuSetListener(listener: () => void | undefined) { + this.listener = listener; + } + + init() { + this.initDefaultSetting(); + let data: any[] = []; + this.table!.innerHTML = ''; + this.createHeaderDiv(); + for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { + let obj = { + cpu: i, + // @ts-ignore + big: CheckCpuSetting.big_cores.includes(i), + // @ts-ignore + middle: CheckCpuSetting.mid_cores.includes(i), + // @ts-ignore + small: CheckCpuSetting.small_cores.includes(i), + }; + data.push(obj); + this.createTableLine(obj); + } + } + + initDefaultSetting() { + if (!CheckCpuSetting.init_setting) { + CheckCpuSetting.mid_cores = []; + CheckCpuSetting.big_cores = []; + CheckCpuSetting.small_cores = []; + for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { + CheckCpuSetting.mid_cores.push(i); + } + } + } + + createTableLine(cpuSetting: CpuSetting) { + let div = document.createElement('div'); + div.className = 'setting_line'; + div.textContent = cpuSetting.cpu + ''; + let bigCheckBox: LitCheckBox = new LitCheckBox(); + bigCheckBox.checked = cpuSetting.big; + let midCheckBox: LitCheckBox = new LitCheckBox(); + midCheckBox.checked = cpuSetting.middle; + let smallCheckBox: LitCheckBox = new LitCheckBox(); + smallCheckBox.checked = cpuSetting.small; + bigCheckBox.addEventListener('change', (e) => { + midCheckBox.checked = false; + smallCheckBox.checked = false; + cpuSetting.big = true; + CheckCpuSetting.big_cores.push(cpuSetting.cpu); + CheckCpuSetting.mid_cores = CheckCpuSetting.mid_cores.filter((it) => it !== cpuSetting.cpu); + CheckCpuSetting.small_cores = CheckCpuSetting.small_cores.filter((it) => it !== cpuSetting.cpu); + }); + midCheckBox.addEventListener('change', (e) => { + bigCheckBox.checked = false; + smallCheckBox.checked = false; + cpuSetting.middle = true; + CheckCpuSetting.mid_cores.push(cpuSetting.cpu); + CheckCpuSetting.big_cores = CheckCpuSetting.big_cores.filter((it) => it !== cpuSetting.cpu); + CheckCpuSetting.small_cores = CheckCpuSetting.small_cores.filter((it) => it !== cpuSetting.cpu); + }); + smallCheckBox.addEventListener('change', (e) => { + midCheckBox.checked = false; + bigCheckBox.checked = false; + cpuSetting.small = true; + CheckCpuSetting.small_cores.push(cpuSetting.cpu); + CheckCpuSetting.mid_cores = CheckCpuSetting.mid_cores.filter((it) => it !== cpuSetting.cpu); + CheckCpuSetting.big_cores = CheckCpuSetting.big_cores.filter((it) => it !== cpuSetting.cpu); + }); + this.table?.append(...[div, bigCheckBox, midCheckBox, smallCheckBox]); + } + + createHeaderDiv() { + let column1 = document.createElement('div'); + column1.className = 'setting_line'; + column1.style.fontWeight = 'bold'; + column1.textContent = 'cpu_id'; + let column2 = document.createElement('div'); + column2.className = 'setting_line'; + column2.style.fontWeight = 'bold'; + column2.textContent = 'big'; + let column3 = document.createElement('div'); + column3.className = 'setting_line'; + column3.style.fontWeight = 'bold'; + column3.textContent = 'middle'; + let column4 = document.createElement('div'); + column4.className = 'setting_line'; + column4.style.fontWeight = 'bold'; + column4.textContent = 'small'; + this.table?.append(...[column1, column2, column3, column4]); + } + + static resetCpuSettings() { + CheckCpuSetting.init_setting = false; + CheckCpuSetting.big_cores = []; + CheckCpuSetting.small_cores = []; + CheckCpuSetting.mid_cores = []; + } + + initHtml(): string { + return ` + +
+
+
CPU 大小核分类
+
Upload
+
+
+
+
+ + `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/DrawerCpuTabs.ts b/ide/src/trace/component/schedulingAnalysis/DrawerCpuTabs.ts new file mode 100644 index 0000000000000000000000000000000000000000..6545c0f7d65afdea1deb4347f235012132b25721 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/DrawerCpuTabs.ts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import './TabCpuDetailsFrequency.js'; +import './TabCpuDetailsIdle.js'; +import './TabCpuDetailsIrq.js'; +import { TabCpuDetailsFrequency } from './TabCpuDetailsFrequency.js'; +import { TabCpuDetailsIdle } from './TabCpuDetailsIdle.js'; +import { LitTabs } from '../../../base-ui/tabs/lit-tabs.js'; +import { TabCpuDetailsIrq } from './TabCpuDetailsIrq.js'; + +@element('drawer-cpu-tabs') +export class DrawerCpuTabs extends BaseElement { + private cpuNumber: number = 0; + private tabs: LitTabs | null | undefined; + private tabCpuDetailsFrequency: TabCpuDetailsFrequency | null | undefined; + private tabCpuDetailsIdle: TabCpuDetailsIdle | null | undefined; + private tabCpuDetailsIrq: TabCpuDetailsIrq | null | undefined; + + initElements(): void { + this.tabs = this.shadowRoot?.querySelector('#tabs'); + this.tabCpuDetailsFrequency = this.shadowRoot?.querySelector('#tab-cpu-details-frequency'); + this.tabCpuDetailsIdle = this.shadowRoot?.querySelector('#tab-cpu-details-idle'); + this.tabCpuDetailsIrq = this.shadowRoot?.querySelector('#tab-cpu-details-irq'); + + this.tabs!.onTabClick = (e: any) => { + if (e.detail.key == '1') { + this.tabCpuDetailsIdle?.init(this.cpuNumber); + } else if (e.detail.key == '2') { + this.tabCpuDetailsFrequency?.init(this.cpuNumber); + } else if (e.detail.key == '3') { + this.tabCpuDetailsIrq?.init(this.cpuNumber); + } + }; + } + + init(cpu: number, value: string) { + this.tabs!.activekey = value; + this.cpuNumber = cpu; + if (value == '1') { + this.tabCpuDetailsIdle?.init(this.cpuNumber); + } else if (value == '2') { + this.tabCpuDetailsFrequency?.init(this.cpuNumber); + } else if (value == '3') { + this.tabCpuDetailsIrq?.init(this.cpuNumber); + } + } + + clearData() { + this.tabCpuDetailsFrequency!.clearData(); + this.tabCpuDetailsIdle!.clearData(); + this.tabCpuDetailsIrq!.clearData(); + } + + initHtml(): string { + return ` + +
+ + + + + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/SpSchedulingAnalysis.ts b/ide/src/trace/component/schedulingAnalysis/SpSchedulingAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f45c1d7354d52042cf298a0a909ba07a0d7a177 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/SpSchedulingAnalysis.ts @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import './TabThreadAnalysis.js'; +import './TabCpuAnalysis.js'; +import { TabCpuAnalysis } from './TabCpuAnalysis.js'; +import { TabThreadAnalysis } from './TabThreadAnalysis.js'; +import { LitTabs } from '../../../base-ui/tabs/lit-tabs.js'; +import { CheckCpuSetting } from './CheckCpuSetting.js'; +import { Top20FrequencyThread } from './Top20FrequencyThread.js'; +import { procedurePool } from '../../database/Procedure.js'; + +@element('sp-scheduling-analysis') +export class SpSchedulingAnalysis extends BaseElement { + static traceChange: boolean = false; + static cpuCount: number = 0; + static startTs: number = 0; + static endTs: number = 0; + static totalDur: number = 0; + private tabs: LitTabs | null | undefined; + private tabCpuAnalysis: TabCpuAnalysis | null | undefined; + private tabThreadAnalysis: TabThreadAnalysis | null | undefined; + + initElements(): void { + this.tabs = this.shadowRoot?.querySelector('#tabs'); + this.tabCpuAnalysis = this.shadowRoot?.querySelector('#cpu-analysis'); + this.tabThreadAnalysis = this.shadowRoot?.querySelector('#thread-analysis'); + } + + static resetCpu() { + SpSchedulingAnalysis.traceChange = true; + CheckCpuSetting.resetCpuSettings(); + Top20FrequencyThread.threads = undefined; + procedurePool.submitWithName('logic1', 'scheduling-clearData', {}, undefined, (res: any) => {}); + } + + init() { + if (SpSchedulingAnalysis.traceChange) { + SpSchedulingAnalysis.traceChange = false; + this.tabs!.activekey = '1'; + SpSchedulingAnalysis.startTs = (window as any).recordStartNS; + SpSchedulingAnalysis.endTs = (window as any).recordEndNS; + SpSchedulingAnalysis.totalDur = SpSchedulingAnalysis.endTs - SpSchedulingAnalysis.startTs; + SpSchedulingAnalysis.cpuCount = (window as any).cpuCount; + this.tabCpuAnalysis?.init(); + this.tabThreadAnalysis?.init(); + } + } + + initHtml(): string { + return ` + +
+
+ + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TabCpuAnalysis.ts b/ide/src/trace/component/schedulingAnalysis/TabCpuAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..212b3f5a87aee06121a148a947d217dbbf303438 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TabCpuAnalysis.ts @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; +import { DrawerCpuTabs } from './DrawerCpuTabs.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import { LitDrawer } from '../../../base-ui/drawer/LitDrawer.js'; +import '../../../base-ui/drawer/LitDrawer.js'; +import './DrawerCpuTabs.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { info } from '../../../log/Log.js'; +import { LitSelect } from '../../../base-ui/select/LitSelect'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import { pieChartColors } from '../../../base-ui/chart/pie/LitChartPieData.js'; +import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('tab-cpu-analysis') +export class TabCpuAnalysis extends BaseElement { + private cpuUsageGrid: HTMLDivElement | undefined; + private cpuUsageChart: HTMLDivElement | undefined; + private drawer: LitDrawer | undefined | null; + private cpuPieMap: Map = new Map(); + private schedulingSelect: LitSelect | undefined | null; + private drawerCpuTabs: DrawerCpuTabs | undefined | null; + private progress: LitProgressBar | null | undefined; + private loadingUsage: boolean = false; + private loadingPieData: boolean = false; + + initElements(): void { + this.progress = this.shadowRoot!.querySelector('#loading'); + this.cpuUsageGrid = this.shadowRoot?.querySelector('#cpu_usage_table') as HTMLDivElement; + this.cpuUsageChart = this.shadowRoot?.querySelector('#cpu_usage_chart') as HTMLDivElement; + this.schedulingSelect = this.shadowRoot?.querySelector('#scheduling_select'); + this.drawer = this.shadowRoot!.querySelector('#drawer-right'); + this.drawerCpuTabs = this.shadowRoot?.querySelector('#drawer-cpu-tabs'); + this.schedulingSelect!.onchange = (e) => { + this.loadingPieData = true; + this.progress!.loading = this.loadingUsage || this.loadingPieData; + this.queryPieChartDataByType((e as any).detail.text); + }; + this.drawer!.onClose = (e: any) => { + this.drawerCpuTabs!.clearData(); + }; + } + + init() { + this.cpuPieMap.clear(); + this.cpuUsageGrid!.innerHTML = ''; + this.cpuUsageChart!.innerHTML = ''; + this.schedulingSelect!.value = '1'; + this.cpuUsageGrid!.append(this.createUsageItem('usage', '%')); + for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { + let cpuPie = new LitChartPie(); + cpuPie.className = 'pie-chart'; + this.cpuPieMap.set(i, cpuPie); + this.cpuUsageGrid!.append(this.createUsageItem(`CPU: ${i}`, 0)); + this.cpuUsageChart!.append(this.createUsageChartItem(i, cpuPie)); + } + this.loadingUsage = true; + this.loadingPieData = true; + this.progress!.loading = this.loadingUsage || this.loadingPieData; + this.queryLogicWorker('scheduling-getCpuUsage', 'query Cpu Usage Time:', (res) => { + if (res && res.length > 0) { + this.cpuUsageGrid!.innerHTML = ''; + this.cpuUsageGrid!.append(this.createUsageItem('usage', '%')); + if (res instanceof Array) { + for (let re of res) { + this.cpuUsageGrid!.append(this.createUsageItem(`CPU: ${re.cpu}`, ((re.usage || 0) * 100).toFixed(2))); + } + } + } + this.loadingUsage = false; + this.progress!.loading = this.loadingUsage || this.loadingPieData; + }); + this.queryPieChartDataByType('CPU Idle'); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'CPU Data', + action: 'trace_tab', + }); + } + + queryPieChartDataByType(type: string) { + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: 'Analysis ' + type, + action: 'scheduling_analysis', + }); + let tip = ''; + if (type === 'CPU Frequency') { + tip = 'freq:'; + } else if (type === 'CPU Idle') { + tip = 'idle:'; + } else { + tip = 'irq:'; + } + this.queryLogicWorker(`scheduling-${type}`, `query ${type} Analysis Time:`, (res) => { + for (let key of this.cpuPieMap.keys()) { + this.cpuPieMap.get(key)!.config = { + appendPadding: 10, + data: res.get(key) || [], + angleField: 'sum', + colorField: 'value', + radius: 0.8, + tip: (obj) => { + return `
+
${tip}${obj.obj.value}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + label: { + type: 'outer', + color: + type !== 'CPU Idle' + ? undefined + : (it) => { + return pieChartColors[(it as any).value]; + }, + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + } + this.loadingPieData = false; + this.progress!.loading = this.loadingUsage || this.loadingPieData; + }); + } + + queryLogicWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName( + 'logic1', + option, + { + endTs: SpSchedulingAnalysis.endTs, + total: SpSchedulingAnalysis.totalDur, + }, + undefined, + handler + ); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + createUsageItem(name: string, value: any) { + let div = document.createElement('div'); + div.className = 'usage_item_box'; + div.innerHTML = `
${name}
${value}
`; + return div; + } + + createUsageChartItem(cpu: number, pie: LitChartPie) { + let div = document.createElement('div'); + div.className = 'usage_chart'; + div.style.cursor = 'pointer'; + div.innerHTML = ` +
CPU: ${cpu}
+ `; + div.append(pie); + div.addEventListener('click', (event) => { + if (this.loadingUsage || this.loadingPieData) { + return; + } + this.drawer!.title = `CPU: ${cpu}`; + this.drawer!.visible = true; + this.drawerCpuTabs!.init(cpu, this.schedulingSelect!.value); + }); + return div; + } + + initHtml(): string { + return ` + +
+ +
+
+
CPU Statistics By Duration
+ + CPU Idle + CPU Frequency + CPU Irq + +
+
+
+ + + + `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.ts b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.ts new file mode 100644 index 0000000000000000000000000000000000000000..418cd1066ce1bb41e47d0ec37a549e7c7ad5581b --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.ts @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; +import { TabCpuDetailsThreads } from './TabCpuDetailsThreads.js'; +import './TabCpuDetailsThreads.js'; +import { info } from '../../../log/Log.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { getDataNo } from './utils/Utils.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; + +@element('tab-cpu-details-frequency') +export class TabCpuDetailsFrequency extends BaseElement { + private tableNoData: TableNoData | null | undefined; + private progress: LitProgressBar | null | undefined; + traceChange: boolean = false; + private pie: LitChartPie | null | undefined; + private table: LitTable | null | undefined; + private tabCpuDetailsThreads: TabCpuDetailsThreads | null | undefined; + private cpu: number = 0; + private data: Array = []; + private sortColumn: string = ''; + private sortType: number = 0; + + initElements(): void { + this.tableNoData = this.shadowRoot!.querySelector('#table-no-data'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.table = this.shadowRoot!.querySelector('#tb-cpu-usage'); + this.tabCpuDetailsThreads = this.shadowRoot!.querySelector('#tab-cpu-details-threads'); + + this.table!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt: any) => { + this.sortColumn = evt.detail.key; + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + init(cpu: number) { + this.cpu = cpu; + this.queryPieChartDataByType('CPU Frequency', cpu); + } + + queryPieChartDataByType(type: string, cpu: number) { + if (this.traceChange) { + return; + } + this.progress!.loading = true; + this.queryLoginWorker(`scheduling-${type}`, 'query Cpu Frequency Analysis Time:', (res) => { + this.traceChange = true; + this.progress!.loading = false; + this.data = res.get(cpu) || []; + this.data = getDataNo(this.data); + this.tableNoData!.noData = this.data.length == 0; + this.noData(this.data.length == 0); + this.pie!.config = { + appendPadding: 0, + data: this.data, + angleField: 'sum', + colorField: 'value', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
frequency:${obj.obj.value}
+
min:${obj.obj.min}
+
max:${obj.obj.max}
+
average:${obj.obj.avg}
+
duration:${obj.obj.sumTimeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + angleClick: (it) => { + this.tabCpuDetailsThreads!.setShow = true; + this.shadowRoot!.querySelector('.d-box')!.style.display = 'none'; + this.tabCpuDetailsThreads!.init(cpu, it); + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + if (this.sortColumn != '') { + this.sortByColumn({ + key: this.sortColumn, + sort: this.sortType, + }); + } else { + this.table!.recycleDataSource = this.data; + } + this.table?.reMeauseHeight(); + }); + } + + noData(value: boolean) { + this.shadowRoot!.querySelector('.chart-box')!.style.display = value ? 'none' : 'block'; + this.shadowRoot!.querySelector('.table-box')!.style.width = value ? '100%' : '60%'; + } + + clearData() { + this.traceChange = false; + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + this.shadowRoot!.querySelector('.d-box')!.style.display = 'flex'; + this.tabCpuDetailsThreads!.setShow = false; + this.noData(false); + } + + set setShow(v: boolean) { + if (v) { + this.shadowRoot!.querySelector('.d-box')!.style.display = 'flex'; + } else { + this.shadowRoot!.querySelector('.d-box')!.style.display = 'none'; + } + } + + queryLoginWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName( + 'logic1', + option, + { + endTs: SpSchedulingAnalysis.endTs, + total: SpSchedulingAnalysis.totalDur, + }, + undefined, + handler + ); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'min') { + detail.key = 'minValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'max') { + detail.key = 'maxValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'avg') { + detail.key = 'avgValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'sumTimeStr') { + detail.key = 'sum'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'value' || detail.key === 'ratio' || detail.key === 'index') { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + +
+
+
Statistics By Duration
+ +
+
+ + + + + + + + + + + +
+
+ + `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsIdle.ts b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsIdle.ts new file mode 100644 index 0000000000000000000000000000000000000000..95f4468f88fa0b8b362e6516b4172ea4f0aec447 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsIdle.ts @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; +import { info } from '../../../log/Log.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import { getDataNo } from './utils/Utils.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; +import { pieChartColors } from '../../../base-ui/chart/pie/LitChartPieData.js'; + +@element('tab-cpu-details-idle') +export class TabCpuDetailsIdle extends BaseElement { + private tableNoData: TableNoData | null | undefined; + private table: LitTable | null | undefined; + private progress: LitProgressBar | null | undefined; + traceChange: boolean = false; + private pie: LitChartPie | null | undefined; + private data: Array = []; + private sortColumn: string = ''; + private sortType: number = 0; + + initElements(): void { + this.tableNoData = this.shadowRoot!.querySelector('#table-no-data'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.table = this.shadowRoot!.querySelector('#tb-cpu-usage'); + + this.table!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt: any) => { + this.sortColumn = evt.detail.key; + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + init(cpu: number) { + this.queryPieChartDataByType('CPU Idle', cpu); + } + + queryPieChartDataByType(type: string, cpu: number) { + if (this.traceChange) { + return; + } + this.progress!.loading = true; + this.queryLoginWorker(`scheduling-${type}`, 'query Cpu Frequency Analysis Time:', (res) => { + this.traceChange = true; + this.progress!.loading = false; + this.data = res.get(cpu) || []; + this.data = getDataNo(this.data); + this.tableNoData!.noData = this.data.length == 0; + this.noData(this.data.length == 0); + this.pie!.config = { + appendPadding: 0, + data: this.data, + angleField: 'sum', + colorField: 'value', + radius: 1, + label: { + type: 'outer', + color: + type !== 'CPU Idle' + ? undefined + : (it) => { + return pieChartColors[(it as any).value]; + }, + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + tip: (obj) => { + return `
+
idle:${obj.obj.value}
+
min:${obj.obj.min}
+
max:${obj.obj.max}
+
average:${obj.obj.avg}
+
duration:${obj.obj.sumTimeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + if (this.sortColumn != '') { + this.sortByColumn({ + key: this.sortColumn, + sort: this.sortType, + }); + } else { + this.table!.recycleDataSource = this.data; + } + this.table?.reMeauseHeight(); + }); + } + + noData(value: boolean) { + this.shadowRoot!.querySelector('.chart-box')!.style.display = value ? 'none' : 'block'; + this.shadowRoot!.querySelector('.table-box')!.style.width = value ? '100%' : '60%'; + } + + clearData() { + this.traceChange = false; + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + this.noData(false); + } + + queryLoginWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName( + 'logic1', + option, + { + endTs: SpSchedulingAnalysis.endTs, + total: SpSchedulingAnalysis.totalDur, + }, + undefined, + handler + ); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'min') { + detail.key = 'minValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'max') { + detail.key = 'maxValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'avg') { + detail.key = 'avgValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'sumTimeStr') { + detail.key = 'sum'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'value' || detail.key === 'ratio' || detail.key === 'index') { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + +
+
+
Statistics By Duration
+ +
+
+ + + + + + + + + + + +
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsIrq.ts b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsIrq.ts new file mode 100644 index 0000000000000000000000000000000000000000..e974f788b71a8b26678b15b2503dfa7ad6b67321 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsIrq.ts @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; +import { info } from '../../../log/Log.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import { getDataNo } from './utils/Utils.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; + +@element('tab-cpu-details-irq') +export class TabCpuDetailsIrq extends BaseElement { + private tableNoData: TableNoData | null | undefined; + private table: LitTable | null | undefined; + private progress: LitProgressBar | null | undefined; + traceChange: boolean = false; + private pie: LitChartPie | null | undefined; + private data: Array = []; + private sortColumn: string = ''; + private sortType: number = 0; + + initElements(): void { + this.tableNoData = this.shadowRoot!.querySelector('#table-no-data'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.table = this.shadowRoot!.querySelector('#tb-cpu-usage'); + + this.table!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt: any) => { + this.sortColumn = evt.detail.key; + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + init(cpu: number) { + this.queryPieChartDataByType('CPU Irq', cpu); + } + + queryPieChartDataByType(type: string, cpu: number) { + if (this.traceChange) { + return; + } + this.progress!.loading = true; + this.queryLoginWorker(`scheduling-${type}`, 'query Cpu Frequency Analysis Time:', (res) => { + this.traceChange = true; + this.progress!.loading = false; + this.data = res.get(cpu) || []; + this.data = getDataNo(this.data); + this.tableNoData!.noData = this.data.length == 0; + this.noData(this.data.length == 0); + this.pie!.config = { + appendPadding: 0, + data: this.data, + angleField: 'sum', + colorField: 'value', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
block:${obj.obj.block}
+
name:${obj.obj.value}
+
min:${obj.obj.min}
+
max:${obj.obj.max}
+
average:${obj.obj.avg}
+
duration:${obj.obj.sumTimeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + if (this.sortColumn != '') { + this.sortByColumn({ + key: this.sortColumn, + sort: this.sortType, + }); + } else { + this.table!.recycleDataSource = this.data; + } + this.table?.reMeauseHeight(); + }); + } + + noData(value: boolean) { + this.shadowRoot!.querySelector('.chart-box')!.style.display = value ? 'none' : 'block'; + this.shadowRoot!.querySelector('.table-box')!.style.width = value ? '100%' : '60%'; + } + + clearData() { + this.traceChange = false; + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + this.noData(false); + } + + queryLoginWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName( + 'logic1', + option, + { + endTs: SpSchedulingAnalysis.endTs, + total: SpSchedulingAnalysis.totalDur, + }, + undefined, + handler + ); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'min') { + detail.key = 'minValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'max') { + detail.key = 'maxValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'avg') { + detail.key = 'avgValue'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'sumTimeStr') { + detail.key = 'sum'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'ratio' || detail.key === 'index') { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + +
+
+
Statistics By Duration
+ +
+
+ + + + + + + + + + + + + +
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsThreads.ts b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsThreads.ts new file mode 100644 index 0000000000000000000000000000000000000000..b946958494f9a477149509943870bf57b3d5e5a4 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TabCpuDetailsThreads.ts @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { getDataNo } from './utils/Utils.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; + +@element('tab-cpu-details-threads') +export class TabCpuDetailsThreads extends BaseElement { + private tableNoData: TableNoData | null | undefined; + private table: LitTable | null | undefined; + private progress: LitProgressBar | null | undefined; + private pie: LitChartPie | null | undefined; + private data: Array = []; + private sortColumn: string = ''; + private sortType: number = 0; + + initElements(): void { + this.tableNoData = this.shadowRoot!.querySelector('#table-no-data'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.table = this.shadowRoot!.querySelector('#tb-cpu-usage'); + + this.shadowRoot!.querySelector('.go-back')!.onclick = (e) => { + if (!this.progress!.loading) { + this.parentNode!.querySelector('.d-box')!.style.display = 'flex'; + this.setShow = false; + } + }; + + this.table!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt: any) => { + this.sortColumn = evt.detail.key; + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + init(cpu: number, it: any) { + this.shadowRoot!.querySelector('.subheading')!.textContent = 'Threads in Freq ' + it.value; + this.progress!.loading = true; + procedurePool.submitWithName( + 'logic1', + 'scheduling-CPU Frequency Thread', + { cpu: cpu, freq: (it as any).value }, + undefined, + (res: any) => { + this.progress!.loading = false; + this.queryPieChartDataByType(res); + } + ); + } + + set setShow(v: boolean) { + if (v) { + this.style.display = 'flex'; + } else { + this.clearData(); + this.style.display = 'none'; + } + } + + queryPieChartDataByType(res: any) { + this.data = res || []; + this.data = getDataNo(this.data); + this.tableNoData!.noData = this.data.length == 0; + this.noData(this.data.length == 0); + this.pie!.config = { + appendPadding: 0, + data: this.data, + angleField: 'dur', + colorField: 'tName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
t_name:${obj.obj.tName}
+
tid:${obj.obj.tid}
+
p_name:${obj.obj.pName}
+
p_pid:${obj.obj.pid}
+
duration:${obj.obj.durStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + if (this.sortColumn != '') { + this.sortByColumn({ key: this.sortColumn, sort: this.sortType }); + } else { + this.table!.recycleDataSource = this.data; + } + this.table?.reMeauseHeight(); + } + + noData(value: boolean) { + this.shadowRoot!.querySelector('.chart-box')!.style.display = value ? 'none' : 'block'; + this.shadowRoot!.querySelector('.table-box')!.style.width = value ? '100%' : '60%'; + } + + clearData() { + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + this.noData(false); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'durStr') { + detail.key = 'dur'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if ( + detail.key === 'value' || + detail.key === 'ratio' || + detail.key === 'index' || + detail.key === 'tid' || + detail.key === 'pid' + ) { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + +
+
+
+
+ +
+ +
Threads in Freq
+
+
Statistics By Duration
+ +
+
+ + + + + + + + + + + +
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TabThreadAnalysis.ts b/ide/src/trace/component/schedulingAnalysis/TabThreadAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..4136fec0e5e590d1e37f1e6f7a6a95f6d1feff8b --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TabThreadAnalysis.ts @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import './Top20ThreadCpuUsage.js'; +import './Top20ThreadRunTime.js'; +import './Top20ProcessSwitchCount.js'; +import './Top20ProcessThreadCount.js'; +import './Top20FrequencyThread.js'; +import { Top20ThreadCpuUsage } from './Top20ThreadCpuUsage.js'; +import { Top20ThreadRunTime } from './Top20ThreadRunTime.js'; +import { Top20ProcessThreadCount } from './Top20ProcessThreadCount.js'; +import { Top20ProcessSwitchCount } from './Top20ProcessSwitchCount.js'; +import { Top20FrequencyThread } from './Top20FrequencyThread.js'; +import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil.js'; + +@element('tab-thread-analysis') +export class TabThreadAnalysis extends BaseElement { + private currentTabID: string | undefined; + private currentTab: BaseElement | undefined; + private contentDiv: HTMLDivElement | null | undefined; + private tab1: HTMLDivElement | null | undefined; + private tab2: HTMLDivElement | null | undefined; + private tab3: HTMLDivElement | null | undefined; + private tab4: HTMLDivElement | null | undefined; + private tab5: HTMLDivElement | null | undefined; + private top20ThreadCpuUsage: Top20ThreadCpuUsage | undefined | null; + private top20ThreadRunTime: Top20ThreadRunTime | undefined | null; + private top20ProcessThreadCount: Top20ProcessThreadCount | undefined | null; + private top20ProcessSwitchCount: Top20ProcessSwitchCount | undefined | null; + private top20FrequencyThread: Top20FrequencyThread | undefined | null; + + initElements(): void { + this.contentDiv = this.shadowRoot!.querySelector('#content'); + this.tab1 = this.shadowRoot!.querySelector('#tab1'); + this.tab2 = this.shadowRoot!.querySelector('#tab2'); + this.tab3 = this.shadowRoot!.querySelector('#tab3'); + this.tab4 = this.shadowRoot!.querySelector('#tab4'); + this.tab5 = this.shadowRoot!.querySelector('#tab5'); + this.top20ThreadCpuUsage = this.shadowRoot!.querySelector('#top20_thread_cpu_usage'); + this.top20ThreadRunTime = this.shadowRoot!.querySelector('#top20_thread_run_time'); + this.top20ProcessThreadCount = + this.shadowRoot!.querySelector('#top20_process_thread_count'); + this.top20ProcessSwitchCount = + this.shadowRoot!.querySelector('#top20_process_switch_count'); + this.top20FrequencyThread = this.shadowRoot!.querySelector('#top20_frequency_thread'); + + this.tab1!.addEventListener('click', (event) => { + this.setClickTab(this.tab1!, this.top20ThreadCpuUsage!); + }); + this.tab2!.addEventListener('click', (event) => { + this.setClickTab(this.tab2!, this.top20ThreadRunTime!); + }); + this.tab3!.addEventListener('click', (event) => { + this.setClickTab(this.tab3!, this.top20ProcessThreadCount!); + }); + this.tab4!.addEventListener('click', (event) => { + this.setClickTab(this.tab4!, this.top20ProcessSwitchCount!); + }); + this.tab5!.addEventListener('click', (event) => { + this.setClickTab(this.tab5!, this.top20FrequencyThread!); + }); + } + + init() { + this.top20FrequencyThread!.clearData(); + this.top20ThreadCpuUsage!.clearData(); + this.top20ThreadRunTime!.clearData(); + this.top20ProcessSwitchCount!.clearData(); + this.top20ProcessThreadCount!.clearData(); + this.hideCurrentTab(); + this.currentTabID = undefined; + this.setClickTab(this.tab1!, this.top20ThreadCpuUsage!, true); + } + + hideCurrentTab() { + if (this.currentTabID) { + let clickTab = this.shadowRoot!.querySelector(`#${this.currentTabID}`); + if (clickTab) { + clickTab.className = 'tag_bt'; + } + } + if (this.currentTab) { + this.currentTab.style.display = 'none'; + } + } + + setClickTab( + tab: HTMLDivElement, + showContent: + | Top20ThreadCpuUsage + | Top20ThreadRunTime + | Top20ProcessSwitchCount + | Top20ProcessThreadCount + | Top20FrequencyThread, + isInit: boolean = false + ) { + if (!isInit) { + let event = showContent.id + .replace(/_/g, ' ') + .toLowerCase() + .replace(/( |^)[a-z]/g, (L) => L.toUpperCase()); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + event: event, + action: 'scheduling_analysis', + }); + } + if (this.currentTabID) { + let clickTab = this.shadowRoot!.querySelector(`#${this.currentTabID}`); + if (clickTab) { + clickTab.className = 'tag_bt'; + } + } + tab.className = 'tab_click'; + if (tab.id !== this.currentTabID) { + this.currentTabID = tab.id; + if (this.currentTab) { + this.currentTab.style.display = 'none'; + } + this.currentTab = showContent; + showContent.style.display = 'inline'; + showContent.init(); + } + } + + initHtml(): string { + return ` + +
+
Top20线程大中小核占用率
+
单个线程频点分布
+
Top20单次运行超长线程
+
Top20进程线程数
+
Top20切换次数线程
+
+
+ + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/TableNoData.ts b/ide/src/trace/component/schedulingAnalysis/TableNoData.ts new file mode 100644 index 0000000000000000000000000000000000000000..0666c9fef2f68e5576a9ef3d62659b25bbea6a06 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/TableNoData.ts @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; + +@element('table-no-data') +export class TableNoData extends BaseElement { + static get observedAttributes() { + return ['noData', 'contentWidth', 'height']; + } + + private dataSlot: HTMLDivElement | null | undefined; + private noDataIcon: HTMLDivElement | null | undefined; + + initElements(): void { + this.dataSlot = this.shadowRoot!.querySelector('.no-data'); + this.noDataIcon = this.shadowRoot!.querySelector('.d-box'); + } + + get noData() { + return this.hasAttribute('noData'); + } + + set noData(value: boolean) { + if (value) { + this.setAttribute('noData', ''); + } else { + this.removeAttribute('noData'); + } + } + + get contentWidth() { + return this.getAttribute('contentWidth') || '100%'; + } + set contentWidth(value) { + this.shadowRoot!.querySelector('.d-box')!.style.width = value; + this.setAttribute('contentWidth', value); + } + get contentHeight() { + return this.getAttribute('contentHeight') || '80%'; + } + set contentHeight(value) { + this.shadowRoot!.querySelector('.d-box')!.style.height = value; + this.setAttribute('contentHeight', value); + } + + initHtml(): string { + return ` + + +
+
+
Sorry, no data
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/Top20FrequencyThread.ts b/ide/src/trace/component/schedulingAnalysis/Top20FrequencyThread.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ca785a0432acf11f47ad007ebfe42c6354c40b0 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/Top20FrequencyThread.ts @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { info } from '../../../log/Log.js'; +import '../../../base-ui/chart/pie/LitChartPie.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import { LitSelect } from '../../../base-ui/select/LitSelect.js'; +import { queryThreads } from '../../database/SqlLite.js'; +import { LitSelectOption } from '../../../base-ui/select/LitSelectOption.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; +import { getProbablyTime } from '../../database/logic-worker/ProcedureLogicWorkerCommon.js'; + +@element('top20-frequency-thread') +export class Top20FrequencyThread extends BaseElement { + static threads: { id: number; tid: number; name: string }[] | undefined; + traceChange: boolean = false; + private table: LitTable | null | undefined; + private threadSelect: LitSelect | null | undefined; + private pie: LitChartPie | null | undefined; + private currentThread: HTMLDivElement | null | undefined; + private progress: LitProgressBar | null | undefined; + private nodata: TableNoData | null | undefined; + private currentTid: number = 0; + private data: Array = []; + private sortColumn: string = ''; + private sortType: number = 0; + + initElements(): void { + this.nodata = this.shadowRoot!.querySelector('#nodata'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.table = this.shadowRoot!.querySelector('#tb-process-thread-count'); + this.currentThread = this.shadowRoot!.querySelector('#current_thread'); + this.threadSelect = this.shadowRoot!.querySelector('#thread_select'); + this.pie = this.shadowRoot!.querySelector('#pie'); + + this.threadSelect!.onchange = (e) => { + this.currentThread!.textContent = (e as any).detail.text; + this.currentTid = parseInt((e as any).detail.value); + this.progress!.loading = true; + this.queryData(); + }; + + this.table!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data; + data.isSelected = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt: any) => { + this.sortColumn = evt.detail.key; + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'timeStr') { + detail.key = 'time'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if (detail.key === 'no' || detail.key === 'cpu' || detail.key === 'freq' || detail.key === 'ratio') { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + async init() { + if (!this.traceChange) { + if (this.table!.recycleDataSource.length > 0) { + this.table?.reMeauseHeight(); + } + return; + } + this.traceChange = false; + this.progress!.loading = true; + if (Top20FrequencyThread.threads === undefined) { + Top20FrequencyThread.threads = (await queryThreads()) || []; + this.nodata!.noData = Top20FrequencyThread.threads === undefined || Top20FrequencyThread.threads.length === 0; + this.threadSelect!.innerHTML = ''; + let threads = Top20FrequencyThread.threads.map((it) => { + let option = new LitSelectOption(); + option.setAttribute('value', it.tid + ''); + option.textContent = it.name; + return option; + }); + this.threadSelect!.append(...threads); + this.threadSelect?.initOptions(); + this.threadSelect!.value = Top20FrequencyThread.threads[0].tid + ''; + this.currentThread!.textContent = Top20FrequencyThread.threads[0].name; + this.currentTid = Top20FrequencyThread.threads[0].tid; + this.queryData(); + } + } + + queryData() { + this.queryLogicWorker('scheduling-Thread Freq', 'query Thread Top 20 Frequency Time:', (res) => { + this.nodata!.noData = + Top20FrequencyThread.threads === undefined || + Top20FrequencyThread.threads.length === 0 || + res === undefined || + res.length === 0; + (res as any[]).map((it: any, index: number) => { + it.no = index + 1; + }); + this.data = res; + if (this.sortColumn != '') { + this.sortByColumn({ + key: this.sortColumn, + sort: this.sortType, + }); + } else { + this.table!.recycleDataSource = res; + } + this.table!.reMeauseHeight(); + this.pie!.config = { + appendPadding: 10, + data: this.getPieChartData(res), + angleField: 'time', + colorField: 'freq', + radius: 0.8, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
freq:${obj.obj.freq}
+
cpu:${obj.obj.cpu}
+
time:${obj.obj.timeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.progress!.loading = false; + this.shadowRoot!.querySelector('#tb_container')!.scrollTop = 0; + }); + } + + getPieChartData(res: any[]) { + if (res.length > 20) { + let pieChartArr: any[] = []; + let other: any = { + cpu: '-', + freq: 'other', + time: 0, + ratio: '0', + totalDur: 0, + }; + for (let i = 0; i < res.length; i++) { + if (i < 19) { + pieChartArr.push(res[i]); + } else { + other.time += res[i].time; + other.timeStr = getProbablyTime(other.time); + other.totalDur = res[i].totalDur; + other.ratio = ((other.time / other.totalDur) * 100).toFixed(2); + } + } + pieChartArr.push(other); + return pieChartArr; + } + return res; + } + + clearData() { + this.traceChange = true; + this.threadSelect!.innerHTML = ''; + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + } + + queryLogicWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName('logic1', option, { tid: this.currentTid }, undefined, handler); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + initHtml(): string { + return ` + + +
+ Thread Search + +
+ +
+
+
Statistics By Duration
+ +
+
+
+
+ + + + + + + +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.ts b/ide/src/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.ts new file mode 100644 index 0000000000000000000000000000000000000000..9fc715b158aba93b228063ac7fccc4f5044531ac --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.ts @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { info } from '../../../log/Log.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; + +@element('top20-process-switch-count') +export class Top20ProcessSwitchCount extends BaseElement { + traceChange: boolean = false; + private table: LitTable | null | undefined; + private pie: LitChartPie | null | undefined; + private progress: LitProgressBar | null | undefined; + private nodata: TableNoData | null | undefined; + private data: Array = []; + + initElements(): void { + this.nodata = this.shadowRoot!.querySelector('#nodata'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.table = this.shadowRoot!.querySelector('#tb-process-switch-count'); + this.pie = this.shadowRoot!.querySelector('#pie'); + + this.table!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + init() { + if (!this.traceChange) { + if (this.table!.recycleDataSource.length > 0) { + this.table?.reMeauseHeight(); + } + return; + } + this.traceChange = false; + this.progress!.loading = true; + this.queryLogicWorker('scheduling-Process SwitchCount', 'query Process Switch Count Analysis Time:', (res) => { + this.nodata!.noData = res === undefined || res.length === 0; + this.table!.recycleDataSource = res; + this.data = res; + this.table?.reMeauseHeight(); + this.pie!.config = { + appendPadding: 10, + data: res, + angleField: 'switchCount', + colorField: 'pid', + radius: 0.8, + tip: (obj) => { + return `
+
pid:${obj.obj.tid}
+
p_name:${obj.obj.tName}
+
sched_switch count:${obj.obj.switchCount}
+
+ `; + }, + label: { + type: 'outer', + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.progress!.loading = false; + }); + } + + clearData() { + this.traceChange = true; + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + } + + queryLogicWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName('logic1', option, {}, undefined, handler); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'NO' || detail.key === 'pid' || detail.key === 'switchCount' || detail.key === 'tid') { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + + +
+
+
Statistics By Sched_Switch Count
+ +
+
+ + + + + + + + +
+
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/Top20ProcessThreadCount.ts b/ide/src/trace/component/schedulingAnalysis/Top20ProcessThreadCount.ts new file mode 100644 index 0000000000000000000000000000000000000000..b91797a48f23d12c41ad26f65b0a55435be87ef8 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/Top20ProcessThreadCount.ts @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { info } from '../../../log/Log.js'; +import '../../../base-ui/chart/pie/LitChartPie.js'; +import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; + +@element('top20-process-thread-count') +export class Top20ProcessThreadCount extends BaseElement { + traceChange: boolean = false; + private table: LitTable | null | undefined; + private pie: LitChartPie | null | undefined; + private progress: LitProgressBar | null | undefined; + private nodata: TableNoData | null | undefined; + private data: Array = []; + + initElements(): void { + this.nodata = this.shadowRoot!.querySelector('#nodata'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.table = this.shadowRoot!.querySelector('#tb-process-thread-count'); + this.pie = this.shadowRoot!.querySelector('#pie'); + + this.table!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.table!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + }); + } + + init() { + if (!this.traceChange) { + if (this.table!.recycleDataSource.length > 0) { + this.table?.reMeauseHeight(); + } + return; + } + this.traceChange = false; + this.progress!.loading = true; + this.queryLogicWorker('scheduling-Process ThreadCount', 'query Process Thread Count Analysis Time:', (res) => { + this.nodata!.noData = res === undefined || res.length === 0; + this.table!.recycleDataSource = res; + this.data = res; + this.table?.reMeauseHeight(); + this.pie!.config = { + appendPadding: 10, + data: res, + angleField: 'threadNumber', + colorField: 'pid', + radius: 0.8, + label: { + type: 'outer', + }, + hoverHandler: (data) => { + if (data) { + this.table!.setCurrentHover(data); + } else { + this.table!.mouseOut(); + } + }, + tip: (obj) => { + return `
+
pid:${obj.obj.pid}
+
p_name:${obj.obj.pName}
+
thread count:${obj.obj.threadNumber}
+
+ `; + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.progress!.loading = false; + }); + } + + clearData() { + this.traceChange = true; + this.pie!.dataSource = []; + this.table!.recycleDataSource = []; + } + + queryLogicWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName('logic1', option, {}, undefined, handler); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'NO' || detail.key === 'pid' || detail.key === 'threadNumber') { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + + +
+
+
Statistics By Thread Count
+ +
+
+ + + + + + +
+
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts b/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts new file mode 100644 index 0000000000000000000000000000000000000000..261b5eee57ac595037067d98dbfa7cd36a342cf3 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.ts @@ -0,0 +1,550 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { LitChartColumn } from '../../../base-ui/chart/column/LitChartColumn.js'; +import '../../../base-ui/chart/column/LitChartColumn.js'; +import './CheckCpuSetting.js'; +import '../../../base-ui/icon/LitIcon.js'; +import { CheckCpuSetting } from './CheckCpuSetting.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { info } from '../../../log/Log.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; +import { getProbablyTime } from '../../database/logic-worker/ProcedureLogicWorkerCommon.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; + +@element('top20-thread-cpu-usage') +export class Top20ThreadCpuUsage extends BaseElement { + traceChange: boolean = false; + private table: LitTable | null | undefined; + private tableBig: LitTable | null | undefined; + private tableMid: LitTable | null | undefined; + private tableSmall: LitTable | null | undefined; + private chartTotal: LitChartColumn | null | undefined; + private chart2: LitChartColumn | null | undefined; + private chart3: LitChartColumn | null | undefined; + private chart4: LitChartColumn | null | undefined; + private cpuSetting: CheckCpuSetting | undefined | null; + private setting: HTMLDivElement | null | undefined; + private progress: LitProgressBar | null | undefined; + private nodata: TableNoData | null | undefined; + private map: Map | undefined; + private data: Array = []; + private dataBig: Array = []; + private dataMid: Array = []; + private dataSmall: Array = []; + private sort: any = { + total: { key: '', sort: 0 }, + small: { key: '', sort: 0 }, + mid: { key: '', sort: 0 }, + big: { key: '', sort: 0 }, + }; + + private publicColumns = ` + + + + + + + + + `; + private bigColumn = ` + + + `; + private midColumn = ` + + + `; + private smallColumn = ` + + + `; + + initElements(): void { + this.nodata = this.shadowRoot!.querySelector('#nodata'); + this.progress = this.shadowRoot!.querySelector('#loading'); + this.table = this.shadowRoot!.querySelector('#tb-thread-usage'); + this.tableBig = this.shadowRoot!.querySelector('#tb-thread-big'); + this.tableMid = this.shadowRoot!.querySelector('#tb-thread-mid'); + this.tableSmall = this.shadowRoot!.querySelector('#tb-thread-small'); + this.chartTotal = this.shadowRoot!.querySelector('#chart_total'); + this.chart2 = this.shadowRoot!.querySelector('#chart_2'); + this.chart3 = this.shadowRoot!.querySelector('#chart_3'); + this.chart4 = this.shadowRoot!.querySelector('#chart_4'); + this.map = new Map(); + this.map.set('total', { chart: this.chartTotal!, table: this.table! }); + this.map.set('small', { chart: this.chart2!, table: this.tableSmall! }); + this.map.set('mid', { chart: this.chart3!, table: this.tableMid! }); + this.map.set('big', { chart: this.chart4!, table: this.tableBig! }); + this.setting = this.shadowRoot!.querySelector('#setting'); + this.cpuSetting = this.shadowRoot!.querySelector('#cpu_setting'); + this.cpuSetting!.cpuSetListener = () => { + this.cpuSetting!.style.display = 'none'; + (this.shadowRoot!.querySelector('#total')! as any).style.display = 'grid'; + (this.shadowRoot!.querySelector('#small')! as any).style.display = + CheckCpuSetting.small_cores.length > 0 ? 'grid' : 'none'; + (this.shadowRoot!.querySelector('#mid')! as any).style.display = + CheckCpuSetting.mid_cores.length > 0 ? 'grid' : 'none'; + (this.shadowRoot!.querySelector('#big')! as any).style.display = + CheckCpuSetting.big_cores.length > 0 ? 'grid' : 'none'; + this.queryData(); + }; + this.setting?.addEventListener('click', (event) => { + for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) { + (node as any).style.display = 'none'; + } + this.cpuSetting!.style.display = 'inline'; + this.cpuSetting?.init(); + }); + + for (let key of this.map!.keys()) { + let tab = this.map!.get(key)!.table; + let chart = this.map!.get(key)!.chart; + tab!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + tab!.addEventListener('column-click', (evt: any) => { + this.sort[key].key = evt.detail.key; + this.sort[key].sort = evt.detail.sort; + if (key == 'total') { + this.sortByColumn(evt.detail, tab, this.data); + } else if (key == 'small') { + this.sortByColumn(evt.detail, tab, this.dataSmall); + } else if (key == 'mid') { + this.sortByColumn(evt.detail, tab, this.dataMid); + } else if (key == 'big') { + this.sortByColumn(evt.detail, tab, this.dataBig); + } + }); + tab!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + chart.showHoverColumn(data.no); + } + }); + } + } + + sortByColumn(detail: any, table: LitTable | null | undefined, data: Array) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + let type = 'number'; + + if (detail.key === 'bigTimeStr') { + detail.key = 'big'; + } else if (detail.key === 'midTimeStr') { + detail.key = 'mid'; + } else if (detail.key === 'smallTimeStr') { + detail.key = 'small'; + } else if ( + detail.key === 'bigPercent' || + detail.key === 'ratio' || + detail.key === 'tid' || + detail.key === 'pid' || + detail.key === 'midPercent' || + detail.key.includes('cpu') + ) { + } else { + type = 'string'; + } + data.sort(compare(detail.key, detail.sort, type)); + table!.recycleDataSource = data; + } + + init() { + if (!this.traceChange) { + for (let key of this.map!.keys()) { + this.map!.get(key)!.table.reMeauseHeight(); + } + return; + } + this.traceChange = false; + for (let key of this.map!.keys()) { + let table = this.map!.get(key)!.table; + table.innerHTML = ''; + let columns = this.getTableColumns(key); + for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { + columns = ` + ${columns} + + `; + } + table.innerHTML = columns; + } + + if (!CheckCpuSetting.init_setting) { + for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) { + (node as any).style.display = 'none'; + } + this.cpuSetting!.style.display = 'inline'; + this.cpuSetting?.init(); + } else { + this.queryData(); + } + } + + clearData() { + this.traceChange = true; + for (let key of this.map!.keys()) { + this.map!.get(key)!.chart.dataSource = []; + this.map!.get(key)!.table.recycleDataSource = []; + } + } + + queryData() { + this.progress!.loading = true; + this.queryLogicWorker(`scheduling-Thread CpuUsage`, `query Thread Cpu Usage Analysis Time:`, (res) => { + this.nodata!.noData = res.keys().length === 0; + for (let key of this.map!.keys()) { + let obj = this.map!.get(key)!; + let source: any[] = res.get(key) || []; + source = source.map((it: any, index: number) => { + let data: any = { + pid: it.pid, + pName: it.pName, + tid: it.tid, + tName: it.tName, + total: it.total, + big: it.big, + mid: it.mid, + small: it.small, + no: index + 1, + visible: 1, + bigPercent: it.bigPercent, + midPercent: it.midPercent, + smallPercent: it.smallPercent, + bigTimeStr: it.bigTimeStr, + midTimeStr: it.midTimeStr, + smallTimeStr: it.smallTimeStr, + hideHandler: () => { + let arr = source.filter((o) => o.visible === 1); + obj.chart.dataSource = this.getArrayDataBySize(key, arr); + }, + }; + for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { + data[`cpu${i}`] = (it[`cpu${i}`] || 0) / 1000; + } + return data; + }); + obj.chart.config = { + data: this.getArrayDataBySize(key, source), + appendPadding: 10, + xField: 'tid', + yField: 'total', + seriesField: key === 'total' ? 'size' : '', + color: (a) => { + if (a.size === 'big core') { + return '#2f72f8'; + } else if (a.size === 'middle core') { + return '#ffab67'; + } else if (a.size === 'small core') { + return '#a285d2'; + } else { + return '#0a59f7'; + } + }, + hoverHandler: (no) => { + let data = source.find((it) => it.no === no); + if (data) { + data.isHover = true; + obj.table!.setCurrentHover(data); + } else { + obj.table!.mouseOut(); + } + }, + tip: (a) => { + if (a && a[0]) { + let tip = ''; + let total = 0; + for (let obj of a) { + total += obj.obj.total; + tip = `${tip} +
+
+
${obj.type || key}:${obj.obj.timeStr}
+
+ `; + } + tip = `
+
tid:${a[0].obj.tid}
+ ${tip} + ${a.length > 1 ? `
total:${getProbablyTime(total)}
` : ''} +
`; + return tip; + } else { + return ''; + } + }, + label: null, + }; + if (key == 'total') { + this.data = source; + } else if (key == 'small') { + this.dataSmall = source; + } else if (key == 'mid') { + this.dataMid = source; + } else if (key == 'big') { + this.dataBig = source; + } + if (this.sort[key].key != '') { + this.sortByColumn(this.sort[key], obj.table, source); + } else { + obj.table.recycleDataSource = source; + } + } + this.progress!.loading = false; + }); + } + + getArrayDataBySize(type: string, arr: Array) { + let data: any[] = []; + for (let obj of arr) { + if (type === 'total') { + data.push({ + pid: obj.pid, + pName: obj.pName, + tid: obj.tid, + tName: obj.tName, + total: obj.big, + size: 'big core', + no: obj.no, + timeStr: obj.bigTimeStr, + }); + data.push({ + pid: obj.pid, + pName: obj.pName, + tid: obj.tid, + tName: obj.tName, + total: obj.mid, + size: 'middle core', + no: obj.no, + timeStr: obj.midTimeStr, + }); + data.push({ + pid: obj.pid, + pName: obj.pName, + tid: obj.tid, + tName: obj.tName, + total: obj.small, + size: 'small core', + no: obj.no, + timeStr: obj.smallTimeStr, + }); + } else { + data.push({ + pid: obj.pid, + pName: obj.pName, + tid: obj.tid, + tName: obj.tName, + total: obj[type], + no: obj.no, + timeStr: obj[`${type}TimeStr`], + }); + } + } + return data; + } + + queryLogicWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName( + 'logic1', + option, + { + bigCores: CheckCpuSetting.big_cores, + midCores: CheckCpuSetting.mid_cores, + smallCores: CheckCpuSetting.small_cores, + }, + undefined, + handler + ); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + getTableColumns(type: string) { + if (type === 'total') { + return `${this.publicColumns}${this.bigColumn}${this.midColumn}${this.smallColumn}`; + } else if (type === 'big') { + return `${this.publicColumns}${this.bigColumn}`; + } else if (type === 'mid') { + return `${this.publicColumns}${this.midColumn}`; + } else if (type === 'small') { + return `${this.publicColumns}${this.smallColumn}`; + } else { + return ''; + } + } + + initHtml(): string { + return ` + + + + +
+
+
+ CPU Setting + + +
+
+ +
+
+
Top20线程大中小核占用率
+ +
+
big
+
mid
+
small
+
+
+
+ +
+
+
+
+
Top20线程小核占用率
+ +
+
small
+
+
+
+ +
+
+
+
+
Top20线程中核占用率
+ +
+
mid
+
+
+
+ +
+
+
+
+
Top20线程大核占用率
+ +
+
big
+
+
+
+ +
+
+
+
+ + `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/Top20ThreadRunTime.ts b/ide/src/trace/component/schedulingAnalysis/Top20ThreadRunTime.ts new file mode 100644 index 0000000000000000000000000000000000000000..70158dc29571105c8bf2932d70cc4c35674b8f7a --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/Top20ThreadRunTime.ts @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../base-ui/table/lit-table.js'; +import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { info } from '../../../log/Log.js'; +import '../../../base-ui/progress-bar/LitProgressBar.js'; +import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; +import './TableNoData.js'; +import { TableNoData } from './TableNoData.js'; + +@element('top20-thread-run-time') +export class Top20ThreadRunTime extends BaseElement { + traceChange: boolean = false; + private table: LitTable | null | undefined; + private progress: LitProgressBar | null | undefined; + private nodata: TableNoData | null | undefined; + private data: Array = []; + + initElements(): void { + this.progress = this.shadowRoot!.querySelector('#loading'); + this.table = this.shadowRoot!.querySelector('#tb-thread-run-time'); + this.nodata = this.shadowRoot!.querySelector('#nodata'); + + this.table!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data; + data.isSelected = true; + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.table!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + init() { + if (!this.traceChange) { + if (this.table!.recycleDataSource.length > 0) { + this.table?.reMeauseHeight(); + } + return; + } + this.progress!.loading = true; + this.traceChange = false; + this.queryLogicWorker(`scheduling-Thread RunTime`, `query Thread Cpu Run Time Analysis Time:`, (res) => { + this.nodata!.noData = res === undefined || res.length === 0; + this.table!.recycleDataSource = res; + this.table?.reMeauseHeight(); + this.progress!.loading = false; + this.data = res; + }); + } + + clearData() { + this.traceChange = true; + this.table!.recycleDataSource = []; + } + + queryLogicWorker(option: string, log: string, handler: (res: any) => void) { + let time = new Date().getTime(); + procedurePool.submitWithName('logic1', option, { cpuMax: SpSchedulingAnalysis.cpuCount - 1 }, undefined, handler); + let durTime = new Date().getTime() - time; + info(log, durTime); + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: any, b: any) { + if (type === 'number') { + // @ts-ignore + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (sort === 2) { + return b[property].toString().localeCompare(a[property].toString()); + } else { + return a[property].toString().localeCompare(b[property].toString()); + } + } + }; + } + + if (detail.key === 'maxDurationStr') { + detail.key = 'maxDuration'; + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else if ( + detail.key === 'cpu' || + detail.key === 'no' || + detail.key === 'pid' || + detail.key === 'tid' || + detail.key === 'timestamp' + ) { + this.data.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.data.sort(compare(detail.key, detail.sort, 'string')); + } + this.table!.recycleDataSource = this.data; + } + + initHtml(): string { + return ` + + +
+
+ + + + + + + + + + + + + + +
+
+ `; + } +} diff --git a/ide/src/trace/component/schedulingAnalysis/utils/Utils.ts b/ide/src/trace/component/schedulingAnalysis/utils/Utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0d40eb6d4cb68ee370fe9c10c3c0d5366802429 --- /dev/null +++ b/ide/src/trace/component/schedulingAnalysis/utils/Utils.ts @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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 { Utils } from '../../trace/base/Utils.js'; + +export const getFormatData = (data: Array) => { + let arrData: Array = []; + data.forEach((item, idx) => { + arrData.push({ + index: idx + 1, + ...item, + avg: Utils.getProbablyTime(item.avg), + max: Utils.getProbablyTime(item.max), + min: Utils.getProbablyTime(item.min), + sum: Utils.getProbablyTime(item.sum), + }); + }); + return arrData; +}; + +export const getDataNo = (data: Array) => { + let arrData: Array = []; + data.forEach((item, idx) => { + arrData.push({ + index: idx + 1, + ...item, + }); + }); + return arrData; +}; + +export const getInitializeTime = (ns: string) => { + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; + let millisecond1 = 1_000_000; + let microsecond1 = 1_000; + + let res = ''; + let currentNs = ns; + if (currentNs.indexOf('h') != -1) { + res += Number(currentNs.slice(0, currentNs.length - 1)) * hour1; + } else if (currentNs.indexOf('m') != -1) { + res += Number(currentNs.slice(0, currentNs.length - 1)) * minute1; + } else if (currentNs.indexOf('s') != -1) { + res += Number(currentNs.slice(0, currentNs.length - 1)) * second1; + } else if (currentNs.indexOf('ms') != -1) { + res += Number(currentNs.slice(0, currentNs.length - 2)) * millisecond1; + } else if (currentNs.indexOf('μs') != -1) { + res += Number(currentNs.slice(0, currentNs.length - 2)) * microsecond1; + } else { + res += Number(currentNs); + } + return res; +}; diff --git a/ide/src/trace/component/setting/SpAllocations.ts b/ide/src/trace/component/setting/SpAllocations.ts new file mode 100644 index 0000000000000000000000000000000000000000..169db93952786d93f4b4c6e34f6dd092f1ae9ff5 --- /dev/null +++ b/ide/src/trace/component/setting/SpAllocations.ts @@ -0,0 +1,530 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { log } from '../../../log/Log.js'; +import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; +import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; +import '../../../base-ui/select/LitAllocationSelect.js'; +import { SpApplication } from '../../SpApplication.js'; +import { LitSearch } from '../trace/search/Search.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; +import { Cmd } from '../../../command/Cmd.js'; +import { CmdConstant } from '../../../command/CmdConstant.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import { LitSlider } from '../../../base-ui/slider/LitSlider'; + +@element('sp-allocations') +export class SpAllocations extends BaseElement { + private processId: LitAllocationSelect | null | undefined; + private unwindEL: HTMLInputElement | null | undefined; + private shareMemory: HTMLInputElement | null | undefined; + private shareMemoryUnit: HTMLSelectElement | null | undefined; + private filterMemory: HTMLInputElement | null | undefined; + private filterMemoryUnit: HTMLSelectElement | null | undefined; + private fpUnWind: LitSwitch | null | undefined; + + private recordAccurately: LitSwitch | null | undefined; + private offlineSymbol: LitSwitch | null | undefined; + private recordStatisticsResult: HTMLDivElement | null | undefined; + + get appProcess(): string { + return this.processId!.value || ''; + } + + get unwind(): number { + log('unwind value is :' + this.unwindEL!.value); + return Number(this.unwindEL!.value); + } + + get shared(): number { + let value = this.shareMemory?.value || ''; + log('shareMemory value is :' + value); + if (value != '') { + let unit = Number(this.shareMemory?.value) || 16384; + return unit; + } + return 16384; + } + + get filter(): number { + let value = this.filterMemory?.value || ''; + log('filter value is :' + value); + if (value != '') { + return Number(value); + } + return 4096; + } + + get fp_unwind(): boolean { + let value = this.fpUnWind?.checked; + if (value != undefined) { + return value; + } + return true; + } + + get record_accurately(): boolean { + let value = this.recordAccurately?.checked; + if (value != undefined) { + return value; + } + return true; + } + + get offline_symbolization(): boolean { + let value = this.offlineSymbol?.checked; + if (value != undefined) { + return value; + } + return true; + } + + get record_statistics(): boolean { + if (this.recordStatisticsResult?.hasAttribute('percent')) { + let value = Number(this.recordStatisticsResult?.getAttribute('percent')); + return value > 0; + } + return true; + } + + get statistics_interval(): number { + if (this.recordStatisticsResult?.hasAttribute('percentValue')) { + return Number(this.recordStatisticsResult?.getAttribute('percentValue')); + } + return 3600; + } + + initElements(): void { + this.processId = this.shadowRoot?.getElementById('pid') as LitAllocationSelect; + let input = this.processId.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; + let sp = document.querySelector('sp-application') as SpApplication; + let litSearch = sp?.shadowRoot?.querySelector('#lit-search') as LitSearch; + let processData: Array = []; + input.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.processId!.processData = []; + } + }); + input.addEventListener('valuable', (ev) => { + this.dispatchEvent(new CustomEvent('addProbe', {})); + }); + input.addEventListener('inputClick', () => { + processData = []; + if (SpRecordTrace.serialNumber != '') { + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_PROCESS_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + this.processId!.processData = processData; + this.processId!.initData(); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((rr) => { + if (sp.search) { + sp.search = false; + litSearch.clear(); + } + if (rr) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_PROCESS, false).then((res) => { + if (res) { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + } + this.processId!.processData = processData; + this.processId!.initData(); + }); + } else { + sp.search = true; + litSearch.clear(); + litSearch.setPercent('please kill other hdc-server! ', -2); + } + }); + } + } + }); + this.unwindEL = this.shadowRoot?.getElementById('unwind') as HTMLInputElement; + this.shareMemory = this.shadowRoot?.getElementById('shareMemory') as HTMLInputElement; + this.shareMemoryUnit = this.shadowRoot?.getElementById('shareMemoryUnit') as HTMLSelectElement; + this.filterMemory = this.shadowRoot?.getElementById('filterSized') as HTMLInputElement; + this.filterMemoryUnit = this.shadowRoot?.getElementById('filterSizedUnit') as HTMLSelectElement; + this.fpUnWind = this.shadowRoot?.getElementById('use_fp_unwind') as LitSwitch; + this.recordAccurately = this.shadowRoot?.getElementById('use_record_accurately') as LitSwitch; + this.offlineSymbol = this.shadowRoot?.getElementById('use_offline_symbolization') as LitSwitch; + let stepValue = [0, 1, 10, 30, 60, 300, 600, 1800, 3600]; + let statisticsSlider = this.shadowRoot?.querySelector('#interval-slider') as LitSlider; + + this.recordStatisticsResult = this.shadowRoot?.querySelector( + '.record-statistics-result' + ) as HTMLDivElement; + statisticsSlider.sliderStyle = { + minRange: 0, + maxRange: 3600, + defaultValue: '3600', + resultUnit: 'S', + stepSize: 450, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + let parentElement = statisticsSlider!.parentNode as Element; + let intervalResultInput = this.shadowRoot?.querySelector('.interval-result') as HTMLInputElement; + intervalResultInput.value = statisticsSlider.sliderStyle.defaultValue; + statisticsSlider.addEventListener('input', (evt) => { + statisticsSlider!.sliderStyle = { + minRange: 0, + maxRange: 3600, + defaultValue: this.recordStatisticsResult!.getAttribute('percent') + '', + resultUnit: 'S', + stepSize: 450, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + intervalResultInput.style.color = 'var(--dark-color1,#000000)'; + if (this.recordStatisticsResult!.hasAttribute('percent')) { + let step = Number(this.recordStatisticsResult!.getAttribute('percent')) / 450; + this.recordStatisticsResult!.setAttribute('percentValue', stepValue[step] + ''); + intervalResultInput.value = stepValue[step] + ''; + } + }); + parentElement.setAttribute('percent', '3600'); + intervalResultInput.style.color = 'var(--dark-color1,#000000)'; + intervalResultInput.addEventListener('input', (ev) => { + if (this.recordStatisticsResult!.hasAttribute('percent')) { + this.recordStatisticsResult!.removeAttribute('percent'); + } + intervalResultInput.style.color = 'var(--dark-color1,#000000)'; + intervalResultInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + intervalResultInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + if (intervalResultInput.value.trim() == '') { + intervalResultInput.style.color = 'red'; + parentElement.setAttribute('percent', '3600'); + return; + } + let memorySize = Number(intervalResultInput.value); + if ( + memorySize < statisticsSlider!.sliderStyle.minRange || + memorySize > statisticsSlider!.sliderStyle.maxRange + ) { + intervalResultInput.style.color = 'red'; + parentElement.setAttribute('percent', '3600'); + } else { + statisticsSlider!.percent = intervalResultInput.value; + let htmlInputElement = statisticsSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; + htmlInputElement.value = intervalResultInput.value; + statisticsSlider!.sliderStyle = { + minRange: 0, + maxRange: 3600, + defaultValue: intervalResultInput.value, + resultUnit: 'S', + stepSize: 1, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + parentElement.setAttribute('percent', intervalResultInput.value); + parentElement.setAttribute('percentValue', intervalResultInput.value); + } + }); + + intervalResultInput.addEventListener('focusout', (ev) => { + if (intervalResultInput.value.trim() == '') { + parentElement.setAttribute('percent', '3600'); + intervalResultInput.value = '3600'; + intervalResultInput.style.color = 'var(--dark-color,#6a6f77)'; + parentElement.setAttribute('percent', intervalResultInput.value); + parentElement.setAttribute('percentValue', intervalResultInput.value); + statisticsSlider!.percent = intervalResultInput.value; + let htmlInputElement = statisticsSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; + htmlInputElement.value = intervalResultInput.value; + } + }); + statisticsSlider.shadowRoot?.querySelector('#slider')!.addEventListener('mouseup', (ev) => { + setTimeout(() => { + let percentValue = this.recordStatisticsResult!.getAttribute('percent'); + let index = Number(percentValue) / 450; + index = index < 1 ? 0 : index; + intervalResultInput.value = stepValue[index] + ''; + this.recordStatisticsResult!.setAttribute('percentValue', stepValue[index] + ''); + }); + }); + } + + initHtml(): string { + return ` + +
+
+ Native Memory +
+
+ ProcessId or ProcessName + Record process + + +
+
+ Max unwind level + Max Unwind Level Rang is 0 - 512, default 10 + +
+
+ Shared Memory Size (One page equals 4 KB) + Shared Memory Size Range is 0 - 131072 page, default 16384 page +
+ + Page +
+
+
+ Filter Memory Size + Filter size Range is 0 - 65535 byte, default 4096 byte +
+ + Byte +
+
+
+ Use Fp Unwind + +
+
+ Use Record Accurately (Available on recent OpenHarmony 4.0) + +
+
+ Use Offline Symbolization (Available on recent OpenHarmony 4.0) + +
+ +
+
+ Use Record Statistics (Available on recent OpenHarmony 4.0) + Time between following interval (0 = disabled) +
+ + +
+ + S +
+
+
+ `; + } + + private convertToValue(input: string, unit: string): number { + let value: number; + switch (unit) { + case 'MB': + value = Number(input) * 1024 * 1024; + break; + case 'KB': + value = Number(input) * 1024; + break; + default: + value = 0; + } + let number = value / 4096; + if (number > 0 && number < 1) { + return 16384; + } + return parseInt(String(number)); + } +} diff --git a/ide/src/trace/component/setting/SpCheckDesBox.ts b/ide/src/trace/component/setting/SpCheckDesBox.ts new file mode 100644 index 0000000000000000000000000000000000000000..57918df3de567188acbcedea19c11c723fb5088a --- /dev/null +++ b/ide/src/trace/component/setting/SpCheckDesBox.ts @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitCheckBox } from '../../../base-ui/checkbox/LitCheckBox.js'; + +@element('check-des-box') +export class SpCheckDesBox extends BaseElement { + private _checkBox: LitCheckBox | undefined; + private _des: HTMLSpanElement | undefined; + + static get observedAttributes() { + return ['checked', 'value', 'des']; + } + + set des(des: string) { + this.setAttribute('des', des); + } + + get value(): string { + return this.getAttribute('value') || ''; + } + + set value(value: string) { + this.setAttribute('value', value); + this._checkBox!.value = value; + } + + get checked() { + return this.getAttribute('checked') != null; + } + + set checked(checked: boolean) { + if (checked) { + this.setAttribute('checked', 'true'); + this._checkBox!.checked = true; + } else { + this.removeAttribute('checked'); + this._checkBox!.checked = false; + } + } + + initElements(): void { + this._checkBox = this.shadowRoot?.getElementById('checkBox') as LitCheckBox; + this._des = this.shadowRoot?.getElementById('des') as HTMLSpanElement; + } + + initHtml(): string { + return ` + + +
+ +
`; + } + + public connectedCallback() { + this._checkBox?.addEventListener('change', (ev: any) => { + let detail = ev.detail; + this.checked = detail.checked; + this.dispatchEvent(new CustomEvent('onchange', { detail })); + }); + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name == 'checked') { + this._checkBox!.checked = newValue !== null; + } + if (name == 'value') { + this._checkBox!.value = newValue; + } + if (name == 'des') { + this._des!.textContent = newValue; + } + } +} + +export interface checkDesBean { + value: string; + isSelect: boolean; + des: string; +} diff --git a/ide/src/trace/component/setting/SpFileSystem.ts b/ide/src/trace/component/setting/SpFileSystem.ts new file mode 100644 index 0000000000000000000000000000000000000000..eaf8592fd3f418fa989d8f015f68051908649ffa --- /dev/null +++ b/ide/src/trace/component/setting/SpFileSystem.ts @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitSelectV } from '../../../base-ui/select/LitSelectV.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import '../../../base-ui/select/LitSelectV.js'; +import '../../../base-ui/select/LitSelect.js'; + +import '../../../base-ui/switch/lit-switch.js'; +import { LitSelect } from '../../../base-ui/select/LitSelect.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; +import { Cmd } from '../../../command/Cmd.js'; +import { CmdConstant } from '../../../command/CmdConstant.js'; +import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; + +@element('sp-file-system') +export class SpFileSystem extends BaseElement { + private processInput: LitSelectV | undefined | null; + private maximum: HTMLInputElement | undefined | null; + private selectProcess: HTMLInputElement | undefined | null; + + private configList: Array = []; + private list: Array = []; + + private eventList: Array = ['open', 'close', 'read', 'write']; + + set startRecord(start: boolean) { + if (start) { + this.unDisable(); + this.setAttribute('startRecord', ''); + this.selectProcess!.removeAttribute('readonly'); + } else { + if (!this.startFileSystem && !this.startVirtualMemory && !this.startIo) { + this.removeAttribute('startRecord'); + this.disable(); + this.selectProcess!.setAttribute('readonly', 'readonly'); + } + } + } + + get startRecord(): boolean { + return this.hasAttribute('startRecord'); + } + + set startFileSystem(start: boolean) { + if (start) { + this.setAttribute('startSamp', ''); + } else { + this.removeAttribute('startSamp'); + } + this.startRecord = start; + } + + get startFileSystem(): boolean { + return this.hasAttribute('startSamp'); + } + + set startVirtualMemory(start: boolean) { + if (start) { + this.setAttribute('virtual', ''); + } else { + this.removeAttribute('virtual'); + } + this.startRecord = start; + } + + get startVirtualMemory(): boolean { + return this.hasAttribute('virtual'); + } + + set startIo(start: boolean) { + if (start) { + this.setAttribute('io', ''); + } else { + this.removeAttribute('io'); + } + this.startRecord = start; + } + + get startIo(): boolean { + return this.hasAttribute('io'); + } + + getSystemConfig(): SystemConfig | undefined { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + let systemConfig: SystemConfig = { + process: '', + unWindLevel: 0, + }; + configVal!.forEach((value) => { + switch (value.title) { + case 'Process': + let processSelect = value as LitSelectV; + if (processSelect.all) { + systemConfig.process = 'ALL'; + break; + } + if (processSelect.value.length > 0) { + let result = processSelect.value.match(/\((.+?)\)/g); + if (result) { + systemConfig.process = result.toString().replaceAll('(', '').replaceAll(')', ''); + } else { + systemConfig.process = processSelect.value; + } + } + break; + case 'Max Unwind Level': + let maxUnwindLevel = value as HTMLInputElement; + if (maxUnwindLevel.value != '') { + systemConfig.unWindLevel = Number(maxUnwindLevel.value); + } + } + }); + return systemConfig; + } + + initElements(): void { + this.initConfigList(); + let configList = this.shadowRoot?.querySelector('.configList'); + this.configList.forEach((config) => { + let div = document.createElement('div'); + if (config.hidden) { + div.className = 'config-div hidden'; + } else { + div.className = 'config-div'; + } + let headDiv = document.createElement('div'); + div.appendChild(headDiv); + let title = document.createElement('span'); + title.className = 'title'; + title.textContent = config.title; + headDiv.appendChild(title); + let des = document.createElement('span'); + des.textContent = config.des; + des.className = 'des'; + headDiv.appendChild(des); + switch (config.type) { + case 'select-multiple': + let html = ''; + let placeholder = config.selectArray[0]; + if (config.title == 'Process') { + } else if (config.title == 'SystemCall Event') { + placeholder = 'ALL-Event'; + } + html += ``; + config.selectArray.forEach((value: string) => { + html += `${value}`; + }); + html += ``; + div.innerHTML = div.innerHTML + html; + break; + case 'input': + let input = document.createElement('input'); + input.className = 'input config'; + input.textContent = config.value; + input.value = config.value; + input.title = config.title; + if (config.title == 'Record Time') { + input.oninput = (ev) => { + input.value = input.value.replace(/\D/g, ''); + }; + } + div.appendChild(input); + break; + case 'select': + let html1 = ''; + html1 += ``; + config.selectArray.forEach((value: string) => { + html1 += `${value}`; + }); + html1 += ``; + div.innerHTML = div.innerHTML + html1; + break; + case 'switch': + let switch1 = document.createElement('lit-switch') as LitSwitch; + switch1.className = 'config'; + switch1.title = config.title; + if (config.value) { + switch1.checked = true; + } else { + switch1.checked = false; + } + if (config.title == 'Start FileSystem Record') { + switch1.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startFileSystem = true; + } else { + this.startFileSystem = false; + } + }); + } + if (config.title == 'Start Page Fault Record') { + switch1.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startVirtualMemory = true; + } else { + this.startVirtualMemory = false; + } + }); + } + if (config.title == 'Start BIO Latency Record') { + switch1.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startIo = true; + } else { + this.startIo = false; + } + }); + } + headDiv.appendChild(switch1); + break; + default: + break; + } + configList!.appendChild(div); + }); + this.processInput = this.shadowRoot?.querySelector("lit-select-v[title='Process']"); + this.maximum = this.shadowRoot?.querySelector("input[title='Max Unwind Level']"); + this.maximum?.addEventListener('keyup', (eve: Event) => { + this.maximum!.value = this.maximum!.value.replace(/\D/g, ''); + if (this.maximum!.value != '') { + let mun = parseInt(this.maximum!.value); + if (mun > 64 || mun < 0) { + this.maximum!.value = '10'; + } + } + }); + this.selectProcess = this.processInput!.shadowRoot?.querySelector('input') as HTMLInputElement; + let processData: Array = []; + this.selectProcess!.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.dataSource([], ''); + } + }); + + this.selectProcess!.addEventListener('mouseup', () => { + if (SpRecordTrace.serialNumber == '') { + this.processInput?.dataSource([], 'ALL-Process'); + } else { + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_PROCESS_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + processData = []; + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + if (processData.length > 0 && this.startRecord) { + this.processInput!.setAttribute('readonly', 'readonly'); + } + this.processInput?.dataSource(processData, 'ALL-Process'); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_PROCESS, false).then((res) => { + processData = []; + if (res) { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + } + if (processData.length > 0 && this.startRecord) { + this.selectProcess!.setAttribute('readonly', 'readonly'); + } + this.processInput?.dataSource(processData, 'ALL-Process'); + }); + } + }); + } + } + }); + this.disable(); + } + + private unDisable() { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + configVal!.forEach((configVal1) => { + configVal1.removeAttribute('disabled'); + }); + } + + private disable() { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + configVal!.forEach((configVal1) => { + if ( + configVal1.title == 'Start FileSystem Record' || + configVal1.title == 'Start Page Fault Record' || + configVal1.title == 'Start BIO Latency Record' + ) { + } else { + configVal1.setAttribute('disabled', ''); + } + }); + } + + initConfigList(): void { + this.configList = [ + { + title: 'Start FileSystem Record', + des: '', + hidden: false, + type: 'switch', + value: false, + }, + { + title: 'Start Page Fault Record', + des: '', + hidden: false, + type: 'switch', + value: false, + }, + { + title: 'Start BIO Latency Record', + des: '', + hidden: false, + type: 'switch', + value: false, + }, + { + title: 'Process', + des: 'Record process', + hidden: false, + type: 'select-multiple', + selectArray: [''], + }, + { + title: 'Max Unwind Level', + des: '', + hidden: false, + type: 'input', + value: '10', + }, + ]; + } + + initHtml(): string { + return ` + +
+
+
+
+ `; + } +} + +export interface SystemConfig { + process: string; + unWindLevel: number; +} diff --git a/ide/src/trace/component/setting/SpHisysEvent.ts b/ide/src/trace/component/setting/SpHisysEvent.ts new file mode 100644 index 0000000000000000000000000000000000000000..a76aefb043aeb9e9afd8d60e9ebd788021b47c2d --- /dev/null +++ b/ide/src/trace/component/setting/SpHisysEvent.ts @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import '../../../base-ui/select/LitAllocationSelect.js'; + +import '../../../base-ui/switch/lit-switch.js'; +import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; +import { Cmd } from '../../../command/Cmd.js'; +import { CmdConstant } from '../../../command/CmdConstant.js'; +import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; + +@element('sp-hisys-event') +export class SpHisysEvent extends BaseElement { + private processInput: LitAllocationSelect | undefined | null; + private selectProcess: HTMLInputElement | undefined | null; + private configList: Array = []; + + set startSamp(start: boolean) { + if (start) { + this.setAttribute('startSamp', ''); + } else { + this.removeAttribute('startSamp'); + let input = this.processInput?.shadowRoot?.querySelector('#singleInput'); + input!.value = ''; + } + } + + get process(): string { + if (this.processInput!.value.length > 0) { + return this.processInput!.value; + } + return ''; + } + + get startSamp(): boolean { + return this.hasAttribute('startSamp'); + } + + initElements(): void { + this.initConfigList(); + let configList = this.shadowRoot?.querySelector('.configList'); + this.configList.forEach((config) => { + let div = document.createElement('div'); + if (config.hidden) { + div.className = 'config-div hidden'; + } else { + div.className = 'config-div'; + } + let headDiv = document.createElement('div'); + div.appendChild(headDiv); + let title = document.createElement('span'); + title.className = 'title'; + title.textContent = config.title; + headDiv.appendChild(title); + let des = document.createElement('span'); + des.textContent = config.des; + des.className = 'des'; + headDiv.appendChild(des); + switch (config.type) { + case 'select': + let html1 = ''; + html1 += ``; + html1 += ``; + div.innerHTML = div.innerHTML + html1; + break; + case 'switch': + let switch1 = document.createElement('lit-switch') as LitSwitch; + switch1.className = 'config'; + switch1.title = config.title; + if (config.value) { + switch1.checked = true; + } else { + switch1.checked = false; + } + if (config.title == 'Start Hisystem Event Tracker Record') { + switch1.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startSamp = true; + this.unDisable(); + } else { + this.startSamp = false; + this.disable(); + } + }); + } + headDiv.appendChild(switch1); + break; + default: + break; + } + configList!.appendChild(div); + }); + this.processInput = this.shadowRoot?.querySelector("lit-allocation-select[title='AppName']"); + let inputDiv = this.processInput?.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; + this.selectProcess = this.processInput!.shadowRoot?.querySelector('input') as HTMLInputElement; + let processData: Array = []; + inputDiv!.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.processData = []; + this.processInput!.initData(); + } + }); + inputDiv!.addEventListener('mouseup', () => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.processData = []; + this.processInput!.initData(); + } else { + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_APP_NMAE_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + processData = []; + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('CMD') != -1) { + continue; + } + let process = lineVal.trim(); + if (process != '') { + processData.push(process); + } + } + this.processInput!.processData = processData; + this.processInput!.initData(); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_APP_NMAE, false).then((res) => { + processData = []; + if (res) { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('CMD') != -1) { + continue; + } + let process = lineVal.trim(); + if (process != '') { + processData.push(process); + } + } + } + this.processInput!.processData = processData; + this.processInput!.initData(); + }); + } + }); + } + } + }); + this.disable(); + } + + private unDisable() { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + configVal!.forEach((configVal1) => { + configVal1.removeAttribute('disabled'); + }); + } + + private disable() { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + configVal!.forEach((configVal1) => { + if (configVal1.title != 'Start Hisystem Event Tracker Record') { + configVal1.setAttribute('disabled', ''); + } + }); + } + + initConfigList(): void { + this.configList = [ + { + title: 'Start Hisystem Event Tracker Record', + des: '', + hidden: false, + type: 'switch', + value: false, + }, + { + title: 'AppName', + des: 'Record AppName', + hidden: false, + type: 'select', + selectArray: [''], + }, + ]; + } + + initHtml(): string { + return ` + +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/setting/SpJsHeap.ts b/ide/src/trace/component/setting/SpJsHeap.ts new file mode 100644 index 0000000000000000000000000000000000000000..74f14a048ca7e903fdb34316e47c766abe042862 --- /dev/null +++ b/ide/src/trace/component/setting/SpJsHeap.ts @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import '../../../base-ui/select/LitAllocationSelect.js'; + +import '../../../base-ui/switch/lit-switch.js'; +import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; +import { Cmd } from '../../../command/Cmd.js'; +import { CmdConstant } from '../../../command/CmdConstant.js'; +import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; +import { LitRadioBox } from '../../../base-ui/radiobox/LitRadioBox.js'; +import { SpCheckDesBox } from './SpCheckDesBox.js'; + +@element('sp-js-heap') +export class SpJsHeap extends BaseElement { + private processInput: LitAllocationSelect | undefined | null; + private spCheckDesBox: SpCheckDesBox | undefined | null; + private radioBox: LitRadioBox | undefined | null; + private interval: HTMLInputElement | undefined | null; + + get process(): string { + if (this.processInput!.value.length > 0) { + return this.processInput!.value; + } + return ''; + } + + get radioBoxType(): number { + this.radioBox = this.shadowRoot?.querySelector(`lit-radio[checked]`); + let type = this.radioBox?.getAttribute('type'); + return Number(type); + } + + get grabNumeric(): boolean { + if (this.radioBoxType === 0) { + this.spCheckDesBox = this.shadowRoot?.querySelector('#snapshot'); + let isChecked = this.spCheckDesBox?.getAttribute('checked'); + return isChecked === 'true'; + } else { + return false; + } + } + + get grabAllocations(): boolean { + if (this.radioBoxType === 1) { + this.spCheckDesBox = this.shadowRoot?.querySelector('#timeline'); + let isChecked = this.spCheckDesBox?.getAttribute('checked'); + return isChecked === 'true'; + } else { + return false; + } + } + + get intervalValue(): number { + if (this.radioBoxType === 0) { + return Number(this.interval!.value); + } else { + return 0; + } + } + + initElements(): void { + this.interval = this.shadowRoot?.querySelector('#interval'); + this.processInput = this.shadowRoot?.querySelector('lit-allocation-select'); + let processInput = this.processInput?.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; + let processData: Array = []; + processInput!.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.processData = []; + this.processInput!.initData(); + } + }); + processInput!.addEventListener('mouseup', () => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.processData = []; + this.processInput!.initData(); + } else { + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_PROCESS_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + processData = []; + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + this.processInput!.processData = processData; + this.processInput!.initData(); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_PROCESS, false).then((res) => { + processData = []; + if (res) { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + } + this.processInput!.processData = processData; + this.processInput!.initData(); + }); + } + }); + } + } + }); + this.interval!.addEventListener('focusout', () => { + if (this.interval!.value === '') { + this.interval!.value = '10'; + } + }); + } + + initHtml(): string { + return ` + +
+
+
+ Process + Record process +
+ +
+
+
+ Select profiling type +
+ Heap snapshot +
+ Heap snapshot profiles show memory distribution among your page’s JavaScript objects and related DOM nodes. +
+ + +
+ Interval(Available on recent OpenHarmony 4.0) +
+ + S +
+
+ + Allocation insteumentation on timeline +
+ Allocation timelines show insturmented Javascript memory allocations over time. Once profile is recorded you can select a time interval to see objects that werre allocated within it and still alive by the end of recording. Use this profile type to isolate memory leaks. +
+ + +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/setting/SpProbesConfig.ts b/ide/src/trace/component/setting/SpProbesConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..313fdeed5d513d4cd5261fe874bd9de0fa9d4da5 --- /dev/null +++ b/ide/src/trace/component/setting/SpProbesConfig.ts @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { checkDesBean, SpCheckDesBox } from './SpCheckDesBox.js'; +import { LitCheckBox } from '../../../base-ui/checkbox/LitCheckBox.js'; +import { LitRadioGroup } from '../../../base-ui/radiobox/LitRadioGroup.js'; +import { info, log } from '../../../log/Log.js'; + +@element('probes-config') +export class SpProbesConfig extends BaseElement { + private traceConfigList: Array | undefined; + private memoryConfigList: Array | undefined; + private abilityConfigList: Array | undefined; + private hitraceConfigList: Array | undefined; + private hitrace: SpCheckDesBox | undefined; + + private _traceConfig: HTMLElement | undefined; + private _memoryConfig: HTMLElement | undefined | null; + private _abilityConfig: HTMLElement | undefined | null; + + get traceConfig() { + let selectedTrace = this._traceConfig?.querySelectorAll(`check-des-box[checked]`) || []; + let values = []; + for (const litCheckBoxElement of selectedTrace) { + values.push(litCheckBoxElement.value); + } + if (this.hitrace && this.hitrace.checked) { + values.push(this.hitrace.value); + } + info('traceConfig is :', values); + return values; + } + + get memoryConfig() { + let values = []; + let selectedMemory = this._memoryConfig?.querySelectorAll( + `check-des-box[checked]` + ) as NodeListOf; + for (const litCheckBoxElement of selectedMemory) { + values.push(litCheckBoxElement.value); + } + log('memoryConfig size is :' + values.length); + return values; + } + + get recordAbility() { + let selectedMemory = this._abilityConfig?.querySelectorAll( + `check-des-box[checked]` + ) as NodeListOf; + return selectedMemory.length > 0; + } + + get traceEvents() { + let values = []; + if (this.hitrace && this.hitrace.checked) { + let parent = this.shadowRoot?.querySelector('.user-events') as Element; + const siblingNode = parent?.querySelectorAll(`lit-check-box[name=userEvents][checked]`); + for (const litCheckBoxElement of siblingNode) { + values.push(litCheckBoxElement.value); + } + } + log('traceEvents size is :' + values.length); + return values; + } + + get hilogConfig() { + let logLevel = this.shadowRoot?.getElementById('logLevel') as LitCheckBox; + if (logLevel.checked) { + let logRadio = this.shadowRoot?.getElementById('log-radio') as LitRadioGroup; + return logRadio.value; + } else { + return []; + } + } + + initElements(): void { + this.traceConfigList = [ + { + value: 'Scheduling details', + isSelect: true, + des: 'enables high-detailed tracking of scheduling events', + }, + { + value: 'CPU Frequency and idle states', + isSelect: true, + des: 'Records cpu frequency and idle state change viaftrace', + }, + { + value: 'Advanced ftrace config', + isSelect: false, + des: + 'Enable individual events and tune the kernel-tracing(ftrace) module.' + + 'The events enabled here are in addition to those from' + + ' enabled by other probes.', + }, + ]; + this._traceConfig = this.shadowRoot?.querySelector('.trace-config') as HTMLElement; + this.traceConfigList.forEach((configBean) => { + let checkDesBox = new SpCheckDesBox(); + checkDesBox.value = configBean.value; + checkDesBox.checked = configBean.isSelect; + checkDesBox.des = configBean.des; + checkDesBox.addEventListener('onchange', (ev: any) => { + this.dispatchEvent(new CustomEvent('addProbe', {})); + }); + this._traceConfig?.appendChild(checkDesBox); + }); + this.memoryConfigList = [ + { + value: 'Kernel meminfo', + isSelect: false, + des: 'polling of /proc/meminfo', + }, + { + value: 'Virtual memory stats', + isSelect: false, + des: + 'Periodically polls virtual memory stats from /proc/vmstat.' + + ' Allows to gather statistics about swap,' + + 'eviction, compression and pagecache efficiency', + }, + ]; + this._memoryConfig = this.shadowRoot?.querySelector('.memory-config'); + this.memoryConfigList.forEach((configBean) => { + let checkDesBox = new SpCheckDesBox(); + checkDesBox.value = configBean.value; + checkDesBox.checked = configBean.isSelect; + checkDesBox.des = configBean.des; + checkDesBox.addEventListener('onchange', (ev: any) => { + this.dispatchEvent(new CustomEvent('addProbe', {})); + }); + this._memoryConfig?.appendChild(checkDesBox); + }); + this.abilityConfigList = [ + { + value: 'AbilityMonitor', + isSelect: false, + des: 'Tracks the AbilityMonitor', + }, + ]; + this._abilityConfig = this.shadowRoot?.querySelector('.ability-config'); + this.abilityConfigList.forEach((configBean) => { + let checkDesBox = new SpCheckDesBox(); + checkDesBox.value = configBean.value; + checkDesBox.checked = configBean.isSelect; + checkDesBox.des = configBean.des; + checkDesBox.addEventListener('onchange', (ev: any) => { + this.dispatchEvent(new CustomEvent('addProbe', {})); + }); + this._abilityConfig?.appendChild(checkDesBox); + }); + + this.hitraceConfigList = [ + { value: 'ability', isSelect: true }, + { value: 'accesscontrol', isSelect: false }, + { value: 'accessibility', isSelect: false }, + { value: 'account', isSelect: false }, + { value: 'ace', isSelect: true }, + { value: 'app', isSelect: true }, + { value: 'ark', isSelect: true }, + { value: 'binder', isSelect: true }, + { value: 'daudio', isSelect: false }, + { value: 'dcamera', isSelect: false }, + { value: 'devicemanager', isSelect: false }, + { value: 'deviceprofile', isSelect: false }, + { value: 'dhfwk', isSelect: false }, + { value: 'dinput', isSelect: false }, + { value: 'disk', isSelect: true }, + { value: 'dlpcre', isSelect: false }, + { value: 'dsched', isSelect: false }, + { value: 'dscreen', isSelect: false }, + { value: 'dslm', isSelect: false }, + { value: 'dsoftbus', isSelect: false }, + { value: 'filemanagement', isSelect: false }, + { value: 'freq', isSelect: true }, + { value: 'graphic', isSelect: true }, + { value: 'gresource', isSelect: false }, + { value: 'huks', isSelect: false }, + { value: 'i2c', isSelect: false }, + { value: 'idle', isSelect: true }, + { value: 'irq', isSelect: true }, + { value: 'load', isSelect: false }, + { value: 'mdfs', isSelect: false }, + { value: 'memreclaim', isSelect: true }, + { value: 'misc', isSelect: false }, + { value: 'mmc', isSelect: true }, + { value: 'msdp', isSelect: false }, + { value: 'multimodalinput', isSelect: true }, + { value: 'net', isSelect: false }, + { value: 'notification', isSelect: false }, + { value: 'nweb', isSelect: false }, + { value: 'ohos', isSelect: true }, + { value: 'pagecache', isSelect: true }, + { value: 'power', isSelect: false }, + { value: 'regulators', isSelect: false }, + { value: 'rpc', isSelect: true }, + { value: 'samgr', isSelect: false }, + { value: 'sched', isSelect: true }, + { value: 'sensors', isSelect: false }, + { value: 'sync', isSelect: true }, + { value: 'ufs', isSelect: false }, + { value: 'useriam', isSelect: false }, + { value: 'window', isSelect: true }, + { value: 'workq', isSelect: true }, + { value: 'zaudio', isSelect: true }, + { value: 'zcamera', isSelect: true }, + { value: 'zimage', isSelect: true }, + { value: 'zmedia', isSelect: true }, + ]; + this.hitrace = this.shadowRoot?.getElementById('hitrace') as SpCheckDesBox; + let parent = this.shadowRoot?.querySelector('.user-events') as Element; + this.hitraceConfigList?.forEach((hitraceConfig: any) => { + let litCheckBox = new LitCheckBox(); + litCheckBox.setAttribute('name', 'userEvents'); + litCheckBox.value = hitraceConfig.value; + litCheckBox.checked = hitraceConfig.isSelect; + litCheckBox.addEventListener('change', (ev: any) => { + let detail = ev.detail; + if (this.hitrace?.checked == false) { + this.hitrace.checked = detail.checked; + } + if (detail.checked == false && this.hitrace?.checked == true) { + let hasChecked = false; + const nodes = parent?.querySelectorAll(`lit-check-box[name=userEvents]`); + nodes.forEach((vv) => { + if (vv.checked) { + hasChecked = true; + } + }); + if (!hasChecked) { + this.hitrace.checked = hasChecked; + } + } + this.dispatchEvent(new CustomEvent('addProbe', {})); + }); + parent.append(litCheckBox); + }); + } + + initHtml(): string { + return ` + +
+
Record mode
+
+
+
+
+ + +
+ +
+
+
+
+
+ Memory Config +
+
+
+
+ Ability Config +
+
+
+
+ `; + } + + //当 custom element首次被插入文档DOM时,被调用。 + public connectedCallback() { + let parent = this.shadowRoot?.querySelector('.user-events') as Element; + const siblingNode = parent?.querySelectorAll(`lit-check-box[name=userEvents]`); + this.hitrace!.addEventListener('onchange', (ev: any) => { + let detail = ev.detail; + siblingNode.forEach((node) => { + node.checked = detail.checked; + }); + this.dispatchEvent(new CustomEvent('addProbe', {})); + }); + } +} diff --git a/ide/src/trace/component/setting/SpRecordPerf.ts b/ide/src/trace/component/setting/SpRecordPerf.ts new file mode 100644 index 0000000000000000000000000000000000000000..238d3281350c5efb59c9ebea7ef397df6f2326fd --- /dev/null +++ b/ide/src/trace/component/setting/SpRecordPerf.ts @@ -0,0 +1,861 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { LitSelectV } from '../../../base-ui/select/LitSelectV.js'; +import { LitSelect } from '../../../base-ui/select/LitSelect.js'; +import { LitSlider } from '../../../base-ui/slider/LitSlider.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import '../../../base-ui/select/LitSelectV.js'; +import '../../../base-ui/select/LitSelect.js'; + +import '../../../base-ui/switch/lit-switch.js'; +import { info, log } from '../../../log/Log.js'; +import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; +import { SpApplication } from '../../SpApplication.js'; +import { LitSearch } from '../trace/search/Search.js'; +import { Cmd } from '../../../command/Cmd.js'; +import { CmdConstant } from '../../../command/CmdConstant.js'; + +@element('sp-record-perf') +export class SpRecordPerf extends BaseElement { + private addOptionButton: HTMLButtonElement | undefined | null; + private processSelect: LitSelectV | undefined | null; + private cpuSelect: LitSelectV | undefined | null; + private eventSelect: LitSelectV | undefined | null; + + private frequencySetInput: HTMLInputElement | undefined | null; + private processInput: HTMLInputElement | undefined | null; + private offCPUSwitch: LitSwitch | undefined | null; + private callSelect: LitSelect | undefined | null; + private configList: Array = []; + + get show(): boolean { + return this.hasAttribute('show'); + } + + set show(show: boolean) { + if (show) { + this.setAttribute('show', ''); + } else { + this.removeAttribute('show'); + } + } + + set startSamp(start: boolean) { + if (start) { + this.setAttribute('startSamp', ''); + this.processInput!.removeAttribute('readonly'); + } else { + this.removeAttribute('startSamp'); + this.processInput!.setAttribute('readonly', 'readonly'); + } + } + + get startSamp(): boolean { + return this.hasAttribute('startSamp'); + } + + getPerfConfig(): PerfConfig | undefined { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + let perfConfig: PerfConfig = { + process: 'ALL', + cpu: 'select ALL', + eventList: 'NONE', + cpuPercent: 100, + frequency: 1000, + period: 1, + isOffCpu: true, + noInherit: false, + callStack: 'dwarf', + branch: 'none', + mmap: 256, + clockType: 'monotonic', + }; + configVal!.forEach((value) => { + switch (value.title) { + case 'Process': + let processSelect = value as LitSelectV; + if (processSelect.all) { + perfConfig.process = 'ALL'; + break; + } + if (processSelect.value.length > 0) { + let result = processSelect.value.match(/\((.+?)\)/g); + if (result) { + perfConfig.process = result.toString().replaceAll('(', '').replaceAll(')', ''); + } else { + perfConfig.process = processSelect.value; + } + } + break; + case 'CPU': + let selectV = value as LitSelectV; + if (selectV.value.length > 0) { + perfConfig.cpu = selectV.value; + } + break; + case 'Event List': + let selectList = value as LitSelectV; + if (selectList.value.length > 0) { + perfConfig.eventList = selectList.value.replace(/\s/g, ','); + } + break; + case 'CPU Percent': + let selectSlider = value as LitSlider; + let parEle = value.parentElement; + if (parEle!.hasAttribute('percent')) { + let percent = parEle!.getAttribute('percent'); + perfConfig.cpuPercent = Number(percent); + } + break; + case 'Frequency': + let input = value as HTMLInputElement; + if (input.value != '') { + perfConfig.frequency = Number(input.value); + } + break; + case 'Period': + let periodInput = value as HTMLInputElement; + if (periodInput.value != '') { + perfConfig.period = Number(periodInput.value); + } + break; + case 'Off CPU': + let cpuImage = value as LitSwitch; + perfConfig.isOffCpu = cpuImage.checked; + break; + case 'No Inherit': + let InheritImage = value as LitSwitch; + perfConfig.noInherit = InheritImage.checked; + break; + case 'Call Stack': + let callStack = value as LitSelect; + if (callStack.value != '') { + perfConfig.callStack = callStack.value; + } + break; + case 'Branch': + let branch = value as LitSelect; + if (branch.value != '') { + perfConfig.branch = branch.value; + } + break; + case 'Mmap Pages': + let pages = value as LitSlider; + let parent = value.parentElement; + if (parent!.hasAttribute('percent')) { + let pagesPercent = parent!.getAttribute('percent'); + perfConfig.mmap = Math.pow(2, Number(pagesPercent)); + } + break; + case 'Clock Type': + let clock = value as LitSelect; + if (clock.value != '') { + perfConfig.clockType = clock.value; + } + break; + } + }); + info('perfConfig is : ', perfConfig); + return perfConfig; + } + + initElements(): void { + let that = this; + this.initConfigList(); + let configList = this.shadowRoot?.querySelector('.configList'); + this.addOptionButton = this.shadowRoot?.querySelector('#addOptions'); + this.configList.forEach((config) => { + let div = document.createElement('div'); + if (config.hidden) { + div.className = 'config-div hidden'; + } else { + div.className = 'config-div'; + } + let headDiv = document.createElement('div'); + div.appendChild(headDiv); + let title = document.createElement('span'); + title.className = 'title'; + title.textContent = config.title; + headDiv.appendChild(title); + let des = document.createElement('span'); + des.textContent = config.des; + des.className = 'des'; + headDiv.appendChild(des); + switch (config.type) { + case 'select-multiple': + let html = ''; + let placeholder = config.selectArray[0]; + if (config.title == 'Event List') { + placeholder = 'NONE'; + } + html += ``; + config.selectArray.forEach((value: string) => { + html += `${value}`; + }); + html += ``; + div.innerHTML = div.innerHTML + html; + break; + case 'lit-slider': + let silder = `
+ +
`; + div.innerHTML = div.innerHTML + silder; + let litSlider = div.querySelector('.silderclass'); + litSlider!.percent = config.litSliderStyle.defaultValue; + let sliderBody = div.querySelector('.sliderBody'); + let bufferInput = div?.querySelector('.sliderInput') as HTMLInputElement; + litSlider!.addEventListener('input', (evt) => { + bufferInput.value = sliderBody!.getAttribute('percent') + config.litSliderStyle.resultUnit; + }); + litSlider!.sliderStyle = config.litSliderStyle; + break; + case 'Mmap-lit-slider': + let defaultValue = Math.pow(2, config.litSliderStyle.defaultValue); + let mapsilder = `
+ +
`; + div.innerHTML = div.innerHTML + mapsilder; + let maplitSlider = div.querySelector('.silderclass'); + maplitSlider!.percent = config.litSliderStyle.defaultValue; + let mapsliderBody = div.querySelector('.sliderBody'); + let mapbufferInput = div?.querySelector('.sliderInput') as HTMLInputElement; + maplitSlider!.addEventListener('input', (evt) => { + let percnet = mapsliderBody!.getAttribute('percent'); + if (percnet != null) { + mapbufferInput.value = Math.pow(2, Number(percnet)) + config.litSliderStyle.resultUnit; + } + }); + maplitSlider!.sliderStyle = config.litSliderStyle; + break; + case 'input': + let input = document.createElement('input'); + input.className = 'input config'; + input.textContent = config.value; + input.value = config.value; + input.title = config.title; + input.oninput = (ev) => { + input.value = input.value.replace(/\D/g, ''); + }; + div.appendChild(input); + break; + case 'select': + let html1 = ''; + html1 += ``; + config.selectArray.forEach((value: string) => { + html1 += `${value}`; + }); + html1 += ``; + div.innerHTML = div.innerHTML + html1; + break; + case 'switch': + let switch1 = document.createElement('lit-switch') as LitSwitch; + switch1.className = 'config'; + switch1.title = config.title; + if (config.value) { + switch1.checked = true; + } else { + switch1.checked = false; + } + if (config.title == 'Start Hiperf Sampling') { + switch1.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startSamp = true; + this.unDisable(); + this.dispatchEvent(new CustomEvent('addProbe', {})); + } else { + this.startSamp = false; + this.addOptionButton!.style.display = 'unset'; + this.disable(); + this.show = false; + } + }); + } + headDiv.appendChild(switch1); + break; + default: + break; + } + configList!.appendChild(div); + }); + let sp = document.querySelector('sp-application') as SpApplication; + let litSearch = sp?.shadowRoot?.querySelector('#lit-search') as LitSearch; + this.processSelect = this.shadowRoot?.querySelector("lit-select-v[title='Process']"); + this.processInput = this.processSelect?.shadowRoot?.querySelector('input'); + let querySelector = this.processSelect!.shadowRoot?.querySelector('input') as HTMLInputElement; + let processData: Array = []; + querySelector.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.processSelect!.dataSource([], 'ALL-Process'); + } + }); + querySelector!.addEventListener('mouseup', () => { + if (SpRecordTrace.serialNumber == '') { + this.processSelect?.dataSource([], 'ALL-Process'); + } else { + if (sp.search) { + sp.search = false; + litSearch.clear(); + } + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_PROCESS_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + processData = []; + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + if (processData.length > 0 && this.startSamp) { + this.processInput!.setAttribute('readonly', 'readonly'); + } + this.processSelect?.dataSource(processData, 'ALL-Process'); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_PROCESS, false).then((res) => { + processData = []; + if (res) { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + } + if (processData.length > 0 && this.startSamp) { + this.processInput!.setAttribute('readonly', 'readonly'); + } + this.processSelect?.dataSource(processData, 'ALL-Process'); + }); + } else { + sp.search = true; + litSearch.clear(); + litSearch.setPercent('please kill other hdc-server !', -2); + } + }); + } + } + }); + + this.cpuSelect = this.shadowRoot?.querySelector("lit-select-v[title='CPU']"); + let inputCpu = this.cpuSelect!.shadowRoot?.querySelector('input') as HTMLInputElement; + let cpuData: Array = []; + inputCpu.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.cpuSelect!.dataSource([], 'ALL-CPU'); + } + }); + inputCpu!.addEventListener('mouseup', () => { + if (SpRecordTrace.serialNumber == '') { + this.cpuSelect?.dataSource([], ''); + } else { + if (sp.search) { + sp.search = false; + litSearch.clear(); + } + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_CPU_COUNT_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + cpuData = []; + let cpuCount = res!.trim(); + let cpus = Number(cpuCount); + for (let index = 0; index < cpus; index++) { + cpuData.push(String(index)); + } + this.cpuSelect?.dataSource(cpuData, 'ALL-CPU'); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + cpuData = []; + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_CPU_COUNT, false).then((res) => { + let cpuCount = res!.trim(); + let cpus = Number(cpuCount); + for (let index = 0; index < cpus; index++) { + cpuData.push(String(index)); + } + this.cpuSelect?.dataSource(cpuData, 'ALL-CPU'); + }); + } else { + sp.search = true; + litSearch.clear(); + litSearch.setPercent('please kill other hdc-server !', -2); + } + }); + } + } + }); + this.eventSelect = this.shadowRoot?.querySelector("lit-select-v[title='Event List']"); + let inputEvent = this.eventSelect!.shadowRoot?.querySelector('input') as HTMLInputElement; + let eventData: Array = []; + inputEvent.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.eventSelect!.dataSource([], ''); + } + }); + inputEvent!.addEventListener('click', () => { + if (SpRecordTrace.serialNumber == '') { + this.eventSelect?.dataSource( + [ + 'hw-cpu-cycles', + 'hw-instructions', + 'hw-cache-references', + 'hw-cache-misses', + 'hw-branch-instructions', + 'hw-branch-misses', + 'hw-bus-cycles', + 'hw-stalled-cycles-backend', + 'hw-stalled-cycles-frontend', + 'sw-cpu-clock', + 'sw-task-clock', + 'sw-page-faults', + 'sw-context-switches', + 'sw-cpu-migrations', + 'sw-page-faults-min', + 'sw-page-faults-maj', + 'sw-alignment-faults', + 'sw-emulation-faults', + 'sw-dummy', + 'sw-bpf-output', + ], + '' + ); + } else { + if (sp.search) { + sp.search = false; + litSearch.clear(); + } + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_HIPERF_EVENTS_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + let eventMap = that.parseEvent(res); + let eventList = that.getSoftHardWareEvents(eventMap); + if (eventList) { + for (let eventListElement of eventList) { + eventData.push(eventListElement.trim()); + } + } + this.eventSelect!.dataSource(eventData, ''); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + eventData = []; + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_HIPERF_EVENTS, false).then((res) => { + if (res) { + let eventMap = that.parseEvent(res); + let eventList = that.getSoftHardWareEvents(eventMap); + if (eventList) { + for (let eventListElement of eventList) { + eventData.push(eventListElement.trim()); + } + } + this.eventSelect!.dataSource(eventData, ''); + } + }); + } else { + sp.search = true; + litSearch.clear(); + litSearch.setPercent('please kill other hdc-server !', -2); + } + }); + } + } + }); + + this.frequencySetInput = this.shadowRoot?.querySelector("input[title='Frequency']"); + this.offCPUSwitch = this.shadowRoot?.querySelector("lit-switch[title='Off CPU']"); + this.callSelect = this.shadowRoot?.querySelector("lit-select[title='Call Stack']"); + this.addOptionButton!.addEventListener('click', (event) => { + if (!this.startSamp) { + return; + } + this.addOptionButton!.style.display = 'none'; + this.show = true; + }); + this.disable(); + } + + getSoftHardWareEvents(eventListResult: Map) { + let shEvents = []; + let hardwareEvents = eventListResult.get('hardware'); + if (hardwareEvents) { + for (let hardwareEvent of hardwareEvents) { + shEvents.push(hardwareEvent); + } + } + let softwareEvents = eventListResult.get('software'); + if (softwareEvents) { + for (let softwareEvent of softwareEvents) { + shEvents.push(softwareEvent); + } + } + return shEvents; + } + + parseEvent(eventListResult: string): Map> { + let eventMap: Map> = new Map>(); + let events: Array = []; + let type: string = ''; + let lineValues: string[] = eventListResult.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let line of lineValues) { + if (line.startsWith('Supported')) { + let startSign: string = 'for'; + type = line.substring(line.indexOf(startSign) + startSign.length, line.lastIndexOf(':')).trim(); + events = new Array(); + eventMap.set(type, events); + } else if (line.indexOf('not support') != -1 || line.trim().length == 0 || line.indexOf('Text file busy') != -1) { + // do not need deal with it + } else { + let event: string = line.split(' ')[0]; + let ventMap = eventMap.get(type); + if (ventMap != null) { + ventMap.push(event); + } + } + } + return eventMap; + } + + private unDisable() { + if (this.processSelect) { + this.processSelect.removeAttribute('disabled'); + } + if (this.frequencySetInput) { + this.frequencySetInput!.disabled = false; + } + if (this.offCPUSwitch) { + this.offCPUSwitch!.disabled = false; + } + if (this.callSelect) { + this.callSelect!.removeAttribute('disabled'); + } + if (this.addOptionButton) { + this.addOptionButton.disabled = false; + } + } + + private disable() { + if (this.processSelect) { + this.processSelect.setAttribute('disabled', ''); + } + if (this.frequencySetInput) { + this.frequencySetInput!.disabled = true; + } + if (this.offCPUSwitch) { + this.offCPUSwitch!.disabled = true; + } + if (this.callSelect) { + this.callSelect!.setAttribute('disabled', ''); + } + if (this.addOptionButton) { + this.addOptionButton.disabled = true; + } + } + + initConfigList(): void { + this.configList = [ + { + title: 'Start Hiperf Sampling', + des: '', + hidden: false, + type: 'switch', + value: false, + }, + { + title: 'Process', + des: 'Record process', + hidden: false, + type: 'select-multiple', + selectArray: [''], + }, + { + title: 'CPU', + des: 'Record assign cpu num such as 0,1,2', + hidden: true, + type: 'select-multiple', + selectArray: [''], + }, + { + title: 'Event List', + des: 'Event type Default is cpu cycles', + hidden: true, + type: 'select-multiple', + selectArray: [''], + }, + { + title: 'CPU Percent', + des: 'Set the max percent of cpu time used for recording', + hidden: true, + type: 'lit-slider', + litSliderStyle: { + minRange: 0, + maxRange: 100, + defaultValue: '100', + resultUnit: '%', + stepSize: 1, + lineColor: 'var(--dark-color3,#a88888)', + buttonColor: '#a88888', + }, + }, + { + title: 'Frequency', + des: 'Set event sampling frequency', + hidden: false, + type: 'input', + value: '1000', + }, + { + title: 'Period', + des: 'Set event sampling period for trace point events2', + hidden: true, + type: 'input', + value: '1', + }, + { + title: 'Off CPU', + des: 'Trace when threads are scheduled off cpu', + hidden: false, + type: 'switch', + value: true, + }, + { + title: 'No Inherit', + des: "Don't trace child processes", + hidden: true, + type: 'switch', + value: false, + }, + { + title: 'Call Stack', + des: 'Setup and enable call stack recording', + hidden: false, + type: 'select', + selectArray: ['dwarf', 'fp', 'none'], + }, + { + title: 'Branch', + des: 'Taken branch stack sampling', + hidden: true, + type: 'select', + selectArray: ['none', 'any', 'any_call', 'any_ret', 'ind_call', 'call', 'user', 'kernel'], + }, + { + title: 'Mmap Pages', + des: 'Used to receiving record data from kernel', + hidden: true, + type: 'Mmap-lit-slider', + litSliderStyle: { + minRange: 1, + maxRange: 10, + defaultValue: '8', + resultUnit: 'MB', + stepSize: 1, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }, + }, + { + title: 'Clock Type', + des: 'Set the clock id to use for the various time fields in the perf_event_type records', + hidden: true, + type: 'select', + selectArray: ['monotonic', 'realtime', 'monotonic_raw', 'boottime', 'perf'], + }, + ]; + } + + initHtml(): string { + return ` + +
+
+
+ +
+ `; + } +} + +export interface PerfConfig { + process: string; + cpu: string; + eventList: string; + cpuPercent: number; + frequency: number; + period: number; + isOffCpu: boolean; + noInherit: boolean; + callStack: string; + branch: string; + mmap: number; + clockType: string; +} diff --git a/ide/src/trace/component/setting/SpRecordSetting.ts b/ide/src/trace/component/setting/SpRecordSetting.ts new file mode 100644 index 0000000000000000000000000000000000000000..0389ba7d44c065ea415140573ae3bdf916a2efd9 --- /dev/null +++ b/ide/src/trace/component/setting/SpRecordSetting.ts @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import '../../../base-ui/radiobox/LitRadioBox.js'; +import { LitRadioBox } from '../../../base-ui/radiobox/LitRadioBox.js'; +import '../../../base-ui/slider/LitSlider.js'; +import { LitSlider } from '../../../base-ui/slider/LitSlider.js'; +import '../../../base-ui/popover/LitPopover.js'; +import { info } from '../../../log/Log.js'; + +@element('record-setting') +export class SpRecordSetting extends BaseElement { + private memoryBufferSlider: LitSlider | undefined; + private maxDurationSliders: LitSlider | undefined; + private radioBox: LitRadioBox | undefined; + private bufferNumber: HTMLElement | undefined; + private durationNumber: HTMLElement | undefined; + private outputPath: HTMLInputElement | undefined; + private lastMemoryValue: string | undefined; + private lastDurationValue: string | undefined; + + get recordMod(): boolean { + if (this.radioBox) { + return this.radioBox.checked; + } + return false; + } + + get output(): string { + if (this.outputPath && this.outputPath.value != '') { + return '/data/local/tmp/' + this.outputPath.value; + } + return '/data/local/tmp/hiprofiler_data.htrace'; + } + + get bufferSize(): number { + if (this.bufferNumber?.hasAttribute('percent')) { + info('bufferSize is : ', this.bufferNumber!.getAttribute('percent')); + return Number(this.bufferNumber!.getAttribute('percent')); + } + return 64; + } + + get maxDur(): number { + if (this.durationNumber?.hasAttribute('percent')) { + info('maxDur is : ', this.durationNumber!.getAttribute('percent')); + return Number(this.durationNumber!.getAttribute('percent')); + } + return 30; + } + + resetValue(): void { + let bufferInput = this.shadowRoot?.querySelector('.memory_buffer_result') as HTMLInputElement; + let parentElement = this.memoryBufferSlider!.parentNode as Element; + if (bufferInput.style.color != 'var(--dark-color1,#000000)' && this.lastMemoryValue) { + bufferInput.value = this.lastMemoryValue + ''; + this.memoryBufferSlider!.percent = this.lastMemoryValue + ''; + this.memoryBufferSlider!.sliderStyle = { + minRange: 4, + maxRange: 512, + defaultValue: this.lastMemoryValue + '', + resultUnit: 'MB', + stepSize: 2, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + parentElement.setAttribute('percent', this.lastMemoryValue + ''); + this.lastMemoryValue = this.lastMemoryValue + ''; + bufferInput.style.color = 'var(--dark-color1,#000000)'; + } + + let durationInput = this.shadowRoot?.querySelector('.max_duration_result') as HTMLInputElement; + let durationEl = this.maxDurationSliders!.parentNode as Element; + if (durationInput.style.color != 'var(--dark-color1,#000000)' && this.lastDurationValue) { + durationInput.style.color = 'var(--dark-color1,#000000)'; + let durationList = this.lastDurationValue.split(':'); + let resultDuration = Number(durationList[0]) * 3600 + Number(durationList[1]) * 60 + Number(durationList[2]); + + durationInput.value = this.lastDurationValue; + this.maxDurationSliders!.sliderStyle = { + minRange: 10, + maxRange: 3600, + defaultValue: this.lastDurationValue!, + resultUnit: 'h:m:s', + stepSize: 1, + lineColor: 'var(--dark-color4,#61CFBE)', + buttonColor: '#999999', + }; + durationEl.setAttribute('percent', resultDuration.toString()); + } + } + + initElements(): void { + this.bufferNumber = this.shadowRoot?.querySelector('.buffer-size') as HTMLElement; + this.durationNumber = this.shadowRoot?.querySelector('.max-duration') as HTMLElement; + let bu = this.shadowRoot?.querySelector('.record') as HTMLDivElement; + this.shadowRoot?.querySelectorAll('.MenuButton').forEach((button) => { + button!.addEventListener('mouseenter', (e) => { + button.style.backgroundColor = '#EFEFEF'; + }); + + button!.addEventListener('mouseout', (e) => { + button.style.backgroundColor = '#E4E3E9'; + }); + }); + + this.radioBox = this.shadowRoot?.querySelector('#litradio') as LitRadioBox; + this.outputPath = this.shadowRoot?.querySelector('#trace_path') as HTMLInputElement; + + this.initLitSlider(); + } + + initLitSlider() { + this.memoryBufferSlider = this.shadowRoot?.querySelector('#memory-buffer') as LitSlider; + this.memoryBufferSlider.sliderStyle = { + minRange: 4, + maxRange: 512, + defaultValue: '64', + resultUnit: 'MB', + stepSize: 2, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + this.lastMemoryValue = '64'; + let parentElement = this.memoryBufferSlider!.parentNode as Element; + let bufferInput = this.shadowRoot?.querySelector('.memory_buffer_result') as HTMLInputElement; + bufferInput.value = this.memoryBufferSlider.sliderStyle.defaultValue; + this.memoryBufferSlider.addEventListener('input', (evt) => { + bufferInput.value = this.bufferSize.toString(); + }); + parentElement.setAttribute('percent', '64'); + bufferInput.style.color = 'var(--dark-color1,#000000)'; + bufferInput.addEventListener('input', (ev) => { + if (this.bufferNumber!.hasAttribute('percent')) { + this.bufferNumber!.removeAttribute('percent'); + } + bufferInput.style.color = 'var(--dark-color1,#000000)'; + bufferInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + bufferInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + if (bufferInput.value.trim() == '') { + bufferInput.style.color = 'red'; + parentElement.setAttribute('percent', '64'); + return; + } + let memorySize = Number(bufferInput.value); + if ( + !memorySize || + memorySize < this.memoryBufferSlider!.sliderStyle.minRange || + memorySize > this.memoryBufferSlider!.sliderStyle.maxRange + ) { + bufferInput.style.color = 'red'; + parentElement.setAttribute('percent', '64'); + } else { + this.memoryBufferSlider!.percent = bufferInput.value; + let htmlInputElement = this.memoryBufferSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; + htmlInputElement.value = bufferInput.value; + this.memoryBufferSlider!.sliderStyle = { + minRange: 4, + maxRange: 512, + defaultValue: bufferInput.value, + resultUnit: 'MB', + stepSize: 2, + lineColor: 'var(--dark-color3,#46B1E3)', + buttonColor: '#999999', + }; + parentElement.setAttribute('percent', bufferInput.value); + this.lastMemoryValue = bufferInput.value; + } + }); + + let memoryBufferInput = this.memoryBufferSlider!.shadowRoot?.querySelector('#slider') as HTMLInputElement; + + memoryBufferInput.addEventListener('input', (ev) => { + bufferInput.style.color = 'var(--dark-color1,#000000)'; + bufferInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + bufferInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + }); + + this.maxDurationSliders = this.shadowRoot?.querySelector('#max-duration') as LitSlider; + this.maxDurationSliders.sliderStyle = { + minRange: 10, + maxRange: 3600, + defaultValue: '00:00:30', + resultUnit: 'h:m:s', + stepSize: 1, + lineColor: 'var(--dark-color4,#61CFBE)', + buttonColor: '#999999', + }; + this.lastDurationValue = '00:00:30'; + let durationParentElement = this.maxDurationSliders!.parentNode as Element; + let durationInput = this.shadowRoot?.querySelector('.max_duration_result') as HTMLInputElement; + durationInput.value = this.maxDurationSliders.sliderStyle.defaultValue; + this.maxDurationSliders.addEventListener('input', (evt) => { + durationInput.value = this.maxDurationSliders!.formatSeconds(this.maxDur.toString()); + }); + + durationInput.style.color = 'var(--dark-color1,#000000)'; + durationInput.addEventListener('input', (ev) => { + if (this.durationNumber!.hasAttribute('percent')) { + this.durationNumber!.removeAttribute('percent'); + } + durationInput.style.color = 'var(--dark-color1,#000000)'; + durationInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + durationInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + let regExpMatchArray = durationInput.value.trim(); + if (regExpMatchArray == '') { + durationInput.style.color = 'red'; + durationParentElement.setAttribute('percent', '30'); + return; + } + let regExpMatch = durationInput.value.trim().match(`^\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}$`); + if (regExpMatch) { + let durationList = regExpMatchArray.split(':'); + let resultDuration = Number(durationList[0]) * 3600 + Number(durationList[1]) * 60 + Number(durationList[2]); + if ( + Number(durationList[0]) > 60 || + Number(durationList[1]) > 60 || + Number(durationList[2]) > 60 || + resultDuration > this.maxDurationSliders!.sliderStyle.maxRange || + resultDuration < this.maxDurationSliders!.sliderStyle.minRange + ) { + durationInput.style.color = 'red'; + durationParentElement.setAttribute('percent', '30'); + } else { + durationInput.style.color = 'var(--dark-color1,#000000)'; + durationInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + durationInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + let htmlInputElement = this.maxDurationSliders!.shadowRoot?.querySelector('#slider') as HTMLInputElement; + htmlInputElement.value = resultDuration + ''; + this.maxDurationSliders!.sliderStyle = { + minRange: 10, + maxRange: 3600, + defaultValue: Number(durationList[0]) + ':' + Number(durationList[1]) + ':' + Number(durationList[2]), + resultUnit: 'h:m:s', + stepSize: 1, + lineColor: 'var(--dark-color4,#61CFBE)', + buttonColor: '#999999', + }; + durationParentElement.setAttribute('percent', resultDuration.toString()); + this.lastDurationValue = regExpMatchArray; + } + } else { + durationInput.style.color = 'red'; + durationParentElement.setAttribute('percent', '30'); + } + }); + + let maxDurationInput = this.maxDurationSliders!.shadowRoot?.querySelector('#slider') as HTMLInputElement; + maxDurationInput.addEventListener('input', (ev) => { + durationInput.style.color = 'var(--dark-color1,#000000)'; + durationInput.parentElement!.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + durationInput.style.backgroundColor = 'var(--dark-background5,#F2F2F2)'; + }); + } + + initHtml(): string { + return ` + +
+
+ Record mode + Stop when full +
+
+ output file path +
+ /data/local/tmp/ + +
+
+
+
+ In-memory buffer size + (max memory buffer size is 512 MB) +
+ + +
+ + MB +
+
+
+
+ Max duration + (max duration value is 01:00:00) +
+ + +
+ + h:m:s +
+ +
+
+ `; + } +} diff --git a/ide/src/trace/component/setting/SpRecordTemplate.ts b/ide/src/trace/component/setting/SpRecordTemplate.ts new file mode 100644 index 0000000000000000000000000000000000000000..f46324ce40af75e207d7ba0a47c9321fb01c56f2 --- /dev/null +++ b/ide/src/trace/component/setting/SpRecordTemplate.ts @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import { ProfilerPluginConfig, TracePluginConfig } from './bean/ProfilerServiceTypes.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; + +@element('sp-record-template') +export class SpRecordTemplate extends BaseElement { + static SCHEDULING_ANALYSIS_EVENT = [ + 'sched/sched_wakeup', + 'sched/sched_switch', + 'sched/sched_wakeup_new', + 'sched/sched_waking', + 'sched/sched_process_exit', + 'sched/sched_process_free', + 'task/task_newtask', + 'task/task_rename', + 'power/cpu_frequency', + 'power/cpu_idle', + 'irq/irq_handler_entry', + 'irq/irq_handler_exit', + 'irq/softirq_entry', + 'irq/softirq_exit', + 'irq/softirq_raise', + ]; + static FRAME_TIMELINE_EVENTS = [ + 'sched/sched_switch', + 'sched/sched_wakeup', + 'sched/sched_wakeup_new', + 'sched/sched_waking', + 'sched/sched_process_exit', + 'sched/sched_process_free', + 'sched/sched_process_free', + 'task/task_rename', + 'power/cpu_frequency', + 'power/cpu_idle', + 'power/suspend_resume', + ]; + static FRAME_TIMELINE_CATEGORIES_EVENT = [ + 'ability', + 'ace', + 'app', + 'ark', + 'binder', + 'disk', + 'freq', + 'graphic', + 'idle', + 'irq', + 'memreclaim', + 'mmc', + 'multimodalinput', + 'ohos', + 'pagecache', + 'rpc', + 'sched', + 'sync', + 'window', + 'workq', + 'zaudio', + 'zcamera', + 'zimage', + 'zmedia', + ]; + private frameTimeline: LitSwitch | undefined | null; + private schedulingAnalysis: LitSwitch | undefined | null; + + initElements(): void { + this.frameTimeline = this.shadowRoot?.querySelector('#frame_timeline'); + this.schedulingAnalysis = this.shadowRoot?.querySelector('#scheduling_analysis'); + this.frameTimeline!.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.dispatchEvent(new CustomEvent('addProbe', {})); + } + }); + this.schedulingAnalysis!.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.dispatchEvent(new CustomEvent('addProbe', {})); + } + }); + } + + getTemplateConfig(): Array> { + let config: Array = []; + let traceEventSet = new Array(); + let hitraceCategories = new Array(); + let useFtracePlugin: boolean = false; + if (this.frameTimeline?.checked) { + useFtracePlugin = true; + SpRecordTemplate.FRAME_TIMELINE_CATEGORIES_EVENT.forEach((categories) => { + if (hitraceCategories.indexOf(categories) == -1) { + hitraceCategories.push(categories); + } + }); + SpRecordTemplate.FRAME_TIMELINE_EVENTS.forEach((ev) => { + if (traceEventSet.indexOf(ev) == -1) { + traceEventSet.push(ev); + } + }); + } + if (this.schedulingAnalysis?.checked) { + useFtracePlugin = true; + SpRecordTemplate.SCHEDULING_ANALYSIS_EVENT.forEach((event) => { + if (traceEventSet.indexOf(event) < 0) { + traceEventSet.push(event); + } + }); + } + if (useFtracePlugin) { + let tracePluginConfig: TracePluginConfig = { + ftraceEvents: traceEventSet, + hitraceCategories: hitraceCategories, + hitraceApps: [], + bufferSizeKb: 2048, + flushIntervalMs: 1000, + flushThresholdKb: 4096, + parseKsyms: true, + clock: 'boot', + tracePeriodMs: 200, + rawDataPrefix: '', + traceDurationMs: 0, + debugOn: false, + hitraceTime: this.args.recordSetting!.maxDur, + }; + let htraceProfilerPluginConfig: ProfilerPluginConfig = { + pluginName: 'ftrace-plugin', + sampleInterval: 1000, + configData: tracePluginConfig, + }; + SpRecordTrace.appendSerialize(htraceProfilerPluginConfig); + config.push(htraceProfilerPluginConfig); + } + return config; + } + + initHtml(): string { + return ` + +
+
+
+ Frame timeline + +
+
+
+
+ Scheduling analysis + +
+
+
+ `; + } +} diff --git a/ide/src/trace/component/setting/SpSdkConfig.ts b/ide/src/trace/component/setting/SpSdkConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7de3d9eae1c7bc20f7179a024d0095b912aab7f --- /dev/null +++ b/ide/src/trace/component/setting/SpSdkConfig.ts @@ -0,0 +1,482 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import '../../../base-ui/select/LitSelectV.js'; +import '../../../base-ui/select/LitSelect.js'; + +import '../../../base-ui/switch/lit-switch.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import { LitSelectV } from '../../../base-ui/select/LitSelectV.js'; +import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; + +@element('sp-sdk-config') +export class SpSdkConfig extends BaseElement { + private worker: Worker | undefined; + private configList: any; + private customConfig: HTMLDivElement | undefined | null; + private selectConfig: LitAllocationSelect | undefined | null; + private list: Array | undefined; + private pluginName: string = ''; + private sampleInterval: number = 5000; + + static get observedAttributes() { + return ['configName', 'value', 'type']; + } + + get show(): boolean { + return this.hasAttribute('show'); + } + + set show(show: boolean) { + if (show) { + this.setAttribute('show', ''); + } else { + this.removeAttribute('show'); + } + } + + set startSamp(start: boolean) { + if (start) { + this.setAttribute('startSamp', ''); + } else { + this.removeAttribute('startSamp'); + } + } + + get startSamp(): boolean { + return this.hasAttribute('startSamp'); + } + + set configName(configName: string) { + if (configName != '') { + this.setAttribute('configName', configName); + } else { + this.removeAttribute('configName'); + } + } + + get configName(): string { + return this.getAttribute('configName') || ''; + } + + get type(): string { + return this.getAttribute('type') || ''; + } + + set type(type: string) { + if (type != '') { + this.setAttribute('type', type); + } else { + this.removeAttribute('type'); + } + } + + private wasmMap: Map = new Map(); + private wasmList: Array = []; + + private changGpu(gpuName: string) { + let config = this.wasmMap.get(gpuName); + this.pluginName = config?.pluginName; + this.sampleInterval = config?.sampleInterval; + let pam = { + action: 'open', + componentId: config.componentId, + wasmJsName: config.wasmJsName, + WasmName: config.wasmName, + }; + this.worker!.postMessage(pam); + this.worker!.onmessage = (event: MessageEvent) => { + let results = event.data.results; + this.configList = results.settingConfig; + this.initConfig(); + }; + } + + getPlugName(): string { + return this.pluginName; + } + + getSampleInterval(): number { + return this.sampleInterval; + } + + getGpuConfig(): any { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + let gpuConfig: any = {}; + for (let i = 0; i < configVal!.length; i++) { + let configName = configVal![i].getAttribute('configName'); + let type = configVal![i].getAttribute('type'); + if (type == 'enum') { + let enumValue = configVal![i].getAttribute('value'); + if (enumValue != undefined && enumValue != 'undefined') { + gpuConfig[configName!] = enumValue; + } + } else if (type == 'number' || type == 'integer' || type == 'num') { + // @ts-ignore + gpuConfig[configName!] = Number(configVal![i].value); + } else if (type == 'boolean') { + let attribute = configVal![i].getAttribute('value'); + gpuConfig[configName!] = attribute == 'true'; + } else { + // @ts-ignore + gpuConfig[configName!] = configVal![i].value; + } + } + return gpuConfig; + } + + initElements(): void { + try { + let spApplication = document.querySelector('sp-application'); + let wasmJsonUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`; + if (spApplication!.hasAttribute('vs')) { + wasmJsonUrl = `http://${window.location.host.split(':')[0]}:${window.location.port}/wasm.json`; + } + fetch(wasmJsonUrl) + .then((res) => { + if (res.ok) { + res.text().then((text) => { + this.wasmMap = new Map(); + this.wasmList = []; + let wasmJson = JSON.parse(text); + let wasmFiles = wasmJson.WasmFiles; + wasmFiles.forEach((wasmFile: any) => { + this.wasmMap.set(wasmFile.disPlayName, wasmFile); + this.wasmList.push(wasmFile.disPlayName); + }); + }); + } + }) + .catch((err) => {}); + if (this.worker == null) { + this.worker = new Worker('trace/database/ConfigWorker.js'); + } + } catch (e) {} + this.customConfig = this.shadowRoot?.querySelector('.configList'); + let switchButton = this.shadowRoot?.querySelector('.config_switch') as LitSwitch; + switchButton.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startSamp = true; + this.isAbleShowConfig(false); + } else { + this.startSamp = false; + this.isAbleShowConfig(true); + } + }); + this.selectConfig = this.shadowRoot?.querySelector('lit-allocation-select'); + let inputDiv = this.selectConfig?.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; + let input = this.selectConfig?.shadowRoot?.querySelector('#singleInput'); + if (input) { + inputDiv.addEventListener('inputClick', () => { + this.selectConfig!.processData = this.wasmList; + this.selectConfig!.initData(); + }); + inputDiv.addEventListener('valuable', (ev) => { + this.changGpu(input!.value); + }); + } + this.list = []; + this.list.push(this.selectConfig!); + this.isAbleShowConfig(true); + } + + initConfig() { + this.customConfig!.innerHTML = ''; + this.list = []; + this.list.push(this.selectConfig!); + let switch1 = document.createElement('lit-switch') as LitSwitch; + for (let key in this.configList.configuration) { + let html = ''; + let div = document.createElement('div'); + div.className = 'config-div'; + let headDiv = document.createElement('div'); + div.appendChild(headDiv); + let title = document.createElement('span'); + title.className = 'title'; + title.textContent = key; + headDiv.appendChild(title); + let des = document.createElement('span'); + des.textContent = this.configList.configuration[key].description; + des.className = 'des'; + headDiv.appendChild(des); + switch (this.configList.configuration[key].type) { + case 'string': + if (this.configList.configuration[key].enum) { + let placeholder = ''; + if (this.configList.configuration[key].default) { + placeholder = this.configList.configuration[key].default; + } + html += ``; + div.innerHTML = div.innerHTML + html; + } else { + let inputElement = document.createElement('input'); + inputElement.className = 'input config'; + if (this.configList.configuration[key].default) { + inputElement.value = this.configList.configuration[key].default; + } + inputElement.setAttribute('configName', key); + inputElement.setAttribute('type', this.configList.configuration[key].type); + div.appendChild(inputElement); + this.list.push(inputElement); + } + break; + case 'number': + let numberInput = document.createElement('input'); + numberInput.className = 'input config'; + if (this.configList.configuration[key].default) { + numberInput.value = this.configList.configuration[key].default; + } + numberInput.setAttribute('configName', key); + numberInput.setAttribute('type', 'num'); + numberInput.oninput = (ev) => { + let inputValue = this.checkFloatInput(numberInput.value); + numberInput.value = inputValue; + }; + div.appendChild(numberInput); + this.list.push(numberInput); + break; + case 'integer': + let input = document.createElement('input'); + input.className = 'input config'; + if (this.configList.configuration[key].default) { + input.value = this.configList.configuration[key].default; + } + input.setAttribute('configName', key); + input.setAttribute('type', this.configList.configuration[key].type); + input.oninput = (ev) => { + let inputValue = this.checkIntegerInput(input.value); + input.value = inputValue; + title.setAttribute('value', input.value); + }; + div.appendChild(input); + this.list.push(input); + break; + case 'boolean': + switch1.className = 'switch1 config'; + switch1.setAttribute('configName', key); + switch1.setAttribute('type', this.configList.configuration[key].type); + if (this.configList.configuration[key].default == 'true') { + switch1.setAttribute('checked', ''); + switch1.setAttribute('value', 'true'); + } else { + switch1.removeAttribute('checked'); + switch1.setAttribute('value', 'false'); + } + headDiv.appendChild(switch1); + this.list.push(switch1); + break; + } + this.customConfig!.appendChild(div); + if (this.configList.configuration[key].enum) { + let select = this.shadowRoot!.querySelector(`#${key}`); + select!.setAttribute('type', 'enum'); + select!.setAttribute('value', this.configList.configuration[key].default); + select!.dataSource(this.configList.configuration[key].enum, ''); + this.list.push(select!); + select!.addEventListener('click', (event: any) => { + select!.setAttribute('value', select!.value); + }); + } + } + switch1.addEventListener('change', (event: any) => { + if (switch1.hasAttribute('checked')) { + switch1.setAttribute('value', 'true'); + } else { + switch1.setAttribute('value', 'false'); + } + }); + } + + checkIntegerInput(value: string): string { + let inputValue = value + .replace(/[^\-\d]|\-{2,}/g, '') + .replace(/(\d)\-|-(0+)|^0+(\d)/g, '$1') + .replace(/(-?\d{15})\d*/, '$1'); + return inputValue; + } + + checkFloatInput(value: string): string { + let inputValue = value + .replace(/[^\d.]/g, '') + .replace(/^\.|^0+(\d)/g, '') + .replace(/(\.\d+)\.|(-)\.|(\d+|\.)-/g, '$1') + .replace(/(-?\d{9})\d*/, '$1'); + return inputValue.replace(/\.{2,}|-(0){2,}|(-)0+(\d+)/g, '.'); + } + + isAbleShowConfig(isAbleShow: boolean) { + if (this.list!) { + if (isAbleShow) { + this.list!.forEach((item) => { + item.setAttribute('disabled', ''); + }); + } else { + this.list!.forEach((item) => { + item.removeAttribute('disabled'); + }); + } + } + } + + initConfigList(): void { + this.configList = { + name: '', + configuration: { + ss: { + type: 'string', + default: 'strsadsa', + description: 'xxxx', + }, + aa: { + type: 'string', + default: '11', + enum: ['consistent', '11', 'delegated'], + }, + cc: { + type: 'number', + description: 'number1111', + }, + ee: { + type: 'integer', + default: '12', + description: 'integer1222', + }, + ff: { + type: 'boolean', + description: 'switchhh', + }, + }, + }; + } + + initHtml(): string { + return ` + +
+
+
+ Start Custom Config + +
+
+
+ +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/setting/SpTraceCommand.ts b/ide/src/trace/component/setting/SpTraceCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..e461f92d05a903ed294e313672b72bc6ecf91770 --- /dev/null +++ b/ide/src/trace/component/setting/SpTraceCommand.ts @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { info } from '../../../log/Log.js'; +import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil.js'; +import { PluginConvertUtils } from './utils/PluginConvertUtils.js'; + +@element('trace-command') +export class SpTraceCommand extends BaseElement { + private codeHl: HTMLTextAreaElement | undefined | null; + private copyEl: HTMLElement | undefined | null; + private codeCopyText: HTMLInputElement | undefined; + + set show(show: boolean) { + if (show) { + this.setAttribute('show', ''); + } else { + this.removeAttribute('show'); + } + } + + get show() { + return this.hasAttribute('show'); + } + + get hdcCommon(): string { + return this.codeHl!.textContent + ''; + } + + set hdcCommon(value: string) { + info('hdc Common is:', value); + this.codeHl!.textContent = value; + } + + //当 custom element首次被插入文档DOM时,被调用。 + public connectedCallback() { + this.codeHl!.textContent = ''; + this.copyEl?.addEventListener('click', this.codeCopyEvent); + this.codeHl?.addEventListener('selectionchange', this.textSelectEvent); + } + + public disconnectedCallback() { + this.copyEl?.removeEventListener('click', this.codeCopyEvent); + } + + codeCopyEvent = (event: any) => { + this.codeHl?.select(); + document.execCommand('copy'); + let allPlugin: Array = []; + PluginConvertUtils.pluginConfig.forEach((plugin) => { + allPlugin.push(plugin.pluginName); + }); + SpStatisticsHttpUtil.addOrdinaryVisitAction({ + action: 'config_page', + event: 'offline_record', + eventData: { + plugin: allPlugin, + }, + }); + }; + + textSelectEvent = (event: any) => { + this.copyEl!.style.backgroundColor = '#FFFFFF'; + }; + + initElements(): void { + this.codeHl = this.shadowRoot?.querySelector('#code-text') as HTMLTextAreaElement; + this.copyEl = this.shadowRoot?.querySelector('#copy-image') as HTMLElement; + } + + initHtml(): string { + return ` + +
+ + + +
+ `; + } +} diff --git a/ide/src/trace/component/setting/SpVmTracker.ts b/ide/src/trace/component/setting/SpVmTracker.ts new file mode 100644 index 0000000000000000000000000000000000000000..7771019cd58193b00bce9beeb59f6d52242c46be --- /dev/null +++ b/ide/src/trace/component/setting/SpVmTracker.ts @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import LitSwitch from '../../../base-ui/switch/lit-switch.js'; +import '../../../base-ui/select/LitAllocationSelect.js'; + +import '../../../base-ui/switch/lit-switch.js'; +import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect.js'; +import { SpRecordTrace } from '../SpRecordTrace.js'; +import { Cmd } from '../../../command/Cmd.js'; +import { CmdConstant } from '../../../command/CmdConstant.js'; +import { HdcDeviceManager } from '../../../hdc/HdcDeviceManager.js'; + +@element('sp-vm-tracker') +export class SpVmTracker extends BaseElement { + private processInput: LitAllocationSelect | undefined | null; + private selectProcess: HTMLInputElement | undefined | null; + private configList: Array = []; + + set startSamp(start: boolean) { + if (start) { + this.setAttribute('startSamp', ''); + } else { + this.removeAttribute('startSamp'); + let input = this.processInput?.shadowRoot?.querySelector('#singleInput'); + input!.value = ''; + } + } + + get process(): string { + if (this.processInput!.value.length > 0) { + let result = this.processInput!.value.match(/\((.+?)\)/g); + if (result) { + return result.toString().replace('(', '').replace(')', ''); + } else { + return this.processInput!.value; + } + } + return ''; + } + + get startSamp(): boolean { + return this.hasAttribute('startSamp'); + } + + initElements(): void { + this.initConfigList(); + let configList = this.shadowRoot?.querySelector('.configList'); + this.configList.forEach((config) => { + let div = document.createElement('div'); + if (config.hidden) { + div.className = 'config-div hidden'; + } else { + div.className = 'config-div'; + } + let headDiv = document.createElement('div'); + div.appendChild(headDiv); + let title = document.createElement('span'); + title.className = 'title'; + title.textContent = config.title; + headDiv.appendChild(title); + let des = document.createElement('span'); + des.textContent = config.des; + des.className = 'des'; + headDiv.appendChild(des); + switch (config.type) { + case 'select': + let html1 = ''; + html1 += ``; + html1 += ``; + div.innerHTML = div.innerHTML + html1; + break; + case 'switch': + let switch1 = document.createElement('lit-switch') as LitSwitch; + switch1.className = 'config'; + switch1.title = config.title; + if (config.value) { + switch1.checked = true; + } else { + switch1.checked = false; + } + if (config.title == 'Start VM Tracker Record') { + switch1.addEventListener('change', (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startSamp = true; + this.unDisable(); + } else { + this.startSamp = false; + this.disable(); + } + }); + } + headDiv.appendChild(switch1); + break; + default: + break; + } + configList!.appendChild(div); + }); + this.processInput = this.shadowRoot?.querySelector("lit-allocation-select[title='Process']"); + let inputDiv = this.processInput?.shadowRoot?.querySelector('.multipleSelect') as HTMLDivElement; + this.selectProcess = this.processInput!.shadowRoot?.querySelector('input') as HTMLInputElement; + let processData: Array = []; + inputDiv!.addEventListener('mousedown', (ev) => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.processData = []; + this.processInput!.initData(); + } + }); + inputDiv!.addEventListener('mouseup', () => { + if (SpRecordTrace.serialNumber == '') { + this.processInput!.processData = []; + this.processInput!.initData(); + } else { + if (SpRecordTrace.isVscode) { + let cmd = Cmd.formatString(CmdConstant.CMD_GET_PROCESS_DEVICES, [SpRecordTrace.serialNumber]); + Cmd.execHdcCmd(cmd, (res: string) => { + processData = []; + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + this.processInput!.processData = processData; + this.processInput!.initData(); + }); + } else { + HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((conn) => { + if (conn) { + HdcDeviceManager.shellResultAsString(CmdConstant.CMD_GET_PROCESS, false).then((res) => { + processData = []; + if (res) { + let lineValues: string[] = res.replace(/\r\n/g, '\r').replace(/\n/g, '\r').split(/\r/); + for (let lineVal of lineValues) { + if (lineVal.indexOf('__progname') != -1 || lineVal.indexOf('PID CMD') != -1) { + continue; + } + let process: string[] = lineVal.trim().split(' '); + if (process.length == 2) { + let processId = process[0]; + let processName = process[1]; + processData.push(processName + '(' + processId + ')'); + } + } + } + this.processInput!.processData = processData; + this.processInput!.initData(); + }); + } + }); + } + } + }); + this.disable(); + } + + private unDisable() { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + configVal!.forEach((configVal1) => { + configVal1.removeAttribute('disabled'); + }); + } + + private disable() { + let configVal = this.shadowRoot?.querySelectorAll('.config'); + configVal!.forEach((configVal1) => { + if (configVal1.title != 'Start VM Tracker Record') { + configVal1.setAttribute('disabled', ''); + } + }); + } + + initConfigList(): void { + this.configList = [ + { + title: 'Start VM Tracker Record', + des: '', + hidden: false, + type: 'switch', + value: false, + }, + { + title: 'Process', + des: 'Record process', + hidden: false, + type: 'select', + selectArray: [''], + }, + ]; + } + + initHtml(): string { + return ` + +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts b/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b65c6c75fdf915df3ac90785ba0e459a4ef8ce1 --- /dev/null +++ b/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts @@ -0,0 +1,914 @@ +/* + * Copyright (C) 2022 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. + */ + +export interface ProfilerSessionConfigBufferConfig { + pages: number; + policy: ProfilerSessionConfigBufferConfigPolicy; +} + +export enum ProfilerSessionConfigBufferConfigPolicy { + RECYCLE = 0, + FLATTEN = 1, + UNRECOGNIZED = 2, +} + +export interface ProfilerSessionConfig { + buffers: ProfilerSessionConfigBufferConfig[]; + sessionMode: ProfilerSessionConfigMode; + /** for OFFLINE mode, result file path */ + resultFile: string; + /** for OFFLINE mode, result file max size in KB */ + resultMaxSize: number; + /** for OFFLINE mode, sample duration in ms */ + sampleDuration: number; + /** if set to non-zero value, session will auto-destroyed after CreateSession in ms */ + keepAliveTime: number; +} + +export enum ProfilerSessionConfigMode { + /** OFFLINE - save all plugin results to result file. */ + OFFLINE = 0, + /** ONLINE - push all plugin results to host PC with streamed FetchDataResponse. */ + ONLINE = 1, + UNRECOGNIZED = -1, +} + +export interface TracePluginConfig { + /** kernel event set */ + ftraceEvents: string[]; + /** bytrace event set */ + hitraceCategories: string[]; + /** bytrace app set */ + hitraceApps: string[]; + /** kernel trace buffer size */ + bufferSizeKb: number; + /** time interval in milliseconds to notify service process */ + flushIntervalMs: number; + /** buffer water mark threshold to notify service process */ + flushThresholdKb: number; + /** parse /proc/kallsyms or not */ + parseKsyms: boolean; + /** value for trace_clock */ + clock: string; + /** time interval in milliseconds to read kernel trace buffer */ + tracePeriodMs: number; + /** raw data file prefix for debug */ + rawDataPrefix: string; + /** time duration in millisconds for trace actions */ + traceDurationMs: number; + /** enable debug options */ + debugOn: boolean; + hitraceTime: number; +} + +export interface CreateSessionRequest { + requestId: number; + sessionConfig: ProfilerSessionConfig | undefined; + pluginConfigs: ProfilerPluginConfig[]; +} + +export interface ProfilerPluginConfig { + pluginName: string; + sampleInterval?: number; + configData: T; + protobuf_serialize?: boolean; +} + +export interface FileSystemConfig { + cmdLine: string; + outfileName: string; +} + +export interface MemoryConfig { + /** set true to report process list */ + reportProcessTree: boolean; + /** set true to report memory counter from /proc/meminfo */ + reportSysmemMemInfo: boolean; + /** set required counter list of system meminfo, eg:MemTotal, MemFree, etc. */ + sysMeminfoCounters: SysMeminfoType[]; + /** set true to report memory counter from /proc/vmstat */ + reportSysmemVmemInfo: boolean; + /** set required counter list of virtual system meminfo, eg:nr_free_pages, nr_anon_pages, etc. */ + sysVmeminfoCounters: SysVMeminfoType[]; + /** set true to report process meminfo from /proc/${pid}/stat */ + reportProcessMemInfo: boolean; + /** set true to report application memory usage summary, eg:java heap memory, native heap, stack memory, etc. */ + reportAppMemInfo: boolean; + /** + * set true to report application memory by memory service, otherwise, + * application memory will count up by /proc/${pid}/smaps information + */ + reportAppMemByMemoryService: boolean; + /** set required pid list */ + pid: number[]; + /** set true to report smaps meminfo from /proc/${pid}/smaps */ + reportSmapsMemInfo?: boolean; +} + +export function sysVMeminfoTypeFromJSON(object: any): SysVMeminfoType { + switch (object) { + case 0: + case 'VMEMINFO_UNSPECIFIED': + return SysVMeminfoType.VMEMINFO_UNSPECIFIED; + case 1: + case 'VMEMINFO_NR_FREE_PAGES': + return SysVMeminfoType.VMEMINFO_NR_FREE_PAGES; + case 2: + case 'VMEMINFO_NR_ALLOC_BATCH': + return SysVMeminfoType.VMEMINFO_NR_ALLOC_BATCH; + case 3: + case 'VMEMINFO_NR_INACTIVE_ANON': + return SysVMeminfoType.VMEMINFO_NR_INACTIVE_ANON; + case 4: + case 'VMEMINFO_NR_ACTIVE_ANON': + return SysVMeminfoType.VMEMINFO_NR_ACTIVE_ANON; + case 5: + case 'VMEMINFO_NR_INACTIVE_FILE': + return SysVMeminfoType.VMEMINFO_NR_INACTIVE_FILE; + case 6: + case 'VMEMINFO_NR_ACTIVE_FILE': + return SysVMeminfoType.VMEMINFO_NR_ACTIVE_FILE; + case 7: + case 'VMEMINFO_NR_UNEVICTABLE': + return SysVMeminfoType.VMEMINFO_NR_UNEVICTABLE; + case 8: + case 'VMEMINFO_NR_MLOCK': + return SysVMeminfoType.VMEMINFO_NR_MLOCK; + case 9: + case 'VMEMINFO_NR_ANON_PAGES': + return SysVMeminfoType.VMEMINFO_NR_ANON_PAGES; + case 10: + case 'VMEMINFO_NR_MAPPED': + return SysVMeminfoType.VMEMINFO_NR_MAPPED; + case 11: + case 'VMEMINFO_NR_FILE_PAGES': + return SysVMeminfoType.VMEMINFO_NR_FILE_PAGES; + case 12: + case 'VMEMINFO_NR_DIRTY': + return SysVMeminfoType.VMEMINFO_NR_DIRTY; + case 13: + case 'VMEMINFO_NR_WRITEBACK': + return SysVMeminfoType.VMEMINFO_NR_WRITEBACK; + case 14: + case 'VMEMINFO_NR_SLAB_RECLAIMABLE': + return SysVMeminfoType.VMEMINFO_NR_SLAB_RECLAIMABLE; + case 15: + case 'VMEMINFO_NR_SLAB_UNRECLAIMABLE': + return SysVMeminfoType.VMEMINFO_NR_SLAB_UNRECLAIMABLE; + case 16: + case 'VMEMINFO_NR_PAGE_TABLE_PAGES': + return SysVMeminfoType.VMEMINFO_NR_PAGE_TABLE_PAGES; + case 17: + case 'VMEMINFO_NR_KERNEL_STACK': + return SysVMeminfoType.VMEMINFO_NR_KERNEL_STACK; + case 18: + case 'VMEMINFO_NR_OVERHEAD': + return SysVMeminfoType.VMEMINFO_NR_OVERHEAD; + case 19: + case 'VMEMINFO_NR_UNSTABLE': + return SysVMeminfoType.VMEMINFO_NR_UNSTABLE; + case 20: + case 'VMEMINFO_NR_BOUNCE': + return SysVMeminfoType.VMEMINFO_NR_BOUNCE; + case 21: + case 'VMEMINFO_NR_VMSCAN_WRITE': + return SysVMeminfoType.VMEMINFO_NR_VMSCAN_WRITE; + case 22: + case 'VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM': + return SysVMeminfoType.VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM; + case 23: + case 'VMEMINFO_NR_WRITEBACK_TEMP': + return SysVMeminfoType.VMEMINFO_NR_WRITEBACK_TEMP; + case 24: + case 'VMEMINFO_NR_ISOLATED_ANON': + return SysVMeminfoType.VMEMINFO_NR_ISOLATED_ANON; + case 25: + case 'VMEMINFO_NR_ISOLATED_FILE': + return SysVMeminfoType.VMEMINFO_NR_ISOLATED_FILE; + case 26: + case 'VMEMINFO_NR_SHMEM': + return SysVMeminfoType.VMEMINFO_NR_SHMEM; + case 27: + case 'VMEMINFO_NR_DIRTIED': + return SysVMeminfoType.VMEMINFO_NR_DIRTIED; + case 28: + case 'VMEMINFO_NR_WRITTEN': + return SysVMeminfoType.VMEMINFO_NR_WRITTEN; + case 29: + case 'VMEMINFO_NR_PAGES_SCANNED': + return SysVMeminfoType.VMEMINFO_NR_PAGES_SCANNED; + case 30: + case 'VMEMINFO_WORKINGSET_REFAULT': + return SysVMeminfoType.VMEMINFO_WORKINGSET_REFAULT; + case 31: + case 'VMEMINFO_WORKINGSET_ACTIVATE': + return SysVMeminfoType.VMEMINFO_WORKINGSET_ACTIVATE; + case 32: + case 'VMEMINFO_WORKINGSET_NODERECLAIM': + return SysVMeminfoType.VMEMINFO_WORKINGSET_NODERECLAIM; + case 33: + case 'VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES': + return SysVMeminfoType.VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES; + case 34: + case 'VMEMINFO_NR_FREE_CMA': + return SysVMeminfoType.VMEMINFO_NR_FREE_CMA; + case 35: + case 'VMEMINFO_NR_SWAPCACHE': + return SysVMeminfoType.VMEMINFO_NR_SWAPCACHE; + case 36: + case 'VMEMINFO_NR_DIRTY_THRESHOLD': + return SysVMeminfoType.VMEMINFO_NR_DIRTY_THRESHOLD; + case 37: + case 'VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD': + return SysVMeminfoType.VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD; + case 38: + case 'VMEMINFO_PGPGIN': + return SysVMeminfoType.VMEMINFO_PGPGIN; + case 39: + case 'VMEMINFO_PGPGOUT': + return SysVMeminfoType.VMEMINFO_PGPGOUT; + case 40: + case 'VMEMINFO_PGPGOUTCLEAN': + return SysVMeminfoType.VMEMINFO_PGPGOUTCLEAN; + case 41: + case 'VMEMINFO_PSWPIN': + return SysVMeminfoType.VMEMINFO_PSWPIN; + case 42: + case 'VMEMINFO_PSWPOUT': + return SysVMeminfoType.VMEMINFO_PSWPOUT; + case 43: + case 'VMEMINFO_PGALLOC_DMA': + return SysVMeminfoType.VMEMINFO_PGALLOC_DMA; + case 44: + case 'VMEMINFO_PGALLOC_NORMAL': + return SysVMeminfoType.VMEMINFO_PGALLOC_NORMAL; + case 45: + case 'VMEMINFO_PGALLOC_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGALLOC_MOVABLE; + case 46: + case 'VMEMINFO_PGFREE': + return SysVMeminfoType.VMEMINFO_PGFREE; + case 47: + case 'VMEMINFO_PGACTIVATE': + return SysVMeminfoType.VMEMINFO_PGACTIVATE; + case 48: + case 'VMEMINFO_PGDEACTIVATE': + return SysVMeminfoType.VMEMINFO_PGDEACTIVATE; + case 49: + case 'VMEMINFO_PGFAULT': + return SysVMeminfoType.VMEMINFO_PGFAULT; + case 50: + case 'VMEMINFO_PGMAJFAULT': + return SysVMeminfoType.VMEMINFO_PGMAJFAULT; + case 51: + case 'VMEMINFO_PGREFILL_DMA': + return SysVMeminfoType.VMEMINFO_PGREFILL_DMA; + case 52: + case 'VMEMINFO_PGREFILL_NORMAL': + return SysVMeminfoType.VMEMINFO_PGREFILL_NORMAL; + case 53: + case 'VMEMINFO_PGREFILL_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGREFILL_MOVABLE; + case 54: + case 'VMEMINFO_PGSTEAL_KSWAPD_DMA': + return SysVMeminfoType.VMEMINFO_PGSTEAL_KSWAPD_DMA; + case 55: + case 'VMEMINFO_PGSTEAL_KSWAPD_NORMAL': + return SysVMeminfoType.VMEMINFO_PGSTEAL_KSWAPD_NORMAL; + case 56: + case 'VMEMINFO_PGSTEAL_KSWAPD_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGSTEAL_KSWAPD_MOVABLE; + case 57: + case 'VMEMINFO_PGSTEAL_DIRECT_DMA': + return SysVMeminfoType.VMEMINFO_PGSTEAL_DIRECT_DMA; + case 58: + case 'VMEMINFO_PGSTEAL_DIRECT_NORMAL': + return SysVMeminfoType.VMEMINFO_PGSTEAL_DIRECT_NORMAL; + case 59: + case 'VMEMINFO_PGSTEAL_DIRECT_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGSTEAL_DIRECT_MOVABLE; + case 60: + case 'VMEMINFO_PGSCAN_KSWAPD_DMA': + return SysVMeminfoType.VMEMINFO_PGSCAN_KSWAPD_DMA; + case 61: + case 'VMEMINFO_PGSCAN_KSWAPD_NORMAL': + return SysVMeminfoType.VMEMINFO_PGSCAN_KSWAPD_NORMAL; + case 62: + case 'VMEMINFO_PGSCAN_KSWAPD_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGSCAN_KSWAPD_MOVABLE; + case 63: + case 'VMEMINFO_PGSCAN_DIRECT_DMA': + return SysVMeminfoType.VMEMINFO_PGSCAN_DIRECT_DMA; + case 64: + case 'VMEMINFO_PGSCAN_DIRECT_NORMAL': + return SysVMeminfoType.VMEMINFO_PGSCAN_DIRECT_NORMAL; + case 65: + case 'VMEMINFO_PGSCAN_DIRECT_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGSCAN_DIRECT_MOVABLE; + case 66: + case 'VMEMINFO_PGSCAN_DIRECT_THROTTLE': + return SysVMeminfoType.VMEMINFO_PGSCAN_DIRECT_THROTTLE; + case 67: + case 'VMEMINFO_PGINODESTEAL': + return SysVMeminfoType.VMEMINFO_PGINODESTEAL; + case 68: + case 'VMEMINFO_SLABS_SCANNED': + return SysVMeminfoType.VMEMINFO_SLABS_SCANNED; + case 69: + case 'VMEMINFO_KSWAPD_INODESTEAL': + return SysVMeminfoType.VMEMINFO_KSWAPD_INODESTEAL; + case 70: + case 'VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY': + return SysVMeminfoType.VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY; + case 71: + case 'VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY': + return SysVMeminfoType.VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY; + case 72: + case 'VMEMINFO_PAGEOUTRUN': + return SysVMeminfoType.VMEMINFO_PAGEOUTRUN; + case 73: + case 'VMEMINFO_ALLOCSTALL': + return SysVMeminfoType.VMEMINFO_ALLOCSTALL; + case 74: + case 'VMEMINFO_PGROTATED': + return SysVMeminfoType.VMEMINFO_PGROTATED; + case 75: + case 'VMEMINFO_DROP_PAGECACHE': + return SysVMeminfoType.VMEMINFO_DROP_PAGECACHE; + case 76: + case 'VMEMINFO_DROP_SLAB': + return SysVMeminfoType.VMEMINFO_DROP_SLAB; + case 77: + case 'VMEMINFO_PGMIGRATE_SUCCESS': + return SysVMeminfoType.VMEMINFO_PGMIGRATE_SUCCESS; + case 78: + case 'VMEMINFO_PGMIGRATE_FAIL': + return SysVMeminfoType.VMEMINFO_PGMIGRATE_FAIL; + case 79: + case 'VMEMINFO_COMPACT_MIGRATE_SCANNED': + return SysVMeminfoType.VMEMINFO_COMPACT_MIGRATE_SCANNED; + case 80: + case 'VMEMINFO_COMPACT_FREE_SCANNED': + return SysVMeminfoType.VMEMINFO_COMPACT_FREE_SCANNED; + case 81: + case 'VMEMINFO_COMPACT_ISOLATED': + return SysVMeminfoType.VMEMINFO_COMPACT_ISOLATED; + case 82: + case 'VMEMINFO_COMPACT_STALL': + return SysVMeminfoType.VMEMINFO_COMPACT_STALL; + case 83: + case 'VMEMINFO_COMPACT_FAIL': + return SysVMeminfoType.VMEMINFO_COMPACT_FAIL; + case 84: + case 'VMEMINFO_COMPACT_SUCCESS': + return SysVMeminfoType.VMEMINFO_COMPACT_SUCCESS; + case 85: + case 'VMEMINFO_COMPACT_DAEMON_WAKE': + return SysVMeminfoType.VMEMINFO_COMPACT_DAEMON_WAKE; + case 86: + case 'VMEMINFO_UNEVICTABLE_PGS_CULLED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_CULLED; + case 87: + case 'VMEMINFO_UNEVICTABLE_PGS_SCANNED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_SCANNED; + case 88: + case 'VMEMINFO_UNEVICTABLE_PGS_RESCUED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_RESCUED; + case 89: + case 'VMEMINFO_UNEVICTABLE_PGS_MLOCKED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_MLOCKED; + case 90: + case 'VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED; + case 91: + case 'VMEMINFO_UNEVICTABLE_PGS_CLEARED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_CLEARED; + case 92: + case 'VMEMINFO_UNEVICTABLE_PGS_STRANDED': + return SysVMeminfoType.VMEMINFO_UNEVICTABLE_PGS_STRANDED; + case 93: + case 'VMEMINFO_NR_ZSPAGES': + return SysVMeminfoType.VMEMINFO_NR_ZSPAGES; + case 94: + case 'VMEMINFO_NR_ION_HEAP': + return SysVMeminfoType.VMEMINFO_NR_ION_HEAP; + case 95: + case 'VMEMINFO_NR_GPU_HEAP': + return SysVMeminfoType.VMEMINFO_NR_GPU_HEAP; + case 96: + case 'VMEMINFO_ALLOCSTALL_DMA': + return SysVMeminfoType.VMEMINFO_ALLOCSTALL_DMA; + case 97: + case 'VMEMINFO_ALLOCSTALL_MOVABLE': + return SysVMeminfoType.VMEMINFO_ALLOCSTALL_MOVABLE; + case 98: + case 'VMEMINFO_ALLOCSTALL_NORMAL': + return SysVMeminfoType.VMEMINFO_ALLOCSTALL_NORMAL; + case 99: + case 'VMEMINFO_COMPACT_DAEMON_FREE_SCANNED': + return SysVMeminfoType.VMEMINFO_COMPACT_DAEMON_FREE_SCANNED; + case 100: + case 'VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED': + return SysVMeminfoType.VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED; + case 101: + case 'VMEMINFO_NR_FASTRPC': + return SysVMeminfoType.VMEMINFO_NR_FASTRPC; + case 102: + case 'VMEMINFO_NR_INDIRECTLY_RECLAIMABLE': + return SysVMeminfoType.VMEMINFO_NR_INDIRECTLY_RECLAIMABLE; + case 103: + case 'VMEMINFO_NR_ION_HEAP_POOL': + return SysVMeminfoType.VMEMINFO_NR_ION_HEAP_POOL; + case 104: + case 'VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE': + return SysVMeminfoType.VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE; + case 105: + case 'VMEMINFO_NR_SHADOW_CALL_STACK_BYTES': + return SysVMeminfoType.VMEMINFO_NR_SHADOW_CALL_STACK_BYTES; + case 106: + case 'VMEMINFO_NR_SHMEM_HUGEPAGES': + return SysVMeminfoType.VMEMINFO_NR_SHMEM_HUGEPAGES; + case 107: + case 'VMEMINFO_NR_SHMEM_PMDMAPPED': + return SysVMeminfoType.VMEMINFO_NR_SHMEM_PMDMAPPED; + case 108: + case 'VMEMINFO_NR_UNRECLAIMABLE_PAGES': + return SysVMeminfoType.VMEMINFO_NR_UNRECLAIMABLE_PAGES; + case 109: + case 'VMEMINFO_NR_ZONE_ACTIVE_ANON': + return SysVMeminfoType.VMEMINFO_NR_ZONE_ACTIVE_ANON; + case 110: + case 'VMEMINFO_NR_ZONE_ACTIVE_FILE': + return SysVMeminfoType.VMEMINFO_NR_ZONE_ACTIVE_FILE; + case 111: + case 'VMEMINFO_NR_ZONE_INACTIVE_ANON': + return SysVMeminfoType.VMEMINFO_NR_ZONE_INACTIVE_ANON; + case 112: + case 'VMEMINFO_NR_ZONE_INACTIVE_FILE': + return SysVMeminfoType.VMEMINFO_NR_ZONE_INACTIVE_FILE; + case 113: + case 'VMEMINFO_NR_ZONE_UNEVICTABLE': + return SysVMeminfoType.VMEMINFO_NR_ZONE_UNEVICTABLE; + case 114: + case 'VMEMINFO_NR_ZONE_WRITE_PENDING': + return SysVMeminfoType.VMEMINFO_NR_ZONE_WRITE_PENDING; + case 115: + case 'VMEMINFO_OOM_KILL': + return SysVMeminfoType.VMEMINFO_OOM_KILL; + case 116: + case 'VMEMINFO_PGLAZYFREE': + return SysVMeminfoType.VMEMINFO_PGLAZYFREE; + case 117: + case 'VMEMINFO_PGLAZYFREED': + return SysVMeminfoType.VMEMINFO_PGLAZYFREED; + case 118: + case 'VMEMINFO_PGREFILL': + return SysVMeminfoType.VMEMINFO_PGREFILL; + case 119: + case 'VMEMINFO_PGSCAN_DIRECT': + return SysVMeminfoType.VMEMINFO_PGSCAN_DIRECT; + case 120: + case 'VMEMINFO_PGSCAN_KSWAPD': + return SysVMeminfoType.VMEMINFO_PGSCAN_KSWAPD; + case 121: + case 'VMEMINFO_PGSKIP_DMA': + return SysVMeminfoType.VMEMINFO_PGSKIP_DMA; + case 122: + case 'VMEMINFO_PGSKIP_MOVABLE': + return SysVMeminfoType.VMEMINFO_PGSKIP_MOVABLE; + case 123: + case 'VMEMINFO_PGSKIP_NORMAL': + return SysVMeminfoType.VMEMINFO_PGSKIP_NORMAL; + case 124: + case 'VMEMINFO_PGSTEAL_DIRECT': + return SysVMeminfoType.VMEMINFO_PGSTEAL_DIRECT; + case 125: + case 'VMEMINFO_PGSTEAL_KSWAPD': + return SysVMeminfoType.VMEMINFO_PGSTEAL_KSWAPD; + case 126: + case 'VMEMINFO_SWAP_RA': + return SysVMeminfoType.VMEMINFO_SWAP_RA; + case 127: + case 'VMEMINFO_SWAP_RA_HIT': + return SysVMeminfoType.VMEMINFO_SWAP_RA_HIT; + case 128: + case 'VMEMINFO_WORKINGSET_RESTORE': + return SysVMeminfoType.VMEMINFO_WORKINGSET_RESTORE; + case -1: + case 'UNRECOGNIZED': + default: + return SysVMeminfoType.UNRECOGNIZED; + } +} + +export enum SysVMeminfoType { + UNRECOGNIZED = 'UNRECOGNIZED', + VMEMINFO_UNSPECIFIED = 'VMEMINFO_UNSPECIFIED', + VMEMINFO_NR_FREE_PAGES = 'VMEMINFO_NR_FREE_PAGES', + VMEMINFO_NR_ALLOC_BATCH = 'VMEMINFO_NR_ALLOC_BATCH', + VMEMINFO_NR_INACTIVE_ANON = 'VMEMINFO_NR_INACTIVE_ANON', + VMEMINFO_NR_ACTIVE_ANON = 'VMEMINFO_NR_ACTIVE_ANON', + VMEMINFO_NR_INACTIVE_FILE = 'VMEMINFO_NR_INACTIVE_FILE', + VMEMINFO_NR_ACTIVE_FILE = 'VMEMINFO_NR_ACTIVE_FILE', + VMEMINFO_NR_UNEVICTABLE = 'VMEMINFO_NR_UNEVICTABLE', + VMEMINFO_NR_MLOCK = 'VMEMINFO_NR_MLOCK', + VMEMINFO_NR_ANON_PAGES = 'VMEMINFO_NR_ANON_PAGES', + VMEMINFO_NR_MAPPED = 'VMEMINFO_NR_MAPPED', + VMEMINFO_NR_FILE_PAGES = 'VMEMINFO_NR_FILE_PAGES', + VMEMINFO_NR_DIRTY = 'VMEMINFO_NR_DIRTY', + VMEMINFO_NR_WRITEBACK = 'VMEMINFO_NR_WRITEBACK', + VMEMINFO_NR_SLAB_RECLAIMABLE = 'VMEMINFO_NR_SLAB_RECLAIMABLE', + VMEMINFO_NR_SLAB_UNRECLAIMABLE = 'VMEMINFO_NR_SLAB_UNRECLAIMABLE', + VMEMINFO_NR_PAGE_TABLE_PAGES = 'VMEMINFO_NR_PAGE_TABLE_PAGES', + VMEMINFO_NR_KERNEL_STACK = 'VMEMINFO_NR_KERNEL_STACK', + VMEMINFO_NR_OVERHEAD = 'VMEMINFO_NR_OVERHEAD', + VMEMINFO_NR_UNSTABLE = 'VMEMINFO_NR_UNSTABLE', + VMEMINFO_NR_BOUNCE = 'VMEMINFO_NR_BOUNCE', + VMEMINFO_NR_VMSCAN_WRITE = 'VMEMINFO_NR_VMSCAN_WRITE', + VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM = 'VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM', + VMEMINFO_NR_WRITEBACK_TEMP = 'VMEMINFO_NR_WRITEBACK_TEMP', + VMEMINFO_NR_ISOLATED_ANON = 'VMEMINFO_NR_ISOLATED_ANON', + VMEMINFO_NR_ISOLATED_FILE = 'VMEMINFO_NR_ISOLATED_FILE', + VMEMINFO_NR_SHMEM = 'VMEMINFO_NR_SHMEM', + VMEMINFO_NR_DIRTIED = 'VMEMINFO_NR_DIRTIED', + VMEMINFO_NR_WRITTEN = 'VMEMINFO_NR_WRITTEN', + VMEMINFO_NR_PAGES_SCANNED = 'VMEMINFO_NR_PAGES_SCANNED', + VMEMINFO_WORKINGSET_REFAULT = 'VMEMINFO_WORKINGSET_REFAULT', + VMEMINFO_WORKINGSET_ACTIVATE = 'VMEMINFO_WORKINGSET_ACTIVATE', + VMEMINFO_WORKINGSET_NODERECLAIM = 'VMEMINFO_WORKINGSET_NODERECLAIM', + VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES = 'VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES', + VMEMINFO_NR_FREE_CMA = 'VMEMINFO_NR_FREE_CMA', + VMEMINFO_NR_SWAPCACHE = 'VMEMINFO_NR_SWAPCACHE', + VMEMINFO_NR_DIRTY_THRESHOLD = 'VMEMINFO_NR_DIRTY_THRESHOLD', + VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD = 'VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD', + VMEMINFO_PGPGIN = 'VMEMINFO_PGPGIN', + VMEMINFO_PGPGOUT = 'VMEMINFO_PGPGOUT', + VMEMINFO_PGPGOUTCLEAN = 'VMEMINFO_PGPGOUTCLEAN', + VMEMINFO_PSWPIN = 'VMEMINFO_PSWPIN', + VMEMINFO_PSWPOUT = 'VMEMINFO_PSWPOUT', + VMEMINFO_PGALLOC_DMA = 'VMEMINFO_PGALLOC_DMA', + VMEMINFO_PGALLOC_NORMAL = 'VMEMINFO_PGALLOC_NORMAL', + VMEMINFO_PGALLOC_MOVABLE = 'VMEMINFO_PGALLOC_MOVABLE', + VMEMINFO_PGFREE = 'VMEMINFO_PGFREE', + VMEMINFO_PGACTIVATE = 'VMEMINFO_PGACTIVATE', + VMEMINFO_PGDEACTIVATE = 'VMEMINFO_PGDEACTIVATE', + VMEMINFO_PGFAULT = 'VMEMINFO_PGFAULT', + VMEMINFO_PGMAJFAULT = 'VMEMINFO_PGMAJFAULT', + VMEMINFO_PGREFILL_DMA = 'VMEMINFO_PGREFILL_DMA', + VMEMINFO_PGREFILL_NORMAL = 'VMEMINFO_PGREFILL_NORMAL', + VMEMINFO_PGREFILL_MOVABLE = 'VMEMINFO_PGREFILL_MOVABLE', + VMEMINFO_PGSTEAL_KSWAPD_DMA = 'VMEMINFO_PGSTEAL_KSWAPD_DMA', + VMEMINFO_PGSTEAL_KSWAPD_NORMAL = 'VMEMINFO_PGSTEAL_KSWAPD_NORMAL', + VMEMINFO_PGSTEAL_KSWAPD_MOVABLE = 'VMEMINFO_PGSTEAL_KSWAPD_MOVABLE', + VMEMINFO_PGSTEAL_DIRECT_DMA = 'VMEMINFO_PGSTEAL_DIRECT_DMA', + VMEMINFO_PGSTEAL_DIRECT_NORMAL = 'VMEMINFO_PGSTEAL_DIRECT_NORMAL', + VMEMINFO_PGSTEAL_DIRECT_MOVABLE = 'VMEMINFO_PGSTEAL_DIRECT_MOVABLE', + VMEMINFO_PGSCAN_KSWAPD_DMA = 'VMEMINFO_PGSCAN_KSWAPD_DMA', + VMEMINFO_PGSCAN_KSWAPD_NORMAL = 'VMEMINFO_PGSCAN_KSWAPD_NORMAL', + VMEMINFO_PGSCAN_KSWAPD_MOVABLE = 'VMEMINFO_PGSCAN_KSWAPD_MOVABLE', + VMEMINFO_PGSCAN_DIRECT_DMA = 'VMEMINFO_PGSCAN_DIRECT_DMA', + VMEMINFO_PGSCAN_DIRECT_NORMAL = 'VMEMINFO_PGSCAN_DIRECT_NORMAL', + VMEMINFO_PGSCAN_DIRECT_MOVABLE = 'VMEMINFO_PGSCAN_DIRECT_MOVABLE', + VMEMINFO_PGSCAN_DIRECT_THROTTLE = 'VMEMINFO_PGSCAN_DIRECT_THROTTLE', + VMEMINFO_PGINODESTEAL = 'VMEMINFO_PGINODESTEAL', + VMEMINFO_SLABS_SCANNED = 'VMEMINFO_SLABS_SCANNED', + VMEMINFO_KSWAPD_INODESTEAL = 'VMEMINFO_KSWAPD_INODESTEAL', + VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY = 'VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY', + VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY = 'VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY', + VMEMINFO_PAGEOUTRUN = 'VMEMINFO_PAGEOUTRUN', + VMEMINFO_ALLOCSTALL = 'VMEMINFO_ALLOCSTALL', + VMEMINFO_PGROTATED = 'VMEMINFO_PGROTATED', + VMEMINFO_DROP_PAGECACHE = 'VMEMINFO_DROP_PAGECACHE', + VMEMINFO_DROP_SLAB = 'VMEMINFO_DROP_SLAB', + VMEMINFO_PGMIGRATE_SUCCESS = 'VMEMINFO_PGMIGRATE_SUCCESS', + VMEMINFO_PGMIGRATE_FAIL = 'VMEMINFO_PGMIGRATE_FAIL', + VMEMINFO_COMPACT_MIGRATE_SCANNED = 'VMEMINFO_COMPACT_MIGRATE_SCANNED', + VMEMINFO_COMPACT_FREE_SCANNED = 'VMEMINFO_COMPACT_FREE_SCANNED', + VMEMINFO_COMPACT_ISOLATED = 'VMEMINFO_COMPACT_ISOLATED', + VMEMINFO_COMPACT_STALL = 'VMEMINFO_COMPACT_STALL', + VMEMINFO_COMPACT_FAIL = 'VMEMINFO_COMPACT_FAIL', + VMEMINFO_COMPACT_SUCCESS = 'VMEMINFO_COMPACT_SUCCESS', + VMEMINFO_COMPACT_DAEMON_WAKE = 'VMEMINFO_COMPACT_DAEMON_WAKE', + VMEMINFO_UNEVICTABLE_PGS_CULLED = 'VMEMINFO_UNEVICTABLE_PGS_CULLED', + VMEMINFO_UNEVICTABLE_PGS_SCANNED = 'VMEMINFO_UNEVICTABLE_PGS_SCANNED ', + VMEMINFO_UNEVICTABLE_PGS_RESCUED = 'VMEMINFO_UNEVICTABLE_PGS_RESCUED', + VMEMINFO_UNEVICTABLE_PGS_MLOCKED = 'VMEMINFO_UNEVICTABLE_PGS_MLOCKED', + VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED = 'VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED', + VMEMINFO_UNEVICTABLE_PGS_CLEARED = 'VMEMINFO_UNEVICTABLE_PGS_CLEARED', + VMEMINFO_UNEVICTABLE_PGS_STRANDED = 'VMEMINFO_UNEVICTABLE_PGS_STRANDED', + VMEMINFO_NR_ZSPAGES = 'VMEMINFO_NR_ZSPAGES', + VMEMINFO_NR_ION_HEAP = 'VMEMINFO_NR_ION_HEAP', + VMEMINFO_NR_GPU_HEAP = 'VMEMINFO_NR_GPU_HEAP', + VMEMINFO_ALLOCSTALL_DMA = 'VMEMINFO_ALLOCSTALL_DMA', + VMEMINFO_ALLOCSTALL_MOVABLE = 'VMEMINFO_ALLOCSTALL_MOVABLE', + VMEMINFO_ALLOCSTALL_NORMAL = 'VMEMINFO_ALLOCSTALL_NORMAL', + VMEMINFO_COMPACT_DAEMON_FREE_SCANNED = 'VMEMINFO_COMPACT_DAEMON_FREE_SCANNED', + VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED = 'VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED', + VMEMINFO_NR_FASTRPC = 'VMEMINFO_NR_FASTRPC', + VMEMINFO_NR_INDIRECTLY_RECLAIMABLE = 'VMEMINFO_NR_INDIRECTLY_RECLAIMABLE', + VMEMINFO_NR_ION_HEAP_POOL = 'VMEMINFO_NR_ION_HEAP_POOL', + VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE = 'VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE', + VMEMINFO_NR_SHADOW_CALL_STACK_BYTES = 'VMEMINFO_NR_SHADOW_CALL_STACK_BYTES', + VMEMINFO_NR_SHMEM_HUGEPAGES = 'VMEMINFO_NR_SHMEM_HUGEPAGES', + VMEMINFO_NR_SHMEM_PMDMAPPED = 'VMEMINFO_NR_SHMEM_PMDMAPPED', + VMEMINFO_NR_UNRECLAIMABLE_PAGES = 'VMEMINFO_NR_UNRECLAIMABLE_PAGES', + VMEMINFO_NR_ZONE_ACTIVE_ANON = 'VMEMINFO_NR_ZONE_ACTIVE_ANON', + VMEMINFO_NR_ZONE_ACTIVE_FILE = 'VMEMINFO_NR_ZONE_ACTIVE_FILE', + VMEMINFO_NR_ZONE_INACTIVE_ANON = 'VMEMINFO_NR_ZONE_INACTIVE_ANON', + VMEMINFO_NR_ZONE_INACTIVE_FILE = 'VMEMINFO_NR_ZONE_INACTIVE_FILE', + VMEMINFO_NR_ZONE_UNEVICTABLE = 'VMEMINFO_NR_ZONE_UNEVICTABLE', + VMEMINFO_NR_ZONE_WRITE_PENDING = 'VMEMINFO_NR_ZONE_WRITE_PENDING', + VMEMINFO_OOM_KILL = 'VMEMINFO_OOM_KILL ', + VMEMINFO_PGLAZYFREE = 'VMEMINFO_PGLAZYFREE', + VMEMINFO_PGLAZYFREED = 'VMEMINFO_PGLAZYFREED', + VMEMINFO_PGREFILL = 'VMEMINFO_PGREFILL', + VMEMINFO_PGSCAN_DIRECT = 'VMEMINFO_PGSCAN_DIRECT', + VMEMINFO_PGSCAN_KSWAPD = 'VMEMINFO_PGSCAN_KSWAPD', + VMEMINFO_PGSKIP_DMA = 'VMEMINFO_PGSKIP_DMA', + VMEMINFO_PGSKIP_MOVABLE = 'VMEMINFO_PGSKIP_MOVABLE', + VMEMINFO_PGSKIP_NORMAL = 'VMEMINFO_PGSKIP_NORMAL', + VMEMINFO_PGSTEAL_DIRECT = 'VMEMINFO_PGSTEAL_DIRECT', + VMEMINFO_PGSTEAL_KSWAPD = 'VMEMINFO_PGSTEAL_KSWAPD', + VMEMINFO_SWAP_RA = 'VMEMINFO_SWAP_RA', + VMEMINFO_SWAP_RA_HIT = 'VMEMINFO_SWAP_RA_HIT', + VMEMINFO_WORKINGSET_RESTORE = 'VMEMINFO_WORKINGSET_RESTORE', +} + +export enum SysMeminfoType { + MEMINFO_UNSPECIFIED = 'PMEM_UNSPECIFIED', + MEMINFO_MEM_TOTAL = 'PMEM_MEM_TOTAL', + MEMINFO_MEM_FREE = 'PMEM_MEM_FREE', + MEMINFO_MEM_AVAILABLE = 'PMEM_MEM_AVAILABLE', + MEMINFO_BUFFERS = 'PMEM_BUFFERS', + MEMINFO_CACHED = 'PMEM_CACHED', + MEMINFO_SWAP_CACHED = 'PMEM_SWAP_CACHED', + MEMINFO_ACTIVE = 'PMEM_ACTIVE', + MEMINFO_INACTIVE = 'PMEM_INACTIVE', + MEMINFO_ACTIVE_ANON = 'PMEM_ACTIVE_ANON', + MEMINFO_INACTIVE_ANON = 'PMEM_INACTIVE_ANON', + MEMINFO_ACTIVE_FILE = 'PMEM_ACTIVE_FILE', + MEMINFO_INACTIVE_FILE = 'PMEM_INACTIVE_FILE', + MEMINFO_UNEVICTABLE = 'PMEM_UNEVICTABLE', + MEMINFO_MLOCKED = 'PMEM_MLOCKED', + MEMINFO_SWAP_TOTAL = 'PMEM_SWAP_TOTAL', + MEMINFO_SWAP_FREE = 'PMEM_SWAP_FREE', + MEMINFO_DIRTY = 'PMEM_DIRTY', + MEMINFO_WRITEBACK = 'PMEM_WRITEBACK', + MEMINFO_ANON_PAGES = 'PMEM_ANON_PAGES', + MEMINFO_MAPPED = 'PMEM_MAPPED', + MEMINFO_SHMEM = 'PMEM_SHMEM', + MEMINFO_SLAB = 'PMEM_SLAB', + MEMINFO_SLAB_RECLAIMABLE = 'PMEM_SLAB_RECLAIMABLE', + MEMINFO_SLAB_UNRECLAIMABLE = 'PMEM_SLAB_UNRECLAIMABLE', + MEMINFO_KERNEL_STACK = 'PMEM_KERNEL_STACK', + MEMINFO_PAGE_TABLES = 'PMEM_PAGE_TABLES', + MEMINFO_COMMIT_LIMIT = 'PMEM_COMMIT_LIMIT', + MEMINFO_COMMITED_AS = 'PMEM_COMMITED_AS', + MEMINFO_VMALLOC_TOTAL = 'PMEM_VMALLOC_TOTAL', + MEMINFO_VMALLOC_USED = 'PMEM_VMALLOC_USED', + MEMINFO_VMALLOC_CHUNK = 'PMEM_VMALLOC_CHUNK', + MEMINFO_CMA_TOTAL = 'PMEM_CMA_TOTAL', + MEMINFO_CMA_FREE = 'PMEM_CMA_FREE', + MEMINFO_KERNEL_RECLAIMABLE = 'PMEM_KERNEL_RECLAIMABLE', + UNRECOGNIZED = 'UNRECOGNIZED', +} + +export function sysMeminfoTypeFromJSON(object: any): SysMeminfoType { + switch (object) { + case 0: + case 'MEMINFO_UNSPECIFIED': + return SysMeminfoType.MEMINFO_UNSPECIFIED; + case 1: + case 'MEMINFO_MEM_TOTAL': + return SysMeminfoType.MEMINFO_MEM_TOTAL; + case 2: + case 'MEMINFO_MEM_FREE': + return SysMeminfoType.MEMINFO_MEM_FREE; + case 3: + case 'MEMINFO_MEM_AVAILABLE': + return SysMeminfoType.MEMINFO_MEM_AVAILABLE; + case 4: + case 'MEMINFO_BUFFERS': + return SysMeminfoType.MEMINFO_BUFFERS; + case 5: + case 'MEMINFO_CACHED': + return SysMeminfoType.MEMINFO_CACHED; + case 6: + case 'MEMINFO_SWAP_CACHED': + return SysMeminfoType.MEMINFO_SWAP_CACHED; + case 7: + case 'MEMINFO_ACTIVE': + return SysMeminfoType.MEMINFO_ACTIVE; + case 8: + case 'MEMINFO_INACTIVE': + return SysMeminfoType.MEMINFO_INACTIVE; + case 9: + case 'MEMINFO_ACTIVE_ANON': + return SysMeminfoType.MEMINFO_ACTIVE_ANON; + case 10: + case 'MEMINFO_INACTIVE_ANON': + return SysMeminfoType.MEMINFO_INACTIVE_ANON; + case 11: + case 'MEMINFO_ACTIVE_FILE': + return SysMeminfoType.MEMINFO_ACTIVE_FILE; + case 12: + case 'MEMINFO_INACTIVE_FILE': + return SysMeminfoType.MEMINFO_INACTIVE_FILE; + case 13: + case 'MEMINFO_UNEVICTABLE': + return SysMeminfoType.MEMINFO_UNEVICTABLE; + case 14: + case 'MEMINFO_MLOCKED': + return SysMeminfoType.MEMINFO_MLOCKED; + case 15: + case 'MEMINFO_SWAP_TOTAL': + return SysMeminfoType.MEMINFO_SWAP_TOTAL; + case 16: + case 'MEMINFO_SWAP_FREE': + return SysMeminfoType.MEMINFO_SWAP_FREE; + case 17: + case 'MEMINFO_DIRTY': + return SysMeminfoType.MEMINFO_DIRTY; + case 18: + case 'MEMINFO_WRITEBACK': + return SysMeminfoType.MEMINFO_WRITEBACK; + case 19: + case 'MEMINFO_ANON_PAGES': + return SysMeminfoType.MEMINFO_ANON_PAGES; + case 20: + case 'MEMINFO_MAPPED': + return SysMeminfoType.MEMINFO_MAPPED; + case 21: + case 'MEMINFO_SHMEM': + return SysMeminfoType.MEMINFO_SHMEM; + case 22: + case 'MEMINFO_SLAB': + return SysMeminfoType.MEMINFO_SLAB; + case 23: + case 'MEMINFO_SLAB_RECLAIMABLE': + return SysMeminfoType.MEMINFO_SLAB_RECLAIMABLE; + case 24: + case 'MEMINFO_SLAB_UNRECLAIMABLE': + return SysMeminfoType.MEMINFO_SLAB_UNRECLAIMABLE; + case 25: + case 'MEMINFO_KERNEL_STACK': + return SysMeminfoType.MEMINFO_KERNEL_STACK; + case 26: + case 'MEMINFO_PAGE_TABLES': + return SysMeminfoType.MEMINFO_PAGE_TABLES; + case 27: + case 'MEMINFO_COMMIT_LIMIT': + return SysMeminfoType.MEMINFO_COMMIT_LIMIT; + case 28: + case 'MEMINFO_COMMITED_AS': + return SysMeminfoType.MEMINFO_COMMITED_AS; + case 29: + case 'MEMINFO_VMALLOC_TOTAL': + return SysMeminfoType.MEMINFO_VMALLOC_TOTAL; + case 30: + case 'MEMINFO_VMALLOC_USED': + return SysMeminfoType.MEMINFO_VMALLOC_USED; + case 31: + case 'MEMINFO_VMALLOC_CHUNK': + return SysMeminfoType.MEMINFO_VMALLOC_CHUNK; + case 32: + case 'MEMINFO_CMA_TOTAL': + return SysMeminfoType.MEMINFO_CMA_TOTAL; + case 33: + case 'MEMINFO_CMA_FREE': + return SysMeminfoType.MEMINFO_CMA_FREE; + case 34: + case 'MEMINFO_KERNEL_RECLAIMABLE': + return SysMeminfoType.MEMINFO_KERNEL_RECLAIMABLE; + case -1: + case 'UNRECOGNIZED': + default: + return SysMeminfoType.UNRECOGNIZED; + } +} + +export enum Type { + TYPE_UNSPECIFIED = 0, + HI3516 = 1, + P40 = 2, + UNRECOGNIZED = -1, +} + +export interface HilogConfig { + deviceType: Type; + logLevel: Level; + needClear: boolean; +} + +export function levelFromJSON(object: any): Level { + switch (object) { + case 0: + case 'LEVEL_UNSPECIFIED': + return Level.LOG_UNSPECIFIED; + case 1: + case 'Error': + return Level.LOG_ERROR; + case 2: + case 'Info': + return Level.LOG_INFO; + case 3: + case 'Debug': + return Level.LOG_DEBUG; + case 4: + case 'Warns': + return Level.LOG_WARN; + case -1: + case 'UNRECOGNIZED': + default: + return Level.UNRECOGNIZED; + } +} + +export enum Level { + LOG_UNSPECIFIED = 'LOG_UNSPECIFIED', + LOG_ERROR = 'LOG_ERROR', + LOG_INFO = 'LOG_INFO', + LOG_DEBUG = 'LOG_DEBUG', + LOG_WARN = 'LOG_WARN', + UNRECOGNIZED = -1, +} + +export interface NativeHookConfig { + pid: number; + saveFile: boolean; + fileName: string; + filterSize: number; + smbPages: number; + maxStackDepth: number; + processName: string; + mallocFreeMatchingInterval: number; + mallocFreeMatchingCnt: number; + stringCompressed: boolean; + fpUnwind: boolean; + blocked: boolean; + recordAccurately?: boolean; + offlineSymbolization?: boolean; + callframeCompress?: boolean; + statisticsInterval?: number; +} + +export interface FpsConfig { + reportFps: boolean; +} + +export interface ProcessConfig { + report_process_tree: boolean; + report_cpu: boolean; + report_diskio: boolean; + report_pss: boolean; +} + +export interface CpuConfig { + pid: number; + reportProcessInfo: boolean; +} + +enum IoReportType { + UNSPECIFIED = 'UNSPECIFIED', + IO_REPORT = 'IO_REPORT', + IO_REPORT_EX = 'IO_REPORT_EX', +} + +export interface DiskioConfig { + reportIoStats: string; +} + +export interface NetworkConfig { + testFile: string; +} + +export interface HiperfPluginConfig { + isRoot: boolean; + outfileName: string; + recordArgs: string; +} + +export interface HiSystemEventConfig { + msg: string; + processName: string; +} + +export interface JsHeapConfig { + pid: number; + type: number; + interval: number; + capture_numeric_value: boolean; + track_allocations: boolean; +} diff --git a/ide/src/trace/component/setting/utils/PluginConvertUtils.ts b/ide/src/trace/component/setting/utils/PluginConvertUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e823f5726000edbfe81d9159505e6399cb0ea8a --- /dev/null +++ b/ide/src/trace/component/setting/utils/PluginConvertUtils.ts @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2022 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. + */ + +export class PluginConvertUtils { + private static crlf: string = '\n'; + private static leftBrace: string = '{'; + private static rightBrace: string = '}'; + static pluginConfig: any[] = []; + + public static createHdcCmd(requestString: string, outputPath: string, time: number) { + return ( + 'hiprofiler_cmd \\' + + this.crlf + + ' -c - \\' + + this.crlf + + ' -o ' + + outputPath + + ' \\' + + this.crlf + + ' -t ' + + time + + ' \\' + + this.crlf + + ' -s \\' + + this.crlf + + ' -k \\' + + this.crlf + + '<, + indentation: number, + needColon: boolean, + spacesNumber: number + ): string { + let text = ''; + arr.forEach((arrValue) => { + switch (typeof arrValue) { + case 'bigint': + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ': ' + + arrValue.toString() + + this.crlf; + break; + case 'boolean': + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ': ' + + arrValue.toString() + + this.crlf; + break; + case 'number': + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ': ' + + arrValue.toString() + + this.crlf; + break; + case 'string': + if (arrValue == '') { + break; + } + if (arrValue.startsWith('VMEMINFO') || arrValue.startsWith('PMEM')) { + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ': ' + + arrValue.toString() + + this.crlf; + } else { + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ': "' + + arrValue.toString() + + '"' + + this.crlf; + } + break; + case 'object': + default: + if (needColon) { + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ': ' + + this.handleObj(arrValue, indentation + 1, needColon, spacesNumber) + + '' + + this.crlf; + } else { + text = + text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + this.handleObj(arrValue, indentation + 1, needColon, spacesNumber) + + '' + + this.crlf; + } + } + }); + return text; + } + + // 驼峰转snake + private static humpToSnake(humpString: string): string { + return humpString.replace(/[A-Z]/g, (value) => '_' + value.toLowerCase()); + } +} diff --git a/ide/src/trace/component/trace/TimerShaftElement.ts b/ide/src/trace/component/trace/TimerShaftElement.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9f58b72392ee01336c4acb55518756df1279645 --- /dev/null +++ b/ide/src/trace/component/trace/TimerShaftElement.ts @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../base-ui/BaseElement.js'; +import { TimeRuler } from './timer-shaft/TimeRuler.js'; +import { Rect } from './timer-shaft/Rect.js'; +import { RangeRuler, TimeRange } from './timer-shaft/RangeRuler.js'; +import { SportRuler } from './timer-shaft/SportRuler.js'; +import { procedurePool } from '../../database/Procedure.js'; +import { Flag } from './timer-shaft/Flag.js'; +import { info } from '../../../log/Log.js'; + +//随机生成十六位进制颜色 +export function randomRgbColor() { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; +} + +export function ns2s(ns: number): string { + let second1 = 1_000_000_000; // 1 second + let millisecond1 = 1_000_000; // 1 millisecond + let microsecond1 = 1_000; // 1 microsecond + let nanosecond1 = 1000.0; + let res; + if (ns >= second1) { + res = (ns / 1000 / 1000 / 1000).toFixed(1) + ' s'; + } else if (ns >= millisecond1) { + res = (ns / 1000 / 1000).toFixed(1) + ' ms'; + } else if (ns >= microsecond1) { + res = (ns / 1000).toFixed(1) + ' μs'; + } else if (ns > 0) { + res = ns.toFixed(1) + ' ns'; + } else { + res = ns.toFixed(1) + ' s'; + } + return res; +} + +export function ns2x(ns: number, startNS: number, endNS: number, duration: number, rect: Rect) { + if (endNS == 0) { + endNS = duration; + } + let xSize: number = ((ns - startNS) * rect.width) / (endNS - startNS); + if (xSize < 0) { + xSize = 0; + } + if (xSize > rect.width) { + xSize = rect.width; + } + return xSize; +} + +@element('timer-shaft-element') +export class TimerShaftElement extends BaseElement { + // @ts-ignore + offscreen: OffscreenCanvas | undefined; + isOffScreen: boolean = false; + public ctx: CanvasRenderingContext2D | undefined | null; + public canvas: HTMLCanvasElement | null | undefined; + public totalEL: HTMLDivElement | null | undefined; + public timeTotalEL: HTMLSpanElement | null | undefined; + public timeOffsetEL: HTMLSpanElement | null | undefined; + public loadComplete: boolean = false; + public collecBtn: HTMLElement | null | undefined; + rangeChangeHandler: ((timeRange: TimeRange) => void) | undefined = undefined; + flagChangeHandler: ((hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => void) | undefined = + undefined; + flagClickHandler: ((flag: Flag | undefined | null) => void) | undefined = undefined; + /** + * 离线渲染需要的变量 + */ + dpr = window.devicePixelRatio || 1; + frame: Rect = new Rect(0, 0, 0, 0); + must: boolean = true; + hoverX: number = 0; + hoverY: number = 0; + canvasWidth: number = 0; + canvasHeight: number = 0; + _cpuUsage: Array<{ cpu: number; ro: number; rate: number }> = []; + protected timeRuler: TimeRuler | undefined; + protected rangeRuler: RangeRuler | undefined; + protected _sportRuler: SportRuler | undefined; + private root: HTMLDivElement | undefined | null; + private _totalNS: number = 10_000_000_000; + private _startNS: number = 0; + private _endNS: number = 10_000_000_000; + + get sportRuler(): SportRuler | undefined { + return this._sportRuler; + } + + set cpuUsage(value: Array<{ cpu: number; ro: number; rate: number }>) { + info('set cpuUsage values :', value); + this._cpuUsage = value; + if (this.rangeRuler) { + this.rangeRuler.cpuUsage = this._cpuUsage; + } + } + + get totalNS(): number { + return this._totalNS; + } + + set totalNS(value: number) { + info('set totalNS values :', value); + this._totalNS = value; + if (this.timeRuler) this.timeRuler.totalNS = value; + if (this.rangeRuler) this.rangeRuler.range.totalNS = value; + if (this.timeTotalEL) this.timeTotalEL.textContent = `${ns2s(value)}`; + requestAnimationFrame(() => this.render()); + } + + get startNS(): number { + return this._startNS; + } + + set startNS(value: number) { + this._startNS = value; + } + + get endNS(): number { + return this._endNS; + } + + set endNS(value: number) { + this._endNS = value; + } + + isScaling(): boolean { + return this.rangeRuler?.isPress || false; + } + + reset(): void { + this.loadComplete = false; + if (this.rangeRuler) { + this.rangeRuler.markA.frame.x = 0; + this.rangeRuler.markB.frame.x = this.rangeRuler.frame.width; + this.rangeRuler.cpuUsage = []; + this.sportRuler!.flagList.length = 0; + this.sportRuler!.isRangeSelect = false; + this.setSlicesMark(); + } + this.removeTriangle('inverted'); + this.totalNS = 10_000_000_000; + } + + initElements(): void { + this.root = this.shadowRoot?.querySelector('.root'); + this.canvas = this.shadowRoot?.querySelector('.panel'); + this.totalEL = this.shadowRoot?.querySelector('.total'); + this.timeTotalEL = this.shadowRoot?.querySelector('.time-total'); + this.timeOffsetEL = this.shadowRoot?.querySelector('.time-offset'); + this.collecBtn = this.shadowRoot?.querySelector('.time-collect'); + procedurePool.timelineChange = (a: any) => this.rangeChangeHandler?.(a); + window.subscribe(window.SmartEvent.UI.TimeRange, (b) => this.setRangeNS(b.startNS, b.endNS)); + } + + getRangeRuler() { + return this.rangeRuler; + } + + connectedCallback() { + if (this.canvas) { + if (this.isOffScreen) { + // @ts-ignore + this.offscreen = this.canvas.transferControlToOffscreen(); + return; + } else { + this.ctx = this.canvas?.getContext('2d', { alpha: true }); + } + } + if (this.timeTotalEL) this.timeTotalEL.textContent = ns2s(this._totalNS); + if (this.timeOffsetEL) this.timeOffsetEL.textContent = ns2s(this._startNS); + const width = this.canvas?.clientWidth || 0; + const height = this.canvas?.clientHeight || 0; + if (!this.timeRuler) { + this.timeRuler = new TimeRuler(this, new Rect(0, 0, width, 20), this._totalNS); + } + if (!this._sportRuler) { + this._sportRuler = new SportRuler( + this, + new Rect(0, 100, width, height - 100), + (hoverFlag, selectFlag) => { + this.flagChangeHandler?.(hoverFlag, selectFlag); + }, + (flag) => { + this.flagClickHandler?.(flag); + } + ); + } + if (!this.rangeRuler) { + this.rangeRuler = new RangeRuler( + this, + new Rect(0, 25, width, 75), + { + slicesTime: { + startTime: null, + endTime: null, + color: null, + }, + scale: 0, + startX: 0, + endX: this.canvas?.clientWidth || 0, + startNS: 0, + endNS: this.totalNS, + totalNS: this.totalNS, + refresh: true, + xs: [], + xsTxt: [], + }, + (a) => { + if (this._sportRuler) { + this._sportRuler.range = a; + } + if (this.timeOffsetEL) { + this.timeOffsetEL.textContent = ns2s(a.startNS); + } + if (this.loadComplete) { + this.rangeChangeHandler?.(a); + } + } + ); + } + this.rangeRuler.frame.width = width; + this._sportRuler.frame.width = width; + this.timeRuler.frame.width = width; + } + + setRangeNS(startNS: number, endNS: number) { + info('set startNS values :' + startNS + 'endNS values : ' + endNS); + this.rangeRuler?.setRangeNS(startNS, endNS); + } + + getRange(): TimeRange | undefined { + return this.rangeRuler?.getRange(); + } + + updateWidth(width: number) { + this.dpr = window.devicePixelRatio || 1; + this.canvas!.width = width - (this.totalEL?.clientWidth || 0); + this.canvas!.height = this.shadowRoot!.host.clientHeight || 0; + let oldWidth = this.canvas!.width; + let oldHeight = this.canvas!.height; + this.canvas!.width = Math.ceil(oldWidth * this.dpr); + this.canvas!.height = Math.ceil(oldHeight * this.dpr); + this.canvas!.style.width = oldWidth + 'px'; + this.canvas!.style.height = oldHeight + 'px'; + this.ctx?.scale(this.dpr, this.dpr); + this.ctx?.translate(0, 0); + this.rangeRuler!.frame.width = oldWidth; + this._sportRuler!.frame.width = oldWidth; + this.timeRuler!.frame.width = oldWidth; + this.rangeRuler?.fillX(); + this.render(); + } + + documentOnMouseDown = (ev: MouseEvent) => { + if ((window as any).isSheetMove) return; + this.rangeRuler?.mouseDown(ev); + }; + + documentOnMouseUp = (ev: MouseEvent) => { + if ((window as any).isSheetMove) return; + this.rangeRuler?.mouseUp(ev); + this.sportRuler?.mouseUp(ev); + }; + + documentOnMouseMove = (ev: MouseEvent) => { + this.rangeRuler?.mouseMove(ev); + if (this.sportRuler?.edgeDetection(ev)) { + this.sportRuler?.mouseMove(ev); + } else { + this.sportRuler?.mouseOut(ev); + } + }; + + documentOnMouseOut = (ev: MouseEvent) => { + this.rangeRuler?.mouseOut(ev); + this.sportRuler?.mouseOut(ev); + }; + + documentOnKeyPress = (ev: KeyboardEvent) => { + if ((window as any).isSheetMove) return; + if ((window as any).flagInputFocus) return; + this.rangeRuler?.keyPress(ev); + this.sportRuler?.clearHoverFlag(); + }; + + documentOnKeyUp = (ev: KeyboardEvent) => { + if ((window as any).isSheetMove) return; + if ((window as any).flagInputFocus) return; + this.rangeRuler?.keyUp(ev); + }; + + disconnectedCallback() {} + + firstRender = true; + + lineColor() { + return window.getComputedStyle(this.canvas!, null).getPropertyValue('color'); + } + + render() { + this.dpr = window.devicePixelRatio || 1; + if (this.ctx) { + this.ctx.fillStyle = 'transparent'; + this.ctx?.fillRect(0, 0, this.canvas?.width || 0, this.canvas?.height || 0); + this.timeRuler?.draw(); + this.rangeRuler?.draw(); + this._sportRuler?.draw(); + } else { + procedurePool.submitWithName( + `timeline`, + `timeline`, + { + offscreen: this.must ? this.offscreen : undefined, //是否离屏 + dpr: this.dpr, //屏幕dpr值 + hoverX: this.hoverX, + hoverY: this.hoverY, + canvasWidth: this.canvasWidth, + canvasHeight: this.canvasHeight, + keyPressCode: null, + keyUpCode: null, + lineColor: '#dadada', + startNS: this.startNS, + endNS: this.endNS, + totalNS: this.totalNS, + frame: this.frame, + }, + this.must ? this.offscreen : undefined, + (res: any) => { + this.must = false; + } + ); + } + } + + modifyFlagList(flag: Flag | null | undefined) { + this._sportRuler?.modifyFlagList(flag); + } + + cancelPressFrame() { + this.rangeRuler?.cancelPressFrame(); + } + + cancelUpFrame() { + this.rangeRuler?.cancelUpFrame(); + } + + stopWASD(ev: any) { + this.rangeRuler?.keyUp(ev); + } + + drawTriangle(time: number, type: string) { + return this._sportRuler?.drawTriangle(time, type); + } + + removeTriangle(type: string) { + this._sportRuler?.removeTriangle(type); + } + + setSlicesMark(startTime: null | number = null, endTime: null | number = null) { + this._sportRuler?.setSlicesMark(startTime, endTime); + } + + displayCollect(showCollect: boolean) { + if (showCollect) { + this.collecBtn!.style.display = 'flex'; + } else { + this.collecBtn!.style.display = 'none'; + } + } + + initHtml(): string { + return ` + +
+
+
+
+ 10 + 0 +
+ +
+
+
+ +
+ `; + } +} diff --git a/ide/src/trace/component/trace/base/ColorUtils.ts b/ide/src/trace/component/trace/base/ColorUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9f406927f0ab1ff1aab673afa4cc521bddc4801 --- /dev/null +++ b/ide/src/trace/component/trace/base/ColorUtils.ts @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 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 { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js'; + +export class ColorUtils { + public static GREY_COLOR: string = '#f0f0f0'; + + public static MD_PALETTE_A: Array = [ + '#40b3e7', + '#606e75', + '#8d9171', + '#8f8f8f', + '#7a9160', + '#9fafc4', + '#8a8a8b', + '#9e8e00', + '#696e35', + '#5c4d21', + '#18a8a1', + '#a16a40', + '#a94eb9', + '#886EB4', + ]; + public static MD_PALETTE_B: Array = [ + '#9785D3', + '#A27F7E', + '#00bdd6', + '#94B5F4', + '#B282F6', + '#E97978', + '#7AD7E6', + '#A1C38A', + '#DB8E86', + '#42B7A4', + '#AACEA0', + '#E69553', + '#7EC6BB', + '#C6D9F2', + ]; + public static FUNC_COLOR_A: Array = [ + '#40b3e7', + '#606e75', + '#8d9171', + '#8f8f8f', + '#7a9160', + '#9fafc4', + '#8a8a8b', + '#9e8e00', + '#696e35', + '#5c4d21', + '#18a8a1', + '#a16a40', + '#a94eb9', + '#886EB4', + ]; + public static FUNC_COLOR_B: Array = [ + '#9785D3', + '#A27F7E', + '#00bdd6', + '#94B5F4', + '#B282F6', + '#E97978', + '#7AD7E6', + '#A1C38A', + '#DB8E86', + '#42B7A4', + '#AACEA0', + '#E69553', + '#7EC6BB', + '#C6D9F2', + ]; + + public static JANK_COLOR: Array = ['#42A14D', '#C0CE85', '#FF651D', '#FFE335', '#009DFA', '#E97978']; + public static MD_PALETTE: Array = ColorUtils.MD_PALETTE_B; + public static FUNC_COLOR: Array = ColorUtils.FUNC_COLOR_B; + + public static hash(str: string, max: number): number { + let colorA: number = 0x811c9dc5; + let colorB: number = 0xfffffff; + let colorC: number = 16777619; + let colorD: number = 0xffffffff; + let hash: number = colorA & colorB; + + for (let index: number = 0; index < str.length; index++) { + hash ^= str.charCodeAt(index); + hash = (hash * colorC) & colorD; + } + return Math.abs(hash) % max; + } + + public static colorForThread(thread: CpuStruct): string { + if (thread == null) { + return ColorUtils.GREY_COLOR; + } + let tid: number | undefined | null = (thread.processId || -1) >= 0 ? thread.processId : thread.tid; + return ColorUtils.colorForTid(tid || 0); + } + + public static colorForTid(tid: number): string { + let colorIdx: number = ColorUtils.hash(`${tid}`, ColorUtils.MD_PALETTE.length); + return ColorUtils.MD_PALETTE[colorIdx]; + } + + public static colorForName(name: string): string { + let colorIdx: number = ColorUtils.hash(name, ColorUtils.MD_PALETTE.length); + return ColorUtils.MD_PALETTE[colorIdx]; + } + + public static formatNumberComma(str: number): string { + if (str === undefined || str === null) return ''; + let unit = str >= 0 ? '' : '-'; + let l = Math.abs(str).toString().split('').reverse(); + let t: string = ''; + for (let i = 0; i < l.length; i++) { + t += l[i] + ((i + 1) % 3 == 0 && i + 1 != l.length ? ',' : ''); + } + return unit + t.split('').reverse().join(''); + } + + public static hashFunc(str: string, depth: number, max: number): number { + let colorA: number = 0x811c9dc5; + let colorB: number = 0xfffffff; + let colorC: number = 16777619; + let colorD: number = 0xffffffff; + let hash: number = colorA & colorB; + let st = str.replace(/[0-9]+/g, ''); + for (let index: number = 0; index < st.length; index++) { + hash ^= st.charCodeAt(index); + hash = (hash * colorC) & colorD; + } + return (Math.abs(hash) + depth) % max; + } + + public static funcTextColor(val: string) { + var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; + // 把颜色值变成小写 + var color = val.toLowerCase(); + var result = ''; + if (reg.test(color)) { + if (color.length === 4) { + var colorNew = '#'; + for (var i = 1; i < 4; i += 1) { + colorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1)); + } + color = colorNew; + } + var colorChange = []; + for (var i = 1; i < 7; i += 2) { + colorChange.push(parseInt('0x' + color.slice(i, i + 2))); + } + var grayLevel = colorChange[0] * 0.299 + colorChange[1] * 0.587 + colorChange[2] * 0.114; + if (grayLevel >= 150) { + //浅色模式 + return '#000'; + } else { + return '#fff'; + } + } else { + result = '无效'; + return result; + } + } +} diff --git a/ide/src/trace/component/trace/base/EventCenter.ts b/ide/src/trace/component/trace/base/EventCenter.ts new file mode 100644 index 0000000000000000000000000000000000000000..09ee0cc79e469df8d381d3b14fba6dfb34e0c2ea --- /dev/null +++ b/ide/src/trace/component/trace/base/EventCenter.ts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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. + */ + +class Event { + map: any; + constructor() { + this.map = {}; + } + + subscribe(event: string, fn: Function) { + this.map[event] = this.map[event] || []; + this.map[event].push(fn); + } + publish(event: string, data: any) { + const fnList = this.map[event] || []; + if (!fnList || fnList.length === 0) return; + fnList.forEach((fn: Function) => fn.call(undefined, data)); + } + unsubscribe(event: string, fn: Function) { + const fnList = this.map[event] || []; + const index = fnList.indexOf(fn); + if (index < 0) return; + fnList.splice(index, 1); + } + subscribeOnce(event: string, callback: Function) { + const f = (data: any) => { + callback(data); + this.unsubscribe(event, f); + }; + this.subscribe(event, f); + } + + clearTraceRowComplete() { + if (this.map[window.SmartEvent.UI.TraceRowComplete].length > 0) { + this.map[window.SmartEvent.UI.TraceRowComplete] = []; + } + } +} + +export const EventCenter = new Event(); diff --git a/ide/src/trace/component/trace/base/Extension.ts b/ide/src/trace/component/trace/base/Extension.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f6bb585b0b315a90121bddcb5988ad795c30412 --- /dev/null +++ b/ide/src/trace/component/trace/base/Extension.ts @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 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 { EventCenter } from './EventCenter.js'; + +declare global { + interface Number { + n2x(): number; + } + + interface Array { + isEmpty(): boolean; + + isNotEmpty(): boolean; + } + + interface HTMLElement { + containPoint( + ev: MouseEvent, + cut?: { + left?: number; + right?: number; + top?: number; + bottom?: number; + } + ): boolean; + } + + interface Window { + SmartEvent: { + UI: { + MenuTrace: string; //selected menu trace + RefreshCanvas: string; //selected menu trace + SliceMark: string; //Set the tag scope + TimeRange: string; //Set the timeline range + TraceRowComplete: string; //Triggered after the row component has finished loading data + KeyboardEnable: string; // SystemTrace Keyboard enable + UploadSOFile: string; // Upload so file + Loading: string; // Upload so file + }; + }; + + subscribe(evt: string, fn: (b: any) => void): void; + + subscribeOnce(evt: string, fn: (b: any) => void): void; + + unsubscribe(evt: string, fn: (b: any) => void): void; + + publish(evt: string, data: any): void; + + clearTraceRowComplete(): void; + } +} + +Number.prototype.n2x = function (): number { + return Number(this); +}; + +Array.prototype.isEmpty = function (): boolean { + return this == null || this == undefined || this.length == 0; +}; +Array.prototype.isNotEmpty = function (): boolean { + return this != null && this != undefined && this.length > 0; +}; + +HTMLElement.prototype.containPoint = function (ev, cut) { + let rect = this.getBoundingClientRect(); + return ( + ev.pageX >= rect.left + (cut?.left ?? 0) && + ev.pageX <= rect.right - (cut?.right ?? 0) && + ev.pageY >= rect.top + (cut?.top ?? 0) && + ev.pageY <= rect.bottom - (cut?.bottom ?? 0) + ); +}; + +window.SmartEvent = { + UI: { + MenuTrace: 'SmartEvent-UI-MenuTrace', + RefreshCanvas: 'SmartEvent-UI-RefreshCanvas', + SliceMark: 'SmartEvent-UI-SliceMark', + TimeRange: 'SmartEvent-UI-TimeRange', + TraceRowComplete: 'SmartEvent-UI-TraceRowComplete', + KeyboardEnable: 'SmartEvent-UI-StopWASD', + UploadSOFile: 'SmartEvent-UI-UploadSoFile', + Loading: 'SmartEvent-UI-Loading', + }, +}; +Window.prototype.subscribe = (ev, fn) => EventCenter.subscribe(ev, fn); +Window.prototype.unsubscribe = (ev, fn) => EventCenter.unsubscribe(ev, fn); +Window.prototype.publish = (ev, data) => EventCenter.publish(ev, data); +Window.prototype.subscribeOnce = (ev, data) => EventCenter.subscribeOnce(ev, data); +Window.prototype.clearTraceRowComplete = () => EventCenter.clearTraceRowComplete(); +export {}; diff --git a/ide/src/trace/component/trace/base/RangeSelect.ts b/ide/src/trace/component/trace/base/RangeSelect.ts new file mode 100644 index 0000000000000000000000000000000000000000..47d8b544126211463313471e31778fa580b7ade2 --- /dev/null +++ b/ide/src/trace/component/trace/base/RangeSelect.ts @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2022 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 { RangeSelectStruct, TraceRow } from './TraceRow.js'; +import { Rect } from '../timer-shaft/Rect.js'; +import { ns2x, TimerShaftElement } from '../TimerShaftElement.js'; +import { info } from '../../../../log/Log.js'; +import './Extension.js'; +import { SpSystemTrace } from '../../SpSystemTrace.js'; + +export class RangeSelect { + private rowsEL: HTMLDivElement | undefined | null; + private rowsPaneEL: HTMLDivElement | undefined | null; + private favoriteRowsEL: HTMLDivElement | undefined | null; + isMouseDown: boolean = false; + public rangeTraceRow: Array> | undefined; + public selectHandler: ((ds: Array>, refreshCheckBox: boolean) => void) | undefined; + private startX: number = 0; + private endX: number = 0; + private startY: number = 0; + private endY: number = 0; + private startY2: number = 0; + private endY2: number = 0; + private timerShaftEL: TimerShaftElement | null | undefined; + private timerShaftDragEL: HTMLDivElement | null | undefined; + private isHover: boolean = false; + private movingMark: string = ''; + private mark: { startMark: number; endMark: number } = { + startMark: 0, + endMark: 0, + }; + private readonly spacerEL: HTMLDivElement; + private trace: SpSystemTrace | null | undefined; + drag = false; + constructor(trace: SpSystemTrace | null | undefined) { + this.trace = trace; + this.timerShaftEL = trace?.timerShaftEL; + this.timerShaftDragEL = this.timerShaftEL?.shadowRoot?.querySelector('.total > div:nth-child(1)'); + this.spacerEL = trace?.spacerEL!; + this.rowsEL = trace?.rowsEL; + this.rowsPaneEL = trace?.rowsPaneEL; + this.favoriteRowsEL = trace?.favoriteRowsEL; + } + + isInRowsEl(ev: MouseEvent): boolean { + return this.rowsPaneEL!.containPoint(ev, { left: 248 }); + } + + isInSpacerEL(ev: MouseEvent): boolean { + return this.spacerEL.containPoint(ev, { left: 248 }); + } + + mouseDown(ev: MouseEvent) { + if (this.isHover) { + this.isMouseDown = true; + return; + } + if (this.isInRowsEl(ev)) { + this.rangeTraceRow = []; + this.isMouseDown = true; + TraceRow.rangeSelectObject = undefined; + this.startX = ev.pageX - this.rowsEL!.getBoundingClientRect().left - 248; + if (this.isInSpacerEL(ev)) { + this.startY = 0; + this.startY2 = ev.pageY - this.spacerEL.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } else { + this.startY = + ev.pageY - this.rowsEL!.getBoundingClientRect().top + this.spacerEL.getBoundingClientRect().height; + this.startY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } + } + } + + mouseUp(ev: MouseEvent) { + if (this.drag) { + this.endX = ev.pageX - this.rowsEL!.getBoundingClientRect().left - 248; + if (this.isInSpacerEL(ev)) { + this.endY = 0; + this.endY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } else { + this.endY = ev.pageY - this.rowsEL!.getBoundingClientRect().top + this.spacerEL.getBoundingClientRect().height; + this.endY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } + if (this.selectHandler) { + this.selectHandler(this.rangeTraceRow || [], !this.isHover); + } + } + this.isMouseDown = false; + } + + isDrag(): boolean { + return this.startX != this.endX; + } + + isTouchMark(ev: MouseEvent): boolean { + let notTimeHeight: boolean = this.rowsPaneEL!.containPoint(ev, { + left: 248, + top: -45, + }); + if (!notTimeHeight) { + return false; + } + if ((this.rangeTraceRow?.isEmpty() ?? false) && !this.isMouseDown) { + this.isHover = false; + } + return notTimeHeight && (this.rangeTraceRow?.isNotEmpty() ?? false) && !this.isMouseDown; + } + + mouseOut(ev: MouseEvent) { + if (this.drag) { + this.endX = this.rowsEL!.getBoundingClientRect().right - this.rowsEL!.getBoundingClientRect().left - 248; + if (this.isInSpacerEL(ev)) { + this.endY = 0; + this.endY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } else { + this.endY = ev.pageY - this.rowsEL!.getBoundingClientRect().top + this.spacerEL.getBoundingClientRect().height; + this.endY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } + if (this.selectHandler && this.isMouseDown) { + this.selectHandler(this.rangeTraceRow || [], !this.isHover); + } + } + document.getSelection()?.removeAllRanges(); + this.isMouseDown = false; + } + + mouseMove(rows: Array>, ev: MouseEvent) { + if (this.isTouchMark(ev) && TraceRow.rangeSelectObject) { + info('isTouchMark'); + let x1 = + ((TraceRow.rangeSelectObject!.startNS! - TraceRow.range!.startNS) * + (this.timerShaftEL?.canvas?.clientWidth || 0)) / + (TraceRow.range!.endNS - TraceRow.range!.startNS); + let x2 = + ((TraceRow.rangeSelectObject!.endNS! - TraceRow.range!.startNS) * + (this.timerShaftEL?.canvas?.clientWidth || 0)) / + (TraceRow.range!.endNS - TraceRow.range!.startNS); + this.mark = { startMark: x1, endMark: x2 }; + let mouseX = ev.pageX - this.rowsPaneEL!.getBoundingClientRect().left - 248; + if (mouseX > x1 - 5 && mouseX < x1 + 5) { + this.isHover = true; + document.body.style.cursor = 'ew-resize'; + this.movingMark = x1 < x2 ? 'markA' : 'markB'; + } else if (mouseX > x2 - 5 && mouseX < x2 + 5) { + this.isHover = true; + document.body.style.cursor = 'ew-resize'; + this.movingMark = x2 < x1 ? 'markA' : 'markB'; + } else { + this.isHover = false; + document.body.style.cursor = 'default'; + } + } else { + document.body.style.cursor = 'default'; + } + if (this.isHover && this.isMouseDown) { + let rangeSelect: RangeSelectStruct | undefined; + this.rangeTraceRow = rows.filter((it) => { + if (it.rangeSelect) { + if (!rangeSelect) { + rangeSelect = new RangeSelectStruct(); + let mouseX = ev.pageX - this.rowsEL!.getBoundingClientRect().left - 248; + mouseX = mouseX < 0 ? 0 : mouseX; + let markA = this.movingMark == 'markA' ? mouseX : this.mark.startMark; + let markB = this.movingMark == 'markB' ? mouseX : this.mark.endMark; + let startX = markA < markB ? markA : markB; + let endX = markB < markA ? markA : markB; + rangeSelect.startX = startX; + rangeSelect.endX = endX; + rangeSelect.startNS = Math.floor( + ((TraceRow.range!.endNS - TraceRow.range!.startNS) * startX) / it.frame.width + TraceRow.range!.startNS! + ); + rangeSelect.endNS = Math.floor( + ((TraceRow.range!.endNS - TraceRow.range!.startNS) * endX) / it.frame.width + TraceRow.range!.startNS! + ); + if (rangeSelect.startNS <= TraceRow.range!.startNS) { + rangeSelect.startNS = TraceRow.range!.startNS; + } + if (rangeSelect.endNS >= TraceRow.range!.endNS) { + rangeSelect.endNS = TraceRow.range!.endNS; + } + if (startX < 0) { + rangeSelect.startNS = TraceRow.rangeSelectObject!.startNS!; + } + if (endX > it.frame.width) { + rangeSelect.endNS = TraceRow.rangeSelectObject!.endNS!; + } + } + TraceRow.rangeSelectObject = rangeSelect; + return true; + } + }); + this.timerShaftEL!.sportRuler!.isRangeSelect = (this.rangeTraceRow?.length || 0) > 0; + this.timerShaftEL!.sportRuler!.draw(); + return; + } + if (!this.isMouseDown) { + this.timerShaftEL!.sportRuler!.isRangeSelect = this.rangeTraceRow?.isNotEmpty() ?? false; + this.timerShaftEL!.sportRuler!.draw(); + return; + } + this.endX = ev.pageX - this.rowsEL!.getBoundingClientRect().left - 248; + if (this.isInSpacerEL(ev)) { + this.endY = 0; + this.endY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } else { + this.endY = ev.pageY - this.rowsEL!.getBoundingClientRect().top + this.spacerEL.getBoundingClientRect().height; + this.endY2 = ev.pageY - this.spacerEL!.getBoundingClientRect().top - this.rowsPaneEL!.scrollTop; + } + let scrollTop = this.rowsPaneEL?.scrollTop || 0; + let xMin = this.startX < this.endX ? this.startX : this.endX; + let xMax = this.startX > this.endX ? this.startX : this.endX; + let yMin = this.startY < this.endY ? this.startY : this.endY; + let yMax = this.startY > this.endY ? this.startY : this.endY; + let rangeSelect: RangeSelectStruct | undefined; + let spacerRect = this.favoriteRowsEL!.getBoundingClientRect(); + let rowsRect = this.rowsPaneEL!.getBoundingClientRect(); + this.rangeTraceRow = rows.filter((it) => { + let rt: Rect; + let bound: DOMRect | any; + let itRect: Rect; + if (it.collect) { + bound = it.getBoundingClientRect(); + itRect = Rect.getIntersect(bound, spacerRect); + rt = new Rect(xMin, Math.min(this.startY2, this.endY2), xMax - xMin, Math.abs(this.startY2 - this.endY2)); + } else { + bound = it.getBoundingClientRect(); + if (spacerRect.height > 0 && bound.y + bound.height < spacerRect.y + spacerRect.height) { + it.rangeSelect = false; + return false; + } + itRect = Rect.getIntersect( + bound, + new Rect(rowsRect.x, rowsRect.y + spacerRect.height, rowsRect.width, rowsRect.height - spacerRect.height) + ); + rt = new Rect(xMin, yMin - scrollTop, xMax - xMin, yMax - yMin); + } + itRect.x -= 248; + itRect.y -= 195; + if (Rect.intersect(itRect, rt)) { + if (!rangeSelect) { + it.setTipLeft(0, null); + rangeSelect = new RangeSelectStruct(); + let startX = Math.floor(rt.x <= 0 ? 0 : rt.x); + let endX = Math.floor(rt.x + rt.width > it.frame.width ? it.frame.width : rt.x + rt.width); + rangeSelect.startX = startX; + rangeSelect.endX = endX; + rangeSelect.startNS = Math.floor( + ((TraceRow.range!.endNS - TraceRow.range!.startNS) * startX) / it.frame.width + TraceRow.range!.startNS! + ); + rangeSelect.endNS = Math.floor( + ((TraceRow.range!.endNS - TraceRow.range!.startNS) * endX) / it.frame.width + TraceRow.range!.startNS! + ); + } + TraceRow.rangeSelectObject = rangeSelect; + it.rangeSelect = true; + return true; + } else { + it.rangeSelect = false; + return false; + } + }); + this.timerShaftEL!.sportRuler!.isRangeSelect = this.rangeTraceRow?.length > 0; + this.timerShaftEL!.sportRuler!.draw(); + } +} diff --git a/ide/src/trace/component/trace/base/TraceRow.ts b/ide/src/trace/component/trace/base/TraceRow.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffc52f46111929503bd87191d1c8631d15343d72 --- /dev/null +++ b/ide/src/trace/component/trace/base/TraceRow.ts @@ -0,0 +1,1276 @@ +/* + * Copyright (C) 2022 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 { element } from '../../../../base-ui/BaseElement.js'; +import { TimeRange } from '../timer-shaft/RangeRuler.js'; +import '../../../../base-ui/icon/LitIcon.js'; +import { Rect } from '../timer-shaft/Rect.js'; +import { BaseStruct } from '../../../bean/BaseStruct.js'; +import { SpSystemTrace } from '../../SpSystemTrace.js'; +import { ns2x } from '../TimerShaftElement.js'; +import { TraceRowObject } from './TraceRowObject.js'; +import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox.js'; +import { LitIcon } from '../../../../base-ui/icon/LitIcon'; +import '../../../../base-ui/popover/LitPopoverV.js'; +import { LitPopover } from '../../../../base-ui/popover/LitPopoverV.js'; +import { info } from '../../../../log/Log.js'; +import { ColorUtils } from './ColorUtils.js'; +import { drawSelectionRange } from '../../../database/ui-worker/ProcedureWorkerCommon.js'; + +export class RangeSelectStruct { + startX: number | undefined; + endX: number | undefined; + startNS: number | undefined; + endNS: number | undefined; +} + +let collectList: Array = []; +let rowDragElement: EventTarget | undefined | null; +let dragDirection: string = ''; + +@element('trace-row') +export class TraceRow extends HTMLElement { + static ROW_TYPE_CPU = 'cpu-data'; + static ROW_TYPE_CPU_STATE = 'cpu-state'; + static ROW_TYPE_CPU_FREQ = 'cpu-freq'; + static ROW_TYPE_CPU_FREQ_LIMIT = 'cpu-limit-freq'; + static ROW_TYPE_FPS = 'fps'; + static ROW_TYPE_NATIVE_MEMORY = 'native-memory'; + static ROW_TYPE_HIPERF = 'hiperf'; + static ROW_TYPE_DELIVER_INPUT_EVENT = 'DeliverInputEvent'; + static ROW_TYPE_HIPERF_CPU = 'hiperf-cpu'; + static ROW_TYPE_HIPERF_PROCESS = 'hiperf-process'; + static ROW_TYPE_HIPERF_THREAD = 'hiperf-thread'; + static ROW_TYPE_HIPERF_REPORT = 'hiperf-report'; + static ROW_TYPE_HIPERF_EVENT = 'hiperf-event'; + static ROW_TYPE_PROCESS = 'process'; + static ROW_TYPE_THREAD = 'thread'; + static ROW_TYPE_MEM = 'mem'; + static ROW_TYPE_VIRTUAL_MEMORY_GROUP = 'virtual-memory-group'; + static ROW_TYPE_VIRTUAL_MEMORY = 'virtual-memory-cell'; + static ROW_TYPE_FILE_SYSTEM_GROUP = 'file-system-group'; + static ROW_TYPE_FILE_SYSTEM = 'file-system-cell'; + static ROW_TYPE_HEAP = 'heap'; + static ROW_TYPE_JS_MEMORY = 'js-memory'; + static ROW_TYPE_HEAP_SNAPSHOT = 'heap-snapshot'; + static ROW_TYPE_HEAP_TIMELINE = 'heap-timeline'; + static ROW_TYPE_FUNC = 'func'; + static ROW_TYPE_MONITOR = 'ability-monitor'; + static ROW_TYPE_CPU_ABILITY = 'cpu-ability'; + static ROW_TYPE_MEMORY_ABILITY = 'memory-ability'; + static ROW_TYPE_DISK_ABILITY = 'disk-ability'; + static ROW_TYPE_NETWORK_ABILITY = 'network-ability'; + static ROW_TYPE_SDK = 'sdk'; + static ROW_TYPE_SDK_COUNTER = 'sdk-counter'; + static ROW_TYPE_SDK_SLICE = 'sdk-slice'; + static ROW_TYPE_ENERGY = 'energy'; + static ROW_TYPE_ANOMALY_ENERGY = 'anomaly-energy'; + static ROW_TYPE_SYSTEM_ENERGY = 'system-energy'; + static ROW_TYPE_POWER_ENERGY = 'power-energy'; + static ROW_TYPE_STATE_ENERGY = 'state-energy'; + static ROW_TYPE_SMAPS = 'smaps'; + static ROW_TYPE_CLOCK_GROUP = 'clock-group'; + static ROW_TYPE_CLOCK = 'clock'; + static ROW_TYPE_IRQ_GROUP = 'irq-group'; + static ROW_TYPE_IRQ = 'irq'; + static ROW_TYPE_JANK = 'janks'; + static range: TimeRange | undefined | null; + static rangeSelectObject: RangeSelectStruct | undefined; + public obj: TraceRowObject | undefined | null; + isHover: boolean = false; + hoverX: number = 0; + hoverY: number = 0; + index: number = 0; + public must: boolean = false; + public isTransferCanvas = false; + onComplete: Function | undefined; + isComplete: boolean = false; + public dataList: Array = []; + public dataList2: Array = []; + public dataListCache: Array = []; + public describeEl: HTMLElement | null | undefined; + public canvas: Array = []; + public canvasContainer: HTMLDivElement | null | undefined; + public tipEL: HTMLDivElement | null | undefined; + public checkBoxEL: LitCheckBox | null | undefined; + public collectEL: LitIcon | null | undefined; + public onThreadHandler: ((useCache: boolean, buf: ArrayBuffer | undefined | null) => void) | undefined | null; + public onDrawTypeChangeHandler: ((type: number) => void) | undefined | null; + public supplier: (() => Promise>) | undefined | null; + public favoriteChangeHandler: ((fav: TraceRow) => void) | undefined | null; + public selectChangeHandler: ((list: Array>) => void) | undefined | null; + dpr = window.devicePixelRatio || 1; + // @ts-ignore + offscreen: Array = []; + canvasWidth = 0; + canvasHeight = 0; + public _frame: Rect | undefined; + public isLoading: boolean = false; + public readonly args: any; + private rootEL: HTMLDivElement | null | undefined; + private nameEL: HTMLLabelElement | null | undefined; + private _rangeSelect: boolean = false; + private _drawType: number = 0; + private folderIconEL: LitIcon | null | undefined; + online: boolean = false; + static isUserInteraction: boolean; + asyncFuncName: string | undefined | null; + asyncFuncNamePID: number | undefined | null; + translateY: number = 0; //single canvas offsetY; + childrenList: Array> = []; + depth: number = 1; + focusHandler?: (ev: MouseEvent) => void | undefined; + + constructor( + args: { + canvasNumber: number; + alpha: boolean; + contextId: string; + isOffScreen: boolean; + skeleton?: boolean; + } = { + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: true, + skeleton: false, + } + ) { + super(); + this.args = args; + this.attachShadow({ mode: 'open' }).innerHTML = this.initHtml(); + this.initElements(); + } + + static skeleton(): TraceRow { + let tr = new TraceRow({ + alpha: false, + canvasNumber: 0, + contextId: '', + isOffScreen: false, + skeleton: true, + }); + tr.isTransferCanvas = true; + return tr; + } + + static get observedAttributes() { + return [ + 'folder', + 'name', + 'expansion', + 'children', + 'height', + 'row-type', + 'row-id', + 'row-parent-id', + 'sleeping', + 'check-type', + 'collect-type', + 'disabled-check', + 'row-discard', + ]; + } + + get rowDiscard(): boolean { + return this.hasAttribute('row-discard'); + } + + set rowDiscard(value: boolean) { + if (value) { + this.setAttribute('row-discard', ''); + this.style.display = 'none'; + } else { + this.removeAttribute('row-discard'); + this.style.display = 'block'; + } + } + + get collect() { + return this.hasAttribute('collect-type'); + } + + set collect(value) { + if (value) { + this.setAttribute('collect-type', ''); + } else { + this.removeAttribute('collect-type'); + } + } + + get rangeSelect(): boolean { + return this._rangeSelect; + } + + set rangeSelect(value: boolean) { + this._rangeSelect = value; + } + + sleeping: boolean = false; + + get rowType(): string | undefined | null { + return this.getAttribute('row-type'); + } + + set rowType(val) { + this.setAttribute('row-type', val || ''); + } + + get rowId(): string | undefined | null { + return this.getAttribute('row-id'); + } + + set rowId(val) { + this.setAttribute('row-id', val || ''); + } + + get rowParentId(): string | undefined | null { + return this.getAttribute('row-parent-id'); + } + + set rowParentId(val) { + this.setAttribute('row-parent-id', val || ''); + } + + set rowHidden(val: boolean) { + if (val) { + this.setAttribute('row-hidden', ''); + } else { + this.removeAttribute('row-hidden'); + } + } + + get name(): string { + return this.getAttribute('name') || ''; + } + + set name(value: string) { + this.setAttribute('name', value); + } + + get folder(): boolean { + return this.hasAttribute('folder'); + } + + set folder(value: boolean) { + if (value) { + this.setAttribute('folder', ''); + } else { + this.removeAttribute('folder'); + } + } + + get expansion(): boolean { + return this.hasAttribute('expansion'); + } + + set expansion(value) { + if (value === this.expansion) { + return; + } + if (value) { + let fragment = document.createDocumentFragment(); + this.childrenList.forEach((child: any) => { + child.rowHidden = false; + fragment.appendChild(child); + }); + this.insertAfter(fragment, this); + } else { + let fragment = document.createDocumentFragment(); + this.childrenList.length = 0; + this.parentElement?.querySelectorAll(`[row-parent-id='${this.rowId!}']`).forEach((it) => { + this.childrenList.push(it); + if (it.folder) { + it.expansion = value; + } + fragment.appendChild(it); + }); + } + if (value) { + this.setAttribute('expansion', ''); + } else { + this.removeAttribute('expansion'); + } + this.dispatchEvent( + new CustomEvent('expansion-change', { + detail: { + expansion: this.expansion, + rowType: this.rowType, + rowId: this.rowId, + rowParentId: this.rowParentId, + }, + }) + ); + } + + addChildTraceRow(child: TraceRow) { + this.depth = 2; + if (child.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) { + this.depth = 3; + } + this.childrenList.push(child); + } + + addChildTraceRowAfter(child: TraceRow, targetRow: TraceRow) { + this.depth = 2; + let index = this.childrenList.indexOf(targetRow); + if (index != -1) { + this.childrenList.splice(index + 1, 0, child); + } else { + this.childrenList.push(child); + } + } + + addChildTraceRowSpecifyLocation(child: TraceRow, index: number) { + this.childrenList.splice(index, 0, child); + } + insertAfter(newEl: DocumentFragment, targetEl: HTMLElement) { + let parentEl = targetEl.parentNode; + if (parentEl!.lastChild == targetEl) { + parentEl!.appendChild(newEl); + } else { + parentEl!.insertBefore(newEl, targetEl.nextSibling); + } + } + + set tip(value: string) { + if (this.tipEL) { + this.tipEL.innerHTML = value; + } + } + + get frame(): Rect | any { + if (this._frame) { + this._frame.width = (this.parentElement?.clientWidth || 0) - 248 - SpSystemTrace.scrollViewWidth; + this._frame.height = this.clientHeight; + return this._frame; + } else { + this._frame = new Rect( + 0, + 0, + (this.parentElement?.clientWidth || 0) - 248 - SpSystemTrace.scrollViewWidth, + this.clientHeight || 40 + ); + return this._frame; + } + } + + set frame(f: Rect) { + this._frame = f; + } + + get disabledCheck(): boolean { + return this.hasAttribute('disabled-check'); + } + + set disabledCheck(value: boolean) { + if (value) { + this.setAttribute('disabled-check', ''); + this.checkBoxEL!.style.display = 'none'; + } else { + this.removeAttribute('disabled-check'); + this.checkBoxEL!.style.display = 'flex'; + } + } + + get checkType(): string { + return this.getAttribute('check-type') || ''; + } + + set checkType(value: string) { + if (!value || value.length == 0) { + this.removeAttribute('check-type'); + return; + } + this.setAttribute('check-type', value); + if (this.hasAttribute('disabled-check')) { + this.checkBoxEL!.style.display = 'none'; + return; + } + switch (value) { + case '-1': + this.checkBoxEL!.style.display = 'none'; + this.rangeSelect = false; + break; + case '0': + this.checkBoxEL!.style.display = 'flex'; + this.checkBoxEL!.checked = false; + this.checkBoxEL!.indeterminate = false; + this.rangeSelect = false; + break; + case '1': + this.checkBoxEL!.style.display = 'flex'; + this.checkBoxEL!.checked = false; + this.checkBoxEL!.indeterminate = true; + this.rangeSelect = false; + break; + case '2': + this.rangeSelect = true; + this.checkBoxEL!.style.display = 'flex'; + this.checkBoxEL!.checked = true; + this.checkBoxEL!.indeterminate = false; + break; + } + } + + get drawType(): number { + return this._drawType; + } + + set drawType(value: number) { + this._drawType = value; + let radioList: NodeListOf = this.shadowRoot!.querySelectorAll('input[type=radio][name=status]'); + if (radioList!.length > 0) { + radioList[Number(value)].checked = true; + } + } + + get highlight(): boolean { + return this.hasAttribute('expansion'); + } + + set highlight(value: boolean) { + if (value) { + this.setAttribute('highlight', ''); + } else { + this.removeAttribute('highlight'); + } + } + + set folderPaddingLeft(value: number) { + this.folderIconEL!.style.marginLeft = value + 'px'; + } + + initElements(): void { + this.rootEL = this.shadowRoot?.querySelector('.root'); + this.checkBoxEL = this.shadowRoot?.querySelector('.lit-check-box'); + this.collectEL = this.shadowRoot?.querySelector('.collect'); + this.describeEl = this.shadowRoot?.querySelector('.describe'); + this.folderIconEL = this.shadowRoot?.querySelector('.icon'); + this.nameEL = this.shadowRoot?.querySelector('.name'); + this.canvasContainer = this.shadowRoot?.querySelector('.panel-container'); + this.tipEL = this.shadowRoot?.querySelector('.tip'); + let canvasNumber = this.args['canvasNumber']; + if (!this.args['skeleton']) { + for (let i = 0; i < canvasNumber; i++) { + let canvas = document.createElement('canvas'); + canvas.className = 'panel'; + this.canvas.push(canvas); + if (this.canvasContainer) { + this.canvasContainer.appendChild(canvas); + } + } + } + this.describeEl?.addEventListener('click', () => { + if (this.folder) { + this.expansion = !this.expansion; + } + }); + } + + initCanvas(list: Array): void { + let timerShaftEL = document! + .querySelector('body > sp-application')! + .shadowRoot!.querySelector('#sp-system-trace')! + .shadowRoot!.querySelector('div > timer-shaft-element'); + let timerShaftCanvas = timerShaftEL!.shadowRoot!.querySelector('canvas'); + let tempHeight: number = 0; + if (this.rowType == TraceRow.ROW_TYPE_FUNC) { + tempHeight = 20; + } else if (this.rowType == TraceRow.ROW_TYPE_THREAD) { + tempHeight = 30; + } else if (this.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) { + tempHeight = 80; + } else if (this.rowType == TraceRow.ROW_TYPE_POWER_ENERGY) { + tempHeight = 200; + } else if (this.rowType == TraceRow.ROW_TYPE_ANOMALY_ENERGY) { + tempHeight = 55; + } else { + tempHeight = 40; + } + this.dpr = window.devicePixelRatio || 1; + list.forEach((canvas, i) => { + this.rootEL!.style.height = `${this.getAttribute('height') || '40'}px`; + canvas.style.width = timerShaftCanvas!.style.width; + canvas.style.height = tempHeight + 'px'; + this.canvasWidth = timerShaftCanvas!.width; + this.canvasHeight = Math.ceil(tempHeight * this.dpr); + canvas.width = this.canvasWidth; + canvas.height = this.canvasHeight; + // @ts-ignore + this.offscreen.push(canvas!.transferControlToOffscreen()); + }); + } + + updateWidth(width: number) { + this.dpr = window.devicePixelRatio || 1; + let tempHeight: number = 0; + if (this.rowType == TraceRow.ROW_TYPE_FUNC) { + tempHeight = 20; + } else if (this.rowType == TraceRow.ROW_TYPE_THREAD) { + tempHeight = 30; + } else if (this.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) { + tempHeight = 90; + } else if (this.rowType == TraceRow.ROW_TYPE_POWER_ENERGY) { + tempHeight = 200; + } else if (this.rowType == TraceRow.ROW_TYPE_ANOMALY_ENERGY) { + tempHeight = 55; + } else { + tempHeight = 40; + } + if (this.canvas.length > 1) { + tempHeight = 20; + } + this.canvas.forEach((it) => { + this.canvasWidth = Math.ceil((width - (this.describeEl?.clientWidth || 248)) * this.dpr); + this.canvasHeight = Math.ceil(tempHeight * this.dpr); + it!.style.width = width - (this.describeEl?.clientWidth || 248) + 'px'; + if (this.args.isOffScreen) { + this.draw(true); + } + }); + } + + drawLine(item: HTMLDivElement, direction: string /*string[top|bottom]*/) { + if (!item) return; + switch (direction) { + case 'top': + item.classList.remove('line-bottom'); + item.classList.add('line-top'); + break; + case 'bottom': + item.classList.remove('line-top'); + item.classList.add('line-bottom'); + break; + case '': + item.classList.remove('line-top'); + item.classList.remove('line-bottom'); + break; + } + } + + connectedCallback() { + this.checkBoxEL!.onchange = (ev: any) => { + info('checkBoxEL onchange '); + if (!ev.target.checked) { + info('checkBoxEL target not checked'); + this.rangeSelect = false; + this.checkType = '0'; + this.draw(); + } else { + this.rangeSelect = true; + this.checkType = '2'; + this.draw(); + } + this.setCheckBox(ev.target.checked); + }; + this.describeEl!.ondragstart = (ev: DragEvent) => this.rowDragstart(ev); + this.describeEl!.ondragleave = (ev: any) => { + this.drawLine(ev.currentTarget, ''); + return undefined; + }; + this.describeEl!.ondragend = (ev: any) => { + rowDragElement = null; + ev.target.classList.remove('drag'); + this.drawLine(ev.currentTarget, ''); + return undefined; + }; + this.describeEl!.ondragover = (ev: any) => { + if (!this.collect) return; + if (rowDragElement === this) return; + let rect = ev.currentTarget.getBoundingClientRect(); + if (ev.clientY >= rect.top && ev.clientY < rect.top + rect.height / 2) { + //上面 + dragDirection = 'top'; + this.drawLine(ev.currentTarget, 'top'); + } else if (ev.clientY <= rect.bottom && ev.clientY > rect.top + rect.height / 2) { + //下面 + dragDirection = 'bottom'; + this.drawLine(ev.currentTarget, 'bottom'); + } + return undefined; + }; + this.describeEl!.ondrop = (ev: any) => { + if (!this.collect) return; + this.drawLine(ev.currentTarget, ''); + let spacer = this.parentElement!.previousElementSibling! as HTMLDivElement; + let startDragNode = collectList.findIndex((it) => it === rowDragElement); + let endDragNode = collectList.findIndex((it) => it === this); + if (startDragNode === -1 || endDragNode === -1) return; + if (startDragNode < endDragNode && dragDirection === 'top') { + endDragNode--; + } else if (startDragNode > endDragNode && dragDirection === 'bottom') { + endDragNode++; + } + collectList.splice(endDragNode, 0, ...collectList.splice(startDragNode, 1)); + collectList.forEach((it, i) => { + if (i == 0) { + it.style.top = `${spacer.offsetTop + 48}px`; + } else { + it.style.top = `${collectList[i - 1].offsetTop + collectList[i - 1].offsetHeight}px`; + } + }); + }; + this.collectEL!.onclick = (e) => { + this.collect = !this.collect; + if (this.collect) { + this.describeEl!.draggable = false; + } else { + this.describeEl!.draggable = false; + } + document.dispatchEvent( + new CustomEvent('collect', { + detail: { + type: e.type, + row: this, + }, + }) + ); + this.favoriteChangeHandler?.(this); + }; + if (!this.args['skeleton']) { + this.initCanvas(this.canvas); + } + let radioList = this.shadowRoot!.querySelectorAll('input[type=radio][name=status]'); + let popover = this.shadowRoot!.querySelector('.popover'); + this.shadowRoot?.querySelector('#first-radio')?.addEventListener('click', (e) => { + // @ts-ignore + radioList[0]!.checked = true; + // @ts-ignore + popover!.visible = false; + setTimeout(() => { + this.onDrawTypeChangeHandler?.(0); + }, 300); + }); + this.shadowRoot?.querySelector('#second-radio')?.addEventListener('click', (e) => { + // @ts-ignore + radioList[1]!.checked = true; + // @ts-ignore + popover!.visible = false; + setTimeout(() => { + this.onDrawTypeChangeHandler?.(1); + }, 300); + }); + } + + rowDragstart(ev: any) { + rowDragElement = this; + ev.target.classList.add('drag'); + } + + setCheckBox(isCheck: boolean) { + if (this.folder) { + this.childrenList!.forEach((ck) => { + ck.setAttribute('check-type', isCheck ? '2' : '0'); + let allCheck: LitCheckBox | null | undefined = ck?.shadowRoot?.querySelector('.lit-check-box'); + allCheck!.checked = isCheck; + }); + } else if (this.rowParentId == '' && !this.folder) { + let traceRowList: Array> = []; + this.parentElement!.parentElement!.querySelectorAll>("trace-row[check-type='2'][folder]").forEach( + (it) => { + traceRowList.push( + ...it.childrenList.filter((it) => { + return it.checkType === '2'; + }) + ); + } + ); + this.selectChangeHandler?.([ + ...this.parentElement!.querySelectorAll>("trace-row[check-type='2']"), + ...traceRowList, + ]); + return; + } + let checkList = this.parentElement!.parentElement!.querySelectorAll>( + `trace-row[row-parent-id='${this.folder ? this.rowId : this.rowParentId}'][check-type="2"]` + ); + let checkList2: Array> = []; + if (this.folder && !this.expansion) { + checkList2 = this.childrenList.filter((it) => { + return it.checkType === '2'; + }); + } + let unselectedList = this.parentElement!.parentElement!.querySelectorAll>( + `trace-row[row-parent-id='${this.folder ? this.rowId : this.rowParentId}'][check-type="0"]` + ); + let unselectedList2: Array> = []; + if (this.folder && !this.expansion) { + unselectedList2 = this.childrenList.filter((it) => { + return it.checkType === '0'; + }); + } + let parentRow = this.parentElement?.querySelector>( + `trace-row[row-id='${this.folder ? this.rowId : this.rowParentId}'][folder]` + ); + let parentCheck: LitCheckBox | null | undefined = parentRow?.shadowRoot?.querySelector('.lit-check-box'); + if (unselectedList?.length == 0 && unselectedList.length === 0) { + parentRow?.setAttribute('check-type', '2'); + if (parentCheck) { + parentCheck!.checked = true; + parentCheck!.indeterminate = false; + } + checkList?.forEach((it) => { + it.checkType = '2'; + it.rangeSelect = true; + it.draw(); + }); + checkList2?.forEach((it) => { + it.checkType = '2'; + it.rangeSelect = true; + it.draw(); + }); + } else { + parentRow?.setAttribute('check-type', '1'); + if (parentCheck) { + parentCheck!.checked = false; + parentCheck!.indeterminate = true; + } + checkList?.forEach((it) => { + it.checkType = '2'; + it.rangeSelect = true; + it.draw(); + }); + checkList2?.forEach((it) => { + it.checkType = '2'; + it.rangeSelect = true; + it.draw(); + }); + unselectedList?.forEach((it) => { + it.checkType = '0'; + it.rangeSelect = false; + it.draw(); + }); + unselectedList2?.forEach((it) => { + it.checkType = '0'; + it.rangeSelect = false; + it.draw(); + }); + } + + if (checkList?.length == 0 && checkList2?.length === 0) { + parentRow?.setAttribute('check-type', '0'); + if (parentCheck) { + parentCheck!.checked = false; + parentCheck!.indeterminate = false; + } + unselectedList?.forEach((it) => { + it.checkType = '0'; + it.rangeSelect = false; + it.draw(); + }); + unselectedList2?.forEach((it) => { + it.checkType = '0'; + it.rangeSelect = false; + it.draw(); + }); + } + let traceRowList: Array> = []; + this.parentElement!.parentElement!.querySelectorAll>("trace-row[check-type='2'][folder]").forEach( + (it) => { + traceRowList.push( + ...it.childrenList.filter((it) => { + return it.checkType === '2'; + }) + ); + } + ); + this.selectChangeHandler?.([ + ...this.parentElement!.parentElement!.querySelectorAll>("trace-row[check-type='2']"), + ...traceRowList, + ]); + } + + onMouseHover(x: number, y: number, tip: boolean = true): T | undefined | null { + if (this.tipEL) { + this.tipEL.style.display = 'none'; + } + return null; + } + + setTipLeft(x: number, struct: any) { + if (struct == null && this.tipEL) { + this.tipEL.style.display = 'none'; + return; + } + if (this.tipEL) { + this.tipEL.style.display = 'flex'; + if (x + this.tipEL.clientWidth > (this.canvasContainer!.clientWidth || 0)) { + this.tipEL.style.transform = `translateX(${x - this.tipEL.clientWidth - 1}px)`; + } else { + this.tipEL.style.transform = `translateX(${x}px)`; + } + } + } + + onMouseLeave(x: number, y: number) { + if (this.tipEL) { + this.tipEL.style.display = 'none'; + } + } + + draw(useCache: boolean = false) { + this.dpr = window.devicePixelRatio || 1; + if (this.sleeping) { + return; + } + if (this.online) { + if (!useCache && !TraceRow.isUserInteraction) { + this.supplier?.().then((res) => { + this.onThreadHandler?.(useCache, res as any); + }); + } + this.onThreadHandler?.(useCache, null); + return; + } + if (!this.isComplete) { + if (this.supplier && !this.isLoading) { + this.isLoading = true; + this.must = true; + if (this.supplier) { + let promise = this.supplier(); + if (promise) { + promise.then((res) => { + this.dataList = res; + if (this.onComplete) { + this.onComplete(); + } + window.publish(window.SmartEvent.UI.TraceRowComplete, this); + this.isComplete = true; + this.isLoading = false; + this.draw(false); + }); + } else { + this.isLoading = false; + this.draw(false); + } + } + } + } else { + if (!this.hasAttribute('row-hidden')) { + if (this.onThreadHandler && this.dataList) { + this.onThreadHandler!(false, null); + } + } + } + } + + canvasSave(ctx: CanvasRenderingContext2D) { + ctx.save(); + ctx.translate(0, this.translateY); + const clipRect = new Path2D(); + clipRect.rect(0, 0, this.frame.width, this.frame.height); + ctx.clip(clipRect); + } + + canvasRestore(ctx: CanvasRenderingContext2D) { + drawSelectionRange(ctx, this); + ctx.restore(); + } + + clearCanvas(ctx: CanvasRenderingContext2D) { + if (ctx) { + this.canvas.forEach((it) => { + ctx.clearRect(0, 0, it!.clientWidth || 0, it!.clientHeight || 0); + }); + } + } + + drawLines(ctx: CanvasRenderingContext2D) { + if (ctx) { + ctx.lineWidth = 1; + ctx.strokeStyle = this.getLineColor(); + TraceRow.range?.xs.forEach((it) => { + ctx.moveTo(Math.floor(it), 0); + ctx.lineTo(Math.floor(it), this.shadowRoot?.host.clientHeight || 0); + }); + ctx.stroke(); + } + } + + getLineColor() { + return window.getComputedStyle(this.rootEL!, null).getPropertyValue('border-bottom-color'); + } + + drawSelection(ctx: CanvasRenderingContext2D) { + if (this.rangeSelect) { + TraceRow.rangeSelectObject!.startX = Math.floor( + ns2x( + TraceRow.rangeSelectObject!.startNS!, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS!, + this.frame + ) + ); + TraceRow.rangeSelectObject!.endX = Math.floor( + ns2x( + TraceRow.rangeSelectObject!.endNS!, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS!, + this.frame + ) + ); + if (ctx) { + ctx.globalAlpha = 0.5; + ctx.fillStyle = '#666666'; + ctx.fillRect( + TraceRow.rangeSelectObject!.startX!, + this.frame.y, + TraceRow.rangeSelectObject!.endX! - TraceRow.rangeSelectObject!.startX!, + this.frame.height + ); + ctx.globalAlpha = 1; + } + } + } + + isInTimeRange(startTime: number, duration: number): boolean { + return ( + (startTime || 0) + (duration || 0) > (TraceRow.range?.startNS || 0) && + (startTime || 0) < (TraceRow.range?.endNS || 0) + ); + } + + buildArgs(obj: any) { + let result: any = { + list: this.must ? this.dataList : undefined, + offscreen: !this.isTransferCanvas ? this.offscreen[0] : undefined, //是否离屏 + dpr: this.dpr, //屏幕dpr值 + xs: TraceRow.range?.xs, //线条坐标信息 + isHover: this.isHover, + hoverX: this.hoverX, + hoverY: this.hoverY, + canvasWidth: this.canvasWidth, + canvasHeight: this.canvasHeight, + isRangeSelect: this.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + lineColor: this.getLineColor(), + chartColor: ColorUtils.MD_PALETTE[0], + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime: TraceRow.range?.slicesTime, + range: TraceRow.range, + frame: this.frame, + flagMoveInfo: null, + flagSelectedInfo: null, + wakeupBean: null, + }; + Reflect.ownKeys(obj).forEach((it) => { + result[it] = obj[it]; + }); + return result; + } + + getTransferArray() { + let tsf = []; + if (!this.isTransferCanvas) { + tsf.push(this.offscreen[0]); + } + if (this.must && this.dataList instanceof ArrayBuffer) { + tsf.push(this.dataList); + } + return tsf; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case 'name': + if (this.nameEL) { + this.nameEL.textContent = newValue; + this.nameEL.title = newValue; + } + break; + case 'height': + if (newValue != oldValue) { + if (!this.args.isOffScreen) { + } + } + break; + case 'check-type': + if (newValue === 'check') { + this.checkBoxEL?.setAttribute('checked', ''); + } else { + this.checkBoxEL?.removeAttribute('checked'); + } + break; + } + } + + focusContain(e: MouseEvent): boolean { + let _y = (e.currentTarget as HTMLElement).getBoundingClientRect().y; + let myRect = this.getBoundingClientRect(); + let x = e.offsetX; + let y = e.offsetY + _y; + if (x >= myRect.x && x <= myRect.x + myRect.width && y >= myRect.y && y <= myRect.y + myRect.height) { + this.hoverX = x - this.describeEl!.clientWidth; + this.hoverY = y - myRect.y; + this.isHover = true; + return true; + } else { + this.isHover = false; + if (this.tipEL) { + this.tipEL.style.display = 'none'; + } + return false; + } + } + + initHtml(): string { + return ` + +
+
+ + + + +
+
+ Current Bytes
+
+ Native Memory Density
+
+ +
+ +
+
+ +
+ +
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/base/TraceRowConfig.ts b/ide/src/trace/component/trace/base/TraceRowConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9397ddb69a9a1c69d2e68e4c52bcca282c49544 --- /dev/null +++ b/ide/src/trace/component/trace/base/TraceRowConfig.ts @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import '../../../../base-ui/checkbox/LitCheckBox.js'; +import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox.js'; +import { TraceRow } from './TraceRow.js'; +import { SpSystemTrace } from '../../SpSystemTrace.js'; +import { LitSearch } from '../search/Search.js'; +import { TraceSheet } from './TraceSheet.js'; +import { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js'; + +@element('trace-row-config') +export class TraceRowConfig extends BaseElement { + selectTypeList: Array | undefined; + private spSystemTrace: SpSystemTrace | null | undefined; + private sceneTable: HTMLDivElement | null | undefined; + private chartTable: HTMLDivElement | null | undefined; + private inputElement: HTMLInputElement | null | undefined; + private allTraceRowList: any; + private traceRowList: NodeListOf> | undefined; + private selectTypeMap: any = {}; + private selectTypeOption: any = {}; + private sceneRowList: any; + + get value() { + return this.getAttribute('value') || ''; + } + + set value(value: string) { + this.setAttribute('value', value); + } + + static get observedAttributes() { + return ['mode']; + } + + init() { + let sceneList = [ + { + title: 'Frame timeline', + name: 'janks', + }, + ]; + this.sceneRowList = []; + this.selectTypeList = []; + this.sceneTable!.innerHTML = ''; + this.chartTable!.innerHTML = ''; + this.allTraceRowList = []; + this.spSystemTrace = this.parentElement!.querySelector('sp-system-trace'); + let parentRows = + this.spSystemTrace!.shadowRoot?.querySelector('div[class=rows]')!.querySelectorAll>('trace-row[row-parent-id=""]'); + if (parentRows && parentRows.length > 0) { + parentRows.forEach((traceRow: TraceRow) => { + let temporaryRows: Array> = traceRow.childrenList; + let temporary: Array> = []; + traceRow.setAttribute('scene', ''); + this.allTraceRowList.push(traceRow); + for (let index = 1; index < traceRow.depth; index++) { + temporary = []; + for (let childIndex = 0; childIndex < temporaryRows.length; childIndex++) { + let childrenListEl = temporaryRows[childIndex]; + childrenListEl.setAttribute('scene', ''); + this.allTraceRowList.push(childrenListEl); + if (1 !== childrenListEl.depth) { + temporary.push(...childrenListEl.childrenList); + } + if (childIndex === temporaryRows.length - 1) { + temporaryRows = []; + temporaryRows.push(...temporary); + } + } + } + }) + } + this.traceRowList = + this.spSystemTrace!.shadowRoot?.querySelector('div[class=rows-pane]')!.querySelectorAll>( + "trace-row[row-parent-id='']" + ); + if (this.traceRowList) { + this.traceRowList!.forEach((it) => { + this.initConfigChartTable(it); + }); + } + sceneList!.forEach((it) => { + let sceneTraceRowList = this.spSystemTrace!.shadowRoot?.querySelector('div[class=rows]')!.querySelector< + TraceRow + >(`trace-row[row-type=${it.name}]`); + if (sceneTraceRowList) { + this.initConfigSceneTable(it); + let parentRow: any = {}; + let selectParentOption: any = {}; + let selectParentRow: any = {}; + this.allTraceRowList!.forEach((traceRow: TraceRow) => { + if (traceRow) { + if (traceRow.rowParentId == '') { + parentRow['parent'] = traceRow; + } + if (traceRow.rowType == it.name && !selectParentRow[traceRow.rowParentId!]) { + selectParentOption[traceRow.rowParentId!] = parentRow['parent'].name; + selectParentRow[traceRow.rowParentId!] = parentRow['parent']; + } + } + }); + // @ts-ignore + this.selectTypeMap[it.name] = Object.values(selectParentRow); + // @ts-ignore + this.selectTypeOption[it.name] = Object.values(selectParentOption); + } + }); + } + + initConfigSceneTable(item: any) { + let div = document.createElement('div'); + div.className = 'scene-option-div'; + div.textContent = item.title; + let optionCheckBox: LitCheckBox = new LitCheckBox(); + optionCheckBox.checked = false; + optionCheckBox.style.justifySelf = 'center'; + optionCheckBox.style.height = '100%'; + optionCheckBox.title = item.title; + optionCheckBox.setAttribute('rowType', item.name); + optionCheckBox.addEventListener('change', (e) => { + this.resetChartOption(item, optionCheckBox.checked); + this.resetChartTable(item, optionCheckBox.checked); + }); + this.sceneTable?.append(...[div, optionCheckBox]); + } + + initConfigChartTable(row: TraceRow) { + let div = document.createElement('div'); + div.className = 'chart-option-div chart-item'; + div.textContent = row.name; + div.title = row.name; + let optionCheckBox: LitCheckBox = new LitCheckBox(); + optionCheckBox.checked = true; + optionCheckBox.className = 'chart-config-check chart-item'; + optionCheckBox.style.height = '100%'; + optionCheckBox.style.justifySelf = 'center'; + optionCheckBox.title = row.name; + optionCheckBox.setAttribute('rowType', row.rowType || ''); + optionCheckBox.addEventListener('change', (e) => { + if (optionCheckBox.checked) { + row.removeAttribute('row-hidden'); + row.setAttribute('scene', ''); + this.resetChildRowModel(row, true, false); + if (this.spSystemTrace!.collectRows.length > 0) { + this.spSystemTrace!.collectRows.forEach((collectRow) => { + let isParentRow = row.folder ? collectRow.rowParentId === row.rowId : collectRow.rowId === row.rowId; + if (isParentRow) { + collectRow.removeAttribute('row-hidden'); + collectRow.setAttribute('scene', ''); + } + }); + } + } else { + if (row.rowParentId == '') { + row.expansion = false; + } + row.setAttribute('row-hidden', ''); + row.removeAttribute('scene'); + this.resetChildRowModel(row, false, true); + if (this.spSystemTrace!.collectRows.length > 0) { + this.spSystemTrace!.collectRows.forEach((collectRow) => { + let isParentRow = row.folder ? collectRow.rowParentId === row.rowId : collectRow.rowId === row.rowId; + if (isParentRow) { + collectRow.removeAttribute('scene'); + collectRow.setAttribute('row-hidden', ''); + } + }); + } + } + this.refreshSystemPanel(); + }); + this.chartTable!.append(...[div, optionCheckBox]); + } + + resetChartOption(item: any, isCheck: boolean) { + if (isCheck) { + this.selectTypeOption[item.name].forEach((selectName: any) => { + this.selectTypeList!.push(selectName); + }); + } else { + this.selectTypeOption[item.name].forEach((name: any) => { + let selectIndex = this.selectTypeList!.indexOf(name); + delete this.selectTypeList![selectIndex]; + }); + } + this.selectTypeList = this.selectTypeList!.filter((selectName) => selectName != ''); + this.shadowRoot!.querySelectorAll('.chart-item').forEach((litCheckBox: LitCheckBox) => { + if (this.selectTypeList!.length > 0) { + litCheckBox.checked = this.selectTypeList!.indexOf(litCheckBox.title) > -1; + } else { + litCheckBox.checked = true; + } + }); + } + + resetChartTable(item: any, isCheck: boolean) { + let favoriteRowList = this.spSystemTrace?.favoriteRowsEL?.querySelectorAll>('trace-row'); + if (this.selectTypeList!.length > 0) { + this.traceRowList!.forEach((traceRow) => { + if (this.selectTypeList!.indexOf(traceRow.name) > -1) { + traceRow.removeAttribute('row-hidden'); + this.resetChildRowModel(traceRow, true, false); + } else { + traceRow.setAttribute('row-hidden', ''); + if (traceRow.expansion) { + traceRow.removeAttribute('expansion'); + } + this.resetChildRowModel(traceRow, false, true); + } + }); + favoriteRowList!.forEach((traceRow) => { + if (traceRow.rowType == item.name) { + traceRow.removeAttribute('row-hidden'); + if (isCheck) { + traceRow.setAttribute('scene', ''); + } else { + traceRow.removeAttribute('scene'); + } + } else { + traceRow.setAttribute('row-hidden', ''); + if (isCheck) { + traceRow.removeAttribute('scene'); + } else { + traceRow.setAttribute('scene', ''); + } + } + }); + } else { + this.traceRowList!.forEach((traceRow) => { + traceRow.removeAttribute('row-hidden'); + this.resetChildRowModel(traceRow, true, false); + }); + favoriteRowList!.forEach((traceRow) => { + traceRow.removeAttribute('row-hidden'); + traceRow.setAttribute('scene', ''); + }); + } + this.refreshSystemPanel(); + } + + resetChildRowModel(row: any, hasRowSceneModel: boolean, hasRowHidden: boolean = false) { + if (hasRowSceneModel) { + row.setAttribute('scene', ''); + } else { + row.removeAttribute('scene'); + } + let sonRowList = this.spSystemTrace!.shadowRoot?.querySelector('div[class=rows]')!.querySelectorAll>( + `trace-row[row-parent-id='${row.rowId}']` + ); + sonRowList!.forEach((sonRow) => { + if (hasRowSceneModel) { + sonRow.setAttribute('scene', ''); + } else { + sonRow.removeAttribute('scene'); + } + if (hasRowHidden) { + sonRow.setAttribute('row-hidden', ''); + } + }); + } + + refreshSystemPanel() { + this.clearSearchAndFlag(); + this.spSystemTrace!.scrollToProcess('', '', '', false); + this.spSystemTrace!.refreshFavoriteCanvas(); + this.spSystemTrace!.refreshCanvas(false); + } + + clearSearchAndFlag() { + let traceSheet = this.spSystemTrace!.shadowRoot?.querySelector('.trace-sheet') as TraceSheet; + if (traceSheet) { + traceSheet!.setAttribute('mode', 'hidden'); + } + let search = document.querySelector('sp-application')!.shadowRoot?.querySelector('#lit-search') as LitSearch; + if (search) { + search.clear(); + } + let highlightRow = this.spSystemTrace!.shadowRoot?.querySelector>('trace-row[highlight]'); + if (highlightRow) { + highlightRow.highlight = false; + } + this.spSystemTrace!.timerShaftEL?.removeTriangle('inverted'); + CpuStruct.wakeupBean = undefined; + this.spSystemTrace!.hoverFlag = undefined; + this.spSystemTrace!.selectFlag = undefined; + } + + initElements(): void {} + + connectedCallback() { + this.sceneTable = this.shadowRoot!.querySelector('#scene-select'); + this.chartTable = this.shadowRoot!.querySelector('#chart-select'); + let bar = this.shadowRoot!.querySelector('.processBar'); + this.inputElement = this.shadowRoot!.querySelector('input'); + this.inputElement?.addEventListener('keyup', () => { + this.shadowRoot!.querySelectorAll('.chart-item').forEach((elementOption: HTMLElement) => { + if (elementOption.title!.indexOf(this.inputElement!.value) <= -1) { + elementOption.style.display = 'none'; + } else { + elementOption.style.display = 'block'; + } + }); + this.value = this.inputElement!.value; + }); + } + + initHtml(): string { + return ` + +
+ Display Template + +
+
+
+ +
Template Select
+
+
+
+
+
+
+ +
Timeline Details
+
+
+ +
+ +
+
+
+
+
+`; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + if (name === 'mode' && newValue == '') { + this.init(); + } + } +} diff --git a/ide/src/trace/component/trace/base/TraceRowObject.ts b/ide/src/trace/component/trace/base/TraceRowObject.ts new file mode 100644 index 0000000000000000000000000000000000000000..22cd59520af8c397d8cf5fb98d47c2e246e685e8 --- /dev/null +++ b/ide/src/trace/component/trace/base/TraceRowObject.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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 { BaseStruct } from '../../../bean/BaseStruct.js'; +import { Rect } from '../timer-shaft/Rect.js'; +import { TraceRow } from './TraceRow.js'; + +export class TraceRowObject { + public rowId: string | undefined; + public rowType: string | undefined; + public rowParentId: string | undefined; + public rowHidden: boolean = false; + public rowHeight: number = 40; + public name: string | undefined; + public must: boolean = true; + public folder: boolean = false; + public isLoading: boolean = false; + public children: boolean = false; + public expansion: boolean = false; + public dataList: Array | undefined; + public dataListCache: Array = []; + public color: string | undefined; + public frame: Rect | undefined; + public supplier: (() => Promise>) | undefined | null; + public onThreadHandler: + | (( + row: TraceRow, + ctx: + | ImageBitmapRenderingContext + | CanvasRenderingContext2D + | WebGLRenderingContext + | WebGL2RenderingContext + | null + | undefined + ) => void) + | undefined + | null; + public onDrawHandler: + | (( + ctx: + | ImageBitmapRenderingContext + | CanvasRenderingContext2D + | WebGLRenderingContext + | WebGL2RenderingContext + | null + | undefined + ) => void) + | undefined + | null; + public top: number = 0; + public rowIndex: number = 0; + public preObject: TraceRowObject | undefined | null; + public nextObject: TraceRowObject | undefined | null; +} diff --git a/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts b/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0df444adfea16de9dda8870cb51ee24f44de436 --- /dev/null +++ b/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import { TraceRowObject } from './TraceRowObject.js'; +import { TraceRow } from './TraceRow.js'; +import { log } from '../../../../log/Log.js'; + +@element('trace-row-recycler-view') +export class TraceRowRecyclerView extends BaseElement { + private recycler: boolean = true; + private gasketEL: HTMLDivElement | null | undefined; + private container: HTMLDivElement | null | undefined; + private visibleRowsCount: number = 0; + private visibleObjects: TraceRowObject[] = []; + private totalHeight: number = 0; + + private _dataSource: Array> = []; + private _renderType: string = 'div'; + + get dataSource(): Array> { + return this._dataSource; + } + + set dataSource(value: Array>) { + log('dataSource TraceRowObject size :' + value.length); + this._dataSource = value; + this.measureHeight(); + this.initUI(); + let els = [...this.shadowRoot!.querySelectorAll>('.recycler-cell')]; + for (let i = 0; i < els.length; i++) { + this.refreshRow(els[i], this.visibleObjects[i]); + } + } + + get renderType(): string { + return this._renderType; + } + + set renderType(value: string) { + this._renderType = value; + } + + refreshRow(el: TraceRow, obj: TraceRowObject) { + if (!obj) { + return; + } + el.obj = obj; + el.folder = obj.folder; + el.style.top = `${obj.top}px`; + el.name = obj.name || ''; + if (obj.children) { + el.setAttribute('children', ``); + } else { + el.removeAttribute('children'); + } + el.style.visibility = 'visible'; + el.rowId = obj.rowId; + el.rowType = obj.rowType; + el.rowParentId = obj.rowParentId; + el.expansion = obj.expansion; + el.rowHidden = obj.rowHidden; + el.setAttribute('height', `${obj.rowHeight}`); + requestAnimationFrame(() => {}); + } + + initElements(): void { + this.container = this.shadowRoot?.querySelector('.container'); + this.gasketEL = this.shadowRoot?.querySelector('.gasket'); + let els: Array> | undefined | null; + this.container!.onscroll = (ev) => { + let top = this.container!.scrollTop; + let skip = 0; + for (let i = 0; i < this.visibleObjects.length; i++) { + if (this.visibleObjects[i].top >= top) { + skip = this.visibleObjects[i].rowIndex - 1; + break; + } + } + if (skip < 0) skip = 0; + if (!els) els = [...this.shadowRoot!.querySelectorAll>('.recycler-cell')]; + for (let i = 0; i < els.length; i++) { + let obj = this.visibleObjects[i + skip]; + this.refreshRow(els[i], obj); + } + }; + } + + measureHeight() { + this.visibleObjects = this.dataSource.filter((it) => !it.rowHidden); + this.totalHeight = this.visibleObjects.map((it) => it.rowHeight).reduce((a, b) => a + b); + let totalHeight = 0; + for (let i = 0; i < this.visibleObjects.length; i++) { + this.visibleObjects[i].top = totalHeight; + this.visibleObjects[i].rowIndex = i; + totalHeight += this.visibleObjects[i].rowHeight; + this.visibleObjects[i].preObject = i == 0 ? null : this.visibleObjects[i - 1]; + this.visibleObjects[i].nextObject = i == this.visibleObjects.length - 1 ? null : this.visibleObjects[i + 1]; + } + this.gasketEL && (this.gasketEL.style.height = `${this.totalHeight}px`); + } + + initUI() { + this.visibleRowsCount = Math.ceil(this.clientHeight / 40); + if (this.visibleRowsCount >= this.visibleObjects.length) { + this.visibleRowsCount = this.visibleObjects.length; + } + if (!this.recycler) this.visibleRowsCount = this.dataSource.length; + for (let i = 0; i <= this.visibleRowsCount; i++) { + let el = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + el.className = 'recycler-cell'; + this.container?.appendChild(el); + el.addEventListener('expansion-change', (ev: any) => { + el.obj!.expansion = ev.detail.expansion; + for (let j = 0; j < this.dataSource.length; j++) { + if (this.dataSource[j].rowParentId == ev.detail.rowId) { + this.dataSource[j].rowHidden = !ev.detail.expansion; + } + } + this.measureHeight(); + let els = [...this.shadowRoot!.querySelectorAll>('.recycler-cell')]; + let top = this.container!.scrollTop; + let skip = 0; + for (let i = 0; i < this.visibleObjects.length; i++) { + if (this.visibleObjects[i].top >= top) { + skip = this.visibleObjects[i].rowIndex - 1; + break; + } + } + if (skip < 0) skip = 0; + for (let i = 0; i < els.length; i++) { + let obj = this.visibleObjects[i + skip]; + this.refreshRow(els[i], obj); + } + }); + } + } + + initHtml(): string { + return ` + +
+
+
+ + `; + } +} diff --git a/ide/src/trace/component/trace/base/TraceSheet.ts b/ide/src/trace/component/trace/base/TraceSheet.ts new file mode 100644 index 0000000000000000000000000000000000000000..496b23ce7f4aece63b529cc41203446ed71e3398 --- /dev/null +++ b/ide/src/trace/component/trace/base/TraceSheet.ts @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import { LitTabs } from '../../../../base-ui/tabs/lit-tabs.js'; +import { LitTabpane } from '../../../../base-ui/tabs/lit-tabpane.js'; +import { BoxJumpParam, SelectionParam } from '../../../bean/BoxSelection.js'; +import { TabPaneCurrentSelection } from '../sheet/TabPaneCurrentSelection.js'; +import { TabPaneFlag } from '../timer-shaft/TabPaneFlag.js'; +import { Flag } from '../timer-shaft/Flag.js'; +import { WakeupBean } from '../../../bean/WakeupBean.js'; +import { LitIcon } from '../../../../base-ui/icon/LitIcon.js'; +import { tabConfig } from './TraceSheetConfig.js'; +import { TabPaneBoxChild } from '../sheet/cpu/TabPaneBoxChild.js'; +import { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js'; +import { CpuFreqStruct } from '../../../database/ui-worker/ProcedureWorkerFreq.js'; +import { CpuFreqLimitsStruct } from '../../../database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; +import { ThreadStruct } from '../../../database/ui-worker/ProcedureWorkerThread.js'; +import { FuncStruct } from '../../../database/ui-worker/ProcedureWorkerFunc.js'; +import { ProcessMemStruct } from '../../../database/ui-worker/ProcedureWorkerMem.js'; +import { CpuStateStruct } from '../../../database/ui-worker/ProcedureWorkerCpuState.js'; +import { ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock.js'; +import { IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq.js'; +import { JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank.js'; +import { HeapStruct } from '../../../database/ui-worker/ProcedureWorkerHeap.js'; +import { TabpaneNMCalltree } from '../sheet/native-memory/TabPaneNMCallTree'; +import { LitTable } from '../../../../base-ui/table/lit-table.js'; +import { threadPool } from '../../../database/SqlLite.js'; +import { HeapSnapshotStruct } from '../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; +import { TabPaneComparison } from '../sheet/snapshot/TabPaneComparison.js'; +import { TabPaneSummary } from '../sheet/snapshot/TabPaneSummary.js'; +import { TabPaneNMStatisticAnalysis } from '../sheet/native-memory/TabPaneNMStatisticAnalysis.js'; + +@element('trace-sheet') +export class TraceSheet extends BaseElement { + private litTabs: LitTabs | undefined | null; + private nav: HTMLDivElement | undefined | null; + private selection: SelectionParam | undefined | null; + private currentPaneID: string = 'current-selection'; + private fragment: DocumentFragment | undefined; + + static get observedAttributes() { + return ['mode']; + } + + buildTabs(litTabs: LitTabs | undefined | null) { + this.fragment = document.createDocumentFragment(); + Reflect.ownKeys(tabConfig).forEach((key, index) => { + let pane = new LitTabpane(); + pane.id = key.toString(); + pane.className = 'tabHeight'; + pane.tab = tabConfig[key].title; + pane.hidden = true; + pane.key = `${tabConfig[key].key || index}`; + let cls = tabConfig[key].type; + let node = new cls(); + pane.append(node); + this.fragment?.appendChild(pane); + }); + litTabs!.appendChild(this.fragment); + } + + displayTab(...names: string[]): T { + this.setAttribute('mode', 'max'); + this.shadowRoot + ?.querySelectorAll('#tabs lit-tabpane') + .forEach((it) => (it.hidden = !names.some((k) => k === it.id))); + let litTabpane = this.shadowRoot?.querySelector(`#tabs lit-tabpane[id='${names[0]}']`); + this.shadowRoot?.querySelector('#tabs')?.activePane(litTabpane!.key); + return litTabpane!.children.item(0) as unknown as T; + } + + getComponentByID(id: string): T { + return this.getPaneByID(id)!.children.item(0) as unknown as T; + } + + getPaneByID(id: string): LitTabpane { + return this.shadowRoot!.querySelector(`#${id}`)!; + } + + initElements(): void { + this.litTabs = this.shadowRoot?.querySelector('#tabs'); + this.buildTabs(this.litTabs); + let minBtn = this.shadowRoot?.querySelector('#min-btn'); + minBtn?.addEventListener('click', () => {}); + this.litTabs!.onTabClick = (e: any) => this.loadTabPaneData(e.detail.key); + this.litTabs!.addEventListener('close-handler', () => { + Reflect.ownKeys(tabConfig) + .reverse() + .forEach((id) => { + let element = tabConfig[id]; + let pane = this.shadowRoot!.querySelector(`#${id as string}`); + if (element.require) { + pane!.hidden = !element.require(this.selection); + } else { + pane!.hidden = true; + } + }); + this.litTabs?.activeByKey(`${this.getPaneByID(this.currentPaneID).key}`); + }); + this.getComponentByID('box-spt')!.addEventListener('row-click', this.rowClickHandler.bind(this)); + this.getComponentByID('box-pts')!.addEventListener('row-click', this.rowClickHandler.bind(this)); + this.getComponentByID('box-cs')!.addEventListener('row-click', this.rowClickHandler.bind(this)); + this.getComponentByID('box-ts')!.addEventListener('row-click', this.rowClickHandler.bind(this)); + this.getComponentByID('box-native-statstics')!.addEventListener('row-click', (e: any) => { + this.selection!.statisticsSelectData = e.detail; + let pane = this.getPaneByID('box-native-memory'); + this.litTabs?.activeByKey(pane.key); + (pane.children.item(0) as any)!.fromStastics(this.selection); + }); + this.getComponentByID('box-virtual-memory-statistics')!.addEventListener('row-click', (e: any) => { + this.selection!.fileSystemVMData = { path: e.detail.path }; + let pane = this.getPaneByID('box-vm-events'); + this.litTabs?.activeByKey(pane.key); + if (e.detail.path) { + (pane.children.item(0) as any)!.fromStastics(this.selection); + } + }); + this.getComponentByID('box-io-tier-statistics')!.addEventListener('row-click', (e: any) => { + this.selection!.fileSystemIoData = { path: e.detail.path }; + let pane = this.getPaneByID('box-io-events'); + this.litTabs?.activeByKey(pane.key); + if (e.detail.path) { + (pane.children.item(0) as any)!.fromStastics(this.selection); + } + }); + this.getComponentByID('box-file-system-statistics')!.addEventListener('row-click', (e: any) => { + this.selection!.fileSystemFsData = e.detail.data; + let pane = this.getPaneByID('box-file-system-event'); + this.litTabs?.activeByKey(pane.key); + if (e.detail.data) { + (pane.children.item(0) as any)!.fromStastics(this.selection); + } + }); + } + + connectedCallback() { + this.nav = this.shadowRoot?.querySelector('#tabs')?.shadowRoot?.querySelector('.tab-nav-container'); + let tabs: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#tabs'); + let navRoot: HTMLDivElement | null | undefined = this.shadowRoot + ?.querySelector('#tabs') + ?.shadowRoot?.querySelector('.nav-root'); + let search: HTMLDivElement | undefined | null = document + .querySelector('body > sp-application') + ?.shadowRoot?.querySelector('div > div.search-container'); + let timerShaft: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.timer-shaft'); + let spacer: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.spacer'); + let rowsPaneEL: HTMLDivElement | undefined | null = this.parentElement?.querySelector('.rows-pane'); + + let borderTop: number = 1; + let initialHeight = { tabs: `calc(30vh + 39px)`, node: '30vh' }; + this.nav!.onmousedown = (event) => { + (window as any).isSheetMove = true; + let litTabpane: NodeListOf | undefined | null = + this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); + let preY = event.pageY; + let preHeight = tabs!.offsetHeight; + document.onmousemove = function (event) { + let moveY: number = preHeight - (event.pageY - preY); + litTabpane!.forEach((node: HTMLDivElement) => { + if (spacer!.offsetHeight > rowsPaneEL!.offsetHeight) { + tabs!.style.height = moveY + 'px'; + node!.style.height = moveY - navRoot!.offsetHeight + 'px'; + tabsPackUp!.name = 'down'; + } else if ( + navRoot!.offsetHeight <= moveY && + search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight <= + window.innerHeight - moveY + ) { + tabs!.style.height = moveY + 'px'; + node!.style.height = moveY - navRoot!.offsetHeight + 'px'; + tabsPackUp!.name = 'down'; + } else if (navRoot!.offsetHeight >= moveY) { + tabs!.style.height = navRoot!.offsetHeight + 'px'; + node!.style.height = '0px'; + tabsPackUp!.name = 'up'; + } else if ( + search!.offsetHeight + timerShaft!.offsetHeight + borderTop + spacer!.offsetHeight >= + window.innerHeight - moveY + ) { + tabs!.style.height = + window.innerHeight - + search!.offsetHeight - + timerShaft!.offsetHeight - + borderTop - + spacer!.offsetHeight + + 'px'; + node!.style.height = + window.innerHeight - + search!.offsetHeight - + timerShaft!.offsetHeight - + navRoot!.offsetHeight - + borderTop - + spacer!.offsetHeight + + 'px'; + tabsPackUp!.name = 'down'; + } + }); + }; + document.onmouseup = function () { + setTimeout(() => { + (window as any).isSheetMove = false; + }, 100); + litTabpane!.forEach((node: HTMLDivElement) => { + if (node!.style.height !== '0px' && tabs!.style.height != '') { + initialHeight.node = node!.style.height; + initialHeight.tabs = tabs!.style.height; + } + }); + this.onmousemove = null; + this.onmouseup = null; + }; + }; + let tabsOpenUp: LitIcon | undefined | null = this.shadowRoot?.querySelector('#max-btn'); + let tabsPackUp: LitIcon | undefined | null = this.shadowRoot?.querySelector('#min-btn'); + let importFileBt: HTMLInputElement | undefined | null = + this.shadowRoot?.querySelector('#import-file'); + let exportDataBt: LitIcon | undefined | null = this.shadowRoot?.querySelector('#export-btn'); + tabsOpenUp!.onclick = () => { + tabs!.style.height = window.innerHeight - search!.offsetHeight - timerShaft!.offsetHeight - borderTop + 'px'; + let litTabpane: NodeListOf | undefined | null = + this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); + litTabpane!.forEach((node: HTMLDivElement) => { + node!.style.height = + window.innerHeight - + search!.offsetHeight - + timerShaft!.offsetHeight - + navRoot!.offsetHeight - + borderTop + + 'px'; + initialHeight.node = node!.style.height; + }); + initialHeight.tabs = tabs!.style.height; + tabsPackUp!.name = 'down'; + }; + tabsPackUp!.onclick = () => { + let litTabpane: NodeListOf | undefined | null = + this.shadowRoot?.querySelectorAll('#tabs > lit-tabpane'); + if (tabsPackUp!.name == 'down') { + tabs!.style.height = navRoot!.offsetHeight + 'px'; + litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = '0px')); + tabsPackUp!.name = 'up'; + (window as any).isPackUpTable = true; + } else { + tabsPackUp!.name = 'down'; + tabs!.style.height = initialHeight.tabs; + litTabpane!.forEach((node: HTMLDivElement) => (node!.style.height = initialHeight.node)); + } + }; + importFileBt!.addEventListener('change', (event) => { + let files = importFileBt?.files; + if (files) { + let fileList: Array = []; + for (let file of files) { + if (file.name.endsWith('.so')) { + fileList.push(file); + } + } + if (fileList.length > 0) { + window.publish(window.SmartEvent.UI.Loading, true); + threadPool.submit( + 'upload-so', + '', + fileList, + (res: any) => { + window.publish(window.SmartEvent.UI.UploadSOFile, {}); + }, + 'upload-so' + ); + } + } + importFileBt!.files = null; + importFileBt!.value = ''; + }); + exportDataBt!.onclick = () => { + let currentTab = this.getTabpaneByKey(this.litTabs?.activekey!); + if (currentTab) { + let tables = Array.from( + (currentTab.firstChild as BaseElement).shadowRoot?.querySelectorAll('lit-table') || [] + ); + for (let table of tables) { + if (!table.hasAttribute('hideDownload')) { + table.exportData(); + } + } + } + }; + } + + getTabpaneByKey(key: string): LitTabpane | undefined { + let tabs = Array.from(this.shadowRoot?.querySelectorAll('#tabs lit-tabpane').values() || []); + return tabs.find((it) => it.key === key); + } + + initHtml(): string { + return ` + +
+ +
+
+ + +
+ + + + + + +
+
+
`; + } + + displayThreadData = ( + data: ThreadStruct, + scrollCallback: ((e: ThreadStruct) => void) | undefined, + scrollWakeUp: (d: any) => void | undefined + ) => this.displayTab('current-selection').setThreadData(data, scrollCallback, scrollWakeUp); + displayMemData = (data: ProcessMemStruct) => + this.displayTab('current-selection').setMemData(data); + displayClockData = (data: ClockStruct) => + this.displayTab('current-selection').setClockData(data); + displayIrqData = (data: IrqStruct) => this.displayTab('current-selection').setIrqData(data); + + displayNativeHookData = (data: HeapStruct, rowType: string) => { + let val = new SelectionParam(); + val.nativeMemoryStatistic.push(rowType); + val.nativeMemory = []; + val.leftNs = data.startTime!; + val.rightNs = data.startTime! + data.dur! -1; + this.selection = val; + this.displayTab('box-native-statistic-analysis', 'box-native-calltree').data = val; + }; + + displayFuncData = (data: FuncStruct, scrollCallback: Function) => + this.displayTab('current-selection').setFunctionData(data, scrollCallback); + displayCpuData = ( + data: CpuStruct, + callback: ((data: WakeupBean | null) => void) | undefined = undefined, + scrollCallback?: (data: CpuStruct) => void + ) => this.displayTab('current-selection').setCpuData(data, callback, scrollCallback); + displayJankData = ( + data: JankStruct, + callback: ((data: Array) => void) | undefined = undefined, + scrollCallback: ((e: JankStruct) => void) | undefined + ) => this.displayTab('current-selection').setJankData(data, callback, scrollCallback); + displaySnapshotData = ( + data: HeapSnapshotStruct, + dataList: Array, + scrollCallback?: (data: HeapSnapshotStruct, dataList: Array) => void + ) => { + if (dataList.length > 1) { + this.displayTab('box-heap-summary', 'box-heap-comparison').setSnapshotData( + data, + dataList, + scrollCallback + ); + let nav = this.shadowRoot!.querySelector('#tabs')!.shadowRoot!.querySelector( + '#nav > #nav-comparison' + ) as HTMLDivElement; + let tabPaneComparison = this.shadowRoot!.querySelector( + '#box-heap-comparison > tabpane-comparison' + ) as TabPaneComparison; + nav!.onclick = () => { + tabPaneComparison.initComparison(data, dataList); + }; + } else { + this.displayTab('box-heap-summary').setSnapshotData(data, dataList, scrollCallback); + } + }; + displayFlagData = (flagObj: Flag) => this.displayTab('box-flag').setFlagObj(flagObj); + displayFreqData = () => + (this.displayTab('box-freq').data = CpuFreqStruct.selectCpuFreqStruct); + displayCpuStateData = () => + (this.displayTab('cpu-state-click').data = CpuStateStruct.selectStateStruct); + displayFreqLimitData = () => + (this.displayTab('box-freq-limit').data = CpuFreqLimitsStruct.selectCpuFreqLimitsStruct); + + rangeSelect(selection: SelectionParam): boolean { + this.selection = selection; + Reflect.ownKeys(tabConfig) + .reverse() + .forEach((id) => { + let element = tabConfig[id]; + if (element.require) { + if (element.require(selection)) { + let pane = this.shadowRoot!.querySelector(`#${id as string}`); + pane!.hidden = false; + } else { + this.shadowRoot!.querySelector(`#${id as string}`)!.hidden = true; + } + } else { + this.shadowRoot!.querySelector(`#${id as string}`)!.hidden = true; + } + }); + let firstPane = this.shadowRoot!.querySelector(`lit-tabpane[hidden='false']`); + if (firstPane) { + this.litTabs?.activeByKey(firstPane.key); + this.loadTabPaneData(firstPane.key); + this.setAttribute('mode', 'max'); + return true; + } else { + this.setAttribute('mode', 'hidden'); + return false; + } + } + + loadTabPaneData(key: string) { + let component: any = this.shadowRoot + ?.querySelector(`#tabs lit-tabpane[key='${key}']`) + ?.children.item(0); + if (component) { + component.data = this.selection; + } + } + + rowClickHandler(e: any) { + this.currentPaneID = e.target.parentElement.id; + this.shadowRoot!.querySelectorAll(`lit-tabpane`).forEach((it) => + it.id != this.currentPaneID ? (it.hidden = true) : (it.hidden = false) + ); + let pane = this.getPaneByID('box-cpu-child'); + pane.closeable = true; + pane.hidden = false; + this.litTabs!.activeByKey(pane.key); + pane.tab = e.detail.title; + let param = new BoxJumpParam(); + param.leftNs = this.selection!.leftNs; + param.rightNs = this.selection!.rightNs; + param.state = e.detail.state; + param.threadId = e.detail.threadId; + param.processId = e.detail.processId; + (pane.children.item(0) as TabPaneBoxChild).data = param; + } +} diff --git a/ide/src/trace/component/trace/base/TraceSheetConfig.ts b/ide/src/trace/component/trace/base/TraceSheetConfig.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f37e444eb19f0eda9790bfdbb476901e984b7db --- /dev/null +++ b/ide/src/trace/component/trace/base/TraceSheetConfig.ts @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2022 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 { TabPaneCurrentSelection } from '../sheet/TabPaneCurrentSelection.js'; +import { TabPaneFreq } from '../sheet/freq/TabPaneFreq.js'; +import { TabPaneCpuByThread } from '../sheet/cpu/TabPaneCpuByThread.js'; +import { SelectionParam } from '../../../bean/BoxSelection.js'; +import { TabPaneCpuByProcess } from '../sheet/cpu/TabPaneCpuByProcess.js'; +import { TabPaneCpuUsage } from '../sheet/cpu/TabPaneCpuUsage.js'; +import { TabPaneSPT } from '../sheet/cpu/TabPaneSPT.js'; +import { TabPaneContextSwitch } from '../sheet/cpu/TabPaneContextSwitch.js'; +import { TabPanePTS } from '../sheet/cpu/TabPanePTS.js'; +import { TabPaneThreadSwitch } from '../sheet/cpu/TabPaneThreadSwitch.js'; +import { TabPaneSlices } from '../sheet/process/TabPaneSlices.js'; +import { TabPaneCounter } from '../sheet/process/TabPaneCounter.js'; +import { TabPaneFps } from '../sheet/fps/TabPaneFps.js'; +import { TabPaneFlag } from '../timer-shaft/TabPaneFlag.js'; +import { TabPaneBoxChild } from '../sheet/cpu/TabPaneBoxChild.js'; +import { TabPaneNMStatstics } from '../sheet/native-memory/TabPaneNMStatstics.js'; +import { TabPaneNMemory } from '../sheet/native-memory/TabPaneNMemory.js'; +import { TabPaneNMSampleList } from '../sheet/native-memory/TabPaneNMSampleList.js'; +import { TabpanePerfProfile } from '../sheet/hiperf/TabPerfProfile.js'; +import { TabPanePerfSample } from '../sheet/hiperf/TabPerfSampleList.js'; +import { TabPaneLiveProcesses } from '../sheet/ability/TabPaneLiveProcesses.js'; +import { TabPaneHistoryProcesses } from '../sheet/ability/TabPaneHistoryProcesses.js'; +import { TabPaneCpuAbility } from '../sheet/ability/TabPaneCpuAbility.js'; +import { TabPaneMemoryAbility } from '../sheet/ability/TabPaneMemoryAbility.js'; +import { TabPaneDiskAbility } from '../sheet/ability/TabPaneDiskAbility.js'; +import { TabPaneNetworkAbility } from '../sheet/ability/TabPaneNetworkAbility.js'; +import { TabPaneFileStatistics } from '../sheet/file-system/TabPaneFilesystemStatistics.js'; +import { TabpaneFilesystemCalltree } from '../sheet/file-system/TabPaneFileSystemCalltree.js'; +import { TabPaneFileSystemEvents } from '../sheet/file-system/TabPaneFileSystemEvents.js'; +import { TabPaneFileSystemDescHistory } from '../sheet/file-system/TabPaneFileSystemDescHistory.js'; +import { TabPaneFileSystemDescTimeSlice } from '../sheet/file-system/TabPaneFileSystemDescTimeSlice.js'; +import { TabPaneSdkSlice } from '../sheet/sdk/TabPaneSdkSlice.js'; +import { TabPaneSdkCounter } from '../sheet/sdk/TabPaneSdkCounter.js'; +import { TabPaneCounterSample } from '../sheet/cpu/TabPaneCounterSample.js'; +import { TabPaneThreadStates } from '../sheet/process/TabPaneThreadStates.js'; +import { TabPaneThreadUsage } from '../sheet/process/TabPaneThreadUsage.js'; +import { TabPaneFrequencySample } from '../sheet/cpu/TabPaneFrequencySample.js'; +import { TabPaneEnergyAnomaly } from '../sheet/energy/TabPaneEnergyAnomaly.js'; +import { TabPaneSystemDetails } from '../sheet/energy/TabPaneSystemDetails.js'; +import { TabPanePowerDetails } from '../sheet/energy/TabPanePowerDetails.js'; +import { TabPanePowerBattery } from '../sheet/energy/TabPanePowerBattery.js'; +import { TabPaneCpuStateClick } from '../sheet/cpu/TabPaneCpuStateClick.js'; +import { TabPaneVirtualMemoryStatistics } from '../sheet/file-system/TabPaneVirtualMemoryStatistics.js'; +import { TabPaneIOTierStatistics } from '../sheet/file-system/TabPaneIOTierStatistics.js'; +import { TabPaneIOCallTree, TabPaneVMCallTree } from '../sheet/file-system/TabPaneIOCallTree.js'; +import { TabPaneIoCompletionTimes } from '../sheet/file-system/TabPaneIoCompletionTimes.js'; +import { TabPaneVirtualMemoryEvents } from '../sheet/file-system/TabPaneVMEvents.js'; +import { TabPaneSmapsStatistics } from '../sheet/smaps/TabPaneSmapsStatistics.js'; +import { TabPaneSmapsRecord } from '../sheet/smaps/TabPaneSmapsRecord.js'; +import { TabPaneFreqLimit } from '../sheet/freq/TabPaneFreqLimit.js'; +import { TabPaneCpuFreqLimits } from '../sheet/freq/TabPaneCpuFreqLimits.js'; +import { TabpaneNMCalltree } from '../sheet/native-memory/TabPaneNMCallTree.js'; +import { TabPaneClockCounter } from '../sheet/clock/TabPaneClockCounter.js'; +import { TabPaneIrqCounter } from '../sheet/irq/TabPaneIrqCounter.js'; +import { TabPaneFrames } from '../sheet/jank/TabPaneFrames.js'; +import { TabPaneSummary } from '../sheet/snapshot/TabPaneSummary.js'; +import { TabPaneComparison } from '../sheet/snapshot/TabPaneComparison.js'; +import { TabPanePerfAnalysis } from '../sheet/hiperf/TabPanePerfAnalysis.js'; +import { TabPaneNMStatisticAnalysis } from '../sheet/native-memory/TabPaneNMStatisticAnalysis.js'; +import { TabPaneFilesystemStatisticsAnalysis } from '../sheet/file-system/TabPaneFilesystemStatisticsAnalysis.js'; +import { TabPaneIOTierStatisticsAnalysis } from '../sheet/file-system/TabPaneIOTierStatisticsAnalysis.js'; +import { TabPaneVirtualMemoryStatisticsAnalysis } from '../sheet/file-system/TabPaneVirtualMemoryStatisticsAnalysis.js'; +export let tabConfig: any = { + 'current-selection': { + title: 'Current Selection', + type: TabPaneCurrentSelection, + }, //cpu data click + 'cpu-state-click': { + title: 'Cpu State', + type: TabPaneCpuStateClick, + }, + 'box-freq': { + title: 'Frequency', + type: TabPaneFreq, + }, //freq data click + 'box-freq-limit': { + title: 'Frequency Limits', + type: TabPaneFreqLimit, + }, + 'box-cpu-freq-limit': { + title: 'Cpu Frequency Limits', + type: TabPaneCpuFreqLimits, + require: (param: SelectionParam) => param.cpuFreqLimitDatas.length > 0, + }, + 'box-cpu-thread': { + title: 'CPU by thread', + type: TabPaneCpuByThread, + require: (param: SelectionParam) => param.cpus.length > 0, + }, //range select + 'box-cpu-process': { + title: 'CPU by process', + type: TabPaneCpuByProcess, + require: (param: SelectionParam) => param.cpus.length > 0, + }, + 'box-cpu-usage': { + title: 'CPU Usage', + type: TabPaneCpuUsage, + require: (param: SelectionParam) => param.cpus.length > 0, + }, + 'box-spt': { + title: 'States List', + type: TabPaneSPT, + require: (param: SelectionParam) => param.cpus.length > 0, + }, + 'box-cs': { + title: 'Switches List', + type: TabPaneContextSwitch, + require: (param: SelectionParam) => param.cpus.length > 0, + }, + 'box-pts': { + title: 'Thread States', + type: TabPanePTS, + require: (param: SelectionParam) => param.cpus.length > 0, + }, + 'box-ts': { + title: 'Thread Switches', + type: TabPaneThreadSwitch, + require: (param: SelectionParam) => param.cpus.length > 0, + }, //end range select + 'box-slices': { + title: 'Slices', + type: TabPaneSlices, + require: (param: SelectionParam) => param.funTids.length > 0 || param.funAsync.length > 0, + }, + 'box-counters': { + title: 'Counters', + type: TabPaneCounter, + require: (param: SelectionParam) => param.processTrackIds.length > 0 || param.virtualTrackIds.length > 0, + }, + 'box-clock-counters': { + title: 'Clock Counters', + type: TabPaneClockCounter, + require: (param: SelectionParam) => param.clockMapData.size > 0, + }, + 'box-irq-counters': { + title: 'Irq Counters', + type: TabPaneIrqCounter, + require: (param: SelectionParam) => param.irqMapData.size > 0, + }, + 'box-fps': { + title: 'FPS', + type: TabPaneFps, + require: (param: SelectionParam) => param.hasFps, + }, + 'box-flag': { + title: 'Current Selection', + type: TabPaneFlag, + }, + 'box-cpu-child': { + title: '', + type: TabPaneBoxChild, + }, + 'box-native-statstics': { + title: 'Statistics', + type: TabPaneNMStatstics, + require: (param: SelectionParam) => param.nativeMemory.length > 0, + }, + 'box-native-statistic-analysis': { + title: 'Analysis', + type: TabPaneNMStatisticAnalysis, + require: (param: SelectionParam) => param.nativeMemory.length > 0 || param.nativeMemoryStatistic.length > 0, + }, + 'box-native-calltree': { + title: 'Call Info', + type: TabpaneNMCalltree, + require: (param: SelectionParam) => param.nativeMemory.length > 0 || param.nativeMemoryStatistic.length > 0, + }, + 'box-native-memory': { + title: 'Native Memory', + type: TabPaneNMemory, + require: (param: SelectionParam) => param.nativeMemory.length > 0, + }, + 'box-native-sample': { + title: 'Snapshot List', + type: TabPaneNMSampleList, + require: (param: SelectionParam) => param.nativeMemory.length > 0, + }, + 'box-perf-analysis': { + title: 'Analysis', + type: TabPanePerfAnalysis, + require: (param: SelectionParam) => param.perfSampleIds.length > 0, + }, + 'box-perf-profile': { + title: 'Perf Profile', + type: TabpanePerfProfile, + require: (param: SelectionParam) => param.perfSampleIds.length > 0, + }, + 'box-perf-sample': { + title: 'Sample List', + type: TabPanePerfSample, + require: (param: SelectionParam) => param.perfSampleIds.length > 0, + }, + 'box-live-processes-child': { + title: 'Live Processes', + type: TabPaneLiveProcesses, + require: (param: SelectionParam) => + param.cpuAbilityIds.length > 0 || + (param.memoryAbilityIds.length > 0 && param.diskAbilityIds.length > 0) || + param.networkAbilityIds.length > 0, + }, + 'box-history-processes-child': { + title: 'Processes History', + type: TabPaneHistoryProcesses, + require: (param: SelectionParam) => + param.cpuAbilityIds.length > 0 || + param.memoryAbilityIds.length > 0 || + param.diskAbilityIds.length > 0 || + param.networkAbilityIds.length > 0, + }, + 'box-system-cpu-child': { + title: 'System CPU Summary', + type: TabPaneCpuAbility, + require: (param: SelectionParam) => param.cpuAbilityIds.length > 0, + }, + 'box-system-memory-child': { + title: 'System Memory Summary', + type: TabPaneMemoryAbility, + require: (param: SelectionParam) => param.memoryAbilityIds.length > 0, + }, + 'box-system-diskIo-child': { + title: 'System Disk Summary', + type: TabPaneDiskAbility, + require: (param: SelectionParam) => param.diskAbilityIds.length > 0, + }, + 'box-system-network-child': { + title: 'System Network Summary', + type: TabPaneNetworkAbility, + require: (param: SelectionParam) => param.networkAbilityIds.length > 0, + }, + 'box-sdk-slice-child': { + title: 'Sdk Slice', + type: TabPaneSdkSlice, + require: (param: SelectionParam) => param.sdkSliceIds.length > 0, + }, + 'box-system-counter-child': { + title: 'SDK Counter', + type: TabPaneSdkCounter, + require: (param: SelectionParam) => param.sdkCounterIds.length > 0, + }, + 'box-counter-sample': { + title: 'Cpu State', + type: TabPaneCounterSample, + require: (param: SelectionParam) => param.cpuStateFilterIds.length > 0, + }, + 'box-thread-states': { + title: 'Thread States', + type: TabPaneThreadStates, + require: (param: SelectionParam) => param.threadIds.length > 0, + }, + 'box-thread-usage': { + title: 'Thread Usage', + type: TabPaneThreadUsage, + require: (param: SelectionParam) => param.threadIds.length > 0, + }, + 'box-frequency-sample': { + title: 'Cpu Frequency', + type: TabPaneFrequencySample, + require: (param: SelectionParam) => param.cpuFreqFilterIds.length > 0, + }, + 'box-anomaly-details': { + title: 'Anomaly details', + type: TabPaneEnergyAnomaly, + require: (param: SelectionParam) => param.anomalyEnergy.length > 0, + }, + 'box-system-details': { + title: 'System Details', + type: TabPaneSystemDetails, + require: (param: SelectionParam) => param.systemEnergy.length > 0, + }, + 'box-power-battery': { + title: 'Power Battery', + type: TabPanePowerBattery, + require: (param: SelectionParam) => param.powerEnergy.length > 0, + }, + 'box-power-details': { + title: 'Power Details', + type: TabPanePowerDetails, + require: (param: SelectionParam) => param.powerEnergy.length > 0, + }, + 'box-file-system-statistics': { + title: 'Filesystem statistics', + type: TabPaneFileStatistics, + require: (param: SelectionParam) => param.fileSystemType.length > 0, + }, + 'box-file-system-statistics-analysis': { + title: 'Analysis', + type: TabPaneFilesystemStatisticsAnalysis, + require: (param: SelectionParam) => param.fileSystemType.length > 0, + }, + 'box-file-system-calltree': { + title: 'Filesystem Calltree', + type: TabpaneFilesystemCalltree, + require: (param: SelectionParam) => param.fileSystemType.length > 0 || param.fsCount > 0, + }, + 'box-file-system-event': { + title: 'Filesystem Events', + type: TabPaneFileSystemEvents, + require: (param: SelectionParam) => param.fileSystemType.length > 0, + }, + 'box-file-system-desc-history': { + title: 'File Descriptor History', + type: TabPaneFileSystemDescHistory, + require: (param: SelectionParam) => param.fileSystemType.length > 0, + }, + 'box-file-system-desc-time-slice': { + title: 'File Descriptor Time Slice', + type: TabPaneFileSystemDescTimeSlice, + require: (param: SelectionParam) => param.fileSystemType.length > 0, + }, + 'box-virtual-memory-statistics': { + title: 'Page Fault Statistics', + type: TabPaneVirtualMemoryStatistics, + require: (param: SelectionParam) => param.fileSysVirtualMemory, + }, + 'box-virtual-memory-statistics-analysis': { + title: 'Analysis', + type: TabPaneVirtualMemoryStatisticsAnalysis, + require: (param: SelectionParam) => param.fileSysVirtualMemory, + }, + 'box-vm-calltree': { + title: 'Page Fault CallTree', + type: TabPaneVMCallTree, + require: (param: SelectionParam) => param.fileSysVirtualMemory || param.vmCount > 0, + }, + 'box-vm-events': { + title: 'Page Fault Events', + type: TabPaneVirtualMemoryEvents, + require: (param: SelectionParam) => param.fileSysVirtualMemory, + }, + 'box-io-tier-statistics': { + title: 'Disk I/O Tier Statistics', + type: TabPaneIOTierStatistics, + require: (param: SelectionParam) => param.diskIOLatency, + }, + 'box-io-tier-statistics-analysis': { + title: 'Analysis', + type: TabPaneIOTierStatisticsAnalysis, + require: (param: SelectionParam) => param.diskIOLatency, + }, + 'box-io-calltree': { + title: 'Disk I/O Latency Calltree', + type: TabPaneIOCallTree, + require: (param: SelectionParam) => param.diskIOLatency || param.diskIOipids.length > 0, + }, + 'box-io-events': { + title: 'Trace Completion Times', + type: TabPaneIoCompletionTimes, + require: (param: SelectionParam) => param.diskIOLatency, + }, + 'box-smaps-statistics': { + title: 'VM Tracker Statistics', + type: TabPaneSmapsStatistics, + require: (param: SelectionParam) => param.smapsType.length > 0, + }, + 'box-smaps-record': { + title: 'VM Tracker Record List', + type: TabPaneSmapsRecord, + require: (param: SelectionParam) => param.smapsType.length > 0, + }, + 'box-frames': { + title: 'Frames', + type: TabPaneFrames, + require: (param: SelectionParam) => param.jankFramesData.length > 0, + }, + 'box-heap-summary': { + title: 'Summary', + type: TabPaneSummary, + require: (param: SelectionParam) => param.jsMemory.length > 0, + }, + 'box-heap-comparison': { + title: 'Comparison', + type: TabPaneComparison, + }, // snapshot data click +}; diff --git a/ide/src/trace/component/trace/base/Utils.ts b/ide/src/trace/component/trace/base/Utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..5747ac9568d3ddc0badbe739d841732608b8f368 --- /dev/null +++ b/ide/src/trace/component/trace/base/Utils.ts @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2022 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. + */ + +export class Utils { + private static statusMap: Map = new Map(); + private static instance: Utils | null = null; + static THREAD_MAP: Map = new Map(); + static PROCESS_MAP: Map = new Map(); + static SCHED_SLICE_MAP: Map< + string, + { + endState: string; + priority: number; + } + > = new Map< + string, + { + endState: string; + priority: number; + } + >(); + + constructor() { + Utils.statusMap.set('D', 'Uninterruptible Sleep'); + Utils.statusMap.set('D-NIO', 'Uninterruptible Sleep(non-IO)'); + Utils.statusMap.set('D-IO', 'Uninterruptible Sleep(IO)'); + Utils.statusMap.set('DK', 'Uninterruptible Sleep + Wake Kill'); + Utils.statusMap.set('DK-NIO', 'Uninterruptible Sleep(non-IO) + Wake Kill'); + Utils.statusMap.set('DK-IO', 'Uninterruptible Sleep(IO) + Wake Kill'); + Utils.statusMap.set('S', 'Sleeping'); + Utils.statusMap.set('R', 'Runnable'); + Utils.statusMap.set('Running', 'Running'); + Utils.statusMap.set('R+', 'Runnable (Preempted)'); + Utils.statusMap.set('I', 'Task Dead'); + Utils.statusMap.set('T', 'Traced'); + Utils.statusMap.set('t', 'Traced'); + Utils.statusMap.set('X', 'Exit (Dead)'); + Utils.statusMap.set('Z', 'Exit (Zombie)'); + Utils.statusMap.set('K', 'Wake Kill'); + Utils.statusMap.set('W', 'Waking'); + Utils.statusMap.set('P', 'Parked'); + Utils.statusMap.set('N', 'No Load'); + } + + public static getInstance(): Utils { + if (Utils.instance == null) { + Utils.instance = new Utils(); + } + return Utils.instance; + } + + public static getEndState(state: string): string { + if (Utils.getInstance().getStatusMap().has(state)) { + return Utils.getInstance().getStatusMap().get(state) || 'Unknown State'; + } else { + if ('' == state || state == null) { + return ''; + } + return 'Unknown State'; + } + } + + public static getStateColor(state: string): string { + if (state == 'D-NIO' || state == 'DK-NIO') { + return '#795548'; + } else if (state == 'D-IO' || state == 'DK-IO' || state == 'D' || state == 'DK') { + return '#f19b38'; + } else if (state == 'R' || state == 'R+') { + return '#a0b84d'; + } else if (state == 'I') { + return '#673ab7'; + } else if (state == 'Running') { + return '#467b3b'; + } else if (state == 'S') { + return '#e0e0e0'; + } else { + return '#ff6e40'; + } + } + + public static getTimeString(ns: number): string { + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; + let millisecond1 = 1_000_000; + let microsecond1 = 1_000; + let res = ''; + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1) + 'h '; + currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + 'm '; + currentNs = currentNs - Math.floor(ns / minute1) * minute1; + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + 's '; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + } + if (currentNs >= millisecond1) { + res += Math.floor(currentNs / millisecond1) + 'ms '; + currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; + } + if (currentNs >= microsecond1) { + res += Math.floor(currentNs / microsecond1) + 'μs '; + currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; + } + if (currentNs > 0) { + res += currentNs + 'ns '; + } + if (res == '') { + res = ns + ''; + } + return res; + } + + public static getProbablyTime(ns: number): string { + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; + let millisecond1 = 1_000_000; + let microsecond1 = 1_000; + let res = ''; + if (currentNs >= hour1) { + res += (currentNs / hour1).toFixed(2) + 'h '; + } else if (currentNs >= minute1) { + res += (currentNs / minute1).toFixed(2) + 'm '; + } else if (currentNs >= second1) { + res += (currentNs / second1).toFixed(2) + 's '; + } else if (currentNs >= millisecond1) { + res += (currentNs / millisecond1).toFixed(2) + 'ms '; + } else if (currentNs >= microsecond1) { + res += (currentNs / microsecond1).toFixed(2) + 'μs '; + } else if (currentNs > 0) { + res += currentNs + 'ns '; + } else if (res == '') { + res = ns + ''; + } + return res; + } + + public static getTimeStringHMS(ns: number): string { + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; // 1 second + let millisecond1 = 1_000_000; // 1 millisecond + let microsecond1 = 1_000; // 1 microsecond + let res = ''; + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1) + ':'; + currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + ':'; + currentNs = currentNs - Math.floor(ns / minute1) * minute1; + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + ':'; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + } + if (currentNs >= millisecond1) { + res += Math.floor(currentNs / millisecond1) + '.'; + currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; + } + if (currentNs >= microsecond1) { + res += Math.floor(currentNs / microsecond1) + '.'; + currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; + } + if (currentNs > 0) { + res += currentNs + ''; + } + if (res == '') { + res = ns + ''; + } + return res; + } + + public static getByteWithUnit(bytes: number): string { + if (bytes < 0) { + return '-' + this.getByteWithUnit(Math.abs(bytes)); + } + let currentBytes = bytes; + let kb1 = 1 << 10; + let mb1 = (1 << 10) << 10; + let gb1 = ((1 << 10) << 10) << 10; // 1 gb + let res = ''; + if (currentBytes > gb1) { + res += (currentBytes / gb1).toFixed(2) + ' Gb'; + } else if (currentBytes > mb1) { + res += (currentBytes / mb1).toFixed(2) + ' Mb'; + } else if (currentBytes > kb1) { + res += (currentBytes / kb1).toFixed(2) + ' Kb'; + } else { + res += Math.round(currentBytes) + ' byte'; + } + return res; + } + + public static groupByMap(array: Array, key: string) { + let result = new Map(); + array.forEach((item) => { + let value = item[key]; + if (!result.has(value)) { + result.set(value, []); + } + result.get(value).push(item); + }); + return result; + } + + public static groupBy(array: Array, key: string) { + return array.reduce((pre, current, index, arr) => { + (pre[current[key]] = pre[current[key]] || []).push(current); + return pre; + }, {}); + } + + public static timeMsFormat2p(ns: number) { + let currentNs = ns; + let hour1 = 3600_000; + let minute1 = 60_000; + let second1 = 1_000; // 1 second + let res = ''; + if (currentNs >= hour1) { + res += Math.round(currentNs / hour1).toFixed(2) + 'h'; + return res; + } + if (currentNs >= minute1) { + res += Math.round(currentNs / minute1).toFixed(2) + 'min'; + return res; + } + if (currentNs >= second1) { + res += Math.round(currentNs / second1).toFixed(2) + 's'; + return res; + } + if (currentNs > 0) { + res += currentNs.toFixed(2) + 'ms'; + return res; + } + if (res == '') { + res = '0s'; + } + return res; + } + + public static uuid(): string { + // @ts-ignore + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => + (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) + ); + } + + public static getBinaryKBWithUnit(kbytes: number): string { + if (kbytes == 0) { + return '0KB'; + } + let currentBytes = kbytes; + let mib1 = 1024; + let gib1 = 1024 * 1024; + let res = ''; + if (currentBytes >= gib1) { + res += (currentBytes / gib1).toFixed(2) + 'GB'; + } else if (currentBytes >= mib1) { + res += (currentBytes / mib1).toFixed(2) + 'MB'; + } else { + res += currentBytes.toFixed(2) + 'KB'; + } + return res; + } + + public static getBinaryByteWithUnit(bytes: number): string { + if (bytes == 0) { + return '0Bytes'; + } + let currentBytes = bytes; + let kib1 = 1024; + let mib1 = 1024 * 1024; + let gib1 = 1024 * 1024 * 1024; + let res = ''; + if (currentBytes >= gib1) { + res += (currentBytes / gib1).toFixed(2) + 'GB'; + } else if (currentBytes >= mib1) { + res += (currentBytes / mib1).toFixed(2) + 'MB'; + } else if (currentBytes >= kib1) { + res += (currentBytes / kib1).toFixed(2) + 'KB'; + } else { + res += currentBytes.toFixed(2) + 'Bytes'; + } + return res; + } + + public static getTimeStampHMS(ns: number): string { + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; // 1 second + let millisecond1 = 1_000_000; // 1 millisecond + let microsecond1 = 1_000; // 1 microsecond + let res = ''; + if (currentNs >= hour1) { + res += this.getCompletionTime(Math.floor(currentNs / hour1), 2) + ':'; + currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; + } + if (currentNs >= minute1) { + res += this.getCompletionTime(Math.floor(currentNs / minute1), 2) + ':'; + currentNs = currentNs - Math.floor(ns / minute1) * minute1; + } + if (currentNs >= second1) { + res += this.getCompletionTime(Math.floor(currentNs / second1), 2) + ':'; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + } else { + res += '00:'; + } + if (currentNs >= millisecond1) { + res += this.getCompletionTime(Math.floor(currentNs / millisecond1), 3) + '.'; + currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; + } else { + res += '000.'; + } + if (currentNs >= microsecond1) { + res += this.getCompletionTime(Math.floor(currentNs / microsecond1), 3) + '.'; + currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; + } else { + res += '000'; + } + if (currentNs > 0) { + res += this.getCompletionTime(currentNs, 3); + } + if (res == '') { + res = ns + ''; + } + return res; + } + + public static getDurString(ns: number): string { + let currentNs = ns; + let second1 = 1000000000; + let millisecond1 = 1000000; + let res = ''; + if (currentNs >= second1) { + let cu = currentNs / second1; + res += cu.toFixed(3) + ' s '; + return res; + } + if (currentNs >= millisecond1) { + res += Math.floor(currentNs / millisecond1) + ' ms '; + return res; + } + if (res == '') { + res = ns + ''; + } + return res; + } + + private static getCompletionTime(time: number, maxLength: number): string { + if (maxLength == 2) { + if (time.toString().length == 2) { + return '' + time; + } else { + return '0' + time; + } + } else if (maxLength == 3) { + if (time.toString().length == 3) { + return time.toString(); + } else if (time.toString().length == 2) { + return '0' + time; + } else { + return '00' + time; + } + } else { + return '0'; + } + } + + public getStatusMap(): Map { + return Utils.statusMap; + } + + public static removeDuplicates(array1: any[], array2: any[], key: string) { + let obj: any = {}; + return array1.concat(array2).reduce(function (total, item) { + if (!obj[`${item[key]}-${item['pid']}`]) { + obj[`${item[key]}-${item['pid']}`] = true; + total.push(item); + } + return total; + }, []); + } + + static getFrequencyWithUnit = (maxFreq: number) => { + let maxFreqObj = { + maxFreqName: ' ', + maxFreq: 0, + }; + let units: Array = ['', 'K', 'M', 'G', 'T', 'E']; + let sb = ' '; + if (maxFreq > 0) { + let log10: number = Math.ceil(Math.log10(maxFreq)); + let pow10: number = Math.pow(10, log10); + let afterCeil: number = Math.ceil(maxFreq / (pow10 / 4)) * (pow10 / 4); + maxFreqObj.maxFreq = afterCeil; + let unitIndex: number = Math.floor(log10 / 3); + sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}`; + } + maxFreqObj.maxFreqName = sb.toString(); + return maxFreqObj; + }; + + public static getTimeIsCross(startTime: number, endTime: number, startTime1: number, endTime1: number) { + return Math.max(startTime, startTime1) <= Math.min(endTime, endTime1); + } +} diff --git a/ide/src/trace/component/trace/search/Search.ts b/ide/src/trace/component/trace/search/Search.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9d5975d0e6045df87764d70da187ab270bd8595 --- /dev/null +++ b/ide/src/trace/component/trace/search/Search.ts @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; + +@element('lit-search') +export class LitSearch extends BaseElement { + valueChangeHandler: ((str: string) => void) | undefined | null; + private search: HTMLInputElement | undefined | null; + private _total: number = 0; + private _index: number = 0; + private _list: Array = []; + private totalEL: HTMLSpanElement | null | undefined; + private indexEL: HTMLSpanElement | null | undefined; + + get list(): Array { + return this._list; + } + + set list(value: Array) { + this._list = value; + this.total = value.length; + } + + get index(): number { + return this._index; + } + + set index(value: number) { + this._index = value; + this.indexEL!.textContent = `${value + 1}`; + } + + get searchValue() { + return this.search?.value; + } + + get total(): number { + return this._total; + } + + set total(value: number) { + value > 0 ? this.setAttribute('show-search-info', '') : this.removeAttribute('show-search-info'); + this._total = value; + this.indexEL!.textContent = '0'; + this.totalEL!.textContent = value.toString(); + } + + get isLoading(): boolean { + return this.hasAttribute('isLoading'); + } + + set isLoading(va) { + if (va) { + this.setAttribute('isLoading', ''); + } else { + this.removeAttribute('isLoading'); + } + } + + setPercent(name: string = '', value: number) { + let searchHide = this.shadowRoot!.querySelector('.root'); + let searchIcon = this.shadowRoot!.querySelector('#search-icon'); + if (this.hasAttribute('textRoll')) { + this.removeAttribute('textRoll'); + } + this.isLoading = false; + if (value > 0 && value <= 100) { + searchHide!.style.display = 'flex'; + searchHide!.style.backgroundColor = 'var(--dark-background5,#e3e3e3)'; + searchIcon?.setAttribute('name', 'cloud-sync'); + this.search!.setAttribute('placeholder', `${name}${value}%`); + this.search!.setAttribute('readonly', ''); + this.search!.className = 'readonly'; + this.isLoading = true; + } else if (value > 100) { + searchHide!.style.display = 'flex'; + searchHide!.style.backgroundColor = 'var(--dark-background5,#fff)'; + searchIcon?.setAttribute('name', 'search'); + this.search?.setAttribute('placeholder', `search`); + this.search?.removeAttribute('readonly'); + this.search!.className = 'write'; + } else if (value == -1) { + searchHide!.style.display = 'flex'; + searchHide!.style.backgroundColor = 'var(--dark-background5,#e3e3e3)'; + searchIcon?.setAttribute('name', 'cloud-sync'); + this.search!.setAttribute('placeholder', `${name}`); + this.search!.setAttribute('readonly', ''); + this.search!.className = 'readonly'; + } else if (value == -2) { + searchHide!.style.display = 'flex'; + searchHide!.style.backgroundColor = 'var(--dark-background5,#e3e3e3)'; + searchIcon?.setAttribute('name', 'cloud-sync'); + this.search!.setAttribute('placeholder', `${name}`); + this.search!.setAttribute('readonly', ''); + this.search!.className = 'text-Roll'; + setTimeout(() => { + this.setAttribute('textRoll', ''); + }, 200); + } else { + searchHide!.style.display = 'none'; + } + } + + clear() { + this.search = this.shadowRoot!.querySelector('input'); + this.search!.value = ''; + this.list = []; + } + + blur() { + this.search?.blur(); + } + + initElements(): void { + this.search = this.shadowRoot!.querySelector('input'); + this.totalEL = this.shadowRoot!.querySelector('#total'); + this.indexEL = this.shadowRoot!.querySelector('#index'); + this.search!.addEventListener('focus', (e) => { + this.dispatchEvent( + new CustomEvent('focus', { + detail: { + value: this.search!.value, + }, + }) + ); + }); + this.search!.addEventListener('blur', (e) => { + this.dispatchEvent( + new CustomEvent('blur', { + detail: { + value: this.search!.value, + }, + }) + ); + }); + this.search!.addEventListener('change', (event) => { + this.index = -1; + }); + + this.search!.addEventListener('keyup', (e: KeyboardEvent) => { + if (e.code == 'Enter') { + if (e.shiftKey) { + this.dispatchEvent( + new CustomEvent('previous-data', { + detail: { + value: this.search!.value, + }, + composed: false, + }) + ); + } else { + this.dispatchEvent( + new CustomEvent('next-data', { + detail: { + value: this.search!.value, + }, + composed: false, + }) + ); + } + } else { + this.valueChangeHandler?.(this.search!.value); + } + e.stopPropagation(); + }); + this.shadowRoot?.querySelector('#arrow-left')?.addEventListener('click', (e) => { + this.dispatchEvent( + new CustomEvent('previous-data', { + detail: { + value: this.search!.value, + }, + }) + ); + }); + this.shadowRoot?.querySelector('#arrow-right')?.addEventListener('click', (e) => { + this.dispatchEvent( + new CustomEvent('next-data', { + detail: { + value: this.search!.value, + }, + }) + ); + }); + } + + initHtml(): string { + return ` + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts b/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b37647815feba324b818a0b24d5b8012f56aab5 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts @@ -0,0 +1,1062 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../base-ui/table/lit-table.js'; +import '../../../../base-ui/table/lit-table-column.js'; + +import { + queryBinderArgsByArgset, + queryBinderByArgsId, + queryBinderBySliceId, + queryFlowsData, + queryGpuDur, + queryPrecedingData, + queryRunnableTimeByRunning, + queryThreadStateArgs, + queryThreadWakeUp, + queryThreadWakeUpFrom, +} from '../../../database/SqlLite.js'; +import { WakeupBean } from '../../../bean/WakeupBean.js'; +import { SpApplication } from '../../../SpApplication.js'; +import { TraceRow } from '../base/TraceRow.js'; +import { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js'; +import { ThreadStruct } from '../../../database/ui-worker/ProcedureWorkerThread.js'; +import { FuncStruct } from '../../../database/ui-worker/ProcedureWorkerFunc.js'; +import { ProcessMemStruct } from '../../../database/ui-worker/ProcedureWorkerMem.js'; +import { ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock.js'; +import { ColorUtils } from '../base/ColorUtils.js'; +import { IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq.js'; +import { BinderArgBean } from '../../../bean/BinderArgBean.js'; +import { JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank.js'; +import { LitIcon } from '../../../../base-ui/icon/LitIcon.js'; +import { Utils } from '../base/Utils.js'; + +const INPUT_WORD = + 'This is the interval from when the task became eligible to run \n(e.g.because of notifying a wait queue it was a suspended on) to\n when it started running.'; + +export function getTimeString(ns: number): string { + if (ns === 0) { + return '0'; + } + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; // 1 second + let millisecond1 = 1_000_000; // 1 millisecond + let microsecond1 = 1_000; // 1 microsecond + let res = ''; + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1) + 'h '; + currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + 'm '; + currentNs = currentNs - Math.floor(ns / minute1) * minute1; + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + 's '; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + } + if (currentNs >= millisecond1) { + res += Math.floor(currentNs / millisecond1) + 'ms '; + currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; + } + if (currentNs >= microsecond1) { + res += Math.floor(currentNs / microsecond1) + 'μs '; + currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; + } + if (currentNs > 0) { + res += currentNs + 'ns '; + } + return res; +} + +@element('tabpane-current-selection') +export class TabPaneCurrentSelection extends BaseElement { + weakUpBean: WakeupBean | null | undefined; + private tbl: LitTable | null | undefined; + private tableObserver: MutationObserver | undefined; + // @ts-ignore + private dpr: any = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1; + + set data(value: any) { + this.setCpuData(value); + } + + setCpuData( + data: CpuStruct, + callback: ((data: WakeupBean | null) => void) | undefined = undefined, + scrollCallback?: (data: CpuStruct) => void + ) { + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + if (leftTitle) { + leftTitle.innerText = 'Slice Details'; + } + let list: any[] = []; + let process = this.transferString(data.processName || 'Process'); + let processId = data.processId || data.tid; + let state = ''; + if (data.end_state) { + state = Utils.getEndState(data.end_state); + } else if (data.end_state == '' || data.end_state == null) { + state = ''; + } else { + state = 'Unknown State'; + } + list.push({ + name: 'Process', + value: `${process || 'Process'} [${processId}]`, + }); + let name = this.transferString(data.name ?? ''); + if (data.processId) { + list.push({ + name: 'Thread', + value: `
+
${name || 'Process'} [${data.tid}]
+ +
`, + }); + } else { + list.push({ + name: 'Thread', + value: `
+
${name || 'Process'} [${data.tid}]
+
`, + }); + } + + list.push({ name: 'CmdLine', value: `${data.processCmdLine}` }); + list.push({ + name: 'StartTime(Relative)', + value: getTimeString(data.startTime || 0), + }); + list.push({ + name: 'StartTime(Absolute)', + value: ((data.startTime || 0) + (window as any).recordStartNS) / 1000000000, + }); + list.push({ name: 'Duration', value: getTimeString(data.dur || 0) }); + list.push({ name: 'Prio', value: data.priority || 0 }); + list.push({ name: 'End State', value: state }); + Promise.all([this.queryThreadStateDArgs(data.argSetID), this.queryCPUWakeUpFromData(data)]).then((resArr) => { + let args = resArr[0]; + let bean = resArr[1]; + if (callback) { + callback(bean); + } + if (args.length > 0) { + args.forEach((arg) => { + list.push({ name: arg.keyName, value: arg.strValue }); + }); + } + this.tbl!.dataSource = list; + let rightArea: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#right-table'); + let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle'); + let threadClick = this.tbl?.shadowRoot?.querySelector('#thread-id'); + threadClick?.addEventListener('click', () => { + //cpu点击 + if (scrollCallback) { + scrollCallback(data); + } + }); + let canvas = this.initCanvas(); + if (bean != null) { + this.weakUpBean = bean; + if (rightArea != null && rightArea) { + rightArea.style.visibility = 'visible'; + } + if (rightTitle != null && rightTitle) { + rightTitle.style.visibility = 'visible'; + } + this.drawRight(canvas, bean); + } else { + this.weakUpBean = null; + if (rightArea != null && rightArea) { + rightArea.style.visibility = 'hidden'; + } + if (rightTitle != null && rightTitle) { + rightTitle.style.visibility = 'hidden'; + } + } + }); + } + + setFunctionData(data: FuncStruct, scrollCallback: Function) { + //方法信息 + this.initCanvas(); + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle'); + if (rightTitle) { + rightTitle.style.visibility = 'hidden'; + } + if (leftTitle) { + leftTitle.innerText = 'Slice Details'; + } + let list: any[] = []; + let name = this.transferString(data.funName ?? ''); + let isBinder = FuncStruct.isBinder(data); + let isAsyncBinder = isBinder && FuncStruct.isBinderAsync(data); + if (data.argsetid != undefined && data.argsetid != null) { + if (isAsyncBinder) { + Promise.all([ + queryBinderByArgsId(data.argsetid!, data.startTs!, !data.funName!.endsWith('rcv')), + queryBinderArgsByArgset(data.argsetid), + ]).then((result) => { + let asyncBinderRes = result[0]; + let argsBinderRes = result[1]; + let asyncBinderStract: any; + if (asyncBinderRes.length > 0) { + asyncBinderRes[0].type = TraceRow.ROW_TYPE_FUNC; + asyncBinderStract = asyncBinderRes[0]; + } + if (argsBinderRes.length > 0) { + argsBinderRes.forEach((item) => { + list.push({ + name: item.keyName, + value: item.strValue, + }); + }); + } + if (asyncBinderStract != undefined) { + list.unshift({ + name: 'Name', + value: `
+
${name || 'binder'}
+ +
`, + }); + } else { + list.unshift({ name: 'Name', value: name }); + } + list.push({ + name: 'StartTime', + value: getTimeString(data.startTs || 0), + }); + list.push({ + name: 'Duration', + value: getTimeString(data.dur || 0), + }); + list.push({ name: 'depth', value: data.depth }); + list.push({ name: 'arg_set_id', value: data.argsetid }); + this.tbl!.dataSource = list; + let funcClick = this.tbl?.shadowRoot?.querySelector('#function-jump'); + funcClick?.addEventListener('click', () => { + scrollCallback(asyncBinderStract); + }); + }); + } else if (isBinder) { + queryBinderArgsByArgset(data.argsetid).then((argset) => { + let binderSliceId = -1; + argset.forEach((item) => { + if (item.keyName == 'destination slice id') { + binderSliceId = Number(item.strValue); + list.unshift({ + name: 'Name', + value: `
+
${name || 'binder'}
+ +
`, + }); + } + list.push({ name: item.keyName, value: item.strValue }); + }); + if (binderSliceId == -1) { + list.unshift({ name: 'Name', value: name }); + } + list.push({ + name: 'StartTime', + value: getTimeString(data.startTs || 0), + }); + list.push({ + name: 'Duration', + value: getTimeString(data.dur || 0), + }); + list.push({ name: 'depth', value: data.depth }); + list.push({ name: 'arg_set_id', value: data.argsetid }); + this.tbl!.dataSource = list; + let funcClick = this.tbl?.shadowRoot?.querySelector('#function-jump'); + funcClick?.addEventListener('click', () => { + if (!Number.isNaN(binderSliceId) && binderSliceId != -1) { + queryBinderBySliceId(binderSliceId).then((result: any[]) => { + if (result.length > 0) { + result[0].type = TraceRow.ROW_TYPE_FUNC; + scrollCallback(result[0]); + } + }); + } + }); + }); + } else { + queryBinderArgsByArgset(data.argsetid).then((argset) => { + list.push({ name: 'Name', value: name }); + argset.forEach((item) => { + list.push({ name: item.keyName, value: item.strValue }); + }); + list.push({ + name: 'StartTime', + value: getTimeString(data.startTs || 0), + }); + list.push({ + name: 'Duration', + value: getTimeString(data.dur || 0), + }); + list.push({ name: 'depth', value: data.depth }); + list.push({ name: 'arg_set_id', value: data.argsetid }); + this.tbl!.dataSource = list; + }); + } + } else { + list.push({ name: 'Name', value: name }); + list.push({ + name: 'StartTime', + value: getTimeString(data.startTs || 0), + }); + list.push({ + name: 'Duration', + value: getTimeString(data.dur || 0), + }); + list.push({ name: 'depth', value: data.depth }); + this.tbl!.dataSource = list; + } + } + + setClockData(data: ClockStruct) { + //时钟信息 + this.initCanvas(); + let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle'); + if (rightTitle) { + rightTitle.style.visibility = 'hidden'; + } + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + if (leftTitle) { + leftTitle.innerText = 'Counter Details'; + } + let list: any[] = []; + list.push({ + name: 'Start time', + value: getTimeString(data.startNS || 0), + }); + list.push({ + name: 'Value', + value: ColorUtils.formatNumberComma(data.value || 0), + }); + // list.push({name: 'Delta', value: ColorUtils.formatNumberComma(data.delta||0)}) + list.push({ name: 'Duration', value: getTimeString(data.dur || 0) }); + this.tbl!.dataSource = list; + } + + setMemData(data: ProcessMemStruct) { + //时钟信息 + this.initCanvas(); + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + if (leftTitle) { + leftTitle.innerText = 'Counter Details'; + } + let list: any[] = []; + list.push({ + name: 'Start time', + value: getTimeString(data.startTime || 0), + }); + list.push({ name: 'Value', value: data.value }); + list.push({ name: 'Delta', value: data.delta }); + list.push({ + name: 'Duration', + value: getTimeString(data.duration || 0), + }); + this.tbl!.dataSource = list; + } + + setIrqData(data: IrqStruct) { + this.initCanvas(); + let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle'); + if (rightTitle) { + rightTitle.style.visibility = 'hidden'; + } + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + if (leftTitle) { + leftTitle.innerText = 'Counter Details'; + } + let list: any[] = []; + list.push({ + name: 'Start time', + value: getTimeString(data.startNS || 0), + }); + list.push({ name: 'Name', value: data.name }); + list.push({ name: 'Duration', value: getTimeString(data.dur || 0) }); + queryBinderArgsByArgset(data.argSetId || 0).then((argsBinderRes) => { + if (argsBinderRes.length > 0) { + argsBinderRes.forEach((item) => { + list.push({ name: item.keyName, value: item.strValue }); + }); + } + this.tbl!.dataSource = list; + }); + } + + setThreadData( + data: ThreadStruct, + scrollCallback: ((d: any) => void) | undefined, + scrollWakeUp: (d: any) => void | undefined + ) { + //线程信息 + this.initCanvas(); + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle'); + if (rightTitle) { + rightTitle.style.visibility = 'hidden'; + } + if (leftTitle) { + leftTitle.innerText = 'Thread State'; + } + let list: any[] = []; + list.push({ + name: 'StartTime', + value: getTimeString(data.startTime || 0), + }); + list.push({ name: 'Duration', value: getTimeString(data.dur || 0) }); + let state = ''; + if (data.state) { + state = Utils.getEndState(data.state); + } else if (data.state == '' || data.state == null) { + state = ''; + } else { + state = 'Unknown State'; + } + if ('Running' == state) { + state = state + ' on CPU ' + data.cpu; + } + if (data.cpu == null || data.cpu == undefined) { + list.push({ name: 'State', value: `${state}` }); + } else { + list.push({ + name: 'State', + value: `
+
${state}
+ +
`, + }); + } + let slice = Utils.SCHED_SLICE_MAP.get(`${data.id}-${data.startTime}`); + if (slice) { + list.push({ name: 'Prio', value: `${slice.priority}` }); + } + let processName = Utils.PROCESS_MAP.get(data.pid!); + if (processName == null || processName == '' || processName.toLowerCase() == 'null') { + processName = Utils.THREAD_MAP.get(data.tid!) || 'null'; + } + list.push({ + name: 'Process', + value: this.transferString(processName ?? '') + ' [' + data.pid + '] ', + }); + let cpu = new CpuStruct(); + cpu.id = data.id; + cpu.startTime = data.startTime; + Promise.all([ + this.queryThreadWakeUpFromData(data.id!, data.startTime!, data.dur!), + this.queryThreadWakeUpData(data.id!, data.startTime!, data.dur!), + this.queryThreadStateDArgs(data.argSetID), + ]).then((result) => { + let fromBean = result[0]; + let wakeUps = result[1]; + let args = result[2]; + if (fromBean != null && fromBean != undefined && fromBean.pid != 0 && fromBean.tid != 0) { + list.push({ + name: 'wakeup from tid', + value: `
+
${fromBean.tid}
+ +
`, + }); + } + if (wakeUps != null) { + wakeUps.map((e) => { + list.push({ + name: 'wakeup tid', + value: `
+
${e.tid}
+ +
`, + }); + }); + } + if (args.length > 0) { + args.forEach((arg) => { + list.push({ name: arg.keyName, value: arg.strValue }); + }); + } + this.tbl!.dataSource = list; + this.tbl?.shadowRoot?.querySelector('#state-click')?.addEventListener('click', () => { + //线程点击 + if (scrollCallback) { + scrollCallback(data); + } + }); + this.tbl?.shadowRoot?.querySelector('#wakeup-from')?.addEventListener('click', (e) => { + //点击跳转,唤醒和被唤醒的 线程 + if (fromBean && scrollWakeUp) { + scrollWakeUp({ + processId: fromBean.pid, + tid: fromBean.tid, + startTime: fromBean.ts, + }); + } + }); + if (wakeUps) { + wakeUps.map((up) => { + this.tbl?.shadowRoot?.querySelector(`#wakeup-${up.tid}`)?.addEventListener('click', (e) => { + //点击跳转,唤醒和被唤醒的 线程 + if (up && scrollWakeUp != undefined) { + scrollWakeUp({ + tid: up.tid, + startTime: up.ts, + processId: up.pid, + }); + } + }); + }); + } + }); + } + + setJankData( + data: JankStruct, + callback: ((data: Array) => void) | undefined = undefined, + scrollCallback: ((d: any) => void) | undefined + ) { + //线程信息 + this.initCanvas(); + let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle'); + let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle'); + if (rightTitle) { + rightTitle.style.visibility = 'hidden'; + } + if (leftTitle) { + leftTitle.innerText = 'Slice Details'; + } + let list: any[] = []; + list.push({ name: 'Name', value: data.name }); + list.push({ name: 'StartTime', value: getTimeString(data.ts || 0) }); + list.push({ + name: 'Absolute Time', + value: ((window as any).recordStartNS + data.ts) / 1000000000, + }); + list.push({ + name: 'Duration', + value: data.dur ? getTimeString(data.dur) : ' ', + }); + if (data.frame_type != 'frameTime') { + list.push({ + name: 'Process', + value: data.cmdline + ' ' + data.pid, + }); + } + if (data.type == '0') { + if (data.jank_tag) { + if (data.frame_type === 'render_service') { + list.push({ + name: 'Jank Type', + value: 'RenderService Deadline Missed', + }); + } else if (data.frame_type === 'app') { + list.push({ + name: 'Jank Type', + value: 'APP Deadline Missed', + }); + } else if (data.frame_type === 'frameTime') { + list.push({ name: 'Jank Type', value: 'Deadline Missed' }); + } + } else { + list.push({ name: 'Jank Type', value: 'NONE' }); + } + let jankJumperList = new Array(); + if (data.frame_type === 'render_service') { + queryGpuDur(data.id!).then((it) => { + if (it.length > 0) { + list.push({ + name: `
Gpu Duration
`, + value: getTimeString(it[0].gpu_dur), + }); + } + }); + if (data.src_slice) { + queryFlowsData(data.src_slice!.split(',')).then((it) => { + if (it.length > 0) { + list.push({ + name: `
FrameTimeLine flows
`, + value: '', + }); + it.forEach((a: any) => { + let appNode = new JankTreeNode(a.name, a.pid, 'app'); + let timeLineNode = new JankTreeNode(a.name, a.pid, 'frameTime'); + appNode.children.push(timeLineNode); + jankJumperList.push(appNode); + list.push({ + name: `
Slice
`, + value: + a.cmdline + + ' [' + + a.name + + ']' + + ``, + }); + }); + list.push({ + name: `
Following flows
`, + value: '', + }); + it.forEach((a: any) => { + list.push({ + name: `
Slice
`, + value: + a.cmdline + + ' [' + + a.name + + ']' + + ``, + }); + }); + this.tbl!.dataSource = list; + let all = this.tbl?.shadowRoot?.querySelectorAll(`.jank_cla`); + all!.forEach((a) => { + a.addEventListener('click', (e) => { + if (scrollCallback) { + scrollCallback({ + rowId: a.id, + name: a.getAttribute('slice_name'), + pid: a.getAttribute('pid'), + }); + } + }); + }); + if (callback) { + callback(jankJumperList); + } + } + }); + } else { + this.tbl!.dataSource = list; + } + } else if (data.frame_type === 'app') { + list.push({ + name: `
FrameTimeLine flows
`, + value: '', + }); + list.push({ + name: `
Slice
`, + value: + data.cmdline + + ' [' + + data.name + + ']' + + ``, + }); + let timeLineNode = new JankTreeNode(data.name!, data.pid!, 'frameTime'); + jankJumperList.push(timeLineNode); + if (data.dst_slice) { + queryPrecedingData(data.dst_slice).then((it) => { + if (it.length > 0) { + list.push({ + name: `
Preceding flows
`, + value: '', + }); + it.forEach((a: any) => { + let rsNode = new JankTreeNode(a.name, a.pid, 'render_service'); + jankJumperList.push(rsNode); + list.push({ + name: `
Slice
`, + value: + a.cmdline + + ' [' + + a.name + + ']' + + ``, + }); + }); + this.tbl!.dataSource = list; + let all = this.tbl?.shadowRoot?.querySelectorAll(`.jank_cla`); + all!.forEach((a) => { + a.addEventListener('click', (e) => { + if (scrollCallback) { + scrollCallback({ + rowId: a.id, + name: a.getAttribute('slice_name'), + pid: a.getAttribute('pid'), + }); + } + }); + }); + if (callback) { + callback(jankJumperList); + } + } + }); + } else { + this.tbl!.dataSource = list; + let all = this.tbl?.shadowRoot?.querySelectorAll(`.jank_cla`); + all!.forEach((a) => { + a.addEventListener('click', (e) => { + if (scrollCallback) { + scrollCallback({ + rowId: a.id, + name: a.getAttribute('slice_name'), + pid: a.getAttribute('pid'), + }); + } + }); + }); + if (callback) { + callback(jankJumperList); + } + } + } else if (data.frame_type === 'frameTime') { + queryGpuDur(data.id!).then((it) => { + if (it.length > 0) { + list.push({ + name: `
Gpu Duration
`, + value: getTimeString(it[0].gpu_dur), + }); + } + if (data.name) { + list.push({ + name: `
App Frame
`, + value: '', + }); + list.push({ + name: `
Process
`, + value: data.cmdline + ' ' + data.pid, + }); + list.push({ + name: `
start time
`, + value: getTimeString(data.ts || 0), + }); + list.push({ + name: `
end time
`, + value: getTimeString(data!.ts! + data.dur! || 0), + }); + } + if (data.rs_name) { + list.push({ + name: `
RenderService Frame
`, + value: '', + }); + list.push({ + name: `
Process
`, + value: data.rs_name + ' ' + data.rs_pid, + }); + list.push({ + name: `
start time
`, + value: getTimeString(data.rs_ts || 0), + }); + list.push({ + name: `
end time
`, + value: getTimeString(data.rs_ts! + data.rs_dur! || 0), + }); + } + list.push({ + name: `
Following
`, + value: '', + }); + list.push({ + name: `
Slice
`, + value: + data.cmdline + + ' [' + + data.name + + ']' + + ``, + }); + let appNode = new JankTreeNode(data.name!, data.pid!, 'app'); + let rsNode = new JankTreeNode(data.rs_vsync!, data.rs_pid!, 'render_service'); + appNode.children.push(rsNode); + jankJumperList.push(appNode); + this.tbl!.dataSource = list; + let all = this.tbl?.shadowRoot?.querySelectorAll(`.jank_cla`); + all!.forEach((a) => { + a!.addEventListener('click', (e) => { + if (scrollCallback) { + scrollCallback({ + rowId: a.id, + name: a.getAttribute('slice_name'), + pid: a.getAttribute('pid'), + }); + } + }); + }); + if (callback) { + callback(jankJumperList); + } + }); + } + } else { + this.tbl!.dataSource = list; + } + } + + async queryThreadStateDArgs(argSetID: number | undefined) { + let list: Array = []; + if (argSetID !== undefined) { + list = await queryThreadStateArgs(argSetID); + } + return list; + } + + /** + * 查询出 线程被唤醒的 线程信息 + * @param data + */ + async queryCPUWakeUpFromData(data: CpuStruct) { + let wb: WakeupBean | null = null; + if (data.id == undefined || data.startTime == undefined) { + return null; + } + let wakeup = await queryRunnableTimeByRunning(data.tid!, data.startTime); + if (wakeup && wakeup[0]) { + let wakeupTs = wakeup[0].ts as number; + let recordStartTs = (window as any).recordStartNS; + let wf = await queryThreadWakeUpFrom(data.id, wakeupTs); + if (wf && wf[0]) { + wb = wf[0]; + if (wb != null) { + wb.wakeupTime = wakeupTs - recordStartTs; + wb.process = Utils.PROCESS_MAP.get(wb.pid!); + wb.thread = Utils.THREAD_MAP.get(wb.tid!); + wb.schedulingLatency = (data.startTime || 0) - (wb.wakeupTime || 0); + if (wb.process == null) { + wb.process = wb.thread; + } + if (wb.pid == undefined) { + wb.pid = wb.tid; + } + wb.schedulingDesc = INPUT_WORD; + } + } + } + return wb; + } + + /** + * 查询出 线程唤醒了哪些线程信息 + * @param data + */ + async queryThreadWakeUpFromData(itid: number, startTime: number, dur: number): Promise { + let wakeUps = await queryThreadWakeUpFrom(itid, startTime + (window as any).recordStartNS); + if (wakeUps != undefined && wakeUps.length > 0) { + return wakeUps[0]; + } + } + + /** + * 查询出 线程唤醒了哪些线程信息 + * @param data + */ + async queryThreadWakeUpData(itid: number, startTime: number, dur: number): Promise> { + let list: Array = []; + if (itid == undefined || startTime == undefined) { + return list; + } + let wakeUps = await queryThreadWakeUp(itid, startTime, dur); // 3,4835380000 + if (wakeUps != undefined && wakeUps.length > 0) { + list.push(...wakeUps); + } + return list; + } + + initCanvas(): HTMLCanvasElement | null { + let canvas = this.shadowRoot!.querySelector('#rightDraw'); + let width = getComputedStyle(this.tbl!).getPropertyValue('width'); + let height = getComputedStyle(this.tbl!).getPropertyValue('height'); + if (canvas != null) { + canvas.width = Math.round(Number(width.replace('px', '')) * this.dpr); + canvas.height = Math.round(Number(height.replace('px', '')) * this.dpr); + canvas.style.width = width; + canvas.style.height = height; + canvas.getContext('2d')!.scale(this.dpr, this.dpr); + } + SpApplication.skinChange = (val: boolean) => { + this.drawRight(canvas, this.weakUpBean!); + }; + return canvas; + } + + drawRight(cavs: HTMLCanvasElement | null, wakeupBean: WakeupBean | null) { + if (cavs == null) { + return; + } + let context = cavs.getContext('2d'); + if (context != null) { + //绘制竖线 + if (document.querySelector('sp-application')!.dark) { + context.strokeStyle = '#ffffff'; + context.fillStyle = '#ffffff'; + } else { + context.strokeStyle = '#000000'; + context.fillStyle = '#000000'; + } + context.lineWidth = 2; + context.moveTo(10, 15); + context.lineTo(10, 125); + context.stroke(); + //绘制菱形 + context.lineWidth = 1; + context.beginPath(); + context.moveTo(10, 30); + context.lineTo(4, 40); + context.lineTo(10, 50); + context.lineTo(16, 40); + context.lineTo(10, 30); + context.closePath(); + context.fill(); + context.font = 12 + 'px sans-serif'; + //绘制wake up 文字 + let strList = []; + strList.push('wakeup @ ' + getTimeString(wakeupBean?.wakeupTime || 0) + ' on CPU ' + wakeupBean?.cpu + ' by'); + strList.push('P:' + wakeupBean?.process + ' [ ' + wakeupBean?.pid + ' ]'); + strList.push('T:' + wakeupBean?.thread + ' [ ' + wakeupBean?.tid + ' ]'); + strList.forEach((str, index) => { + if (context != null) { + context.fillText(str, 40, 40 + 16 * index); + } + }); + //绘制左右箭头 + context.lineWidth = 2; + context.lineJoin = 'bevel'; + context.moveTo(10, 95); + context.lineTo(20, 90); + context.moveTo(10, 95); + context.lineTo(20, 100); + context.moveTo(10, 95); + context.lineTo(80, 95); + context.lineTo(70, 90); + context.moveTo(80, 95); + context.lineTo(70, 100); + context.stroke(); + //绘制latency + context.font = 12 + 'px sans-serif'; + context.fillText('Scheduling latency:' + getTimeString(wakeupBean?.schedulingLatency || 0), 90, 100); + //绘制最下方提示语句 + context.font = 10 + 'px sans-serif'; + INPUT_WORD.split('\n').forEach((str, index) => { + context?.fillText(str, 90, 120 + 12 * index); + }); + } + } + + transferString(str: string): string { + let s = ''; + if (str.length == 0) { + return ''; + } + s = str.replace(/&/g, '&'); + s = s.replace(//g, '>'); + // s = s.replace(/ /g," ") + s = s.replace(/\'/g, '''); + s = s.replace(/\"/g, '&#quat;'); + // s = s.replace(/(/g,"&") + // s = s.replace(/)/g,"&") + return s; + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#selectionTbl'); + this.tbl?.addEventListener('column-click', (ev: any) => {}); + this.addTableObserver(); + } + + addTableObserver() { + let MutationObserver = window.MutationObserver; + this.tableObserver = new MutationObserver((list) => { + if (this.tbl) { + let width = getComputedStyle(this.tbl).getPropertyValue('width'); + let height = getComputedStyle(this.tbl).getPropertyValue('height'); + } + }); + let selector = this.shadowRoot?.querySelector('.left-table'); + this.tableObserver?.observe(selector!, { + attributes: true, + attributeFilter: ['style'], + attributeOldValue: true, + }); + } + + initHtml(): string { + return ` + +
+
+

+

Scheduling Latency

+
+
+
+ + + + + + + + +
+
+ +
+
+
+ `; + } +} + +export class JankTreeNode { + name: string = ''; + pid: number = -1; + frame_type: string = ''; + type: number = 0; + + constructor(name: string, pid: number, frame_type: string) { + this.name = name; + this.pid = pid; + this.frame_type = frame_type; + } + + children: Array = []; +} diff --git a/ide/src/trace/component/trace/sheet/TabPaneFilter.ts b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e01d441f821d31f59c471bac2d124923075b639 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/TabPaneFilter.ts @@ -0,0 +1,863 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import '../../../../base-ui/select/LitSelect.js'; +import '../../../../base-ui/select/LitSelectOption.js'; +import '../../../../base-ui/icon/LitIcon.js'; +import { LitIcon } from '../../../../base-ui/icon/LitIcon.js'; +import '../../../../base-ui/popover/LitPopoverV.js'; +import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox.js'; +import { LitSelect } from '../../../../base-ui/select/LitSelect'; + +export interface FilterData { + inputValue: string; + firstSelect: string | null | undefined; + secondSelect: string | null | undefined; + thirdSelect: string | null | undefined; + mark: boolean | null | undefined; + icon: string | null; + type: string; +} + +export interface MiningData { + type: string; + item: any | null | undefined; + remove?: Array | null | undefined; +} + +@element('tab-pane-filter') +export class TabPaneFilter extends BaseElement { + private filterInputEL: HTMLInputElement | null | undefined; + private firstSelectEL: HTMLSelectElement | null | undefined; + private secondSelectEL: HTMLSelectElement | null | undefined; + private thirdSelectEL: LitSelect | null | undefined; + private markButtonEL: HTMLButtonElement | null | undefined; + private iconEL: LitIcon | null | undefined; + private statisticsName: HTMLDivElement | null | undefined; + private getFilter: ((e: FilterData) => void) | undefined; + private getMining: ((e: MiningData) => void) | undefined; + private getLibrary: ((e: MiningData) => void) | undefined; + private getCallTree: ((e: any) => void) | undefined; + private getCallTreeConstraints: ((e: any) => void) | undefined; + private getStatisticsType: ((e: any) => void) | undefined; + + private cutList: Array | undefined; + private libraryList: Array | undefined; + + filterData(type: string, data: object = {}) { + return { + type: type, + inputValue: this.filterInputEL!.value, + firstSelect: this.firstSelectEL?.value, + secondSelect: this.secondSelectEL?.value, + thirdSelect: this.thirdSelectEL?.value, + mark: false, + icon: this.icon, + ...data, + }; + } + + showThird(b: boolean) { + if (b) { + if (this.thirdSelectEL?.value) { + this.setAttribute('third', ''); + } else { + this.removeAttribute('third'); + } + } else { + this.removeAttribute('third'); + } + } + + initElements(): void { + this.cutList = []; + this.libraryList = []; + this.filterInputEL = this.shadowRoot?.querySelector('#filter-input'); + this.markButtonEL = this.shadowRoot?.querySelector('#mark'); + this.iconEL = this.shadowRoot?.querySelector('#icon'); + this.statisticsName = this.shadowRoot?.querySelector('.statistics-name'); + this.iconEL!.onclick = (e) => { + if (this.iconEL!.name == 'statistics') { + this.iconEL!.name = 'menu'; + this.iconEL!.size = 18; + if (this.getFilter) { + this.getFilter(this.filterData('icon')); + } + } else if (this.iconEL!.name == 'menu') { + this.iconEL!.name = 'statistics'; + this.iconEL!.size = 16; + if (this.getFilter) { + this.getFilter(this.filterData('icon')); + } + } + }; + + this.markButtonEL!.onclick = (e) => { + if (this.getFilter) { + this.getFilter(this.filterData('mark', { mark: true })); + } + }; + + this.filterInputEL?.addEventListener('keyup', (event: any) => { + if (event.keyCode == 13) { + if (this.getFilter) { + this.getFilter( + this.filterData('inputValue', { + inputValue: event.target.value, + }) + ); + } + } + event.stopPropagation(); + }); + + this.filterInputEL?.addEventListener('keypress', (event: any) => { + event.stopPropagation(); + }); + + this.setSelectList(); + + this.initializeCallTree(); + + this.initializeTreeConstraints(); + + this.initializeMining(); + + this.initializeLibrary(); + + this.shadowRoot!.querySelectorAll('.mining-button').forEach((e, idx) => { + e!.onclick = (ev) => { + if (idx == 0) { + const restoreList = this.cutList!.filter((item) => item.highlight === true); + const list = this.cutList!.filter((item) => item.highlight === false); + this.cutList = list; + if (this.getMining) { + this.getMining({ + type: 'button', + item: 'restore', + remove: restoreList, + }); + } + this.initializeMining(); + } + }; + }); + this.shadowRoot!.querySelector('.library-button')!.onclick = (ev) => { + const restoreList = this.libraryList!.filter((item) => item.highlight === true); + const list = this.libraryList!.filter((item) => item.highlight === false); + this.libraryList = list; + if (this.getLibrary) { + this.getLibrary({ + type: 'button', + item: 'restore', + remove: restoreList, + }); + } + this.initializeLibrary(); + }; + + this.shadowRoot!.querySelector('#data-mining')!.onclick = (e) => { + if (this.getMining) { + this.getMining({ type: 'button', item: 'symbol' }); + } + }; + this.shadowRoot!.querySelector('#data-library')!.onclick = (e) => { + if (this.getLibrary) { + this.getLibrary({ type: 'button', item: 'library' }); + } + }; + this.shadowRoot!.querySelector('.sort')!.onclick = (e) => { + let statisticsType = this.statisticsName!.textContent == 'Statistics by Operation'; + this.statisticsName!.textContent = statisticsType ? 'Statistics by Thread' : 'Statistics by Operation'; + if (this.getStatisticsType) { + this.getStatisticsType(statisticsType ? 'thread' : 'operation'); + } + }; + } + + set firstSelect(value: string) { + this.firstSelectEL!.value = value; + } + + get firstSelect() { + return this.firstSelectEL?.value || ''; + } + + set secondSelect(value: string) { + this.secondSelectEL!.value = value; + } + + get secondSelect() { + return this.secondSelectEL?.value || ''; + } + + set filterValue(value: string) { + this.filterInputEL!.value = value; + } + + get filterValue() { + return this.filterInputEL!.value; + } + + set thirdSelect(value: string) { + this.thirdSelectEL!.value = value; + } + + get thirdSelect() { + return this.thirdSelectEL?.value || ''; + } + + get inputPlaceholder() { + return this.getAttribute('inputPlaceholder') || 'Detail Filter'; + } + + get icon() { + if (this.getAttribute('icon') != 'false') { + if (this.iconEL!.name == 'statistics') { + return 'tree'; + } else if (this.iconEL!.name == 'menu') { + return 'block'; + } else { + return ''; + } + } else { + return ''; + } + } + + set icon(value: string) { + if (value == 'block') { + this.iconEL!.name = 'menu'; + this.iconEL!.size = 18; + } else if (value == 'tree') { + this.iconEL!.name = 'statistics'; + this.iconEL!.size = 16; + } + } + + get disabledMining() { + return this.hasAttribute('disabledMining'); + } + + set disabledMining(value: boolean) { + if (value) { + this.setAttribute('disabledMining', ''); + } else { + this.removeAttribute('disabledMining'); + } + } + + setFilterModuleSelect(module: string, styleName: any, value: any) { + this.shadowRoot!.querySelector(module)!.style[styleName] = value; + } + + getCallTreeData(getCallTree: (v: any) => void) { + this.getCallTree = getCallTree; + } + + getCallTreeConstraintsData(getCallTreeConstraints: (v: any) => void) { + this.getCallTreeConstraints = getCallTreeConstraints; + } + + getFilterData(getFilter: (v: FilterData) => void) { + this.getFilter = getFilter; + } + + getStatisticsTypeData(getStatisticsType: (v: any) => void) { + this.getStatisticsType = getStatisticsType; + } + + setSelectList( + firstList: Array | null | undefined = ['All Allocations', 'Created & Existing', 'Created & Destroyed'], + secondList: Array | null | undefined = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'], + firstTitle = 'Allocation Lifespan', + secondTitle = 'Allocation Type', + thirdList: Array | null | undefined = null, + thirdTitle = 'Responsible Library' + ) { + let sLE = this.shadowRoot?.querySelector('#load'); + let html = ``; + if (firstList) { + html += ``; + if (firstTitle != '') { + html += `${firstTitle}`; + } + firstList!.forEach((a, b) => { + html += `${a}`; + }); + html += ``; + } + if (secondList) { + html += ``; + if (secondTitle != '') { + html += `${secondTitle}`; + } + secondList!.forEach((a, b) => { + html += `${a}`; + }); + html += ``; + } + let thtml = ''; + if (thirdList) { + this.setAttribute('third', ''); + } + thtml += ``; + if (thirdList) { + if (thirdTitle != '') { + thtml += `${thirdTitle}`; + } + thirdList!.forEach((a, b) => { + thtml += `${a}`; + }); + } + thtml += ``; + + if (!firstList && !secondList) { + this.thirdSelectEL!.outerHTML = thtml; + this.thirdSelectEL = this.shadowRoot?.querySelector('#third-select'); + this.thirdSelectEL!.onchange = (e) => { + if (this.getFilter) { + this.getFilter(this.filterData('thirdSelect')); + } + }; + return; + } + + if (!firstList) { + this.secondSelectEL!.outerHTML = html; + } else if (!secondList) { + this.firstSelectEL!.outerHTML = html; + } else { + sLE!.innerHTML = html + thtml; + } + this.thirdSelectEL = this.shadowRoot?.querySelector('#third-select'); + this.thirdSelectEL!.outerHTML = thtml; + this.thirdSelectEL = this.shadowRoot?.querySelector('#third-select'); + + this.firstSelectEL = this.shadowRoot?.querySelector('#first-select'); + this.secondSelectEL = this.shadowRoot?.querySelector('#second-select'); + + this.firstSelectEL!.onchange = (e) => { + if (this.getFilter) { + this.getFilter(this.filterData('firstSelect')); + } + }; + this.secondSelectEL!.onchange = (e) => { + if (this.getFilter) { + this.getFilter(this.filterData('secondSelect')); + } + }; + this.thirdSelectEL!.onchange = (e) => { + if (this.getFilter) { + this.getFilter(this.filterData('thirdSelect')); + } + }; + } + + initializeCallTree() { + let row = this.shadowRoot!.querySelectorAll('.tree-check'); + row.forEach((e, idx) => { + let check = e.querySelector('lit-check-box'); + e.querySelector('div')!.onclick = (ev) => { + if (this.getCallTree) { + if (idx == 0) { + this.getCallTree({ + checks: [!check!.checked, row[1].querySelector('lit-check-box')!.checked], + value: idx, + }); + } else { + this.getCallTree({ + checks: [row[0].querySelector('lit-check-box')!.checked, !check!.checked], + value: idx, + }); + } + } + check!.checked = !check!.checked; + }; + check!.onchange = (ev: any) => { + if (this.getCallTree) { + if (idx == 0) { + this.getCallTree({ + checks: [ev.target.checked, row[1].querySelector('lit-check-box')!.checked], + value: idx, + }); + } else { + this.getCallTree({ + checks: [row[0].querySelector('lit-check-box')!.checked, ev.target.checked], + value: idx, + }); + } + } + }; + }); + } + + initializeTreeConstraints() { + let inputs = this.shadowRoot!.querySelectorAll('.constraints-input'); + let check = this.shadowRoot!.querySelector('#constraints-check'); + check!.onchange = (ev: any) => { + inputs.forEach((e: any, idx) => { + if (inputs[idx].value == '') { + inputs[idx].value = idx == 0 ? '0' : '∞'; + } + ev.target.checked ? e.removeAttribute('disabled') : e.setAttribute('disabled', ''); + }); + if (this.getCallTreeConstraints) { + this.getCallTreeConstraints({ + checked: ev.target.checked, + min: inputs[0].value, + max: inputs[1].value, + }); + } + }; + inputs.forEach((e, idx) => { + e.oninput = function () { + // @ts-ignore + this.value = this.value.replace(/\D/g, ''); + }; + e.addEventListener('keyup', (event: any) => { + event.stopPropagation(); + if (event.keyCode == '13') { + if (event?.target.value == '') { + inputs[idx].value = idx == 0 ? '0' : '∞'; + } + if (this.getCallTreeConstraints) { + this.getCallTreeConstraints({ + checked: check!.checked, + min: idx == 0 ? event?.target.value : inputs[0].value, + max: idx == 1 ? event?.target.value : inputs[1].value, + }); + } + } + }); + }); + } + + initializeMining() { + let html = ``; + this.cutList!.forEach((a, b) => { + html += `
+ +
${a.name}
`; + }); + + this.shadowRoot!.querySelector('#mining-row')!.innerHTML = html; + + let row = this.shadowRoot!.querySelector('#mining-row')!.childNodes; + row!.forEach((e: any, idx) => { + e!.querySelector('#title')!.onclick = (ev: any) => { + if (e.getAttribute('highlight') == '') { + e.removeAttribute('highlight'); + this.cutList![idx].highlight = false; + } else { + e.setAttribute('highlight', ''); + this.cutList![idx].highlight = true; + } + }; + // @ts-ignore + e!.querySelector('lit-check-box')!.onchange = (ev) => { + // @ts-ignore + this.cutList[idx].checked = e!.querySelector('lit-check-box')!.checked; + if (this.getMining) { + this.getMining({ type: 'check', item: this.cutList![idx] }); + } + }; + }); + } + + initializeLibrary() { + let html = ``; + this.libraryList!.forEach((a, b) => { + html += `
+ +
${a.name}
`; + }); + + this.shadowRoot!.querySelector('#library-row')!.innerHTML = html; + + let row = this.shadowRoot!.querySelector('#library-row')!.childNodes; + row!.forEach((e: any, idx) => { + e!.querySelector('#title')!.onclick = (ev: any) => { + if (e.getAttribute('highlight') == '') { + e.removeAttribute('highlight'); + this.libraryList![idx].highlight = false; + } else { + e.setAttribute('highlight', ''); + this.libraryList![idx].highlight = true; + } + }; + + // @ts-ignore + e!.querySelector('lit-check-box')!.onchange = (ev) => { + // @ts-ignore + this.libraryList[idx].checked = e!.querySelector('lit-check-box')!.checked; + if (this.getLibrary) { + this.getLibrary({ + type: 'check', + item: this.libraryList![idx], + }); + } + }; + }); + } + + getDataMining(getMining: (v: MiningData) => void) { + this.getMining = getMining; + } + + getDataLibrary(getLibrary: (v: MiningData) => void) { + this.getLibrary = getLibrary; + } + + addDataMining(data: any, type: string) { + let list: Array = (type == 'symbol' ? this.cutList : this.libraryList) || []; + let idx = list!.findIndex((e) => e.name == data.name); + if (idx == -1) { + list!.push({ + type: type, + name: data.name, + checked: true, + select: '1', + data: data, + highlight: false, + }); + } else { + list![idx] = { + type: type, + name: data.name, + checked: true, + select: '1', + data: data, + highlight: false, + }; + } + this.initializeMining(); + this.initializeLibrary(); + return idx; + } + + getFilterTreeData() { + let row = this.shadowRoot!.querySelectorAll('.tree-check lit-check-box'); + let inputs = this.shadowRoot!.querySelectorAll('.constraints-input'); + let check = this.shadowRoot!.querySelector('#constraints-check'); + let data = { + callTree: [row[0]!.checked, row[1]!.checked], + callTreeConstraints: { + checked: check!.checked, + inputs: [inputs[0].value == '' ? '0' : inputs[0].value, inputs[1].value == '' ? '∞' : inputs[1].value], + }, + dataMining: this.cutList, + dataLibrary: this.libraryList, + }; + return data; + } + + initializeFilterTree(callTree: boolean = true, treeConstraints: boolean = true, mining: boolean = true) { + if (callTree) { + let row = this.shadowRoot!.querySelectorAll('.tree-check'); + row.forEach((e, idx) => { + let check = e.querySelector('lit-check-box'); + check!.checked = false; + }); + } + if (treeConstraints) { + let inputs = this.shadowRoot!.querySelectorAll('.constraints-input'); + if (inputs.length > 0) { + inputs[0].value = '0'; + inputs[1].value = '∞'; + } + let check = this.shadowRoot!.querySelector('#constraints-check'); + check!.checked = false; + } + if (mining) { + this.cutList = []; + this.libraryList = []; + this.initializeMining(); + this.initializeLibrary(); + } + } + + initHtml(): string { + return ` + + + Input Filter + + +
+ +
+ +
+
Invert
+
Hide System so
+
+ Options +
+ +
+ + + +
+
Constraints:Only enabled with data and while stopped;
+
filters data to thresholds.
+
+ +
+
+ Sample Count Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Symbol Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Library Filter +
+
+ +
Statistics by Thread
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/TabPaneJsMemoryFilter.ts b/ide/src/trace/component/trace/sheet/TabPaneJsMemoryFilter.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd1951bfec0bc2e22be81fc9b3b63d38d7f7edb3 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/TabPaneJsMemoryFilter.ts @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import '../../../../base-ui/icon/LitIcon.js'; +import { LitIcon } from '../../../../base-ui/icon/LitIcon.js'; +import '../../../../base-ui/popover/LitPopoverV.js'; +import { LitCheckBox } from '../../../../base-ui/checkbox/LitCheckBox.js'; +import { LitSelect } from '../../../../base-ui/select/LitSelect.js'; +import '../../../../base-ui/select/LitSelect.js'; +import { LitSelectOption } from '../../../../base-ui/select/LitSelectOption.js'; + +@element('tab-pane-js-memory-filter') +export class TabPaneJsMemoryFilter extends BaseElement { + initElements(): void {} + + initHtml(): string { + return ` + + Class Filter + +
+ +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/TabProgressBar.ts b/ide/src/trace/component/trace/sheet/TabProgressBar.ts new file mode 100644 index 0000000000000000000000000000000000000000..469e869aa4814cbcddabae95ef0857c156858832 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/TabProgressBar.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; + +@element('tab-progress-bar') +export class TabProgressBar extends BaseElement { + initElements(): void { + let data: Array = this.getAttribute('data')!.split(','); + let first: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#first'); + let second: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#second'); + if (data!.length > 0 && data && data![2] != '0') { + if (parseInt(data[0]) < 0) { + first!.style.width = Number((Math.abs(parseInt(data[0])) / parseInt(data[2])) * 100).toFixed(2) + '%'; + first!.style.background = '#FC74FF'; + } else { + first!.style.width = Number((parseInt(data[0]) / parseInt(data[2])) * 100).toFixed(2) + '%'; + } + if (parseInt(data[1]) < 0) { + second!.style.width = Number((Math.abs(parseInt(data[1])) / parseInt(data[2])) * 100).toFixed(2) + '%'; + first!.style.background = '#CC34CF'; + } else { + second!.style.width = Number((parseInt(data[1]) / parseInt(data[2])) * 100).toFixed(2) + '%'; + } + } + } + + initHtml(): string { + return ` + +
+
+
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/ability/TabPaneCpuAbility.ts b/ide/src/trace/component/trace/sheet/ability/TabPaneCpuAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b84a19a9b7603dcaa0ecc19964fb21a968b90a0 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/ability/TabPaneCpuAbility.ts @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCpuAbilityData } from '../../../../database/SqlLite.js'; +import { SystemCpuSummary } from '../../../../bean/AbilityMonitor.js'; +import { Utils } from '../../base/Utils.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; +import '../../../SpFilter.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-cpu-ability') +export class TabPaneCpuAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = []; + private float: HTMLDivElement | null | undefined; + private search: HTMLInputElement | undefined | null; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cpu-ability'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toCpuAbilityArray(item); + let isInclude = array.filter((value) => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0; + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + } + } + + toCpuAbilityArray(systemCpuSummary: SystemCpuSummary): any[] { + let array: Array = []; + array.push(systemCpuSummary.startTimeStr); + array.push(systemCpuSummary.durationStr); + array.push(systemCpuSummary.totalLoadStr); + array.push(systemCpuSummary.userLoadStr); + array.push(systemCpuSummary.systemLoadStr); + array.push(systemCpuSummary.threadsStr); + return array; + } + + queryDataByDB(val: SelectionParam | any) { + getTabCpuAbilityData(val.leftNs, val.rightNs).then((result) => { + log('getTabCpuAbilityData size :' + result.length); + if (result.length != null && result.length > 0) { + for (const systemCpuSummary of result) { + if (systemCpuSummary.startTime == 0) { + systemCpuSummary.startTimeStr = '0:000.000.000'; + } else { + systemCpuSummary.startTimeStr = Utils.getTimeStampHMS(systemCpuSummary.startTime); + } + systemCpuSummary.durationStr = Utils.getDurString(systemCpuSummary.duration); + systemCpuSummary.totalLoadStr = systemCpuSummary.totalLoad.toFixed(2) + '%'; + systemCpuSummary.userLoadStr = systemCpuSummary.userLoad.toFixed(2) + '%'; + systemCpuSummary.systemLoadStr = systemCpuSummary.systemLoad.toFixed(2) + '%'; + systemCpuSummary.threadsStr = ColorUtils.formatNumberComma(systemCpuSummary.threads); + } + this.source = result; + this.queryResult = result; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.queryResult = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemCpuSummary, b: SystemCpuSummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'durationStr') { + return sort === 2 ? b.duration - a.duration : a.duration - b.duration; + } else if (type === 'totalLoadStr') { + return sort === 2 ? b.totalLoad - a.totalLoad : a.totalLoad - b.totalLoad; + } else if (type === 'userLoadStr') { + return sort === 2 ? b.userLoad - a.userLoad : a.userLoad - b.userLoad; + } else if (type === 'systemLoadStr') { + return sort === 2 ? b.systemLoad - a.systemLoad : a.systemLoad - b.systemLoad; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else if (detail.key === 'durationStr') { + this.source.sort(compare(detail.key, detail.sort, 'durationStr')); + } else if (detail.key === 'totalLoadStr') { + this.source.sort(compare(detail.key, detail.sort, 'totalLoadStr')); + } else if (detail.key === 'userLoadStr') { + this.source.sort(compare(detail.key, detail.sort, 'userLoadStr')); + } else if (detail.key === 'systemLoadStr') { + this.source.sort(compare(detail.key, detail.sort, 'systemLoadStr')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/ability/TabPaneDiskAbility.ts b/ide/src/trace/component/trace/sheet/ability/TabPaneDiskAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..a88f19acd39ec407c5a0e649807236a049a89f9c --- /dev/null +++ b/ide/src/trace/component/trace/sheet/ability/TabPaneDiskAbility.ts @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabDiskAbilityData } from '../../../../database/SqlLite.js'; +import { SystemDiskIOSummary } from '../../../../bean/AbilityMonitor.js'; +import { Utils } from '../../base/Utils.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; +import '../../../SpFilter.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-disk-ability') +export class TabPaneDiskAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = []; + private search: HTMLInputElement | undefined | null; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-disk-ability'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toDiskAbilityArray(item); + let isInclude = array.filter((value) => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0; + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + } + } + + toDiskAbilityArray(systemDiskIOSummary: SystemDiskIOSummary): any[] { + let array: Array = []; + array.push(systemDiskIOSummary.startTimeStr); + array.push(systemDiskIOSummary.durationStr); + array.push(systemDiskIOSummary.dataReadStr); + array.push(systemDiskIOSummary.dataReadSecStr); + array.push(systemDiskIOSummary.dataWriteStr); + array.push(systemDiskIOSummary.readsInStr); + array.push(systemDiskIOSummary.readsInSecStr); + array.push(systemDiskIOSummary.writeOutStr); + array.push(systemDiskIOSummary.writeOutSecStr); + return array; + } + + queryDataByDB(val: SelectionParam | any) { + getTabDiskAbilityData(val.leftNs, val.rightNs).then((result) => { + log('getTabDiskAbilityData result size : ' + result.length); + if (result.length != null && result.length > 0) { + for (const systemDiskIOSummary of result) { + if (systemDiskIOSummary.startTime <= 0) { + systemDiskIOSummary.startTimeStr = '0:000.000.000'; + } else { + systemDiskIOSummary.startTimeStr = Utils.getTimeStampHMS(systemDiskIOSummary.startTime); + } + systemDiskIOSummary.durationStr = Utils.getDurString(systemDiskIOSummary.duration); + systemDiskIOSummary.dataReadStr = systemDiskIOSummary.dataRead + 'KB'; + systemDiskIOSummary.dataReadSecStr = systemDiskIOSummary.dataReadSec + 'KB/S'; + systemDiskIOSummary.dataWriteStr = systemDiskIOSummary.dataWrite + 'KB'; + systemDiskIOSummary.dataWriteSecStr = systemDiskIOSummary.dataWriteSec + 'KB/S'; + systemDiskIOSummary.readsInStr = ColorUtils.formatNumberComma(systemDiskIOSummary.readsIn); + systemDiskIOSummary.readsInSecStr = systemDiskIOSummary.readsInSec.toString(); + systemDiskIOSummary.writeOutStr = ColorUtils.formatNumberComma(systemDiskIOSummary.writeOut); + systemDiskIOSummary.writeOutSecStr = systemDiskIOSummary.writeOutSec.toString(); + } + this.source = result; + this.queryResult = result; + this.tbl!.recycleDataSource = result; + } else { + this.source = []; + this.queryResult = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemDiskIOSummary, b: SystemDiskIOSummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'durationStr') { + return sort === 2 ? b.duration - a.duration : a.duration - b.duration; + } else if (type === 'dataReadStr') { + return sort === 2 ? b.dataRead - a.dataRead : a.dataRead - b.dataRead; + } else if (type === 'dataReadSecStr') { + return sort === 2 ? b.dataReadSec - a.dataReadSec : a.dataReadSec - b.dataReadSec; + } else if (type === 'dataWriteStr') { + return sort === 2 ? b.dataWrite - a.dataWrite : a.dataWrite - b.dataWrite; + } else if (type === 'dataWriteSecStr') { + return sort === 2 ? b.dataWriteSec - a.dataWriteSec : a.dataWriteSec - b.dataWriteSec; + } else if (type === 'readsInStr') { + return sort === 2 ? b.readsIn - a.readsIn : a.readsIn - b.readsIn; + } else if (type === 'readsInSecStr') { + return sort === 2 ? b.readsInSec - a.readsInSec : a.readsInSec - b.readsInSec; + } else if (type === 'writeOutStr') { + return sort === 2 ? b.writeOut - a.writeOut : a.writeOut - b.writeOut; + } else if (type === 'writeOutSecStr') { + return sort === 2 ? b.writeOutSec - a.writeOutSec : a.writeOutSec - b.writeOutSec; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else if (detail.key === 'durationStr') { + this.source.sort(compare(detail.key, detail.sort, 'durationStr')); + } else if (detail.key === 'dataReadStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataReadStr')); + } else if (detail.key === 'dataReadSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataReadSecStr')); + } else if (detail.key === 'dataWriteStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataWriteStr')); + } else if (detail.key === 'dataWriteSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataWriteSecStr')); + } else if (detail.key === 'readsInStr') { + this.source.sort(compare(detail.key, detail.sort, 'readsInStr')); + } else if (detail.key === 'readsInSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'readsInSecStr')); + } else if (detail.key === 'writeOutStr') { + this.source.sort(compare(detail.key, detail.sort, 'writeOutStr')); + } else if (detail.key === 'writeOutSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'writeOutSecStr')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.ts b/ide/src/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.ts new file mode 100644 index 0000000000000000000000000000000000000000..33962db5a18ea1e1f3145dbbfabb386c30a982cd --- /dev/null +++ b/ide/src/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.ts @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabProcessHistoryData } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { ProcessHistory } from '../../../../bean/AbilityMonitor.js'; +import '../../../SpFilter.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-history-processes') +export class TabPaneHistoryProcesses extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = []; + private float: HTMLDivElement | null | undefined; + private search: HTMLInputElement | undefined | null; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-history-processes'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toProcessHistoryArray(item); + let isInclude = array.filter((value) => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0; + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + } + } + + toProcessHistoryArray(process: ProcessHistory): any[] { + let array: Array = []; + array.push(process.processId.toString()); + array.push(process.processName); + array.push(process.alive); + array.push(process.firstSeen); + array.push(process.lastSeen); + array.push(process.responsibleProcess); + array.push(process.userName); + array.push(process.cpuTime); + return array; + } + + queryDataByDB(val: SelectionParam | any) { + getTabProcessHistoryData(val.leftNs, val.rightNs, val.processId, val.threadId).then((item) => { + if (item.length != null && item.length > 0) { + log('getTabProcessHistoryData result size : ' + item.length); + for (const processHistory of item) { + processHistory.alive = processHistory.alive == '0' ? 'No' : 'Yes'; + if (Number(processHistory.firstSeen) <= 0) { + processHistory.firstSeen = '0:000.000.000'; + processHistory.firstSeenNumber = 0; + } else { + processHistory.firstSeenNumber = Number(processHistory.firstSeen); + processHistory.firstSeen = Utils.getTimeStampHMS(processHistory.firstSeenNumber); + } + processHistory.lastSeenNumber = Number(processHistory.lastSeen); + processHistory.lastSeen = Utils.getTimeStampHMS(Number(processHistory.lastSeenNumber)); + processHistory.processName = processHistory.processName + '(' + processHistory.processId + ')'; + processHistory.cpuTimeNumber = Number(processHistory.cpuTime); + processHistory.cpuTime = this.timeFormat(processHistory.cpuTimeNumber); + } + this.source = item; + this.queryResult = item; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.queryResult = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + timeFormat(ms: number): string { + let currentMs = ms; + let hours = 3600000; + let minute1 = 60000; + let second1 = 1000; + let res = ''; + if (currentMs >= hours) { + res += Math.floor(currentMs / hours) + ' h '; + currentMs = currentMs - Math.floor(currentMs / hours) * hours; + } + if (currentMs >= minute1) { + res += Math.floor(currentMs / minute1) + ' min '; + currentMs = currentMs - Math.floor(currentMs / minute1) * minute1; + } + if (currentMs >= second1) { + res += Math.floor(currentMs / second1) + ' s '; + currentMs = currentMs - Math.floor(currentMs / second1) * second1; + } + if (currentMs > 0) { + res += currentMs + ' ms '; + } else { + res += '0 ms '; + } + return res; + } + + initHtml(): string { + return ` + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: ProcessHistory, b: ProcessHistory) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'cpuTime') { + return sort === 2 ? b.cpuTimeNumber - a.cpuTimeNumber : a.cpuTimeNumber - b.cpuTimeNumber; + } else if (type === 'lastSeen') { + return sort === 2 ? b.lastSeenNumber - a.lastSeenNumber : a.lastSeenNumber - b.lastSeenNumber; + } else if (type === 'firstSeen') { + return sort === 2 ? b.firstSeenNumber - a.firstSeenNumber : a.firstSeenNumber - b.firstSeenNumber; + } else if (type === 'alive') { + let aaaa = 0; + let bbbb = 0; + // @ts-ignore + if (b[property] == 'Yes') { + bbbb = 1; + } + // @ts-ignore + if (a[property] == 'Yes') { + aaaa = 1; + } + if (aaaa - bbbb == 0) { + return 0; + } + return aaaa - bbbb ? -1 : 1; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'startTime' || detail.key === 'processName') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else if (detail.key == 'cpuTime') { + this.source.sort(compare(detail.key, detail.sort, 'cpuTime')); + } else if (detail.key === 'alive') { + this.source.sort(compare(detail.key, detail.sort, 'alive')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/ability/TabPaneLiveProcesses.ts b/ide/src/trace/component/trace/sheet/ability/TabPaneLiveProcesses.ts new file mode 100644 index 0000000000000000000000000000000000000000..870035d46794160de6ddf7a5060a173cd1a1c302 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/ability/TabPaneLiveProcesses.ts @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabLiveProcessData } from '../../../../database/SqlLite.js'; +import { LiveProcess } from '../../../../bean/AbilityMonitor.js'; +import '../../../SpFilter.js'; +import { Utils } from '../../base/Utils.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-live-processes') +export class TabPaneLiveProcesses extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = []; + private float: HTMLDivElement | null | undefined; + private search: HTMLInputElement | undefined | null; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-live-processes'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toLiveProcessArray(item); + let isInclude = array.filter((value) => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0; + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + } + } + + toLiveProcessArray(liveProcess: LiveProcess): any[] { + let array: Array = []; + array.push(liveProcess.processId.toString()); + array.push(liveProcess.processName); + array.push(liveProcess.responsibleProcess); + array.push(liveProcess.userName); + array.push(liveProcess.threads.toString()); + array.push(liveProcess.cpu); + array.push(liveProcess.memory); + array.push(liveProcess.diskReads.toString()); + array.push(liveProcess.diskWrite.toString()); + return array; + } + + queryDataByDB(val: SelectionParam | any) { + getTabLiveProcessData(val.leftNs, val.rightNs).then((item) => { + if (item.length != null && item.length > 0) { + log('getTabLiveProcessData result size : ' + item.length); + for (const liveProcess of item) { + liveProcess.processName = liveProcess.processName + '(' + liveProcess.processId + ')'; + liveProcess.memoryNumber = Number(liveProcess.memory); + liveProcess.memory = Utils.getBinaryByteWithUnit(liveProcess.memoryNumber); + if (Number(liveProcess.cpu) > 0) { + liveProcess.cpu = Number(Number(liveProcess.cpu).toFixed(3)) + '%'; + } else { + liveProcess.cpu = '0%'; + } + liveProcess.cpuTimeNumber = Number(liveProcess.cpuTime); + liveProcess.cpuTime = this.timeFormat(Number(liveProcess.cpuTime)); + } + this.source = item; + this.queryResult = item; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.queryResult = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + timeFormat(ms: number): string { + let currentMs = ms; + let hours = 3600000; + let minute1 = 60000; + let second1 = 1000; + let res = ''; + if (currentMs >= hours) { + res += Math.floor(currentMs / hours) + ' h '; + currentMs = currentMs - Math.floor(currentMs / hours) * hours; + } + if (currentMs >= minute1) { + res += Math.floor(currentMs / minute1) + ' min '; + currentMs = currentMs - Math.floor(currentMs / minute1) * minute1; + } + if (currentMs >= second1) { + res += Math.floor(currentMs / second1) + ' s '; + currentMs = currentMs - Math.floor(currentMs / second1) * second1; + } + if (currentMs > 0) { + res += currentMs + ' ms '; + } else { + res += '0 ms '; + } + return res; + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: LiveProcess, b: LiveProcess) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'cpuTime') { + return sort === 2 ? b.cpuTimeNumber - a.cpuTimeNumber : a.cpuTimeNumber - b.cpuTimeNumber; + } else if (type === 'memory') { + return sort === 2 ? b.memoryNumber - a.memoryNumber : a.memoryNumber - b.memoryNumber; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key == 'startTime' || detail.key == 'processName') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else if (detail.key == 'cpuTime') { + this.source.sort(compare(detail.key, detail.sort, 'cpuTime')); + } else if (detail.key == 'memory') { + this.source.sort(compare(detail.key, detail.sort, 'memory')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/ability/TabPaneMemoryAbility.ts b/ide/src/trace/component/trace/sheet/ability/TabPaneMemoryAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..9a7708b9f67b9cd20d7603f55bceca3026fbf6b7 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/ability/TabPaneMemoryAbility.ts @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabMemoryAbilityData, queryStartTime } from '../../../../database/SqlLite.js'; +import { SystemMemorySummary } from '../../../../bean/AbilityMonitor.js'; +import { Utils } from '../../base/Utils.js'; +import '../../../SpFilter.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-memory-ability') +export class TabPaneMemoryAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private float: HTMLDivElement | null | undefined; + private queryResult: Array = []; + private search: HTMLInputElement | undefined | null; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-memory-ability'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toMemoryAbilityArray(item); + let isInclude = array.filter((value) => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0; + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + } + } + + toMemoryAbilityArray(systemMemorySummary: SystemMemorySummary): any[] { + let array: Array = []; + array.push(systemMemorySummary.startTimeStr); + array.push(systemMemorySummary.durationStr); + array.push(systemMemorySummary.memoryTotal); + array.push(systemMemorySummary.cached); + array.push(systemMemorySummary.swapTotal); + return array; + } + + queryDataByDB(val: SelectionParam | any) { + queryStartTime().then((res) => { + let startTime = res[0].start_ts; + getTabMemoryAbilityData(val.leftNs + startTime, val.rightNs + startTime).then((items) => { + log('getTabMemoryAbilityData result size : ' + items.length); + this.source = []; + this.queryResult = []; + if (items.length != null && items.length > 0) { + let lastTime = 0; + for (const item of items) { + let systemMemorySummary = new SystemMemorySummary(); + if (item.startTime - startTime <= 0) { + systemMemorySummary.startTimeStr = '0:000.000.000'; + } else { + systemMemorySummary.startTimeStr = Utils.getTimeStampHMS(item.startTime - startTime); + } + if (lastTime !== 0) { + systemMemorySummary.durationNumber = item.startTime - lastTime; + systemMemorySummary.durationStr = Utils.getDurString(systemMemorySummary.durationNumber); + } else { + systemMemorySummary.durationNumber = 0; + systemMemorySummary.durationStr = '-'; + } + lastTime = item.startTime; + let memorys = item.value.split(','); + let names = item.name.split(','); + if (memorys.length != names.length) { + continue; + } + for (let i = 0; i < names.length; i++) { + switch (names[i]) { + case 'sys.mem.total': + systemMemorySummary.memoryTotal = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.free': + systemMemorySummary.memFree = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.buffers': + systemMemorySummary.buffers = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.cached': + systemMemorySummary.cached = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.shmem': + systemMemorySummary.shmem = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.slab': + systemMemorySummary.slab = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.swap.total': + systemMemorySummary.swapTotal = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.swap.free': + systemMemorySummary.swapFree = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.mapped': + systemMemorySummary.mapped = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.vmalloc.used': + systemMemorySummary.vmallocUsed = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.page.tables': + systemMemorySummary.pageTables = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.kernel.stack': + systemMemorySummary.kernelStack = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.active': + systemMemorySummary.active = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.inactive': + systemMemorySummary.inactive = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.unevictable': + systemMemorySummary.unevictable = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.vmalloc.total': + systemMemorySummary.vmallocTotal = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.slab.unreclaimable': + systemMemorySummary.sUnreclaim = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.cma.total': + systemMemorySummary.cmaTotal = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.cma.free': + systemMemorySummary.cmaFree = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.kernel.reclaimable': + systemMemorySummary.kReclaimable = Utils.getBinaryKBWithUnit(Number(memorys[i])); + break; + case 'sys.mem.zram': + systemMemorySummary.zram = Utils.getBinaryKBWithUnit(Number(memorys[i]) * 1000); + break; + } + } + this.source.push(systemMemorySummary); + } + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + }); + }); + if (this.tbl) { + let th = this.tbl.shadowRoot?.querySelector('.th'); + if (th) { + th.style.gridColumnGap = '5px'; + } + } + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemMemorySummary, b: SystemMemorySummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'durationStr') { + return sort === 2 ? b.durationNumber - a.durationNumber : a.durationNumber - b.durationNumber; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else if (detail.key === 'durationStr') { + this.source.sort(compare(detail.key, detail.sort, 'durationStr')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/ability/TabPaneNetworkAbility.ts b/ide/src/trace/component/trace/sheet/ability/TabPaneNetworkAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..49382b4c6699988fe94ae1dd87e163cc679c5227 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/ability/TabPaneNetworkAbility.ts @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabNetworkAbilityData } from '../../../../database/SqlLite.js'; +import { SystemNetworkSummary } from '../../../../bean/AbilityMonitor.js'; +import { Utils } from '../../base/Utils.js'; +import '../../../SpFilter.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-network-ability') +export class TabPaneNetworkAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private float: HTMLDivElement | null | undefined; + private queryResult: Array = []; + private search: HTMLInputElement | undefined | null; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-network-ability'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toNetWorkAbilityArray(item); + let isInclude = array.filter((value) => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0; + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + } + } + + toNetWorkAbilityArray(systemNetworkSummary: SystemNetworkSummary): any[] { + let array: Array = []; + array.push(systemNetworkSummary.startTimeStr); + array.push(systemNetworkSummary.durationStr); + array.push(systemNetworkSummary.dataReceivedStr); + array.push(systemNetworkSummary.dataReceivedSecStr); + array.push(systemNetworkSummary.dataSendSecStr); + array.push(systemNetworkSummary.dataSendStr); + array.push(systemNetworkSummary.packetsIn.toString()); + array.push(systemNetworkSummary.packetsOut.toString()); + array.push(systemNetworkSummary.packetsOutSec.toString()); + return array; + } + + queryDataByDB(val: SelectionParam | any) { + getTabNetworkAbilityData(val.leftNs, val.rightNs).then((item) => { + log('getTabNetworkAbilityData result size : ' + item.length); + if (item.length != null && item.length > 0) { + for (const systemNetworkSummary of item) { + if (systemNetworkSummary.startTime == 0) { + systemNetworkSummary.startTimeStr = '0:000.000.000'; + } else { + systemNetworkSummary.startTimeStr = Utils.getTimeStampHMS(systemNetworkSummary.startTime); + } + systemNetworkSummary.durationStr = Utils.getDurString(systemNetworkSummary.duration); + systemNetworkSummary.dataReceivedStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataReceived); + systemNetworkSummary.dataReceivedSecStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataReceivedSec); + systemNetworkSummary.dataSendStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataSend); + systemNetworkSummary.dataSendSecStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataSendSec); + systemNetworkSummary.packetsInStr = ColorUtils.formatNumberComma(systemNetworkSummary.packetsIn); + systemNetworkSummary.packetsInSecStr = systemNetworkSummary.packetsInSec.toFixed(2); + systemNetworkSummary.packetsOutStr = ColorUtils.formatNumberComma(systemNetworkSummary.packetsOut); + systemNetworkSummary.packetsOutSecStr = systemNetworkSummary.packetsOutSec.toFixed(2); + } + this.source = item; + this.queryResult = item; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.queryResult = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemNetworkSummary, b: SystemNetworkSummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'durationStr') { + return sort === 2 ? b.duration - a.duration : a.duration - b.duration; + } else if (type === 'dataReceivedStr') { + return sort === 2 ? b.dataReceived - a.dataReceived : a.dataReceived - b.dataReceived; + } else if (type === 'dataReceivedSecStr') { + return sort === 2 ? b.dataReceivedSec - a.dataReceivedSec : a.dataReceivedSec - b.dataReceivedSec; + } else if (type === 'dataSendStr') { + return sort === 2 ? b.dataSend - a.dataSend : a.dataSend - b.dataSend; + } else if (type === 'dataSendSecStr') { + return sort === 2 ? b.dataSendSec - a.dataSendSec : a.dataSendSec - b.dataSendSec; + } else if (type === 'packetsInStr') { + return sort === 2 ? b.packetsIn - a.packetsIn : a.packetsIn - b.packetsIn; + } else if (type === 'packetsInSecStr') { + return sort === 2 ? b.packetsInSec - a.packetsInSec : a.packetsInSec - b.packetsInSec; + } else if (type === 'packetsOutStr') { + return sort === 2 ? b.packetsOut - a.packetsOut : a.packetsOut - b.packetsOut; + } else if (type === 'packetsOutSecStr') { + return sort === 2 ? b.packetsOutSec - a.packetsOutSec : a.packetsOutSec - b.packetsOutSec; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else if (detail.key === 'durationStr') { + this.source.sort(compare(detail.key, detail.sort, 'durationStr')); + } else if (detail.key === 'dataReceivedStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataReceivedStr')); + } else if (detail.key === 'dataReceivedSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataReceivedSecStr')); + } else if (detail.key === 'dataSendStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataSendStr')); + } else if (detail.key === 'dataSendSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'dataSendSecStr')); + } else if (detail.key === 'packetsInStr') { + this.source.sort(compare(detail.key, detail.sort, 'packetsInStr')); + } else if (detail.key === 'packetsInSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'packetsInSecStr')); + } else if (detail.key === 'packetsOutStr') { + this.source.sort(compare(detail.key, detail.sort, 'packetsOutStr')); + } else if (detail.key === 'packetsOutSecStr') { + this.source.sort(compare(detail.key, detail.sort, 'packetsOutSecStr')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/clock/TabPaneClockCounter.ts b/ide/src/trace/component/trace/sheet/clock/TabPaneClockCounter.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f2d8696092c36b78f21740a1f9514b428a1d1b9 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/clock/TabPaneClockCounter.ts @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { Counter, SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCounters, getTabVirtualCounters } from '../../../../database/SqlLite.js'; + +@element('tabpane-clock-counter') +export class TabPaneClockCounter extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + + set data(val: SelectionParam | any) { + //@ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + let dataSource: Array = []; + let collect = val.clockMapData; + let sumCount = 0; + for (let key of collect.keys()) { + let counters = collect.get(key); + let sd = this.createSelectCounterData(key, counters, val.leftNs, val.rightNs); + sumCount += Number.parseInt(sd.count || '0'); + dataSource.push(sd); + } + let sumData = new SelectionData(); + sumData.count = sumCount.toString(); + sumData.process = ' '; + dataSource.splice(0, 0, sumData); + this.source = dataSource; + this.tbl!.recycleDataSource = dataSource; + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-counter'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + `; + } + + createSelectCounterData(name: string, list: Array, leftNs: number, rightNs: number): SelectionData { + let selectData = new SelectionData(); + if (list.length > 0) { + let range = rightNs - leftNs; + let first = list[0]; + selectData.trackId = first.filterId; + selectData.name = name; + selectData.first = first.value + ''; + selectData.count = list.length + ''; + selectData.last = list[list.length - 1].value + ''; + selectData.delta = parseInt(selectData.last) - parseInt(selectData.first) + ''; + selectData.rate = (parseInt(selectData.delta) / ((range * 1.0) / 1000000000)).toFixed(4); + selectData.min = first.value + ''; + selectData.max = '0'; + let weightAvg = 0.0; + for (let i = 0; i < list.length; i++) { + let counter = list[i]; + if (counter.value < parseInt(selectData.min)) { + selectData.min = counter.value.toString(); + } + if (counter.value > parseInt(selectData.max)) { + selectData.max = counter.value.toString(); + } + let start = i == 0 ? leftNs : counter.startNS; + let end = i == list.length - 1 ? rightNs : list[i + 1].startNS; + weightAvg += counter.value * (((end - start) * 1.0) / range); + } + selectData.avgWeight = weightAvg.toFixed(2); + } + return selectData; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'name') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts new file mode 100644 index 0000000000000000000000000000000000000000..f38ae77dcb8e79107cc2e45d0673362ff29f788e --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneBoxChild.ts @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { BoxJumpParam, SelectionData } from '../../../../bean/BoxSelection.js'; +import { getTabBoxChildData } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; +import { SPTChild } from '../../../../bean/StateProcessThread.js'; +import { TraceRow } from '../../base/TraceRow.js'; + +@element('tabpane-box-child') +export class TabPaneBoxChild extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + private loadDataInCache: boolean = false; + + set data(val: BoxJumpParam) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + if (val.state != null && val.state != undefined && val.processId && val.threadId) { + this.tbl!.recycleDataSource = []; + if (this.loadDataInCache) { + this.getDataByCache(val).then((arr) => { + this.source = arr; + // @ts-ignore + this.tbl?.recycleDataSource = arr; + }); + } else { + this.getDataByDB(val); + } + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cpu-thread'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + getDataByDB(val: BoxJumpParam) { + getTabBoxChildData(val.leftNs, val.rightNs, val.state, val.processId, val.threadId).then((result) => { + if (result.length != null && result.length > 0) { + result.map((e) => { + e.startTime = Utils.getTimeString(e.startNs); + e.absoluteTime = ((window as any).recordStartNS + e.startNs) / 1000000000; + e.state = Utils.getEndState(e.state)!; + e.prior = e.priority == undefined || e.priority == null ? '-' : e.priority + ''; + e.core = e.cpu == undefined || e.cpu == null ? '-' : 'CPU' + e.cpu; + e.processName = + (e.process == undefined || e.process == null ? 'process' : e.process) + '(' + e.processId + ')'; + e.threadName = (e.thread == undefined || e.thread == null ? 'thread' : e.thread) + '(' + e.threadId + ')'; + e.note = '-'; + }); + this.source = result; + // @ts-ignore + this.tbl?.recycleDataSource = result; + } else { + this.source = []; + // @ts-ignore + this.tbl?.recycleDataSource = []; + } + }); + } + + getDataByCache(val: BoxJumpParam): Promise> { + return new Promise>((resolve, reject) => { + let arr: Array = []; + SpSystemTrace.SPT_DATA.map((spt) => { + let b1 = val.state != undefined && val.state != '' ? spt.state == val.state : true; + let b2 = val.processId != undefined && val.processId != -1 ? spt.processId == val.processId : true; + let b3 = val.threadId != undefined && val.threadId != -1 ? spt.threadId == val.threadId : true; + if (!(spt.end_ts < val.leftNs || spt.start_ts > val.rightNs) && b1 && b2 && b3) { + let sptChild = new SPTChild(); + sptChild.startTime = Utils.getTimeString(spt.start_ts); + sptChild.absoluteTime = ((window as any).recordStartNS + spt.start_ts) / 1000000000; + sptChild.startNs = spt.start_ts; + sptChild.state = Utils.getEndState(spt.state)!; + sptChild.prior = spt.priority == undefined || spt.priority == null ? '-' : spt.priority + ''; + sptChild.core = spt.cpu == undefined || spt.cpu == null ? '-' : 'CPU' + spt.cpu; + sptChild.processName = + (spt.process == undefined || spt.process == null || spt.process == '' ? 'process' : spt.process) + + '(' + + spt.processId + + ')'; + sptChild.threadName = + (spt.thread == undefined || spt.thread == null || spt.thread == '' ? 'thread' : spt.thread) + + '(' + + spt.threadId + + ')'; + arr.push(sptChild); + } + }); + resolve(arr); + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + // @ts-ignore + this.source.sort(compare(detail.key, detail.sort, 'string')); + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneContextSwitch.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneContextSwitch.ts new file mode 100644 index 0000000000000000000000000000000000000000..ade1a6e56c4f4e99e0dc8001729ebcb65dc901d6 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneContextSwitch.ts @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getStatesProcessThreadDataByRange } from '../../../../database/SqlLite.js'; +import { SPT, StateProcessThread } from '../../../../bean/StateProcessThread.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-context-switch') +export class TabPaneContextSwitch extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.selectionParam = val; + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + if (this.loadDataInCache) { + this.getDataBySPT(val.leftNs, val.rightNs, SpSystemTrace.SPT_DATA); + } else { + this.queryDataByDB(val); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cs'); + this.range = this.shadowRoot?.querySelector('#time-range'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + getDataBySPT(leftNs: number, rightNs: number, source: Array) { + let pMap: Map = new Map(); + let ptMap: Map = new Map(); + let ptsMap: Map = new Map(); + source.map((d) => { + if (!(d.end_ts < leftNs || d.start_ts > rightNs)) { + if (pMap.has(d.processId + '')) { + let obj1 = pMap.get(d.processId + ''); + obj1!.count++; + obj1!.wallDuration += d.dur; + obj1!.avgDuration = (obj1!.wallDuration / obj1!.count).toFixed(2); + if (d.dur > obj1!.maxDuration) { + obj1!.maxDuration = d.dur; + } + if (d.dur < obj1!.minDuration) { + obj1!.minDuration = d.dur; + } + } else { + let obj1 = new StateProcessThread(); + obj1.id = 'p' + d.processId; + obj1.title = (d.process == null || d.process == '' ? 'Process' : d.process) + '(' + d.processId + ')'; + obj1.process = d.process; + obj1.processId = d.processId; + obj1.minDuration = d.dur; + obj1.maxDuration = d.dur; + obj1.count = 1; + obj1.avgDuration = d.dur + ''; + obj1.wallDuration = d.dur; + pMap.set(d.processId + '', obj1); + } + if (ptMap.has(d.processId + '_' + d.threadId)) { + let obj2 = ptMap.get(d.processId + '_' + d.threadId); + obj2!.count++; + obj2!.wallDuration += d.dur; + obj2!.avgDuration = (obj2!.wallDuration / obj2!.count).toFixed(2); + if (d.dur > obj2!.maxDuration) { + obj2!.maxDuration = d.dur; + } + if (d.dur < obj2!.minDuration) { + obj2!.minDuration = d.dur; + } + } else { + let obj2 = new StateProcessThread(); + obj2.id = 'p' + d.processId + '_' + 't' + d.threadId; + obj2.pid = 'p' + d.processId; + obj2.title = (d.thread == null || d.thread == '' ? 'Thread' : d.thread) + '(' + d.threadId + ')'; + obj2.processId = d.processId; + obj2.process = d.process; + obj2.thread = d.thread; + obj2.threadId = d.threadId; + obj2.minDuration = d.dur; + obj2.maxDuration = d.dur; + obj2.count = 1; + obj2.avgDuration = d.dur + ''; + obj2.wallDuration = d.dur; + ptMap.set(d.processId + '_' + d.threadId, obj2); + } + if (ptsMap.has(d.processId + '_' + d.threadId + '_' + d.state)) { + let obj3 = ptsMap.get(d.processId + '_' + d.threadId + '_' + d.state); + obj3!.count++; + obj3!.wallDuration += d.dur; + obj3!.avgDuration = (obj3!.wallDuration / obj3!.count).toFixed(2); + if (d.dur > obj3!.maxDuration) { + obj3!.maxDuration = d.dur; + } + if (d.dur < obj3!.minDuration) { + obj3!.minDuration = d.dur; + } + } else { + let obj3 = new StateProcessThread(); + obj3.id = 'p' + d.processId + '_' + 't' + d.threadId + '_' + (d.state == 'R+' ? 'RP' : d.state); + obj3.pid = 'p' + d.processId + '_' + 't' + d.threadId; + obj3.title = Utils.getEndState(d.state); + obj3.processId = d.processId; + obj3.process = d.process; + obj3.thread = d.thread; + obj3.threadId = d.threadId; + obj3.state = d.state; + obj3.minDuration = d.dur; + obj3.maxDuration = d.dur; + obj3.count = 1; + obj3.avgDuration = d.dur + ''; + obj3.wallDuration = d.dur; + ptsMap.set(d.processId + '_' + d.threadId + '_' + d.state, obj3); + } + } + }); + let arr: Array = []; + for (let key of pMap.keys()) { + let s = pMap.get(key); + s!.children = []; + for (let ks of ptMap.keys()) { + if (ks.startsWith(key + '_')) { + let sp = ptMap.get(ks); + sp!.children = []; + for (let kst of ptsMap.keys()) { + if (kst.startsWith(ks + '_')) { + let spt = ptsMap.get(kst); + sp!.children.push(spt!); + } + } + s!.children.push(sp!); + } + } + arr.push(s!); + } + this.tbl!.recycleDataSource = arr; + } + + queryDataByDB(val: SelectionParam | any) { + getStatesProcessThreadDataByRange(val.leftNs, val.rightNs).then((result) => { + this.getDataBySPT(val.leftNs, val.rightNs, result); + }); + } + + initHtml(): string { + return ` + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneCounterSample.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneCounterSample.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b4c592c7cfe4dbb2c1c277b419e10df2666947b --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneCounterSample.ts @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPaneCounterSampleData } from '../../../../database/SqlLite.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-counter-sample') +export class TabPaneCounterSample extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingPage: any; + private loadingList: number[] = []; + private source: any[] = []; + private sortKey: string = 'counter'; + private sortType: number = 0; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.selectionParam = val; + // @ts-ignore + this.tbl!.shadowRoot?.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.progressEL = this.shadowRoot!.querySelector('.progress'); + this.loadingPage = this.shadowRoot!.querySelector('.loading'); + this.tbl = this.shadowRoot!.querySelector('#tb-states'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement!.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.tbl!.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + + getTabPaneCounterSampleData( + val.leftNs + val.recordStartNs, + val.rightNs + val.recordStartNs, + val.cpuStateFilterIds + ).then((result) => { + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + let sampleMap = new Map(); + val.cpuStateFilterIds.forEach((a: number) => { + this.getInitTime( + result.filter((f) => f.filterId == a), + sampleMap, + val + ); + }); + let dataList: Array = []; + sampleMap.forEach((a) => { + a.timeStr = Utils.getProbablyTime(a.time); + dataList.push(a); + }); + this.source = dataList; + this.sortTable(this.sortKey, this.sortType); + }); + } + + getInitTime(result: Array, sampleMap: Map, val: SelectionParam) { + let leftNs = val.leftNs + val.recordStartNs; + let rightNs = val.rightNs + val.recordStartNs; + if (result.length == 0) return; + let idx = result.findIndex((a) => a.ts >= leftNs); + if (idx !== 0) { + result = result.slice(idx == -1 ? result.length - 1 : idx - 1, result.length); + } + if (result[0].ts < leftNs && idx !== 0) result[0].ts = leftNs; + result.forEach((item, idx) => { + if (idx + 1 == result.length) { + item.time = rightNs - item.ts; + } else { + item.time = result[idx + 1].ts - item.ts; + } + if (sampleMap.has(item.filterId + '-' + item.value)) { + let obj = sampleMap.get(item.filterId + '-' + item.value); + obj.time += item.time; + } else { + sampleMap.set(item.filterId + '-' + item.value, { + ...item, + counter: 'Cpu ' + item.cpu, + }); + } + }); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'timeStr') { + if (type == 1) { + return a.time - b.time; + } else { + return b.time - a.time; + } + } else if (key == 'counter') { + if (a.counter > b.counter) { + return type === 2 ? -1 : 1; + } else if (a.counter == b.counter) { + return 0; + } else { + return type === 2 ? 1 : -1; + } + } else if (key == 'value') { + if (type == 1) { + return a.value - b.value; + } else { + return b.value - a.value; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + + + + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.ts new file mode 100644 index 0000000000000000000000000000000000000000..492233ded5c64c6ff1de396a3a5277abd3763cde --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.ts @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCpuByProcess } from '../../../../database/SqlLite.js'; +import { log } from '../../../../../log/Log.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-cpu-process') +export class TabPaneCpuByProcess extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + + set data(val: SelectionParam | any) { + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + this.tbl!.recycleDataSource = []; + getTabCpuByProcess(val.cpus, val.leftNs, val.rightNs).then((result) => { + if (result != null && result.length > 0) { + log('getTabCpuByProcess size :' + result.length); + let sumWall = 0.0; + let sumOcc = 0; + for (let e of result) { + let process = Utils.PROCESS_MAP.get(e.pid); + e.process = process == null || process.length == 0 ? '[NULL]' : process; + sumWall += e.wallDuration; + sumOcc += e.occurrences; + e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); + e.avgDuration = parseFloat((parseFloat(e.avgDuration) / 1000000.0).toFixed(5)).toString(); + } + let count = new SelectionData(); + count.process = ' '; + count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(5)); + count.occurrences = sumOcc; + result.splice(0, 0, count); + this.source = result; + this.tbl!.recycleDataSource = result; + } else { + this.source = []; + this.tbl!.recycleDataSource = this.source; + } + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cpu-process'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if ( + detail.key === 'pid' || + detail.key === 'wallDuration' || + detail.key === 'avgDuration' || + detail.key === 'occurrences' + ) { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuByThread.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuByThread.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b660c0f81969921a8faf9b2a00ce738a9f88e01 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuByThread.ts @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCpuByThread } from '../../../../database/SqlLite.js'; +import { log } from '../../../../../log/Log.js'; +import { getProbablyTime } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-cpu-thread') +export class TabPaneCpuByThread extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + private pubColumns = ` + + + + + + + + + + + + + + + `; + + set data(val: SelectionParam | any) { + this.tbl!.innerHTML = this.getTableColumns(val.cpus); + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + getTabCpuByThread(val.cpus, val.leftNs, val.rightNs).then((result) => { + if (result != null && result.length > 0) { + log('getTabCpuByThread size :' + result.length); + let sumWall = 0.0; + let sumOcc = 0; + let map: Map = new Map(); + for (let e of result) { + sumWall += e.wallDuration; + sumOcc += e.occurrences; + if (map.has(`${e.tid}`)) { + let thread = map.get(`${e.tid}`)!; + thread.wallDuration += e.wallDuration; + thread.occurrences += e.occurrences; + thread[`cpu${e.cpu}`] = e.wallDuration || 0; + thread[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0); + thread[`cpu${e.cpu}Ratio`] = ((100.0 * (e.wallDuration || 0)) / (val.rightNs - val.leftNs)).toFixed(2); + } else { + let process = Utils.PROCESS_MAP.get(e.pid); + let thread = Utils.THREAD_MAP.get(e.tid); + let obj: any = { + tid: e.tid, + pid: e.pid, + thread: thread == null || thread.length == 0 ? '[NULL]' : thread, + process: process == null || process.length == 0 ? '[NULL]' : process, + wallDuration: e.wallDuration || 0, + occurrences: e.occurrences || 0, + avgDuration: 0, + }; + for (let i of val.cpus) { + obj[`cpu${i}`] = 0; + obj[`cpu${i}TimeStr`] = '0'; + obj[`cpu${i}Ratio`] = '0'; + } + obj[`cpu${e.cpu}`] = e.wallDuration || 0; + obj[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0); + obj[`cpu${e.cpu}Ratio`] = ((100.0 * (e.wallDuration || 0)) / (val.rightNs - val.leftNs)).toFixed(2); + map.set(`${e.tid}`, obj); + } + } + let arr = Array.from(map.values()).sort((a, b) => b.wallDuration - a.wallDuration); + for (let e of arr) { + e.avgDuration = (e.wallDuration / (e.occurrences || 1.0) / 1000000.0).toFixed(5); + e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); + } + let count: any = {}; + count.process = ' '; + count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(7)); + count.occurrences = sumOcc; + arr.splice(0, 0, count); + this.source = arr; + this.tbl!.recycleDataSource = arr; + } else { + this.source = []; + this.tbl!.recycleDataSource = this.source; + } + }); + } + + getTableColumns(cpus: Array) { + let col = `${this.pubColumns}`; + let cpuArr = cpus.sort((a, b) => a - b); + for (let i of cpuArr) { + col = `${col} + + + + + `; + } + return col; + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cpu-thread'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.tbl!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data; + data.isSelected = true; + this.tbl?.clearAllSelection(data); + this.tbl?.setCurrentSelection(data); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + if ((detail.key as string).includes('cpu')) { + if ((detail.key as string).includes('Ratio')) { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare((detail.key as string).replace('TimeStr', ''), detail.sort, 'number')); + } + } else { + if ( + detail.key === 'pid' || + detail.key == 'tid' || + detail.key === 'wallDuration' || + detail.key === 'avgDuration' || + detail.key === 'occurrences' + ) { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } + } + + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuStateClick.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuStateClick.ts new file mode 100644 index 0000000000000000000000000000000000000000..03c847368070726109a94bfb9205cb5ebf7df115 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuStateClick.ts @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-cpu-state-click') +export class TabPaneCpuStateClick extends BaseElement { + private tbl: LitTable | null | undefined; + + set data(val: any) { + if (val) { + this.tbl!.dataSource = [ + { + startNS: Utils.getTimeString(val.startTs), + absoluteTime: (val.startTs + (window as any).recordStartNS) / 1000000000, + dur: Utils.getProbablyTime(val.dur), + state: val.value, + cpu: `Cpu ${val.cpu}`, + }, + ]; + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-freq'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuUsage.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuUsage.ts new file mode 100644 index 0000000000000000000000000000000000000000..a68dd1bd075164c8b49325aa097101d67c10ef4d --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneCpuUsage.ts @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCpuFreq, getTabCpuUsage } from '../../../../database/SqlLite.js'; +import { CpuUsage, Freq } from '../../../../bean/CpuUsage.js'; + +@element('tabpane-cpu-usage') +export class TabPaneCpuUsage extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private orderByOldList: any[] = []; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + Promise.all([ + getTabCpuUsage(val.cpus, val.leftNs, val.rightNs), + getTabCpuFreq(val.cpus, val.leftNs, val.rightNs), + ]).then((result) => { + let usages = result[0]; + let freqMap = this.groupByCpuToMap(result[1]); + let data = []; + let range = val.rightNs - val.leftNs; + for (let cpu of val.cpus) { + let usage = new CpuUsage(); + usage.cpu = cpu; + let u = usages.find((e) => e.cpu == cpu); + if (u != undefined && u != null) { + usage.usage = u.usage; + } else { + usage.usage = 0; + } + if (usage.usage > 1) { + usage.usage = 1; + } + usage.usageStr = (usage.usage * 100.0).toFixed(2) + '%'; + let arr = []; + if (freqMap.has(usage.cpu)) { + let freqList = freqMap.get(usage.cpu); + let list = []; + for (let i = 0; i < freqList!.length; i++) { + let freq = freqList![i]; + if (i == freqList!.length - 1) { + freq.dur = val.rightNs - freq.startNs; + } else { + freq.dur = freqList![i + 1].startNs - freq.startNs; + } + if (freq.startNs + freq.dur > val.leftNs) { + list.push(freq); + } + } + if (list.length > 0) { + if (list[0].startNs < val.leftNs) { + list[0].dur = list[0].startNs + list[0].dur - val.leftNs; + list[0].startNs = val.leftNs; + } + } + arr = this.sortFreq(list); + this.getFreqTop3(usage, arr[0], arr[1], arr[2], range); + } + data.push(usage); + } + this.tbl!.recycleDataSource = data; + this.orderByOldList = [...data]; + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cpu-usage'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl?.addEventListener('column-click', (event) => { + // @ts-ignore + let orderType = event.detail; + if (orderType.sort == 1) { + //倒序 注意 sort会改变原数组,需要传入table上的数组 不能传入缓存排序数组 + this.sortTable(this.tbl!.recycleDataSource, orderType.key, false); + } else if (orderType.sort == 2) { + //正序 + this.sortTable(this.tbl!.recycleDataSource, orderType.key, true); + } else { + //默认排序 + this.tbl!.recycleDataSource = [...this.orderByOldList]; + } + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + sortTable(arr: any[], key: string, sort: boolean) { + this.tbl!.recycleDataSource = arr.sort((item1, item2) => { + let value1 = Number(item1[key].toString().replace('%', '')); + let value2 = Number(item2[key].toString().replace('%', '')); + if (value1 > value2) { + return sort ? -1 : 1; + } else if (value1 < value2) { + return sort ? 1 : -1; + } else { + return 0; + } + }); + } + + sortFreq(arr: Array): Array> { + let map = new Map(); + for (let freq of arr) { + if (map.has(freq.value)) { + let sumDur = map.get(freq.value)! + freq.dur; + map.set(freq.value, sumDur); + } else { + map.set(freq.value, freq.dur); + } + } + let array = Array.from(map); + array.sort((a, b) => b[1] - a[1]); + return array; + } + + getFreqTop3(usage: CpuUsage, top1: Array, top2: Array, top3: Array, range: number) { + // @ts-ignore + usage.top1 = top1 == undefined ? '-' : top1[0]; + usage.top1Percent = top1 == undefined ? 0 : (top1[1] * 1.0) / range; + usage.top1PercentStr = top1 == undefined ? '-' : (usage.top1Percent * 100).toFixed(2) + '%'; + // @ts-ignore + usage.top2 = top2 == undefined ? '-' : top2[0]; + usage.top2Percent = top2 == undefined ? 0 : (top2[1] * 1.0) / range; + usage.top2PercentStr = top2 == undefined ? '-' : (usage.top2Percent * 100).toFixed(2) + '%'; + // @ts-ignore + usage.top3 = top3 == undefined ? '-' : top3[0]; + usage.top3Percent = top3 == undefined ? 0 : (top3[1] * 1.0) / range; + usage.top3PercentStr = top3 == undefined ? '-' : (usage.top3Percent * 100).toFixed(2) + '%'; + } + + groupByCpuToMap(arr: Array): Map> { + let map = new Map>(); + for (let spt of arr) { + if (map.has(spt.cpu)) { + map.get(spt.cpu)!.push(spt); + } else { + let list: Array = []; + list.push(spt); + map.set(spt.cpu, list); + } + } + return map; + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b0af20635b11b6a7f71cc9791c5468cf1d57676 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneFrequencySample.ts @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPaneFrequencySampleData } from '../../../../database/SqlLite.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { Utils } from '../../base/Utils.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; + +@element('tabpane-frequency-sample') +export class TabPaneFrequencySample extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingPage: any; + private loadingList: number[] = []; + private source: any[] = []; + private sortKey: string = 'counter'; + private sortType: number = 0; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.selectionParam = val; + // @ts-ignore + this.tbl!.shadowRoot?.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.progressEL = this.shadowRoot!.querySelector('.progress'); + this.loadingPage = this.shadowRoot!.querySelector('.loading'); + this.tbl = this.shadowRoot!.querySelector('#tb-states'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement!.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.tbl!.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + + getTabPaneFrequencySampleData( + val.leftNs + val.recordStartNs, + val.rightNs + val.recordStartNs, + val.cpuFreqFilterIds + ).then((result) => { + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + let sampleMap = new Map(); + val.cpuFreqFilterIds.forEach((a: number) => { + this.getInitTime( + result.filter((f) => f.filterId == a), + sampleMap, + val + ); + }); + + let dataList: Array = []; + sampleMap.forEach((a) => { + a.timeStr = Utils.getProbablyTime(a.time); + dataList.push(a); + }); + this.source = dataList; + this.sortTable(this.sortKey, this.sortType); + }); + } + + getInitTime(result: Array, sampleMap: Map, val: SelectionParam) { + let leftNs = val.leftNs + val.recordStartNs; + let rightNs = val.rightNs + val.recordStartNs; + if (result.length == 0) return; + let idx = result.findIndex((a) => a.ts >= leftNs); + if (idx !== 0) { + result = result.slice(idx == -1 ? result.length - 1 : idx - 1, result.length); + } + if (result[0].ts < leftNs && idx !== 0) result[0].ts = leftNs; + result.forEach((item, idx) => { + if (idx + 1 == result.length) { + item.time = rightNs - item.ts; + } else { + item.time = result[idx + 1].ts - item.ts; + } + if (sampleMap.has(item.filterId + '-' + item.value)) { + let obj = sampleMap.get(item.filterId + '-' + item.value); + obj.time += item.time; + } else { + sampleMap.set(item.filterId + '-' + item.value, { + ...item, + counter: 'Cpu ' + item.cpu, + valueStr: ColorUtils.formatNumberComma(item.value) + ' kHz', + }); + } + }); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'timeStr') { + if (type == 1) { + return a.time - b.time; + } else { + return b.time - a.time; + } + } else if (key == 'counter') { + if (a.counter > b.counter) { + return type === 2 ? -1 : 1; + } else if (a.counter == b.counter) { + return 0; + } else { + return type === 2 ? 1 : -1; + } + } else if (key == 'valueStr') { + if (type == 1) { + return a.value - b.value; + } else { + return b.value - a.value; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + + + + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPanePTS.ts b/ide/src/trace/component/trace/sheet/cpu/TabPanePTS.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec19d417fe3fbe03fb436faf1cbc77f2eb95042f --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPanePTS.ts @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getStatesProcessThreadDataByRange } from '../../../../database/SqlLite.js'; +import { SPT, StateProcessThread } from '../../../../bean/StateProcessThread.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-pts') +export class TabPanePTS extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.selectionParam = val; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + if (this.loadDataInCache) { + this.getDataBySPT(val.leftNs, val.rightNs, SpSystemTrace.SPT_DATA); + } else { + this.queryDataByDB(val); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-states'); + this.range = this.shadowRoot?.querySelector('#time-range'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + getStatesProcessThreadDataByRange(val.leftNs, val.rightNs).then((result) => { + this.getDataBySPT(val.leftNs, val.rightNs, result); + }); + } + + getDataBySPT(leftNs: number, rightNs: number, source: Array) { + let pMap: Map = new Map(); + let ptMap: Map = new Map(); + let ptsMap: Map = new Map(); + source.map((d) => { + if (!(d.end_ts < leftNs || d.start_ts > rightNs)) { + if (pMap.has(d.processId + '')) { + let obj1 = pMap.get(d.processId + ''); + obj1!.count++; + obj1!.wallDuration += d.dur; + obj1!.avgDuration = (obj1!.wallDuration / obj1!.count).toFixed(2); + if (d.dur > obj1!.maxDuration) { + obj1!.maxDuration = d.dur; + } + if (d.dur < obj1!.minDuration) { + obj1!.minDuration = d.dur; + } + } else { + let obj1 = new StateProcessThread(); + obj1.id = 'p' + d.processId; + obj1.title = (d.process == null || d.process == '' ? 'Process' : d.process) + '(' + d.processId + ')'; + obj1.process = d.process; + obj1.processId = d.processId; + obj1.minDuration = d.dur; + obj1.maxDuration = d.dur; + obj1.count = 1; + obj1.avgDuration = d.dur + ''; + obj1.wallDuration = d.dur; + pMap.set(d.processId + '', obj1); + } + if (ptMap.has(d.processId + '_' + d.threadId)) { + let obj2 = ptMap.get(d.processId + '_' + d.threadId); + obj2!.count++; + obj2!.wallDuration += d.dur; + obj2!.avgDuration = (obj2!.wallDuration / obj2!.count).toFixed(2); + if (d.dur > obj2!.maxDuration) { + obj2!.maxDuration = d.dur; + } + if (d.dur < obj2!.minDuration) { + obj2!.minDuration = d.dur; + } + } else { + let obj2 = new StateProcessThread(); + obj2.id = 'p' + d.processId + '_' + 't' + d.threadId; + obj2.pid = 'p' + d.processId; + obj2.title = (d.thread == null || d.thread == '' ? 'Thread' : d.thread) + '(' + d.threadId + ')'; + obj2.processId = d.processId; + obj2.process = d.process; + obj2.thread = d.thread; + obj2.threadId = d.threadId; + obj2.minDuration = d.dur; + obj2.maxDuration = d.dur; + obj2.count = 1; + obj2.avgDuration = d.dur + ''; + obj2.wallDuration = d.dur; + ptMap.set(d.processId + '_' + d.threadId, obj2); + } + if (ptsMap.has(d.processId + '_' + d.threadId + '_' + d.state)) { + let obj3 = ptsMap.get(d.processId + '_' + d.threadId + '_' + d.state); + obj3!.count++; + obj3!.wallDuration += d.dur; + obj3!.avgDuration = (obj3!.wallDuration / obj3!.count).toFixed(2); + if (d.dur > obj3!.maxDuration) { + obj3!.maxDuration = d.dur; + } + if (d.dur < obj3!.minDuration) { + obj3!.minDuration = d.dur; + } + } else { + let obj3 = new StateProcessThread(); + obj3.id = 'p' + d.processId + '_' + 't' + d.threadId + '_' + (d.state == 'R+' ? 'RP' : d.state); + obj3.pid = 'p' + d.processId + '_' + 't' + d.threadId; + obj3.title = Utils.getEndState(d.state); + obj3.processId = d.processId; + obj3.process = d.process; + obj3.thread = d.thread; + obj3.threadId = d.threadId; + obj3.state = d.state; + obj3.minDuration = d.dur; + obj3.maxDuration = d.dur; + obj3.count = 1; + obj3.avgDuration = d.dur + ''; + obj3.wallDuration = d.dur; + ptsMap.set(d.processId + '_' + d.threadId + '_' + d.state, obj3); + } + } + }); + let arr: Array = []; + for (let key of pMap.keys()) { + let s = pMap.get(key); + s!.children = []; + for (let ks of ptMap.keys()) { + if (ks.startsWith(key + '_')) { + let sp = ptMap.get(ks); + sp!.children = []; + for (let kst of ptsMap.keys()) { + if (kst.startsWith(ks + '_')) { + let spt = ptsMap.get(kst); + sp!.children.push(spt!); + } + } + s!.children.push(sp!); + } + } + arr.push(s!); + } + this.tbl!.recycleDataSource = arr; + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneSPT.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneSPT.ts new file mode 100644 index 0000000000000000000000000000000000000000..393211ef3503acb0ab84815e5915150a62d47180 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneSPT.ts @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getStatesProcessThreadDataByRange } from '../../../../database/SqlLite.js'; +import { SPT, StateProcessThread } from '../../../../bean/StateProcessThread.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-spt') +export class TabPaneSPT extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.selectionParam = val; + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement!.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + if (this.loadDataInCache) { + this.getDataBySPT(val.leftNs, val.rightNs, SpSystemTrace.SPT_DATA); + } else { + this.queryDataByDB(val); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-states'); + this.range = this.shadowRoot?.querySelector('#time-range'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement!.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + getDataBySPT(leftNs: number, rightNs: number, source: Array) { + let statesMap: Map = new Map(); + let spMap: Map = new Map(); + let sptMap: Map = new Map(); + source.map((d) => { + if (!(d.end_ts < leftNs || d.start_ts > rightNs)) { + if (statesMap.has(d.state)) { + let obj1 = statesMap.get(d.state); + obj1!.count++; + obj1!.wallDuration += d.dur; + obj1!.avgDuration = (obj1!.wallDuration / obj1!.count).toFixed(2); + if (d.dur > obj1!.maxDuration) { + obj1!.maxDuration = d.dur; + } + if (d.dur < obj1!.minDuration) { + obj1!.minDuration = d.dur; + } + } else { + let obj1 = new StateProcessThread(); + obj1.id = d.state == 'R+' ? 'RP' : d.state; + obj1.title = Utils.getEndState(d.state); + obj1.state = d.state; + obj1.minDuration = d.dur; + obj1.maxDuration = d.dur; + obj1.count = 1; + obj1.avgDuration = d.dur + ''; + obj1.wallDuration = d.dur; + statesMap.set(d.state, obj1); + } + if (spMap.has(d.state + '_' + d.processId)) { + let obj2 = spMap.get(d.state + '_' + d.processId); + obj2!.count++; + obj2!.wallDuration += d.dur; + obj2!.avgDuration = (obj2!.wallDuration / obj2!.count).toFixed(2); + if (d.dur > obj2!.maxDuration) { + obj2!.maxDuration = d.dur; + } + if (d.dur < obj2!.minDuration) { + obj2!.minDuration = d.dur; + } + } else { + let obj2 = new StateProcessThread(); + obj2.id = (d.state == 'R+' ? 'RP' : d.state) + '_' + d.processId; + obj2.pid = d.state == 'R+' ? 'RP' : d.state; + obj2.title = (d.process == null || d.process == '' ? 'Process' : d.process) + '(' + d.processId + ')'; + obj2.processId = d.processId; + obj2.process = d.process; + obj2.state = d.state; + obj2.minDuration = d.dur; + obj2.maxDuration = d.dur; + obj2.count = 1; + obj2.avgDuration = d.dur + ''; + obj2.wallDuration = d.dur; + spMap.set(d.state + '_' + d.processId, obj2); + } + if (sptMap.has(d.state + '_' + d.processId + '_' + d.threadId)) { + let obj3 = sptMap.get(d.state + '_' + d.processId + '_' + d.threadId); + obj3!.count++; + obj3!.wallDuration += d.dur; + obj3!.avgDuration = (obj3!.wallDuration / obj3!.count).toFixed(2); + if (d.dur > obj3!.maxDuration) { + obj3!.maxDuration = d.dur; + } + if (d.dur < obj3!.minDuration) { + obj3!.minDuration = d.dur; + } + } else { + let obj3 = new StateProcessThread(); + obj3.id = (d.state == 'R+' ? 'RP' : d.state) + '_' + d.processId + '_' + d.threadId; + obj3.pid = (d.state == 'R+' ? 'RP' : d.state) + '_' + d.processId; + obj3.title = (d.thread == null || d.thread == '' ? 'Thread' : d.thread) + '(' + d.threadId + ')'; + obj3.processId = d.processId; + obj3.process = d.process; + obj3.thread = d.thread; + obj3.threadId = d.threadId; + obj3.state = d.state; + obj3.minDuration = d.dur; + obj3.maxDuration = d.dur; + obj3.count = 1; + obj3.avgDuration = d.dur + ''; + obj3.wallDuration = d.dur; + sptMap.set(d.state + '_' + d.processId + '_' + d.threadId, obj3); + } + } + }); + let arr: Array = []; + for (let key of statesMap.keys()) { + let s = statesMap.get(key); + s!.children = []; + for (let ks of spMap.keys()) { + if (ks.startsWith(key + '_')) { + let sp = spMap.get(ks); + sp!.children = []; + for (let kst of sptMap.keys()) { + if (kst.startsWith(ks + '_')) { + let spt = sptMap.get(kst); + sp!.children.push(spt!); + } + } + s!.children.push(sp!); + } + } + arr.push(s!); + } + this.tbl!.recycleDataSource = arr; + } + + queryDataByDB(val: SelectionParam | any) { + getStatesProcessThreadDataByRange(val.leftNs, val.rightNs).then((result) => { + this.getDataBySPT(val.leftNs, val.rightNs, result); + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.ts b/ide/src/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff2c767ca743c39c955b9529474ee80236188855 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.ts @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getStatesProcessThreadDataByRange } from '../../../../database/SqlLite.js'; +import { SPT, StateProcessThread } from '../../../../bean/StateProcessThread.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-thread-switch') +export class TabPaneThreadSwitch extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.selectionParam = val; + //@ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + if (this.loadDataInCache) { + this.getDataBySPT(val.leftNs, val.rightNs, SpSystemTrace.SPT_DATA); + } else { + this.queryDataByDB(val); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-ts'); + this.range = this.shadowRoot?.querySelector('#time-range'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement!.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + getDataBySPT(leftNs: number, rightNs: number, source: Array) { + let statesMap: Map = new Map(); + let spMap: Map = new Map(); + let sptMap: Map = new Map(); + source.map((d) => { + if (!(d.end_ts < leftNs || d.start_ts > rightNs)) { + if (statesMap.has(d.state)) { + let obj1 = statesMap.get(d.state); + obj1!.count++; + obj1!.wallDuration += d.dur; + obj1!.avgDuration = (obj1!.wallDuration / obj1!.count).toFixed(2); + if (d.dur > obj1!.maxDuration) { + obj1!.maxDuration = d.dur; + } + if (d.dur < obj1!.minDuration) { + obj1!.minDuration = d.dur; + } + } else { + let obj1 = new StateProcessThread(); + obj1.id = d.state == 'R+' ? 'RP' : d.state; + obj1.title = Utils.getEndState(d.state); + obj1.state = d.state; + obj1.minDuration = d.dur; + obj1.maxDuration = d.dur; + obj1.count = 1; + obj1.avgDuration = d.dur + ''; + obj1.wallDuration = d.dur; + statesMap.set(d.state, obj1); + } + if (spMap.has(d.state + '_' + d.processId)) { + let obj2 = spMap.get(d.state + '_' + d.processId); + obj2!.count++; + obj2!.wallDuration += d.dur; + obj2!.avgDuration = (obj2!.wallDuration / obj2!.count).toFixed(2); + if (d.dur > obj2!.maxDuration) { + obj2!.maxDuration = d.dur; + } + if (d.dur < obj2!.minDuration) { + obj2!.minDuration = d.dur; + } + } else { + let obj2 = new StateProcessThread(); + obj2.id = (d.state == 'R+' ? 'RP' : d.state) + '_' + d.processId; + obj2.pid = d.state == 'R+' ? 'RP' : d.state; + obj2.title = (d.process == null || d.process == '' ? 'Process' : d.process) + '(' + d.processId + ')'; + obj2.processId = d.processId; + obj2.process = d.process; + obj2.state = d.state; + obj2.minDuration = d.dur; + obj2.maxDuration = d.dur; + obj2.count = 1; + obj2.avgDuration = d.dur + ''; + obj2.wallDuration = d.dur; + spMap.set(d.state + '_' + d.processId, obj2); + } + if (sptMap.has(d.state + '_' + d.processId + '_' + d.threadId)) { + let obj3 = sptMap.get(d.state + '_' + d.processId + '_' + d.threadId); + obj3!.count++; + obj3!.wallDuration += d.dur; + obj3!.avgDuration = (obj3!.wallDuration / obj3!.count).toFixed(2); + if (d.dur > obj3!.maxDuration) { + obj3!.maxDuration = d.dur; + } + if (d.dur < obj3!.minDuration) { + obj3!.minDuration = d.dur; + } + } else { + let obj3 = new StateProcessThread(); + obj3.id = (d.state == 'R+' ? 'RP' : d.state) + '_' + d.processId + '_' + d.threadId; + obj3.pid = (d.state == 'R+' ? 'RP' : d.state) + '_' + d.processId; + obj3.title = (d.thread == null || d.thread == '' ? 'Thread' : d.thread) + '(' + d.threadId + ')'; + obj3.processId = d.processId; + obj3.process = d.process; + obj3.thread = d.thread; + obj3.threadId = d.threadId; + obj3.state = d.state; + obj3.minDuration = d.dur; + obj3.maxDuration = d.dur; + obj3.count = 1; + obj3.avgDuration = d.dur + ''; + obj3.wallDuration = d.dur; + sptMap.set(d.state + '_' + d.processId + '_' + d.threadId, obj3); + } + } + }); + let arr: Array = []; + for (let key of statesMap.keys()) { + let s = statesMap.get(key); + s!.children = []; + for (let ks of spMap.keys()) { + if (ks.startsWith(key + '_')) { + let sp = spMap.get(ks); + sp!.children = []; + for (let kst of sptMap.keys()) { + if (kst.startsWith(ks + '_')) { + let spt = sptMap.get(kst); + sp!.children.push(spt!); + } + } + s!.children.push(sp!); + } + } + arr.push(s!); + } + this.tbl!.recycleDataSource = arr; + } + + queryDataByDB(val: SelectionParam | any) { + getStatesProcessThreadDataByRange(val.leftNs, val.rightNs).then((result) => { + this.getDataBySPT(val.leftNs, val.rightNs, result); + }); + } + + initHtml(): string { + return ` + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.ts b/ide/src/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d05edcbd9d0bf1ac8038009c52a4ce794482864 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.ts @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { SpHiSysEventChart } from '../../../chart/SpHiSysEventChart.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; + +import { queryAnomalyDetailedData } from '../../../../database/SqlLite.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { EnergyAnomalyStruct } from '../../../../database/ui-worker/ProcedureWorkerEnergyAnomaly.js'; + +@element('tabpane-anomaly-details') +export class TabPaneEnergyAnomaly extends BaseElement { + private tbl: LitTable | null | undefined; + private tableObserver: MutationObserver | undefined; + private static KEY_INDEX: number = 2; + private static VALUE_INDEX: number = 3; + set data(selection: SelectionParam) { + let div: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#anomaly-details'); + let htmlText = ''; + if (selection) { + this.queryAnomalyTableData(selection.leftNs, selection.rightNs).then((bean) => { + let filterAppMap = new Map(); + for (let index = 0; index < bean.length; index++) { + let findAppNameIndex = -1; + // @ts-ignore + let values = Object.values(bean[index]); + if (values[TabPaneEnergyAnomaly.VALUE_INDEX]) { + let apps = values[TabPaneEnergyAnomaly.VALUE_INDEX].split(','); + for (let appIndex = 0; appIndex < apps.length; appIndex++) { + if (apps.indexOf(SpHiSysEventChart.app_name) != -1) { + findAppNameIndex = apps.indexOf(SpHiSysEventChart.app_name); + filterAppMap.set(values[0] + values[1], findAppNameIndex); + break; + } + } + if (values[TabPaneEnergyAnomaly.KEY_INDEX] == 'APPNAME') { + //ts+eventName : appNameIndex + filterAppMap.set(values[0] + values[1], findAppNameIndex); + } + } + } + let set = new Set(); + for (let index = 0; index < bean.length; index++) { + // @ts-ignore + let values = Object.values(bean[index]); + let findAppNameIndex = -1; + if (filterAppMap.get(values[0] + values[1]) == -1) { + continue; + } else { + findAppNameIndex = filterAppMap.get(values[0] + values[1]); + } + if (!set.has(values[0])) { + set.add(values[0]); + htmlText += + '
' + + '' + + values[1] + + ''; + } + // @ts-ignore + if (set.has(Object.values(bean[index])[0])) { + let appValues = values[TabPaneEnergyAnomaly.VALUE_INDEX].split(','); + htmlText += + "" + + values[TabPaneEnergyAnomaly.KEY_INDEX] + + "" + + (findAppNameIndex >= 0 + ? appValues.length > 1 + ? appValues[findAppNameIndex] + : values[TabPaneEnergyAnomaly.VALUE_INDEX] + : values[TabPaneEnergyAnomaly.VALUE_INDEX]) + + TabPaneEnergyAnomaly.getUnit(values[TabPaneEnergyAnomaly.KEY_INDEX]) + + ""; + } + if (index + 1 < bean.length) { + // @ts-ignore + let nextValues = Object.values(bean[index + 1]); + let appValues = nextValues[TabPaneEnergyAnomaly.VALUE_INDEX].split(','); + if (set.has(nextValues[0])) { + htmlText += + "" + + nextValues[TabPaneEnergyAnomaly.KEY_INDEX] + + "" + + (findAppNameIndex >= 0 + ? appValues.length > 1 + ? appValues[findAppNameIndex] + : nextValues[TabPaneEnergyAnomaly.VALUE_INDEX] + : nextValues[TabPaneEnergyAnomaly.VALUE_INDEX]) + + TabPaneEnergyAnomaly.getUnit(nextValues[TabPaneEnergyAnomaly.KEY_INDEX]) + + ''; + } else { + htmlText += ''; + htmlText += '
'; + continue; + } + index++; + } + } + div!.innerHTML = htmlText; + }); + } + } + + static getUnit(value: any) { + if (value == 'DURATION') { + return ' ms'; + } else if (value == 'ENERGY' || value == 'BGENERGY' || value == 'BATTERY_GAS_GUAGE') { + return ' mAh'; + } else if (value == 'BGUSAGE') { + return ' s'; + } + return ''; + } + + /** + * 查询出 异常详细信息 + * @param data + */ + async queryAnomalyTableData(startTime: number, endTime: number): Promise> { + let anomalyTableData = await queryAnomalyDetailedData(startTime, endTime); + return anomalyTableData; + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#anomalyselectionTbl'); + this.tbl?.addEventListener('column-click', (ev: any) => {}); + this.addTableObserver(); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + addTableObserver() { + let MutationObserver = window.MutationObserver; + this.tableObserver = new MutationObserver((list) => { + if (this.tbl) { + let width = getComputedStyle(this.tbl).getPropertyValue('width'); + let height = getComputedStyle(this.tbl).getPropertyValue('height'); + } + }); + let selector = this.shadowRoot?.querySelector('.left-table'); + this.tableObserver?.observe(selector!, { + attributes: true, + attributeFilter: ['style'], + attributeOldValue: true, + }); + } + + initHtml(): string { + return ` + +
+
+

+
+
+
+ + + + + + +
+
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/energy/TabPanePowerBattery.ts b/ide/src/trace/component/trace/sheet/energy/TabPanePowerBattery.ts new file mode 100644 index 0000000000000000000000000000000000000000..74c297136db30cd3de219500cb9c4760129f0e12 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/energy/TabPanePowerBattery.ts @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPowerBatteryData } from '../../../../database/SqlLite.js'; +import { SpHiSysEventChart } from '../../../chart/SpHiSysEventChart.js'; +import '../../../../../base-ui/table/lit-table.js'; + +@element('tabpane-power-battery') +export class TabPanePowerBattery extends BaseElement { + private tbl: LitTable | null | undefined; + + set data(val: SelectionParam | any) { + this.queryDataByDB(val); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-power-battery-energy'); + } + + queryDataByDB(val: SelectionParam | any) { + getTabPowerBatteryData(val.rightNs).then((result) => { + let list: Array = []; + let powerData: any = { + POWER_IDE_BATTERY: { + gas_gauge: [], + charge: [], + screen: [], + level: [], + current: [], + capacity: [], + appName: '', + uid: [], + }, + }; + result.forEach((item) => { + let powerDatum: any = powerData[item.eventName]; + if (item.appKey.toLocaleLowerCase() === 'appname') { + powerDatum['appName'] = SpHiSysEventChart.app_name; + } else { + let eventData: Array = item.eventValue.split(','); + if (eventData.length > 0) { + let i = eventData.length - 1 >= 0 ? eventData.length - 1 : 0; + powerDatum[item.appKey.toLocaleLowerCase()] = eventData[i]; + } else { + powerDatum[item.appKey.toLocaleLowerCase()] = eventData.toString(); + } + } + }); + list.push({ + name: 'Gas Gauge', + value: powerData['POWER_IDE_BATTERY'].gas_gauge + ' mAh', + }); + list.push({ + name: 'Charge', + value: powerData['POWER_IDE_BATTERY'].charge, + }); + list.push({ + name: 'Screen', + value: powerData['POWER_IDE_BATTERY'].screen, + }); + list.push({ + name: 'Level', + value: powerData['POWER_IDE_BATTERY'].level + ' %', + }); + list.push({ + name: 'Current', + value: powerData['POWER_IDE_BATTERY'].current + ' mA', + }); + list.push({ + name: 'Capacity', + value: powerData['POWER_IDE_BATTERY'].capacity + ' mAh', + }); + list.push({ name: 'APP Name', value: SpHiSysEventChart.app_name! }); + if (list.length > 0) { + this.tbl!.recycleDataSource = list; + } else { + this.tbl!.recycleDataSource = []; + } + this.tbl?.shadowRoot?.querySelectorAll('.tr').forEach((tr) => { + let td = tr.querySelectorAll('.td'); + this.setTableStyle(td[0], '0.9', '16px'); + this.setTableStyle(td[1], '0.6', '20px'); + }); + }); + } + + setTableStyle(td: HTMLDivElement, opacity: string, lineHeight: string) { + td.style.fontWeight = '400'; + td.style.fontSize = '14px'; + td.style.opacity = opacity; + td.style.lineHeight = lineHeight; + } + + initHtml(): string { + return ` + +
+
+
+ + + + +
+
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/energy/TabPanePowerDetails.ts b/ide/src/trace/component/trace/sheet/energy/TabPanePowerDetails.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9c44ec2ef71adb70b021eebebc4cb6b9da5230f --- /dev/null +++ b/ide/src/trace/component/trace/sheet/energy/TabPanePowerDetails.ts @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPowerDetailsData } from '../../../../database/SqlLite.js'; +import { log } from '../../../../../log/Log.js'; +import { PowerDetailsEnergy } from '../../../../bean/EnergyStruct.js'; +import { SpHiSysEventChart } from '../../../chart/SpHiSysEventChart.js'; + +@element('tabpane-power-details') +export class TabPanePowerDetails extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private itemType: any; + + set data(val: SelectionParam | any) { + this.queryDataByDB(val); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-power-details-energy'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + this.source = []; + this.itemType = { + time_type: [ + 'foreground_duration', + 'background_duration', + 'screen_on_duration', + 'screen_off_duration', + 'foreground_count', + 'background_count', + 'screen_on_count', + 'screen_off_count', + 'duration', + 'energy', + 'usage', + 'camera_id', + ], + duration_type: [ + 'background_time', + 'screen_on_time', + 'screen_off_time', + 'load', + 'uid', + 'usage', + 'charge', + 'foreground_count', + 'background_count', + 'screen_on_count', + 'screen_off_count', + 'energy', + 'duration', + ], + energy_type: [ + 'background_time', + 'screen_on_time', + 'screen_off_time', + 'load', + 'charge', + 'foreground_count', + 'background_count', + 'screen_on_count', + 'screen_off_count', + 'camera_id', + 'uid', + 'foreground_duration', + 'foreground_energy', + 'background_duration', + 'background_energy', + 'screen_on_duration', + 'screen_on_energy', + 'screen_off_duration', + 'screen_off_energy', + ], + count_type: [ + 'background_time', + 'screen_on_time', + 'screen_off_time', + 'load', + 'energy', + 'usage', + 'foreground_duration', + 'background_duration', + 'screen_on_duration', + 'screen_off_duration', + 'camera_id', + 'uid', + 'duration', + 'charge', + ], + }; + } + + queryDataByDB(val: SelectionParam | any) { + getTabPowerDetailsData(val.leftNs - val.leftNs, val.rightNs).then((items) => { + log('getTabPowerDetailsData size :' + items.length); + let detailsData: Array = []; + let set = new Set(); + set.add('COUNT'); + set.add('LOAD'); + set.add('CHARGE'); + set.add('CAMERA_ID'); + + let powerData: any = { + POWER_IDE_CPU: new PowerDetailsEnergy('CPU'), + POWER_IDE_LOCATION: new PowerDetailsEnergy('LOCATION'), + POWER_IDE_GPU: new PowerDetailsEnergy('GPU'), + POWER_IDE_DISPLAY: new PowerDetailsEnergy('DISPLAY'), + POWER_IDE_CAMERA: new PowerDetailsEnergy('CAMERA'), + POWER_IDE_BLUETOOTH: new PowerDetailsEnergy('BLUETOOTH'), + POWER_IDE_FLASHLIGHT: new PowerDetailsEnergy('FLASHLIGHT'), + POWER_IDE_AUDIO: new PowerDetailsEnergy('AUDIO'), + POWER_IDE_WIFISCAN: new PowerDetailsEnergy('WIFISCAN'), + }; + let tsMax = 0; + let currentAppIndex = -1; + items.forEach((item) => { + let powerDatum: any = powerData[item.eventName]; + if (item.appKey.toLocaleLowerCase() === 'appname') { + powerDatum['appName'] = SpHiSysEventChart.app_name; + currentAppIndex = item.eventValue.split(',').indexOf(SpHiSysEventChart.app_name!); + tsMax = 0; + } else if (currentAppIndex > -1) { + if (set.has(item.appKey)) { + if (item.startNS >= tsMax) { + powerDatum[item.appKey.toLocaleLowerCase()] = item.eventValue; + tsMax = item.startNS; + } + } else { + powerDatum[item.appKey.toLocaleLowerCase()] += parseInt(item.eventValue.split(',')[currentAppIndex]); + } + } + }); + + let totalEnergy = + powerData['POWER_IDE_CPU'].getTotalEnergy(false) + + powerData['POWER_IDE_LOCATION'].getTotalEnergy(false) + + powerData['POWER_IDE_GPU'].getTotalEnergy(true) + + powerData['POWER_IDE_DISPLAY'].getTotalEnergy(true) + + powerData['POWER_IDE_CAMERA'].getTotalEnergy(false) + + powerData['POWER_IDE_BLUETOOTH'].getTotalEnergy(false) + + powerData['POWER_IDE_FLASHLIGHT'].getTotalEnergy(false) + + powerData['POWER_IDE_AUDIO'].getTotalEnergy(false) + + powerData['POWER_IDE_WIFISCAN'].getTotalEnergy(false); + + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_CPU', false, 'time_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_LOCATION', false, 'duration_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_GPU', true, 'energy_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_DISPLAY', true, 'energy_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_CAMERA', false, 'duration_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_BLUETOOTH', false, 'duration_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_FLASHLIGHT', false, 'duration_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_AUDIO', false, 'duration_type')); + detailsData.push(this.setEnergyItems(powerData, totalEnergy, 'POWER_IDE_WIFISCAN', false, 'count_type')); + + if (detailsData.length > 0) { + this.source = detailsData; + this.tbl!.recycleDataSource = detailsData; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + this.tbl?.shadowRoot?.querySelectorAll('.td').forEach((td) => { + td.style.fontSize = '14px'; + td.style.fontWeight = '400'; + td.style.opacity = '0.9'; + td.style.lineHeight = '16px'; + }); + }); + let th = this.tbl?.shadowRoot?.querySelector('.th'); + if (th) { + th!.style.gridColumnGap = '5px'; + } + } + + setEnergyItems(powerData: any, totalEnergy: number, energyName: string, isSimpleEnergy: boolean, type: any): any { + let ratio = (powerData[energyName].getTotalEnergy(isSimpleEnergy) * 100) / totalEnergy; + if (totalEnergy == 0) { + powerData[energyName].energyConsumptionRatio = '0.000 %'; + } else { + powerData[energyName].energyConsumptionRatio = ratio.toFixed(3) + ' %'; + } + return this.getEnergyStyle(powerData, energyName, type); + } + + getEnergyStyle(powerData: any, energyName: string, type: any) { + this.itemType[type].forEach((item: any) => { + powerData[energyName][item] = '-'; + }); + if (type === 'energy_type') { + if (energyName == 'POWER_IDE_GPU') { + powerData[energyName]['duration'] = '-'; + } else { + powerData[energyName]['usage'] = '-'; + } + } else if (type === 'duration_type') { + if (energyName != 'POWER_IDE_CAMERA') { + powerData[energyName]['camera_id'] = '-'; + } + } + return powerData[energyName]; + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: PowerDetailsEnergy, b: PowerDetailsEnergy) { + if (type === 'number') { + return sort === 2 + ? // @ts-ignore + parseFloat(b[property] == '-' ? 0 : b[property]) - parseFloat(a[property] == '-' ? 0 : a[property]) + : // @ts-ignore + parseFloat(a[property] == '-' ? 0 : a[property]) - parseFloat(b[property] == '-' ? 0 : b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'appName') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + + this.tbl?.shadowRoot?.querySelectorAll('.td').forEach((td) => { + td.style.fontSize = '14px'; + td.style.fontWeight = '400'; + td.style.opacity = '0.9'; + td.style.lineHeight = '16px'; + }); + } +} diff --git a/ide/src/trace/component/trace/sheet/energy/TabPaneSystemDetails.ts b/ide/src/trace/component/trace/sheet/energy/TabPaneSystemDetails.ts new file mode 100644 index 0000000000000000000000000000000000000000..09cc0ac19c86c8e5d59786ac1f6d3d83d64fea26 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/energy/TabPaneSystemDetails.ts @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2022 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 { SystemDetailsEnergy } from '../../../../bean/EnergyStruct.js'; +import { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { + querySysLocationDetailsData, + querySysLockDetailsData, + querySystemWorkData, +} from '../../../../database/SqlLite.js'; +import { SpHiSysEventChart } from '../../../chart/SpHiSysEventChart.js'; + +@element('tabpane-system-details') +export class TabPaneSystemDetails extends BaseElement { + private tbl: LitTable | null | undefined; + private detailsTbl: LitTable | null | undefined; + private eventSource: Array = []; + private detailsSource: Array = []; + private boxDetails: HTMLDivElement | null | undefined; + + set data(val: SelectionParam | any) { + this.queryDataByDB(val); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initElements(): void { + this.boxDetails = this.shadowRoot?.querySelector('.box-details'); + this.tbl = this.shadowRoot?.querySelector('#tb-system-data'); + this.detailsTbl = this.shadowRoot?.querySelector('#tb-system-details-data'); + + this.tbl!.addEventListener('row-click', (e) => { + this.detailsSource = []; + // @ts-ignore + let data = e.detail.data as SystemDetailsEnergy; + this.convertData(data); + }); + + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + + convertData(data: SystemDetailsEnergy) { + if (data.eventName === 'Event Name') { + this.detailsTbl!.recycleDataSource = []; + this.boxDetails!.style.width = '100%'; + } else { + this.detailsSource.push({ + key: 'EVENT_NAME : ', + value: data.eventName, + }); + this.detailsSource.push({ key: 'PID : ', value: data.pid }); + this.detailsSource.push({ key: 'UID : ', value: data.uid }); + if (data.eventName === 'GNSS_STATE') { + this.detailsSource.push({ key: 'STATE : ', value: data.state }); + } else if (data.eventName === 'POWER_RUNNINGLOCK') { + this.detailsSource.push({ key: 'TYPE : ', value: data.type }); + this.detailsSource.push({ key: 'STATE : ', value: data.state }); + this.detailsSource.push({ + key: 'LOG_LEVEL : ', + value: data.log_level, + }); + this.detailsSource.push({ key: 'NAME : ', value: data.name }); + this.detailsSource.push({ + key: 'MESSAGE : ', + value: data.message, + }); + this.detailsSource.push({ key: 'TAG : ', value: data.tag }); + } else { + this.detailsSource.push({ key: 'TYPE : ', value: data.type }); + this.detailsSource.push({ + key: 'WORK_ID : ', + value: data.workId, + }); + this.detailsSource.push({ key: 'NAME : ', value: data.name }); + this.detailsSource.push({ + key: 'INTERVAL : ', + value: data.interval, + }); + } + this.detailsTbl!.recycleDataSource = this.detailsSource; + this.boxDetails!.style.width = '65%'; + } + this.detailsTbl!.shadowRoot?.querySelectorAll('.td').forEach((td) => { + let item = td.getAttribute('title'); + td.style.fontSize = '14px'; + td.style.fontWeight = '400'; + if (item != null && item.indexOf(':') > -1) { + td.style.opacity = '0.9'; + td.style.lineHeight = '16px'; + } else { + td.style.opacity = '0.6'; + td.style.lineHeight = '20px'; + } + }); + } + + queryDataByDB(val: SelectionParam | any) { + Promise.all([ + querySystemWorkData(val.rightNs), + querySysLockDetailsData(val.rightNs, 'POWER_RUNNINGLOCK'), + querySysLocationDetailsData(val.rightNs, 'GNSS_STATE'), + ]).then((result) => { + let itemList: Array = []; + let systemWorkData = this.getSystemWorkData(result[0], val.leftNs, val.rightNs); + if (systemWorkData.length > 0) { + systemWorkData.forEach((item) => { + itemList.push(item); + }); + } + let systemLockData = this.getSystemLockData(result[1], val.leftNs); + if (systemLockData.length > 0) { + systemLockData.forEach((item) => { + itemList.push(item); + }); + } + let systemLocationData = this.getSystemLocationData(result[2], val.leftNs); + if (systemLocationData.length > 0) { + systemLocationData.forEach((item) => { + itemList.push(item); + }); + } + itemList.sort((leftData: any, rightData: any) => { + return leftData.ts - rightData.ts; + }); + this.eventSource = []; + this.eventSource.push({ + ts: 'Time', + interval: 0, + level: 0, + name: '', + state: 0, + tag: '', + type: '', + uid: 0, + pid: 0, + workId: '', + message: '', + log_level: '', + eventName: 'Event Name', + }); + + this.tbl!.recycleDataSource = this.eventSource.concat(itemList); + this.detailsTbl!.recycleDataSource = []; + this.boxDetails!.style.width = '100%'; + this.tbl?.shadowRoot?.querySelectorAll('.td').forEach((td) => { + td.style.fontSize = '14px'; + if (td.getAttribute('title') === 'Event Name' || td.getAttribute('title') === 'Time') { + td.style.fontWeight = '700'; + } else { + td.style.fontWeight = '400'; + td.style.opacity = '0.9'; + td.style.lineHeight = '16px'; + } + }); + }); + } + + private getSystemWorkData(data: Array, leftNs: number, rightNs: number) { + let values = this.getConvertData(data); + let lifeCycleData: Array = []; + let watchIndex: Array = []; + for (let index = 0; index < values.length; index++) { + let filterData: any = values[index]; + if (filterData.name == SpHiSysEventChart.app_name) { + if (filterData.eventName.indexOf('WORK_ADD') > -1) { + watchIndex.push(filterData.workId); + let number = watchIndex.indexOf(filterData.workId); + lifeCycleData[number] = { + startData: {}, + endData: {}, + rangeData: [], + }; + lifeCycleData[number].startData = filterData; + let virtualEndData = JSON.parse(JSON.stringify(filterData)); + virtualEndData.ts = rightNs; + virtualEndData.eventName = 'WORK_REMOVE'; + lifeCycleData[number].endData = virtualEndData; + } else if (filterData.eventName.indexOf('WORK_REMOVE') > -1) { + let number = watchIndex.indexOf(filterData.workId); + if (number > -1) { + lifeCycleData[number].endData = filterData; + watchIndex[number] = number + filterData.ts; + } + } else { + let number = watchIndex.indexOf(filterData.workId); + if (number > -1) { + lifeCycleData[number].rangeData.push(filterData); + let virtualEndData = JSON.parse(JSON.stringify(filterData)); + virtualEndData.ts = rightNs; + virtualEndData.eventName = 'WORK_REMOVE'; + lifeCycleData[number].endData = virtualEndData; + } else { + if (filterData.eventName.indexOf('WORK_START') > -1) { + lifeCycleData.push({ + startData: {}, + endData: {}, + rangeData: [], + }); + watchIndex.push(filterData.workId); + number = watchIndex.indexOf(filterData.workId); + let virtualData = JSON.parse(JSON.stringify(filterData)); + if (filterData.ts > 0) { + virtualData.ts = 0; + } else { + virtualData.ts = filterData.ts - 1; + } + virtualData.eventName = 'WORK_ADD'; + lifeCycleData[number].startData = virtualData; + lifeCycleData[number].rangeData.push(filterData); + let virtualEndData = JSON.parse(JSON.stringify(filterData)); + virtualEndData.ts = rightNs; + virtualEndData.eventName = 'WORK_REMOVE'; + lifeCycleData[number].endData = virtualEndData; + } + } + } + } + } + let resultData: Array = []; + lifeCycleData.forEach((life: any) => { + if (life.endData.ts >= leftNs) { + let midData = life.rangeData; + midData.forEach((rang: any, index: number) => { + if (rang.eventName.indexOf('WORK_STOP') > -1 && rang.ts >= leftNs) { + resultData.push(life.startData); + if (index - 1 >= 0 && midData[index - 1].eventName.indexOf('WORK_START') > -1) { + resultData.push(midData[index - 1]); + } + resultData.push(rang); + } + }); + } + }); + return resultData; + } + + private getSystemLocationData(data: Array, leftNs: number) { + let values = this.getConvertData(data); + let fillMap: Map = new Map(); + let leftMap: Map = new Map(); + let watchIndex: Array = []; + for (let index = 0; index < values.length; index++) { + let filterData: any = values[index]; + if (filterData.state.indexOf('start') > -1) { + leftMap.set(filterData.pid, filterData); + watchIndex.push(filterData.pid); + } else { + let i = watchIndex.indexOf(filterData.pid); + if (i > -1) { + fillMap.set(leftMap.get(filterData.pid), filterData); + delete watchIndex[i]; + leftMap.delete(filterData.pid); + } + } + } + + let locationData: Array = []; + fillMap.forEach((value, key) => { + if (value.ts >= leftNs) { + locationData.push(key); + locationData.push(value); + } + }); + leftMap.forEach((value, key) => { + locationData.push(value); + }); + return locationData; + } + + private getSystemLockData(data: Array, leftNs: number) { + let values = this.getConvertData(data); + let watchIndex: Array = []; + let fillMap: Map = new Map(); + let leftMap: Map = new Map(); + for (let index = 0; index < values.length; index++) { + let filterData: any = values[index]; + if (filterData.tag.indexOf('ADD') > -1) { + leftMap.set(filterData.message, filterData); + watchIndex.push(filterData.message); + } else { + let i = watchIndex.indexOf(filterData.message); + if (i > -1) { + fillMap.set(leftMap.get(filterData.message), filterData); + delete watchIndex[i]; + leftMap.delete(filterData.message); + } + } + } + let lockData: Array = []; + fillMap.forEach((value, key) => { + if (value.ts >= leftNs) { + lockData.push(key); + lockData.push(value); + } + }); + leftMap.forEach((value, key) => { + lockData.push(value); + }); + return lockData; + } + + private getConvertData(data: Array) { + let it: any = {}; + data.forEach((item: any) => { + if (it[item.ts + item.eventName] == undefined) { + it[item.ts + item.eventName] = {}; + it[item.ts + item.eventName]['ts'] = item.ts; + it[item.ts + item.eventName]['eventName'] = item.eventName; + it[item.ts + item.eventName][item.appKey.toLocaleLowerCase()] = item.appValue; + } else { + it[item.ts + item.eventName][item.appKey.toLocaleLowerCase()] = item.appValue; + } + }); + // @ts-ignore + return Object.values(it); + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + +
+ + + + + + + +
+
+ +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneCallTree.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneCallTree.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f9acfdf318ec57c2541600b7c23d4a94fb78bd5 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneCallTree.ts @@ -0,0 +1,640 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { FrameChart } from '../../../chart/FrameChart.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { ChartMode } from '../../../../bean/FrameChartStruct.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { MerageBean } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon.js'; + +@element('tabpane-calltree') +export class TabPaneCallTree extends BaseElement { + public queryFuncName: string = ''; + public procedureAction: string = ''; + private tbl: LitTable | null | undefined; + private tbr: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private rightSource: Array = []; + private filter: any; + private dataSource: any[] = []; + private sortKey = 'weight'; + private sortType = 0; + private currentSelectedData: any = undefined; + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private systmeRuleName = '/system/'; + private numRuleName = '/max/min/'; + private needShowMenu = true; + private searchValue: string = ''; + private loadingList: number[] = []; + private loadingPage: any; + private currentSelection: SelectionParam | undefined; + private flameChartMode: ChartMode = ChartMode.Duration; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.searchValue = ''; + this.initModeAndAction(); + this.currentSelection = val; + this.tbl!.style.visibility = 'visible'; + if (this.parentElement!.clientHeight > this.filter!.clientHeight) { + this.filter!.style.display = 'flex'; + } else { + this.filter!.style.display = 'none'; + } + this.filter!.initializeFilterTree(true, true, true); + this.filter!.filterValue = ''; + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [{ queryFuncName: this.queryFuncName, ...val }], + }, + ], + (results: any[]) => { + this.setLTableData(results); + this.tbr!.recycleDataSource = []; + this.frameChart!.mode = this.flameChartMode; + this.frameChart!.data = this.dataSource; + this.frameChart?.updateCanvas(true, this.clientWidth); + this.frameChart?.calculateChartData(); + } + ); + } + + initModeAndAction() { + if (this.procedureAction == '' && this.hasAttribute('action')) { + this.procedureAction = this.getAttribute('action') || ''; + } + if (this.hasAttribute('flame-mode')) { + let mode = this.getAttribute('flame-mode'); + switch (mode) { + case 'Byte': + this.flameChartMode = ChartMode.Byte; + break; + case 'Count': + this.flameChartMode = ChartMode.Count; + break; + case 'Duration': + this.flameChartMode = ChartMode.Duration; + break; + } + } + if (this.hasAttribute('query')) { + this.queryFuncName = this.getAttribute('query') || ''; + } + } + + getParentTree(src: Array, target: MerageBean, parents: Array): boolean { + for (let call of src) { + if (call.id == target.id) { + parents.push(call); + return true; + } else { + if (this.getParentTree(call.children as Array, target, parents)) { + parents.push(call); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, id: string, children: Array): boolean { + for (let call of src) { + if (call.id == id && call.children.length == 0) { + children.push(call); + return true; + } else { + if (this.getChildTree(call.children as Array, id, children)) { + children.push(call); + return true; + } + } + } + return false; + } + + setRightTableData(call: MerageBean) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.dataSource, call, parents); + let maxId = call.id; + let maxDur = 0; + + function findMaxStack(call: MerageBean) { + if (call.children.length == 0) { + if (call.dur > maxDur) { + maxDur = call.dur; + maxId = call.id; + } + } else { + call.children.map((callChild: any) => { + findMaxStack(callChild); + }); + } + } + + findMaxStack(call); + this.getChildTree(call.children as Array, maxId, children); + let arr = parents.reverse().concat(children.reverse()); + for (let data of arr) { + data.type = + data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1; + } + let len = arr.length; + this.rightSource = arr; + this.tbr!.dataSource = len == 0 ? [] : arr; + } + + showButtomMenu(isShow: boolean) { + if (isShow) { + this.filter.setAttribute('tree', ''); + this.filter.setAttribute('input', ''); + this.filter.setAttribute('inputLeftText', ''); + } else { + this.filter.removeAttribute('tree'); + this.filter.removeAttribute('input'); + this.filter.removeAttribute('inputLeftText'); + } + } + + connectedCallback() { + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; + this.frameChart!.addChartClickListener((needShowMenu: boolean) => { + this.parentElement!.scrollTo(0, 0); + this.showButtomMenu(needShowMenu); + this.needShowMenu = needShowMenu; + }); + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + if (this.tbl!.style.visibility == 'hidden') { + tabPaneFilter.style.display = 'none'; + } + if (this.parentElement?.clientHeight != 0) { + if (this.isChartShow) { + this.frameChart?.updateCanvas(false, entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 35 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tbr?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 - 21 + 'px'; + this.tbr?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-calltree'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + + this.tbl!.rememberScrollTop = true; + this.filter = this.shadowRoot?.querySelector('#filter'); + this.tbl!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as MerageBean; + this.setRightTableData(data); + data.isSelected = true; + this.currentSelectedData = data; + this.tbr?.clearAllSelection(data); + this.tbr?.setCurrentSelection(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.tbr = this.shadowRoot?.querySelector('#tb-list'); + this.tbr!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as MerageBean; + this.tbl?.clearAllSelection(data); + (data as any).isSelected = true; + this.tbl!.scrollToData(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + let filterFunc = (data: any) => { + let args: any[] = []; + if (data.type == 'check') { + if (data.item.checked) { + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + } + } else if (data.type == 'select') { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else if (data.type == 'button') { + if (data.item == 'symbol') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined) { + this.filter!.addDataMining({ name: this.currentSelectedData.symbolName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.symbolName, false, true], + }); + } else { + return; + } + } else if (data.item == 'library') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined && this.currentSelectedData.libName != '') { + this.filter!.addDataMining({ name: this.currentSelectedData.libName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.libName, false, false], + }); + } else { + return; + } + } else if (data.item == 'restore') { + if (data.remove != undefined && data.remove.length > 0) { + let list = data.remove.map((item: any) => { + return item.name; + }); + args.push({ + funcName: 'resotreAllNode', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + list.forEach((symbolName: string) => { + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [symbolName], + }); + }); + } + } + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + this.tbl!.move1px(); + if (this.currentSelectedData) { + this.currentSelectedData.isSelected = false; + this.tbl?.clearAllSelection(this.currentSelectedData); + this.tbr!.recycleDataSource = []; + this.currentSelectedData = undefined; + } + }); + }; + this.filter!.getDataLibrary(filterFunc); + this.filter!.getDataMining(filterFunc); + this.filter!.getCallTreeData((data: any) => { + if (data.value == 0) { + this.refreshAllNode({ + ...this.filter!.getFilterTreeData(), + callTree: data.checks, + }); + } else { + let args: any[] = []; + if (data.checks[1]) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[this.systmeRuleName]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [this.systmeRuleName], + }); + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + }); + this.filter!.getCallTreeConstraintsData((data: any) => { + let args: any[] = [ + { + funcName: 'resotreAllNode', + funcArgs: [[this.numRuleName]], + }, + { + funcName: 'clearSplitMapData', + funcArgs: [this.numRuleName], + }, + ]; + if (data.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(data.min), data.max], + }); + } + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + }); + this.filter!.getFilterData((data: FilterData) => { + if (this.searchValue != this.filter!.filterValue) { + this.searchValue = this.filter!.filterValue; + let args = [ + { + funcName: 'setSearchValue', + funcArgs: [this.searchValue], + }, + { + funcName: 'resetAllNode', + funcArgs: [], + }, + ]; + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + this.switchFlameChart(data); + }); + } else { + this.switchFlameChart(data); + } + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.setLTableData(this.dataSource); + this.frameChart!.data = this.dataSource; + }); + } + + switchFlameChart(data: any) { + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); + if (data.icon == 'block') { + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + this.filter!.disabledMining = true; + this.showButtomMenu(this.needShowMenu); + this.frameChart!.data = this.dataSource; + this.frameChart?.calculateChartData(); + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.showButtomMenu(true); + this.isChartShow = false; + this.filter!.disabledMining = false; + this.frameChart!.clearCanvas(); + this.tbl!.reMeauseHeight(); + } + } + + refreshAllNode(filterData: any) { + let args: any[] = []; + let isTopDown: boolean = !filterData.callTree[0]; + let isHideSystemLibrary = filterData.callTree[1]; + let list = filterData.dataMining.concat(filterData.dataLibrary); + args.push({ + funcName: 'getCallChainsBySampleIds', + funcArgs: [isTopDown, this.queryFuncName], + }); + this.tbr!.recycleDataSource = []; + if (isHideSystemLibrary) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + } + if (filterData.callTreeConstraints.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]], + }); + } + args.push({ + funcName: 'splitAllProcess', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + + setLTableData(resultData: any[]) { + this.dataSource = this.sortTree(resultData); + this.tbl!.recycleDataSource = this.dataSource; + } + + sortTree(arr: Array): Array { + let sortArr = arr.sort((a, b) => { + if (this.sortKey == 'self') { + if (this.sortType == 0) { + return b.dur - a.dur; + } else if (this.sortType == 1) { + return a.selfDur - b.selfDur; + } else { + return b.selfDur - a.selfDur; + } + } else { + if (this.sortType == 0) { + return b.dur - a.dur; + } else if (this.sortType == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } + }); + sortArr.map((call) => { + call.children = this.sortTree(call.children); + }); + return sortArr; + } + + getDataByWorker(args: any[], handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName( + 'logic0', + this.procedureAction, + { args, callType: this.queryFuncName }, + undefined, + (results: any) => { + handler(results); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + ); + } + + initHtml(): string { + return ` + +
+ + + +
+ + + + + + + +
+ + + Heaviest Stack Trace + + + + + + +
+ + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemCalltree.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemCalltree.ts new file mode 100644 index 0000000000000000000000000000000000000000..0cb2500f7ea61bdfa20b95ab6c61722821bac166 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemCalltree.ts @@ -0,0 +1,627 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { FrameChart } from '../../../chart/FrameChart.js'; +import '../../../chart/FrameChart.js'; +import { DisassemblingWindow } from '../../../DisassemblingWindow.js'; +import '../../../DisassemblingWindow.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { ChartMode } from '../../../../bean/FrameChartStruct.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import '../TabPaneFilter.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { FileMerageBean } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; + +@element('tabpane-filesystem-calltree') +export class TabpaneFilesystemCalltree extends BaseElement { + private tbl: LitTable | null | undefined; + private tbr: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private rightSource: Array = []; + private filter: any; + private dataSource: any[] = []; + private sortKey = 'weight'; + private sortType = 0; + private currentSelectedData: any = undefined; + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private systmeRuleName = '/system/'; + private numRuleName = '/max/min/'; + private modal: DisassemblingWindow | null | undefined; + private needShowMenu = true; + private searchValue: string = ''; + private loadingList: number[] = []; + private loadingPage: any; + private currentSelection: SelectionParam | undefined; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.searchValue = ''; + this.currentSelection = val; + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + if (this.parentElement!.clientHeight > this.filter!.clientHeight) { + this.filter!.style.display = 'flex'; + } else { + this.filter!.style.display = 'none'; + } + this.filter!.initializeFilterTree(true, true, true); + this.filter!.filterValue = ''; + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [{ queryFuncName: 'fileSystem', ...val }], + }, + ], + (results: any[]) => { + this.setLTableData(results); + this.tbr!.recycleDataSource = []; + this.frameChart!.mode = ChartMode.Duration; + this.frameChart!.data = this.dataSource; + this.frameChart?.updateCanvas(true, this.clientWidth); + this.frameChart?.calculateChartData(); + } + ); + } + + getParentTree(src: Array, target: FileMerageBean, parents: Array): boolean { + for (let call of src) { + if (call.id == target.id) { + parents.push(call); + return true; + } else { + if (this.getParentTree(call.children as Array, target, parents)) { + parents.push(call); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, id: string, children: Array): boolean { + for (let call of src) { + if (call.id == id && call.children.length == 0) { + children.push(call); + return true; + } else { + if (this.getChildTree(call.children as Array, id, children)) { + children.push(call); + return true; + } + } + } + return false; + } + + setRightTableData(call: FileMerageBean) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.dataSource, call, parents); + let maxId = call.id; + let maxDur = 0; + + function findMaxStack(call: FileMerageBean) { + if (call.children.length == 0) { + if (call.dur > maxDur) { + maxDur = call.dur; + maxId = call.id; + } + } else { + call.children.map((callChild: any) => { + findMaxStack(callChild); + }); + } + } + + findMaxStack(call); + this.getChildTree(call.children as Array, maxId, children); + let arr = parents.reverse().concat(children.reverse()); + for (let data of arr) { + data.type = + data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1; + } + let len = arr.length; + this.rightSource = arr; + this.tbr!.dataSource = len == 0 ? [] : arr; + } + + showButtomMenu(isShow: boolean) { + if (isShow) { + this.filter.setAttribute('tree', ''); + this.filter.setAttribute('input', ''); + this.filter.setAttribute('inputLeftText', ''); + } else { + this.filter.removeAttribute('tree'); + this.filter.removeAttribute('input'); + this.filter.removeAttribute('inputLeftText'); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-filesystem-calltree'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + this.modal = this.shadowRoot?.querySelector('tab-native-data-modal'); + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.frameChart!.addChartClickListener((needShowMenu: boolean) => { + this.parentElement!.scrollTo(0, 0); + this.showButtomMenu(needShowMenu); + this.needShowMenu = needShowMenu; + }); + this.tbl!.rememberScrollTop = true; + this.filter = this.shadowRoot?.querySelector('#filter'); + this.tbl!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as FileMerageBean; + this.setRightTableData(data); + data.isSelected = true; + this.currentSelectedData = data; + this.tbr?.clearAllSelection(data); + this.tbr?.setCurrentSelection(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.tbr = this.shadowRoot?.querySelector('#tb-filesystem-list'); + this.tbr!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as FileMerageBean; + this.tbl?.clearAllSelection(data); + (data as any).isSelected = true; + this.tbl!.scrollToData(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.modal!.setCloseListener(() => { + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + this.shadowRoot!.querySelector('#filter')!.style.display = 'flex'; + }); + let filterFunc = (data: any) => { + let args: any[] = []; + if (data.type == 'check') { + if (data.item.checked) { + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + } + } else if (data.type == 'select') { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else if (data.type == 'button') { + if (data.item == 'symbol') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined) { + this.filter!.addDataMining({ name: this.currentSelectedData.symbolName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.symbolName, false, true], + }); + } else { + return; + } + } else if (data.item == 'library') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined && this.currentSelectedData.libName != '') { + this.filter!.addDataMining({ name: this.currentSelectedData.libName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.libName, false, false], + }); + } else { + return; + } + } else if (data.item == 'restore') { + if (data.remove != undefined && data.remove.length > 0) { + let list = data.remove.map((item: any) => { + return item.name; + }); + args.push({ + funcName: 'resotreAllNode', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + list.forEach((symbolName: string) => { + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [symbolName], + }); + }); + } + } + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + this.tbl!.move1px(); + if (this.currentSelectedData) { + this.currentSelectedData.isSelected = false; + this.tbl?.clearAllSelection(this.currentSelectedData); + this.tbr!.recycleDataSource = []; + this.currentSelectedData = undefined; + } + }); + }; + this.filter!.getDataLibrary(filterFunc); + this.filter!.getDataMining(filterFunc); + this.filter!.getCallTreeData((data: any) => { + if (data.value == 0) { + this.refreshAllNode({ + ...this.filter!.getFilterTreeData(), + callTree: data.checks, + }); + } else { + let args: any[] = []; + if (data.checks[1]) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[this.systmeRuleName]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [this.systmeRuleName], + }); + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + }); + this.filter!.getCallTreeConstraintsData((data: any) => { + let args: any[] = [ + { + funcName: 'resotreAllNode', + funcArgs: [[this.numRuleName]], + }, + { + funcName: 'clearSplitMapData', + funcArgs: [this.numRuleName], + }, + ]; + if (data.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(data.min), data.max], + }); + } + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + }); + this.filter!.getFilterData((data: FilterData) => { + if (this.searchValue != this.filter!.filterValue) { + this.searchValue = this.filter!.filterValue; + let args = [ + { + funcName: 'setSearchValue', + funcArgs: [this.searchValue], + }, + { + funcName: 'resetAllNode', + funcArgs: [], + }, + ]; + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + this.switchFlameChart(data); + }); + } else { + this.switchFlameChart(data); + } + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.setLTableData(this.dataSource); + this.frameChart!.data = this.dataSource; + }); + } + + connectedCallback() { + super.connectedCallback(); + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + this.modal!.style.height = this.tbl!.clientHeight - 2 + 'px'; //2 is borderWidth + if (this.tbl!.style.visibility == 'hidden') { + tabPaneFilter.style.display = 'none'; + } + if (this.parentElement?.clientHeight != 0) { + if (this.isChartShow) { + this.frameChart?.updateCanvas(false, entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 35 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tbr?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 - 21 + 'px'; + this.tbr?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; + } + + switchFlameChart(data: any) { + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); + if (data.icon == 'block') { + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + this.filter!.disabledMining = true; + this.showButtomMenu(this.needShowMenu); + this.frameChart!.data = this.dataSource; + this.frameChart?.calculateChartData(); + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.showButtomMenu(true); + this.isChartShow = false; + this.filter!.disabledMining = false; + this.frameChart!.clearCanvas(); + this.tbl!.reMeauseHeight(); + } + } + + refreshAllNode(filterData: any) { + let args: any[] = []; + let isTopDown: boolean = !filterData.callTree[0]; + let isHideSystemLibrary = filterData.callTree[1]; + let list = filterData.dataMining.concat(filterData.dataLibrary); + args.push({ + funcName: 'getCallChainsBySampleIds', + funcArgs: [isTopDown, 'fileSystem'], + }); + this.tbr!.recycleDataSource = []; + if (isHideSystemLibrary) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + } + if (filterData.callTreeConstraints.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]], + }); + } + args.push({ + funcName: 'splitAllProcess', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + + setLTableData(resultData: any[]) { + this.dataSource = this.sortTree(resultData); + this.tbl!.recycleDataSource = this.dataSource; + } + + sortTree(arr: Array): Array { + let sortArr = arr.sort((a, b) => { + if (this.sortKey == 'self') { + if (this.sortType == 0) { + return b.dur - a.dur; + } else if (this.sortType == 1) { + return a.selfDur - b.selfDur; + } else { + return b.selfDur - a.selfDur; + } + } else { + if (this.sortType == 0) { + return b.dur - a.dur; + } else if (this.sortType == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } + }); + sortArr.map((call) => { + call.children = this.sortTree(call.children); + }); + return sortArr; + } + + getDataByWorker(args: any[], handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-action', + { args, callType: 'fileSystem' }, + undefined, + (results: any) => { + handler(results); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + ); + } + + initHtml(): string { + return ` + +
+ + + +
+ + + + + + + + +
+ + + Heaviest Stack Trace + + + + + + +
+ + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.ts new file mode 100644 index 0000000000000000000000000000000000000000..de139112a8261ea458ed4d106f96908638b44892 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.ts @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { FileSysEvent } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-filesystem-desc-history') +export class TabPaneFileSystemDescHistory extends BaseElement { + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private filter: TabPaneFilter | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private source: Array = []; + private filterSource: Array = []; + private sortKey: string = 'startTs'; + private sortType: number = 0; + private filterEventType: string = '0'; + private filterProcess: string = '0'; + private filterPath: string = '0'; + private currentSelection: SelectionParam | undefined | null; + private eventList: string[] | null | undefined; + private processList: string[] | null | undefined; + private pathList: string[] | null | undefined; + + set data(val: SelectionParam | null | undefined) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + this.tbl!.recycleDataSource = []; + this.tblData!.recycleDataSource = []; + if (val) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.source = []; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryFileSysEvents', + { + leftNs: val.leftNs, + rightNs: val.rightNs, + typeArr: [0, 1], + tab: 'history', + }, + undefined, + (res: any) => { + this.source = this.source.concat(res.data); + res.data = null; + if (!res.isSending) { + this.tbl!.recycleDataSource = this.source; + this.filterSource = this.source; + this.setProcessFilter(); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + } + ); + } + } + + setProcessFilter() { + this.processList = ['All Process']; + this.pathList = ['All Path']; + this.source.map((it) => { + if (this.processList!.findIndex((a) => a === it.process) == -1) { + this.processList!.push(it.process); + } + if (this.pathList!.findIndex((a) => a === it.path) == -1) { + this.pathList!.push(it.path); + } + }); + this.filter!.setSelectList(this.eventList, this.processList, '', '', this.pathList, ''); + this.filter!.firstSelect = '0'; + this.filter!.secondSelect = '0'; + this.filter!.thirdSelect = '0'; + this.filterProcess = '0'; + this.filterPath = '0'; + this.filterEventType = '0'; + } + + filterData() { + let pfv = parseInt(this.filterProcess); + let pathIndex = parseInt(this.filterPath); + this.filterSource = this.source.filter((it) => { + let pathFilter = true; + let eventFilter = true; + let processFilter = true; + if (this.filterPath != '0') { + pathFilter = it.path == this.pathList![pathIndex]; + } + if (this.filterEventType == '1') { + eventFilter = it.type == 0; + } else if (this.filterEventType == '2') { + eventFilter = it.type == 1; + } + if (this.filterProcess != '0') { + processFilter = it.process == this.processList![pfv]; + } + return pathFilter && eventFilter && processFilter; + }); + this.tblData!.recycleDataSource = []; + this.sortTable(this.sortKey, this.sortType); + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tbl'); + this.tblData = this.shadowRoot?.querySelector('#tbr'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as FileSysEvent; + (data as any).isSelected = true; + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryStack', + { callchainId: data.callchainId }, + undefined, + (res: any) => { + this.tblData!.recycleDataSource = res; + } + ); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + this.filter = this.shadowRoot?.querySelector('#filter'); + this.eventList = ['All FD Event', 'All Open Event', 'All Close Event']; + this.processList = ['All Process']; + this.pathList = ['All Path']; + this.filter!.setSelectList(this.eventList, this.processList, '', '', this.pathList, ''); + this.filter!.firstSelect = '0'; + this.filter!.getFilterData((data: FilterData) => { + this.filterEventType = data.firstSelect || '0'; + this.filterProcess = data.secondSelect || '0'; + this.filterPath = data.thirdSelect || '0'; + this.filterData(); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.filterSource; + } else { + let arr = Array.from(this.filterSource); + arr.sort((a, b): number => { + if (key == 'startTsStr') { + if (type == 1) { + return a.startTs - b.startTs; + } else { + return b.startTs - a.startTs; + } + } else if (key == 'durStr') { + if (type == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } else if (key == 'process') { + if (a.process > b.process) { + return type === 2 ? 1 : -1; + } else if (a.process == b.process) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'typeStr') { + if (a.typeStr > b.typeStr) { + return type === 2 ? 1 : -1; + } else if (a.typeStr == b.typeStr) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'fd') { + if (type == 1) { + return a.fd - b.fd; + } else { + return b.fd - a.fd; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.ts new file mode 100644 index 0000000000000000000000000000000000000000..84aa6601d71a5cb37de174396a37bdb2d44b5ce9 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.ts @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { FileSysEvent } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-filesystem-desc-time-slice') +export class TabPaneFileSystemDescTimeSlice extends BaseElement { + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private source: Array = []; + private sortKey: string = 'startTs'; + private sortType: number = 0; + private currentSelection: SelectionParam | undefined | null; + + set data(val: SelectionParam | null | undefined) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + this.tbl!.recycleDataSource = []; + this.tblData!.recycleDataSource = []; + if (val) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + let startNs = (window as any).recordStartNS ?? 0; + this.source = []; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryFileSysEvents', + { + leftNs: startNs + val.leftNs, + rightNs: startNs + val.rightNs, + typeArr: [0], + tab: 'time-slice', + }, + undefined, + (res: any) => { + this.source = this.source.concat(res.data); + res.data = null; + if (!res.isSending) { + this.tbl!.recycleDataSource = this.source; + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + } + ); + } + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tbl'); + this.tblData = this.shadowRoot?.querySelector('#tbr'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as FileSysEvent; + (data as any).isSelected = true; + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryStack', + { callchainId: data.callchainId }, + undefined, + (res: any) => { + this.tblData!.recycleDataSource = res; + } + ); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'startTsStr') { + if (type == 1) { + return a.startTs - b.startTs; + } else { + return b.startTs - a.startTs; + } + } else if (key == 'durStr') { + if (type == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } else if (key == 'process') { + if (a.process > b.process) { + return type === 2 ? 1 : -1; + } else if (a.process == b.process) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'fd') { + if (type == 1) { + return a.fd - b.fd; + } else { + return b.fd - a.fd; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.ts new file mode 100644 index 0000000000000000000000000000000000000000..7dde9be75078f5cb1321cb7fd9738797d58e130f --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.ts @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { FileSysEvent } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import '../TabPaneFilter.js'; + +@element('tabpane-filesystem-event') +export class TabPaneFileSystemEvents extends BaseElement { + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private filter: TabPaneFilter | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private source: Array = []; + private filterSource: Array = []; + private sortKey: string = 'startTs'; + private sortType: number = 0; + private currentSelection: SelectionParam | undefined | null; + private filterEventType: string = '0'; + private filterProcess: string = '0'; + private filterPath: string = '0'; + private eventList: string[] | null | undefined; + private processList: string[] | null | undefined; + private pathList: string[] | null | undefined; + + set data(val: SelectionParam | null | undefined) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + this.filterEventType = '0'; + this.filterProcess = '0'; + this.queryData(val); + } + + queryData(val: SelectionParam | null | undefined) { + this.tbl!.recycleDataSource = []; + this.tblData!.recycleDataSource = []; + if (val) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.source = []; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryFileSysEvents', + { + leftNs: val.leftNs, + rightNs: val.rightNs, + typeArr: val.fileSystemType, + tab: 'events', + }, + undefined, + (res: any) => { + this.source = this.source.concat(res.data); + res.data = null; + if (!res.isSending) { + this.setProcessFilter(); + this.filterData(); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + } + ); + } + } + + setProcessFilter() { + this.processList = ['All Process']; + this.pathList = ['All Path']; + this.source.map((it) => { + if (this.processList!.findIndex((a) => a === it.process) == -1) { + this.processList!.push(it.process); + } + if (this.pathList!.findIndex((a) => a === it.path) == -1) { + this.pathList!.push(it.path); + } + }); + this.filter!.setSelectList(this.eventList, this.processList, '', '', this.pathList, ''); + if (this.filterProcess == '-1') { + this.filterProcess = + this.processList.indexOf( + `${this.currentSelection?.fileSystemFsData.name}[${this.currentSelection?.fileSystemFsData.pid}]` + ) + ''; + } + this.filter!.firstSelect = this.filterEventType; + this.filter!.secondSelect = this.filterProcess; + this.filter!.thirdSelect = this.filterPath; + } + + filterData() { + let pfv = parseInt(this.filterProcess); + let pathIndex = parseInt(this.filterPath); + let eventType = parseInt(this.filterEventType) - 1; + this.filterSource = this.source.filter((it) => { + let pathFilter = true; + let eventFilter = it.type == eventType || eventType == -1; + let processFilter = true; + if (this.filterPath != '0') { + pathFilter = it.path == this.pathList![pathIndex]; + } + if (this.filterProcess != '0') { + processFilter = it.process == this.processList![pfv]; + } + return pathFilter && eventFilter && processFilter; + }); + this.tblData!.recycleDataSource = []; + this.sortTable(this.sortKey, this.sortType); + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tbl'); + this.tblData = this.shadowRoot?.querySelector('#tbr'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as FileSysEvent; + (data as any).isSelected = true; + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryStack', + { callchainId: data.callchainId }, + undefined, + (res: any) => { + this.tblData!.recycleDataSource = res; + } + ); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + this.filter = this.shadowRoot?.querySelector('#filter'); + this.eventList = ['All Event', 'All Open Event', 'All Close Event', 'All Read Event', 'All Write Event']; + this.processList = ['All Process']; + this.pathList = ['All Path']; + this.filter!.setSelectList(this.eventList, this.processList, '', '', this.pathList, ''); + this.filter!.firstSelect = '0'; + this.filter!.getFilterData((data: FilterData) => { + this.filterEventType = data.firstSelect || '0'; + this.filterProcess = data.secondSelect || '0'; + this.filterPath = data.thirdSelect || '0'; + this.filterData(); + }); + } + + fromStastics(val: SelectionParam | any) { + if (val.fileSystemFsData == undefined) { + return; + } + if (val.fileSystemFsData.title == 'All') { + this.filterEventType = '0'; + this.filterProcess = '0'; + } else if (val.fileSystemFsData.pid == undefined) { + this.filterEventType = '' + (val.fileSystemFsData.type + 1); + this.filterProcess = '0'; + } else { + this.filterEventType = '' + (val.fileSystemFsData.type + 1); + this.filterProcess = '-1'; + } + this.filterPath = '0'; + if (this.currentSelection == val) { + if (this.filterProcess == '-1') { + this.filterProcess = + this.processList?.indexOf(`${val.fileSystemFsData.name}[${val.fileSystemFsData.pid}]`) + ''; + } + this.filter!.firstSelect = this.filterEventType; + this.filter!.secondSelect = this.filterProcess; + this.filter!.thirdSelect = this.filterPath; + this.filterData(); + } else { + this.currentSelection = val; + this.queryData(val); + } + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 33 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 33 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.filterSource; + } else { + let arr = Array.from(this.filterSource); + arr.sort((a, b): number => { + if (key == 'startTsStr') { + if (type == 1) { + return a.startTs - b.startTs; + } else { + return b.startTs - a.startTs; + } + } else if (key == 'durStr') { + if (type == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } else if (key == 'process') { + if (a.process > b.process) { + return type === 2 ? 1 : -1; + } else if (a.process == b.process) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'thread') { + if (a.thread > b.thread) { + return type === 2 ? 1 : -1; + } else if (a.thread == b.thread) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'typeStr') { + if (a.typeStr > b.typeStr) { + return type === 2 ? 1 : -1; + } else if (a.typeStr == b.typeStr) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'fd') { + if (type == 1) { + return (a.fd || 0) - (b.fd || 0); + } else { + return (b.fd || 0) - (a.fd || 0); + } + } else if (key == 'path') { + if (a.path > b.path) { + return type === 2 ? 1 : -1; + } else if (a.path == b.path) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc4b6db0e98e520de4298dda50acfcd077205b2f --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.ts @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPaneFilesystemStatistics } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; + +@element('tabpane-file-statistics') +export class TabPaneFileStatistics extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingPage: any; + private loadingList: number[] = []; + private source: Array = []; + private typeList: Array = ['OPEN', 'CLOSE', 'READ', 'WRITE']; + private sortKey: string = ''; + private sortType: number = 0; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.selectionParam = val; + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.progressEL = this.shadowRoot!.querySelector('.progress'); + this.loadingPage = this.shadowRoot!.querySelector('.loading'); + this.tbl = this.shadowRoot!.querySelector('#tb-states'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + + let newSource = JSON.parse(JSON.stringify(this.source)); + if (this.sortType != 0 && newSource.length > 0) this.sortTable(newSource[0], this.sortKey); + this.tbl!.recycleDataSource = newSource; + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement!.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.tbl!.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + getInitData(item: any) { + return { + ...item, + title: item.name + '(' + item.pid + ')', + logicalWrites: Utils.getBinaryByteWithUnit(item.logicalWrites), + logicalReads: Utils.getBinaryByteWithUnit(item.logicalReads), + otherFile: Utils.getBinaryByteWithUnit(item.otherFile), + allDuration: Utils.getProbablyTime(item.allDuration), + minDuration: Utils.getProbablyTime(item.minDuration), + maxDuration: Utils.getProbablyTime(item.maxDuration), + avgDuration: Utils.getProbablyTime(item.avgDuration), + node: { ...item, children: [] }, + }; + } + + queryDataByDB(val: SelectionParam | any) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + getTabPaneFilesystemStatistics( + val.leftNs + val.recordStartNs, + val.rightNs + val.recordStartNs, + val.fileSystemType + ).then((result) => { + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + let fatherMap = new Map(); + let allNode: any = { + title: 'All', + count: 0, + logicalReads: 0, + logicalWrites: 0, + otherFile: 0, + allDuration: 0, + minDuration: 0, + maxDuration: 0, + avgDuration: '', + children: [], + }; + result.forEach((item, idx) => { + if (fatherMap.has(item.type)) { + let obj1 = fatherMap.get(item.type); + obj1.count += item.count; + obj1.logicalReads += item.logicalReads; + obj1.logicalWrites += item.logicalWrites; + obj1.otherFile += item.otherFile; + obj1.allDuration += item.allDuration; + obj1.minDuration = obj1.minDuration <= item.minDuration ? obj1.minDuration : item.minDuration; + obj1.maxDuration = obj1.maxDuration >= item.maxDuration ? obj1.maxDuration : item.maxDuration; + obj1.children.push(this.getInitData(item)); + } else { + fatherMap.set(item.type, { + type: item.type, + count: item.count, + logicalReads: item.logicalReads, + logicalWrites: item.logicalWrites, + otherFile: item.otherFile, + allDuration: item.allDuration, + minDuration: item.minDuration, + maxDuration: item.maxDuration, + children: [this.getInitData(item)], + }); + } + if (idx == 0) { + allNode.minDuration = item.minDuration; + } else { + allNode.minDuration = allNode.minDuration <= item.minDuration ? allNode.minDuration : item.minDuration; + } + allNode.count += item.count; + allNode.logicalReads += item.logicalReads; + allNode.logicalWrites += item.logicalWrites; + allNode.otherFile += item.otherFile; + allNode.allDuration += item.allDuration; + allNode.maxDuration = allNode.maxDuration >= item.maxDuration ? allNode.maxDuration : item.maxDuration; + }); + fatherMap.forEach((item) => { + item.avgDuration = item.allDuration / item.count; + let node = this.getInitData(item); + if (item.type < 4) { + node.title = this.typeList[item.type]; + } else { + node.title = item.type; + } + allNode.children.push(node); + }); + allNode.avgDuration = allNode.allDuration / allNode.count; + allNode = this.getInitData(allNode); + allNode.title = 'All'; + this.source = result.length > 0 ? [allNode] : []; + let newSource = JSON.parse(JSON.stringify(this.source)); + if (this.sortType != 0 && result.length > 0) this.sortTable(newSource[0], this.sortKey); + this.tbl!.recycleDataSource = newSource; + }); + } + + sortTable(allNode: any, key: string) { + allNode.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + allNode.children.forEach((item: any) => { + item.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..5539c308b6f3593ff4b83aeb90a64d9726482555 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.ts @@ -0,0 +1,982 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../../../base-ui/chart/pie/LitChartPie.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; +import { Utils } from '../../base/Utils.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-file-statistics-analysis') +export class TabPaneFilesystemStatisticsAnalysis extends BaseElement { + private pie: LitChartPie | null | undefined; + private currentSelection: SelectionParam | any; + private processData: any; + private threadData!: any[]; + private soData!: any[]; + private pidData!: any[]; + private typeData!: any[]; + private functionData!: any[]; + private tableProcess: LitTable | null | undefined; + private tableType: LitTable | null | undefined; + private tableThread: LitTable | null | undefined; + private tableSo: LitTable | null | undefined; + private tableFunction: LitTable | null | undefined; + private sumDur: any; + private range: HTMLLabelElement | null | undefined; + private back: HTMLDivElement | null | undefined; + private tabName: HTMLDivElement | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private processName: string = ''; + private threadName: string = ''; + private sortColumn: string = ''; + private sortType: number = 0; + private typeName: any; + private currentLevel = -1; + private currentLevelData!: Array; + private processStatisticsData!: any; + private typeStatisticsData!: any; + private threadStatisticsData!: any; + private libStatisticsData!: any; + private functionStatisticsData!: any; + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + this.pidData.unshift(this.processStatisticsData); + this.tableProcess!.recycleDataSource = this.pidData; + // @ts-ignore + this.pidData.shift(this.processStatisticsData); + return; + } + this.clearData(); + this.currentSelection = val; + this.tableProcess!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'none'; + this.tableType!.style.display = 'none'; + this.tableFunction!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + this.progressEL!.loading = true; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [{ queryFuncName: 'fileSystem', ...val }], + }, + ], + (results: any[]) => { + this.getFilesystemProcess(val, results); + } + ); + } + initElements(): void { + this.range = this.shadowRoot?.querySelector('#time-range'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.tableProcess = this.shadowRoot!.querySelector('#tb-process-usage'); + this.tableThread = this.shadowRoot!.querySelector('#tb-thread-usage'); + this.tableSo = this.shadowRoot!.querySelector('#tb-so-usage'); + this.tableFunction = this.shadowRoot!.querySelector('#tb-function-usage'); + this.back = this.shadowRoot!.querySelector('.go-back'); + this.tabName = this.shadowRoot!.querySelector('.subheading'); + this.tableType = this.shadowRoot!.querySelector('#tb-type-usage'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.goBack(); + } + clearData() { + this.pie!.dataSource = []; + this.tableProcess!.recycleDataSource = []; + this.tableThread!.recycleDataSource = []; + this.tableType!.recycleDataSource = []; + this.tableSo!.recycleDataSource = []; + this.tableFunction!.recycleDataSource = []; + } + goBack() { + this.back!.addEventListener('click', () => { + if (this.tabName!.textContent === 'Statistic By type AllDuration') { + this.tableProcess!.style.display = 'grid'; + this.tableType!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableProcess?.removeAttribute('hideDownload'); + this.currentLevel = 0; + this.processPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Thread AllDuration') { + this.tableType!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.currentLevel = 1; + this.typePieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Library AllDuration') { + this.tableThread!.style.display = 'grid'; + this.tableSo!.style.display = 'none'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.currentLevel = 2; + this.threadPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Function AllDuration') { + this.tableSo!.style.display = 'grid'; + this.tableFunction!.style.display = 'none'; + this.tableFunction!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.currentLevel = 3; + this.libraryPieChart(this.currentSelection); + } + }); + } + processPieChart(val: any) { + this.sumDur = this.processStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.pidData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ProcessName:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableProcess!.style.display = 'none'; + this.tableType!.style.display = 'grid'; + this.tableProcess!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.getFilesystemType(it, val); + // @ts-ignore + this.processName = it.tableName; + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableProcess!.setCurrentHover(data); + } else { + this.tableProcess!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableProcess!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = ''; + this.tabName!.textContent = 'Statistic By Process AllDuration'; + this.pidData.unshift(this.processStatisticsData); + this.tableProcess!.recycleDataSource = this.pidData; + this.currentLevelData = JSON.parse(JSON.stringify(this.pidData)); + // @ts-ignore + this.pidData.shift(this.processStatisticsData); + this.tableProcess?.reMeauseHeight(); + this.tableProcess!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + typePieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.typeData, + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Type:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + this.clearData(); + this.tableType!.style.display = 'none'; + this.tableThread!.style.display = 'grid'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.getFilesystemThread(it, val); + // @ts-ignore + this.typeName = it.tableName; + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName; + this.pie?.hideTip(); + }, + hoverHandler: (data) => { + if (data) { + this.tableType!.setCurrentHover(data); + } else { + this.tableType!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableType!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + this.tabName!.textContent = 'Statistic By type AllDuration'; + this.typeData.unshift(this.typeStatisticsData); + this.tableType!.recycleDataSource = this.typeData; + this.currentLevelData = JSON.parse(JSON.stringify(this.typeData)); + // @ts-ignore + this.typeData.shift(this.typeStatisticsData); + this.tableType?.reMeauseHeight(); + this.tableType!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + threadPieChart(val: any) { + this.sumDur = this.threadStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.threadData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ThreadName:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'grid'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.getFilesystemSo(it, val); + // @ts-ignore + this.threadName = it.tableName; + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName + ' / ' + this.threadName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableThread!.setCurrentHover(data); + } else { + this.tableThread!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableThread!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName + ' / ' + this.typeName; + this.tabName!.textContent = 'Statistic By Thread AllDuration'; + this.threadData.unshift(this.threadStatisticsData); + this.tableThread!.recycleDataSource = this.threadData; + this.currentLevelData = JSON.parse(JSON.stringify(this.threadData)); + // @ts-ignore + this.threadData.shift(this.threadStatisticsData); + this.tableThread?.reMeauseHeight(); + this.tableThread!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + libraryPieChart(val: any) { + this.sumDur = this.libStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.soData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Library:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'grid'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableFunction?.removeAttribute('hideDownload'); + this.getFilesystemFunction(it, val); + this.shadowRoot!.querySelector('.title')!.textContent = + // @ts-ignore + this.processName + ' / ' + this.typeName + ' / ' + this.threadName + ' / ' + it.tableName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableSo!.setCurrentHover(data); + } else { + this.tableSo!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableSo!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName + ' / ' + this.threadName; + this.tabName!.textContent = 'Statistic By Library AllDuration'; + this.soData.unshift(this.libStatisticsData); + this.tableSo!.recycleDataSource = this.soData; + this.currentLevelData = JSON.parse(JSON.stringify(this.soData)); + // @ts-ignore + this.soData.shift(this.libStatisticsData); + this.tableSo?.reMeauseHeight(); + this.tableSo!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + let currentTable: LitTable | null | undefined; + switch (this.currentLevel) { + case 0: + currentTable = this.tableProcess; + break; + case 1: + currentTable = this.tableType; + break; + case 2: + currentTable = this.tableThread; + break; + case 3: + currentTable = this.tableSo; + break; + case 4: + currentTable = this.tableFunction; + break; + } + if (!currentTable) { + return; + } + if (sort == 0) { + currentTable!.recycleDataSource = this.currentLevelData; + } else { + let arr = [...this.currentLevelData]; + switch (this.currentLevel) { + case 0: + // @ts-ignore + arr.shift(this.processStatisticsData); + break; + case 1: + // @ts-ignore + arr.shift(this.typeStatisticsData); + break; + case 2: + // @ts-ignore + arr.shift(this.threadStatisticsData); + break; + case 3: + // @ts-ignore + arr.shift(this.libStatisticsData); + break; + case 4: + // @ts-ignore + arr.shift(this.functionStatisticsData); + break; + } + if (column == 'tableName') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.tableName > b.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } else { + if (b.tableName > a.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'durFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.duration - b.duration : b.duration - a.duration; + }); + } else if (column == 'percent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.duration - b.duration : b.duration - a.v; + }); + } + switch (this.currentLevel) { + case 0: + arr.unshift(this.processStatisticsData); + break; + case 1: + arr.unshift(this.typeStatisticsData); + break; + case 2: + arr.unshift(this.threadStatisticsData); + break; + case 3: + arr.unshift(this.libStatisticsData); + break; + case 4: + arr.unshift(this.functionStatisticsData); + break; + } + currentTable!.recycleDataSource = arr; + } + } + getFilesystemProcess(val: any, result: Array) { + this.processData = JSON.parse(JSON.stringify(result)); + if (!this.processData || this.processData.length == 0) { + return; + } + let allDur = 0; + let pidMap = new Map>(); + for (let itemData of result) { + allDur += itemData.dur; + if (pidMap.has(itemData.pid)) { + pidMap.get(itemData.pid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + pidMap.set(itemData.pid, itemArray); + } + } + this.pidData = []; + pidMap.forEach((value: Array, key: string) => { + let dur = 0; + let pName = ''; + for (let item of value) { + pName = item.processName = + item.processName == null || item.processName == undefined + ? `Process(${item.pid})` + : `${item.processName}(${item.pid})`; + dur += item.dur; + } + const pidData = { + tableName: pName, + pid: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.pidData.push(pidData); + }); + this.pidData.sort((a, b) => b.duration - a.duration); + this.processStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 0; + this.progressEL!.loading = false; + this.processPieChart(val); + } + + getFilesystemType(item: any, val: any) { + this.progressEL!.loading = true; + let typeMap = new Map>(); + let pid = item.pid; + let allDur = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid) { + continue; + } + allDur += itemData.dur; + if (typeMap.has(itemData.type)) { + typeMap.get(itemData.type)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(itemData.type, itemArray); + } + } + this.typeData = []; + typeMap.forEach((value: Array, key: string) => { + let dur = 0; + for (let item of value) { + dur += item.dur; + } + const typeData = { + tableName: this.typeIdToString(key), + pid: item.pid, + type: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.typeData.push(typeData); + }); + this.typeData.sort((a, b) => b.duration - a.duration); + this.typeStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 1; + this.typePieChart(val); + this.progressEL!.loading = false; + } + + getFilesystemThread(item: any, val: any) { + this.progressEL!.loading = true; + let threadMap = new Map>(); + let pid = item.pid; + let type = item.type; + let allDur = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.type !== type) { + continue; + } + allDur += itemData.dur; + if (threadMap.has(itemData.tid)) { + threadMap.get(itemData.tid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + threadMap.set(itemData.tid, itemArray); + } + } + this.threadData = []; + threadMap.forEach((value: Array, key: string) => { + let dur = 0; + let tName = ''; + for (let item of value) { + dur += item.dur; + tName = item.threadName = + item.threadName == null || item.threadName == undefined ? `Thread(${item.tid})` : `${item.threadName}`; + } + const threadData = { + tableName: tName, + pid: item.pid, + type: item.type, + tid: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.threadData.push(threadData); + }); + this.threadData.sort((a, b) => b.duration - a.duration); + this.threadStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 2; + this.progressEL!.loading = false; + this.threadPieChart(val); + } + + getFilesystemSo(item: any, val: any) { + this.progressEL!.loading = true; + let tid = item.tid; + let pid = item.pid; + let type = item.type; + let allDur = 0; + let libMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid || itemData.type !== type) { + continue; + } + allDur += itemData.dur; + if (libMap.has(itemData.libId)) { + libMap.get(itemData.libId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + libMap.set(itemData.libId, dataArray); + } + } + this.soData = []; + libMap.forEach((value: any[], key: number) => { + let dur = 0; + let libName = ''; + for (let item of value) { + dur += item.dur; + if (key == null) { + item.libName = 'unkown'; + } + libName = item.libName; + } + let libPath = libName?.split('/'); + if (libPath) { + libName = libPath[libPath.length - 1]; + } + const soData = { + tableName: libName, + pid: item.pid, + type: item.type, + tid: item.tid, + libId: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.soData.push(soData); + }); + this.soData.sort((a, b) => b.duration - a.duration); + this.libStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 3; + this.progressEL!.loading = false; + this.libraryPieChart(val); + } + + getFilesystemFunction(item: any, val: any) { + this.progressEL!.loading = true; + this.shadowRoot!.querySelector('.subheading')!.textContent = 'Statistic By Function AllDuration'; + let tid = item.tid; + let pid = item.pid; + let type = item.type; + let libId = item.libId; + let allDur = 0; + let symbolMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid || itemData.type !== type || itemData.libId !== libId) { + continue; + } + allDur += itemData.dur; + if (symbolMap.has(itemData.symbolId)) { + symbolMap.get(itemData.symbolId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + symbolMap.set(itemData.symbolId, dataArray); + } + } + this.functionData = []; + symbolMap.forEach((symbolItems, key) => { + let dur = 0; + let symbolName = ''; + for (let symbolItem of symbolItems) { + symbolName = symbolItem.symbolName; + dur += symbolItem.dur; + } + let symbolPath = symbolName?.split('/'); + if (symbolPath) { + symbolName = symbolPath[symbolPath.length - 1]; + } + const symbolData = { + pid: item.pid, + tid: item.tid, + percent: ((dur / allDur) * 100).toFixed(2), + tableName: symbolName, + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.functionData.push(symbolData); + }); + this.functionData.sort((a, b) => b.duration - a.duration); + this.functionStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 4; + this.progressEL!.loading = false; + this.sumDur = this.functionStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.functionData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Function:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
percent:${obj.obj.percent}
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.tableFunction!.setCurrentHover(data); + } else { + this.tableFunction!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableFunction!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.functionData.unshift(this.functionStatisticsData); + this.tableFunction!.recycleDataSource = this.functionData; + this.tableFunction?.reMeauseHeight(); + this.currentLevelData = JSON.parse(JSON.stringify(this.functionData)); + // @ts-ignore + this.functionData.shift(this.functionStatisticsData); + this.tableFunction!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + typeIdToString(type: any) { + let releaseType: any; + if (type === 0) { + releaseType = 'OPEN'; + } else if (type === 2) { + releaseType = 'READ'; + } else if (type === 3) { + releaseType = 'WRITE'; + } else if (type === 1) { + releaseType = 'CLOSE'; + } + return releaseType; + } + totalDurationData(duration: any) { + let allDuration; + allDuration = { + durFormat: Utils.getProbablyTime(duration), + percent: ((duration / duration) * 100).toFixed(2), + tableName: '', + duration: 0, + }; + return allDuration; + } + getPieChartData(res: any[]) { + if (res.length > 20) { + let pieChartArr: any[] = []; + let other: any = { + tableName: 'other', + duration: 0, + percent: 0, + durFormat: 0, + }; + for (let i = 0; i < res.length; i++) { + if (i < 19) { + pieChartArr.push(res[i]); + } else { + other.duration += res[i].duration; + other.durFormat = Utils.getProbablyTime(other.duration); + other.percent = ((other.duration / this.sumDur) * 100).toFixed(2); + } + } + pieChartArr.push(other); + return pieChartArr; + } + return res; + } + + getDataByWorker(args: any[], handler: Function) { + procedurePool.submitWithName( + 'logic0', + 'fileSystem-action', + { args, callType: 'fileSystem', isAnalysis: true }, + undefined, + (results: any) => { + handler(results); + this.progressEL!.loading = false; + } + ); + } + + initHtml(): string { + return ` + + +
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + +
+ +
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneIOCallTree.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneIOCallTree.ts new file mode 100644 index 0000000000000000000000000000000000000000..9cf8310707f26be85ff07eedcea4d62c855af538 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneIOCallTree.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import './TabPaneCallTree.js'; +import { TabPaneCallTree } from './TabPaneCallTree.js'; + +@element('tabpane-io-calltree') +export class TabPaneIOCallTree extends TabPaneCallTree { + constructor() { + super(); + this.queryFuncName = 'io'; + this.procedureAction = 'fileSystem-action'; + } +} + +@element('tabpane-vm-calltree') +export class TabPaneVMCallTree extends TabPaneCallTree { + constructor() { + super(); + this.queryFuncName = 'virtualMemory'; + this.procedureAction = 'fileSystem-action'; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.ts new file mode 100644 index 0000000000000000000000000000000000000000..0eb5e96dbba4d97aeb37cef535b98bfdffcbe4f1 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.ts @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPaneIOTierStatisticsData } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { TabPaneFilter } from '../TabPaneFilter.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-io-tier-statistics') +export class TabPaneIOTierStatistics extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private filter: TabPaneFilter | null | undefined; + private loadingPage: any; + private loadingList: number[] = []; + private source: Array = []; + private typeList: Array = ['OPEN', 'CLOSE', 'READ', 'WRITE']; + private sortKey: string = ''; + private sortType: number = 0; + private resultData: Array = []; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.selectionParam = val; + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 20 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.progressEL = this.shadowRoot!.querySelector('.progress'); + this.loadingPage = this.shadowRoot!.querySelector('.loading'); + this.tbl = this.shadowRoot!.querySelector('#tb-states'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + + let newSource = JSON.parse(JSON.stringify(this.source)); + if (this.sortType != 0 && newSource.length > 0) this.sortTable(newSource[0], this.sortKey); + this.tbl!.recycleDataSource = newSource; + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement!.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.tbl!.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + getInitData(item: any, nameTitle: any = 'pname', subtitle: any = null) { + if (nameTitle == 'path') { + item.path = item.path != null ? SpSystemTrace.DATA_DICT.get(parseInt(item.path)) : '-'; + } + return { + ...item, + title: item[nameTitle] + (subtitle ? '(' + item[subtitle] + ')' : ''), + allDuration: Utils.getProbablyTime(item.allDuration), + minDuration: Utils.getProbablyTime(item.minDuration), + maxDuration: Utils.getProbablyTime(item.maxDuration), + avgDuration: Utils.getProbablyTime(item.avgDuration), + node: { ...item, children: [] }, + }; + } + + queryDataByDB(val: SelectionParam | any) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + getTabPaneIOTierStatisticsData( + val.leftNs + val.recordStartNs, + val.rightNs + val.recordStartNs, + val.diskIOipids + ).then((result) => { + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + this.resultData = JSON.parse(JSON.stringify(result)); + this.sortStatus(result, 'tier', 'ipid'); + }); + } + + sortStatus(result: Array, firstLevel: string, secondLevel: string) { + let fatherMap = new Map(); + let childMap = new Map(); + let allNode: any = { + title: 'All', + count: 0, + allDuration: 0, + minDuration: 0, + maxDuration: 0, + avgDuration: '', + children: [], + }; + result.forEach((item, idx) => { + if (childMap.has(item[firstLevel] + '_' + item[secondLevel])) { + let obj1 = childMap.get(item[firstLevel] + '_' + item[secondLevel]); + obj1.count += item.count; + obj1.allDuration += item.allDuration; + obj1.minDuration = obj1.minDuration <= item.minDuration ? obj1.minDuration : item.minDuration; + obj1.maxDuration = obj1.maxDuration >= item.maxDuration ? obj1.maxDuration : item.maxDuration; + obj1.children.push(this.getInitData(item, 'path', null)); + } else { + childMap.set(item[firstLevel] + '_' + item[secondLevel], { + ...item, + children: [this.getInitData(item, 'path', null)], + }); + } + + if (fatherMap.has(item[firstLevel])) { + let obj1 = fatherMap.get(item[firstLevel]); + obj1.count += item.count; + obj1.allDuration += item.allDuration; + obj1.minDuration = obj1.minDuration <= item.minDuration ? obj1.minDuration : item.minDuration; + obj1.maxDuration = obj1.maxDuration >= item.maxDuration ? obj1.maxDuration : item.maxDuration; + obj1.children.push(this.getInitData(item)); + } else { + fatherMap.set(item[firstLevel], { + ...item, + children: [this.getInitData(item)], + }); + } + if (idx == 0) { + allNode.minDuration = item.minDuration; + } else { + allNode.minDuration = allNode.minDuration <= item.minDuration ? allNode.minDuration : item.minDuration; + } + allNode.count += item.count; + allNode.allDuration += item.allDuration; + allNode.maxDuration = allNode.maxDuration >= item.maxDuration ? allNode.maxDuration : item.maxDuration; + }); + + for (let ks of fatherMap.keys()) { + let sp = fatherMap.get(ks); + sp!.children = []; + sp.avgDuration = sp.allDuration / sp.count; + let node = this.getInitData(sp, 'tier', null); + node.path = { + tier: node.tier, + pid: null, + path: null, + value: node.title, + }; + for (let kst of childMap.keys()) { + if (kst.startsWith(ks + '_')) { + let spt = childMap.get(kst); + let data = this.getInitData(spt!, 'pname', 'pid'); + data.path = { + tier: node.tier, + pid: data.pid, + path: null, + value: 'All-' + node.title + '-' + data.title, + }; + data.children.forEach((e: any) => { + e.path = { + tier: node.tier, + pid: data.pid, + path: e.path, + value: 'All-' + node.title + '-' + data.title + '-' + e.title, + }; + }); + sp!.children.push(data); + } + } + allNode.children.push(node); + } + + allNode.avgDuration = allNode.allDuration / allNode.count; + allNode = this.getInitData(allNode); + allNode.title = 'All'; + allNode.path = { tier: null, pid: null, path: null, value: 'All' }; + this.source = result.length > 0 ? [allNode] : []; + let newSource = JSON.parse(JSON.stringify(this.source)); + if (this.sortType != 0 && result.length > 0) this.sortTable(newSource[0], this.sortKey); + this.tbl!.recycleDataSource = newSource; + } + + sortTable(allNode: any, key: string) { + allNode.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + allNode.children.forEach((item: any) => { + item.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + item.children.forEach((i: any) => { + i.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + }); + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneIOTierStatisticsAnalysis.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneIOTierStatisticsAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..35187c859e6bce22989ffdca8a10b00266505347 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneIOTierStatisticsAnalysis.ts @@ -0,0 +1,979 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../../../base-ui/chart/pie/LitChartPie.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; +import { Utils } from '../../base/Utils.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-io-statistics-analysis') +export class TabPaneIOTierStatisticsAnalysis extends BaseElement { + private pie: LitChartPie | null | undefined; + private currentSelection: SelectionParam | any; + private processData: any; + private pidData!: any[]; + private threadData!: any[]; + private soData!: any[]; + private functionData!: any[]; + private typeData!: any[]; + private tableProcess: LitTable | null | undefined; + private tableThread: LitTable | null | undefined; + private tableType: LitTable | null | undefined; + private tableSo: LitTable | null | undefined; + private tableFunction: LitTable | null | undefined; + private sumDur: any; + private range: HTMLLabelElement | null | undefined; + private back: HTMLDivElement | null | undefined; + private tabName: HTMLDivElement | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private processName: string = ''; + private threadName: string = ''; + private sortColumn: string = ''; + private sortType: number = 0; + private typeName: any; + private currentLevel = -1; + private currentLevelData!: Array; + private processStatisticsData!: any; + private typeStatisticsData!: any; + private threadStatisticsData!: any; + private libStatisticsData!: any; + private functionStatisticsData!: any; + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + this.pidData.unshift(this.processStatisticsData); + this.tableProcess!.recycleDataSource = this.pidData; + // @ts-ignore + this.pidData.shift(this.processStatisticsData); + return; + } + this.clearData(); + this.currentSelection = val; + this.tableProcess!.style.display = 'grid'; + this.tableType!.style.display = 'none'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + this.progressEL!.loading = true; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [{ queryFuncName: 'io', ...val }], + }, + ], + (results: any[]) => { + this.getIOTierProcess(val, results); + } + ); + } + initElements(): void { + this.range = this.shadowRoot?.querySelector('#time-range'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.tableProcess = this.shadowRoot!.querySelector('#tb-process-usage'); + this.tableThread = this.shadowRoot!.querySelector('#tb-thread-usage'); + this.tableSo = this.shadowRoot!.querySelector('#tb-so-usage'); + this.tableFunction = this.shadowRoot!.querySelector('#tb-function-usage'); + this.tableType = this.shadowRoot!.querySelector('#tb-type-usage'); + this.back = this.shadowRoot!.querySelector('.go-back'); + this.tabName = this.shadowRoot!.querySelector('.subheading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.goBack(); + } + clearData() { + this.pie!.dataSource = []; + this.tableProcess!.recycleDataSource = []; + this.tableType!.recycleDataSource = []; + this.tableThread!.recycleDataSource = []; + this.tableSo!.recycleDataSource = []; + this.tableFunction!.recycleDataSource = []; + } + goBack() { + this.back!.addEventListener('click', () => { + if (this.tabName!.textContent === 'Statistic By type AllDuration') { + this.tableProcess!.style.display = 'grid'; + this.tableType!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableProcess?.removeAttribute('hideDownload'); + this.currentLevel = 0; + this.processPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Thread AllDuration') { + this.tableType!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.currentLevel = 1; + this.typePieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Library AllDuration') { + this.tableThread!.style.display = 'grid'; + this.tableSo!.style.display = 'none'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.currentLevel = 2; + this.threadPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Function AllDuration') { + this.tableSo!.style.display = 'grid'; + this.tableFunction!.style.display = 'none'; + this.tableFunction!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.currentLevel = 3; + this.libraryPieChart(this.currentSelection); + } + }); + } + processPieChart(val: any) { + this.sumDur = this.processStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.pidData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ProcessName:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableProcess!.style.display = 'none'; + this.tableType!.style.display = 'grid'; + this.tableProcess!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.getIOTierType(it, val); + // @ts-ignore + this.processName = it.tableName; + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + } + }, + hoverHandler: (data) => { + if (data) { + this.tableProcess!.setCurrentHover(data); + } else { + this.tableProcess!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableProcess!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = ''; + this.tabName!.textContent = 'Statistic By Process AllDuration'; + this.pidData.unshift(this.processStatisticsData); + this.tableProcess!.recycleDataSource = this.pidData; + this.currentLevelData = JSON.parse(JSON.stringify(this.pidData)); + // @ts-ignore + this.pidData.shift(this.processStatisticsData); + this.tableProcess?.reMeauseHeight(); + this.tableProcess!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + typePieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.typeData, + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Type:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + this.clearData(); + this.tableType!.style.display = 'none'; + this.tableThread!.style.display = 'grid'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.getIOTierThread(it, val); + // @ts-ignore + this.typeName = it.tableName; + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName; + }, + hoverHandler: (data) => { + if (data) { + this.tableType!.setCurrentHover(data); + } else { + this.tableType!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableType!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + this.tabName!.textContent = 'Statistic By type AllDuration'; + this.typeData.unshift(this.typeStatisticsData); + this.tableType!.recycleDataSource = this.typeData; + this.currentLevelData = JSON.parse(JSON.stringify(this.typeData)); + // @ts-ignore + this.typeData.shift(this.typeStatisticsData); + this.tableType?.reMeauseHeight(); + this.tableType!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + threadPieChart(val: any) { + this.sumDur = this.threadStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.threadData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ThreadName:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'grid'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.getIOTierSo(it, val); + // @ts-ignore + this.threadName = it.tableName; + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName + ' / ' + this.threadName; + } + }, + hoverHandler: (data) => { + if (data) { + this.tableThread!.setCurrentHover(data); + } else { + this.tableThread!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableThread!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName + ' / ' + this.typeName; + this.tabName!.textContent = 'Statistic By Thread AllDuration'; + this.threadData.unshift(this.threadStatisticsData); + this.tableThread!.recycleDataSource = this.threadData; + this.currentLevelData = JSON.parse(JSON.stringify(this.threadData)); + // @ts-ignore + this.threadData.shift(this.threadStatisticsData); + this.tableThread?.reMeauseHeight(); + this.tableThread!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + libraryPieChart(val: any) { + this.sumDur = this.libStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.soData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Library:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'grid'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableFunction?.removeAttribute('hideDownload'); + this.getIOTierFunction(it, val); + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = + // @ts-ignore + this.processName + ' / ' + this.typeName + ' / ' + this.threadName + ' / ' + it.tableName; + } + }, + hoverHandler: (data) => { + if (data) { + this.tableSo!.setCurrentHover(data); + } else { + this.tableSo!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableSo!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName + ' / ' + this.threadName; + this.tabName!.textContent = 'Statistic By Library AllDuration'; + this.soData.unshift(this.libStatisticsData); + this.tableSo!.recycleDataSource = this.soData; + this.currentLevelData = JSON.parse(JSON.stringify(this.soData)); + // @ts-ignore + this.soData.shift(this.libStatisticsData); + this.tableSo?.reMeauseHeight(); + this.tableSo!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + let currentTable: LitTable | null | undefined; + switch (this.currentLevel) { + case 0: + currentTable = this.tableProcess; + break; + case 1: + currentTable = this.tableType; + break; + case 2: + currentTable = this.tableThread; + break; + case 3: + currentTable = this.tableSo; + break; + case 4: + currentTable = this.tableFunction; + break; + } + if (!currentTable) { + return; + } + if (sort == 0) { + currentTable!.recycleDataSource = this.currentLevelData; + } else { + let arr = [...this.currentLevelData]; + switch (this.currentLevel) { + case 0: + // @ts-ignore + arr.shift(this.processStatisticsData); + break; + case 1: + // @ts-ignore + arr.shift(this.typeStatisticsData); + break; + case 2: + // @ts-ignore + arr.shift(this.threadStatisticsData); + break; + case 3: + // @ts-ignore + arr.shift(this.libStatisticsData); + break; + case 4: + // @ts-ignore + arr.shift(this.functionStatisticsData); + break; + } + if (column == 'tableName') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.tableName > b.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } else { + if (b.tableName > a.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'durFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.duration - b.duration : b.duration - a.duration; + }); + } else if (column == 'percent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.duration - b.duration : b.duration - a.v; + }); + } + switch (this.currentLevel) { + case 0: + arr.unshift(this.processStatisticsData); + break; + case 1: + arr.unshift(this.typeStatisticsData); + break; + case 2: + arr.unshift(this.threadStatisticsData); + break; + case 3: + arr.unshift(this.libStatisticsData); + break; + case 4: + arr.unshift(this.functionStatisticsData); + break; + } + currentTable!.recycleDataSource = arr; + } + } + getIOTierProcess(val: any, result: Array) { + this.processData = JSON.parse(JSON.stringify(result)); + if (!this.processData || this.processData.length == 0) { + return; + } + let allDur = 0; + let pidMap = new Map>(); + for (let itemData of result) { + allDur += itemData.dur; + if (pidMap.has(itemData.pid)) { + pidMap.get(itemData.pid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + pidMap.set(itemData.pid, itemArray); + } + } + this.pidData = []; + pidMap.forEach((value: Array, key: string) => { + let dur = 0; + let pName = ''; + for (let item of value) { + pName = item.processName = + item.processName == null || item.processName == undefined + ? `Process(${item.pid})` + : `${item.processName}(${item.pid})`; + dur += item.dur; + } + const pidData = { + tableName: pName, + pid: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.pidData.push(pidData); + }); + this.pidData.sort((a, b) => b.duration - a.duration); + this.processStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 0; + this.progressEL!.loading = false; + this.processPieChart(val); + } + getIOTierType(item: any, val: any) { + this.progressEL!.loading = true; + let typeMap = new Map>(); + let pid = item.pid; + let allDur = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid) { + continue; + } + allDur += itemData.dur; + if (typeMap.has(itemData.type)) { + typeMap.get(itemData.type)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(itemData.type, itemArray); + } + } + this.typeData = []; + typeMap.forEach((value: Array, key: string) => { + let dur = 0; + for (let item of value) { + dur += item.dur; + } + const typeData = { + tableName: this.typeIdToString(key), + pid: item.pid, + type: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.typeData.push(typeData); + }); + this.typeData.sort((a, b) => b.duration - a.duration); + this.typeStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 1; + this.typePieChart(val); + this.progressEL!.loading = false; + } + getIOTierThread(item: any, val: any) { + this.progressEL!.loading = true; + let threadMap = new Map>(); + let pid = item.pid; + let type = item.type; + let allDur = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.type !== type) { + continue; + } + allDur += itemData.dur; + if (threadMap.has(itemData.tid)) { + threadMap.get(itemData.tid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + threadMap.set(itemData.tid, itemArray); + } + } + this.threadData = []; + threadMap.forEach((value: Array, key: string) => { + let dur = 0; + let tName = ''; + for (let item of value) { + dur += item.dur; + tName = item.threadName = + item.threadName == null || item.threadName == undefined ? `Thread(${item.tid})` : `${item.threadName}`; + } + const threadData = { + tableName: tName, + pid: item.pid, + type: item.type, + tid: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.threadData.push(threadData); + }); + this.threadData.sort((a, b) => b.duration - a.duration); + this.threadStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 2; + this.progressEL!.loading = false; + this.threadPieChart(val); + } + getIOTierSo(item: any, val: any) { + this.progressEL!.loading = true; + let tid = item.tid; + let pid = item.pid; + let type = item.type; + let allDur = 0; + let libMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid || itemData.type !== type) { + continue; + } + allDur += itemData.dur; + if (libMap.has(itemData.libId)) { + libMap.get(itemData.libId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + libMap.set(itemData.libId, dataArray); + } + } + this.soData = []; + libMap.forEach((value: any[], key: number) => { + let dur = 0; + let libName = ''; + for (let item of value) { + dur += item.dur; + if (key == null) { + item.libName = 'unkown'; + } + libName = item.libName; + } + let libPath = libName?.split('/'); + if (libPath) { + libName = libPath[libPath.length - 1]; + } + const soData = { + tableName: libName, + pid: item.pid, + type: item.type, + tid: item.tid, + libId: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.soData.push(soData); + }); + this.soData.sort((a, b) => b.duration - a.duration); + this.libStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 3; + this.progressEL!.loading = false; + this.libraryPieChart(val); + } + getIOTierFunction(item: any, val: any) { + this.progressEL!.loading = true; + this.shadowRoot!.querySelector('.subheading')!.textContent = 'Statistic By Function AllDuration'; + let tid = item.tid; + let pid = item.pid; + let type = item.type; + let libId = item.libId; + let allDur = 0; + let symbolMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid || itemData.type !== type || itemData.libId !== libId) { + continue; + } + allDur += itemData.dur; + if (symbolMap.has(itemData.symbolId)) { + symbolMap.get(itemData.symbolId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + symbolMap.set(itemData.symbolId, dataArray); + } + } + this.functionData = []; + symbolMap.forEach((symbolItems, key) => { + let dur = 0; + let symbolName = ''; + for (let symbolItem of symbolItems) { + symbolName = symbolItem.symbolName; + dur += symbolItem.dur; + } + let symbolPath = symbolName?.split('/'); + if (symbolPath) { + symbolName = symbolPath[symbolPath.length - 1]; + } + const symbolData = { + pid: item.pid, + tid: item.tid, + percent: ((dur / allDur) * 100).toFixed(2), + tableName: symbolName, + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.functionData.push(symbolData); + }); + this.functionData.sort((a, b) => b.duration - a.duration); + this.functionStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 4; + this.progressEL!.loading = false; + this.sumDur = this.functionStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.functionData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Function:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
percent:${obj.obj.percent}
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.tableFunction!.setCurrentHover(data); + } else { + this.tableFunction!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableFunction!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.functionData.unshift(this.functionStatisticsData); + this.tableFunction!.recycleDataSource = this.functionData; + this.tableFunction?.reMeauseHeight(); + this.currentLevelData = JSON.parse(JSON.stringify(this.functionData)); + // @ts-ignore + this.functionData.shift(this.functionStatisticsData); + this.tableFunction!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + typeIdToString(type: any) { + let releaseType: any; + if (type === 1) { + releaseType = 'DATA_READ'; + } else if (type === 2) { + releaseType = 'DATA_WRITE'; + } else if (type === 3) { + releaseType = 'METADATA_READ'; + } else if (type === 4) { + releaseType = 'METADATA_WRITE'; + } + return releaseType; + } + totalDurationData(duration: any) { + let allDuration; + allDuration = { + durFormat: Utils.getProbablyTime(duration), + percent: ((duration / duration) * 100).toFixed(2), + tableName: '', + duration: 0, + allDuration: duration, + }; + return allDuration; + } + getPieChartData(res: any[]) { + if (res.length > 20) { + let pieChartArr: any[] = []; + let other: any = { + tableName: 'other', + duration: 0, + percent: 0, + durFormat: 0, + }; + for (let i = 0; i < res.length; i++) { + if (i < 19) { + pieChartArr.push(res[i]); + } else { + other.duration += res[i].duration; + other.durFormat = Utils.getProbablyTime(other.duration); + other.percent = ((other.duration / this.sumDur) * 100).toFixed(2); + } + } + pieChartArr.push(other); + return pieChartArr; + } + return res; + } + + getDataByWorker(args: any[], handler: Function) { + procedurePool.submitWithName( + 'logic0', + 'fileSystem-action', + { args, callType: 'io', isAnalysis: true }, + undefined, + (results: any) => { + handler(results); + this.progressEL!.loading = false; + } + ); + } + + initHtml(): string { + return ` + + +
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + +
+ +
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneIoCompletionTimes.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneIoCompletionTimes.ts new file mode 100644 index 0000000000000000000000000000000000000000..369741f5b00a2dd0804531b71deb2668f30f747c --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneIoCompletionTimes.ts @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { + DISKIO_TYPE_MAP, + FileSysEvent, + IoCompletionTimes, + VirtualMemoryEvent, + VM_TYPE_MAP, +} from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { getTabIoCompletionTimesType, getTabVirtualMemoryType } from '../../../../database/SqlLite.js'; + +@element('tabpane-io-completiontimes') +export class TabPaneIoCompletionTimes extends BaseElement { + // @ts-ignore + private defaultNativeTypes = ['All', ...Object.values(VM_TYPE_MAP)]; + private native_type: Array = [...this.defaultNativeTypes]; + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private sortKey: string = 'startTs'; + private sortType: number = 0; + private currentSelection: SelectionParam | undefined | null; + private source: Array = []; + private queryDataSource: Array = []; + private statsticsSelection: Array = []; + + set data(val: SelectionParam | null | undefined) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + this.initFilterTypes(val!).then(() => { + this.queryData(val!); + }); + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + this.tbl!.recycleDataSource = []; + this.tblData!.recycleDataSource = []; + } + + connectedCallback() { + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 33 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 33 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tbl'); + this.tblData = this.shadowRoot?.querySelector('#tbr'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as FileSysEvent; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryStack', + { callchainId: data.callchainId }, + undefined, + (res: any) => { + this.tblData!.recycleDataSource = res; + } + ); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + this.shadowRoot?.querySelector('#filter')!.getFilterData((data: FilterData) => { + let index = parseInt(data.firstSelect || '0'); + if (index > this.defaultNativeTypes.length - 1) { + this.filterTypeData(this.statsticsSelection[index - this.defaultNativeTypes.length]); + } else { + this.filterTypeData(undefined); + } + this.tbl!.recycleDataSource = this.source; + }); + } + + async initFilterTypes(val: SelectionParam) { + let filter = this.shadowRoot?.querySelector('#filter'); + let typeKeys = await getTabIoCompletionTimesType(val.leftNs, val.rightNs); + this.defaultNativeTypes = ['All']; + this.statsticsSelection = []; + typeKeys.forEach((item) => { + // @ts-ignore + this.defaultNativeTypes.push(item.tier + ''); + }); + this.native_type = [...this.defaultNativeTypes]; + filter!.setSelectList([...this.defaultNativeTypes], null, 'Tier'); + filter!.firstSelect = '0'; + } + + async fromStastics(val: SelectionParam | any) { + if (val.fileSystemIoData == undefined) { + return; + } + this.tblData!.recycleDataSource = []; + this.tblData?.clearAllSelection(undefined); + let filter = this.shadowRoot?.querySelector('#filter'); + if (this.currentSelection != val) { + await this.initFilterTypes(val); + } + let typeIndexOf = this.native_type.indexOf(val.fileSystemIoData.path.value); + if (typeIndexOf == -1) { + this.statsticsSelection.push(val.fileSystemIoData.path); + this.native_type.push(val.fileSystemIoData.path.value); + typeIndexOf = this.native_type.length - 1; + } + if (this.currentSelection != val) { + this.currentSelection = val; + filter!.setSelectList(this.native_type, null, 'Tier'); + filter!.firstSelect = typeIndexOf + ''; + this.queryData(val); + } else { + if (typeIndexOf == parseInt(filter!.firstSelect)) { + return; + } + filter!.setSelectList(this.native_type, null, 'Tier'); + filter!.firstSelect = typeIndexOf + ''; + this.filterTypeData(val?.fileSystemIoData?.path || undefined); + val.fileSystemIoData = undefined; + this.tbl!.recycleDataSource = this.source; + } + } + + queryData(val: SelectionParam) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.source = []; + this.queryDataSource = []; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryIOEvents', + { + leftNs: val.leftNs, + rightNs: val.rightNs, + diskIOipids: val.diskIOipids, + }, + undefined, + (res: any) => { + this.source = this.source.concat(res.data); + this.queryDataSource = this.queryDataSource.concat(res.data); + this.filterTypeData(val?.fileSystemIoData?.path || undefined); + val.fileSystemIoData = undefined; + res.data = null; + if (!res.isSending) { + this.tbl!.recycleDataSource = this.source; + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + } + ); + } + + filterTypeData(pathData: any) { + let filter = this.shadowRoot?.querySelector('#filter'); + let firstSelect = filter!.firstSelect; + let tier = -1; + let path = ''; + let pid = -1; + if (parseInt(firstSelect) <= this.defaultNativeTypes.length - 1) { + let index = parseInt(firstSelect); + tier = index == 0 ? -1 : parseInt(this.defaultNativeTypes[index]); + } else if (pathData != undefined) { + tier = parseInt(pathData.tier); + path = pathData.path || ''; + pid = pathData.pid || -1; + } else if (pathData == undefined) { + return; + } + let isTierFilter = false; + let isPidFilter = false; + let isPathFilter = false; + this.source = this.queryDataSource.filter((item) => { + if (tier == -1) { + isTierFilter = true; + } else { + isTierFilter = item.tier == tier; + } + if (pid == -1) { + isPidFilter = true; + } else { + isPidFilter = item.pid == pid; + } + isPathFilter = path == '' || item.path == path; + return isTierFilter && isPidFilter && isPathFilter; + }); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'startTsStr') { + if (type == 1) { + return a.startTs - b.startTs; + } else { + return b.startTs - a.startTs; + } + } else if (key == 'durStr') { + if (type == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } else if (key == 'process') { + if (a.process > b.process) { + return type === 2 ? 1 : -1; + } else if (a.process == b.process) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'durPer4kStr') { + if (type == 1) { + return a.durPer4k - b.durPer4k; + } else { + return b.durPer4k - a.durPer4k; + } + } else if (key == 'thread') { + if (a.thread > b.thread) { + return type === 2 ? 1 : -1; + } else if (a.thread == b.thread) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'operation') { + if (a.operation > b.operation) { + return type === 2 ? 1 : -1; + } else if (a.operation == b.operation) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'sizeStr') { + if (type == 1) { + return a.size - b.size; + } else { + return b.size - a.size; + } + } else if (key == 'tier') { + if (type == 1) { + return a.tier - b.tier; + } else { + return b.tier - a.tier; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneVMEvents.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneVMEvents.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc321343f569fa8b8e075e0ed2522a0c317e8765 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneVMEvents.ts @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { + FileSysEvent, + VirtualMemoryEvent, + VM_TYPE_MAP, +} from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { getTabVirtualMemoryType } from '../../../../database/SqlLite.js'; + +@element('tabpane-virtualmemory-event') +export class TabPaneVirtualMemoryEvents extends BaseElement { + // @ts-ignore + private defaultNativeTypes = ['All', ...Object.values(VM_TYPE_MAP)]; + private native_type: Array = [...this.defaultNativeTypes]; + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private source: Array = []; + private queryDataSource: Array = []; + private sortKey: string = 'startTs'; + private sortType: number = 0; + private currentSelection: SelectionParam | undefined | null; + private statsticsSelection: Array = []; + + set data(val: SelectionParam | null | undefined) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + this.initFilterTypes(val!).then(() => { + this.queryData(val!); + }); + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + this.tbl!.recycleDataSource = []; + this.tblData!.recycleDataSource = []; + } + + connectedCallback() { + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 33 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 33 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tbl'); + this.tblData = this.shadowRoot?.querySelector('#tbr'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data; + (data as any).isSelected = true; + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryStack', + { callchainId: data.callchainId }, + undefined, + (res: any) => { + this.tblData!.recycleDataSource = res; + } + ); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + this.shadowRoot?.querySelector('#filter')!.getFilterData((data: FilterData) => { + let index = parseInt(data.firstSelect || '0'); + if (index > this.defaultNativeTypes.length - 1) { + this.filterTypeData(this.statsticsSelection[index - this.defaultNativeTypes.length]); + } else { + this.filterTypeData(undefined); + } + this.tbl!.recycleDataSource = this.source; + }); + } + + async initFilterTypes(val: SelectionParam) { + let filter = this.shadowRoot?.querySelector('#filter'); + let typeKeys = await getTabVirtualMemoryType(val.leftNs, val.rightNs); + this.defaultNativeTypes = ['All']; + this.statsticsSelection = []; + typeKeys.forEach((item) => { + // @ts-ignore + this.defaultNativeTypes.push(VM_TYPE_MAP[item.type + '']); + }); + this.native_type = [...this.defaultNativeTypes]; + filter!.setSelectList([...this.defaultNativeTypes], null, 'Operation Type'); + filter!.firstSelect = '0'; + } + + async fromStastics(val: SelectionParam | any) { + if (val.fileSystemVMData == undefined) { + return; + } + this.tblData!.recycleDataSource = []; + this.tblData?.clearAllSelection(undefined); + let filter = this.shadowRoot?.querySelector('#filter'); + if (this.currentSelection != val) { + await this.initFilterTypes(val); + } + let typeIndexOf = this.native_type.indexOf(val.fileSystemVMData.path.value); + if (typeIndexOf == -1) { + this.statsticsSelection.push(val.fileSystemVMData.path); + this.native_type.push(val.fileSystemVMData.path.value); + typeIndexOf = this.native_type.length - 1; + } + if (this.currentSelection != val) { + this.currentSelection = val; + filter!.setSelectList(this.native_type, null, 'Operation Type'); + filter!.firstSelect = typeIndexOf + ''; + this.queryData(val); + } else { + if (typeIndexOf == parseInt(filter!.firstSelect)) { + return; + } + filter!.setSelectList(this.native_type, null, 'Operation Type'); + filter!.firstSelect = typeIndexOf + ''; + this.filterTypeData(val?.fileSystemVMData?.path || undefined); + val.fileSystemVMData = undefined; + this.tbl!.recycleDataSource = this.source; + } + } + + queryData(val: SelectionParam) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.source = []; + this.queryDataSource = []; + procedurePool.submitWithName( + 'logic0', + 'fileSystem-queryVMEvents', + { + leftNs: val.leftNs, + rightNs: val.rightNs, + typeArr: val.fileSystemType, + }, + undefined, + (res: any) => { + this.source = this.source.concat(res.data); + this.queryDataSource = this.queryDataSource.concat(res.data); + this.filterTypeData(val?.fileSystemVMData?.path || undefined); + val.fileSystemVMData = undefined; + res.data = null; + if (!res.isSending) { + this.tbl!.recycleDataSource = this.source; + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + } + ); + } + + filterTypeData(pathData: any) { + let filter = this.shadowRoot?.querySelector('#filter'); + let firstSelect = filter!.firstSelect; + let type = -1; + let tid = -1; + let pid = -1; + if (parseInt(firstSelect) <= this.defaultNativeTypes.length - 1) { + // @ts-ignore + let typeEntry = Object.entries(VM_TYPE_MAP).find((entry) => { + return entry[1] == this.defaultNativeTypes[parseInt(firstSelect)]; + }); + type = typeEntry ? parseInt(typeEntry[0]) : 0; + } else if (pathData != undefined) { + type = parseInt(pathData.type || 0); + tid = pathData.tid || -1; + pid = pathData.pid || -1; + } else if (pathData == undefined) { + return; + } + let isTidFilter = false; + let isPidFilter = false; + let isTypeFilter = false; + this.source = this.queryDataSource.filter((item) => { + if (tid == -1) { + isTidFilter = true; + } else { + isTidFilter = item.tid == tid; + } + if (pid == -1) { + isPidFilter = true; + } else { + isPidFilter = item.pid == pid; + } + isTypeFilter = type == 0 || item.type == type; + return isTidFilter && isPidFilter && isTypeFilter; + }); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'startTsStr') { + if (type == 1) { + return a.startTs - b.startTs; + } else { + return b.startTs - a.startTs; + } + } else if (key == 'durStr') { + if (type == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } else if (key == 'thread') { + if (a.thread > b.thread) { + return type === 2 ? 1 : -1; + } else if (a.thread == b.thread) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else if (key == 'sizeStr') { + if (type == 1) { + return a.size - b.size; + } else { + return b.size - a.size; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.ts new file mode 100644 index 0000000000000000000000000000000000000000..31143b7452ef977f304a277f21256988f0ce7030 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.ts @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabPaneVirtualMemoryStatisticsData } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { TabPaneFilter } from '../TabPaneFilter.js'; +import '../TabPaneFilter.js'; +import { VM_TYPE_MAP } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; + +@element('tabpane-virtual-memory-statistics') +export class TabPaneVirtualMemoryStatistics extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private filter: TabPaneFilter | null | undefined; + private loadingPage: any; + private loadingList: number[] = []; + private source: Array = []; + private typeList: Array = ['OPEN', 'CLOSE', 'READ', 'WRITE']; + private sortKey: string = ''; + private sortType: number = 0; + private resultData: Array = []; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.selectionParam = val; + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 20 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.progressEL = this.shadowRoot!.querySelector('.progress'); + this.loadingPage = this.shadowRoot!.querySelector('.loading'); + this.tbl = this.shadowRoot!.querySelector('#tb-states'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + + let newSource = JSON.parse(JSON.stringify(this.source)); + if (this.sortType != 0 && newSource.length > 0) this.sortTable(newSource[0], this.sortKey); + this.tbl!.recycleDataSource = newSource; + }); + this.filter = this.shadowRoot!.querySelector('#filter'); + this.filter!.getStatisticsTypeData((type) => { + if (type == 'operation') { + this.sortStatus(this.resultData, 'ipid', 'itid'); + } else { + this.sortStatus(this.resultData, 'type', 'ipid'); + } + this.tbl!.shadowRoot!.querySelector('div > div.thead > div > div:nth-child(1) > label')!.textContent = + type == 'operation' ? 'Process/Thread/Operation' : 'Operation/Process/Thread'; + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement!.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 10 - 32 + 'px'; + this.tbl!.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + getInitData(item: any, nameTitle: any = 'pname', subtitle: any = null) { + // @ts-ignore + let title = nameTitle == 'type' ? VM_TYPE_MAP[item[nameTitle]] : item[nameTitle]; + return { + ...item, + title: title + (subtitle ? '(' + item[subtitle] + ')' : ''), + allDuration: Utils.getProbablyTime(item.allDuration), + minDuration: Utils.getProbablyTime(item.minDuration), + maxDuration: Utils.getProbablyTime(item.maxDuration), + avgDuration: Utils.getProbablyTime(item.avgDuration), + node: { ...item, children: [] }, + }; + } + + queryDataByDB(val: SelectionParam | any) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + getTabPaneVirtualMemoryStatisticsData(val.leftNs + val.recordStartNs, val.rightNs + val.recordStartNs).then( + (result) => { + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + this.resultData = JSON.parse(JSON.stringify(result)); + this.sortStatus(result, 'type', 'ipid'); + } + ); + } + + sortStatus(result: Array, firstLevel: string, secondLevel: string) { + let fatherMap = new Map(); + let childMap = new Map(); + let allNode: any = { + title: 'All', + count: 0, + allDuration: 0, + minDuration: 0, + maxDuration: 0, + avgDuration: '', + children: [], + }; + result.forEach((item, idx) => { + if (childMap.has(item[firstLevel] + '_' + item[secondLevel])) { + let obj1 = childMap.get(item[firstLevel] + '_' + item[secondLevel]); + obj1.count += item.count; + obj1.allDuration += item.allDuration; + obj1.minDuration = obj1.minDuration <= item.minDuration ? obj1.minDuration : item.minDuration; + obj1.maxDuration = obj1.maxDuration >= item.maxDuration ? obj1.maxDuration : item.maxDuration; + obj1.children.push( + this.getInitData(item, firstLevel == 'type' ? 'tname' : 'type', firstLevel == 'type' ? 'tid' : null) + ); + } else { + childMap.set(item[firstLevel] + '_' + item[secondLevel], { + ...item, + children: [ + this.getInitData(item, firstLevel == 'type' ? 'tname' : 'type', firstLevel == 'type' ? 'tid' : null), + ], + }); + } + + if (fatherMap.has(item[firstLevel])) { + let obj1 = fatherMap.get(item[firstLevel]); + obj1.count += item.count; + obj1.allDuration += item.allDuration; + obj1.minDuration = obj1.minDuration <= item.minDuration ? obj1.minDuration : item.minDuration; + obj1.maxDuration = obj1.maxDuration >= item.maxDuration ? obj1.maxDuration : item.maxDuration; + obj1.children.push(this.getInitData(item)); + } else { + fatherMap.set(item[firstLevel], { + ...item, + children: [this.getInitData(item)], + }); + } + if (idx == 0) { + allNode.minDuration = item.minDuration; + } else { + allNode.minDuration = allNode.minDuration <= item.minDuration ? allNode.minDuration : item.minDuration; + } + allNode.count += item.count; + allNode.allDuration += item.allDuration; + allNode.maxDuration = allNode.maxDuration >= item.maxDuration ? allNode.maxDuration : item.maxDuration; + }); + + for (let ks of fatherMap.keys()) { + let sp = fatherMap.get(ks); + sp!.children = []; + sp.avgDuration = sp.allDuration / sp.count; + let node = this.getInitData(sp, firstLevel == 'type' ? 'type' : 'pname', firstLevel == 'type' ? null : 'pid'); + node.path = { type: null, tid: null, pid: null, value: node.title }; + node.path[firstLevel == 'type' ? 'type' : 'pid'] = node[firstLevel == 'type' ? 'type' : 'pid']; + for (let kst of childMap.keys()) { + if (kst.startsWith(ks + '_')) { + let spt = childMap.get(kst); + let data = this.getInitData( + spt!, + firstLevel == 'type' ? 'pname' : 'tname', + firstLevel == 'type' ? 'pid' : 'tid' + ); + data.path = { + type: null, + tid: null, + pid: null, + value: 'All-' + node.title + '-' + data.title, + }; + data.path[firstLevel == 'type' ? 'type' : 'pid'] = node[firstLevel == 'type' ? 'type' : 'pid']; + data.path[firstLevel == 'type' ? 'pid' : 'tid'] = data[firstLevel == 'type' ? 'pid' : 'tid']; + data.children.forEach((e: any) => { + e.path = { + type: null, + tid: null, + pid: null, + value: 'All-' + node.title + '-' + data.title + '-' + e.title, + }; + e.path[firstLevel == 'type' ? 'type' : 'pid'] = node[firstLevel == 'type' ? 'type' : 'pid']; + e.path[firstLevel == 'type' ? 'pid' : 'tid'] = data[firstLevel == 'type' ? 'pid' : 'tid']; + e.path[firstLevel == 'type' ? 'tid' : 'type'] = e[firstLevel == 'type' ? 'tid' : 'type']; + }); + sp!.children.push(data); + } + } + allNode.children.push(node); + } + + allNode.avgDuration = allNode.allDuration / allNode.count; + allNode = this.getInitData(allNode); + allNode.title = 'All'; + allNode.path = { type: null, tid: null, pid: null, value: 'All' }; + this.source = result.length > 0 ? [allNode] : []; + let newSource = JSON.parse(JSON.stringify(this.source)); + if (this.sortType != 0 && result.length > 0) this.sortTable(newSource[0], this.sortKey); + this.tbl!.recycleDataSource = newSource; + } + + sortTable(allNode: any, key: string) { + allNode.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + allNode.children.forEach((item: any) => { + item.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + item.children.forEach((i: any) => { + i.children.sort((a: any, b: any) => { + if (this.sortType == 1) { + return a.node[key] - b.node[key]; + } else if (this.sortType == 2) { + return b.node[key] - a.node[key]; + } + }); + }); + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatisticsAnalysis.ts b/ide/src/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatisticsAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6e5dbbecbf5413b85ad271ef9f0bbaf7ae30895 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatisticsAnalysis.ts @@ -0,0 +1,976 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../../../base-ui/chart/pie/LitChartPie.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; +import { Utils } from '../../base/Utils.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-virtual-memory-statistics-analysis') +export class TabPaneVirtualMemoryStatisticsAnalysis extends BaseElement { + private pie: LitChartPie | null | undefined; + private currentSelection: SelectionParam | any; + private processData: any; + private pidData!: any[]; + private threadData!: any[]; + private soData!: any[]; + private functionData!: any[]; + private typeData!: any[]; + private tableProcess: LitTable | null | undefined; + private tableType: LitTable | null | undefined; + private tableThread: LitTable | null | undefined; + private tableSo: LitTable | null | undefined; + private tableFunction: LitTable | null | undefined; + private sumDur: any; + private range: HTMLLabelElement | null | undefined; + private back: HTMLDivElement | null | undefined; + private tabName: HTMLDivElement | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private processName: string = ''; + private typeName: string = ''; + private threadName: string = ''; + private sortColumn: string = ''; + private sortType: number = 0; + private currentLevel = -1; + private currentLevelData!: Array; + private processStatisticsData!: any; + private typeStatisticsData!: any; + private threadStatisticsData!: any; + private libStatisticsData!: any; + private functionStatisticsData!: any; + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + this.pidData.unshift(this.processStatisticsData); + this.tableProcess!.recycleDataSource = this.pidData; + // @ts-ignore + this.pidData.shift(this.processStatisticsData); + return; + } + this.clearData(); + this.currentSelection = val; + this.tableProcess!.style.display = 'grid'; + this.tableType!.style.display = 'none'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + this.progressEL!.loading = true; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [{ queryFuncName: 'virtualMemory', ...val }], + }, + ], + (results: any[]) => { + this.getVirtualMemoryProcess(val, results); + } + ); + } + initElements(): void { + this.range = this.shadowRoot?.querySelector('#time-range'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.tableProcess = this.shadowRoot!.querySelector('#tb-process-usage'); + this.tableType = this.shadowRoot!.querySelector('#tb-type-usage'); + this.tableThread = this.shadowRoot!.querySelector('#tb-thread-usage'); + this.tableSo = this.shadowRoot!.querySelector('#tb-so-usage'); + this.tableFunction = this.shadowRoot!.querySelector('#tb-function-usage'); + this.back = this.shadowRoot!.querySelector('.go-back'); + this.tabName = this.shadowRoot!.querySelector('.subheading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.goBack(); + } + clearData() { + this.pie!.dataSource = []; + this.tableProcess!.recycleDataSource = []; + this.tableType!.recycleDataSource = []; + this.tableThread!.recycleDataSource = []; + this.tableSo!.recycleDataSource = []; + this.tableFunction!.recycleDataSource = []; + } + goBack() { + this.back!.addEventListener('click', () => { + if (this.tabName!.textContent === 'Statistic By type AllDuration') { + this.tableProcess!.style.display = 'grid'; + this.tableType!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableProcess?.removeAttribute('hideDownload'); + this.currentLevel = 0; + this.processPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Thread AllDuration') { + this.tableType!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.currentLevel = 1; + this.typePieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Library AllDuration') { + this.tableThread!.style.display = 'grid'; + this.tableSo!.style.display = 'none'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.currentLevel = 2; + this.threadPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Function AllDuration') { + this.tableSo!.style.display = 'grid'; + this.tableFunction!.style.display = 'none'; + this.tableFunction!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.currentLevel = 3; + this.libraryPieChart(this.currentSelection); + } + }); + } + processPieChart(val: any) { + this.sumDur = this.processStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.pidData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ProcessName:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableProcess!.style.display = 'none'; + this.tableType!.style.display = 'grid'; + this.tableProcess!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.getVirtualMemoryType(it, val); + // @ts-ignore + this.processName = it.tableName; + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableProcess!.setCurrentHover(data); + } else { + this.tableProcess!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableProcess!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = ''; + this.tabName!.textContent = 'Statistic By Process AllDuration'; + this.pidData.unshift(this.processStatisticsData); + this.tableProcess!.recycleDataSource = this.pidData; + this.currentLevelData = JSON.parse(JSON.stringify(this.pidData)); + // @ts-ignore + this.pidData.shift(this.processStatisticsData); + this.tableProcess?.reMeauseHeight(); + this.tableProcess!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + typePieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.typeData, + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Type:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + this.clearData(); + this.tableType!.style.display = 'none'; + this.tableThread!.style.display = 'grid'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.getVirtualMemoryThread(it, val); + // @ts-ignore + this.typeName = it.tableName; + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName; + }, + hoverHandler: (data) => { + if (data) { + this.tableType!.setCurrentHover(data); + } else { + this.tableType!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableType!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + this.tabName!.textContent = 'Statistic By type AllDuration'; + this.typeData.unshift(this.typeStatisticsData); + this.tableType!.recycleDataSource = this.typeData; + this.currentLevelData = JSON.parse(JSON.stringify(this.typeData)); + // @ts-ignore + this.typeData.shift(this.typeStatisticsData); + this.tableType?.reMeauseHeight(); + this.tableType!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + threadPieChart(val: any) { + this.sumDur = this.threadStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.threadData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ThreadName:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'grid'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.getVirtualMemorySo(it, val); + // @ts-ignore + this.threadName = it.tableName; + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName + ' / ' + this.threadName; + } + }, + hoverHandler: (data) => { + if (data) { + this.tableThread!.setCurrentHover(data); + } else { + this.tableThread!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableThread!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName + ' / ' + this.typeName; + this.tabName!.textContent = 'Statistic By Thread AllDuration'; + this.threadData.unshift(this.threadStatisticsData); + this.tableThread!.recycleDataSource = this.threadData; + this.currentLevelData = JSON.parse(JSON.stringify(this.threadData)); + // @ts-ignore + this.threadData.shift(this.threadStatisticsData); + this.tableThread?.reMeauseHeight(); + this.tableThread!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + libraryPieChart(val: any) { + this.sumDur = this.libStatisticsData.allDuration; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.soData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Library:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'grid'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableFunction?.removeAttribute('hideDownload'); + this.getVirtualMemoryFunction(it, val); + this.pie?.hideTip(); + this.shadowRoot!.querySelector('.title')!.textContent = + // @ts-ignore + this.processName + ' / ' + this.typeName + ' / ' + this.threadName + ' / ' + it.tableName; + } + }, + hoverHandler: (data) => { + if (data) { + this.tableSo!.setCurrentHover(data); + } else { + this.tableSo!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableSo!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = + this.processName + ' / ' + this.typeName + ' / ' + this.threadName; + this.tabName!.textContent = 'Statistic By Library AllDuration'; + this.soData.unshift(this.libStatisticsData); + this.tableSo!.recycleDataSource = this.soData; + this.currentLevelData = JSON.parse(JSON.stringify(this.soData)); + // @ts-ignore + this.soData.shift(this.libStatisticsData); + this.tableSo?.reMeauseHeight(); + this.tableSo!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + let currentTable: LitTable | null | undefined; + switch (this.currentLevel) { + case 0: + currentTable = this.tableProcess; + break; + case 1: + currentTable = this.tableType; + break; + case 2: + currentTable = this.tableThread; + break; + case 3: + currentTable = this.tableSo; + break; + case 4: + currentTable = this.tableFunction; + break; + } + if (!currentTable) { + return; + } + if (sort == 0) { + currentTable!.recycleDataSource = this.currentLevelData; + } else { + let arr = [...this.currentLevelData]; + switch (this.currentLevel) { + case 0: + // @ts-ignore + arr.shift(this.processStatisticsData); + break; + case 1: + // @ts-ignore + arr.shift(this.typeStatisticsData); + break; + case 2: + // @ts-ignore + arr.shift(this.threadStatisticsData); + break; + case 3: + // @ts-ignore + arr.shift(this.libStatisticsData); + break; + case 4: + // @ts-ignore + arr.shift(this.functionStatisticsData); + break; + } + if (column == 'tableName') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.tableName > b.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } else { + if (b.tableName > a.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'durFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.duration - b.duration : b.duration - a.duration; + }); + } else if (column == 'percent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.duration - b.duration : b.duration - a.v; + }); + } + switch (this.currentLevel) { + case 0: + arr.unshift(this.processStatisticsData); + break; + case 1: + arr.unshift(this.typeStatisticsData); + break; + case 2: + arr.unshift(this.threadStatisticsData); + break; + case 3: + arr.unshift(this.libStatisticsData); + break; + case 4: + arr.unshift(this.functionStatisticsData); + break; + } + currentTable!.recycleDataSource = arr; + } + } + getVirtualMemoryProcess(val: any, result: Array) { + this.progressEL!.loading = true; + this.processData = JSON.parse(JSON.stringify(result)); + if (!this.processData || this.processData.length == 0) { + return; + } + let allDur = 0; + let pidMap = new Map>(); + for (let itemData of result) { + allDur += itemData.dur; + if (pidMap.has(itemData.pid)) { + pidMap.get(itemData.pid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + pidMap.set(itemData.pid, itemArray); + } + } + this.pidData = []; + pidMap.forEach((value: Array, key: string) => { + let dur = 0; + let pName = ''; + for (let item of value) { + pName = item.processName = + item.processName == null || item.processName == undefined + ? `Process(${item.pid})` + : `${item.processName}(${item.pid})`; + dur += item.dur; + } + const pidData = { + tableName: pName, + pid: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.pidData.push(pidData); + }); + this.pidData.sort((a, b) => b.duration - a.duration); + this.processStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 0; + this.progressEL!.loading = false; + this.processPieChart(val); + } + getVirtualMemoryType(item: any, val: any) { + this.progressEL!.loading = true; + let typeMap = new Map>(); + let pid = item.pid; + let allDur = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid) { + continue; + } + allDur += itemData.dur; + if (typeMap.has(itemData.type)) { + typeMap.get(itemData.type)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(itemData.type, itemArray); + } + } + this.typeData = []; + typeMap.forEach((value: Array, key: string) => { + let dur = 0; + for (let item of value) { + dur += item.dur; + } + const typeData = { + tableName: this.typeIdToString(key), + pid: item.pid, + type: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.typeData.push(typeData); + }); + this.typeData.sort((a, b) => b.duration - a.duration); + this.typeStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 1; + this.typePieChart(val); + this.progressEL!.loading = false; + } + getVirtualMemoryThread(item: any, val: any) { + this.progressEL!.loading = true; + let threadMap = new Map>(); + let pid = item.pid; + let type = item.type; + let allDur = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.type !== type) { + continue; + } + allDur += itemData.dur; + if (threadMap.has(itemData.tid)) { + threadMap.get(itemData.tid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + threadMap.set(itemData.tid, itemArray); + } + } + this.threadData = []; + threadMap.forEach((value: Array, key: string) => { + let dur = 0; + let tName = ''; + for (let item of value) { + dur += item.dur; + tName = item.threadName = + item.threadName == null || item.threadName == undefined ? `Thread(${item.tid})` : `${item.threadName}`; + } + const threadData = { + tableName: tName, + pid: item.pid, + type: item.type, + tid: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.threadData.push(threadData); + }); + this.threadData.sort((a, b) => b.duration - a.duration); + this.threadStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 2; + this.progressEL!.loading = false; + this.threadPieChart(val); + } + getVirtualMemorySo(item: any, val: any) { + this.progressEL!.loading = true; + let tid = item.tid; + let pid = item.pid; + let type = item.type; + let allDur = 0; + let libMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid || itemData.type !== type) { + continue; + } + allDur += itemData.dur; + if (libMap.has(itemData.libId)) { + libMap.get(itemData.libId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + libMap.set(itemData.libId, dataArray); + } + } + this.soData = []; + libMap.forEach((value: any[], key: number) => { + let dur = 0; + let libName = ''; + for (let item of value) { + dur += item.dur; + if (key == null) { + item.libName = 'unkown'; + } + libName = item.libName; + } + let libPath = libName?.split('/'); + if (libPath) { + libName = libPath[libPath.length - 1]; + } + const soData = { + tableName: libName, + pid: item.pid, + type: item.type, + tid: item.tid, + libId: key, + percent: ((dur / allDur) * 100).toFixed(2), + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.soData.push(soData); + }); + this.soData.sort((a, b) => b.duration - a.duration); + this.libStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 3; + this.progressEL!.loading = false; + this.libraryPieChart(val); + } + + getVirtualMemoryFunction(item: any, val: any) { + this.progressEL!.loading = true; + this.shadowRoot!.querySelector('.subheading')!.textContent = 'Statistic By Function AllDuration'; + let tid = item.tid; + let pid = item.pid; + let type = item.type; + let libId = item.libId; + let allDur = 0; + let symbolMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid || itemData.type !== type || itemData.libId !== libId) { + continue; + } + allDur += itemData.dur; + if (symbolMap.has(itemData.symbolId)) { + symbolMap.get(itemData.symbolId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + symbolMap.set(itemData.symbolId, dataArray); + } + } + this.functionData = []; + symbolMap.forEach((symbolItems, key) => { + let dur = 0; + let symbolName = ''; + for (let symbolItem of symbolItems) { + symbolName = symbolItem.symbolName; + dur += symbolItem.dur; + } + let symbolPath = symbolName?.split('/'); + if (symbolPath) { + symbolName = symbolPath[symbolPath.length - 1]; + } + const symbolData = { + pid: item.pid, + tid: item.tid, + percent: ((dur / allDur) * 100).toFixed(2), + tableName: symbolName, + durFormat: Utils.getProbablyTime(dur), + duration: dur, + }; + this.functionData.push(symbolData); + }); + this.functionData.sort((a, b) => b.duration - a.duration); + this.functionStatisticsData = this.totalDurationData(allDur); + this.currentLevel = 4; + this.sumDur = this.libStatisticsData.allDuration; + this.progressEL!.loading = false; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.functionData), + angleField: 'duration', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Function:${obj.obj.tableName}
+
Duration:${obj.obj.durFormat}
+
percent:${obj.obj.percent}
+
+ `; + }, + hoverHandler: (data) => { + if (data) { + this.tableFunction!.setCurrentHover(data); + } else { + this.tableFunction!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableFunction!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.functionData.unshift(this.functionStatisticsData); + this.tableFunction!.recycleDataSource = this.functionData; + this.tableFunction?.reMeauseHeight(); + this.currentLevelData = JSON.parse(JSON.stringify(this.functionData)); + // @ts-ignore + this.functionData.shift(this.functionStatisticsData); + this.tableFunction!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + typeIdToString(type: any) { + let releaseType: any; + if (type == 1) { + releaseType = 'File Backed In'; + } else if (type == 7) { + releaseType = 'Copy On Writer'; + } + return releaseType; + } + totalDurationData(duration: any) { + let allDuration; + allDuration = { + durFormat: Utils.getProbablyTime(duration), + percent: ((duration / duration) * 100).toFixed(2), + tableName: '', + duration: 0, + }; + return allDuration; + } + getPieChartData(res: any[]) { + if (res.length > 20) { + let pieChartArr: any[] = []; + let other: any = { + tableName: 'other', + duration: 0, + percent: 0, + durFormat: 0, + }; + for (let i = 0; i < res.length; i++) { + if (i < 19) { + pieChartArr.push(res[i]); + } else { + other.duration += res[i].duration; + other.durFormat = Utils.getProbablyTime(other.duration); + other.percent = ((other.duration / this.sumDur) * 100).toFixed(2); + } + } + pieChartArr.push(other); + return pieChartArr; + } + return res; + } + + getDataByWorker(args: any[], handler: Function) { + procedurePool.submitWithName( + 'logic0', + 'fileSystem-action', + { args, callType: 'virtualMemory', isAnalysis: true }, + undefined, + (results: any) => { + handler(results); + this.progressEL!.loading = false; + } + ); + } + + initHtml(): string { + return ` + + +
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + +
+ +
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/fps/TabPaneFps.ts b/ide/src/trace/component/trace/sheet/fps/TabPaneFps.ts new file mode 100644 index 0000000000000000000000000000000000000000..4ff9e8afcf066daf4ee0cfd330f56274c777c5f9 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/fps/TabPaneFps.ts @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabFps } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-fps') +export class TabPaneFps extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + + set data(val: SelectionParam | any) { + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + getTabFps(val.leftNs, val.rightNs).then((result) => { + if (result != null && result.length > 0) { + log('getTabFps result size : ' + result.length); + + let index = result.findIndex((d) => d.startNS >= val.leftNs); + if (index != -1) { + let arr = result.splice(index > 0 ? index - 1 : index); + arr.map((e) => (e.timeStr = Utils.getTimeString(e.startNS))); + this.tbl!.recycleDataSource = arr; + } else { + let last = result[result.length - 1]; + last.timeStr = Utils.getTimeString(last.startNS); + this.tbl!.recycleDataSource = [last]; + } + } else { + this.tbl!.recycleDataSource = []; + } + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-fps'); + this.range = this.shadowRoot?.querySelector('#time-range'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/freq/TabPaneCpuFreqLimits.ts b/ide/src/trace/component/trace/sheet/freq/TabPaneCpuFreqLimits.ts new file mode 100644 index 0000000000000000000000000000000000000000..f28a4b85f39603ebd07a7ee92e44880358643a18 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/freq/TabPaneCpuFreqLimits.ts @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { Utils } from '../../base/Utils.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; +import { CpuFreqLimitsStruct } from '../../../../database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; + +@element('tabpane-cpu-freq-limits') +export class TabPaneCpuFreqLimits extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private loadDataInCache: boolean = true; + private selectionParam: SelectionParam | null | undefined; + private source: CpuFreqLimit[] = []; + private sortKey: string = 'cpu'; + private sortType: number = 0; + + set data(val: SelectionParam | any) { + if (val == this.selectionParam) { + return; + } + this.selectionParam = val; + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + let list: any[] = []; + val.cpuFreqLimitDatas.forEach((limitRowDatas: any) => { + for (let i = 0, len = limitRowDatas.length; i < len; i++) { + let it = limitRowDatas[i]; + if (it.startNs > val.rightNs) { + break; + } + if (i === limitRowDatas.length - 1) { + it.dur = (val.rightNs || 0) - (it.startNs || 0); + } else { + it.dur = (limitRowDatas[i + 1].startNs || 0) - (it.startNs || 0); + } + list.push(it); + } + }); + this.formatData(list, val.leftNs, val.rightNs); + } + + initElements(): void { + this.tbl = this.shadowRoot!.querySelector('#tb-states'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement!.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot!.querySelector('.table').style.height = this.parentElement!.clientHeight - 25 + 'px'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + formatData(list: CpuFreqLimitsStruct[], start: number, end: number) { + let limitsMap = new Map(); + let groupMapData = (time: number, id: string, item: CpuFreqLimitsStruct) => { + if (limitsMap.has(id)) { + limitsMap.get(id)!.time += time; + } else { + let isMax = id.endsWith('max'); + let limit = new CpuFreqLimit(); + limit.cpu = `Cpu ${item.cpu}`; + limit.time = time; + limit.type = isMax ? 'Max Freqency' : 'Min Frequency'; + limit.value = isMax ? item.max! : item.min!; + limitsMap.set(id, limit); + } + }; + list.forEach((item) => { + if (item.startNs! > end) { + return; + } + let max = Math.max(item.startNs || 0, start); + let min = Math.min((item.startNs || 0) + item.dur, end); + if (max < min) { + let maxId = `${item.cpu}-${item.max}-max`; + let minId = `${item.cpu}-${item.min}-min`; + groupMapData(min - max, maxId, item); + groupMapData(min - max, minId, item); + } + }); + this.source = Array.from(limitsMap.values()).map((item) => { + item.timeStr = Utils.getProbablyTime(item.time); + item.valueStr = `${ColorUtils.formatNumberComma(item.value!)} kHz`; + return item; + }); + this.sortTable(this.sortKey, this.sortType); + } + + sortTable(key: string, type: number) { + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'timeStr') { + if (type == 1) { + return a.time - b.time; + } else { + return b.time - a.time; + } + } else if (key == 'valueStr') { + if (type == 1) { + return a.value - b.value; + } else { + return b.value - a.value; + } + } else if (key == 'cpu') { + if (a.cpu > b.cpu) { + return type === 2 ? -1 : 1; + } else if (a.cpu == b.cpu) { + return 0; + } else { + return type === 2 ? 1 : -1; + } + } else if (key == 'type') { + if (a.type > b.type) { + return type === 2 ? 1 : -1; + } else if (a.type == b.type) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } + + initHtml(): string { + return ` + + + + + + + + + + + + `; + } +} + +class CpuFreqLimit { + cpu: string = ''; + type: string = ''; + time: number = 0; + value: number = 0; + timeStr: string = ''; + valueStr: string = ''; +} diff --git a/ide/src/trace/component/trace/sheet/freq/TabPaneFreq.ts b/ide/src/trace/component/trace/sheet/freq/TabPaneFreq.ts new file mode 100644 index 0000000000000000000000000000000000000000..26849f5aaa9fe85ac8145369491d0cbf01d78ad1 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/freq/TabPaneFreq.ts @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-freq') +export class TabPaneFreq extends BaseElement { + private tbl: LitTable | null | undefined; + + set data(freq: any) { + if (freq) { + this.tbl!.dataSource = [ + { + startNS: Utils.getTimeString(freq.startNS >= 0 ? freq.startNS : 0), + absoluteTime: (freq.startNS + (window as any).recordStartNS) / 1000000000, + dur: Utils.getProbablyTime(freq.dur), + freq: `${ColorUtils.formatNumberComma(freq.value!)} kHz`, + cpu: `Cpu ${freq.cpu}`, + }, + ]; + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-freq'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/freq/TabPaneFreqLimit.ts b/ide/src/trace/component/trace/sheet/freq/TabPaneFreqLimit.ts new file mode 100644 index 0000000000000000000000000000000000000000..ce59b53a4cf6770269b074ee03e50da26e281b85 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/freq/TabPaneFreqLimit.ts @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { ColorUtils } from '../../base/ColorUtils.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-freq-limit') +export class TabPaneFreqLimit extends BaseElement { + private tbl: LitTable | null | undefined; + + set data(freq: any) { + if (freq) { + this.tbl!.dataSource = [ + { + startNs: Utils.getTimeString(freq.startNs >= 0 ? freq.startNs : 0), + absoluteTime: (freq.startNs + (window as any).recordStartNS) / 1000000000, + dur: Utils.getProbablyTime(freq.dur), + maxFreq: `${ColorUtils.formatNumberComma(freq.max!)} kHz`, + minFreq: `${ColorUtils.formatNumberComma(freq.min!)} kHz`, + cpu: `Cpu ${freq.cpu}`, + }, + ]; + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-freq'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..66462b19413161ffde973c64c769110870dca154 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.ts @@ -0,0 +1,855 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../../../base-ui/chart/pie/LitChartPie.js'; +import { queryHiPerfProcessCount, queryPerfProcess } from '../../../../database/SqlLite.js'; +import { PerfThread } from '../../../../bean/PerfProfile.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-perf-analysis') +export class TabPanePerfAnalysis extends BaseElement { + private currentSelection: SelectionParam | any; + private pie: LitChartPie | null | undefined; + private processData!: Array; + private threadDataMap?: Map; + private pidData!: any[]; + private threadData!: any[]; + private soData!: any[]; + private functionData!: any[]; + private tableThread: LitTable | null | undefined; + private tableProcess: LitTable | null | undefined; + private tableSo: LitTable | null | undefined; + private tableFunction: LitTable | null | undefined; + private sumCount: any; + private range: HTMLLabelElement | null | undefined; + private processMap: Map = new Map(); + private back: HTMLDivElement | null | undefined; + private tabName: HTMLDivElement | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private processName: any; + private threadName: any; + private callChainMap!: Map; + private sortColumn: string = ''; + private sortType: number = 0; + private allProcessCount!: any; + private allThreadCount!: any; + private allLibCount!: any; + private allSymbolCount!: any; + private currentLevel = -1; + private currentLevelData!: Array; + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + this.pidData.unshift(this.allProcessCount); + this.tableProcess!.recycleDataSource = this.pidData; + // @ts-ignore + this.pidData.shift(this.allProcessCount); + return; + } + this.clearData(); + this.currentSelection = val; + this.tableProcess!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + if (!this.callChainMap) { + this.getCallChainDataFromWorker(); + } + queryPerfProcess().then((result) => { + let processes = result; + for (let process of processes) { + this.processMap.set(process.pid, process); + } + }); + this.getHiperfProcess(val); + } + initElements(): void { + this.range = this.shadowRoot?.querySelector('#time-range'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.tableProcess = this.shadowRoot!.querySelector('#tb-process-usage'); + this.tableSo = this.shadowRoot!.querySelector('#tb-so-usage'); + this.tableFunction = this.shadowRoot!.querySelector('#tb-function-usage'); + this.tableThread = this.shadowRoot!.querySelector('#tb-thread-usage'); + this.back = this.shadowRoot!.querySelector('.go-back'); + this.tabName = this.shadowRoot!.querySelector('.subheading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.getBack(); + } + + clearData() { + this.pie!.dataSource = []; + this.tableProcess!.recycleDataSource = []; + this.tableThread!.recycleDataSource = []; + this.tableSo!.recycleDataSource = []; + this.tableFunction!.recycleDataSource = []; + } + + getBack() { + this.back!.addEventListener('click', () => { + if (this.tabName!.textContent === 'Statistic By Thread Count') { + this.tableProcess!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableProcess?.removeAttribute('hideDownload'); + this.back!.style.visibility = 'hidden'; + this.currentLevel = 0; + this.currentLevelData = this.pidData; + this.processPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Library Count') { + this.tableThread!.style.display = 'grid'; + this.tableSo!.style.display = 'none'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.currentLevel = 1; + this.currentLevelData = this.threadData; + this.threadPieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Function Count') { + this.tableSo!.style.display = 'grid'; + this.tableFunction!.style.display = 'none'; + this.tableFunction!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.currentLevel = 2; + this.currentLevelData = this.soData; + this.libraryPieChart(this.currentSelection); + } + }); + } + processPieChart(val: any) { + this.sumCount = this.allProcessCount.allCount; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.pidData), + angleField: 'count', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ProcessName:${obj.obj.tableName}
+
Count:${obj.obj.countFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableProcess!.style.display = 'none'; + this.tableThread!.style.display = 'grid'; + this.tableProcess!.setAttribute('hideDownload', ''); + this.tableThread?.removeAttribute('hideDownload'); + this.getHiperfThread(it, val); + // @ts-ignore + this.shadowRoot!.querySelector('.title')!.textContent = it.tableName; + // @ts-ignore + this.processName = it.tableName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableProcess!.setCurrentHover(data); + } else { + this.tableProcess!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableProcess!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = ''; + this.tabName!.textContent = 'Statistic By Process Count'; + this.pidData.unshift(this.allProcessCount); + this.tableProcess!.recycleDataSource = this.pidData; + this.currentLevelData = JSON.parse(JSON.stringify(this.pidData)); + // @ts-ignore + this.pidData.shift(this.allProcessCount); + this.tableProcess?.reMeauseHeight(); + this.tableProcess!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + threadPieChart(val: any) { + if (val.perfThread.length > 0 && val.perfProcess.length == 0) { + this.back!.style.visibility = 'hidden'; + this.shadowRoot!.querySelector('.title')!.textContent = ''; + this.tableThread!.style.display = 'grid'; + } else { + this.shadowRoot!.querySelector('.title')!.textContent = this.processName; + } + this.sumCount = this.allThreadCount.allCount; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.threadData), + angleField: 'count', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
ThreadName:${obj.obj.tableName}
+
Count:${obj.obj.countFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'grid'; + this.tableThread!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.getHiperfSo(it, val); + this.shadowRoot!.querySelector('.title')!.textContent = + // @ts-ignore + this.processName + ' / ' + it.tableName; + // @ts-ignore + this.threadName = it.tableName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableThread!.setCurrentHover(data); + } else { + this.tableThread!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableThread!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.tableThread!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + this.tabName!.textContent = 'Statistic By Thread Count'; + this.threadData.unshift(this.allThreadCount); + this.tableThread!.recycleDataSource = this.threadData; + this.currentLevelData = JSON.parse(JSON.stringify(this.threadData)); + // @ts-ignore + this.threadData.shift(this.allThreadCount); + this.tableThread?.reMeauseHeight(); + } + libraryPieChart(val: any) { + this.sumCount = this.allLibCount.allCount; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.soData), + angleField: 'count', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Library:${obj.obj.tableName}
+
Count:${obj.obj.countFormat}
+
Percent:${obj.obj.percent}%
+
+ `; + }, + angleClick: (it) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'grid'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableFunction?.removeAttribute('hideDownload'); + this.getHiperfFunction(it, val); + this.shadowRoot!.querySelector('.title')!.textContent = + // @ts-ignore + this.processName + ' / ' + this.threadName + ' / ' + it.tableName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableSo!.setCurrentHover(data); + } else { + this.tableSo!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableSo!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.processName + ' / ' + this.threadName; + this.tabName!.textContent = 'Statistic By Library Count'; + this.soData.unshift(this.allLibCount); + this.tableSo!.recycleDataSource = this.soData; + this.currentLevelData = JSON.parse(JSON.stringify(this.soData)); + // @ts-ignore + this.soData.shift(this.allLibCount); + this.tableSo?.reMeauseHeight(); + this.tableSo!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + let currentTable: LitTable | null | undefined; + switch (this.currentLevel) { + case 0: + currentTable = this.tableProcess; + break; + case 1: + currentTable = this.tableThread; + break; + case 2: + currentTable = this.tableSo; + break; + case 3: + currentTable = this.tableFunction; + break; + } + if (!currentTable) { + return; + } + if (sort == 0) { + currentTable!.recycleDataSource = this.currentLevelData; + } else { + let arr = [...this.currentLevelData]; + switch (this.currentLevel) { + case 0: + // @ts-ignore + arr.shift(this.allProcessCount); + break; + case 1: + // @ts-ignore + arr.shift(this.allThreadCount); + break; + case 2: + // @ts-ignore + arr.shift(this.allLibCount); + break; + case 3: + // @ts-ignore + arr.shift(this.allSymbolCount); + break; + } + if (column == 'tableName') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.tableName > b.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } else { + if (b.tableName > a.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'countFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.count - b.count : b.count - a.count; + }); + } else if (column == 'percent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.count - b.count : b.count - a.count; + }); + } + switch (this.currentLevel) { + case 0: + arr.unshift(this.allProcessCount); + break; + case 1: + arr.unshift(this.allThreadCount); + break; + case 2: + arr.unshift(this.allLibCount); + break; + case 3: + arr.unshift(this.allSymbolCount); + break; + } + currentTable!.recycleDataSource = arr; + } + } + async getHiperfProcess(val: any) { + this.progressEL!.loading = true; + await queryHiPerfProcessCount( + val.leftNs, + val.rightNs, + val.perfAll ? [] : val.perfCpus, + val.perfThread, + val.perfProcess + ).then((result) => { + this.processData = result; + this.processData = JSON.parse(JSON.stringify(result)); + if (!this.processData || this.processData.length == 0) { + return; + } + let allCount = 0; + let pidMap = new Map>(); + if (val.perfThread.length > 0 && val.perfProcess.length == 0) { + this.tableProcess!.style.display = 'none'; + this.getHiperfThread(this.processData[0], val); + } else { + for (let itemData of result) { + allCount++; + if (pidMap.has(itemData.pid)) { + pidMap.get(itemData.pid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + pidMap.set(itemData.pid, itemArray); + } + } + this.pidData = []; + pidMap.forEach((value: Array, key: string) => { + let count = 0; + let pName = ''; + for (let item of value) { + let process = this.processMap.get(item.pid); + pName = item.processName = + process == null || process == undefined + ? `Process(${item.pid})` + : `${process!.processName || 'Process'}(${item.pid})`; + count++; + } + const pidData = { + tableName: pName, + pid: key, + percent: ((count / allCount) * 100).toFixed(2), + countFormat: Utils.timeMsFormat2p(count), + count: count, + }; + this.pidData.push(pidData); + }); + this.pidData.sort((a, b) => b.count - a.count); + this.allProcessCount = this.totalCountData(allCount); + this.currentLevel = 0; + this.progressEL!.loading = false; + this.processPieChart(val); + } + }); + } + getHiperfThread(item: any, val: any) { + this.progressEL!.loading = true; + this.threadDataMap = new Map(); + let threadMap = new Map>(); + let pid = item.pid; + let allCount = 0; + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid) { + continue; + } + allCount++; + if (threadMap.has(itemData.tid)) { + threadMap.get(itemData.tid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + threadMap.set(itemData.tid, itemArray); + } + } + this.threadData = []; + threadMap.forEach((value: Array, key: string) => { + let threadCount = 0; + let tName = ''; + for (let item of value) { + threadCount++; + tName = + item.threadName == null || item.threadName == undefined + ? `Thread(${item.tid})` + : `${item.threadName}(${item.tid})`; + } + const threadData = { + pid: item.pid, + tid: key, + tableName: tName, + countFormat: Utils.timeMsFormat2p(threadCount), + count: threadCount, + percent: ((threadCount / allCount) * 100).toFixed(2), + }; + this.threadData.push(threadData); + }); + this.allThreadCount = this.totalCountData(allCount); + this.currentLevel = 1; + this.threadData.sort((a, b) => b.count - a.count); + this.progressEL!.loading = false; + this.threadPieChart(val); + } + getHiperfSo(item: any, val: any) { + this.progressEL!.loading = true; + let parentCount = item.count; + let tid = item.tid; + let pid = item.pid; + let allCount = 0; + let libMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid) { + continue; + } + let lastLibCallChain = this.callChainMap!.get(itemData.callchain_id); + if (!lastLibCallChain) { + continue; + } + allCount++; + if (libMap.has(lastLibCallChain.fileId)) { + libMap.get(lastLibCallChain.fileId)?.push(lastLibCallChain); + } else { + let dataArray = new Array(); + dataArray.push(lastLibCallChain); + libMap.set(lastLibCallChain.fileId, dataArray); + } + } + this.soData = []; + libMap.forEach((libItems, libId) => { + let libCount = 0; + let libName = ''; + for (let libItem of libItems) { + libCount++; + libName = libItem.path; + } + let libPath = libName?.split('/'); + if (libPath) { + libName = libPath[libPath.length - 1]; + } + const libData = { + pid: item.pid, + tid: item.tid, + percent: ((libCount / parentCount) * 100).toFixed(2), + countFormat: Utils.timeMsFormat2p(libCount), + count: libCount, + tableName: libName, + libId: libId, + }; + this.soData.push(libData); + }); + this.allLibCount = this.totalCountData(allCount); + this.soData.sort((a, b) => b.count - a.count); + this.currentLevel = 2; + this.progressEL!.loading = false; + this.libraryPieChart(val); + } + getHiperfFunction(item: any, val: any) { + this.progressEL!.loading = true; + this.shadowRoot!.querySelector('.subheading')!.textContent = 'Statistic By Function Count'; + let parentCount = item.count; + let tid = item.tid; + let pid = item.pid; + let libId = item.libId; + let allCount = 0; + let symbolMap = new Map>(); + if (!this.processData || this.processData.length == 0) { + return; + } + for (let itemData of this.processData) { + if (itemData.pid !== pid || itemData.tid !== tid) { + continue; + } + let dataCallChain = this.callChainMap!.get(itemData.callchain_id); + if (!dataCallChain || dataCallChain.fileId !== libId) { + continue; + } + allCount++; + if (symbolMap.has(dataCallChain.symbolId)) { + symbolMap.get(dataCallChain.symbolId)?.push(dataCallChain); + } else { + let dataArray = new Array(); + dataArray.push(dataCallChain); + symbolMap.set(dataCallChain.symbolId, dataArray); + } + } + this.functionData = []; + symbolMap.forEach((symbolItems, symbolId) => { + let symbolCount = 0; + let symbolName = ''; + for (let symbolItem of symbolItems) { + symbolCount++; + symbolName = symbolItem.name; + } + let symbolPath = symbolName?.split('/'); + if (symbolPath) { + symbolName = symbolPath[symbolPath.length - 1]; + } + const symbolData = { + pid: item.pid, + tid: item.tid, + percent: ((symbolCount / parentCount) * 100).toFixed(2), + countFormat: Utils.timeMsFormat2p(symbolCount), + count: symbolCount, + tableName: symbolName, + }; + this.functionData.push(symbolData); + }); + this.functionData.sort((a, b) => b.count - a.count); + this.allSymbolCount = this.totalCountData(allCount); + this.currentLevel = 3; + this.progressEL!.loading = false; + this.sumCount = this.allSymbolCount.allCount; + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.functionData), + angleField: 'count', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Function:${obj.obj.tableName}
+
Count:${obj.obj.countFormat}
+
Percent:${obj.obj.percent}%
+
`; + }, + hoverHandler: (data) => { + if (data) { + this.tableFunction!.setCurrentHover(data); + } else { + this.tableFunction!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableFunction!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.functionData.unshift(this.allSymbolCount); + this.tableFunction!.recycleDataSource = this.functionData; + this.currentLevelData = JSON.parse(JSON.stringify(this.functionData)); + // @ts-ignore + this.functionData.shift(this.allSymbolCount); + this.tableFunction?.reMeauseHeight(); + this.tableFunction!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + totalCountData(count: any) { + let allCount; + allCount = { + countFormat: Utils.timeMsFormat2p(count), + percent: ((count / count) * 100).toFixed(2), + count: 0, + allCount: count, + pid: '', + }; + return allCount; + } + + getPieChartData(res: any[]) { + if (res.length > 20) { + let pieChartArr: any[] = []; + let other: any = { + tableName: 'other', + count: 0, + percent: 0, + countFormat: 0, + }; + for (let i = 0; i < res.length; i++) { + if (i < 19) { + pieChartArr.push(res[i]); + } else { + other.count += res[i].count; + other.countFormat = Utils.timeMsFormat2p(other.count); + other.percent = ((other.count / this.sumCount) * 100).toFixed(2); + } + } + pieChartArr.push(other); + return pieChartArr; + } + return res; + } + getCallChainDataFromWorker() { + this.getDataByWorker([], (results: any) => { + this.callChainMap = results; + }); + } + getDataByWorker(args: any[], handler: Function) { + this.progressEL!.loading = true; + procedurePool.submitWithName('logic0', 'perf-queryPerfAnalysisCallChain', args, undefined, (results: any) => { + handler(results); + this.progressEL!.loading = false; + }); + } + + initHtml(): string { + return ` + + +
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + + +
+ +
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..97de60238b8cd91fc906b692fe864291f06b09ac --- /dev/null +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfProfile.ts @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import '../TabPaneFilter.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { PerfCallChainMerageData } from '../../../../bean/PerfProfile.js'; +import '../../../chart/FrameChart.js'; +import { FrameChart } from '../../../chart/FrameChart.js'; +import { ChartMode } from '../../../../bean/FrameChartStruct.js'; +import '../../../DisassemblingWindow.js'; +import { DisassemblingWindow } from '../../../DisassemblingWindow.js'; +import { Cmd } from '../../../../../command/Cmd.js'; +import { SpApplication } from '../../../../SpApplication.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { query, queryPerfSampleIdsByTimeRange } from '../../../../database/SqlLite.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { SpHiPerf } from '../../../chart/SpHiPerf.js'; + +@element('tabpane-perf-profile') +export class TabpanePerfProfile extends BaseElement { + private tbl: LitTable | null | undefined; + private tbr: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private rightSource: Array = []; + private filter: any; + private dataSource: any[] = []; + private sortKey = 'weight'; + private sortType = 0; + private currentSelectedData: any = undefined; + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private systmeRuleName = '/system/'; + private numRuleName = '/max/min/'; + private modal: DisassemblingWindow | null | undefined; + private needShowMenu = true; + private searchValue: string = ''; + private loadingList: number[] = []; + private loadingPage: any; + private currentSelection: SelectionParam | undefined; + private isCurrentIsTopDown: boolean = true; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.searchValue = ''; + this.currentSelection = val; + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + if (this.parentElement!.clientHeight > this.filter!.clientHeight) { + this.filter!.style.display = 'flex'; + } else { + this.filter!.style.display = 'none'; + } + this.filter!.initializeFilterTree(true, true, true); + this.filter!.filterValue = ''; + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + this.isCurrentIsTopDown = true; + this.getDataByWorker( + [ + { + funcName: 'setSearchValue', + funcArgs: [''], + }, + { + funcName: 'getCurrentDataFromDb', + funcArgs: [val], + }, + ], + (results: any[]) => { + this.setLTableData(results); + this.tbr!.recycleDataSource = []; + this.frameChart!.mode = ChartMode.Count; + this.frameChart!.data = this.dataSource; + this.frameChart?.updateCanvas(true, this.clientWidth); + this.frameChart?.calculateChartData(); + } + ); + } + + getParentTree( + src: Array, + target: PerfCallChainMerageData, + parents: Array + ): boolean { + for (let call of src) { + if (call.id == target.id) { + parents.push(call); + return true; + } else { + if (this.getParentTree(call.children as Array, target, parents)) { + parents.push(call); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, id: string, children: Array): boolean { + for (let call of src) { + if (call.id == id && call.children.length == 0) { + children.push(call); + return true; + } else { + if (this.getChildTree(call.children as Array, id, children)) { + children.push(call); + return true; + } + } + } + return false; + } + + setRightTableData(call: PerfCallChainMerageData) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.dataSource, call, parents); + let maxId = call.id; + let maxDur = 0; + + function findMaxStack(call: PerfCallChainMerageData) { + if (call.children.length == 0) { + if (call.dur > maxDur) { + maxDur = call.dur; + maxId = call.id; + } + } else { + call.children.map((callChild) => { + findMaxStack(callChild); + }); + } + } + + findMaxStack(call); + this.getChildTree(call.children as Array, maxId, children); + let arr = parents.reverse().concat(children.reverse()); + for (let data of arr) { + data.type = + data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1; + } + let len = arr.length; + this.rightSource = arr; + let rightSource: Array = []; + if (len != 0) { + rightSource = this.rightSource.filter((item) => { + return item.canCharge; + }); + } + this.tbr!.dataSource = rightSource; + } + + showButtomMenu(isShow: boolean) { + if (isShow) { + this.filter.setAttribute('tree', ''); + this.filter.setAttribute('input', ''); + this.filter.setAttribute('inputLeftText', ''); + } else { + this.filter.removeAttribute('tree'); + this.filter.removeAttribute('input'); + this.filter.removeAttribute('inputLeftText'); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-perf-profile'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + this.modal = this.shadowRoot?.querySelector('tab-native-data-modal'); + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.frameChart!.addChartClickListener((needShowMenu: boolean) => { + this.parentElement!.scrollTo(0, 0); + this.showButtomMenu(needShowMenu); + this.needShowMenu = needShowMenu; + }); + this.tbl!.rememberScrollTop = true; + this.filter = this.shadowRoot?.querySelector('#filter'); + this.tbl!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as PerfCallChainMerageData; + this.setRightTableData(data); + data.isSelected = true; + this.currentSelectedData = data; + this.tbr?.clearAllSelection(data); + this.tbr?.setCurrentSelection(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.tbr = this.shadowRoot?.querySelector('#tb-perf-list'); + let lastClikTime = 0; + this.tbr!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as PerfCallChainMerageData; + this.tbl?.clearAllSelection(data); + (data as any).isSelected = true; + this.tbl!.scrollToData(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + let spApplication = document.getElementsByTagName('sp-application')[0]; + if (Date.now() - lastClikTime < 200 && spApplication.vs) { + this.tbl!.style.visibility = 'hidden'; + this.filter.style.display = 'none'; + new ResizeObserver((entries) => { + this.modal!.style.width = this.tbl!.clientWidth + 'px'; + this.modal!.style.height = this.tbl!.clientHeight + 'px'; + }).observe(this.tbl!); + this.modal!.showLoading(); + // @ts-ignore + let data = evt.detail.data as PerfCallChainMerageData; + let path = data.path; + let addr = data.vaddrInFile; + let addrHex = addr.toString(16); + if (path.trim() === '[kernel.kallsyms]') { + this.modal?.showContent(`error : Symbol ${data.symbol} lib is [kernel.kallsyms] ,not support `, addrHex); + } else if (path.trim() === '') { + this.modal?.showContent(`error : Symbol ${data.symbol} lib is null `, addrHex); + } else if (addr < 0) { + this.modal?.showContent(`error : Symbol ${data.symbol} current addr is error ` + addrHex, addrHex); + } else { + const binDir = 'C:/binary_cache'; + let binPath = binDir + path; + let cmd = 'C:/binary_cache/llvm-objdump.exe -S ' + binPath; + Cmd.execObjDump(cmd, addrHex, (result: any) => { + this.modal?.showContent(result, addrHex); + }); + } + } + lastClikTime = Date.now(); + }); + this.modal!.setCloseListener(() => { + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + this.shadowRoot!.querySelector('#filter')!.style.display = 'flex'; + }); + this.tbr = this.shadowRoot?.querySelector('#tb-perf-list'); + let filterFunc = (data: any) => { + let args: any[] = []; + if (data.type == 'check') { + if (data.item.checked) { + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + } + } else if (data.type == 'select') { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else if (data.type == 'button') { + if (data.item == 'symbol') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined) { + this.filter!.addDataMining({ name: this.currentSelectedData.symbolName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.symbolName, false, true], + }); + } else { + return; + } + } else if (data.item == 'library') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined && this.currentSelectedData.libName != '') { + this.filter!.addDataMining({ name: this.currentSelectedData.libName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.libName, false, false], + }); + } else { + return; + } + } else if (data.item == 'restore') { + if (data.remove != undefined && data.remove.length > 0) { + let list = data.remove.map((item: any) => { + return item.name; + }); + args.push({ + funcName: 'resotreAllNode', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + list.forEach((symbolName: string) => { + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [symbolName], + }); + }); + } + } + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + this.tbl!.move1px(); + if (this.currentSelectedData) { + this.currentSelectedData.isSelected = false; + this.tbl?.clearAllSelection(this.currentSelectedData); + this.tbr!.recycleDataSource = []; + this.currentSelectedData = undefined; + } + }); + }; + this.filter!.getDataLibrary(filterFunc); + this.filter!.getDataMining(filterFunc); + this.filter!.getCallTreeData((data: any) => { + if (data.value == 0) { + this.refreshAllNode({ + ...this.filter!.getFilterTreeData(), + callTree: data.checks, + }); + } else { + let args: any[] = []; + if (data.checks[1]) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[this.systmeRuleName]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [this.systmeRuleName], + }); + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + }); + this.filter!.getCallTreeConstraintsData((data: any) => { + let args: any[] = [ + { + funcName: 'resotreAllNode', + funcArgs: [[this.numRuleName]], + }, + { + funcName: 'clearSplitMapData', + funcArgs: [this.numRuleName], + }, + ]; + if (data.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(data.min), data.max], + }); + } + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + }); + this.filter!.getFilterData((data: FilterData) => { + if (this.searchValue != this.filter!.filterValue) { + this.searchValue = this.filter!.filterValue; + let args = [ + { + funcName: 'setSearchValue', + funcArgs: [this.searchValue], + }, + { + funcName: 'resetAllNode', + funcArgs: [], + }, + ]; + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + this.switchFlameChart(data); + }); + } else { + this.switchFlameChart(data); + } + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.setLTableData(this.dataSource); + this.frameChart!.data = this.dataSource; + }); + } + + connectedCallback() { + super.connectedCallback(); + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + this.modal!.style.height = this.tbl!.clientHeight - 2 + 'px'; //2 is borderWidth + if (this.tbl!.style.visibility == 'hidden') { + tabPaneFilter.style.display = 'none'; + } + if (this.parentElement?.clientHeight != 0) { + if (this.isChartShow) { + this.frameChart?.updateCanvas(false, entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 35 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tbr?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 - 21 + 'px'; + this.tbr?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + switchFlameChart(data: any) { + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); + if (data.icon == 'block') { + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + this.filter!.disabledMining = true; + this.showButtomMenu(this.needShowMenu); + this.frameChart!.data = this.dataSource; + this.frameChart?.calculateChartData(); + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.showButtomMenu(true); + this.isChartShow = false; + this.filter!.disabledMining = false; + this.frameChart!.clearCanvas(); + this.tbl!.reMeauseHeight(); + } + } + + refreshAllNode(filterData: any) { + let args: any[] = []; + let isTopDown: boolean = !filterData.callTree[0]; + this.isCurrentIsTopDown = isTopDown; + let isHideSystemLibrary = filterData.callTree[1]; + let list = filterData.dataMining.concat(filterData.dataLibrary); + args.push({ + funcName: 'getCallChainsBySampleIds', + funcArgs: [isTopDown], + }); + this.tbr!.recycleDataSource = []; + if (isHideSystemLibrary) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + } + if (filterData.callTreeConstraints.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]], + }); + } + args.push({ + funcName: 'splitAllProcess', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + + setLTableData(resultData: any[]) { + this.dataSource = this.sortTree(resultData); + this.tbl!.recycleDataSource = this.dataSource; + } + + sortTree(arr: Array): Array { + let sortArr = arr.sort((a, b) => { + if (this.sortKey == 'self') { + if (this.sortType == 0) { + return b.dur - a.dur; + } else if (this.sortType == 1) { + return a.selfDur - b.selfDur; + } else { + return b.selfDur - a.selfDur; + } + } else { + if (this.sortType == 0) { + return b.dur - a.dur; + } else if (this.sortType == 1) { + return a.dur - b.dur; + } else { + return b.dur - a.dur; + } + } + }); + sortArr.map((call) => { + call.children = this.sortTree(call.children); + }); + return sortArr; + } + + getDataByWorker(args: any[], handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName('logic0', 'perf-action', args, undefined, (results: any) => { + handler(results); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + }); + } + + initHtml(): string { + return ` + +
+ + + +
+ + + + + + + + +
+ + + Heaviest Stack Trace + + + + + +
+ + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/hiperf/TabPerfSampleList.ts b/ide/src/trace/component/trace/sheet/hiperf/TabPerfSampleList.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d12aee332ec2da5e70b0fdd3c8c7fe1ada10da2 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/hiperf/TabPerfSampleList.ts @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { perfDataQuery } from '../../../chart/PerfDataQuery.js'; +import { + queryPerfProcess, + queryPerfSampleCallChain, + queryPerfSampleListByTimeRange, +} from '../../../../database/SqlLite.js'; +import { PerfFile, PerfSample, PerfStack, PerfThread } from '../../../../bean/PerfProfile.js'; +import { Utils } from '../../base/Utils.js'; +import '../../../DisassemblingWindow.js'; +import { DisassemblingWindow } from '../../../DisassemblingWindow.js'; +import { SpApplication } from '../../../../SpApplication.js'; +import { log } from '../../../../../log/Log.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { Cmd } from '../../../../../command/Cmd.js'; + +@element('tabpane-perf-sample') +export class TabPanePerfSample extends BaseElement { + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private source: Array = []; + private processMap: Map = new Map(); + private modal: DisassemblingWindow | null | undefined; + private sortKey: string = 'timeString'; + private sortType: number = 0; + + set data(val: SelectionParam | null | undefined) { + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 40 + 'px'; + this.tbl!.recycleDataSource = []; + // @ts-ignore + this.tblData?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 25 + 'px'; + this.tblData!.recycleDataSource = []; + if (val) { + Promise.all([ + queryPerfProcess(), + queryPerfSampleListByTimeRange( + val.leftNs, + val.rightNs, + val.perfAll ? [] : val.perfCpus, + val.perfAll ? [] : val.perfProcess, + val.perfAll ? [] : val.perfThread + ), + ]).then((results) => { + let processes = results[0] as Array; + log('queryPerfProcess size : ' + processes.length); + let samples = results[1] as Array; + log('queryPerfSampleListByTimeRange size : ' + samples.length); + this.processMap.clear(); + for (let process of processes) { + this.processMap.set(process.pid, process); + } + for (let sample of samples) { + let process = this.processMap.get(sample.pid); + sample.processName = + process == null || process == undefined + ? `Process(${sample.pid})` + : `${process!.processName || 'Process'}(${sample.pid})`; + sample.threadName = + sample.threadName == null || sample.threadName == undefined + ? `Thread(${sample.tid})` + : `${sample.threadName}(${sample.tid})`; + sample.coreName = `CPU ${sample.core}`; + sample.timeString = Utils.getTimeString(sample.time); + sample.backtrace = []; + let call = perfDataQuery.callChainMap.get(sample.sampleId); + if (call == undefined || call == null) { + sample.depth = 0; + sample.backtrace.push('No Effective Call Stack'); + } else { + sample.depth = call.depth; + sample.backtrace.push(call.name); + sample.backtrace.push(`(${sample.depth} other frames)`); + } + } + this.source = samples; + this.sortTable(this.sortKey, this.sortType); + }); + } + } + + setRightTableData(sample: PerfSample) { + queryPerfSampleCallChain(sample.sampleId).then((result) => { + for (let stack of result) { + let files = (perfDataQuery.filesData[stack.fileId] ?? []) as Array; + stack.path = files[stack.symbolId].path; + stack.type = stack.path.endsWith('.so.1') || stack.path.endsWith('.dll') || stack.path.endsWith('.so') ? 0 : 1; + } + this.tblData!.dataSource = result; + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-perf-sample'); + this.tblData = this.shadowRoot?.querySelector('#tb-stack-data'); + this.modal = this.shadowRoot?.querySelector('tab-native-data-modal'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as PerfSample; + this.setRightTableData(data); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.sortTable(evt.detail.key, evt.detail.sort); + }); + let lastClikTime = 0; + let spApplication = document.getElementsByTagName('sp-application')[0]; + this.tblData!.addEventListener('row-click', (e) => { + if (Date.now() - lastClikTime < 200 && spApplication.vs) { + this.tbl!.style.visibility = 'hidden'; + new ResizeObserver((entries) => { + this.modal!.style.width = this.tbl!.clientWidth + 'px'; + this.modal!.style.height = this.tbl!.clientHeight + 'px'; + }).observe(this.tbl!); + this.modal!.showLoading(); + // @ts-ignore + let data = e.detail.data as PerfStack; + let path = data.path; + let addr = data.vaddrInFile; + let addrHex = addr.toString(16); + if (path.trim() === '[kernel.kallsyms]') { + this.modal?.showContent(`error : Symbol ${data.symbol} lib is [kernel.kallsyms] ,not support `, addrHex); + } else if (path.trim() === '') { + this.modal?.showContent(`error : Symbol ${data.symbol} lib is null `, addrHex); + } else if (addr < 0) { + this.modal?.showContent(`error : Symbol ${data.symbol} current addr is error ` + addrHex, addrHex); + } else { + const binDir = 'C:/binary_cache'; + let binPath = binDir + path; + let cmd = 'C:/binary_cache/llvm-objdump.exe -S ' + binPath; + Cmd.execObjDump(cmd, addrHex, (result: any) => { + this.modal?.showContent(result, addrHex); + }); + } + } + lastClikTime = Date.now(); + }); + this.modal!.setCloseListener(() => { + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 40 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 25 + 'px'; + this.tbl?.reMeauseHeight(); + this.tblData?.reMeauseHeight(); + } + this.modal!.style.height = this.tbl!.clientHeight - 2 + 'px'; //2 is borderWidth + }).observe(this.parentElement!); + } + + sortTable(key: string, type: number) { + this.source.sort((a, b): number => { + if (key == 'timeString') { + if (type == 0) { + return a.time - b.time; + } else if (type == 1) { + return a.time - b.time; + } else { + return b.time - a.time; + } + } else { + if (type == 0) { + return a.core - b.core; + } else if (type == 1) { + return a.core - b.core; + } else { + return b.core - a.core; + } + } + }); + this.tbl!.recycleDataSource = this.source; + } + + initHtml(): string { + return ` + +
+ +
+ + + + + + + + + + + +
+ + + + + + + +
+
`; + } +} diff --git a/ide/src/trace/component/trace/sheet/irq/TabPaneIrqCounter.ts b/ide/src/trace/component/trace/sheet/irq/TabPaneIrqCounter.ts new file mode 100644 index 0000000000000000000000000000000000000000..233f985ba13da9abd39ca66a72673fe5be12835d --- /dev/null +++ b/ide/src/trace/component/trace/sheet/irq/TabPaneIrqCounter.ts @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { Counter, SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCounters, getTabVirtualCounters } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-irq-counter') +export class TabPaneIrqCounter extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + + set data(val: SelectionParam | any) { + //@ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + let dataSource: Array = []; + let collect = val.irqMapData; + let sumCount = 0; + for (let key of collect.keys()) { + let counters = collect.get(key); + let sd = this.createSelectCounterData(key, counters); + sumCount += Number.parseInt(sd.count || '0'); + sd.avgDuration = Utils.getProbablyTime(sd.wallDuration / parseInt(sd.count)); + dataSource.push(sd); + } + this.source = dataSource; + this.tbl!.recycleDataSource = dataSource; + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-counter'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + `; + } + + createSelectCounterData(name: string, list: Array): SelectionData { + let selectData = new SelectionData(); + if (list.length > 0) { + selectData.name = name; + selectData.count = list.length + ''; + for (let i = 0; i < list.length; i++) { + selectData.wallDuration += list[i].dur; + } + selectData.wallDurationFormat = Utils.getProbablyTime(selectData.wallDuration); + } + return selectData; + } + + sortByColumn(detail: any) { + let type = detail.sort; + let key = detail.key; + if (type == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = Array.from(this.source); + arr.sort((a, b): number => { + if (key == 'wallDurationFormat') { + if (type == 1) { + return a.wallDuration - b.wallDuration; + } else { + return b.wallDuration - a.wallDuration; + } + } else if (key == 'count') { + if (type == 1) { + return parseInt(a.count) >= parseInt(b.count) ? 1 : -1; + } else { + return parseInt(b.count) >= parseInt(a.count) ? 1 : -1; + } + } else if (key == 'avgDuration') { + if (type == 1) { + return a.wallDuration / parseInt(a.count) - b.wallDuration / parseInt(b.count); + } else { + return b.wallDuration / parseInt(b.count) - a.wallDuration / parseInt(a.count); + } + } else if (key == 'name') { + if (a.name > b.name) { + return type === 2 ? 1 : -1; + } else if (a.name == b.name) { + return 0; + } else { + return type === 2 ? -1 : 1; + } + } else { + return 0; + } + }); + this.tbl!.recycleDataSource = arr; + } + } +} diff --git a/ide/src/trace/component/trace/sheet/jank/TabPaneFrames.ts b/ide/src/trace/component/trace/sheet/jank/TabPaneFrames.ts new file mode 100644 index 0000000000000000000000000000000000000000..01de7c4d96d1f9e83d1486dafd49bbceaf3aa224 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/jank/TabPaneFrames.ts @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; +import { LitTable } from '../../../../../base-ui/table/lit-table'; +import { JankFramesStruct } from '../../../../bean/JankFramesStruct.js'; +import { JanksStruct } from '../../../../bean/JanksStruct.js'; + +@element('tabpane-frames') +export class TabPaneFrames extends BaseElement { + private litTable: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + set data(val: SelectionParam | any) { + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + this.queryDataByDB(val); + } + + queryDataByDB(val: SelectionParam | any) { + let tablelist = new Array(); + let sumRes: JankFramesStruct = new JankFramesStruct(); + let appJank: JankFramesStruct = new JankFramesStruct(); + let rsJank: JankFramesStruct = new JankFramesStruct(); + let noJank: JankFramesStruct = new JankFramesStruct(); + val.jankFramesData.forEach((data: Array) => { + sumRes.occurrences += data.length; + data.forEach((da: JanksStruct) => { + if (da.dur == null || da.dur == undefined) { + da.dur = 0; + } + if (da.frame_type == 'app') { + if (da.jank_tag) { + appJank.flag = da.jank_tag; + appJank.jankType = 'APP Deadline Missed'; + appJank.occurrences += 1; + appJank.maxDuration = Math.max(da.dur, appJank.maxDuration!); + if (appJank.minDuration == -1) { + appJank.minDuration = da.dur; + } else { + appJank.minDuration = Math.min(da.dur, appJank.minDuration!); + } + if (appJank.meanDuration == -1) { + appJank.meanDuration = da.dur; + } else { + appJank.meanDuration = Number(((da.dur + appJank.meanDuration!) / 2).toFixed(2)); + } + } else { + noJank.flag = da.jank_tag; + noJank.jankType = 'None'; + noJank.occurrences += 1; + noJank.maxDuration = Math.max(da.dur, noJank.maxDuration!); + if (noJank.minDuration == -1) { + noJank.minDuration = da.dur; + } else { + noJank.minDuration = Math.min(da.dur, noJank.minDuration!); + } + if (noJank.meanDuration == -1) { + noJank.meanDuration = da.dur; + } else { + noJank.meanDuration = Number(((da.dur + noJank.meanDuration!) / 2).toFixed(2)); + } + } + } else if (da.frame_type == 'renderService') { + if (da.jank_tag) { + rsJank.flag = da.jank_tag; + rsJank.jankType = 'RenderService Deadline Missed'; + rsJank.occurrences += 1; + rsJank.maxDuration = Math.max(da.dur, rsJank.maxDuration!); + if (rsJank.minDuration == -1) { + rsJank.minDuration = da.dur; + } else { + rsJank.minDuration = Math.min(da.dur, rsJank.minDuration!); + } + if (rsJank.meanDuration == -1) { + rsJank.meanDuration = da.dur; + } else { + rsJank.meanDuration = Number(((da.dur + rsJank.meanDuration!) / 2).toFixed(2)); + } + } else { + noJank.flag = da.jank_tag; + noJank.jankType = 'None'; + noJank.occurrences += 1; + noJank.maxDuration = Math.max(da.dur, noJank.maxDuration); + if (noJank.minDuration == -1) { + noJank.minDuration = da.dur; + } else { + noJank.minDuration = Math.min(da.dur, noJank.minDuration!); + } + if (noJank.meanDuration == -1) { + noJank.meanDuration = da.dur; + } else { + noJank.meanDuration = Number(((da.dur + noJank.meanDuration) / 2).toFixed(2)); + } + } + } else { + // frameTime + if (da.jank_tag) { + appJank.flag = da.jank_tag; + appJank.jankType = 'Deadline Missed'; + appJank.occurrences += 1; + appJank.maxDuration = Math.max(da.dur, appJank.maxDuration); + appJank.minDuration = Math.min(da.dur, appJank.minDuration); + if (appJank.minDuration == -1) { + appJank.minDuration = da.dur; + } else { + appJank.minDuration = Math.min(da.dur, appJank.minDuration!); + } + if (appJank.meanDuration == -1) { + appJank.meanDuration = da.dur; + } else { + appJank.meanDuration = Number(((da.dur + appJank.meanDuration) / 2).toFixed(2)); + } + } else { + noJank.flag = da.jank_tag; + noJank.jankType = 'None'; + noJank.occurrences += 1; + noJank.maxDuration = Math.max(da.dur, noJank.maxDuration); + if (noJank.minDuration == -1) { + noJank.minDuration = da.dur; + } else { + noJank.minDuration = Math.min(da.dur, noJank.minDuration!); + } + if (noJank.meanDuration == -1) { + noJank.meanDuration = da.dur; + } else { + noJank.meanDuration = Number(((da.dur + noJank.meanDuration) / 2).toFixed(2)); + } + } + } + }); + }); + tablelist.push(sumRes); + if (appJank.occurrences > 0) { + appJank.maxDurationStr = appJank.maxDuration + ''; + appJank.minDurationStr = appJank.minDuration + ''; + appJank.meanDurationStr = appJank.meanDuration + ''; + tablelist.push(appJank); + } + if (rsJank.occurrences > 0) { + rsJank.maxDurationStr = rsJank.maxDuration + ''; + rsJank.minDurationStr = rsJank.minDuration + ''; + rsJank.meanDurationStr = rsJank.meanDuration + ''; + tablelist.push(rsJank); + } + if (noJank.occurrences > 0) { + noJank.maxDurationStr = noJank.maxDuration + ''; + noJank.minDurationStr = noJank.minDuration + ''; + noJank.meanDurationStr = noJank.meanDuration + ''; + tablelist.push(noJank); + } + this.source = tablelist; + this.litTable!.recycleDataSource = tablelist; + } + + initElements(): void { + this.litTable = this.shadowRoot?.querySelector('#tb-frames'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.litTable!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.litTable?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.litTable?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'jankType') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.litTable!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f51c084bae0ae90d45851332a785cc5379e0d0d --- /dev/null +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.ts @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { query, queryNativeHookEventTid } from '../../../../database/SqlLite.js'; +import { NativeHookCallInfo, NativeHookStatistics } from '../../../../bean/NativeHook.js'; +import '../TabPaneFilter.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import '../../../chart/FrameChart.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { FrameChart } from '../../../chart/FrameChart.js'; +import { ChartMode } from '../../../../bean/FrameChartStruct.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-native-callinfo') +export class TabPaneNMCallInfo extends BaseElement { + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private source: Array = []; + private rightSource: Array = []; + private queryResult: Array = []; + private native_type: Array = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + private filterAllocationType: string = '0'; + private filterNativeType: string = '0'; + private currentSelection: SelectionParam | undefined; + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private sortColumn: string = ''; + private sortType: number = 0; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + this.initFilterTypes(); + let types: Array = []; + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { + types.push("'AllocEvent'"); + types.push("'MmapEvent'"); + } else { + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { + types.push("'AllocEvent'"); + } + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { + types.push("'MmapEvent'"); + } + } + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight + 'px'; + // @ts-ignore + this.tblData?.recycleDataSource = []; + // @ts-ignore + this.tbl?.recycleDataSource = []; + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + queryNativeHookEventTid(val.leftNs, val.rightNs, types).then((result) => { + this.queryResult = result; + this.getDataByNativeMemoryWorker(val); + }); + } + + getDataByNativeMemoryWorker(val: SelectionParam | any) { + let args = new Map(); + args.set('data', this.queryResult); + args.set('filterAllocType', this.filterAllocationType); + args.set('filterEventType', this.filterNativeType); + args.set('leftNs', val.leftNs); + args.set('rightNs', val.rightNs); + args.set('actionType', 'call-info'); + this.startWorker(args, (results: any[]) => { + this.tblData!.recycleDataSource = []; + this.progressEL!.loading = false; + if (results.length > 0) { + this.source = results; + this.sortTreeByColumn(this.sortColumn, this.sortType); + this.frameChart!.mode = ChartMode.Byte; + this.frameChart!.data = this.source; + this.frameChart?.updateCanvas(true, this.clientWidth); + this.frameChart?.calculateChartData(); + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + this.frameChart!.data = []; + this.frameChart!.clearCanvas(); + } + }); + } + + startWorker(args: Map, handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName('logic1', 'native-memory-action', args, undefined, (res: any) => { + handler(res); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + }); + } + + getParentTree( + src: Array, + target: NativeHookCallInfo, + parents: Array + ): boolean { + for (let hook of src) { + if (hook.id == target.id) { + parents.push(hook); + return true; + } else { + if (this.getParentTree(hook.children as Array, target, parents)) { + parents.push(hook); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, eventId: number, children: Array): boolean { + for (let hook of src) { + if (hook.eventId == eventId && hook.children.length == 0) { + children.push(hook); + return true; + } else { + if (this.getChildTree(hook.children as Array, eventId, children)) { + children.push(hook); + return true; + } + } + } + return false; + } + + setRightTableData(hook: NativeHookCallInfo) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.source, hook, parents); + let maxEventId = hook.eventId; + let maxHeap = 0; + + function findMaxStack(hook: NativeHookCallInfo) { + if (hook.children.length == 0) { + if (hook.size > maxHeap) { + maxHeap = hook.size; + maxEventId = hook.eventId; + } + } else { + hook.children.map((hookChild) => { + findMaxStack(hookChild); + }); + } + } + + findMaxStack(hook); + this.getChildTree(hook.children as Array, maxEventId, children); + this.rightSource = parents.reverse().concat(children.reverse()); + let len = this.rightSource.length; + // @ts-ignore + this.tblData?.dataSource = len == 0 ? [] : this.rightSource.slice(1, len); + } + + initFilterTypes() { + let filter = this.shadowRoot?.querySelector('#filter'); + this.queryResult = []; + filter!.firstSelect = '0'; + filter!.secondSelect = '0'; + this.filterAllocationType = '0'; + this.filterNativeType = '0'; + } + + sortTreeByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + this.tbl!.recycleDataSource = this.sortTree(this.source, column, sort); + } + + sortTree(arr: Array, column: string, sort: number): Array { + let sortArr = arr.sort((a, b) => { + if (column == 'size') { + if (sort == 0) { + return a.eventId - b.eventId; + } else if (sort == 1) { + return a.size - b.size; + } else { + return b.size - a.size; + } + } else { + if (sort == 0) { + return a.eventId - b.eventId; + } else if (sort == 1) { + return a.count - b.count; + } else { + return b.count - a.count; + } + } + }); + sortArr.map((call) => { + call.children = this.sortTree(call.children as Array, column, sort); + }); + return sortArr; + } + + showButtomMenu(isShow: boolean) { + let filter = this.shadowRoot?.querySelector('#filter')!; + if (isShow) { + filter.setAttribute('first', ''); + filter.setAttribute('second', ''); + } else { + filter.removeAttribute('first'); + filter.removeAttribute('second'); + } + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tb-native-callinfo'); + this.tblData = this.shadowRoot?.querySelector('#tb-native-data'); + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); + this.frameChart?.addChartClickListener((showMenu: boolean) => { + this.parentElement!.scrollTo(0, 0); + this.showButtomMenu(showMenu); + }); + + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as NativeHookCallInfo; + this.setRightTableData(data); + data.isSelected = true; + this.tblData?.clearAllSelection(data); + this.tblData?.setCurrentSelection(data); + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + }); + this.tblData!.addEventListener('row-click', (e) => { + // @ts-ignore + let detail = e.detail.data as NativeHookCallInfo; + this.tbl?.clearAllSelection(detail); + detail.isSelected = true; + this.tbl!.scrollToData(detail); + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + }); + this.tbl!.addEventListener('column-click', (evt) => { + this.sortTreeByColumn( + // @ts-ignore + evt.detail.key == 'countValue' || evt.detail.key == 'countPercent' ? 'countValue' : 'size', evt.detail.sort + ); + }); + + this.shadowRoot?.querySelector('#filter')!.getFilterData((data: FilterData) => { + this.filterAllocationType = data.firstSelect || '0'; + this.filterNativeType = data.secondSelect || '0'; + this.getDataByNativeMemoryWorker(this.currentSelection); + if (data.icon == 'block') { + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + this.frameChart!.data = this.source; + this.frameChart?.calculateChartData(); + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.isChartShow = false; + this.frameChart!.clearCanvas(); + this.tbl!.reMeauseHeight(); + } + }); + this.initFilterTypes(); + } + + connectedCallback() { + super.connectedCallback(); + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + if (this.parentElement?.clientHeight != 0) { + if (!this.isChartShow) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight + 'px'; + this.tbl?.reMeauseHeight(); + } else { + // @ts-ignore + this.frameChart?.updateCanvas(false, entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + +
+ + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + + + + +
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.ts new file mode 100644 index 0000000000000000000000000000000000000000..234db0491c3e7da6538f17b67f5f69dc283ac18c --- /dev/null +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.ts @@ -0,0 +1,772 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { FrameChart } from '../../../chart/FrameChart.js'; +import { DisassemblingWindow } from '../../../DisassemblingWindow.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { ChartMode } from '../../../../bean/FrameChartStruct.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { FileMerageBean } from '../../../../database/logic-worker/ProcedureLogicWorkerFileSystem.js'; + +@element('tabpane-nm-calltree') +export class TabpaneNMCalltree extends BaseElement { + private tbl: LitTable | null | undefined; + private tbr: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private rightSource: Array = []; + private filter: any; + private dataSource: any[] = []; + private native_type: Array = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + private sortKey = 'heapSizeStr'; + private sortType = 0; + private currentSelectedData: any = undefined; + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private systmeRuleName = '/system/'; + private numRuleName = '/max/min/'; + private modal: DisassemblingWindow | null | undefined; + private needShowMenu = true; + private searchValue: string = ''; + private loadingList: number[] = []; + private loadingPage: any; + private currentSelection: SelectionParam | undefined; + private filterAllocationType: string = '0'; + private filterNativeType: string = '0'; + private filterResponseType: number = -1; + private filterResponseSelect: string = '0'; + private responseTypes: any[] = []; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.searchValue = ''; + this.currentSelection = val; + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + if (this.parentElement!.clientHeight > this.filter!.clientHeight) { + this.filter!.style.display = 'flex'; + } else { + this.filter!.style.display = 'none'; + } + this.filter!.initializeFilterTree(true, true, val.nativeMemory.length > 0); + this.filter!.filterValue = ''; + this.initFilterTypes(); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + let types: Array = []; + if (val.nativeMemory.length > 0) { + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { + types.push("'AllocEvent'"); + types.push("'MmapEvent'"); + } else { + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { + types.push("'AllocEvent'"); + } + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { + types.push("'MmapEvent'"); + } + } + } else { + if (val.nativeMemoryStatistic.indexOf(this.native_type[0]) != -1) { + types.push(0); + types.push(1); + } else { + if (val.nativeMemoryStatistic.indexOf(this.native_type[1]) != -1) { + types.push(0); + } + if (val.nativeMemoryStatistic.indexOf(this.native_type[2]) != -1) { + types.push(1); + } + } + } + + this.getDataByWorkerQuery( + { + leftNs: val.leftNs, + rightNs: val.rightNs, + types, + }, + (results: any[]) => { + this.setLTableData(results); + this.tbr!.recycleDataSource = []; + this.frameChart!.mode = ChartMode.Byte; + this.frameChart!.data = this.dataSource; + this.frameChart?.updateCanvas(true, this.clientWidth); + this.frameChart?.calculateChartData(); + } + ); + } + + getParentTree(src: Array, target: FileMerageBean, parents: Array): boolean { + for (let call of src) { + if (call.id == target.id) { + parents.push(call); + return true; + } else { + if (this.getParentTree(call.children as Array, target, parents)) { + parents.push(call); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, id: string, children: Array): boolean { + for (let call of src) { + if (call.id == id && call.children.length == 0) { + children.push(call); + return true; + } else { + if (this.getChildTree(call.children as Array, id, children)) { + children.push(call); + return true; + } + } + } + return false; + } + + setRightTableData(call: FileMerageBean) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.dataSource, call, parents); + let maxId = call.id; + let maxDur = 0; + + function findMaxStack(call: any) { + if (call.children.length == 0) { + if (call.heapSize > maxDur) { + maxDur = call.heapSize; + maxId = call.id; + } + } else { + call.children.map((callChild: any) => { + findMaxStack(callChild); + }); + } + } + + findMaxStack(call); + this.getChildTree(call.children as Array, maxId, children); + let arr = parents.reverse().concat(children.reverse()); + for (let data of arr) { + data.type = + data.libName.endsWith('.so.1') || data.libName.endsWith('.dll') || data.libName.endsWith('.so') ? 0 : 1; + } + let len = arr.length; + this.rightSource = arr; + this.tbr!.dataSource = len == 0 ? [] : arr; + } + + showButtomMenu(isShow: boolean) { + if (isShow) { + this.filter.setAttribute('tree', ''); + this.filter.setAttribute('input', ''); + this.filter.setAttribute('inputLeftText', ''); + this.filter.setAttribute('first', ''); + this.filter.setAttribute('second', ''); + this.filter.showThird(true); + } else { + this.filter.removeAttribute('tree'); + this.filter.removeAttribute('input'); + this.filter.removeAttribute('inputLeftText'); + this.filter.removeAttribute('first'); + this.filter.removeAttribute('second'); + this.filter.showThird(false); + } + } + + initFilterTypes() { + let filter = this.shadowRoot?.querySelector('#filter'); + if (this.currentSelection!.nativeMemory.length > 0) { + procedurePool.submitWithName('logic1', 'native-memory-get-responseType', {}, undefined, (res: any) => { + this.responseTypes = res; + let nullIndex = this.responseTypes.findIndex((item) => { + return item.key == 0; + }); + if (nullIndex != -1) { + this.responseTypes.splice(nullIndex, 1); + } + filter!.setSelectList( + null, + null, + 'Allocation Lifespan', + 'Allocation Type', + this.responseTypes.map((item: any) => { + return item.value; + }) + ); + filter!.setFilterModuleSelect('#first-select', 'width', '150px'); + filter!.setFilterModuleSelect('#second-select', 'width', '150px'); + filter!.setFilterModuleSelect('#third-select', 'width', '150px'); + filter!.firstSelect = '0'; + filter!.secondSelect = '0'; + filter!.thirdSelect = '0'; + this.filterAllocationType = '0'; + this.filterNativeType = '0'; + this.filterResponseSelect = '0'; + this.filterResponseType = -1; + }); + } else { + filter!.setSelectList(null, null, 'Allocation Lifespan', 'Allocation Type', undefined); + filter!.setFilterModuleSelect('#first-select', 'width', '150px'); + filter!.setFilterModuleSelect('#second-select', 'width', '150px'); + filter!.firstSelect = '0'; + filter!.secondSelect = '0'; + this.filterAllocationType = '0'; + this.filterNativeType = '0'; + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-filesystem-calltree'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + this.modal = this.shadowRoot?.querySelector('tab-native-data-modal'); + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.frameChart!.addChartClickListener((needShowMenu: boolean) => { + this.parentElement!.scrollTo(0, 0); + this.showButtomMenu(needShowMenu); + this.needShowMenu = needShowMenu; + }); + this.tbl!.rememberScrollTop = true; + this.filter = this.shadowRoot?.querySelector('#filter'); + this.tbl!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as FileMerageBean; + this.setRightTableData(data); + data.isSelected = true; + this.currentSelectedData = data; + this.tbr?.clearAllSelection(data); + this.tbr?.setCurrentSelection(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.tbr = this.shadowRoot?.querySelector('#tb-filesystem-list'); + this.tbr!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + let data = evt.detail.data as FileMerageBean; + this.tbl?.clearAllSelection(data); + (data as any).isSelected = true; + this.tbl!.scrollToData(data); + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.modal!.setCloseListener(() => { + this.modal!.style.display = 'none'; + this.tbl!.style.visibility = 'visible'; + this.shadowRoot!.querySelector('#filter')!.style.display = 'flex'; + }); + let filterFunc = (data: any) => { + let args: any[] = []; + if (data.type == 'check') { + if (data.item.checked) { + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + } + } else if (data.type == 'select') { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[data.item.name]], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [data.item.name], + }); + args.push({ + funcName: 'splitTree', + funcArgs: [data.item.name, data.item.select == '0', data.item.type == 'symbol'], + }); + } else if (data.type == 'button') { + if (data.item == 'symbol') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined) { + this.filter!.addDataMining({ name: this.currentSelectedData.symbolName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.symbolName, false, true], + }); + } else { + return; + } + } else if (data.item == 'library') { + if (this.currentSelectedData && !this.currentSelectedData.canCharge) { + return; + } + if (this.currentSelectedData != undefined && this.currentSelectedData.libName != '') { + this.filter!.addDataMining({ name: this.currentSelectedData.libName }, data.item); + args.push({ + funcName: 'splitTree', + funcArgs: [this.currentSelectedData.libName, false, false], + }); + } else { + return; + } + } else if (data.item == 'restore') { + if (data.remove != undefined && data.remove.length > 0) { + let list = data.remove.map((item: any) => { + return item.name; + }); + args.push({ + funcName: 'resotreAllNode', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + list.forEach((symbolName: string) => { + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [symbolName], + }); + }); + } + } + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + this.tbl!.move1px(); + if (this.currentSelectedData) { + this.currentSelectedData.isSelected = false; + this.tbl?.clearAllSelection(this.currentSelectedData); + this.tbr!.recycleDataSource = []; + this.currentSelectedData = undefined; + } + }); + }; + this.filter!.getDataLibrary(filterFunc); + this.filter!.getDataMining(filterFunc); + this.filter!.getCallTreeData((data: any) => { + if (data.value == 0) { + this.refreshAllNode({ + ...this.filter!.getFilterTreeData(), + callTree: data.checks, + }); + } else { + let args: any[] = []; + if (data.checks[1]) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + } else { + args.push({ + funcName: 'resotreAllNode', + funcArgs: [[this.systmeRuleName]], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + args.push({ + funcName: 'clearSplitMapData', + funcArgs: [this.systmeRuleName], + }); + } + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + }); + this.filter!.getCallTreeConstraintsData((data: any) => { + let args: any[] = [ + { + funcName: 'resotreAllNode', + funcArgs: [[this.numRuleName]], + }, + { + funcName: 'clearSplitMapData', + funcArgs: [this.numRuleName], + }, + ]; + if (data.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(data.min), data.max], + }); + } + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + }); + this.filter!.getFilterData((data: FilterData) => { + if (this.currentSelection!.nativeMemoryStatistic.length > 0) { + this.filterResponseSelect = ''; + } + if ( + this.filterAllocationType != data.firstSelect || + this.filterNativeType != data.secondSelect || + this.filterResponseSelect != data.thirdSelect + ) { + this.filterAllocationType = data.firstSelect || '0'; + this.filterNativeType = data.secondSelect || '0'; + this.filterResponseSelect = data.thirdSelect || "0'"; + let thirdIndex = parseInt(data.thirdSelect || '0'); + if (this.responseTypes.length > thirdIndex) { + this.filterResponseType = this.responseTypes[thirdIndex].key || -1; + } + this.refreshAllNode(this.filter!.getFilterTreeData()); + } else if (this.searchValue != this.filter!.filterValue) { + this.searchValue = this.filter!.filterValue; + let args = [ + { + funcName: 'setSearchValue', + funcArgs: [this.searchValue], + }, + { + funcName: 'resetAllNode', + funcArgs: [], + }, + ]; + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + this.switchFlameChart(data); + }); + } else { + this.switchFlameChart(data); + } + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortKey = evt.detail.key; + // @ts-ignore + this.sortType = evt.detail.sort; + // @ts-ignore + this.setLTableData(this.dataSource, true); + this.frameChart!.data = this.dataSource; + }); + } + + connectedCallback() { + super.connectedCallback(); + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + this.modal!.style.height = this.tbl!.clientHeight - 2 + 'px'; //2 is borderWidth + if (this.tbl!.style.visibility == 'hidden') { + tabPaneFilter.style.display = 'none'; + } + if (this.parentElement?.clientHeight != 0) { + if (this.isChartShow) { + this.frameChart?.updateCanvas(false, entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 35 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tbr?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 - 21 + 'px'; + this.tbr?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; + } + + switchFlameChart(data: any) { + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); + if (data.icon == 'block') { + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + this.filter!.disabledMining = true; + this.showButtomMenu(this.needShowMenu); + this.frameChart!.data = this.dataSource; + this.frameChart?.calculateChartData(); + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.showButtomMenu(true); + this.isChartShow = false; + this.filter!.disabledMining = false; + this.frameChart!.clearCanvas(); + this.tbl!.reMeauseHeight(); + } + } + + refreshAllNode(filterData: any) { + let args: any[] = []; + let isTopDown: boolean = !filterData.callTree[0]; + let isHideSystemLibrary = filterData.callTree[1]; + let list = filterData.dataMining.concat(filterData.dataLibrary); + let groupArgs = new Map(); + groupArgs.set('filterAllocType', this.filterAllocationType); + groupArgs.set('filterEventType', this.filterNativeType); + groupArgs.set('filterResponseType', this.filterResponseType); + groupArgs.set('leftNs', this.currentSelection?.leftNs || 0); + groupArgs.set('rightNs', this.currentSelection?.rightNs || 0); + groupArgs.set( + 'nativeHookType', + this.currentSelection!.nativeMemory.length > 0 ? 'native-hook' : 'native-hook-statistic' + ); + args.push( + { + funcName: 'groupCallchainSample', + funcArgs: [groupArgs], + }, + { + funcName: 'getCallChainsBySampleIds', + funcArgs: [isTopDown], + } + ); + this.tbr!.recycleDataSource = []; + if (isHideSystemLibrary) { + args.push({ + funcName: 'hideSystemLibrary', + funcArgs: [], + }); + } + if (filterData.callTreeConstraints.checked) { + args.push({ + funcName: 'hideNumMaxAndMin', + funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]], + }); + } + args.push({ + funcName: 'splitAllProcess', + funcArgs: [list], + }); + args.push({ + funcName: 'resetAllNode', + funcArgs: [], + }); + this.getDataByWorker(args, (result: any[]) => { + this.setLTableData(result); + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }); + } + + setLTableData(resultData: any[], sort?: boolean) { + if (sort) { + this.dataSource = this.sortTree(resultData); + } else { + if (resultData && resultData[0]) { + this.dataSource = + this.currentSelection!.nativeMemory.length > 0 + ? this.sortTree(resultData) + : this.sortTree(resultData[0].children || []); + } else { + this.dataSource = []; + } + } + this.tbl!.recycleDataSource = this.dataSource; + } + + sortTree(arr: Array): Array { + let sortArr = arr.sort((a, b) => { + if (this.sortKey == 'heapSizeStr' || this.sortKey == 'heapPercent') { + if (this.sortType == 0) { + return b.size - a.size; + } else if (this.sortType == 1) { + return a.size - b.size; + } else { + return b.size - a.size; + } + } else { + if (this.sortType == 0) { + return b.count - a.count; + } else if (this.sortType == 1) { + return a.count - b.count; + } else { + return b.count - a.count; + } + } + }); + sortArr.map((call) => { + call.children = this.sortTree(call.children); + }); + return sortArr; + } + + getDataByWorker(args: any[], handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName('logic1', 'native-memory-calltree-action', args, undefined, (results: any) => { + handler(results); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + }); + } + + getDataByWorkerQuery(args: any, handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName( + 'logic1', + this.currentSelection!.nativeMemory!.length > 0 + ? 'native-memory-queryCallchainsSamples' + : 'native-memory-queryStatisticCallchainsSamples', + args, + undefined, + (results: any) => { + handler(results); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + } + ); + } + + initHtml(): string { + return ` + +
+ + + +
+ + + + + + + + + + + + + + + + + +
+ + + Heaviest Stack Trace + + + + + +
+ + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.ts new file mode 100644 index 0000000000000000000000000000000000000000..60f4e54afa13d5c80cdc2d612a8c708881fd3919 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.ts @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2022 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 '../../../../../base-ui/table/lit-table-column.js'; +import { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { queryAllHookData, queryNativeHookSnapshotTypes } from '../../../../database/SqlLite.js'; +import { + NativeHookCallInfo, + NativeHookSampleQueryInfo, + NativeHookSamplerInfo, + NativeMemory, +} from '../../../../bean/NativeHook.js'; +import { Utils } from '../../base/Utils.js'; +import '../TabPaneFilter.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +import { formatRealDateMs, getTimeString } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon.js'; +import { SpNativeMemoryChart } from '../../../chart/SpNativeMemoryChart.js'; + +@element('tabpane-native-sample') +export class TabPaneNMSampleList extends BaseElement { + static tblData: LitTable | null | undefined; + static tbl: LitTable | null | undefined; + static filter: any; + static filterSelect: string = '0'; + static source: Array = []; + static types: Array = []; + static native_type: Array = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + static tableMarkData: Array = []; + static selectionParam: SelectionParam | undefined = undefined; + static sampleTypes: Array = []; + static sampleTypesList: any[] = []; + + set data(val: SelectionParam | any) { + TabPaneNMSampleList.serSelection(val); + this.filterAllList(); + } + + static serSelection(val: SelectionParam) { + if (this.selectionParam !== val) { + this.clearData(); + this.selectionParam = val; + this.initTypes(); + } + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { + this.types.push("'AllocEvent'"); + this.types.push("'MmapEvent'"); + } else { + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { + this.types.push("'AllocEvent'"); + } + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { + this.types.push("'MmapEvent'"); + } + } + } + + static initTypes() { + queryNativeHookSnapshotTypes().then((result) => { + if (result.length > 0) { + this.sampleTypes = result; + } + }); + } + + static addSampleData(data: any) { + if (TabPaneNMSampleList.tableMarkData.indexOf(data) != -1) { + return; + } + TabPaneNMSampleList.tableMarkData.push(data); + let rootSample = new NativeHookSamplerInfo(); + rootSample.snapshot = 'Snapshot' + this.numberToWord(this.source.length + 1); + rootSample.startTs = data.startTs; + rootSample.timestamp = + SpNativeMemoryChart.REAL_TIME_DIF == 0 + ? getTimeString(data.startTs) + : formatRealDateMs(data.startTs + SpNativeMemoryChart.REAL_TIME_DIF); + rootSample.eventId = data.eventId; + rootSample.threadId = data.threadId; + rootSample.threadName = data.threadName; + this.queryAllHookInfo(data, rootSample); + } + + static merageSampleData( + leftTime: number, + startNs: number, + rootSample: NativeHookSampleQueryInfo, + merageSample: NativeHookSampleQueryInfo + ) { + if (merageSample.endTs >= startNs) { + rootSample.growth += merageSample.growth; + } + if (merageSample.startTs > leftTime) { + rootSample.existing++; + let childSample = new NativeHookSamplerInfo(); //新增最下层的叶子节点 + childSample.snapshot = '0x' + merageSample.addr; + childSample.eventId = merageSample.eventId; + childSample.heapSize = merageSample.growth; + childSample.growth = Utils.getByteWithUnit(merageSample.growth); + childSample.totalGrowth = childSample.growth; + childSample.startTs = merageSample.startTs; + childSample.timestamp = + SpNativeMemoryChart.REAL_TIME_DIF == 0 + ? getTimeString(merageSample.startTs) + : formatRealDateMs(merageSample.startTs + SpNativeMemoryChart.REAL_TIME_DIF); + childSample.threadId = merageSample.threadId; + childSample.threadName = merageSample.threadName; + (childSample as any).existing = ''; + rootSample.children.push(childSample); + } + rootSample.total += merageSample.growth; + } + + static queryAllHookInfo(data: any, rootSample: NativeHookSamplerInfo) { + let copyTypes = this.sampleTypes.map((type) => { + let copyType = new NativeHookSampleQueryInfo(); + copyType.eventType = type.eventType; + copyType.subType = type.subType; + return copyType; + }); + queryAllHookData(data.startTs).then((result) => { + if (result.length > 0) { + let nameGroup: any = {}; + copyTypes.forEach((item) => { + nameGroup[item.eventType] = nameGroup[item.eventType] || []; + nameGroup[item.eventType].push(item); + }); + let leftTime = + TabPaneNMSampleList.tableMarkData.length == 1 + ? 0 + : TabPaneNMSampleList.tableMarkData[TabPaneNMSampleList.tableMarkData.length - 2].startTs; + result.forEach((item) => { + item.threadId = rootSample.threadId; + item.threadName = rootSample.threadName; + if (nameGroup[item.eventType] != undefined) { + if (item.subType == null) { + this.merageSampleData(leftTime, data.startTs, nameGroup[item.eventType][0], item); + } else { + let filter = nameGroup[item.eventType].filter((type: any) => { + return type.subType == item.subType; + }); + if (filter.length > 0) { + this.merageSampleData(leftTime, data.startTs, filter[0], item); + } + } + } + }); + if (this.sampleTypesList.length > 0) { + let sampleTypesListElement = this.sampleTypesList[this.sampleTypesList.length - 1]; + sampleTypesListElement.forEach((item: any, index: number) => { + copyTypes[index].current = copyTypes[index].growth; + if (index < copyTypes.length) { + copyTypes[index].growth -= item.current; + copyTypes[index].total -= item.total; + } + }); + } else { + copyTypes.forEach((item: any, index: number) => { + item.current = item.growth; + }); + } + this.sampleTypesList.push(copyTypes); + this.createTree(nameGroup, rootSample); + rootSample.tempList = [...rootSample.children]; + this.source.push(rootSample); + } + }); + } + + static createTree(nameGroup: any, rootSample: NativeHookSamplerInfo) { + Object.keys(nameGroup).forEach((key) => { + let parentSample = new NativeHookSamplerInfo(); + parentSample.snapshot = key; + if (nameGroup[key].length > 0) { + nameGroup[key].forEach((child: any) => { + let childSample = new NativeHookSamplerInfo(); + childSample.snapshot = child.subType || child.eventType; + childSample.heapSize = child.growth; + childSample.growth = Utils.getByteWithUnit(child.growth); + childSample.total = child.total; + childSample.totalGrowth = Utils.getByteWithUnit(child.total); + childSample.existing = child.existing; + childSample.currentSize = child.current; + childSample.current = Utils.getByteWithUnit(child.current); + childSample.threadName = rootSample.threadName; + childSample.threadId = rootSample.threadId; + parentSample.merageObj(childSample); + if (childSample.snapshot != parentSample.snapshot) { + //根据名称是否一致来判断是否需要添加子节点 + childSample.children.push(...child.children); + parentSample.children.push(childSample); + } else { + parentSample.children.push(...child.children); + } + }); + } + rootSample.merageObj(parentSample); + rootSample.children.push(parentSample); + }); + } + + static prepChild(currentSample: NativeHookSamplerInfo, rootSample: NativeHookSamplerInfo) { + currentSample.heapSize -= rootSample.heapSize; + currentSample.growth = Utils.getByteWithUnit(currentSample.heapSize); + let currentMap: any = {}; + currentSample.children.forEach((currentChild) => { + currentMap[currentChild.snapshot] = currentChild; + }); + rootSample.children.forEach((rootChild) => { + if (currentMap[rootChild.snapshot] == undefined) { + let perpSample = new NativeHookSamplerInfo(); + perpSample.snapshot = rootChild.snapshot; + currentMap[rootChild.snapshot] = perpSample; + currentSample.children.push(perpSample); + } + this.prepChild(currentMap[rootChild.snapshot], rootChild); + }); + } + + static clearData() { + this.types = []; + this.source = []; + this.tblData!.dataSource = []; + this.tbl!.recycleDataSource = []; + this.sampleTypesList = []; + this.tableMarkData = []; + TabPaneNMSampleList.filter!.firstSelect = '0'; + } + + static numberToWord(num: number) { + let word = ''; + while (num > 0) { + let end = num % 26; + end = end === 0 ? (end = 26) : end; + word = String.fromCharCode(96 + end) + word; + num = (num - end) / 26; + } + return word.toUpperCase(); + } + + startWorker(args: Map, handler: Function) { + procedurePool.submitWithName('logic1', 'native-memory-action', args, undefined, (res: any) => { + handler(res); + }); + } + + setRightTableData(sample: NativeHookSamplerInfo) { + let args = new Map(); + args.set('eventId', sample.eventId); + args.set('actionType', 'memory-stack'); + this.startWorker(args, (results: any[]) => { + let source = []; + if (results.length > 0) { + let thread = new NativeHookCallInfo(); + thread.threadId = sample.threadId; + thread.threadName = sample.threadName; + thread.title = `${sample.threadName ?? ''}【${sample.threadId}】`; + thread.type = -1; + source.push(thread); + source.push(...results); + } + // @ts-ignore + TabPaneNMSampleList.tblData?.dataSource = source; + }); + } + + initElements(): void { + TabPaneNMSampleList.tbl = this.shadowRoot?.querySelector('#tb-native-sample'); + TabPaneNMSampleList.tbl!.addEventListener('row-click', (evt: any) => { + // @ts-ignore + this.setRightTableData(evt.detail.data); + }); + TabPaneNMSampleList.tblData = this.shadowRoot?.querySelector('#tb-native-data'); + TabPaneNMSampleList.filter = this.shadowRoot?.querySelector('#filter'); + this.shadowRoot?.querySelector('#filter')!.setSelectList(TabPaneNMSampleList.native_type, null); + this.shadowRoot?.querySelector('#filter')!.getFilterData((data: FilterData) => { + if (data.firstSelect) { + TabPaneNMSampleList.filterSelect = data.firstSelect; + this.filterAllList(); + } + }); + TabPaneNMSampleList.filter!.firstSelect = TabPaneNMSampleList.filterSelect; + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + TabPaneNMSampleList.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + TabPaneNMSampleList.tbl?.reMeauseHeight(); + // @ts-ignore + TabPaneNMSampleList.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 + 'px'; + TabPaneNMSampleList.tblData?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + filterAllList() { + TabPaneNMSampleList.source.forEach((rootSample) => { + rootSample.heapSize = 0; + rootSample.existing = 0; + rootSample.total = 0; + if (TabPaneNMSampleList.filterSelect == '0') { + rootSample.children = [...rootSample.tempList]; + rootSample.tempList.forEach((parentSample) => { + rootSample.heapSize += parentSample.heapSize; + rootSample.existing += parentSample.existing; + rootSample.total += parentSample.total; + }); + rootSample.growth = Utils.getByteWithUnit(rootSample.heapSize); + rootSample.totalGrowth = Utils.getByteWithUnit(rootSample.total); + } else if (TabPaneNMSampleList.filterSelect == '2') { + if (rootSample.tempList.length > 1) { + rootSample.children = [rootSample.tempList[1]]; + rootSample.heapSize += rootSample.tempList[1].heapSize; + rootSample.existing += rootSample.tempList[1].existing; + rootSample.growth = Utils.getByteWithUnit(rootSample.heapSize); + rootSample.total += rootSample.tempList[1].total; + rootSample.totalGrowth = Utils.getByteWithUnit(rootSample.total); + } else { + rootSample.children = []; + rootSample.growth = ''; + rootSample.totalGrowth = ''; + } + } else { + if (rootSample.tempList.length > 0) { + rootSample.children = [rootSample.tempList[0]]; + rootSample.heapSize += rootSample.tempList[0].heapSize; + rootSample.existing += rootSample.tempList[0].existing; + rootSample.growth = Utils.getByteWithUnit(rootSample.heapSize); + rootSample.total += rootSample.tempList[0].total; + rootSample.totalGrowth = Utils.getByteWithUnit(rootSample.total); + } else { + rootSample.children = []; + rootSample.growth = ''; + rootSample.totalGrowth = ''; + } + } + }); + TabPaneNMSampleList.tbl!.recycleDataSource = TabPaneNMSampleList.source; + } + + initHtml(): string { + return ` + + +
+ + + + + + + + + + + + + +
+ + + + + + + + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..6548d6bd363f1bfeef94641a8c896af0d8255b39 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.ts @@ -0,0 +1,1156 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { LitChartPie } from '../../../../../base-ui/chart/pie/LitChartPie.js'; +import '../../../../../base-ui/chart/pie/LitChartPie.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; +import { procedurePool } from '../../../../database/Procedure.js'; +const TYPE_ALLOC_STRING = 'AllocEvent'; +const TYPE_MAP_STRING = 'MmapEvent'; + +const TYPE_ALLOC = 0; +const TYPE_MAP = 1; +const TYPE_FREE = 2; +const TYPE_UN_MAP = 3; +const PIE_CHART_LIMIT = 20; + +class AnalysisObj { + tName?: string; + tid?: number; + typeName?: string; + typeId?: number; + libName?: string; + libId?: number; + symbolName?: string; + symbolId?: number; + + tableName = ''; + + applySize: number; + applySizeFormat: string; + applyCount: number; + releaseSize: number; + releaseSizeFormat: string; + releaseCount: number; + existSize: number; + existSizeFormat: string; + existCount: number; + + applySizePercent?: string; + applyCountPercent?: string; + releaseSizePercent?: string; + releaseCountPercent?: string; + existSizePercent?: string; + existCountPercent?: string; + + constructor(applySize: number, applyCount: number, releaseSize: number, releaseCount: number) { + this.applySize = applySize; + this.applyCount = applyCount; + this.releaseSize = releaseSize; + this.releaseCount = releaseCount; + this.existSize = applySize - releaseSize; + this.existCount = applyCount - releaseCount; + this.applySizeFormat = Utils.getBinaryByteWithUnit(this.applySize); + this.releaseSizeFormat = Utils.getBinaryByteWithUnit(this.releaseSize); + this.existSizeFormat = Utils.getBinaryByteWithUnit(this.existSize); + } +} + +class SizeObj { + applySize = 0; + applyCount = 0; + releaseSize = 0; + releaseCount = 0; +} + +@element('tabpane-nm-statistic-analysis') +export class TabPaneNMStatisticAnalysis extends BaseElement { + private currentSelection: SelectionParam | any; + private pie: LitChartPie | null | undefined; + private processData!: Array; + private eventTypeData!: any[]; + private threadData!: any[]; + private soData!: any[]; + private functionData!: any[]; + private tableType: LitTable | null | undefined; + private tableThread: LitTable | null | undefined; + private tableSo: LitTable | null | undefined; + private tableFunction: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private back: HTMLDivElement | null | undefined; + private tabName: HTMLDivElement | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private type: string | null | undefined; + private sortColumn: string = ''; + private sortType: number = 0; + private isStatistic = false; + private typeMap!: Map>; + private currentLevel = -1; + private currentLevelApplySize = 0; + private currentLevelReleaseSize = 0; + private currentLevelExistSize = 0; + private currentLevelApplyCount = 0; + private currentLevelReleaseCount = 0; + private currentLevelExistCount = 0; + private releaseLibMap!: Map; + private currentLevelData!: Array; + private typeStatisticsData!: {}; + private libStatisticsData!: {}; + private functionStatisticsData!: {}; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + this.eventTypeData.unshift(this.typeStatisticsData); + this.tableType!.recycleDataSource = this.eventTypeData; + // @ts-ignore + this.eventTypeData.shift(this.typeStatisticsData); + return; + } + // @ts-ignore + this.tableSo?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tableFunction?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + this.clearData(); + this.currentSelection = val; + this.tableType!.style.display = 'grid'; + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + this.isStatistic = val.nativeMemory.length === 0; + + this.getNMEventTypeSize(val); + } + initElements(): void { + this.range = this.shadowRoot?.querySelector('#time-range'); + this.pie = this.shadowRoot!.querySelector('#chart-pie'); + this.tableType = this.shadowRoot!.querySelector('#tb-eventtype-usage'); + this.tableThread = this.shadowRoot!.querySelector('#tb-thread-usage'); + this.tableSo = this.shadowRoot!.querySelector('#tb-so-usage'); + this.tableFunction = this.shadowRoot!.querySelector('#tb-function-usage'); + this.back = this.shadowRoot!.querySelector('.go-back'); + this.tabName = this.shadowRoot!.querySelector('.subheading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.getBack(); + } + clearData() { + this.pie!.dataSource = []; + this.tableType!.recycleDataSource = []; + this.tableThread!.recycleDataSource = []; + this.tableSo!.recycleDataSource = []; + this.tableFunction!.recycleDataSource = []; + } + getBack() { + this.back!.addEventListener('click', () => { + if (this.tabName!.textContent === 'Statistic By Library Existing') { + this.tableType!.style.display = 'grid'; + this.tableSo!.style.display = 'none'; + this.back!.style.visibility = 'hidden'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableType?.removeAttribute('hideDownload'); + this.currentLevel = 0; + this.currentLevelData = this.eventTypeData; + this.typePieChart(this.currentSelection); + } else if (this.tabName!.textContent === 'Statistic By Function Existing') { + this.tableSo!.style.display = 'grid'; + this.tableFunction!.style.display = 'none'; + this.tableFunction!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.currentLevelData = this.soData; + this.currentLevel = 1; + this.libraryPieChart(this.currentSelection); + } + }); + } + typePieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.eventTypeData, + angleField: 'existSize', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Memory Type:${obj.obj.tableName}
+
Existing:${obj.obj.existSizeFormat} (${obj.obj.existSizePercent}%)
+
# Existing:${obj.obj.existCount} (${obj.obj.existCountPercent}%)
+
Total Bytes:${obj.obj.applySizeFormat} (${obj.obj.applySizePercent}%)
+
# Total:${obj.obj.applyCount} (${obj.obj.applyCountPercent}%)
+
Transient:${obj.obj.releaseSizeFormat} (${obj.obj.releaseSizePercent}%)
+
# Transient:${obj.obj.releaseCount} (${obj.obj.releaseCountPercent}%)
+
`; + }, + angleClick: (it: any) => { + this.clearData(); + this.back!.style.visibility = 'visible'; + this.tableType!.style.display = 'none'; + this.tableSo!.style.display = 'grid'; + this.tableType!.setAttribute('hideDownload', ''); + this.tableSo?.removeAttribute('hideDownload'); + this.getLibSize(it, val); + // @ts-ignore + this.shadowRoot!.querySelector('.title')!.textContent = it.typeName; + // @ts-ignore + this.type = it.typeName; + this.pie?.hideTip(); + }, + hoverHandler: (data) => { + if (data) { + this.tableType!.setCurrentHover(data); + } else { + this.tableType!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableType!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = ''; + this.tabName!.textContent = 'Statistic By Event Type Existing'; + this.eventTypeData.unshift(this.typeStatisticsData); + this.tableType!.recycleDataSource = this.eventTypeData; + this.currentLevelData = JSON.parse(JSON.stringify(this.eventTypeData)); + // @ts-ignore + this.eventTypeData.shift(this.typeStatisticsData); + this.tableType?.reMeauseHeight(); + } + threadPieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.threadData), + angleField: 'existSize', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Thread:${obj.obj.tableName}
+
Existing:${obj.obj.existSizeFormat} (${obj.obj.existSizePercent}%)
+
# Existing:${obj.obj.existCount} (${obj.obj.existCountPercent}%)
+
Total Bytes:${obj.obj.applySizeFormat} (${obj.obj.applySizePercent}%)
+
# Total:${obj.obj.applyCount} (${obj.obj.applyCountPercent}%)
+
Transient:${obj.obj.releaseSizeFormat} (${obj.obj.releaseSizePercent}%)
+
# Transient:${obj.obj.releaseCount} (${obj.obj.releaseCountPercent}%)
+
`; + }, + angleClick: (it: any) => { + // @ts-ignore + if (it.tid != 'other') { + this.clearData(); + this.tableThread!.style.display = 'none'; + this.tableSo!.style.display = 'grid'; + this.getLibSize(it, val); + // @ts-ignore + this.shadowRoot!.querySelector('.title')!.textContent = it.type + ' / ' + 'Thread ' + it.tid; + // @ts-ignore + this.tid = it.tid; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableThread!.setCurrentHover(data); + } else { + this.tableThread!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableThread!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.shadowRoot!.querySelector('.title')!.textContent = this.type + ''; + this.tabName!.textContent = 'Statistic By Thread Existing'; + this.tableThread!.recycleDataSource = this.threadData; + this.tableThread?.reMeauseHeight(); + } + libraryPieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.soData), + angleField: 'existSize', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Library:${obj.obj.libName}
+
Existing:${obj.obj.existSizeFormat} (${obj.obj.existSizePercent}%)
+
# Existing:${obj.obj.existCount} (${obj.obj.existCountPercent}%)
+
Total Bytes:${obj.obj.applySizeFormat} (${obj.obj.applySizePercent}%)
+
# Total:${obj.obj.applyCount} (${obj.obj.applyCountPercent}%)
+
Transient:${obj.obj.releaseSizeFormat} (${obj.obj.releaseSizePercent}%)
+
# Transient:${obj.obj.releaseCount} (${obj.obj.releaseCountPercent}%)
+
`; + }, + angleClick: (it: any) => { + // @ts-ignore + if (it.tableName != 'other') { + this.clearData(); + this.tableSo!.style.display = 'none'; + this.tableFunction!.style.display = 'grid'; + this.tableSo!.setAttribute('hideDownload', ''); + this.tableFunction?.removeAttribute('hideDownload'); + this.getNMFunctionSize(it, val); + // @ts-ignore + this.shadowRoot!.querySelector('.title')!.textContent = this.type + ' / ' + it.libName; + this.pie?.hideTip(); + } + }, + hoverHandler: (data) => { + if (data) { + this.tableSo!.setCurrentHover(data); + } else { + this.tableSo!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.shadowRoot!.querySelector('.title')!.textContent = this.type + ''; + this.tableSo!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.tabName!.textContent = 'Statistic By Library Existing'; + this.soData.unshift(this.libStatisticsData); + this.currentLevelData = JSON.parse(JSON.stringify(this.soData)); + this.tableSo!.recycleDataSource = this.soData; + // @ts-ignore + this.soData.shift(this.libStatisticsData); + this.tableSo?.reMeauseHeight(); + this.tableSo!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + + functionPieChart(val: any) { + this.pie!.config = { + appendPadding: 0, + data: this.getPieChartData(this.functionData), + angleField: 'existSize', + colorField: 'tableName', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj) => { + return `
+
Function:${obj.obj.symbolName}
+
Existing:${obj.obj.existSizeFormat} (${obj.obj.existSizePercent}%)
+
# Existing:${obj.obj.existCount} (${obj.obj.existCountPercent}%)
+
Total Bytes:${obj.obj.applySizeFormat} (${obj.obj.applySizePercent}%)
+
# Total:${obj.obj.applyCount} (${obj.obj.applyCountPercent}%)
+
Transient:${obj.obj.releaseSizeFormat} (${obj.obj.releaseSizePercent}%)
+
# Transient:${obj.obj.releaseCount} (${obj.obj.releaseCountPercent}%)
+
`; + }, + hoverHandler: (data) => { + if (data) { + this.tableFunction!.setCurrentHover(data); + } else { + this.tableFunction!.mouseOut(); + } + }, + interactions: [ + { + type: 'element-active', + }, + ], + }; + this.tableFunction!.addEventListener('row-hover', (evt: any) => { + if (evt.detail.data) { + let data = evt.detail.data; + data.isHover = true; + if ((evt.detail as any).callBack) { + (evt.detail as any).callBack(true); + } + } + this.pie?.showHover(); + this.pie?.hideTip(); + }); + this.functionData.unshift(this.functionStatisticsData); + this.currentLevelData = JSON.parse(JSON.stringify(this.functionData)); + this.tableFunction!.recycleDataSource = this.functionData; + // @ts-ignore + this.functionData.shift(this.functionStatisticsData); + this.tableFunction?.reMeauseHeight(); + this.tableFunction!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + let currentTable: LitTable | null | undefined; + switch (this.currentLevel) { + case 0: + currentTable = this.tableType; + break; + case 1: + currentTable = this.tableSo; + break; + case 2: + currentTable = this.tableFunction; + break; + } + if (!currentTable) { + return; + } + if (sort == 0) { + currentTable!.recycleDataSource = this.currentLevelData; + } else { + let arr = [...this.currentLevelData]; + switch (this.currentLevel) { + case 0: + // @ts-ignore + arr.shift(this.typeStatisticsData); + break; + case 1: + // @ts-ignore + arr.shift(this.libStatisticsData); + break; + case 2: + // @ts-ignore + arr.shift(this.functionStatisticsData); + break; + } + if (column == 'tableName') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.tableName > b.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } else { + if (b.tableName > a.tableName) { + return 1; + } else if (a.tableName == b.tableName) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'existSizeFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.existSize - b.existSize : b.existSize - a.existSize; + }); + } else if (column == 'existSizePercent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.existSize - b.existSize : b.existSize - a.existSize; + }); + } else if (column == 'existCount') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.existCount - b.existCount : b.existCount - a.existCount; + }); + } else if (column == 'existCountPercent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.existCount - b.existCount : b.existCount - a.existCount; + }); + } else if (column == 'releaseSizeFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.releaseSize - b.releaseSize : b.releaseSize - a.releaseSize; + }); + }else if (column == 'releaseSizePercent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.releaseSize - b.releaseSize : b.releaseSize - a.releaseSize; + }); + }else if (column == 'releaseCount') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.releaseCount - b.releaseCount : b.releaseCount - a.releaseCount; + }); + }else if (column == 'releaseCountPercent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.releaseCount - b.releaseCount : b.releaseCount - a.releaseCount; + }); + }else if (column == 'applySizeFormat') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.applySize - b.applySize : b.applySize - a.applySize; + }); + }else if (column == 'applySizePercent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.applySize - b.applySize : b.applySize - a.applySize; + }); + }else if (column == 'applyCount') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.applyCount - b.applyCount : b.applyCount - a.applyCount; + }); + }else if (column == 'applyCountPercent') { + currentTable!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.applyCount - b.applyCount : b.applyCount - a.applyCount; + }); + } + switch (this.currentLevel) { + case 0: + arr.unshift(this.typeStatisticsData); + break; + case 1: + arr.unshift(this.libStatisticsData); + break; + case 2: + arr.unshift(this.functionStatisticsData); + break; + } + currentTable!.recycleDataSource = arr; + } + } + + getNMEventTypeSize(val: any) { + this.progressEL!.loading = true; + let typeFilter = []; + if (this.isStatistic) { + for (let type of val.nativeMemoryStatistic) { + if (type === 'All Heap & Anonymous VM') { + typeFilter = [0, 1]; + break; + } else if (type === 'All Heap') { + typeFilter.push(0); + } else { + typeFilter.push(1); + } + } + this.getDataFromWorker(val, typeFilter); + } else { + for (let type of val.nativeMemory) { + if (type === 'All Heap & Anonymous VM') { + typeFilter = []; + typeFilter.push(...["'AllocEvent'", "'FreeEvent'", "'MmapEvent'", "'MunmapEvent'"]); + break; + } else if (type === 'All Heap') { + typeFilter.push(...["'AllocEvent'", "'FreeEvent'"]); + } else { + typeFilter.push(...["'MmapEvent'", "'MunmapEvent'"]); + } + } + this.getDataFromWorker(val, typeFilter); + } + + this.tableType!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + + private calTypeSize(val: any, result: any) { + this.processData = JSON.parse(JSON.stringify(result)); + this.resetCurrentLevelData(); + this.typeMap = this.typeSizeGroup(this.processData); + this.currentLevelExistSize = this.currentLevelApplySize - this.currentLevelReleaseSize; + this.currentLevelExistCount = this.currentLevelApplyCount - this.currentLevelReleaseCount; + this.eventTypeData = []; + if (this.typeMap.has(TYPE_ALLOC)) { + let allocType = this.setTypeMap(this.typeMap, TYPE_ALLOC, TYPE_ALLOC_STRING); + if (allocType) { + this.calPercent(allocType); + this.eventTypeData.push(allocType); + } + } + if (this.typeMap.has(TYPE_MAP)) { + let mapType = this.setTypeMap(this.typeMap, TYPE_MAP, TYPE_MAP_STRING); + if (mapType) { + this.calPercent(mapType); + this.eventTypeData.push(mapType); + } + } + this.eventTypeData.sort((a, b) => b.existSize - a.existCount); + this.typeStatisticsData = this.totalData(this.typeStatisticsData); + this.progressEL!.loading = false; + this.currentLevel = 0; + this.typePieChart(val); + } + + getNMThreadSize(item: any, val: any) { + this.progressEL!.loading = true; + let threadMap = new Map>(); + let types = this.getTypes(item); + this.resetCurrentLevelData(item); + + for (let itemData of this.processData) { + // @ts-ignore + if (!types.includes(itemData.type)) { + continue; + } + if (threadMap.has(itemData.tid)) { + threadMap.get(itemData.tid)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + threadMap.set(itemData.tid, itemArray); + } + } + this.threadData = []; + threadMap.forEach((dbData: Array, tid: number) => { + const sizeObj = this.calSizeObj(dbData); + let analysis = new AnalysisObj(sizeObj.applySize, sizeObj.applyCount, sizeObj.releaseSize, sizeObj.releaseCount); + this.calPercent(analysis); + analysis.typeId = item.typeId; + analysis.typeName = item.typeName; + analysis.tid = tid; + analysis.tName = 'Thread ' + tid; + analysis.tableName = analysis.tName; + this.threadData.push(analysis); + }); + this.threadData.sort((a, b) => b.existSize - a.existSize); + this.currentLevelData = this.threadData; + this.progressEL!.loading = false; + this.threadPieChart(val); + this.tableThread!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + + getLibSize(item: any, val: any) { + this.progressEL!.loading = true; + let typeId = item.typeId; + let typeName = item.typeName; + let tid = item.tid; + let libMap = new Map>(); + this.resetCurrentLevelData(item); + let types = this.getTypes(item); + this.soData = []; + if (!this.processData) return; + for (let itemData of this.processData) { + // @ts-ignore + if (!types.includes(itemData.type)) { + continue; + } + let libId = itemData.libId; + + if (libMap.has(libId)) { + libMap.get(libId)?.push(itemData); + } else { + let dataArray = new Array(); + dataArray.push(itemData); + libMap.set(libId, dataArray); + } + } + libMap.forEach((libItems, libId) => { + let libPath = SpSystemTrace.DATA_DICT.get(libId)?.split('/'); + let libName = ''; + if (libPath) { + libName = libPath[libPath.length - 1]; + } + const sizeObj = this.calSizeObj(libItems); + let analysis = new AnalysisObj(sizeObj.applySize, sizeObj.applyCount, sizeObj.releaseSize, sizeObj.releaseCount); + this.calPercent(analysis); + analysis.typeId = typeId; + analysis.typeName = typeName; + analysis.tid = tid; + analysis.tName = 'Thread ' + tid; + analysis.libId = libId; + analysis.libName = libName; + analysis.tableName = analysis.libName; + this.soData.push(analysis); + }); + this.soData.sort((a, b) => b.existSize - a.existSize); + this.libStatisticsData = this.totalData(this.libStatisticsData); + this.currentLevel = 1; + this.libraryPieChart(val); + this.progressEL!.loading = false; + } + + getNMFunctionSize(item: any, val: any) { + this.progressEL!.loading = true; + this.shadowRoot!.querySelector('.subheading')!.textContent = 'Statistic By Function Existing'; + let typeId = item.typeId; + let typeName = item.typeName; + let tid = item.tid; + let libId = item.libId; + let symbolMap = new Map>(); + this.resetCurrentLevelData(item); + let types = this.getTypes(item); + if (!this.processData) { + return; + } + for (let data of this.processData) { + // @ts-ignore + if (!types.includes(data.type) || data.libId !== libId) { + continue; + } + if (symbolMap.has(data.symbolId)) { + symbolMap.get(data.symbolId)?.push(data); + } else { + let dataArray = new Array(); + dataArray.push(data); + symbolMap.set(data.symbolId, dataArray); + } + } + + this.functionData = []; + symbolMap.forEach((symbolItems, symbolId) => { + let symbolPath = SpSystemTrace.DATA_DICT.get(symbolId)?.split('/'); + let symbolName = symbolPath ? symbolPath[symbolPath.length - 1] : 'null'; + const sizeObj = this.calSizeObj(symbolItems); + let analysis = new AnalysisObj(sizeObj.applySize, sizeObj.applyCount, sizeObj.releaseSize, sizeObj.releaseCount); + this.calPercent(analysis); + analysis.typeId = typeId; + analysis.typeName = typeName; + analysis.tid = tid; + analysis.tName = 'Thread ' + tid; + analysis.libId = libId; + analysis.libName = item.libName; + analysis.symbolId = symbolId; + analysis.symbolName = symbolName; + analysis.tableName = analysis.symbolName; + this.functionData.push(analysis); + }); + this.functionData.sort((a, b) => b.existSize - a.existSize); + // @ts-ignore + this.functionStatisticsData = this.totalData(this.functionStatisticsData); + this.currentLevel = 2; + this.progressEL!.loading = false; + this.functionPieChart(val); + } + + getPieChartData(res: any[]) { + if (res.length > PIE_CHART_LIMIT) { + let pieChartArr: any[] = []; + let other: any = { + tableName: 'other', + symbolName: 'other', + existSizePercent: 0, + libName: 'other', + existSize: 0, + existSizeFormat: '', + existCount: 0, + countPercent: 'other', + existCountPercent: 0, + }; + for (let i = 0; i < res.length; i++) { + if (i < PIE_CHART_LIMIT - 1) { + pieChartArr.push(res[i]); + } else { + other.existCount += res[i].existCount; + other.existSize += res[i].existSize; + other.existSizeFormat = Utils.getBinaryByteWithUnit(other.existSize); + other.existSizePercent = ((other.existSize / this.currentLevelExistSize) * 100).toFixed(2); + other.existCountPercent = ((other.existCount / this.currentLevelExistCount) * 100).toFixed(2); + } + } + pieChartArr.push(other); + return pieChartArr; + } + return res; + } + + setTypeMap(typeMap: Map, tyeId: number, typeName: string): AnalysisObj | null { + let applySize = 0; + let releaseSize = 0; + let applyCount = 0; + let releaseCount = 0; + let releaseTypeId = tyeId === TYPE_ALLOC ? TYPE_FREE : TYPE_UN_MAP; + let currentType = typeMap.get(tyeId); + if (!currentType) { + return null; + } + + if (!this.isStatistic) { + if (typeMap.has(releaseTypeId)) { + for (let freeSample of typeMap.get(releaseTypeId)!) { + releaseSize += freeSample.size; + releaseCount += freeSample.count; + } + } + } + + for (let applySample of typeMap.get(tyeId)!) { + applySize += applySample.size; + applyCount += applySample.count; + if (this.isStatistic) { + releaseSize += applySample.releaseSize; + releaseCount += applySample.releaseCount; + } + } + let typeItem = new AnalysisObj(applySize, applyCount, releaseSize, releaseCount); + typeItem.typeId = tyeId; + typeItem.typeName = typeName; + typeItem.tableName = typeName; + return typeItem; + } + + calSize(sizeObj: SizeObj, itemData: any): any { + switch (itemData.type) { + case TYPE_ALLOC: + case TYPE_MAP: + sizeObj.applySize += itemData.size; + sizeObj.applyCount += itemData.count; + if (this.isStatistic) { + sizeObj.releaseSize += itemData.releaseSize; + sizeObj.releaseCount += itemData.releaseCount; + } + break; + case TYPE_FREE: + case TYPE_UN_MAP: + sizeObj.releaseSize += itemData.size; + sizeObj.releaseCount += itemData.count; + break; + } + } + + private calPercent(item: AnalysisObj) { + item.applySizePercent = ((item.applySize / this.currentLevelApplySize) * 100).toFixed(2); + item.applyCountPercent = ((item.applyCount / this.currentLevelApplyCount) * 100).toFixed(2); + item.releaseSizePercent = ((item.releaseSize / this.currentLevelReleaseSize) * 100).toFixed(2); + item.releaseCountPercent = ((item.releaseCount / this.currentLevelReleaseCount) * 100).toFixed(2); + item.existSizePercent = ((item.existSize / this.currentLevelExistSize) * 100).toFixed(2); + item.existCountPercent = ((item.existCount / this.currentLevelExistCount) * 100).toFixed(2); + } + + private resetCurrentLevelData(parent?: any) { + if (parent) { + this.currentLevelApplySize = parent.applySize; + this.currentLevelApplyCount = parent.applyCount; + this.currentLevelExistSize = parent.existSize; + this.currentLevelExistCount = parent.existCount; + this.currentLevelReleaseSize = parent.releaseSize; + this.currentLevelReleaseCount = parent.releaseCount; + } else { + this.currentLevelApplySize = 0; + this.currentLevelApplyCount = 0; + this.currentLevelExistSize = 0; + this.currentLevelExistCount = 0; + this.currentLevelReleaseSize = 0; + this.currentLevelReleaseCount = 0; + } + } + + private typeSizeGroup(dbArray: Array): Map> { + let typeMap = new Map>(); + if (!dbArray || dbArray.length == 0) { + return typeMap; + } + + for (let itemData of dbArray) { + switch (itemData.type) { + case TYPE_ALLOC: + this.currentLevelApplySize += itemData.size; + this.currentLevelApplyCount += itemData.count; + if (this.isStatistic) { + this.currentLevelReleaseSize += itemData.releaseSize; + this.currentLevelReleaseCount += itemData.releaseCount; + } + if (typeMap.has(TYPE_ALLOC)) { + typeMap.get(TYPE_ALLOC)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(TYPE_ALLOC, itemArray); + } + break; + case TYPE_MAP: + this.currentLevelApplySize += itemData.size; + this.currentLevelApplyCount += itemData.count; + if (this.isStatistic) { + this.currentLevelReleaseSize += itemData.releaseSize; + this.currentLevelReleaseCount += itemData.releaseCount; + } + if (typeMap.has(TYPE_MAP)) { + typeMap.get(TYPE_MAP)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(TYPE_MAP, itemArray); + } + break; + case TYPE_FREE: + this.currentLevelReleaseSize += itemData.size; + this.currentLevelReleaseCount += itemData.count; + if (typeMap.has(TYPE_FREE)) { + typeMap.get(TYPE_FREE)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(TYPE_FREE, itemArray); + } + break; + case TYPE_UN_MAP: + this.currentLevelReleaseSize += itemData.size; + this.currentLevelReleaseCount += itemData.count; + if (typeMap.has(TYPE_UN_MAP)) { + typeMap.get(TYPE_UN_MAP)?.push(itemData); + } else { + let itemArray = new Array(); + itemArray.push(itemData); + typeMap.set(TYPE_UN_MAP, itemArray); + } + break; + } + } + + return typeMap; + } + + totalData(total: any) { + total = { + existSizeFormat: Utils.getBinaryByteWithUnit(this.currentLevelExistSize), + existSizePercent: ((this.currentLevelExistSize / this.currentLevelExistSize) * 100).toFixed(2), + existCount: this.currentLevelExistCount, + existCountPercent: ((this.currentLevelExistCount / this.currentLevelExistCount) * 100).toFixed(2), + releaseSizeFormat: Utils.getBinaryByteWithUnit(this.currentLevelReleaseSize), + releaseSizePercent:((this.currentLevelReleaseSize / this.currentLevelReleaseSize) * 100).toFixed(2), + releaseCount:this.currentLevelReleaseCount, + releaseCountPercent:((this.currentLevelReleaseCount / this.currentLevelReleaseCount) * 100).toFixed(2), + applySizeFormat:Utils.getBinaryByteWithUnit(this.currentLevelApplySize), + applySizePercent:((this.currentLevelApplySize / this.currentLevelApplySize) * 100).toFixed(2), + applyCount:this.currentLevelApplyCount, + applyCountPercent:((this.currentLevelApplyCount / this.currentLevelApplyCount) * 100).toFixed(2), + existSize: 0, + tableName: '', + libName: '', + symbolName: '', + }; + return total; + } + + calSizeObj(dbData: Array) { + let sizeObj = new SizeObj(); + for (let item of dbData) { + if (this.isStatistic) { + sizeObj.applyCount += item.count; + sizeObj.applySize += item.size; + sizeObj.releaseCount += item.releaseCount; + sizeObj.releaseSize += item.releaseSize; + } else { + // @ts-ignore + if ([TYPE_ALLOC, TYPE_MAP].includes(item.type)) { + sizeObj.applyCount += item.count; + sizeObj.applySize += item.size; + } else { + sizeObj.releaseCount += item.count; + sizeObj.releaseSize += item.size; + } + } + } + return sizeObj; + } + + getTypes(parent: AnalysisObj) { + let types = new Array(); + types.push(parent.typeId!); + if (!this.isStatistic) { + let releaseType; + if (parent.typeId === TYPE_ALLOC) { + releaseType = TYPE_FREE; + } else { + releaseType = TYPE_UN_MAP; + } + types.push(releaseType); + } + return types; + } + + getDataFromWorker(val: SelectionParam | any, typeFilter: Array) { + this.getDataByWorkerQuery( + { + leftNs: val.leftNs, + rightNs: val.rightNs, + types: typeFilter, + isStatistic: this.isStatistic, + }, + (results: any) => { + this.calTypeSize(val, results); + } + ); + } + getDataByWorkerQuery(args: any, handler: Function) { + this.progressEL!.loading = true; + procedurePool.submitWithName('logic1', 'native-memory-queryAnalysis', args, undefined, (results: any) => { + handler(results); + this.progressEL!.loading = false; + }); + } + + initHtml(): string { + return ` + + +
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
+
+`; + } +} diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd34782e8e4fdebe85aac319c91c1fca15bca62d --- /dev/null +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.ts @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { + queryNativeHookResponseTypes, + queryNativeHookStatistics, + queryNativeHookStatisticsMalloc, + queryNativeHookStatisticsSubType, +} from '../../../../database/SqlLite.js'; +import { NativeHookMalloc, NativeHookStatisticsTableData } from '../../../../bean/NativeHook.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; +import '../TabProgressBar.js'; +import { SpNativeMemoryChart } from '../../../chart/SpNativeMemoryChart.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-native-statistics') +export class TabPaneNMStatstics extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private native_type: Array = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + private allMax: number = 0; + private sortColumn: string = ''; + private sortType: number = 0; + private currentSelection: SelectionParam | undefined; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + this.allMax = 0; + SpNativeMemoryChart.EVENT_HEAP.map((heap) => { + this.allMax += heap.sumHeapSize; + }); + this.initResponseTypeList(val); + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 + 'px'; + // @ts-ignore + this.tbl?.recycleDataSource = []; + Promise.all([ + queryNativeHookStatistics(val.leftNs, val.rightNs), + queryNativeHookStatisticsSubType(val.leftNs, val.rightNs), + queryNativeHookStatisticsMalloc(val.leftNs, val.rightNs), + ]).then((values) => { + let arr: Array = []; + let index1 = val.nativeMemory.indexOf(this.native_type[0]); + let index2 = val.nativeMemory.indexOf(this.native_type[1]); + let index3 = val.nativeMemory.indexOf(this.native_type[2]); + this.setMemoryTypeData(val, values[0], arr); + if (index1 != -1 || index3 != -1) { + this.setSubTypeTableData(values[1], arr); + } + let type = 0; + if (index1 != -1 || (index2 != -1 && index3 != -1)) { + type = 0; + } else { + type = index2 != -1 ? 1 : 2; + } + this.setMallocTableData(values[2], arr, type); + this.source = arr; + this.sortByColumn(this.sortColumn, this.sortType); + }); + } + + setMallocTableData(result: Array, arr: Array, type: number) { + result.map((malloc) => { + let data = new NativeHookStatisticsTableData(); + if (malloc.eventType == 'AllocEvent') { + data.memoryTap = 'Malloc ' + Utils.getByteWithUnit(malloc.heapSize); + } else { + data.memoryTap = 'Mmap ' + Utils.getByteWithUnit(malloc.heapSize); + } + data.existing = malloc.allocByte - malloc.freeByte; + data.allocCount = malloc.allocCount - malloc.freeCount; + data.freeCount = malloc.freeCount; + data.freeByte = malloc.freeByte; + data.totalBytes = malloc.allocByte; + data.totalCount = malloc.allocCount; + data.max = malloc.heapSize; + data.existingString = Utils.getByteWithUnit(data.existing); + data.freeByteString = Utils.getByteWithUnit(malloc.freeByte); + data.totalBytesString = Utils.getByteWithUnit(data.totalBytes); + data.maxStr = Utils.getByteWithUnit(malloc.heapSize); + data.existingValue = [data.existing, data.totalBytes, this.allMax]; + if (type == 0) { + arr.push(data); + } else if (type == 1 && malloc.eventType == 'AllocEvent') { + arr.push(data); + } else if (type == 2 && malloc.eventType == 'MmapEvent') { + arr.push(data); + } else { + } + }); + } + + setSubTypeTableData(result: Array, arr: Array) { + result.map((sub) => { + let subType = SpSystemTrace.DATA_DICT.get(sub.subTypeId); + if (subType != null && subType != undefined) { + let data = new NativeHookStatisticsTableData(); + data.memoryTap = subType; + data.existing = sub.allocByte - sub.freeByte; + data.allocCount = sub.allocCount - sub.freeCount; + data.freeCount = sub.freeCount; + data.freeByte = sub.freeByte; + data.totalBytes = sub.allocByte; + data.totalCount = sub.allocCount; + data.max = sub.max; + data.freeByteString = Utils.getByteWithUnit(sub.freeByte); + data.existingString = Utils.getByteWithUnit(data.existing); + data.totalBytesString = Utils.getByteWithUnit(data.totalBytes); + data.maxStr = Utils.getByteWithUnit(sub.max); + data.existingValue = [data.existing, data.totalBytes, this.allMax]; + arr.push(data); + } + }); + } + + initResponseTypeList(val: SelectionParam | any) { + let types: Array = []; + if (val.nativeMemory.indexOf('All Heap & Anonymous VM') != -1) { + types.push("'AllocEvent'"); + types.push("'MmapEvent'"); + } else { + if (val.nativeMemory.indexOf('All Heap') != -1) { + types.push("'AllocEvent'"); + } + if (val.nativeMemory.indexOf('All Anonymous VM') != -1) { + types.push("'MmapEvent'"); + } + } + queryNativeHookResponseTypes(val.leftNs, val.rightNs, types).then((res) => { + procedurePool.submitWithName('logic1', 'native-memory-init-responseType', res, undefined, () => {}); + }); + } + + setMemoryTypeData(val: SelectionParam, result: Array, arr: Array) { + let all: NativeHookStatisticsTableData | null = null; + let heap: NativeHookStatisticsTableData | null = null; + let anonymous: NativeHookStatisticsTableData | null = null; + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { + all = new NativeHookStatisticsTableData(); + all.memoryTap = this.native_type[0]; + } + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { + heap = new NativeHookStatisticsTableData(); + heap.memoryTap = this.native_type[1]; + } + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { + anonymous = new NativeHookStatisticsTableData(); + anonymous.memoryTap = this.native_type[2]; + } + for (let hook of result) { + if (all != null) { + all.totalBytes += hook.allocByte; + all.totalCount += hook.allocCount; + all.freeByte += hook.freeByte; + all.freeCount += hook.freeCount; + if (hook.max > all.max) { + all.max = hook.max; + all.maxStr = Utils.getByteWithUnit(all.max); + } + } + if (heap != null && hook.eventType == 'AllocEvent') { + heap.totalBytes += hook.allocByte; + heap.totalCount += hook.allocCount; + heap.freeByte += hook.freeByte; + heap.freeCount += hook.freeCount; + if (hook.max > heap.max) { + heap.max = hook.max; + heap.maxStr = Utils.getByteWithUnit(heap.max); + } + } + if (anonymous != null && hook.eventType == 'MmapEvent') { + anonymous.totalBytes += hook.allocByte; + anonymous.totalCount += hook.allocCount; + anonymous.freeByte += hook.freeByte; + anonymous.freeCount += hook.freeCount; + if (hook.max > anonymous.max) { + anonymous.max = hook.max; + anonymous.maxStr = Utils.getByteWithUnit(anonymous.max); + } + } + } + if (all != null) { + all.existing = all.totalBytes - all.freeByte; + all.allocCount = all.totalCount - all.freeCount; + all.existingString = Utils.getByteWithUnit(all.existing); + all.totalBytesString = Utils.getByteWithUnit(all.totalBytes); + all.freeByteString = Utils.getByteWithUnit(all.freeByte); + all.existingValue = [all.existing, all.totalBytes, this.allMax]; + arr.push(all); + } + if (heap != null) { + heap.existing = heap.totalBytes - heap.freeByte; + heap.allocCount = heap.totalCount - heap.freeCount; + heap.existingString = Utils.getByteWithUnit(heap.existing); + heap.totalBytesString = Utils.getByteWithUnit(heap.totalBytes); + heap.freeByteString = Utils.getByteWithUnit(heap.freeByte); + heap.existingValue = [heap.existing, heap.totalBytes, this.allMax]; + arr.push(heap); + } + if (anonymous != null) { + anonymous.existing = anonymous.totalBytes - anonymous.freeByte; + anonymous.allocCount = anonymous.totalCount - anonymous.freeCount; + anonymous.existingString = Utils.getByteWithUnit(anonymous.existing); + anonymous.totalBytesString = Utils.getByteWithUnit(anonymous.totalBytes); + anonymous.freeByteString = Utils.getByteWithUnit(anonymous.totalBytes - anonymous.existing); + anonymous.existingValue = [anonymous.existing, anonymous.totalBytes, this.allMax]; + arr.push(anonymous); + } + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-native-statstics'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 20 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + if (sort == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = [...this.source]; + if (column == 'existingString') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.existing - b.existing : b.existing - a.existing; + }); + } else if (column == 'allocCount') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.allocCount - b.allocCount : b.allocCount - a.allocCount; + }); + } else if (column == 'freeByteString') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 + ? a.totalBytes - a.existing - (b.totalBytes - b.existing) + : b.totalBytes - b.existing - (a.totalBytes - a.existing); + }); + } else if (column == 'freeCount') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.freeCount - b.freeCount : b.freeCount - a.freeCount; + }); + } else if (column == 'totalBytesString') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.totalBytes - b.totalBytes : b.totalBytes - a.totalBytes; + }); + } else if (column == 'maxStr') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.max - b.max : b.max - a.max; + }); + } else if (column == 'totalCount') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.totalCount - b.totalCount : b.totalCount - a.totalCount; + }); + } + } + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMemory.ts b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMemory.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4ce3ad9600ae9c322ace6800e27ff82f2142d0d --- /dev/null +++ b/ide/src/trace/component/trace/sheet/native-memory/TabPaneNMemory.ts @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { query, queryNativeHookEventTid } from '../../../../database/SqlLite.js'; +import { NativeHookStatistics, NativeMemory, NativeHookCallInfo } from '../../../../bean/NativeHook.js'; +import '../TabPaneFilter.js'; +import { FilterData, TabPaneFilter } from '../TabPaneFilter.js'; +import { TabPaneNMSampleList } from './TabPaneNMSampleList.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import { procedurePool } from '../../../../database/Procedure.js'; + +@element('tabpane-native-memory') +export class TabPaneNMemory extends BaseElement { + private defaultNativeTypes = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']; + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private progressEL: LitProgressBar | null | undefined; + private loadingList: number[] = []; + private loadingPage: any; + private source: Array = []; + private native_type: Array = [...this.defaultNativeTypes]; + private statsticsSelection: Array = []; + private queryResult: Array = []; + private filterAllocationType: string = '0'; + private filterNativeType: string = '0'; + private filterResponseType: number = -1; + private filterResponseSelect: string = '0'; + private currentSelection: SelectionParam | undefined; + private rowSelectData: any = undefined; + private sortColumn: string = ''; + private sortType: number = 0; + private leftNs: number = 0; + private rightNs: number = 0; + private responseTypes: any[] = []; + + set data(val: SelectionParam | any) { + if (val == this.currentSelection) { + return; + } + this.currentSelection = val; + this.initFilterTypes(); + this.queryData(val); + } + + queryData(val: SelectionParam | any) { + let types: Array = []; + if (val.nativeMemory.indexOf(this.defaultNativeTypes[0]) != -1) { + types.push("'AllocEvent'"); + types.push("'MmapEvent'"); + } else { + if (val.nativeMemory.indexOf(this.defaultNativeTypes[1]) != -1) { + types.push("'AllocEvent'"); + } + if (val.nativeMemory.indexOf(this.defaultNativeTypes[2]) != -1) { + types.push("'MmapEvent'"); + } + } + TabPaneNMSampleList.serSelection(val); + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 20 - 31 + 'px'; + // @ts-ignore + this.tblData?.recycleDataSource = []; + // @ts-ignore + this.tbl?.recycleDataSource = []; + this.leftNs = val.leftNs; + this.rightNs = val.rightNs; + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + queryNativeHookEventTid(val.leftNs, val.rightNs, types).then((result) => { + this.queryResult = result; + this.getDataByNativeMemoryWorker(val); + }); + } + + getDataByNativeMemoryWorker(val: SelectionParam | any) { + let args = new Map(); + args.set('data', this.queryResult); + args.set('filterAllocType', this.filterAllocationType); + args.set('filterEventType', this.filterNativeType); + args.set('filterResponseType', this.filterResponseType); + args.set('leftNs', val.leftNs); + args.set('rightNs', val.rightNs); + let selections: Array = []; + if (this.statsticsSelection.length > 0) { + this.statsticsSelection.map((memory) => { + selections.push({ + memoryTap: memory.memoryTap, + max: memory.max, + }); + }); + } + args.set('statisticsSelection', selections); + args.set('actionType', 'native-memory'); + this.startWorker(args, (results: any[]) => { + this.tblData!.recycleDataSource = []; + this.progressEL!.loading = false; + if (results.length > 0) { + this.source = results; + this.sortByColumn(this.sortColumn, this.sortType); + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + startWorker(args: Map, handler: Function) { + this.loadingList.push(1); + this.progressEL!.loading = true; + this.loadingPage.style.visibility = 'visible'; + procedurePool.submitWithName('logic1', 'native-memory-action', args, undefined, (res: any) => { + handler(res); + this.loadingList.splice(0, 1); + if (this.loadingList.length == 0) { + this.progressEL!.loading = false; + this.loadingPage.style.visibility = 'hidden'; + } + }); + } + + fromStastics(val: SelectionParam | any) { + let filter = this.shadowRoot?.querySelector('#filter'); + if (this.currentSelection != val) { + this.initFilterTypes(() => { + this.currentSelection = val; + filter!.setSelectList( + null, + this.native_type, + 'Allocation Lifespan', + 'Allocation Type', + this.responseTypes.map((item: any) => { + return item.value; + }) + ); + filter!.secondSelect = typeIndexOf + ''; + filter!.thirdSelect = this.filterResponseSelect; + this.filterNativeType = typeIndexOf + ''; + this.queryData(val); + }); + } + let typeIndexOf = this.native_type.indexOf(val.statisticsSelectData.memoryTap); + if (this.statsticsSelection.indexOf(val.statisticsSelectData) == -1 && typeIndexOf == -1) { + this.statsticsSelection.push(val.statisticsSelectData); + this.native_type.push(val.statisticsSelectData.memoryTap); + typeIndexOf = this.native_type.length - 1; + } else { + let index = this.statsticsSelection.findIndex((mt) => mt.memoryTap == val.statisticsSelectData.memoryTap); + if (index != -1) { + this.statsticsSelection[index] = val.statisticsSelectData; + } + } + if (this.currentSelection == val) { + this.tblData!.recycleDataSource = []; + this.rowSelectData = undefined; + filter!.setSelectList( + null, + this.native_type, + 'Allocation Lifespan', + 'Allocation Type', + this.responseTypes.map((item: any) => { + return item.value; + }) + ); + filter!.secondSelect = typeIndexOf + ''; + filter!.thirdSelect = this.filterResponseSelect; + this.filterNativeType = typeIndexOf + ''; + //直接将当前数据过滤即可 + this.getDataByNativeMemoryWorker(val); + } + } + + initFilterTypes(initCallback?: () => void) { + let filter = this.shadowRoot?.querySelector('#filter'); + this.queryResult = []; + this.native_type = [...this.defaultNativeTypes]; + this.statsticsSelection = []; + procedurePool.submitWithName('logic1', 'native-memory-get-responseType', {}, undefined, (res: any) => { + filter!.setSelectList( + null, + this.native_type, + 'Allocation Lifespan', + 'Allocation Type', + res.map((item: any) => { + return item.value; + }) + ); + filter!.setFilterModuleSelect('#first-select', 'width', '150px'); + filter!.setFilterModuleSelect('#second-select', 'width', '150px'); + filter!.setFilterModuleSelect('#third-select', 'width', '150px'); + this.responseTypes = res; + filter!.firstSelect = '0'; + filter!.secondSelect = '0'; + filter!.thirdSelect = '0'; + this.filterResponseSelect = '0'; + this.filterAllocationType = '0'; + this.filterNativeType = '0'; + this.filterResponseType = -1; + this.rowSelectData = undefined; + if (initCallback) { + initCallback(); + } + }); + } + + initElements(): void { + this.loadingPage = this.shadowRoot?.querySelector('.loading'); + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.tbl = this.shadowRoot?.querySelector('#tb-native-memory'); + this.tblData = this.shadowRoot?.querySelector('#tb-native-data'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = e.detail.data as NativeMemory; + this.rowSelectData = data; + this.setRightTableData(data); + document.dispatchEvent( + new CustomEvent('triangle-flag', { + detail: { time: data.startTs, type: 'triangle' }, + }) + ); + }); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail.key, evt.detail.sort); + }); + let filter = this.shadowRoot?.querySelector('#filter'); + + this.shadowRoot?.querySelector('#filter')!.getFilterData((data: FilterData) => { + if (data.mark) { + document.dispatchEvent( + new CustomEvent('triangle-flag', { + detail: { + time: '', + type: 'square', + timeCallback: (t: any) => { + let minTs = 0; + let minItem: any = undefined; + let filterTemp = this.source.filter((tempItem) => { + if (minTs == 0 || (tempItem.startTs - t != 0 && Math.abs(tempItem.startTs - t) < minTs)) { + minTs = Math.abs(tempItem.startTs - t); + minItem = tempItem; + } + return tempItem.startTs == t; + }); + if (filterTemp.length > 0) { + filterTemp[0].isSelected = true; + } else { + if (minItem) { + filterTemp.push(minItem); + minItem.isSelected = true; + } + } + if (filterTemp.length > 0) { + this.rowSelectData = filterTemp[0]; + let currentSelection = this.queryResult.filter((item) => { + return item.startTs == this.rowSelectData.startTs; + }); + if (currentSelection.length > 0) { + currentSelection[0].isSelected = true; + } + TabPaneNMSampleList.addSampleData(this.rowSelectData); + this.tbl!.scrollToData(this.rowSelectData); + } + }, + }, + }) + ); + } else { + this.filterAllocationType = data.firstSelect || '0'; + this.filterNativeType = data.secondSelect || '0'; + this.filterResponseSelect = data.thirdSelect || '0'; + let thirdIndex = parseInt(data.thirdSelect || '0'); + if (this.responseTypes.length > thirdIndex) { + this.filterResponseType = + this.responseTypes[thirdIndex].key == undefined ? -1 : this.responseTypes[thirdIndex].key; + } + this.getDataByNativeMemoryWorker(this.currentSelection); + } + }); + filter!.firstSelect = '1'; + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tbl?.reMeauseHeight(); + // @ts-ignore + this.tblData?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 10 - 31 + 'px'; + this.tblData?.reMeauseHeight(); + this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; + } + }).observe(this.parentElement!); + } + + sortByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + if (sort == 0) { + this.tbl!.recycleDataSource = this.source; + } else { + let arr = [...this.source]; + if (column == 'index') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.index - b.index : b.index - a.index; + }); + } else if (column == 'addr') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.addr > b.addr) { + return 1; + } else if (a.addr == b.addr) { + return 0; + } else { + return -1; + } + } else { + if (b.addr > a.addr) { + return 1; + } else if (a.addr == b.addr) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'timestamp') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.startTs - b.startTs : b.startTs - a.startTs; + }); + } else if (column == 'heapSizeUnit') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + return sort == 1 ? a.heapSize - b.heapSize : b.heapSize - a.heapSize; + }); + } else if (column == 'library') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.library > b.library) { + return 1; + } else if (a.library == b.library) { + return 0; + } else { + return -1; + } + } else { + if (b.library > a.library) { + return 1; + } else if (a.library == b.library) { + return 0; + } else { + return -1; + } + } + }); + } else if (column == 'symbol') { + this.tbl!.recycleDataSource = arr.sort((a, b) => { + if (sort == 1) { + if (a.symbol > b.symbol) { + return 1; + } else if (a.symbol == b.symbol) { + return 0; + } else { + return -1; + } + } else { + if (b.symbol > a.symbol) { + return 1; + } else if (a.symbol == b.symbol) { + return 0; + } else { + return -1; + } + } + }); + } + } + } + + setRightTableData(hook: NativeMemory) { + let args = new Map(); + args.set('eventId', hook.eventId); + args.set('actionType', 'memory-stack'); + this.startWorker(args, (results: any[]) => { + let thread = new NativeHookCallInfo(); + thread.threadId = hook.threadId; + thread.threadName = hook.threadName; + thread.title = `${hook.threadName ?? ''}【${hook.threadId}】`; + thread.type = -1; + let source = []; + source.push(thread); + source.push(...results); + this.progressEL!.loading = false; + this.tblData!.dataSource = source; + }); + } + + initHtml(): string { + return ` + +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneCounter.ts b/ide/src/trace/component/trace/sheet/process/TabPaneCounter.ts new file mode 100644 index 0000000000000000000000000000000000000000..f32e1a5965da8cf53574c57fb259c2708e229b71 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/process/TabPaneCounter.ts @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { Counter, SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabCounters, getTabVirtualCounters } from '../../../../database/SqlLite.js'; + +@element('tabpane-counter') +export class TabPaneCounter extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + + set data(val: SelectionParam | any) { + //@ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + getTabCounters(val.processTrackIds, val.virtualTrackIds, val.rightNs).then((result) => { + if (result != null && result.length > 0) { + let dataSource: Array = []; + let collect = this.groupByTrackIdToMap(result); + let sumCount = 0; + for (let key of collect.keys()) { + let counters = collect.get(key); + let list: Array = []; + let index = counters!.findIndex((item) => item.startTime >= val.leftNs); + if (index != -1) { + list = counters!.splice(index > 0 ? index - 1 : index); + } else { + list.push(counters![counters!.length - 1]); + } + let sd = this.createSelectCounterData(list, val.leftNs, val.rightNs); + sumCount += Number.parseInt(sd.count); + dataSource.push(sd); + } + let sumData = new SelectionData(); + sumData.count = sumCount.toString(); + sumData.process = ' '; + dataSource.splice(0, 0, sumData); + this.source = dataSource; + this.tbl!.recycleDataSource = dataSource; + } else { + this.source = []; + this.tbl!.recycleDataSource = this.source; + } + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-counter'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + `; + } + + groupByTrackIdToMap(arr: Array): Map> { + let map = new Map>(); + for (let counter of arr) { + counter.name = counter.name.replace('sys.virtual.mem.', ''); + if (map.has(counter.trackId)) { + map.get(counter.trackId)!.push(counter); + } else { + let list: Array = []; + list.push(counter); + map.set(counter.trackId, list); + } + } + return map; + } + + createSelectCounterData(list: Array, leftNs: number, rightNs: number): SelectionData { + let selectData = new SelectionData(); + if (list.length > 0) { + let range = rightNs - leftNs; + let first = list[0]; + selectData.trackId = first.trackId; + selectData.name = first.name; + selectData.first = first.value + ''; + selectData.count = list.length + ''; + selectData.last = list[list.length - 1].value + ''; + selectData.delta = parseInt(selectData.last) - parseInt(selectData.first) + ''; + selectData.rate = (parseInt(selectData.delta) / ((range * 1.0) / 1000000000)).toFixed(4); + selectData.min = first.value + ''; + selectData.max = '0'; + let weightAvg = 0.0; + for (let i = 0; i < list.length; i++) { + let counter = list[i]; + if (counter.value < parseInt(selectData.min)) { + selectData.min = counter.value.toString(); + } + if (counter.value > parseInt(selectData.max)) { + selectData.max = counter.value.toString(); + } + let start = i == 0 ? leftNs : counter.startTime; + let end = i == list.length - 1 ? rightNs : list[i + 1].startTime; + weightAvg += counter.value * (((end - start) * 1.0) / range); + } + selectData.avgWeight = weightAvg.toFixed(2); + } + return selectData; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'name') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts b/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3f30d463757c0b517a3a19f085545d1b8017d57 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/process/TabPaneSlices.ts @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabSlices, getTabSlicesAsyncFunc } from '../../../../database/SqlLite.js'; + +@element('tabpane-slices') +export class TabPaneSlices extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private source: Array = []; + + set data(val: SelectionParam | any) { + this.range!.textContent = + 'Selected range: ' + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + ' ms'; + let asyncNames: Array = []; + let asyncPid: Array = []; + val.funAsync.forEach((it: any) => { + asyncNames.push(it.name); + asyncPid.push(it.pid); + }); + getTabSlicesAsyncFunc(asyncNames, asyncPid, val.leftNs, val.rightNs).then((res) => { + getTabSlices(val.funTids, val.leftNs, val.rightNs).then((res2) => { + let result = (res || []).concat(res2 || []); + if (result != null && result.length > 0) { + let sumWall = 0.0; + let sumOcc = 0; + for (let e of result) { + e.name = e.name == null ? '' : e.name; + sumWall += e.wallDuration; + sumOcc += e.occurrences; + e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); + e.avgDuration = parseFloat((e.avgDuration / 1000000.0).toFixed(5)); + } + let count = new SelectionData(); + count.process = ' '; + count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(5)); + count.occurrences = sumOcc; + result.splice(0, 0, count); + this.source = result; + this.tbl!.recycleDataSource = result; + } else { + this.source = []; + this.tbl!.recycleDataSource = this.source; + } + }); + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-slices'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if (detail.key === 'name') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts b/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts new file mode 100644 index 0000000000000000000000000000000000000000..c65e6718c09f99a5d38b2dddd2b9ebd45f92c06a --- /dev/null +++ b/ide/src/trace/component/trace/sheet/process/TabPaneThreadStates.ts @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../StackBar.js'; +import { getTabThreadStates } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { StackBar } from '../../../StackBar.js'; +import { log } from '../../../../../log/Log.js'; + +@element('tabpane-thread-states') +export class TabPaneThreadStates extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private stackBar: StackBar | null | undefined; + private source: Array = []; + + set data(val: SelectionParam | any) { + //@ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + // // @ts-ignore + this.range!.textContent = 'Selected range: ' + ((val.rightNs - val.leftNs) / 1000000.0).toFixed(5) + ' ms'; + getTabThreadStates(val.threadIds, val.leftNs, val.rightNs).then((result) => { + if (result != null && result.length > 0) { + log('getTabThreadStates result size : ' + result.length); + let sumWall = 0.0; + let sumOcc = 0; + for (let e of result) { + let process = Utils.PROCESS_MAP.get(e.pid); + let thread = Utils.THREAD_MAP.get(e.tid); + e.process = process == null || process.length == 0 ? '[NULL]' : process; + e.thread = thread == null || thread.length == 0 ? '[NULL]' : thread; + sumWall += e.wallDuration; + sumOcc += e.occurrences; + e.stateJX = e.state; + e.state = Utils.getEndState(e.stateJX); + e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5)); + e.avgDuration = parseFloat((e.avgDuration / 1000000.0).toFixed(5)); + } + let count: any = {}; + count.process = ' '; + count.state = ' '; + count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(5)); + count.occurrences = sumOcc; + result.splice(0, 0, count); + this.source = result; + this.tbl!.recycleDataSource = result; + this.stackBar!.data = result; + } else { + this.source = []; + this.stackBar!.data = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-thread-states'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.stackBar = this.shadowRoot?.querySelector('#stack-bar'); + this.tbl!.addEventListener('column-click', (evt: any) => { + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + +
+ + +
+ + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + function compare(property: any, sort: any, type: any) { + return function (a: SelectionData | any, b: SelectionData | any) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + }; + } + + if (detail.key === 'name' || detail.key === 'thread' || detail.key === 'state') { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/process/TabPaneThreadUsage.ts b/ide/src/trace/component/trace/sheet/process/TabPaneThreadUsage.ts new file mode 100644 index 0000000000000000000000000000000000000000..60b8dc2d432f2bd27f890aa92e071e921012359a --- /dev/null +++ b/ide/src/trace/component/trace/sheet/process/TabPaneThreadUsage.ts @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import '../../../StackBar.js'; +import { getTabThreadStatesCpu } from '../../../../database/SqlLite.js'; +import { StackBar } from '../../../StackBar.js'; +import { log } from '../../../../../log/Log.js'; +import { getProbablyTime } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon.js'; +import { Utils } from '../../base/Utils.js'; +import { CpuStruct } from '../../../../database/ui-worker/ProcedureWorkerCPU.js'; + +@element('tabpane-thread-usage') +export class TabPaneThreadUsage extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private stackBar: StackBar | null | undefined; + private source: Array = []; + private cpuCount = 0; + private pubColumns = ` + + + + + + + + + + + `; + + set data(val: SelectionParam | any) { + if (this.cpuCount !== CpuStruct.cpuCount) { + this.cpuCount = CpuStruct.cpuCount; + this.tbl!.innerHTML = this.getTableColumns(); + } + //@ts-ignore + this.tbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; + // // @ts-ignore + this.range!.textContent = 'Selected range: ' + ((val.rightNs - val.leftNs) / 1000000.0).toFixed(5) + ' ms'; + getTabThreadStatesCpu(val.threadIds, val.leftNs, val.rightNs).then((result) => { + if (result != null && result.length > 0) { + log('getTabThreadStates result size : ' + result.length); + let map: Map = new Map(); + for (let e of result) { + if (map.has(e.tid)) { + map.get(e.tid)[`cpu${e.cpu}`] = e.wallDuration || 0; + map.get(e.tid)[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0); + map.get(e.tid)[`cpu${e.cpu}Ratio`] = ((100.0 * (e.wallDuration || 0)) / (val.rightNs - val.leftNs)).toFixed( + 2 + ); + map.get(e.tid)[`wallDuration`] = map.get(e.tid)[`wallDuration`] + (e.wallDuration || 0); + map.get(e.tid)[`wallDurationTimeStr`] = getProbablyTime(map.get(e.tid)[`wallDuration`]); + } else { + let process = Utils.PROCESS_MAP.get(e.pid); + let thread = Utils.THREAD_MAP.get(e.tid); + let obj: any = { + tid: e.tid, + pid: e.pid, + thread: thread || 'null', + process: process || 'null', + wallDuration: e.wallDuration || 0, + wallDurationTimeStr: getProbablyTime(e.wallDuration || 0), + }; + for (let i = 0; i < this.cpuCount; i++) { + obj[`cpu${i}`] = 0; + obj[`cpu${i}TimeStr`] = '0'; + obj[`cpu${i}Ratio`] = '0'; + } + obj[`cpu${e.cpu}`] = e.wallDuration || 0; + obj[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0); + obj[`cpu${e.cpu}Ratio`] = ((100.0 * (e.wallDuration || 0)) / (val.rightNs - val.leftNs)).toFixed(2); + map.set(e.tid, obj); + } + } + this.source = Array.from(map.values()); + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + getTableColumns() { + let col = `${this.pubColumns}`; + let cpuCount = CpuStruct.cpuCount; + for (let i = 0; i < cpuCount; i++) { + col = `${col} + + + + + `; + } + return col; + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-thread-states'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.stackBar = this.shadowRoot?.querySelector('#stack-bar'); + this.tbl!.addEventListener('column-click', (evt: any) => { + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + +
+ + +
+
+ +
+ `; + } + + sortByColumn(detail: any) { + function compare(property: any, sort: any, type: any) { + return function (a: SelectionData | any, b: SelectionData | any) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + return sort === 2 + ? parseFloat(b[property]) - parseFloat(a[property]) + : parseFloat(a[property]) - parseFloat(b[property]); + } else { + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + }; + } + + if (detail.key === 'process' || detail.key === 'thread' || (detail.key as string).includes('Ratio')) { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.source.sort(compare((detail.key as string).replace('TimeStr', ''), detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/sdk/TabPaneSdkCounter.ts b/ide/src/trace/component/trace/sheet/sdk/TabPaneSdkCounter.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4821ecc41b4d33295bf83237092343be109a010 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/sdk/TabPaneSdkCounter.ts @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabSdkCounterData, getTabSdkCounterLeftData, queryStartTime } from '../../../../database/SqlLite.js'; +import '../../../SpFilter.js'; +import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-sdk-counter') +export class TabPaneSdkCounter extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private keyList: Array | undefined; + private statDataArray: any = []; + private columnMap: any = {}; + private sqlMap: Map = new Map(); + + set data(val: SelectionParam | any) { + this.range!.textContent = 'Selected range: ' + ((val.rightNs - val.leftNs) / 1000000.0).toFixed(5) + ' ms'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-counter'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + queryStartTime().then((res) => { + let startTime = res[0].start_ts; + this.parseJson(SpSystemTrace.SDK_CONFIG_MAP); + let counters: Array = []; + let componentId: number = -1; + for (let index = 0; index < val.sdkCounterIds.length; index++) { + let values = val.sdkCounterIds[index].split('-'); + let value = values[0]; + componentId = Number(values[1]); + counters.push(value); + } + let sqlObj = this.sqlMap.get(componentId); + let sql = sqlObj.TabCounterLeftData; + getTabSdkCounterLeftData(sql, val.leftNs + startTime, counters, componentId).then((res) => { + let leftTime = res[res.length - 1].max_value - startTime; + let sql = sqlObj.TabCounterData; + getTabSdkCounterData(sql, startTime, leftTime, val.rightNs, counters, componentId).then((item) => { + this.keyList = []; + this.tbl!.innerHTML = ''; + this.statDataArray = []; + if (item.length != null && item.length > 0) { + for (let index = 0; index < item.length; index++) { + const dataResult = item[index]; + let keys = Object.keys(dataResult); + // @ts-ignore + let values = Object.values(dataResult); + let jsonText = '{'; + for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) { + let key = keys[keyIndex]; + if (this.keyList.indexOf(key) <= -1) { + this.keyList.push(key); + } + let value = values[keyIndex]; + if (this.columnMap[key] == 'TimeStamp') { + value = Utils.getTimeString(Number(value)); + } else if (this.columnMap[key] == 'ClockTime') { + value = Utils.getTimeStampHMS(Number(value)); + } else if (this.columnMap[key] == 'RangTime') { + value = Utils.getDurString(Number(value)); + } else if (this.columnMap[key] == 'PercentType') { + value = value + '%'; + } else if (this.columnMap[key] == 'CurrencyType') { + // @ts-ignore + value = value.toString().replace(/\B(?=(\d{3})+$)/g, ','); + } + if (typeof value == 'string') { + value = value.replace(//gi, '>'); + } + jsonText += '"' + key + '"' + ': ' + '"' + value + '"'; + if (keyIndex != keys.length - 1) { + jsonText += ','; + } else { + jsonText += '}'; + } + } + this.statDataArray.push(JSON.parse(jsonText)); + } + this.tbl!.recycleDataSource = this.statDataArray; + } else { + this.tbl!.recycleDataSource = []; + } + this.initDataElement(); + + setTimeout(() => { + this.tbl!.recycleDataSource = this.statDataArray; + new ResizeObserver(() => { + if (this.parentElement?.clientHeight != 0) { + this.tbl!.style.height = '100%'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + }, 200); + }); + }); + }); + } + + parseJson(map: Map): string { + let keys = map.keys(); + for (let key of keys) { + let configObj: any = map.get(key); + if (configObj != undefined) { + let configStr = configObj.jsonConfig; + let json = JSON.parse(configStr); + let tableConfig = json.tableConfig; + if (tableConfig != null) { + let showTypes = tableConfig.showType; + for (let i = 0; i < showTypes.length; i++) { + let showType = showTypes[i]; + let type = this.getTableType(showType); + if (type == 'counter') { + let selectSql = 'select '; + for (let j = 0; j < showType.columns.length; j++) { + this.columnMap[showType.columns[j].column] = showType.columns[j].displayName; + if (showType.columns[j].showType.indexOf(3) > -1) { + selectSql += showType.columns[j].column + ','; + } + } + let leftSql = + 'select max(ts) as max_value,counter_id from ' + + showType.tableName + + ' where ts <= $leftNs and counter_id in' + + ' ($counters) group by counter_id order by max_value desc'; + let tabCounterDataSql = + selectSql.substring(0, selectSql.length - 1) + + ' from ' + + showType.tableName + + ' where counter_id in ($counters) and (ts - $startTime) between $leftNs and $rightNs'; + this.sqlMap.set(key, { + TabCounterData: tabCounterDataSql, + TabCounterLeftData: leftSql, + }); + } + } + } + } + } + return ''; + } + + private getTableType(showType: any) { + let columns = showType.columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + let showType = column.showType; + if (showType != null) { + if (showType.indexOf(1) != -1) { + return 'counter'; + } + if (showType.indexOf(2) != -1) { + return 'slice'; + } + } + } + return ''; + } + + initDataElement() { + if (this.keyList) { + this.keyList.forEach((item) => { + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', item); + htmlElement.setAttribute('data-index', item); + htmlElement.setAttribute('key', item); + htmlElement.setAttribute('align', 'flex-start'); + htmlElement.setAttribute('width', '1fr'); + htmlElement.setAttribute('order', ''); + this.tbl!.appendChild(htmlElement); + }); + } + } + + initHtml(): string { + return ` + +
+ + +
+ + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + }; + } + + if (detail.key.indexOf('name') != -1) { + this.statDataArray.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.statDataArray.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.statDataArray; + } +} diff --git a/ide/src/trace/component/trace/sheet/sdk/TabPaneSdkSlice.ts b/ide/src/trace/component/trace/sheet/sdk/TabPaneSdkSlice.ts new file mode 100644 index 0000000000000000000000000000000000000000..305519d35956c4ebc7accf5e6e3b22c6882e7502 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/sdk/TabPaneSdkSlice.ts @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabSdkSliceData, queryStartTime, queryTotalTime } from '../../../../database/SqlLite.js'; +import '../../../SpFilter.js'; +import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column.js'; +import { Utils } from '../../base/Utils.js'; +import { SpSystemTrace } from '../../../SpSystemTrace.js'; + +@element('tabpane-sdk-slice') +export class TabPaneSdkSlice extends BaseElement { + private tbl: LitTable | null | undefined; + private range: HTMLLabelElement | null | undefined; + private keyList: Array | undefined; + private statDataArray: any = []; + private columnMap: any = {}; + private sqlMap: Map = new Map(); + + set data(val: SelectionParam | any) { + this.range!.textContent = 'Selected range: ' + ((val.rightNs - val.leftNs) / 1000000.0).toFixed(5) + ' ms'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-sdk-slice'); + this.range = this.shadowRoot?.querySelector('#time-range'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + queryTotalTime().then((res) => { + let startTime = res[0].recordStartNS; + let totalTime = res[0].total; + let componentId: number = -1; + let slices: Array = []; + for (let index = 0; index < val.sdkSliceIds.length; index++) { + let values = val.sdkSliceIds[index].split('-'); + let value = values[0]; + componentId = Number(values[1]); + slices.push(value); + } + this.parseJson(SpSystemTrace.SDK_CONFIG_MAP); + let sql = this.sqlMap.get(componentId); + if (sql == undefined) { + return; + } + getTabSdkSliceData(sql, startTime, val.leftNs, val.rightNs, slices, componentId).then((item) => { + this.keyList = []; + this.tbl!.innerHTML = ''; + this.statDataArray = []; + if (item.length != null && item.length > 0) { + for (let index = 0; index < item.length; index++) { + const dataResult = item[index]; + let keys = Object.keys(dataResult); + // @ts-ignore + let values = Object.values(dataResult); + let jsonText = '{'; + for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) { + let key = keys[keyIndex]; + if (this.keyList.indexOf(key) <= -1) { + this.keyList.push(key); + } + let value = values[keyIndex]; + if (this.columnMap[key] == 'TimeStamp') { + value = Utils.getTimeString(Number(value)); + } else if (this.columnMap[key] == 'ClockTime') { + value = Utils.getTimeStampHMS(Number(value)); + } else if (this.columnMap[key] == 'RangTime') { + value = Utils.getDurString(Number(value)); + } else if (this.columnMap[key] == 'PercentType') { + value = value + '%'; + } else if (this.columnMap[key] == 'CurrencyType') { + // @ts-ignore + value = value.toString().replace(/\B(?=(\d{3})+$)/g, ','); + } else if (this.columnMap[key] == 'FIXED') { + value = value.toFixed(2); + } + if (typeof value == 'string') { + value = value.replace(//gi, '>'); + } + jsonText += '"' + key + '"' + ': ' + '"' + value + '"'; + if (keyIndex != keys.length - 1) { + jsonText += ','; + } else { + jsonText += '}'; + } + } + let data = JSON.parse(jsonText); + if (data.start_ts != null && data.end_ts != null && data.start_ts > data.end_ts && data.end_ts == 0) { + data.end_ts = totalTime; + } + if (this.isDateIntersection(val.leftNs, val.rightNs, data.start_ts, data.end_ts)) { + this.statDataArray.push(data); + } + } + this.tbl!.recycleDataSource = this.statDataArray; + } else { + this.tbl!.recycleDataSource = []; + } + this.initDataElement(); + + setTimeout(() => { + this.tbl!.recycleDataSource = this.statDataArray; + new ResizeObserver(() => { + if (this.parentElement?.clientHeight != 0) { + this.tbl!.style.height = '100%'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + }, 200); + }); + }); + } + + private isDateIntersection(selectStartTime: number, selectEndTime: number, startTime: number, endTime: number) { + if (selectStartTime > startTime && selectStartTime < endTime) { + return true; + } + if (selectEndTime > startTime && selectEndTime < endTime) { + return true; + } + if (selectStartTime < startTime && selectEndTime > endTime) { + return true; + } + return false; + } + + parseJson(map: Map): string { + let keys = map.keys(); + for (let key of keys) { + let configObj: any = map.get(key); + if (configObj != undefined) { + let configStr = configObj.jsonConfig; + let json = JSON.parse(configStr); + let tableConfig = json.tableConfig; + if (tableConfig != null) { + let showTypes = tableConfig.showType; + for (let i = 0; i < showTypes.length; i++) { + let showType = showTypes[i]; + let innerTableName = this.getInnerTableName(showType); + let type = this.getTableType(showType); + if (type == 'slice') { + let selectSql = 'select '; + for (let j = 0; j < showType.columns.length; j++) { + this.columnMap[showType.columns[j].column] = showType.columns[j].displayName; + if (showType.columns[j].showType.indexOf(3) > -1) { + switch (showType.columns[j].column) { + case 'slice_id': + selectSql += 'a.slice_id,b.slice_name,'; + break; + case 'start_ts': + selectSql += '(a.start_ts - $startTime) as start_ts,'; + break; + case 'end_ts': + selectSql += '(a.end_ts - $startTime) as end_ts,'; + break; + default: + selectSql += 'a.' + showType.columns[j].column + ','; + } + } + } + let sql = + selectSql.substring(0, selectSql.length - 1) + + ' from ' + + showType.tableName + + ' as a,' + + innerTableName + + ' as b' + + ' where a.slice_id in ($slices)' + + ' and a.slice_id = b.slice_id' + + ' and ((a.start_ts - $startTime) >= $leftNs and (a.end_ts - $startTime) <= $rightNs ' + + 'or (a.start_ts - $startTime) <= $leftNs and $leftNs <= (a.end_ts - $startTime) ' + + 'or (a.start_ts - $startTime) <= $rightNs and $rightNs <= (a.end_ts - $startTime))'; + this.sqlMap.set(key, sql); + } + } + } + } + } + return ''; + } + + initDataElement() { + if (this.keyList) { + this.keyList.forEach((item) => { + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', item); + htmlElement.setAttribute('data-index', item); + htmlElement.setAttribute('key', item); + htmlElement.setAttribute('align', 'flex-start'); + if (item == 'slice_id') { + htmlElement.setAttribute('width', '0.5fr'); + } else { + htmlElement.setAttribute('width', '1fr'); + } + htmlElement.setAttribute('order', ''); + this.tbl!.appendChild(htmlElement); + }); + } + } + + initHtml(): string { + return ` + +
+ + +
+ + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SelectionData, b: SelectionData) { + if (a.process == ' ' || b.process == ' ') { + return 0; + } + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + }; + } + if (detail.key.indexOf('name') != -1) { + this.statDataArray.sort(compare(detail.key, detail.sort, 'string')); + } else { + this.statDataArray.sort(compare(detail.key, detail.sort, 'number')); + } + this.tbl!.recycleDataSource = this.statDataArray; + } + + private getInnerTableName(showType: any) { + let inner = showType.inner; + if (inner != null) { + return inner.tableName; + } + return ''; + } + private getTableType(showType: any) { + let columns = showType.columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + let showType = column.showType; + if (showType != null) { + if (showType.indexOf(1) != -1) { + return 'counter'; + } + if (showType.indexOf(2) != -1) { + return 'slice'; + } + } + } + return ''; + } +} diff --git a/ide/src/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.ts b/ide/src/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.ts new file mode 100644 index 0000000000000000000000000000000000000000..728a8e7a83cd5ddd4e00e5afd010c440e0c6862c --- /dev/null +++ b/ide/src/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.ts @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabSmapsData } from '../../../../database/SqlLite.js'; +import { Utils } from '../../base/Utils.js'; +import { log } from '../../../../../log/Log.js'; +import { Smaps } from '../../../../bean/SmapsStruct.js'; + +@element('tabpane-smaps-record') +export class TabPaneSmapsRecord extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = []; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-smaps-record'); + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail); + }); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + getTabSmapsData(val.leftNs, val.rightNs).then((result) => { + log('getTabSmapsData size :' + result.length); + if (result.length != null && result.length > 0) { + for (const smaps of result) { + switch (smaps.permission.trim()) { + case 'rw-': + smaps.type = 'DATA'; + break; + case 'r-x': + smaps.type = 'TEXT'; + break; + case 'r--': + smaps.type = 'CONST'; + break; + default: + smaps.type = 'OTHER'; + break; + } + smaps.address = smaps.start_addr + ' - ' + smaps.end_addr; + smaps.dirtyStr = Utils.getBinaryByteWithUnit(smaps.dirty * 1024); + smaps.swapperStr = Utils.getBinaryByteWithUnit(smaps.swapper * 1024); + smaps.rssStr = Utils.getBinaryByteWithUnit(smaps.rss * 1024); + smaps.pssStr = Utils.getBinaryByteWithUnit(smaps.pss * 1024); + smaps.sizeStr = Utils.getBinaryByteWithUnit(smaps.size * 1024); + let resideS = smaps.reside.toFixed(2); + if (resideS == '0.00') { + smaps.resideStr = '0 %'; + } else { + smaps.resideStr = resideS + '%'; + } + } + this.source = result; + this.queryResult = result; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = []; + this.queryResult = []; + this.tbl!.recycleDataSource = []; + } + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: Smaps, b: Smaps) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { + // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + }; + } + + if ( + detail.key === 'dirtyStr' || + detail.key === 'swapperStr' || + detail.key === 'rssStr' || + detail.key === 'sizeStr' || + detail.key === 'resideStr' + ) { + let key = detail.key.substring(0, detail.key.indexOf('Str')); + this.source.sort(compare(key, detail.sort, 'number')); + } else { + this.source.sort(compare(detail.key, detail.sort, 'string')); + } + this.tbl!.recycleDataSource = this.source; + } +} diff --git a/ide/src/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.ts b/ide/src/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.ts new file mode 100644 index 0000000000000000000000000000000000000000..bab8b756a3a9a8afe9a6df1b0fecb8b1b826f8c1 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.ts @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { getTabSmapsData, getTabSmapsMaxRss } from '../../../../database/SqlLite.js'; +import { Smaps, SmapsTreeObj } from '../../../../bean/SmapsStruct.js'; +import { Utils } from '../../base/Utils.js'; + +@element('tabpane-smaps-statistics') +export class TabPaneSmapsStatistics extends BaseElement { + private tbl: LitTable | null | undefined; + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot?.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.queryDataByDB(val); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-smaps-statistics'); + } + + connectedCallback() { + super.connectedCallback(); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector('.table').style.height = this.parentElement.clientHeight - 45 + 'px'; + this.tbl?.reMeauseHeight(); + } + }).observe(this.parentElement!); + } + + queryDataByDB(val: SelectionParam | any) { + getTabSmapsMaxRss(val.leftNs, val.rightNs).then((maxRes) => { + let sumRss = maxRes[0].max_value; + let allTree: SmapsTreeObj = new SmapsTreeObj('All', '', '*All*'); + let dataTree: SmapsTreeObj = new SmapsTreeObj('DATA', '', 'DATA'); + let textTree: SmapsTreeObj = new SmapsTreeObj('TEXT', '', 'TEXT'); + let constTree: SmapsTreeObj = new SmapsTreeObj('CONST', '', 'CONST'); + let otherTree: SmapsTreeObj = new SmapsTreeObj('OTHER', '', 'OTHER'); + getTabSmapsData(val.leftNs, val.rightNs).then((result) => { + if (result.length != null && result.length > 0) { + for (let id = 0; id < result.length; id++) { + let smaps = result[id]; + switch (smaps.permission.trim()) { + case 'rw-': + smaps.type = 'DATA'; + this.handleTree(smaps, id, 'DATA', dataTree, sumRss); + break; + case 'r-x': + smaps.type = 'TEXT'; + this.handleTree(smaps, id, 'TEXT', textTree, sumRss); + break; + case 'r--': + smaps.type = 'CONST'; + this.handleTree(smaps, id, 'CONST', constTree, sumRss); + break; + default: + smaps.type = 'OTHER'; + this.handleTree(smaps, id, 'OTHER', otherTree, sumRss); + break; + } + this.handleAllDataTree(smaps, id, 'All', allTree, sumRss); + if (id == result.length - 1) { + this.handleSmapsTreeObj(dataTree, sumRss); + this.handleSmapsTreeObj(textTree, sumRss); + this.handleSmapsTreeObj(constTree, sumRss); + this.handleSmapsTreeObj(otherTree, sumRss); + this.handleSmapsTreeObj(allTree, sumRss); + } + } + this.tbl!.recycleDataSource = [allTree, dataTree, textTree, constTree, otherTree]; + } else { + this.tbl!.recycleDataSource = []; + } + }); + }); + } + + private calculatePercentage(divisor: number, dividend: number) { + if (dividend == 0) { + return 0; + } else { + return (divisor / dividend) * 100; + } + } + + private handleSmapsTreeObj(smapsTreeObj: SmapsTreeObj, sumRss: number) { + smapsTreeObj.rsspro = this.calculatePercentage(smapsTreeObj.rss, sumRss); + smapsTreeObj.rssproStr = smapsTreeObj.rsspro.toFixed(2) + '%'; + smapsTreeObj.regStr = smapsTreeObj.reg + ''; + smapsTreeObj.rssStr = Utils.getBinaryByteWithUnit(smapsTreeObj.rss * 1024); + smapsTreeObj.dirtyStr = Utils.getBinaryByteWithUnit(smapsTreeObj.dirty * 1024); + smapsTreeObj.swapperStr = Utils.getBinaryByteWithUnit(smapsTreeObj.swapper * 1024); + smapsTreeObj.sizeStr = Utils.getBinaryByteWithUnit(smapsTreeObj.size * 1024); + smapsTreeObj.respro = this.calculatePercentage(smapsTreeObj.rss, smapsTreeObj.size); + smapsTreeObj.pssStr = Utils.getBinaryByteWithUnit(smapsTreeObj.pss * 1024); + smapsTreeObj.resproStr = smapsTreeObj.respro.toFixed(2) + '%'; + } + + private handleAllDataTree(smaps: Smaps, id: number, parentId: string, dataTree: SmapsTreeObj, sumRss: number) { + let type = smaps.type; + let obj = new SmapsTreeObj(id + '', parentId, type); + obj.path = smaps.path; + obj.rss = smaps.rss; + obj.rsspro = this.calculatePercentage(smaps.rss, sumRss); + obj.rssproStr = obj.rsspro.toFixed(2) + '%'; + obj.rssStr = Utils.getBinaryByteWithUnit(smaps.rss * 1024); + obj.dirty = smaps.dirty; + obj.dirtyStr = Utils.getBinaryByteWithUnit(smaps.dirty * 1024); + obj.swapper = smaps.swapper; + obj.swapperStr = Utils.getBinaryByteWithUnit(smaps.swapper * 1024); + obj.size = smaps.size; + obj.sizeStr = Utils.getBinaryByteWithUnit(smaps.size * 1024); + obj.pss = smaps.pss; + obj.pssStr = Utils.getBinaryByteWithUnit(smaps.pss * 1024); + obj.respro = smaps.reside; + obj.resproStr = smaps.reside.toFixed(2) + '%'; + dataTree.reg += 1; + if (dataTree.children.length > 1 && dataTree.path != '< multiple >') { + dataTree.path = '< multiple >'; + } + dataTree.rss += smaps.rss; + dataTree.dirty += smaps.dirty; + dataTree.swapper += smaps.swapper; + dataTree.size += smaps.size; + dataTree.respro += smaps.reside; + dataTree.pss += smaps.pss; + dataTree.children.push(obj); + } + + private handleTree(smaps: Smaps, id: number, parentId: string, dataTree: SmapsTreeObj, sumRss: number) { + let type = smaps.start_addr + ' (' + smaps.size / 4 + ' pages)'; + let obj = new SmapsTreeObj(id + '', parentId, type); + obj.path = smaps.path; + obj.rss = smaps.rss; + obj.rsspro = this.calculatePercentage(smaps.rss, sumRss); + obj.rssproStr = obj.rsspro.toFixed(2) + '%'; + obj.rssStr = Utils.getBinaryByteWithUnit(smaps.rss * 1024); + obj.dirty = smaps.dirty; + obj.dirtyStr = Utils.getBinaryByteWithUnit(smaps.dirty * 1024); + obj.swapper = smaps.swapper; + obj.swapperStr = Utils.getBinaryByteWithUnit(smaps.swapper * 1024); + obj.size = smaps.size; + obj.sizeStr = Utils.getBinaryByteWithUnit(smaps.size * 1024); + obj.pss = smaps.pss; + obj.pssStr = Utils.getBinaryByteWithUnit(smaps.pss * 1024); + obj.respro = smaps.reside; + obj.resproStr = smaps.reside.toFixed(2) + '%'; + dataTree.reg += 1; + if (dataTree.children.length > 1 && dataTree.path != '< multiple >') { + dataTree.path = '< multiple >'; + } + dataTree.rss += smaps.rss; + dataTree.dirty += smaps.dirty; + dataTree.swapper += smaps.swapper; + dataTree.size += smaps.size; + dataTree.pss += smaps.pss; + dataTree.children.push(obj); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + `; + } +} diff --git a/ide/src/trace/component/trace/sheet/snapshot/TabPaneComparison.ts b/ide/src/trace/component/trace/sheet/snapshot/TabPaneComparison.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b1bc4048b6041a82156c51adf954ce13ded7ec4 --- /dev/null +++ b/ide/src/trace/component/trace/sheet/snapshot/TabPaneComparison.ts @@ -0,0 +1,611 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import { HeapDataInterface } from '../../../../../js-heap/HeapDataInterface.js'; +import { ConstructorItem, ConstructorType } from '../../../../../js-heap/model/UiStruct.js'; +import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column.js'; +import '../../../../../base-ui/table/lit-table-column.js'; +import { TabPaneJsMemoryFilter } from '../TabPaneJsMemoryFilter.js'; +import '../TabPaneJsMemoryFilter.js'; +import { HeapSnapshotStruct } from '../../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; +import { LitSelectOption } from '../../../../../base-ui/select/LitSelectOption.js'; +import { LitSelect } from '../../../../../base-ui/select/LitSelect.js'; +import { TabPaneSummary } from './TabPaneSummary.js'; + +@element('tabpane-comparison') +export class TabPaneComparison extends BaseElement { + private comparisonTableEl: LitTable | undefined | null; + private retainerTableEl: LitTable | undefined | null; + private comparisonsData: any; + private clickRow: any; + private retainsData: any; + private retainerNext: any; + private sortColumn: string | undefined | null; + private sortType: number | undefined | null; + private baseFileId: number | undefined | null; + private targetFileId: number | undefined | null; + private filterEl: TabPaneJsMemoryFilter | undefined | null; + private selectEl: LitSelect | undefined | null; + private search: HTMLInputElement | undefined | null; + private comparisonData: Array = []; + private comparisonFilter: Array = []; + private leftArray: Array = []; + private rightArray: Array = []; + private rightTheadTable: HTMLDivElement | undefined | null; + private leftTheadTable: HTMLDivElement | undefined | null; + + initElements(): void { + this.comparisonTableEl = this.shadowRoot!.querySelector('#tb-comparison') as LitTable; + this.retainerTableEl = this.shadowRoot!.querySelector('#tb-retainer') as LitTable; + this.filterEl = this.shadowRoot!.querySelector('#filter'); + this.selectEl = this.filterEl?.shadowRoot?.querySelector('lit-select'); + this.search = this.filterEl?.shadowRoot?.querySelector('#filter-input') as HTMLInputElement; + this.rightTheadTable = this.retainerTableEl!.shadowRoot?.querySelector('.thead') as HTMLDivElement; + this.leftTheadTable = this.comparisonTableEl!.shadowRoot?.querySelector('.thead') as HTMLDivElement; + this.comparisonTableEl!.addEventListener('icon-click', (e) => { + // @ts-ignore + this.clickRow = e.detail.data; + if (this.clickRow.status) { + this.clickRow.targetFileId = this.targetFileId; + let next = HeapDataInterface.getInstance().getNextForComparison(this.clickRow); + this.clickRow.children = next; + if (this.clickRow.children.length > 0) { + for (let item of this.clickRow.children) { + let nodeName = item.nodeName.concat(` @${item.id}`); + item.objectName = nodeName; + item.deltaCount = '-'; + item.deltaSize = '-'; + if (item.edgeName != '') { + item.objectName = item.edgeName + '\xa0' + '::' + '\xa0' + nodeName; + } else { + if (item.fileId == this.baseFileId) { + item.addedCount = '•'; + item.addedSize = item.shallowSize; + item.removedCount = '-'; + item.removedSize = '-'; + } else if (item.fileId) { + item.removedCount = '•'; + item.removedSize = item.shallowSize; + item.addedCount = '-'; + item.addedSize = '-'; + } + } + if (item.type == ConstructorType.FiledType) { + item.removedCount = '-'; + item.removedSize = '-'; + item.addedCount = '-'; + item.addedSize = '-'; + } + } + } else { + this.comparisonTableEl!.snapshotDataSource = []; + } + } else { + this.clickRow.status = true; + } + if (this.search!.value != '') { + if (this.leftTheadTable!.hasAttribute('sort')) { + this.comparisonTableEl!.snapshotDataSource = this.leftArray; + } else { + this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter; + } + } else { + if (this.leftTheadTable!.hasAttribute('sort')) { + this.comparisonTableEl!.snapshotDataSource = this.leftArray; + } else { + this.comparisonTableEl!.snapshotDataSource = this.comparisonsData; + } + } + new ResizeObserver(() => { + this.comparisonTableEl!.style.height = '100%'; + this.comparisonTableEl!.reMeauseHeight(); + }).observe(this.parentElement!); + }); + this.retainerTableEl!.addEventListener('icon-click', (e) => { + // @ts-ignore + this.retainerNext = e.detail.data as ConstructorItem; + if (this.retainerNext) { + if (this.retainsData.length > 0) { + if (this.retainerNext.status) { + this.retainerNext.getChildren(); + let i = 0; + let that = this; + let retainsTable = function () { + const getList = function (list: any) { + list.forEach(function (row: any) { + let shallow = Math.round((row.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((row.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + row.shallowPercent = shallow; + row.retainedPercent = retained; + let nodeId = row.nodeName.concat(` @${row.id}`); + row.objectName = row.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; + if (row.distance >= 100000000 || row.distance == -5) { + row.distance = '-'; + } + i++; + if (i < that.retainsData[0].distance - 1 && list[0].distance != '-') { + list[0].getChildren(); + if (row.hasNext) { + getList(row.children); + } + } else { + return; + } + }); + }; + getList(that.retainerNext.children); + }; + retainsTable(); + } else { + this.retainerNext.status = true; + } + if (this.rightTheadTable!.hasAttribute('sort')) { + this.retainerTableEl!.snapshotDataSource = this.rightArray; + } else { + this.retainerTableEl!.snapshotDataSource = this.retainsData; + } + } else { + this.retainerTableEl!.snapshotDataSource = []; + } + new ResizeObserver(() => { + this.retainerTableEl!.style.height = 'calc(100% - 21px)'; + this.retainerTableEl!.reMeauseHeight(); + }).observe(this.parentElement!); + } + }); + this.comparisonTableEl!.addEventListener('column-click', (e) => { + // @ts-ignore + this.sortComprisonByColumn(e.detail.key, e.detail.sort); + }); + this.retainerTableEl!.addEventListener('column-click', (e) => { + // @ts-ignore + this.sortRetainerByColumn(e.detail.key, e.detail.sort); + }); + this.comparisonTableEl!.addEventListener('row-click', (e: any) => { + this.rightTheadTable!.removeAttribute('sort'); + // @ts-ignore + let item = e.detail.data as ConstructorItem; + (item as any).isSelected = true; + this.retainsData = HeapDataInterface.getInstance().getRetains(item); + if (this.retainsData && this.retainsData.length > 0) { + this.retainsData.forEach((element: any) => { + let shallow = Math.round((element.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((element.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + element.shallowPercent = shallow; + element.retainedPercent = retained; + if (element.distance >= 100000000 || element.distance === -5) { + element.distance = '-'; + } + let nodeId = element.nodeName + ` @${element.id}`; + element.objectName = element.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; + }); + let i = 0; + let that = this; + if (this.retainsData[0].distance > 1) { + this.retainsData[0].getChildren(); + } + let retainsTable = function () { + const getList = function (list: any) { + list.forEach(function (row: any) { + let shallow = Math.round((row.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((row.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + row.shallowPercent = shallow; + row.retainedPercent = retained; + let nodeId = row.nodeName.concat(` @${row.id}`); + row.objectName = row.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; + if (row.distance >= 100000000 || row.distance === -5) { + row.distance = '-'; + } + i++; + if (i < that.retainsData[0].distance - 1 && list[0].distance != '-') { + list[0].getChildren(); + if (row.hasNext) { + getList(row.children); + } + } else { + return; + } + }); + }; + getList(that.retainsData[0].children); + }; + retainsTable(); + this.retainerTableEl!.snapshotDataSource = this.retainsData; + } else { + this.retainerTableEl!.snapshotDataSource = []; + } + new ResizeObserver(() => { + this.retainerTableEl!.style.height = 'calc(100% - 21px)'; + this.retainerTableEl!.reMeauseHeight(); + }).observe(this.parentElement!); + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true); + } + }); + this.retainerTableEl!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data as ConstructorItem; + (data as any).isSelected = true; + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + this.classFilter(); + } + + setSnapshotData( + data: HeapSnapshotStruct, + dataList: Array, + scrollCallback: ((d: any, ds: any) => void) | undefined + ) { + if (scrollCallback) { + scrollCallback(data, dataList); + } + this.initComparison(data, dataList); + } + + initComparison(data: HeapSnapshotStruct, dataList: Array) { + this.clear(); + this.retainerTableEl!.snapshotDataSource = []; + let fileArr: any[] = []; + let that = this; + for (let file of dataList) { + if (file.id !== data.id) { + fileArr.push(file); + } + } + fileArr = fileArr.sort(); + this.initSelect(data.id, fileArr); + this.baseFileId = data.id; + this.targetFileId = fileArr[0].id; + that.updateComparisonData(data.id, fileArr[0].id); + new ResizeObserver(() => { + this.comparisonTableEl!.style.height = '100%'; + this.comparisonTableEl!.reMeauseHeight(); + }).observe(this.parentElement!); + } + + updateComparisonData(baseFileId: number, targetFileId: number) { + this.comparisonsData = HeapDataInterface.getInstance().getClassListForComparison(baseFileId, targetFileId); + this.comparisonsData.forEach((dataList: any) => { + dataList.objectName = dataList.nodeName; + }); + if (this.comparisonsData.length > 0) { + this.comparisonData = this.comparisonsData; + this.comparisonTableEl!.snapshotDataSource = this.comparisonsData; + } else { + this.comparisonTableEl!.snapshotDataSource = []; + } + } + + initSelect(fileId: number, fileArr: Array) { + let that = this; + let input = this.selectEl!.shadowRoot?.querySelector('input') as HTMLInputElement; + this.selectEl!.innerHTML = ''; + let option = new LitSelectOption(); + option.innerHTML = 'File Name'; + option.setAttribute('disabled', 'disabled'); + this.selectEl?.appendChild(option); + if (fileArr[0].file_name) option.setAttribute('value', fileArr[0].file_name); + this.selectEl!.defaultValue = fileArr[0].file_name; + this.selectEl!.placeholder = fileArr[0].file_name; + this.selectEl!.dataSource = fileArr; + this.selectEl!.querySelectorAll('lit-select-option').forEach((a) => { + a.addEventListener('onSelected', (e: any) => { + for (let f of fileArr) { + if (input.value == f.file_name) { + that.updateComparisonData(fileId, f.id); + } + } + e.stopPropagation(); + }); + }); + } + + sortComprisonByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + switch (sort) { + case 0: + if (this.search!.value === '') { + this.comparisonTableEl!.snapshotDataSource = this.comparisonsData; + } else { + this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter; + } + break; + default: + if (this.search!.value === '') { + this.leftArray = [...this.comparisonsData]; + } else { + this.leftArray = [...this.comparisonFilter]; + } + switch (column) { + case 'addedCount': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.addedCount - b.addedCount : b.addedCount - a.addedCount; + }); + break; + case 'removedCount': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.removedCount - b.removedCount : b.removedCount - a.removedCount; + }); + break; + case 'deltaCount': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.deltaCount - b.deltaCount : b.deltaCount - a.deltaCount; + }); + break; + case 'objectName': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + break; + case 'addedSize': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.addedSize - b.addedSize : b.addedSize - a.addedSize; + }); + break; + case 'removedSize': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.removedSize - b.removedSize : b.removedSize - a.removedSize; + }); + break; + case 'deltaSize': + this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.deltaSize - b.deltaSize : b.deltaSize - a.deltaSize; + }); + break; + } + break; + } + } + + sortRetainerByColumn(column: string, sort: number) { + this.sortColumn = column; + this.sortType = sort; + switch (sort) { + case 0: + this.retainerTableEl!.snapshotDataSource = this.retainsData; + break; + default: + this.rightArray = [...this.retainsData]; + switch (column) { + case 'distance': + this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 ? a.distance - b.distance : b.distance - a.distance; + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.distance - b.distance : b.distance - a.distance; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.retainerTableEl!.snapshotDataSource = this.rightArray; + break; + case 'shallowSize': + this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 ? a.shallowSize - b.shallowSize : b.shallowSize - a.shallowSize; + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.shallowSize - b.shallowSize : b.shallowSize - a.shallowSize; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.retainerTableEl!.snapshotDataSource = this.rightArray; + break; + case 'retainedSize': + this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 ? a.retainedSize - b.retainedSize : b.retainedSize - a.retainedSize; + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.retainedSize - b.retainedSize : b.retainedSize - a.retainedSize; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.retainerTableEl!.snapshotDataSource = this.rightArray; + break; + case 'objectName': + this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.retainerTableEl!.snapshotDataSource = this.rightArray; + break; + } + break; + } + } + + classFilter() { + this.search!.addEventListener('keyup', () => { + this.comparisonFilter = []; + this.comparisonData.forEach((a: any, key: number) => { + if (a.objectName.toLowerCase().includes(this.search!.value.toLowerCase())) { + this.comparisonFilter.push(a); + } else { + } + }); + this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter; + let summaryTable = this.comparisonTableEl!.shadowRoot?.querySelector('.table') as HTMLDivElement; + summaryTable.scrollTop = 0; + }); + } + + clear() { + this.search!.value = ''; + this.rightTheadTable!.removeAttribute('sort'); + this.leftTheadTable!.removeAttribute('sort'); + } + + connectedCallback() { + super.connectedCallback(); + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + +
+ + +
+ + + + + + + + + + + + + + + + +
+ +
+
+ Retainers + + + + + + + + + + + + + +
+
+ +
+
+ + +
+
+ `; + } +} diff --git a/ide/src/trace/component/trace/sheet/snapshot/TabPaneSummary.ts b/ide/src/trace/component/trace/sheet/snapshot/TabPaneSummary.ts new file mode 100644 index 0000000000000000000000000000000000000000..285e7e06244e4e04a348ea89008c2cbb62c2cedb --- /dev/null +++ b/ide/src/trace/component/trace/sheet/snapshot/TabPaneSummary.ts @@ -0,0 +1,790 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js'; +import { LitTable } from '../../../../../base-ui/table/lit-table.js'; +import '../../../../../base-ui/table/lit-table.js'; +import { ConstructorItem, FileType } from '../../../../../js-heap/model/UiStruct.js'; +import { HeapDataInterface } from '../../../../../js-heap/HeapDataInterface.js'; +import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column.js'; +import '../../../../../base-ui/table/lit-table-column.js'; +import { TabPaneJsMemoryFilter } from '../TabPaneJsMemoryFilter.js'; +import '../TabPaneJsMemoryFilter.js'; +import { SelectionParam } from '../../../../bean/BoxSelection.js'; +import { SpJsMemoryChart } from '../../../chart/SpJsMemoryChart.js'; +import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import '../../../../../base-ui/progress-bar/LitProgressBar.js'; +import '../../../../../base-ui/slicer/lit-slicer.js'; +import { HeapSnapshotStruct } from '../../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js'; + +@element('tabpane-summary') +export class TabPaneSummary extends BaseElement { + private tbl: LitTable | null | undefined; + private tbs: LitTable | null | undefined; + private stackTable: LitTable | null | undefined; + private summary: Array = []; + private retainsData: Array = []; + private stackData: Array = []; + private stackText: HTMLElement | undefined; + static fileSize: number; + private tabFilter: TabPaneJsMemoryFilter | undefined | null; + private progressEL: LitProgressBar | null | undefined; + private summaryFilter: Array = []; + private summaryData: Array = []; + private search: HTMLInputElement | null | undefined; + private tbsTable: HTMLDivElement | null | undefined; + private tblTable: HTMLDivElement | null | undefined; + private rightTheadTable: HTMLDivElement | null | undefined; + private leftTheadTable: HTMLDivElement | null | undefined; + private leftArray: ConstructorItem[] = []; + private rightArray: ConstructorItem[] = []; + private stack: HTMLLIElement | null | undefined; + private retainers: HTMLLIElement | null | undefined; + + set data(val: SelectionParam | any) {} + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#left'); + this.tbs = this.shadowRoot?.querySelector('#right'); + this.stackTable = this.shadowRoot?.querySelector('#stackTable'); + this.stackText = this.shadowRoot?.querySelector('.stackText') as HTMLElement; + this.tabFilter = this.shadowRoot?.querySelector('#filter') as TabPaneJsMemoryFilter; + this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar; + this.search = this.tabFilter?.shadowRoot?.querySelector('#filter-input') as HTMLInputElement; + this.stack = this.shadowRoot?.querySelector('#stack') as HTMLLIElement; + this.retainers = this.shadowRoot?.querySelector('#retainers') as HTMLLIElement; + this.tblTable = this.tbl!.shadowRoot?.querySelector('.table') as HTMLDivElement; + this.rightTheadTable = this.tbs!.shadowRoot?.querySelector('.thead') as HTMLDivElement; + this.leftTheadTable = this.tbl!.shadowRoot?.querySelector('.thead') as HTMLDivElement; + this.tbl!.addEventListener('row-click', (evt: any) => { + this.rightTheadTable!.removeAttribute('sort'); + this.tbsTable = this.tbs!.shadowRoot?.querySelector('.table') as HTMLDivElement; + this.tbsTable!.scrollTop = 0; + let data = evt.detail.data as ConstructorItem; + (data as any).isSelected = true; + this.retainsData = []; + this.retainsData = HeapDataInterface.getInstance().getRetains(data); + this.retainsData.forEach((element: any) => { + let shallow = Math.round((element.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((element.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + element.shallowPercent = shallow; + element.retainedPercent = retained; + if (element.distance >= 100000000 || element.distance === -5) { + element.distance = '-'; + } + let nodeId = element.nodeName + ` @${element.id}`; + element.objectName = element.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; + }); + if (this.retainsData.length > 0) { + if (this.retainsData[0].distance > 1) { + this.retainsData[0].getChildren(); + } + let i = 0; + let that = this; + let retainsTable = function () { + const getList = function (list: any) { + list.forEach(function (row: any) { + let shallow = Math.round((row.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((row.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + row.shallowPercent = shallow; + row.retainedPercent = retained; + let nodeId = row.nodeName.concat(` @${row.id}`); + row.objectName = row.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; + if (row.distance >= 100000000 || row.distance === -5) { + row.distance = '-'; + } + i++; + if (i < that.retainsData[0].distance - 1 && list[0].distance != '-') { + list[0].getChildren(); + if (row.hasNext) { + getList(row.children); + } + } else { + return; + } + }); + }; + getList(that.retainsData[0].children); + }; + retainsTable(); + this.tbs!.snapshotDataSource = this.retainsData; + } else { + this.tbs!.snapshotDataSource = []; + } + if (SpJsMemoryChart.file.file_name.includes('Timeline')) { + this.stackData = HeapDataInterface.getInstance().getAllocationStackData(data); + if (this.stackData.length > 0) { + this.stackTable!.recycleDataSource = this.stackData; + this.stackText!.textContent = ''; + this.stackText!.style.display = 'none'; + if (this.stack!.className == 'active') { + this.stackTable!.style.display = 'grid'; + this.tbs!.style.display = 'none'; + } + } else { + this.stackText!.style.display = 'flex'; + this.stackTable!.recycleDataSource = []; + this.stackTable!.style.display = 'none'; + if (this.retainers!.className == 'active') { + this.stackText!.style.display = 'none'; + } + if (this.retainsData === undefined || this.retainsData.length === 0) { + this.stackText!.textContent = ''; + } else { + this.stackText!.textContent = + 'Stack was not recorded for this object because it had been allocated before this profile recording started.'; + } + } + } + new ResizeObserver(() => { + this.tbs!.style.height = 'calc(100% - 30px)'; + this.tbs!.reMeauseHeight(); + this.stackTable!.style.height = 'calc(100% - 30px)'; + this.stackTable!.reMeauseHeight(); + }).observe(this.parentElement!); + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.tbs!.addEventListener('row-click', (evt: any) => { + let data = evt.detail.data as ConstructorItem; + (data as any).isSelected = true; + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true); + } + }); + + this.tbl!.addEventListener('icon-click', (evt: any) => { + if (evt.detail.data.status) { + evt.detail.data.getChildren(); + evt.detail.data.children.sort(function (a: ConstructorItem, b: ConstructorItem) { + return b.retainedSize - a.retainedSize; + }); + evt.detail.data.children.forEach((element: any) => { + let shallow = Math.round((element.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((element.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + element.shallowPercent = shallow; + element.retainedPercent = retained; + if (element.distance >= 100000000 || element.distance === -5) { + element.distance = '-'; + } + let nodeId = element.nodeName.concat(` @${element.id}`); + element.objectName = nodeId; + if (element.edgeName != '') { + element.objectName = element.edgeName + '\xa0' + '::' + '\xa0' + nodeId; + } + }); + } else { + evt.detail.data.status = true; + } + if (this.search!.value != '') { + if (this.leftTheadTable!.hasAttribute('sort')) { + this.tbl!.snapshotDataSource = this.leftArray; + } else { + this.tbl!.snapshotDataSource = this.summaryFilter; + } + } else { + if (this.leftTheadTable!.hasAttribute('sort')) { + this.tbl!.snapshotDataSource = this.leftArray; + } else { + this.tbl!.snapshotDataSource = this.summary; + } + } + new ResizeObserver(() => { + if (this.parentElement?.clientHeight !== 0) { + this.tbl!.style.height = '100%'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + }); + this.tbs!.addEventListener('icon-click', (evt: any) => { + let that = this; + if (evt.detail.data.status) { + evt.detail.data.getChildren(); + let i = 0; + let retainsTable = function () { + const getList = function (list: any) { + list.forEach(function (row: any) { + let shallow = Math.round((row.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((row.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + row.shallowPercent = shallow; + row.retainedPercent = retained; + let nodeId = row.nodeName.concat(` @${row.id}`); + row.objectName = row.edgeName + '\xa0' + 'in' + '\xa0' + nodeId; + if (row.distance >= 100000000 || row.distance === -5) { + row.distance = '-'; + } + i++; + if (i < evt.detail.data.distance - 1 && list[0].distance != '-') { + list[0].getChildren(); + if (row.hasNext) { + getList(row.children); + } + } else { + return; + } + }); + }; + getList(evt.detail.data.children); + }; + retainsTable(); + } else { + evt.detail.data.status = true; + } + if (this.rightTheadTable!.hasAttribute('sort')) { + this.tbs!.snapshotDataSource = this.rightArray; + } else { + this.tbs!.snapshotDataSource = this.retainsData; + } + new ResizeObserver(() => { + if (this.parentElement?.clientHeight !== 0) { + this.tbs!.style.height = 'calc(100% - 30px)'; + this.tbs!.reMeauseHeight(); + } + }).observe(this.parentElement!); + }); + + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByLeftTable(evt.detail.key, evt.detail.sort); + }); + this.tbs!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByRightTable(evt.detail.key, evt.detail.sort); + }); + this.classFilter(); + } + + setSnapshotData( + data: HeapSnapshotStruct, + dataList: Array, + scrollCallback: ((d: any, ds: any) => void) | undefined + ) { + if (scrollCallback) { + scrollCallback(data, dataList); + } + this.summary = []; + this.initSummaryData(data.id); + } + + initSummaryData(fileId: number, maxNodeId?: number, minNodeId?: number) { + this.clear(); + this.summary = []; + this.progressEL!.loading = true; + this.summary = HeapDataInterface.getInstance().getClassesListForSummary(fileId, minNodeId, maxNodeId); + let dataList = HeapDataInterface.getInstance().getClassesListForSummary(SpJsMemoryChart.file.id); + TabPaneSummary.fileSize = dataList.reduce((sum, e) => sum + e.shallowSize, 0); + this.summary.forEach((element: any) => { + if (element.childCount > 1) { + let count = element.nodeName + ` ×${element.childCount}`; + element.objectName = count; + } else { + element.objectName = element.nodeName; + } + let shallow = Math.round((element.shallowSize / TabPaneSummary.fileSize) * 100) + '%'; + let retained = Math.round((element.retainedSize / TabPaneSummary.fileSize) * 100) + '%'; + element.shallowPercent = shallow; + element.retainedPercent = retained; + if (element.distance >= 100000000 || element.distance === -5) { + element.distance = '-'; + } + }); + if (this.summary.length > 0) { + this.summaryData = this.summary; + this.tbl!.snapshotDataSource = this.summary; + this.progressEL!.loading = false; + } else { + this.tbl!.snapshotDataSource = []; + this.progressEL!.loading = false; + } + new ResizeObserver(() => { + if (this.parentElement?.clientHeight !== 0) { + this.tbl!.style.height = '100%'; + this.tbl!.reMeauseHeight(); + } + }).observe(this.parentElement!); + if (SpJsMemoryChart.file.file_name.includes('Timeline')) { + this.retainers!.classList.add('active'); + this.stack!.style.display = 'flex'; + this.retainers!.style.pointerEvents = 'auto'; + } else { + this.stack!.style.display = 'none'; + this.retainers!.classList.remove('active'); + this.retainers!.style.pointerEvents = 'none'; + } + this.clickToggleTable(); + } + + sortByLeftTable(column: string, sort: number) { + switch (sort) { + case 0: + if (this.search!.value === '') { + this.tbl!.snapshotDataSource = this.summary; + } else { + this.tbl!.snapshotDataSource = this.summaryFilter; + } + break; + default: + if (this.search!.value === '') { + this.leftArray = [...this.summary]; + } else { + this.leftArray = [...this.summaryFilter]; + } + switch (column) { + case 'distance': + this.tbl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.distance - b.distance : b.distance - a.distance; + }); + this.leftArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.distance - b.distance : b.distance - a.distance; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbl!.snapshotDataSource = this.leftArray; + break; + case 'shallowSize': + this.tbl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.shallowSize - b.shallowSize : b.shallowSize - a.shallowSize; + }); + this.leftArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.shallowSize - b.shallowSize : b.shallowSize - a.shallowSize; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbl!.snapshotDataSource = this.leftArray; + break; + case 'retainedSize': + this.tbl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 ? a.retainedSize - b.retainedSize : b.retainedSize - a.retainedSize; + }); + this.leftArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.retainedSize - b.retainedSize : b.retainedSize - a.retainedSize; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbl!.snapshotDataSource = this.leftArray; + break; + case 'objectName': + this.tbl!.snapshotDataSource = this.leftArray.sort((a, b) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + this.leftArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbl!.snapshotDataSource = this.leftArray; + break; + } + break; + } + } + + sortByRightTable(column: string, sort: number) { + switch (sort) { + case 0: + this.tbs!.snapshotDataSource = this.retainsData; + break; + default: + this.rightArray = [...this.retainsData]; + switch (column) { + case 'distance': + this.tbs!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 ? a.distance - b.distance : b.distance - a.distance; + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.distance - b.distance : b.distance - a.distance; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbs!.snapshotDataSource = this.rightArray; + break; + case 'shallowSize': + this.tbs!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 ? a.shallowSize - b.shallowSize : b.shallowSize - a.shallowSize; + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.shallowSize - b.shallowSize : b.shallowSize - a.shallowSize; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbs!.snapshotDataSource = this.rightArray; + break; + case 'retainedSize': + this.tbs!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 ? a.retainedSize - b.retainedSize : b.retainedSize - a.retainedSize; + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 ? a.retainedSize - b.retainedSize : b.retainedSize - a.retainedSize; + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbs!.snapshotDataSource = this.rightArray; + break; + case 'objectName': + this.tbs!.snapshotDataSource = this.rightArray.sort((a, b) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + this.rightArray.forEach((list) => { + let retainsTable = function () { + const getList = function (list: any) { + list.sort((a: any, b: any) => { + return sort === 1 + ? (a.objectName + '').localeCompare(b.objectName + '') + : (b.objectName + '').localeCompare(a.objectName + ''); + }); + list.forEach(function (row: any) { + if (row.children.length > 0) { + getList(row.children); + } + }); + }; + getList(list.children); + }; + retainsTable(); + }); + this.tbs!.snapshotDataSource = this.rightArray; + break; + } + break; + } + } + + clickToggleTable() { + let lis = this.shadowRoot?.querySelectorAll('li') as any; + let that = this; + lis.forEach((li: any, i: any) => { + lis[i].onclick = function () { + for (let i = 0; i < lis.length; i++) { + lis[i].className = ''; + } + switch (li.textContent) { + case 'Retainers': + that.stackTable!.style.display = 'none'; + that.stackText!.style.display = 'none'; + that.tbs!.style.display = 'flex'; + that.tbs!.snapshotDataSource = that.retainsData; + break; + case 'Allocation stack': + if (that.stackData.length > 0) { + that.stackText!.style.display = 'none'; + that.stackTable!.style.display = 'flex'; + that.stackTable!.recycleDataSource = that.stackData; + } else { + that.stackText!.style.display = 'flex'; + if (that.retainsData === undefined || that.retainsData.length === 0) { + that.stackText!.textContent = ''; + } else { + that.stackText!.textContent = + 'Stack was not recorded for this object because it had been allocated before this profile recording started.'; + } + } + that.tbs!.style.display = 'none'; + break; + } + this.className = 'active'; + }; + }); + } + + classFilter() { + this.search!.addEventListener('keyup', () => { + this.summaryFilter = []; + this.summaryData.forEach((a: any, key: number) => { + if (a.objectName.toLowerCase().includes(this.search!.value.toLowerCase())) { + this.summaryFilter.push(a); + } else { + } + }); + this.tbl!.snapshotDataSource = this.summaryFilter; + let summaryTable = this.tbl!.shadowRoot?.querySelector('.table') as HTMLDivElement; + summaryTable.scrollTop = 0; + }); + } + + clear() { + this.tbs!.snapshotDataSource = []; + this.stackTable!.recycleDataSource = []; + this.retainsData = []; + this.stackText!.textContent = ''; + this.search!.value = ''; + this.stack!.classList.remove('active'); + this.tblTable!.scrollTop = 0; + this.stackTable!.style.display = 'none'; + this.stackText!.style.display = 'none'; + this.tbs!.style.display = 'flex'; + this.rightTheadTable!.removeAttribute('sort'); + this.leftTheadTable!.removeAttribute('sort'); + } + + connectedCallback() { + super.connectedCallback(); + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = 'flex'; + } else { + tabPaneFilter.style.display = 'none'; + } + }).observe(this.parentElement!); + } + + initHtml(): string { + return ` + +
+ + +
+ + + + + + + + + + + + + + +
+ +
+
+
+
    +
  • Retainers
  • + +
+
+ + + + + + + + + + + + + + + + +
+
+
+
+ + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/timer-shaft/Flag.ts b/ide/src/trace/component/trace/timer-shaft/Flag.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3a2bedcfd91f1076c6ab1f3081a15586f7e7684 --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/Flag.ts @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 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. + */ + +export class Flag { + x: number = 0; + y: number = 0; + width: number = 0; + height: number = 0; + time: number = 0; + color: string = ''; + selected: boolean = false; + text: string = ''; + hidden: boolean = false; + type: string = ''; + + constructor( + x: number, + y: number, + width: number, + height: number, + time: number, + color: string = '#999999', + selected = false, + type: string = '' + ) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.time = time; + this.color = color; + this.selected = selected; + this.type = type; + } +} diff --git a/ide/src/trace/component/trace/timer-shaft/Graph.ts b/ide/src/trace/component/trace/timer-shaft/Graph.ts new file mode 100644 index 0000000000000000000000000000000000000000..b120be822bcdaf3c4f68a553201b1689fecc820e --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/Graph.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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 { Rect } from './Rect.js'; + +export abstract class Graph { + frame: Rect; + c: CanvasRenderingContext2D; + canvas: HTMLCanvasElement | undefined | null; + + protected constructor(canvas: HTMLCanvasElement | undefined | null, c: CanvasRenderingContext2D, frame: Rect) { + this.canvas = canvas; + this.frame = frame; + this.c = c; + } + + abstract draw(): void; +} diff --git a/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts b/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ab8d76ba73468a5a145115803ef27a70b590eb0 --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2022 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 { Graph } from './Graph.js'; +import { Rect } from './Rect.js'; +import { ns2s, TimerShaftElement } from '../TimerShaftElement.js'; +import { ColorUtils } from '../base/ColorUtils.js'; +import { CpuStruct } from '../../../database/ui-worker/ProcedureWorkerCPU.js'; + +const markPadding = 5; + +export class Mark extends Graph { + name: string | undefined; + inspectionFrame: Rect; + private _isHover: boolean = false; + + constructor(canvas: HTMLCanvasElement | undefined | null, name: string, c: CanvasRenderingContext2D, frame: Rect) { + super(canvas, c, frame); + this.name = name; + this.inspectionFrame = new Rect(frame.x - markPadding, frame.y, frame.width + markPadding * 2, frame.height); + } + + get isHover(): boolean { + return this._isHover; + } + + set isHover(value: boolean) { + this._isHover = value; + if (value) { + document.body.style.cursor = 'ew-resize'; + } else { + document.body.style.cursor = 'default'; + } + } + + draw(): void { + this.c.beginPath(); + this.c.lineWidth = 7; + this.c.strokeStyle = '#999999'; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x, this.frame.y + this.frame.height / 3); + this.c.stroke(); + this.c.lineWidth = 1; + this.c.strokeStyle = '#999999'; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x, this.frame.y + this.frame.height); + this.c.stroke(); + this.c.closePath(); + } +} + +export interface TimeRange { + slicesTime: { + color: string | null | undefined; + startTime: number | null | undefined; + endTime: number | null | undefined; + }; + scale: number; + totalNS: number; + startX: number; + endX: number; + startNS: number; + endNS: number; + xs: Array; + refresh: boolean; + xsTxt: Array; +} + +export class RangeRuler extends Graph { + public rangeRect: Rect; + public markA: Mark; + public markB: Mark; + public range: TimeRange; + private pressedKeys: Array = []; + mouseDownOffsetX = 0; + mouseDownMovingMarkX = 0; + movingMark: Mark | undefined | null; + isMouseDown: boolean = false; + isMovingRange: boolean = false; + isNewRange: boolean = false; + markAX: number = 0; + markBX: number = 0; + isPress: boolean = false; + pressFrameIdW: number = -1; + pressFrameIdS: number = -1; + pressFrameIdA: number = -1; + pressFrameIdD: number = -1; + upFrameIdW: number = -1; + upFrameIdS: number = -1; + upFrameIdA: number = -1; + upFrameIdD: number = -1; + currentDuration: number = 0; + cacheInterval: { interval: number; value: number; flag: boolean } = { + interval: 200, + value: 0, + flag: false, + }; + centerXPercentage: number = 0; + animaStartTime: number | undefined; + p: number = 1000; + private readonly notifyHandler: (r: TimeRange) => void; + private scale: number = 0; + private delayTimer: any = null; + //缩放级别 + private scales: Array = [ + 50, 100, 200, 500, 1_000, 2_000, 5_000, 10_000, 20_000, 50_000, 100_000, 200_000, 500_000, 1_000_000, 2_000_000, + 5_000_000, 10_000_000, 20_000_000, 50_000_000, 100_000_000, 200_000_000, 500_000_000, 1_000_000_000, 2_000_000_000, + 5_000_000_000, 10_000_000_000, 20_000_000_000, 50_000_000_000, 100_000_000_000, 200_000_000_000, 500_000_000_000, + ]; + private _cpuUsage: Array<{ cpu: number; ro: number; rate: number }> = []; + + constructor(timerShaftEL: TimerShaftElement, frame: Rect, range: TimeRange, notifyHandler: (r: TimeRange) => void) { + super(timerShaftEL.canvas, timerShaftEL.ctx!, frame); + this.range = range; + this.notifyHandler = notifyHandler; + this.markA = new Mark( + timerShaftEL.canvas, + 'A', + timerShaftEL.ctx!, + new Rect(range.startX, frame.y, 1, frame.height) + ); + this.markB = new Mark(timerShaftEL.canvas, 'B', timerShaftEL.ctx!, new Rect(range.endX, frame.y, 1, frame.height)); + this.rangeRect = new Rect(range.startX, frame.y, range.endX - range.startX, frame.height); + } + + set cpuUsage(value: Array<{ cpu: number; ro: number; rate: number }>) { + this._cpuUsage = value; + this.draw(); + } + + drawCpuUsage() { + let maxNum = Math.round(this._cpuUsage.length / 100); + let miniHeight = Math.round(this.frame.height / CpuStruct.cpuCount); //每格高度 + let miniWidth = Math.ceil(this.frame.width / 100); //每格宽度 + for (let i = 0; i < this._cpuUsage.length; i++) { + let it = this._cpuUsage[i]; + this.c.fillStyle = ColorUtils.MD_PALETTE[it.cpu]; + this.c.globalAlpha = it.rate; + this.c.fillRect(this.frame.x + miniWidth * it.ro, this.frame.y + it.cpu * miniHeight, miniWidth, miniHeight); + } + } + + draw(discardNotify: boolean = false): void { + this.c.clearRect(this.frame.x - markPadding, this.frame.y, this.frame.width + markPadding * 2, this.frame.height); + this.c.beginPath(); + if (this._cpuUsage.length > 0) { + this.drawCpuUsage(); + this.c.globalAlpha = 0; + } else { + this.c.globalAlpha = 1; + } + //绘制选中区域 + this.c.fillStyle = window.getComputedStyle(this.canvas!, null).getPropertyValue('background-color'); //"#ffffff" + this.rangeRect.x = this.markA.frame.x < this.markB.frame.x ? this.markA.frame.x : this.markB.frame.x; + this.rangeRect.width = Math.abs(this.markB.frame.x - this.markA.frame.x); + this.c.fillRect(this.rangeRect.x, this.rangeRect.y, this.rangeRect.width, this.rangeRect.height); + this.c.globalAlpha = 1; + this.c.globalAlpha = 0.5; + this.c.fillStyle = '#999999'; + this.c.fillRect(this.frame.x, this.frame.y, this.rangeRect.x, this.rangeRect.height); + this.c.fillRect( + this.rangeRect.x + this.rangeRect.width, + this.frame.y, + this.frame.width - this.rangeRect.width, + this.rangeRect.height + ); + this.c.globalAlpha = 1; + this.c.closePath(); + this.markA.draw(); + this.markB.draw(); + if (this.notifyHandler) { + this.range.startX = this.rangeRect.x; + this.range.endX = this.rangeRect.x + this.rangeRect.width; + this.range.startNS = (this.range.startX * this.range.totalNS) / (this.canvas?.clientWidth || 0); + this.range.endNS = (this.range.endX * this.range.totalNS) / (this.canvas?.clientWidth || 0); + let l20 = (this.range.endNS - this.range.startNS) / 20; + let min = 0; + let max = 0; + let weight = 0; + for (let index = 0; index < this.scales.length; index++) { + if (this.scales[index] > l20) { + if (index > 0) { + min = this.scales[index - 1]; + } else { + min = 0; + } + max = this.scales[index]; + weight = ((l20 - min) * 1.0) / (max - min); + if (weight > 0.243) { + this.scale = max; + } else { + this.scale = min; + } + break; + } + } + if (this.scale == 0) { + this.scale = this.scales[0]; + } + let tmpNs = 0; + let yu = this.range.startNS % this.scale; + let realW = (this.scale * this.frame.width) / (this.range.endNS - this.range.startNS); + let startX = 0; + if (this.range.xs) { + this.range.xs.length = 0; + } else { + this.range.xs = []; + } + if (this.range.xsTxt) { + this.range.xsTxt.length = 0; + } else { + this.range.xsTxt = []; + } + this.range.scale = this.scale; + if (yu != 0) { + let firstNodeWidth = ((this.scale - yu) / this.scale) * realW; + startX += firstNodeWidth; + tmpNs += yu; + this.range.xs.push(startX); + this.range.xsTxt.push(ns2s(tmpNs)); + } + while (tmpNs < this.range.endNS - this.range.startNS) { + startX += realW; + tmpNs += this.scale; + this.range.xs.push(startX); + this.range.xsTxt.push(ns2s(tmpNs)); + } + + if (!discardNotify) { + this.notifyHandler(this.range); + } + } + } + + mouseDown(ev: MouseEvent) { + let x = ev.offsetX - (this.canvas?.offsetLeft || 0); + let y = ev.offsetY - (this.canvas?.offsetTop || 0); + this.isMouseDown = true; + this.mouseDownOffsetX = x; + if (this.markA.isHover) { + this.movingMark = this.markA; + this.mouseDownMovingMarkX = this.movingMark.frame.x || 0; + } else if (this.markB.isHover) { + this.movingMark = this.markB; + this.mouseDownMovingMarkX = this.movingMark.frame.x || 0; + } else { + this.movingMark = null; + } + if (this.rangeRect.containsWithPadding(x, y, 5, 0)) { + this.isMovingRange = true; + this.markAX = this.markA.frame.x; + this.markBX = this.markB.frame.x; + document.body.style.cursor = 'move'; + } else if ( + this.frame.containsWithMargin(x, y, 20, 0, 0, 0) && + !this.rangeRect.containsWithMargin(x, y, 0, markPadding, 0, markPadding) + ) { + this.isNewRange = true; + } + } + + mouseUp(ev: MouseEvent) { + this.isMouseDown = false; + this.isMovingRange = false; + this.isNewRange = false; + this.movingMark = null; + } + + mouseMove(ev: MouseEvent) { + this.range.refresh = false; + let x = ev.offsetX - (this.canvas?.offsetLeft || 0); + let y = ev.offsetY - (this.canvas?.offsetTop || 0); + this.centerXPercentage = x / (this.canvas?.clientWidth || 0); + if (this.centerXPercentage <= 0) { + this.centerXPercentage = 0; + } else if (this.centerXPercentage >= 1) { + this.centerXPercentage = 1; + } + let maxX = this.canvas?.clientWidth || 0; + if (this.markA.inspectionFrame.contains(x, y)) { + this.markA.isHover = true; + } else if (this.markB.inspectionFrame.contains(x, y)) { + this.markB.isHover = true; + } else { + this.markA.isHover = false; + this.markB.isHover = false; + } + if (this.movingMark) { + let result = x - this.mouseDownOffsetX + this.mouseDownMovingMarkX; + if (result >= 0 && result <= maxX) { + this.movingMark.frame.x = result; + } else if (result < 0) { + this.movingMark.frame.x = 0; + } else { + this.movingMark.frame.x = maxX; + } + this.movingMark.inspectionFrame.x = this.movingMark.frame.x - markPadding; + this.recordMovingS(); + requestAnimationFrame(() => { + this.draw(); + this.range.refresh = false; + this.delayDraw(); + }); + } else if (this.rangeRect.containsWithPadding(x, y, markPadding, 0)) { + document.body.style.cursor = 'move'; + } else if ( + this.frame.containsWithMargin(x, y, 20, 0, 0, 0) && + !this.rangeRect.containsWithMargin(x, y, 0, markPadding, 0, markPadding) + ) { + document.body.style.cursor = 'crosshair'; + } + if (this.isMovingRange && this.isMouseDown) { + let result = x - this.mouseDownOffsetX; + let mA = result + this.markAX; + let mB = result + this.markBX; + if (mA >= 0 && mA <= maxX) { + this.markA.frame.x = mA; + } else if (mA < 0) { + this.markA.frame.x = 0; + } else { + this.markA.frame.x = maxX; + } + this.markA.inspectionFrame.x = this.markA.frame.x - markPadding; + if (mB >= 0 && mB <= maxX) { + this.markB.frame.x = mB; + } else if (mB < 0) { + this.markB.frame.x = 0; + } else { + this.markB.frame.x = maxX; + } + this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; + this.recordMovingS(); + requestAnimationFrame(() => { + this.draw(); + this.range.refresh = false; + this.delayDraw(); + }); + } else if (this.isNewRange) { + this.markA.frame.x = this.mouseDownOffsetX; + this.markA.inspectionFrame.x = this.mouseDownOffsetX - markPadding; + if (x >= 0 && x <= maxX) { + this.markB.frame.x = x; + } else if (x < 0) { + this.markB.frame.x = 0; + } else { + this.markB.frame.x = maxX; + } + this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; + this.recordMovingS(); + requestAnimationFrame(() => { + this.draw(); + this.range.refresh = false; + this.delayDraw(); + }); + } + } + + recordMovingS() { + if (this.animaStartTime == undefined) { + let dat = new Date(); + dat.setTime(dat.getTime() - 400); + this.animaStartTime = dat.getTime(); + } + this.currentDuration = new Date().getTime() - this.animaStartTime; + if (Math.trunc(this.currentDuration / this.cacheInterval.interval) != this.cacheInterval.value) { + this.cacheInterval.flag = true; + this.cacheInterval.value = Math.trunc(this.currentDuration / this.cacheInterval.interval); + } else { + this.cacheInterval.flag = false; + } + this.range.refresh = this.cacheInterval.flag; + } + + delayDraw() { + if (this.delayTimer) { + clearTimeout(this.delayTimer); + } + this.delayTimer = setTimeout(() => { + this.range.refresh = true; + this.draw(); + this.range.refresh = false; + this.animaStartTime = undefined; + }, this.cacheInterval.interval + 50); + } + + mouseOut(ev: MouseEvent) { + this.movingMark = null; + } + + fillX() { + if (this.range.startNS < 0) this.range.startNS = 0; + if (this.range.endNS < 0) this.range.endNS = 0; + if (this.range.endNS > this.range.totalNS) this.range.endNS = this.range.totalNS; + if (this.range.startNS > this.range.totalNS) this.range.startNS = this.range.totalNS; + this.range.startX = (this.range.startNS * (this.canvas?.clientWidth || 0)) / this.range.totalNS; + this.range.endX = (this.range.endNS * (this.canvas?.clientWidth || 0)) / this.range.totalNS; + this.markA.frame.x = this.range.startX; + this.markA.inspectionFrame.x = this.markA.frame.x - markPadding; + this.markB.frame.x = this.range.endX; + this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; + } + + setRangeNS(startNS: number, endNS: number) { + this.range.startNS = startNS; + this.range.endNS = endNS; + this.fillX(); + this.draw(); + } + + getRange(): TimeRange { + return this.range; + } + + cancelPressFrame() { + if (this.pressFrameIdA != -1) cancelAnimationFrame(this.pressFrameIdA); + if (this.pressFrameIdD != -1) cancelAnimationFrame(this.pressFrameIdD); + if (this.pressFrameIdW != -1) cancelAnimationFrame(this.pressFrameIdW); + if (this.pressFrameIdS != -1) cancelAnimationFrame(this.pressFrameIdS); + } + + cancelUpFrame() { + if (this.upFrameIdA != -1) cancelAnimationFrame(this.upFrameIdA); + if (this.upFrameIdD != -1) cancelAnimationFrame(this.upFrameIdD); + if (this.upFrameIdW != -1) cancelAnimationFrame(this.upFrameIdW); + if (this.upFrameIdS != -1) cancelAnimationFrame(this.upFrameIdS); + } + + cancelTimeOut: any = undefined; + + keyPress(ev: KeyboardEvent) { + if ( + this.animaStartTime == undefined || + (this.pressedKeys.length > 0 && this.pressedKeys[this.pressedKeys.length - 1] != ev.key.toLocaleLowerCase()) + ) { + let dat = new Date(); + dat.setTime(dat.getTime() - 400); + this.animaStartTime = dat.getTime(); + } + this.currentDuration = new Date().getTime() - this.animaStartTime; + if (Math.trunc(this.currentDuration / this.cacheInterval.interval) != this.cacheInterval.value) { + this.cacheInterval.flag = true; + this.cacheInterval.value = Math.trunc(this.currentDuration / this.cacheInterval.interval); + } else { + this.cacheInterval.flag = false; + } + this.range.refresh = this.cacheInterval.flag; + if (this.pressedKeys.length > 0) { + if (this.pressedKeys[this.pressedKeys.length - 1] != ev.key.toLocaleLowerCase()) { + this.cancelPressFrame(); + this.cancelUpFrame(); + this.pressedKeys.push(ev.key.toLocaleLowerCase()); + let dat = new Date(); + dat.setTime(dat.getTime() - 400); + this.animaStartTime = dat.getTime(); + this.keyboardKeyPressMap[this.pressedKeys[this.pressedKeys.length - 1]]?.bind(this)(); + } + } else { + this.cancelPressFrame(); + this.cancelUpFrame(); + this.pressedKeys.push(ev.key.toLocaleLowerCase()); + let dat = new Date(); + dat.setTime(dat.getTime() - 400); + this.animaStartTime = dat.getTime(); + this.keyboardKeyPressMap[this.pressedKeys[this.pressedKeys.length - 1]]?.bind(this)(); + } + this.isPress = true; + if (this.cancelTimeOut) { + clearTimeout(this.cancelTimeOut); + } + this.cancelTimeOut = setTimeout(() => { + this.keyUp({ key: ev.key } as KeyboardEvent); + }, 1000); + } + + keyPressW() { + let animW = () => { + if (this.scale === 50) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + this.range.startNS += (this.centerXPercentage * this.currentDuration * this.scale) / this.p; + this.range.endNS -= ((1 - this.centerXPercentage) * this.currentDuration * this.scale) / this.p; + this.fillX(); + this.draw(); + this.range.refresh = false; + this.pressFrameIdW = requestAnimationFrame(animW); + }; + this.pressFrameIdW = requestAnimationFrame(animW); + } + + keyPressS() { + let animS = () => { + if (this.range.startNS <= 0 && this.range.endNS >= this.range.totalNS) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + this.range.startNS -= ((this.centerXPercentage * this.scale) / this.p) * this.currentDuration; + this.range.endNS += (((1 - this.centerXPercentage) * this.scale) / this.p) * this.currentDuration; + this.fillX(); + this.draw(); + this.range.refresh = false; + this.pressFrameIdS = requestAnimationFrame(animS); + }; + this.pressFrameIdS = requestAnimationFrame(animS); + } + + keyPressA() { + let animA = () => { + if (this.range.startNS == 0) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + let s = (this.scale / this.p) * this.currentDuration * 0.4; + this.range.startNS -= s; + this.range.endNS -= s; + this.fillX(); + this.draw(); + this.range.refresh = false; + this.pressFrameIdA = requestAnimationFrame(animA); + }; + this.pressFrameIdA = requestAnimationFrame(animA); + } + + keyPressD() { + let animD = () => { + if (this.range.endNS >= this.range.totalNS) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + let s = (this.scale / this.p) * this.currentDuration * 0.4; + this.range.startNS += s; + this.range.endNS += s; + this.fillX(); + this.draw(); + this.range.refresh = false; + this.pressFrameIdD = requestAnimationFrame(animD); + }; + this.pressFrameIdD = requestAnimationFrame(animD); + } + + keyboardKeyPressMap: any = { + w: this.keyPressW, + s: this.keyPressS, + a: this.keyPressA, + d: this.keyPressD, + }; + + keyboardKeyUpMap: any = { + w: this.keyUpW, + s: this.keyUpS, + a: this.keyUpA, + d: this.keyUpD, + }; + + keyUp(ev: KeyboardEvent) { + this.cacheInterval.value = 0; + if (this.pressedKeys.length > 0) { + let number = this.pressedKeys.findIndex((value) => value === ev.key.toLocaleLowerCase()); + if (number == this.pressedKeys.length - 1) { + this.animaStartTime = undefined; + this.cancelPressFrame(); + this.keyboardKeyUpMap[ev.key]?.bind(this)(); + } + if (number != -1) { + this.pressedKeys.splice(number, 1); + } + } + this.isPress = false; + } + + keyUpW() { + let startTime = new Date().getTime(); + let animW = () => { + if (this.scale === 50) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + let dur = new Date().getTime() - startTime; + this.range.startNS += (this.centerXPercentage * 100 * this.scale) / this.p; + this.range.endNS -= ((1 - this.centerXPercentage) * 100 * this.scale) / this.p; + this.fillX(); + this.draw(); + this.range.refresh = false; + if (dur < 200) { + this.upFrameIdW = requestAnimationFrame(animW); + } else { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + } + }; + this.upFrameIdW = requestAnimationFrame(animW); + } + + keyUpS() { + let startTime = new Date().getTime(); + let animS = () => { + if (this.range.startNS <= 0 && this.range.endNS >= this.range.totalNS) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + let dur = new Date().getTime() - startTime; + this.range.startNS -= (this.centerXPercentage * 100 * this.scale) / this.p; + this.range.endNS += ((1 - this.centerXPercentage) * 100 * this.scale) / this.p; + this.fillX(); + this.draw(); + this.range.refresh = false; + if (dur < 200) { + this.upFrameIdS = requestAnimationFrame(animS); + } else { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + } + }; + this.upFrameIdS = requestAnimationFrame(animS); + } + + keyUpA() { + let startTime = new Date().getTime(); + let animA = () => { + if (this.range.startNS <= 0) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + let dur = new Date().getTime() - startTime; + let s = (this.scale * 80) / this.p; + this.range.startNS -= s; + this.range.endNS -= s; + this.fillX(); + this.draw(); + this.range.refresh = false; + if (dur < 200) { + this.upFrameIdA = requestAnimationFrame(animA); + } else { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + } + }; + this.upFrameIdA = requestAnimationFrame(animA); + } + + keyUpD() { + let startTime = new Date().getTime(); + let animD = () => { + if (this.range.endNS >= this.range.totalNS) { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + return; + } + let dur = new Date().getTime() - startTime; + let s = (this.scale * 80) / this.p; + this.range.startNS += s; + this.range.endNS += s; + this.fillX(); + this.draw(); + this.range.refresh = false; + if (dur < 200) { + this.upFrameIdD = requestAnimationFrame(animD); + } else { + this.range.refresh = true; + this.notifyHandler(this.range); + this.range.refresh = false; + } + }; + this.upFrameIdD = requestAnimationFrame(animD); + } +} diff --git a/ide/src/trace/component/trace/timer-shaft/Rect.ts b/ide/src/trace/component/trace/timer-shaft/Rect.ts new file mode 100644 index 0000000000000000000000000000000000000000..d80bc81ed8d12aff2da3b88534367b8d363d3deb --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/Rect.ts @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 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. + */ + +export class Rect { + x: number = 0; + y: number = 0; + width: number = 0; + height: number = 0; + + constructor(x: number, y: number, width: number, height: number) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + static contains(rect: Rect, x: number, y: number): boolean { + return rect.x <= x && x <= rect.x + rect.width && rect.y <= y && y <= rect.y + rect.height; + } + + static containsWithPadding( + rect: Rect, + x: number, + y: number, + paddingLeftRight: number, + paddingTopBottom: number + ): boolean { + return ( + rect.x + paddingLeftRight <= x && + x <= rect.x + rect.width - paddingLeftRight && + rect.y + paddingTopBottom <= y && + y <= rect.y + rect.height - paddingTopBottom + ); + } + + static containsWithMargin(rect: Rect, x: number, y: number, t: number, r: number, b: number, l: number): boolean { + return rect.x - l <= x && x <= rect.x + rect.width + r && rect.y - t <= y && y <= rect.y + rect.height + b; + } + + static intersect(r1: Rect, rect: Rect): boolean { + let maxX = r1.x + r1.width > rect.x + rect.width ? r1.x + r1.width : rect.x + rect.width; + let maxY = r1.y + r1.height > rect.y + rect.height ? r1.y + r1.height : rect.y + rect.height; + let minX = r1.x < rect.x ? r1.x : rect.x; + let minY = r1.y < rect.y ? r1.y : rect.y; + if (maxX - minX < rect.width + r1.width && maxY - minY < r1.height + rect.height) { + return true; + } else { + return false; + } + } + + static getIntersect(r1: DOMRect | Rect, rect: DOMRect | Rect): Rect { + let maxX = Math.max(r1.x, rect.x); + let maxY = Math.max(r1.y, rect.y); + let width = Math.abs(Math.min(r1.x + r1.width, rect.x + rect.width) - Math.max(r1.x, rect.x)); + let height = Math.abs(Math.min(r1.y + r1.height, rect.y + rect.height) - Math.max(r1.y, rect.y)); + return new Rect(maxX, maxY, width, height); + } + + contains(x: number, y: number): boolean { + return this.x <= x && x <= this.x + this.width && this.y <= y && y <= this.y + this.height; + } + + containsWithPadding(x: number, y: number, paddingLeftRight: number, paddingTopBottom: number): boolean { + return ( + this.x + paddingLeftRight <= x && + x <= this.x + this.width - paddingLeftRight && + this.y + paddingTopBottom <= y && + y <= this.y + this.height - paddingTopBottom + ); + } + + containsWithMargin(x: number, y: number, t: number, r: number, b: number, l: number): boolean { + return this.x - l <= x && x <= this.x + this.width + r && this.y - t <= y && y <= this.y + this.height + b; + } + + /** + * 判断是否相交 + * @param rect + */ + intersect(rect: Rect): boolean { + let maxX = this.x + this.width >= rect.x + rect.width ? this.x + this.width : rect.x + rect.width; + let maxY = this.y + this.height >= rect.y + rect.height ? this.y + this.height : rect.y + rect.height; + let minX = this.x <= rect.x ? this.x : rect.x; + let minY = this.y <= rect.y ? this.y : rect.y; + if (maxX - minX <= rect.width + this.width && maxY - minY <= this.height + rect.height) { + return true; + } else { + return false; + } + } +} + +export class Point { + x: number = 0; + y: number = 0; + + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } +} diff --git a/ide/src/trace/component/trace/timer-shaft/SportRuler.ts b/ide/src/trace/component/trace/timer-shaft/SportRuler.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a6001ce957bca6846fbac114eff920ffec38637 --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/SportRuler.ts @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2022 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 { Graph } from './Graph.js'; +import { Rect } from './Rect.js'; +import { TimeRange } from './RangeRuler.js'; +import { Flag } from './Flag.js'; +import { ns2s, ns2x, randomRgbColor, TimerShaftElement } from '../TimerShaftElement.js'; +import { TraceRow } from '../base/TraceRow.js'; +import { SpApplication } from '../../../SpApplication.js'; + +export class SportRuler extends Graph { + static isMouseInSportRuler = false; + public flagList: Array = []; + isRangeSelect: boolean = false; //region selection + private hoverFlag: Flag = new Flag(-1, 0, 0, 0, 0); + private lineColor: string | null = null; + private rulerW = 0; + private _range: TimeRange = {} as TimeRange; + private readonly notifyHandler: + | ((hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => void) + | undefined; + private readonly flagClickHandler: ((flag: Flag | undefined | null) => void) | undefined; + private invertedTriangleTime: number | null | undefined = null; + private slicesTime: { + startTime: number | null | undefined; + endTime: number | null | undefined; + color: string | null; + } | null = { + startTime: null, + endTime: null, + color: null, + }; + private timerShaftEL: TimerShaftElement | undefined | null; + constructor( + timerShaftEL: TimerShaftElement, + frame: Rect, + notifyHandler: (hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => void, + flagClickHandler: (flag: Flag | undefined | null) => void + ) { + super(timerShaftEL.canvas, timerShaftEL.ctx!, frame); + this.notifyHandler = notifyHandler; + this.flagClickHandler = flagClickHandler; + this.timerShaftEL = timerShaftEL; + } + + get range(): TimeRange { + return this._range; + } + + set range(value: TimeRange) { + this._range = value; + this.draw(); + } + + modifyFlagList(flag: Flag | null | undefined) { + if (flag) { + if (flag.hidden) { + let i = this.flagList.findIndex((it) => it.time == flag.time); + this.flagList.splice(i, 1); + } else { + let i = this.flagList.findIndex((it) => it.time == flag.time); + this.flagList[i] = flag; + } + } else { + this.flagList.forEach((it) => (it.selected = false)); + } + this.draw(); + } + + draw(): void { + this.rulerW = this.canvas!.offsetWidth; + this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height + 1); + this.c.beginPath(); + this.lineColor = window.getComputedStyle(this.canvas!, null).getPropertyValue('color'); + this.c.strokeStyle = this.lineColor; //"#dadada" + this.c.lineWidth = 1; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x + this.frame.width, this.frame.y); + this.c.stroke(); + this.c.closePath(); + this.c.beginPath(); + this.c.lineWidth = 3; + this.c.strokeStyle = '#999999'; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x, this.frame.y + this.frame.height); + this.c.stroke(); + this.c.closePath(); + this.c.beginPath(); + this.c.lineWidth = 1; + this.c.strokeStyle = this.lineColor; //"#999999" + this.c.fillStyle = '#999999'; + this.c.font = '8px sans-serif'; + this.range.xs?.forEach((it, i) => { + this.c.moveTo(it, this.frame.y); + this.c.lineTo(it, this.frame.y + this.frame.height); + this.c.fillText(`+${this.range.xsTxt[i]}`, it + 3, this.frame.y + 12); + }); + this.c.stroke(); + this.c.closePath(); + //绘制旗子 + this.flagList.forEach((flagObj: Flag, b) => { + if (flagObj.time >= this.range.startNS && flagObj.time <= this.range.endNS) { + flagObj.x = Math.round( + (this.rulerW * (flagObj.time - this.range.startNS)) / (this.range.endNS - this.range.startNS) + ); + this.drawFlag(flagObj.x, flagObj.color, flagObj.selected, flagObj.text, flagObj.type); + } + }); + !this.hoverFlag.hidden && this.drawFlag(this.hoverFlag.x, this.hoverFlag.color, true, this.hoverFlag.text); + //If region selection is enabled, the serial number draws a line on the axis to show the length of the box selection + if (this.isRangeSelect) { + let range = TraceRow.rangeSelectObject; + this.c.beginPath(); + if (document.querySelector('sp-application')!.dark) { + this.c.strokeStyle = '#FFF'; + this.c.fillStyle = '#FFF'; + } else { + this.c.strokeStyle = '#000'; + this.c.fillStyle = '#000'; + } + let startX = ns2x(range?.startNS || 0, this.range.startNS, this.range.endNS, this.range.totalNS, this.frame); + let endX = ns2x(range?.endNS || 0, this.range.startNS, this.range.endNS, this.range.totalNS, this.frame); + let lineWidth = endX - startX; + let txt = ns2s((range?.endNS || 0) - (range?.startNS || 0)); + this.c.moveTo(startX, this.frame.y + 22); + this.c.lineTo(endX, this.frame.y + 22); + this.c.moveTo(startX, this.frame.y + 22 - 5); + this.c.lineTo(startX, this.frame.y + 22 + 5); + this.c.moveTo(endX, this.frame.y + 22 - 5); + this.c.lineTo(endX, this.frame.y + 22 + 5); + let txtWidth = this.c.measureText(txt).width; + if (lineWidth > txtWidth) { + this.c.fillText(`${txt}`, startX + (lineWidth - txtWidth) / 2, this.frame.y + 20); + } else { + if (endX + txtWidth >= this.frame.width) { + this.c.fillText(`${txt}`, startX - 5 - txtWidth, this.frame.y + 20); + } else { + this.c.fillText(`${txt}`, endX + 5, this.frame.y + 20); + } + } + this.c.stroke(); + this.c.closePath(); + } + if (this.invertedTriangleTime != null && typeof this.invertedTriangleTime != undefined) { + this.drawInvertedTriangle( + this.invertedTriangleTime, + document.querySelector('sp-application')!.dark ? '#FFFFFF' : '#000000' + ); + } + this.drawSlicesMark(this.slicesTime?.startTime, this.slicesTime?.endTime); + } + + drawTriangle(time: number, type: string) { + if (time != null && typeof time != undefined) { + let i = this.flagList.findIndex((it) => it.time == time); + if (type == 'triangle') { + let triangle = this.flagList.findIndex((it) => it.type == type); + if (i !== -1) { + if (triangle !== -1) { + this.flagList[i].type == '' ? this.flagList.splice(triangle, 1) : ''; + } + this.flagList.forEach((it) => (it.selected = false)); + this.flagList[i].selected = true; + } else { + if (triangle == -1) { + this.flagList.forEach((it) => (it.selected = false)); + this.flagList.push(new Flag(0, 125, 18, 18, time, randomRgbColor(), true, 'triangle')); + } else { + this.flagList.forEach((it) => (it.selected = false)); + this.flagList[triangle].time = time; + this.flagList[triangle].selected = true; + } + } + } else if (type == 'square') { + if (i != -1) { + this.flagList[i].type = ''; + } else { + let triangle = this.flagList.findIndex((it) => it.type == 'triangle'); + if (triangle !== -1) { + this.flagList[triangle].type = ''; + this.draw(); + this.notifyHandler && + this.notifyHandler( + !this.hoverFlag.hidden ? this.hoverFlag : null, + this.flagList.find((it) => it.selected) || null + ); + return this.flagList[triangle].time; + } + } + } else if (type == 'inverted') { + this.invertedTriangleTime = time; + } + this.draw(); + this.notifyHandler && + this.notifyHandler( + !this.hoverFlag.hidden ? this.hoverFlag : null, + this.flagList.find((it) => it.selected) || null + ); + } + } + + removeTriangle(type: string) { + if (type == 'inverted') { + this.invertedTriangleTime = null; + } else { + let i = this.flagList.findIndex((it) => it.type == type); + if (i !== -1) { + this.flagList.splice(i, 1); + } + } + this.draw(); + this.notifyHandler && + this.notifyHandler( + !this.hoverFlag.hidden ? this.hoverFlag : null, + this.flagList.find((it) => it.selected) || null + ); + } + + drawInvertedTriangle(time: number, color: string = '#000000') { + if (time != null && typeof time != undefined) { + let x = Math.round((this.rulerW * (time - this.range.startNS)) / (this.range.endNS - this.range.startNS)); + this.c.beginPath(); + this.c.fillStyle = color; + this.c.strokeStyle = color; + this.c.moveTo(x - 3, 141); + this.c.lineTo(x + 3, 141); + this.c.lineTo(x, 145); + this.c.fill(); + this.c.closePath(); + this.c.stroke(); + } + } + + setSlicesMark(startTime: number | null = null, endTime: number | null = null) { + if (startTime != null && typeof startTime != undefined && endTime != null && typeof endTime != undefined) { + this.slicesTime = { + startTime: startTime <= endTime ? startTime : endTime, + endTime: startTime <= endTime ? endTime : startTime, + color: null, + }; + } else { + this.slicesTime = { startTime: null, endTime: null, color: null }; + } + this.range.slicesTime = this.slicesTime; + this.timerShaftEL?.render(); + } + + clearHoverFlag() { + this.hoverFlag.hidden = true; + } + + drawSlicesMark(startTime: number | null = null, endTime: number | null = null) { + if (startTime != null && typeof startTime != undefined && endTime != null && typeof endTime != undefined) { + let startX = Math.round( + (this.rulerW * (startTime - this.range.startNS)) / (this.range.endNS - this.range.startNS) + ); + let endX = Math.round((this.rulerW * (endTime - this.range.startNS)) / (this.range.endNS - this.range.startNS)); + this.c.beginPath(); + if (document.querySelector('sp-application')!.dark) { + this.c.strokeStyle = '#FFF'; + this.c.fillStyle = '#FFF'; + this.range.slicesTime.color = '#FFF'; + } else { + this.c.strokeStyle = '#344596'; + this.c.fillStyle = '#344596'; + this.range.slicesTime.color = '#344596'; + } + this.c.moveTo(startX + 9, 132); + this.c.lineTo(startX, 141); + this.c.lineTo(startX, 132); + this.c.lineTo(startX + 9, 132); + + this.c.lineTo(endX - 9, 132); + this.c.lineTo(endX, 132); + this.c.lineTo(endX, 141); + this.c.lineTo(endX - 9, 132); + this.c.closePath(); + this.c.stroke(); + + this.c.beginPath(); + if (document.querySelector('sp-application')!.dark) { + this.c.strokeStyle = '#FFF'; + this.c.fillStyle = '#FFF'; + } else { + this.c.strokeStyle = '#000'; + this.c.fillStyle = '#000'; + } + let lineWidth = endX - startX; + let txt = ns2s((endTime || 0) - (startTime || 0)); + this.c.moveTo(startX, this.frame.y + 22); + this.c.lineTo(endX, this.frame.y + 22); + this.c.moveTo(startX, this.frame.y + 22 - 5); + this.c.lineTo(startX, this.frame.y + 22 + 5); + this.c.moveTo(endX, this.frame.y + 22 - 5); + this.c.lineTo(endX, this.frame.y + 22 + 5); + let txtWidth = this.c.measureText(txt).width; + this.c.fillStyle = '#FFF'; //为了解决文字重叠问题。在时间刻度的文字下面绘制一个小方块 + this.c.fillRect(startX + (lineWidth - txtWidth) / 2, this.frame.y + 10, txtWidth + 2, 10); + this.c.fillStyle = 'black'; + if (lineWidth > txtWidth) { + this.c.fillText(`${txt}`, startX + (lineWidth - txtWidth) / 2, this.frame.y + 20); + } else { + if (endX + txtWidth >= this.frame.width) { + this.c.fillText(`${txt}`, startX - 5 - txtWidth, this.frame.y + 20); + } else { + this.c.fillText(`${txt}`, endX + 5, this.frame.y + 20); + } + } + this.c.stroke(); + this.c.closePath(); + } + } + + //绘制旗子 + drawFlag(x: number, color: string = '#999999', isFill: boolean = false, text: string = '', type: string = '') { + if (x < 0) return; + this.c.beginPath(); + this.c.fillStyle = color; + this.c.strokeStyle = color; + this.c.moveTo(x, 125); + if (type == 'triangle') { + this.c.lineTo(x + 15, 131); + } else { + this.c.lineTo(x + 10, 125); + this.c.lineTo(x + 10, 127); + this.c.lineTo(x + 18, 127); + this.c.lineTo(x + 18, 137); + this.c.lineTo(x + 10, 137); + this.c.lineTo(x + 10, 135); + } + this.c.lineTo(x + 2, 135); + this.c.lineTo(x + 2, 142); + this.c.lineTo(x, 142); + this.c.closePath(); + isFill && this.c.fill(); + this.c.stroke(); + if (text !== '') { + this.c.font = '10px Microsoft YaHei'; + const { width } = this.c.measureText(text); + this.c.fillStyle = 'rgba(255, 255, 255, 0.8)'; // + this.c.fillRect(x + 21, 132, width + 4, 12); + this.c.fillStyle = 'black'; + this.c.fillText(text, x + 23, 142); + this.c.stroke(); + } + } + + mouseUp(ev: MouseEvent) { + if (this.edgeDetection(ev)) { + this.flagList.forEach((it) => (it.selected = false)); + let x = ev.offsetX - (this.canvas?.offsetLeft || 0); + let findFlag = this.flagList.find((it) => x >= it.x && x <= it.x + 18); + if (findFlag) { + findFlag.selected = true; + } else { + let flagAtRulerTime = Math.round(((this.range.endNS - this.range.startNS) * x) / this.rulerW); + if (flagAtRulerTime > 0 && this.range.startNS + flagAtRulerTime < this.range.endNS) { + this.flagList.push(new Flag(x, 125, 18, 18, flagAtRulerTime + this.range.startNS, randomRgbColor(), true)); + } + } + this.flagClickHandler && this.flagClickHandler(this.flagList.find((it) => it.selected)); + } + } + + mouseMove(ev: MouseEvent) { + if (this.edgeDetection(ev)) { + let x = ev.offsetX - (this.canvas?.offsetLeft || 0); + let flg = this.flagList.find((it) => x >= it.x && x <= it.x + 18); + if (flg) { + this.hoverFlag.hidden = true; + } else { + this.hoverFlag.hidden = false; + this.hoverFlag.x = x; + this.hoverFlag.color = '#999999'; + } + } else { + this.hoverFlag.hidden = true; + } + this.draw(); + this.notifyHandler && + this.notifyHandler( + !this.hoverFlag.hidden ? this.hoverFlag : null, + this.flagList.find((it) => it.selected) || null + ); + } + + mouseOut(ev: MouseEvent) { + if (!this.hoverFlag.hidden) { + this.hoverFlag.hidden = true; + this.notifyHandler && + this.notifyHandler( + !this.hoverFlag.hidden ? this.hoverFlag : null, + this.flagList.find((it) => it.selected) || null + ); + } + this.draw(); + } + + edgeDetection(ev: MouseEvent): boolean { + let x = ev.offsetX - (this.canvas?.offsetLeft || 0); + let y = ev.offsetY - (this.canvas?.offsetTop || 0); + SportRuler.isMouseInSportRuler = + x > 0 && + x < this.canvas!.offsetWidth && + ev.offsetY - this.frame.y > 20 && + ev.offsetY - this.frame.y < this.frame.height; + return SportRuler.isMouseInSportRuler; + } +} diff --git a/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts b/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts new file mode 100644 index 0000000000000000000000000000000000000000..6eebb50d1c2d8349b7071df64dd4bb53e638e34e --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2022 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 { BaseElement, element } from '../../../../base-ui/BaseElement.js'; +import { Flag } from './Flag.js'; +import { ns2s } from '../TimerShaftElement.js'; + +@element('tabpane-flag') +export class TabPaneFlag extends BaseElement { + private flagListIdx: number | null = null; + private flag: Flag | null = null; + + initElements(): void { + this.shadowRoot?.querySelector('#color-input')?.addEventListener('change', (event: any) => { + if (this.flag) { + this.flag.color = event?.target.value; + document.dispatchEvent(new CustomEvent('flag-change', { detail: this.flag })); + } + }); + this.shadowRoot?.querySelector('#text-input')?.addEventListener('keyup', (event: any) => { + event.stopPropagation(); + if (event.keyCode == '13') { + if (this.flag) { + (window as any).flagInputFocus = false; + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: true, + }); + this.flag.text = event?.target.value; + document.dispatchEvent( + new CustomEvent('flag-change', { + detail: this.flag, + }) + ); + } + } + }); + this.shadowRoot?.querySelector('#text-input')?.addEventListener('blur', (event: any) => { + (window as any).flagInputFocus = false; + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: true, + }); + }); + this.shadowRoot?.querySelector('#text-input')?.addEventListener('focus', (event: any) => { + (window as any).flagInputFocus = true; + window.publish(window.SmartEvent.UI.KeyboardEnable, { + enable: false, + }); + }); + this.shadowRoot?.querySelector('#remove-flag')?.addEventListener('click', (event: any) => { + if (this.flag) { + this.flag.hidden = true; + document.dispatchEvent(new CustomEvent('flag-change', { detail: this.flag })); + } + }); + } + + setFlagObj(flagObj: Flag) { + this.flag = flagObj; + this.shadowRoot!.querySelector('#color-input')!.value = flagObj.color; + this.shadowRoot!.querySelector('#text-input')!.value = flagObj.text; + this.shadowRoot!.querySelector('#flag-time')!.innerHTML = ns2s(flagObj.time); + } + + initHtml(): string { + return ` + +
+
Annotation at
+ + Change color: + +
+ `; + } +} diff --git a/ide/src/trace/component/trace/timer-shaft/TimeRuler.ts b/ide/src/trace/component/trace/timer-shaft/TimeRuler.ts new file mode 100644 index 0000000000000000000000000000000000000000..172ad525549f97f3272a8be871fecf6b733db90d --- /dev/null +++ b/ide/src/trace/component/trace/timer-shaft/TimeRuler.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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 { Graph } from './Graph.js'; +import { Rect } from './Rect.js'; +import { ns2s, TimerShaftElement } from '../TimerShaftElement.js'; + +export class TimeRuler extends Graph { + totalNS: number; + private stepSmall: number; + private step: number; + private stepNS: number; + + constructor(timerShaftEL: TimerShaftElement, frame: Rect, totalNS: number = 10_000_000_000) { + super(timerShaftEL.canvas, timerShaftEL.ctx!, frame); + this.totalNS = totalNS; + this.step = this.frame.width / 10; + this.stepSmall = this.frame.width / 100; + this.stepNS = this.totalNS / 10; + } + + draw() { + this.step = this.frame.width / 10; + this.stepSmall = this.frame.width / 100; + this.stepNS = this.totalNS / 10; + this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height); + this.c.beginPath(); + this.c.strokeStyle = '#999'; + this.c.lineWidth = 1; + for (let i = 0; i <= 10; i++) { + let x = Math.floor(i * this.step) + this.frame.x; + this.c.moveTo(x, 0); + this.c.lineTo(x, this.frame.height); + if (i == 10) break; + for (let j = 1; j < 10; j++) { + this.c.moveTo(x + Math.floor(j * this.stepSmall), 0); + this.c.lineTo(x + Math.floor(j * this.stepSmall), this.frame.height / 4); + } + this.c.fillStyle = '#999'; + this.c.fillText(`${ns2s(i * this.stepNS)}`, x + 5, this.frame.height - 1); + } + this.c.stroke(); + this.c.closePath(); + } +} diff --git a/ide/src/trace/database/ConfigWorker.ts b/ide/src/trace/database/ConfigWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..d52488aac99e620d406b23ba1cfb0576e34d19a4 --- /dev/null +++ b/ide/src/trace/database/ConfigWorker.ts @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022 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. + */ + +const mallocSize = 1024 * 1024; + +let Module_T: any = null; + +function initConfigWASM(wasmFunctionName: string) { + return new Promise((resolve, reject) => { + function callModelFun(functionName: string) { + let func = eval(functionName); + Module_T = new func({ + locateFile: (s: any) => { + return s; + }, + print: (line: any) => {}, + printErr: (line: any) => {}, + onRuntimeInitialized: () => { + resolve('ok'); + }, + onAbort: () => {}, + }); + } + callModelFun(wasmFunctionName); + }); +} + +self.onmessage = async (e: MessageEvent) => { + if (e.data.action === 'open') { + let jsFile = e.data.wasmJsName; + importScripts(jsFile); + await initConfigWASM(e.data.WasmName); + let dataCallBack = (heapPtr: number, size: number, isEnd: number, isConfig: number) => { + if (isConfig == 1) { + let jsonOut: Uint8Array = Module_T.HEAPU8.slice(heapPtr, heapPtr + size); + let decoder = new TextDecoder(); + let result = decoder.decode(jsonOut); + let json = JSON.parse(result); + self.postMessage({ + results: json, + }); + } + }; + let fn = Module_T.addFunction(dataCallBack, 'viiii'); + Module_T._Init(fn, mallocSize); + Module_T._TraceStreamer_In_JsonConfig(); + } +}; diff --git a/ide/src/trace/database/Procedure.ts b/ide/src/trace/database/Procedure.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f222287d58c80f8db74a639225e82c0a5d0a140 --- /dev/null +++ b/ide/src/trace/database/Procedure.ts @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2022 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 { query } from './SqlLite.js'; + +class ProcedureThread extends Worker { + busy: boolean = false; + isCancelled: boolean = false; + id: number = -1; + taskMap: any = {}; + name: string | undefined; + + uuid(): string { + // @ts-ignore + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => + (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) + ); + } + + queryFunc(type: string, args: any, transfer: any, handler: Function) { + this.busy = true; + let id = this.uuid(); + this.taskMap[id] = handler; + let pam = { + id: id, + type: type, + params: args, + }; + if (transfer) { + try { + if (Array.isArray(transfer)) { + if (transfer.length > 0) { + this.postMessage(pam, [...transfer]); + } else { + this.postMessage(pam); + } + } else { + this.postMessage(pam, [transfer]); + } + } catch (e: any) {} + } else { + this.postMessage(pam); + } + } + + cancel() { + this.isCancelled = true; + this.terminate(); + } +} + +class ProcedurePool { + static cpuCount = Math.floor((window.navigator.hardwareConcurrency || 4) / 2); + maxThreadNumber: number = 1; + works: Array = []; + timelineChange: ((a: any) => void) | undefined | null = null; + cpusLen = ProcedurePool.build('cpu', 0); + freqLen = ProcedurePool.build('freq', 0); + processLen = ProcedurePool.build('process', 0); + logicDataLen = ProcedurePool.build('logic', 2); + names = [...this.cpusLen, ...this.processLen, ...this.freqLen]; + logicDataHandles = [...this.logicDataLen]; + + onComplete: Function | undefined; //任务完成回调 + + constructor(threadBuild: (() => ProcedureThread) | undefined = undefined) { + this.init(threadBuild); + } + + static build(name: string, len: number) { + return [...Array(len).keys()].map((it) => `${name}${it}`); + } + + init(threadBuild: (() => ProcedureThread) | undefined = undefined) { + this.maxThreadNumber = this.names.length; + for (let i = 0; i < this.maxThreadNumber; i++) { + this.newThread(); + } + for (let j = 0; j < this.logicDataHandles.length; j++) { + this.logicDataThread(); + } + } + + newThread() { + let thread: ProcedureThread = new ProcedureThread('trace/database/ui-worker/ProcedureWorker.js', { + type: 'module', + }); + thread.name = this.names[this.works.length]; + thread.onmessage = (event: MessageEvent) => { + thread.busy = false; + if ((event.data.type as string) == 'timeline-range-changed') { + this.timelineChange && this.timelineChange(event.data.results); + thread.busy = false; + return; + } + if (Reflect.has(thread.taskMap, event.data.id)) { + if (event.data) { + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun(event.data.results, event.data.hover); + } + Reflect.deleteProperty(thread.taskMap, event.data.id); + } + } + if (this.isIdle() && this.onComplete) { + this.onComplete(); + } + }; + thread.onmessageerror = (e) => {}; + thread.onerror = (e) => {}; + thread.id = this.works.length; + thread.busy = false; + this.works?.push(thread); + return thread; + } + + logicDataThread() { + let thread: ProcedureThread = new ProcedureThread('trace/database/logic-worker/ProcedureLogicWorker.js', { + type: 'module', + }); + thread.name = this.logicDataHandles[this.works.length - this.names.length]; + thread.onmessage = (event: MessageEvent) => { + thread.busy = false; + if (event.data.isQuery) { + query(event.data.type, event.data.sql, event.data.args, 'exec-buf').then((res: any) => { + thread.postMessage({ + type: event.data.type, + params: { + list: res, + }, + id: event.data.id, + }); + }); + return; + } + if (event.data.isSending) { + if (Reflect.has(thread.taskMap, event.data.id)) { + if (event.data) { + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun(event.data.results, event.data.hover); + } + return; + } + } + } + if (Reflect.has(thread.taskMap, event.data.id)) { + if (event.data) { + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun(event.data.results, event.data.hover); + } + Reflect.deleteProperty(thread.taskMap, event.data.id); + } + } + if (this.isIdle() && this.onComplete) { + this.onComplete(); + } + }; + thread.onmessageerror = (e) => {}; + thread.onerror = (e) => {}; + thread.id = this.works.length; + thread.busy = false; + this.works?.push(thread); + return thread; + } + + close = () => { + for (let i = 0; i < this.works.length; i++) { + let thread = this.works[i]; + thread.terminate(); + } + this.works.length = 0; + }; + + clearCache = () => { + for (let i = 0; i < this.works.length; i++) { + let thread = this.works[i]; + thread.queryFunc('clear', {}, undefined, () => {}); + } + }; + + submitWithName(name: string, type: string, args: any, transfer: any, handler: Function): ProcedureThread | undefined { + let noBusyThreads = this.works.filter((it) => it.name === name); + let thread: ProcedureThread | undefined; + if (noBusyThreads.length > 0) { + //取第一个空闲的线程进行任务 + thread = noBusyThreads[0]; + thread!.queryFunc(type, args, transfer, handler); + } + return thread; + } + + submitWithNamePromise(name: string, type: string, args: any, transfer: any): Promise { + return new Promise((resolve, reject) => { + let noBusyThreads = this.works.filter((it) => it.name === name); + let thread: ProcedureThread | undefined; + if (noBusyThreads.length > 0) { + //取第一个空闲的线程进行任务 + thread = noBusyThreads[0]; + thread!.queryFunc(type, args, transfer, (res: any, hover: any) => { + resolve({ + res: res, + hover: hover, + }); + }); + } + }); + } + + isIdle() { + return this.works.every((it) => !it.busy); + } +} + +export const procedurePool = new ProcedurePool(); diff --git a/ide/src/trace/database/SqlLite.ts b/ide/src/trace/database/SqlLite.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7af023dd260112a58569e4c37e2ddeca9142c64 --- /dev/null +++ b/ide/src/trace/database/SqlLite.ts @@ -0,0 +1,4027 @@ +/* + * Copyright (C) 2022 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 './sql-wasm.js'; + +import { Counter, Fps, SelectionData } from '../bean/BoxSelection.js'; +import { WakeUpTimeBean } from '../bean/WakeUpTimeBean.js'; +import { WakeupBean } from '../bean/WakeupBean.js'; +import { BinderArgBean } from '../bean/BinderArgBean.js'; +import { SPT, SPTChild } from '../bean/StateProcessThread.js'; +import { CpuUsage, Freq } from '../bean/CpuUsage.js'; + +import { + NativeEvent, + NativeEventHeap, + NativeHookMalloc, + NativeHookProcess, + NativeHookSampleQueryInfo, + NativeHookStatistics, +} from '../bean/NativeHook.js'; +import { + LiveProcess, + ProcessHistory, + SystemCpuSummary, + SystemDiskIOSummary, + SystemNetworkSummary, +} from '../bean/AbilityMonitor.js'; + +import { + PerfCall, + PerfCallChain, + PerfCmdLine, + PerfFile, + PerfSample, + PerfStack, + PerfThread, +} from '../bean/PerfProfile.js'; +import { SearchFuncBean } from '../bean/SearchFuncBean.js'; +import { CounterSummary, SdkSliceSummary } from '../bean/SdkSummary.js'; +import { Smaps } from '../bean/SmapsStruct.js'; +import { CpuFreqRowLimit } from '../component/chart/SpFreqChart.js'; +import { CpuFreqLimitsStruct } from './ui-worker/ProcedureWorkerCpuFreqLimits.js'; +import { CpuStruct } from './ui-worker/ProcedureWorkerCPU.js'; +import { CpuFreqStruct } from './ui-worker/ProcedureWorkerFreq.js'; +import { ThreadStruct } from './ui-worker/ProcedureWorkerThread.js'; +import { FuncStruct } from './ui-worker/ProcedureWorkerFunc.js'; +import { ProcessMemStruct } from './ui-worker/ProcedureWorkerMem.js'; +import { HeapTreeDataBean } from './logic-worker/ProcedureLogicWorkerNativeNemory.js'; +import { FpsStruct } from './ui-worker/ProcedureWorkerFPS.js'; +import { CpuAbilityMonitorStruct } from './ui-worker/ProcedureWorkerCpuAbility.js'; +import { MemoryAbilityMonitorStruct } from './ui-worker/ProcedureWorkerMemoryAbility.js'; +import { DiskAbilityMonitorStruct } from './ui-worker/ProcedureWorkerDiskIoAbility.js'; +import { NetworkAbilityMonitorStruct } from './ui-worker/ProcedureWorkerNetworkAbility.js'; +import { EnergyAnomalyStruct } from './ui-worker/ProcedureWorkerEnergyAnomaly.js'; +import { EnergyStateStruct } from './ui-worker/ProcedureWorkerEnergyState.js'; +import { CounterStruct } from './ui-worker/ProduceWorkerSdkCounter.js'; +import { SdkSliceStruct } from './ui-worker/ProduceWorkerSdkSlice.js'; +import { SystemDetailsEnergy } from '../bean/EnergyStruct.js'; +import { ClockStruct } from './ui-worker/ProcedureWorkerClock.js'; +import { IrqStruct } from './ui-worker/ProcedureWorkerIrq.js'; + +class DataWorkerThread extends Worker { + taskMap: any = {}; + uuid(): string { + // @ts-ignore + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: any) => + (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) + ); + } + //发送方法名 参数 回调 + queryFunc(action: string, args: any, handler: Function) { + let id = this.uuid(); + this.taskMap[id] = handler; + let msg = { + id: id, + action: action, + args: args, + }; + this.postMessage(msg); + } +} + +class DbThread extends Worker { + busy: boolean = false; + isCancelled: boolean = false; + id: number = -1; + taskMap: any = {}; + cacheArray: Array = []; + + uuid(): string { + // @ts-ignore + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: any) => + (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) + ); + } + + queryFunc(name: string, sql: string, args: any, handler: Function, action: string | null) { + this.busy = true; + let id = this.uuid(); + this.taskMap[id] = handler; + let msg = { + id: id, + name: name, + action: action || 'exec', + sql: sql, + params: args, + }; + this.postMessage(msg); + } + + dbOpen = async ( + sdkWasmConfig?: string + ): Promise<{ + status: boolean; + msg: string; + buffer: ArrayBuffer; + sdkConfigMap: any; + }> => { + return new Promise((resolve, reject) => { + let id = this.uuid(); + this.taskMap[id] = (res: any) => { + if (res.init) { + resolve({ + status: res.init, + msg: res.msg, + sdkConfigMap: res.configSqlMap, + buffer: res.buffer, + }); + } else { + resolve({ status: res.init, msg: res.msg }); + } + }; + this.postMessage( + { + id: id, + action: 'open', + wasmConfig: sdkWasmConfig, + buffer: DbPool.sharedBuffer! /*Optional. An ArrayBuffer representing an SQLite Database file*/, + }, + [DbPool.sharedBuffer!] + ); + }); + }; +} + +export class DbPool { + static sharedBuffer: ArrayBuffer | null = null; + maxThreadNumber: number = 0; + works: Array = []; + progress: Function | undefined | null; + num = Math.floor(Math.random() * 10 + 1) + 20; + cutDownTimer: any | undefined; + dataWorker: DataWorkerThread | undefined | null; + init = async (type: string, threadBuild: (() => DbThread) | undefined = undefined) => { + // wasm | server | sqlite + await this.close(); + const { port1, port2 } = new MessageChannel(); + if (type === 'wasm') { + this.maxThreadNumber = 1; + } else if (type === 'server') { + this.maxThreadNumber = 1; + } else if (type === 'sqlite') { + this.maxThreadNumber = 1; + } else if (type === 'duck') { + this.maxThreadNumber = 1; + } + for (let i = 0; i < this.maxThreadNumber; i++) { + let thread: DbThread; + if (threadBuild) { + thread = threadBuild(); + } else { + if (type === 'wasm') { + thread = new DbThread('trace/database/TraceWorker.js'); + } else if (type === 'server') { + thread = new DbThread('trace/database/SqlLiteWorker.js'); + } else if (type === 'sqlite') { + thread = new DbThread('trace/database/SqlLiteWorker.js'); + } + } + thread!.onmessage = (event: MessageEvent) => { + thread.busy = false; + if (Reflect.has(thread.taskMap, event.data.id)) { + if (event.data.results) { + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun(event.data.results); + } + Reflect.deleteProperty(thread.taskMap, event.data.id); + } else if (Reflect.has(event.data, 'ready')) { + this.progress!('database opened', this.num + event.data.index); + this.progressTimer(this.num + event.data.index, this.progress!); + } else if (Reflect.has(event.data, 'init')) { + if (this.cutDownTimer != undefined) { + clearInterval(this.cutDownTimer); + } + this.progress!('database ready', 40); + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun(event.data); + } + Reflect.deleteProperty(thread.taskMap, event.data.id); + } else { + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun([]); + } + Reflect.deleteProperty(thread.taskMap, event.data.id); + } + } + }; + thread!.onmessageerror = (e) => {}; + thread!.onerror = (e) => {}; + thread!.id = i; + thread!.busy = false; + this.works?.push(thread!); + } + }; + + initServer = async (url: string, progress: Function) => { + this.progress = progress; + progress('database loaded', 15); + let buf = await fetch(url).then((res) => res.arrayBuffer()); + DbPool.sharedBuffer = buf; + progress('open database', 20); + for (let i = 0; i < this.works.length; i++) { + let thread = this.works[i]; + let { status, msg } = await thread.dbOpen(); + if (!status) { + return { status, msg }; + } + } + return { status: true, msg: 'ok' }; + }; + initSqlite = async (buf: ArrayBuffer, sdkWasmConfig: string, progress: Function) => { + this.progress = progress; + progress('database loaded', 15); + DbPool.sharedBuffer = buf; + progress('parse database', 20); + let configMap; + for (let i = 0; i < this.works.length; i++) { + let thread = this.works[i]; + let { status, msg, buffer, sdkConfigMap } = await thread.dbOpen(sdkWasmConfig); + if (!status) { + return { status, msg }; + } else { + configMap = sdkConfigMap; + DbPool.sharedBuffer = buffer; + } + } + return { status: true, msg: 'ok', sdkConfigMap: configMap }; + }; + + close = async () => { + clearInterval(this.cutDownTimer); + for (let i = 0; i < this.works.length; i++) { + let thread = this.works[i]; + thread.terminate(); + } + this.works.length = 0; + }; + + submit(name: string, sql: string, args: any, handler: Function, action: string | null) { + let noBusyThreads = this.works.filter((it) => !it.busy); + let thread: DbThread; + if (noBusyThreads.length > 0) { + //取第一个空闲的线程进行任务 + thread = noBusyThreads[0]; + thread.queryFunc(name, sql, args, handler, action); + } else { + // 随机插入一个线程中 + thread = this.works[Math.floor(Math.random() * this.works.length)]; + thread.queryFunc(name, sql, args, handler, action); + } + } + + //new method replace submit() method + submitTask(action: string, args: any, handler: Function) { + this.dataWorker?.queryFunc(action, args, handler); + } + + progressTimer(num: number, progress: Function) { + let currentNum = num; + clearInterval(this.cutDownTimer); + this.cutDownTimer = setInterval(() => { + currentNum += Math.floor(Math.random() * 3); + if (currentNum >= 50) { + progress('database opened', 40); + clearInterval(this.cutDownTimer); + } else { + progress('database opened', currentNum); + } + }, Math.floor(Math.random() * 2500 + 1000)); + } +} + +export const threadPool = new DbPool(); + +export function query( + name: string, + sql: string, + args: any = null, + action: string | null = null +): Promise> { + return new Promise>((resolve, reject) => { + threadPool.submit( + name, + sql, + args, + (res: any) => { + resolve(res); + }, + action + ); + }); +} + +export const queryEventCountMap = (): Promise< + Array<{ + eventName: string; + count: number; + }> +> => query('queryEventCountMap', `select event_name as eventName,count from stat where stat_type = 'received';`); + +export const queryProcess = (): Promise< + Array<{ + pid: number | null; + processName: string | null; + }> +> => + query( + 'queryProcess', + ` + SELECT + pid, processName + FROM + temp_query_process where pid != 0` + ); + +export const queryProcessByTable = (): Promise< + Array<{ + pid: number | null; + processName: string | null; + }> +> => + query( + 'queryProcessByTable', + ` + SELECT + pid, name as processName + FROM + process where pid != 0` + ); + +export const queryProcessAsyncFunc = (_funName?: string): Promise> => + query( + 'queryProcessAsyncFunc', + ` +select tid, + P.pid, + A.name as threadName, + is_main_thread, + c.callid as track_id, + c.ts-D.start_ts as startTs, + c.dur, + c.name as funName, + c.parent_id, + c.id, + c.cookie, + c.depth, + c.argsetid +from thread A,trace_range D +left join callstack C on A.id = C.callid +left join process P on P.id = A.ipid +where startTs not null and cookie not null ${_funName ? 'funName=$funName' : ''};`, + { + funName: _funName, + } + ); + +export const queryTotalTime = (): Promise> => + query( + 'queryTotalTime', + ` + select + start_ts as recordStartNS,end_ts as recordEndNS,end_ts-start_ts as total + from + trace_range;` + ); + +export const getAsyncEvents = (): Promise> => + query( + 'getAsyncEvents', + ` + select + *, + p.pid as pid, + c.ts - t.start_ts as "startTime" + from + callstack c,trace_range t + left join + process p + on + c.callid = p.id + where + cookie is not null;` + ); + +export const getCpuUtilizationRate = ( + startNS: number, + endNS: number +): Promise< + Array<{ + cpu: number; + ro: number; + rate: number; + }> +> => + query( + 'getCpuUtilizationRate', + ` + with cpu as ( + select + cpu, + ts, + dur, + (case when ro < 99 then ro else 99 end) as ro , + (case when ro < 99 then stime+ro*cell else stime + 99 * cell end) as st, + (case when ro < 99 then stime + (ro+1)*cell else etime end) as et + from ( + select + cpu, + ts, + A.dur, + ((ts+A.dur)-D.start_ts)/((D.end_ts-D.start_ts)/100) as ro, + D.start_ts as stime, + D.end_ts etime, + (D.end_ts-D.start_ts)/100 as cell + from + sched_slice A + left join + trace_range D + left join + thread B on A.itid = B.id + where + tid != 0 + and (A.ts) + between D.start_ts and D.end_ts)) + select cpu,ro, + sum(case + when ts <= st and ts + dur <= et then (ts + dur - st) + when ts <= st and ts + dur > et then et-st + when ts > st and ts + dur <= et then dur + when ts > st and ts + dur > et then et - ts end)/cast(et-st as float) as rate + from cpu + group by cpu,ro;`, + {} + ); + +export const getFps = () => + query( + 'getFps', + ` + select + distinct(ts-tb.start_ts) as startNS, fps + from + hidump c ,trace_range tb + where + startNS >= 0 + --order by startNS; + `, + {} + ); + +export const getFunDataByTid = (tid: number): Promise> => + query( + 'getFunDataByTid', + ` + select + --tid, + --A.name as threadName, + c.ts-D.start_ts as startTs, + c.dur, + c.name as funName, + c.argsetid, + c.depth +from thread A,trace_range D +left join callstack C on A.id = C.callid +where startTs not null and c.cookie is null and tid = $tid`, + { $tid: tid } + ); + +export const getMaxDepthByTid = (): Promise> => + query( + 'getMaxDepthByTid', + ` + select +tid, + MAX(c.depth + 1) as maxDepth +from thread A +left join callstack C on A.id = C.callid +where c.ts not null and c.cookie is null group by tid`, + {} + ); + +export const getStatesProcessThreadDataByRange = (leftNs: number, rightNs: number): Promise> => + query( + 'getStatesProcessThreadDataByRange', + ` + select + IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur, + (B.ts - TR.start_ts + B.dur) as end_ts, + (B.ts - TR.start_ts) as start_ts, + B.cpu + from + thread_state as B + left join thread as A on B.itid = A.id + left join process as IP on A.ipid = IP.id + left join trace_range as TR + where B.dur > 0 + and IP.pid not null + and (B.ts - TR.start_ts) >= $leftNs + and (B.ts - TR.start_ts + B.dur) <= $rightNs +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const getTabBoxChildData = ( + leftNs: number, + rightNs: number, + state: string | undefined, + processId: number | undefined, + threadId: number | undefined +): Promise> => + query( + 'getTabBoxChildData', + ` + select + IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur as duration, + B.ts - TR.start_ts as startNs, + B.cpu, + C.priority + from + thread_state AS B + left join + thread as A + on + B.itid = A.id + left join + process AS IP + on + A.ipid = IP.id + left join + trace_range AS TR + left join + sched_slice as C + on + B.itid = C.itid + and + C.ts = B.ts + where + B.dur > 0 + and + IP.pid not null + and + not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + ${state != undefined && state != '' ? 'and B.state = $state' : ''} + ${processId != undefined && processId != -1 ? 'and IP.pid = $processID' : ''} + ${threadId != undefined && threadId != -1 ? 'and A.tid = $threadID' : ''} + `, + { + $leftNS: leftNs, + $rightNS: rightNs, + $state: state, + $processID: processId, + $threadID: threadId, + } + ); + +export const getTabCpuUsage = (cpus: Array, leftNs: number, rightNs: number): Promise> => + query( + 'getTabCpuUsage', + ` + select + cpu, + sum(case + when (A.ts - B.start_ts) < $leftNS + then (A.ts - B.start_ts + A.dur - $leftNS) + when (A.ts - B.start_ts) >= $leftNS + and (A.ts - B.start_ts + A.dur) <= $rightNS + then A.dur + when (A.ts - B.start_ts + A.dur) > $rightNS + then ($rightNS - (A.ts - B.start_ts)) end) / cast($rightNS - $leftNS as float) as usage + from + thread_state A, + trace_range B + where + (A.ts - B.start_ts) > 0 and A.dur > 0 + and + cpu in (${cpus.join(',')}) + and + (A.ts - B.start_ts + A.dur) > $leftNS + and + (A.ts - B.start_ts) < $rightNS + group by + cpu`, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabCpuFreq = (cpus: Array, leftNs: number, rightNs: number): Promise> => + query( + 'getTabCpuFreq', + ` + select + cpu, + value, + (ts - tb.start_ts) as startNs + from + measure c, + trace_range tb + inner join + cpu_measure_filter t + on + c.filter_id = t.id + where + (name = 'cpufreq' or name='cpu_frequency') + and + cpu in (${cpus.join(',')}) + and + startNs > 0 + and + startNs < $rightNS + --order by startNs + `, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabFps = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabFps', + ` + select + distinct(ts-tb.start_ts) as startNS, + fps + from + hidump c, + trace_range tb + where + startNS <= $rightNS + and + startNS >= 0 + --order by startNS; + `, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabCounters = (processFilterIds: Array, virtualFilterIds: Array, startTime: number) => + query( + 'getTabCounters', + ` + select + t1.filter_id as trackId, + t2.name, + value, + t1.ts - t3.start_ts as startTime + from + process_measure t1 + left join + process_measure_filter t2 + on + t1.filter_id = t2.id + left join + trace_range t3 + where + filter_id in (${processFilterIds.join(',')}) + and + startTime <= $startTime +union + select + t1.filter_id as trackId, + t2.name, + value, + t1.ts - t3.start_ts as startTime + from + sys_mem_measure t1 + left join + sys_event_filter t2 + on + t1.filter_id = t2.id + left join + trace_range t3 + where + filter_id in (${virtualFilterIds.join(',')}) + and + startTime <= $startTime + `, + { $startTime: startTime } + ); + +export const getTabVirtualCounters = (virtualFilterIds: Array, startTime: number) => + query( + 'getTabVirtualCounters', + ` + select + t1.filter_id as trackId, + t2.name, + value, + t1.ts - t3.start_ts as startTime + from + sys_mem_measure t1 + left join + sys_event_filter t2 + on + t1.filter_id = t2.id + left join + trace_range t3 + where + filter_id in (${virtualFilterIds.join(',')}) + and + startTime <= $startTime + `, + { $startTime: startTime } + ); + +export const getTabCpuByProcess = (cpus: Array, leftNS: number, rightNS: number) => + query( + 'getTabCpuByProcess', + ` + select + B.pid as pid, + sum(B.dur) as wallDuration, + avg(B.dur) as avgDuration, + count(B.tid) as occurrences + from + thread_state AS B + left join + trace_range AS TR + where + B.cpu in (${cpus.join(',')}) + and + not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS )) + group by + B.pid + order by + wallDuration desc;`, + { $rightNS: rightNS, $leftNS: leftNS } + ); + +export const getTabCpuByThread = (cpus: Array, leftNS: number, rightNS: number) => + query( + 'getTabCpuByThread', + ` + select + B.pid as pid, + B.tid as tid, + B.cpu, + sum( min(${rightNS},(B.ts - TR.start_ts + B.dur)) - max(${leftNS},B.ts - TR.start_ts)) wallDuration, + count(B.tid) as occurrences + from + thread_state AS B + left join + trace_range AS TR + where + B.cpu in (${cpus.join(',')}) + and + not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + group by + B.cpu, + B.pid, + B.tid + order by + wallDuration desc;`, + { $rightNS: rightNS, $leftNS: leftNS } + ); + +export const getTabSlices = (funTids: Array, leftNS: number, rightNS: number): Promise> => + query( + 'getTabSlices', + ` + select + c.name as name, + sum(c.dur) as wallDuration, + avg(c.dur) as avgDuration, + count(c.name) as occurrences + from + thread A, trace_range D + left join + callstack C + on + A.id = C.callid + where + C.ts not null + and + c.dur >= 0 + and + A.tid in (${funTids.join(',')}) + and + c.name != 'binder transaction async' + and + c.name != 'binder async rcv' + and + c.cookie is null + and + not ((C.ts - D.start_ts + C.dur < $leftNS) or (C.ts - D.start_ts > $rightNS)) + group by + c.name + order by + wallDuration desc;`, + { $leftNS: leftNS, $rightNS: rightNS } + ); + +export const getTabSlicesAsyncFunc = ( + asyncNames: Array, + asyncPid: Array, + leftNS: number, + rightNS: number +): Promise> => + query( + 'getTabSlicesAsyncFunc', + ` + select + c.name as name, + sum(c.dur) as wallDuration, + avg(c.dur) as avgDuration, + count(c.name) as occurrences + from + thread A, trace_range D + left join + callstack C + on + A.id = C.callid + left join process P on P.id = A.ipid + where + C.ts not null + and + c.dur >= -1 + and + c.cookie not null + and + P.pid in (${asyncPid.join(',')}) + and + c.name in (${asyncNames.map((it) => "'" + it + "'").join(',')}) + and + not ((C.ts - D.start_ts + C.dur < $leftNS) or (C.ts - D.start_ts > $rightNS)) + group by + c.name + order by + wallDuration desc;`, + { $leftNS: leftNS, $rightNS: rightNS } + ); + +export const getTabThreadStates = (tIds: Array, leftNS: number, rightNS: number): Promise> => + query( + 'getTabThreadStates', + ` + select + B.pid, + B.tid, + B.state, + sum(B.dur) as wallDuration, + avg(ifnull(B.dur,0)) as avgDuration, + count(B.tid) as occurrences + from + thread_state AS B + left join + trace_range AS TR + where + B.tid in (${tIds.join(',')}) + and + not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + group by + B.pid, B.tid, B.state + order by + wallDuration desc;`, + { $leftNS: leftNS, $rightNS: rightNS } + ); + +export const getTabThreadStatesCpu = (tIds: Array, leftNS: number, rightNS: number): Promise> => { + let sql = ` +select + B.pid, + B.tid, + B.cpu, + sum( min(${rightNS},(B.ts - TR.start_ts + B.dur)) - max(${leftNS},B.ts - TR.start_ts)) wallDuration +from thread_state as B +left join trace_range as TR +where cpu notnull + and B.tid in (${tIds.join(',')}) + and not ((B.ts - TR.start_ts + ifnull(B.dur,0) < ${leftNS}) or (B.ts - TR.start_ts > ${rightNS})) +group by B.tid, B.pid, B.cpu;`; + return query('getTabThreadStatesCpu', sql, { + $leftNS: leftNS, + $rightNS: rightNS, + }); +}; + +export const queryBinderArgsByArgset = (argset: number): Promise> => + query( + 'queryBinderArgsByArgset', + ` + select + * + from + args_view + where + argset = $argset;`, + { $argset: argset } + ); + +export const queryCpuData = (cpu: number, startNS: number, endNS: number): Promise> => + query( + 'queryCpuData', + ` + SELECT + B.pid as processId, + B.cpu, + B.tid, + B.itid as id, + B.dur, + B.ts - TR.start_ts AS startTime, + B.arg_setid as argSetID +from thread_state AS B + left join trace_range AS TR +where B.itid is not null + and + B.cpu = $cpu + and + startTime between $startNS and $endNS;`, + { + $cpu: cpu, + $startNS: startNS, + $endNS: endNS, + } + ); + +export const queryCpuFreq = (): Promise> => + query( + 'queryCpuFreq', + ` + select + cpu,id as filterId + from + cpu_measure_filter + where + (name='cpufreq' or name='cpu_frequency') + order by cpu; + ` + ); + +export const queryCpuFreqData = (cpu: number): Promise> => + query( + 'queryCpuFreqData', + ` + select + cpu, + value, + ifnull(dur,tb.end_ts - c.ts) dur, + ts-tb.start_ts as startNS + from + measure c, + trace_range tb + inner join + cpu_measure_filter t + on + c.filter_id = t.id + where + (name = 'cpufreq' or name='cpu_frequency') + and + cpu= $cpu + --order by ts; + `, + { $cpu: cpu } + ); + +export const queryCpuMax = (): Promise> => + query( + 'queryCpuMax', + ` + select + cpu + from + sched_slice + order by + cpu + desc limit 1;` + ); + +export const queryCpuCount = (): Promise> => + query( + 'queryCpuCount', + ` + select max(cpuCount) cpuCount from +(select ifnull((max(cpu) + 1),0) cpuCount from cpu_measure_filter where name in ('cpu_frequency','cpu_idle') + union all + select ifnull((max(callid)+1),0) cpuCount from irq +) A;` + ); + +export const queryCpuSchedSlice = (): Promise> => + query( + 'queryCpuSchedSlice', + ` + select (ts - start_ts) as ts, + itid, + end_state as endState, + priority + from sched_slice,trace_range;` + ); + +export const queryCpuStateFilter = (): Promise> => + query( + 'queryCpuStateFilter', + `select cpu,id as filterId from cpu_measure_filter where name = 'cpu_idle' order by cpu;`, + {} + ); + +export const queryCpuState = (cpuFilterId: number): Promise> => + query( + 'queryCpuState', + ` + select (A.ts - B.start_ts) as startTs,ifnull(dur,B.end_ts - A.ts) dur, + value + from measure A,trace_range B + where filter_id = $filterId;`, + { $filterId: cpuFilterId } + ); + +export const queryCpuMaxFreq = (): Promise> => + query( + 'queryCpuMaxFreq', + ` + select + max(value) as maxFreq + from + measure c + inner join + cpu_measure_filter t + on + c.filter_id = t.id + where + (name = 'cpufreq' or name='cpu_frequency');` + ); + +export const queryProcessData = (pid: number, startNS: number, endNS: number): Promise> => + query( + 'queryProcessData', + ` + select ta.cpu, + dur, + ts-${(window as any).recordStartNS} as startTime +from thread_state ta +where ta.cpu is not null and pid=$pid and startTime between $startNS and $endNS;`, + { + $pid: pid, + $startNS: startNS, + $endNS: endNS, + } + ); + +export const queryProcessMem = (): Promise> => + query( + 'queryProcessMem', + ` + select + process_measure_filter.id as trackId, + process_measure_filter.name as trackName, + ipid as upid, + process.pid, + process.name as processName + from + process_measure_filter + join + process using (ipid) + order by trackName;` + ); + +export const queryProcessThreadDataCount = (): Promise> => + query( + `queryProcessThreadDataCount`, + `select pid,count(id) as count + from thread_state + where ts between ${(window as any).recordStartNS} and ${(window as any).recordEndNS} group by pid;`, + {} + ); + +export const queryProcessFuncDataCount = (): Promise> => + query( + `queryProcessFuncDataCount`, + `select + P.pid, + count(tid) as count + from callstack C + left join thread A on A.id = C.callid + left join process AS P on P.id = A.ipid + where C.ts between ${(window as any).recordStartNS} and ${(window as any).recordEndNS} + group by pid;`, + {} + ); + +export const queryProcessMemDataCount = (): Promise> => + query( + `queryProcessMemDataCount`, + `select + p.pid as pid, count(value) count + from process_measure c + left join process_measure_filter f on f.id = c.filter_id + left join process p on p.ipid = f.ipid +where f.id not NULL and value>0 + and c.ts between ${(window as any).recordStartNS} and ${(window as any).recordEndNS} +group by p.pid`, + {} + ); + +export const queryProcessMemData = (trackId: number): Promise> => + query( + 'queryProcessMemData', + ` + select + c.type, + ts, + value, + filter_id as track_id, + c.ts-tb.start_ts startTime + from + process_measure c, + trace_range tb + where + filter_id = $id;`, + { $id: trackId } + ); + +export const queryThreads = (): Promise> => + query('queryThreads', `select id,tid,(ifnull(name,'Thread') || '(' || tid || ')') name from thread where id != 0;`); + +export const queryDataDICT = (): Promise> => query('queryDataDICT', `select * from data_dict;`); +export const queryProcessContentCount = (): Promise> => + query(`queryProcessContentCount`, `select pid,switch_count,thread_count,slice_count,mem_count from process;`); +export const queryProcessThreadsByTable = (): Promise> => + query( + 'queryProcessThreadsByTable', + ` + select p.pid as pid,t.tid as tid,p.name as processName,t.name as threadName from thread t left join process p on t.ipid = p.id where t.tid != 0; + ` + ); +export const queryVirtualMemory = (): Promise> => + query('queryVirtualMemory', `select id,name from sys_event_filter where type='sys_virtual_memory_filter'`); +export const queryVirtualMemoryData = (filterId: number): Promise> => + query( + 'queryVirtualMemoryData', + `select ts-${ + (window as any).recordStartNS + } as startTime,value,filter_id as filterID from sys_mem_measure where filter_id=$filter_id`, + { $filter_id: filterId } + ); +export const queryProcessThreads = (): Promise> => + query( + 'queryProcessThreads', + ` + select + the_tracks.ipid as upid, + the_tracks.itid as utid, + total_dur as hasSched, + process.pid as pid, + thread.tid as tid, + process.name as processName, + thread.name as threadName + from ( + select ipid,itid from sched_slice group by itid + ) the_tracks + left join (select itid,sum(dur) as total_dur from thread_state where state != 'S' group by itid) using(itid) + left join thread using(itid) + left join process using(ipid) + order by total_dur desc,the_tracks.ipid,the_tracks.itid;`, + {} + ); + +export const queryThreadData = (tid: number): Promise> => + query( + 'queryThreadData', + ` + select + B.itid as id + , B.tid + , B.cpu + , B.ts - TR.start_ts AS startTime + , B.dur + , B.state + , B.pid + , B.arg_setid as argSetID +from thread_state AS B + left join trace_range AS TR +where B.tid = $tid;`, + { $tid: tid } + ); + +export const queryThreadAndProcessName = (): Promise> => + query( + 'queryThreadAndProcessName', + ` + select tid id,name,'t' type from thread +union all +select pid id,name,'p' type from process;`, + {} + ); + +export const queryThreadStateArgs = (argset: number): Promise> => + query('queryThreadStateArgs', ` select args_view.* from args_view where argset = ${argset}`, {}); + +export const queryWakeUpThread_Desc = (): Promise> => + query( + 'queryWakeUpThread_Desc', + `This is the interval from when the task became eligible to run +(e.g.because of notifying a wait queue it was a suspended on) to when it started running.` + ); + +export const queryThreadWakeUp = (itid: number, startTime: number, dur: number): Promise> => + query( + 'queryThreadWakeUp', + ` +select TA.tid,min(TA.ts - TR.start_ts) as ts,TA.pid +from + (select min(ts) as wakeTs,ref as itid from instant,trace_range + where name = 'sched_wakeup' + and wakeup_from = $itid + and ts > start_ts + $startTime + and ts < start_ts + $startTime + $dur + group by ref + ) TW +left join thread_state TA on TW.itid = TA.itid +left join trace_range TR +where TA.ts > TW.wakeTs +group by TA.tid,TA.pid; + `, + { $itid: itid, $startTime: startTime, $dur: dur } + ); + +export const queryRunnableTimeByRunning = (tid: number, startTime: number): Promise> => { + let sql = ` +select ts from thread_state,trace_range where ts + dur -start_ts = ${startTime} and state = 'R' and tid=${tid} limit 1 + `; + return query('queryRunnableTimeByRunning', sql, {}); +}; + +export const queryThreadWakeUpFrom = (itid: number, startTime: number): Promise> => { + let sql = ` +select (A.ts - B.start_ts) as ts, + A.tid, + A.pid, + A.cpu, + A.dur +from thread_state A,trace_range B +where A.state = 'Running' +and A.itid = (select wakeup_from from instant where ts = ${startTime} and ref = ${itid} limit 1) +and (A.ts - B.start_ts) < (${startTime} - B.start_ts) +order by ts desc limit 1 + `; + return query('queryThreadWakeUpFrom', sql, {}); +}; +/*-------------------------------------------------------------------------------------*/ + +export const queryHeapGroupByEvent = (type: string): Promise> => { + let sql1 = ` + select + event_type as eventType, + sum(heap_size) as sumHeapSize + from native_hook + where event_type = 'AllocEvent' or event_type = 'MmapEvent' + group by event_type + `; + let sql2 = ` + select (case when type = 0 then 'AllocEvent' else 'MmapEvent' end) eventType, + sum(apply_size) sumHeapSize + from native_hook_statistic + group by eventType; + `; + return query('queryHeapGroupByEvent', type === 'native_hook' ? sql1 : sql2, {}); +}; + +export const queryAllHeapByEvent = (): Promise> => + query( + 'queryAllHeapByEvent', + ` + select * from ( + select h.start_ts - t.start_ts as startTime, + h.heap_size as heapSize, + h.event_type as eventType +from native_hook h ,trace_range t +where h.start_ts >= t.start_ts and h.start_ts <= t.end_ts +and (h.event_type = 'AllocEvent' or h.event_type = 'MmapEvent') +union +select h.end_ts - t.start_ts as startTime, + h.heap_size as heapSize, + (case when h.event_type = 'AllocEvent' then 'FreeEvent' else 'MunmapEvent' end) as eventType +from native_hook h ,trace_range t +where h.start_ts >= t.start_ts and h.start_ts <= t.end_ts +and (h.event_type = 'AllocEvent' or h.event_type = 'MmapEvent') +and h.end_ts not null ) order by startTime; +`, + {} + ); + +export const queryHeapAllData = ( + startTs: number, + endTs: number, + ipids: Array +): Promise> => + query( + 'queryHeapAllData', + ` + select + h.start_ts - t.start_ts as startTs, + h.end_ts - t.start_ts as endTs, + h.heap_size as heapSize, + h.event_type as eventType, + h.callchain_id as eventId + from + native_hook h + inner join + trace_range t + where + event_type = 'AllocEvent' + and + ipid in (${ipids.join(',')}) + and + (h.start_ts - t.start_ts between ${startTs} and ${endTs} or h.end_ts - t.start_ts between ${startTs} and ${endTs})`, + { ipids: ipids, $startTs: startTs, $endTs: endTs } + ); + +export const queryNativeHookStatistics = (leftNs: number, rightNs: number): Promise> => + query( + 'queryNativeHookStatistics', + ` + select + event_type as eventType, + sub_type_id as subTypeId, + max(heap_size) as max, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount + from + native_hook A, + trace_range B + where + (A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} + and (event_type = 'AllocEvent' or event_type = 'MmapEvent') + group by event_type;`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const queryNativeHookStatisticsMalloc = (leftNs: number, rightNs: number): Promise> => + query( + 'queryNativeHookStatisticsMalloc', + ` + select + event_type as eventType, + heap_size as heapSize, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount + from + native_hook A, + trace_range B + where + (A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} + and + (event_type = 'AllocEvent' or event_type = 'MmapEvent') + and + sub_type_id is null + group by + event_type, + heap_size + order by heap_size desc + `, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const queryNativeHookStatisticsSubType = (leftNs: number, rightNs: number): Promise> => + query( + 'queryNativeHookStatisticsSubType', + ` + select + event_type as eventType, + sub_type_id as subTypeId, + max(heap_size) as max, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount + from + native_hook A, + trace_range B + where + (A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} + and + (event_type = 'MmapEvent') + group by + event_type,sub_type_id; + `, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const queryNativeHookEventTid = ( + leftNs: number, + rightNs: number, + types: Array +): Promise> => + query( + 'queryNativeHookEventTid', + ` + select + callchain_id as eventId, + event_type as eventType, + heap_size as heapSize, + addr, + (A.start_ts - B.start_ts) as startTs, + (A.end_ts - B.start_ts) as endTs, + tid, + sub_type_id as subTypeId, + ifnull(last_lib_id,0) as lastLibId, + t.name as threadName + from + native_hook A, + trace_range B + left join + thread t + on + A.itid = t.id + where + A.start_ts - B.start_ts + between ${leftNs} and ${rightNs} and A.event_type in (${types.join(',')})`, + { $leftNs: leftNs, $rightNs: rightNs, $types: types } + ); + +export const queryNativeHookStatisticsCount = (): Promise> => + query('queryNativeHookStatisticsCount', `select count(1) num from native_hook_statistic`, {}); + +export const queryNativeHookProcess = (table: string): Promise> => { + let sql = ` + select + distinct ${table}.ipid, + pid, + name + from + ${table} + left join + process p + on + ${table}.ipid = p.id + `; + return query('queryNativeHookProcess', sql, {}); +}; + +export const queryNativeHookSnapshotTypes = (): Promise> => + query( + 'queryNativeHookSnapshotTypes', + ` +select + event_type as eventType, + data as subType + from + native_hook left join data_dict on native_hook.sub_type_id = data_dict.id + where + (event_type = 'AllocEvent' or event_type = 'MmapEvent') + group by + event_type,data;`, + {} + ); + +export const queryAllHookData = (rightNs: number): Promise> => + query( + 'queryAllHookData', + ` + select + callchain_id as eventId, + event_type as eventType, + data as subType, + addr, + heap_size as growth, + (n.start_ts - t.start_ts) as startTs, + (n.end_ts - t.start_ts) as endTs + from + native_hook n left join data_dict on n.sub_type_id = data_dict.id, + trace_range t + where + (event_type = 'AllocEvent' or event_type = 'MmapEvent') + and + n.start_ts between t.start_ts and ${rightNs} + t.start_ts`, + { $rightNs: rightNs } + ); + +export const queryNativeHookResponseTypes = ( + leftNs: number, + rightNs: number, + types: Array +): Promise> => + query( + 'queryNativeHookResponseTypes', + ` + select last_lib_id as lastLibId,data_dict.data as value from + native_hook A ,trace_range B + left join data_dict on A.last_lib_id = data_dict.id + where + A.start_ts - B.start_ts + between ${leftNs} and ${rightNs} and A.event_type in (${types.join(',')}) + group by last_lib_id; + `, + { $leftNs: leftNs, $rightNs: rightNs, $types: types } + ); +/** + * HiPerf + */ +export const queryHiPerfEventList = (): Promise> => + query('queryHiPerfEventList', `select id,report_value from perf_report where report_type='config_name'`, {}); +export const queryHiPerfEventListData = (eventTypeId: number): Promise> => + query( + 'queryHiPerfEventListData', + ` + select s.callchain_id, + (s.timestamp_trace-t.start_ts) startNS + from perf_sample s,trace_range t + where + event_type_id=${eventTypeId} + and s.thread_id != 0 + and s.callchain_id != -1; +`, + { $eventTypeId: eventTypeId } + ); +export const queryHiPerfEventData = (eventTypeId: number, cpu: number): Promise> => + query( + 'queryHiPerfEventList', + ` + select s.callchain_id, + (s.timestamp_trace-t.start_ts) startNS + from perf_sample s,trace_range t + where + event_type_id=${eventTypeId} + and cpu_id=${cpu} + and s.thread_id != 0 + and s.callchain_id != -1; +`, + { $eventTypeId: eventTypeId, $cpu: cpu } + ); +export const queryHiPerfCpuData = (cpu: number): Promise> => + query( + 'queryHiPerfCpuData', + ` + select s.callchain_id, + (s.timestamp_trace-t.start_ts) startNS + from perf_sample s,trace_range t + where + cpu_id=${cpu} + and s.thread_id != 0 + and s.callchain_id != -1;`, + { $cpu: cpu } + ); +export const queryHiPerfCpuMergeData = (): Promise> => + query( + 'queryHiPerfCpuData', + `select s.callchain_id,(s.timestamp_trace-t.start_ts) startNS from perf_sample s,trace_range t +where s.thread_id != 0 and s.callchain_id != -1;`, + {} + ); +export const queryHiPerfCpuMergeData2 = (): Promise> => + query( + 'queryHiPerfCpuData2', + `select distinct cpu_id from perf_sample where thread_id != 0 order by cpu_id desc;`, + {} + ); + +export const queryHiPerfProcessData = (pid: number): Promise> => + query( + 'queryHiPerfProcessData', + ` +SELECT sp.callchain_id, + th.thread_name, + th.thread_id tid, + th.process_id pid, + sp.timestamp_trace - tr.start_ts startNS +from perf_sample sp, + trace_range tr + left join perf_thread th on th.thread_id = sp.thread_id +where pid = ${pid} and sp.thread_id != 0 and sp.callchain_id != -1;`, + { $pid: pid } + ); + +export const queryHiPerfThreadData = (tid: number): Promise> => + query( + 'queryHiPerfThreadData', + ` +SELECT sp.callchain_id, + th.thread_name, + th.thread_id tid, + th.process_id pid, + sp.timestamp_trace - tr.start_ts startNS +from perf_sample sp, + trace_range tr + left join perf_thread th on th.thread_id = sp.thread_id +where tid = ${tid} and sp.thread_id != 0 and sp.callchain_id != -1;`, + { $tid: tid } + ); + +export const querySelectTraceStats = (): Promise< + Array<{ + event_name: string; + stat_type: string; + count: number; + source: string; + serverity: string; + }> +> => query('querySelectTraceStats', 'select event_name,stat_type,count,source,serverity from stat'); + +export const queryCustomizeSelect = (sql: string): Promise> => query('queryCustomizeSelect', sql); + +export const queryDistributedTerm = (): Promise< + Array<{ + threadId: string; + threadName: string; + processId: string; + processName: string; + funName: string; + dur: string; + ts: string; + chainId: string; + spanId: string; + parentSpanId: string; + flag: string; + trace_name: string; + }> +> => + query( + 'queryDistributedTerm', + ` + select + group_concat(thread.id,',') as threadId, + group_concat(thread.name,',') as threadName, + group_concat(process.id,',') as processId, + group_concat(process.name,',') as processName, + group_concat(callstack.name,',') as funName, + group_concat(callstack.dur,',') as dur, + group_concat(callstack.ts,',') as ts, + cast(callstack.chainId as varchar) as chainId, + callstack.spanId as spanId, + callstack.parentSpanId as parentSpanId, + group_concat(callstack.flag,',') as flag, + (select + value + from + meta + where + name='source_name') as trace_name + from + callstack + inner join thread on callstack.callid = thread.id + inner join process on process.id = thread.ipid + where (callstack.flag='S' or callstack.flag='C') + group by callstack.chainId,callstack.spanId,callstack.parentSpanId` + ); + +export const queryTraceCpu = (): Promise< + Array<{ + tid: string; + pid: string; + cpu: string; + dur: string; + min_freq: string; + max_freq: string; + avg_frequency: string; + }> +> => + query( + 'queryTraceCpu', + `SELECT + itid AS tid, + ipid AS pid, + group_concat(cpu, ',') AS cpu, + group_concat(dur, ',') AS dur, + group_concat(min_freq, ',') AS min_freq, + group_concat(max_freq, ',') AS max_freq, + group_concat(avg_frequency, ',') AS avg_frequency + FROM + (SELECT + itid, + ipid, + cpu, + CAST (SUM(dur) AS INT) AS dur, + CAST (MIN(freq) AS INT) AS min_freq, + CAST (MAX(freq) AS INT) AS max_freq, + CAST ( (SUM(dur * freq) / SUM(dur) ) AS INT) AS avg_frequency + from + result + group by + itid, cpu + ) + GROUP BY + ipid, itid + ORDER BY + ipid + ` + ); + +export const queryTraceCpuTop = (): Promise< + Array<{ + tid: string; + pid: string; + cpu: string; + duration: string; + min_freq: string; + max_freq: string; + avg_frequency: string; + sumNum: string; + }> +> => + query( + 'queryTraceCpuTop', + `SELECT + itid AS tid, + ipid AS pid, + group_concat(cpu, ',') AS cpu, + group_concat(dur, ',') AS dur, + group_concat(min_freq, ',') AS min_freq, + group_concat(max_freq, ',') AS max_freq, + group_concat(avg_frequency, ',') AS avg_frequency, + sum(dur * avg_frequency) AS sumNum + FROM + (SELECT + itid, + ipid, + cpu, + CAST (SUM(dur) AS INT) AS dur, + CAST (MIN(freq) AS INT) AS min_freq, + CAST (MAX(freq) AS INT) AS max_freq, + CAST ( (SUM(dur * freq) / SUM(dur) ) AS INT) AS avg_frequency + from result group by itid, cpu + ) + GROUP BY + ipid, itid + ORDER BY + sumNum + DESC + LIMIT 10; + ` + ); + +export const queryTraceMemory = (): Promise< + Array<{ + maxNum: string; + minNum: string; + avgNum: string; + name: string; + processName: string; + }> +> => + query( + 'queryTraceMemory', + ` + select + max(value) as maxNum, + min(value) as minNum, + avg(value) as avgNum, + filter.name as name, + p.name as processName + from process_measure + left join process_measure_filter as filter on filter.id= filter_id + left join process as p on p.id = filter.ipid + where + filter_id > 0 + and + filter.name = 'mem.rss.anon' + group by + filter_id + order by + avgNum desc` + ); + +export const queryTraceMemoryTop = (): Promise< + Array<{ + maxNum: string; + minNum: string; + avgNum: string; + name: string; + processName: string; + }> +> => + query( + 'queryTraceMemoryTop', + ` + select + max(value) as maxNum, + min(value) as minNum, + avg(value) as avgNum, + filter.name as name, + p.name as processName + from process_measure + left join process_measure_filter as filter on filter.id= filter_id + left join process as p on p.id = filter.ipid + where + filter_id > 0 + and + filter.name = 'mem.rss.anon' + group by + filter_id + order by + avgNum desc limit 10` + ); + +export const queryTraceMemoryUnAgg = (): Promise< + Array<{ + processName: string; + name: string; + value: string; + ts: string; + }> +> => + query( + 'queryTraceMemoryUnAgg', + ` + select + p.name as processName, + group_concat(filter.name) as name, + cast(group_concat(value) as varchar) as value, + cast(group_concat(ts) as varchar) as ts + from process_measure m + left join process_measure_filter as filter on filter.id= m.filter_id + left join process as p on p.id = filter.ipid + where + filter.name = 'mem.rss.anon' + or + filter.name = 'mem.rss.file' + or + filter.name = 'mem.swap' + or + filter.name = 'oom_score_adj' + group by + p.name,filter.ipid + order by + filter.ipid` + ); + +export const queryTraceTaskName = (): Promise< + Array<{ + id: string; + pid: string; + process_name: string; + thread_name: string; + }> +> => + query( + 'queryTraceTaskName', + ` + select + P.id as id, + P.pid as pid, + P.name as process_name, + group_concat(T.name,',') as thread_name + from process as P left join thread as T where P.id = T.ipid + group by pid` + ); + +export const queryTraceMetaData = (): Promise< + Array<{ + name: string; + valueText: string; + }> +> => + query( + 'queryTraceMetaData', + ` + select + cast(name as varchar) as name, + cast(value as varchar) as valueText + from meta + UNION + select 'start_ts',cast(start_ts as varchar) from trace_range + UNION + select 'end_ts',cast(end_ts as varchar) from trace_range` + ); + +export const querySystemCalls = (): Promise< + Array<{ + frequency: string; + minDur: string; + maxDur: string; + avgDur: string; + funName: string; + }> +> => + query( + 'querySystemCalls', + ` + select + count(*) as frequency, + min(dur) as minDur, + max(dur) as maxDur, + avg(dur) as avgDur, + name as funName + from + callstack + group by name + order by + frequency desc limit 100` + ); + +export const querySystemCallsTop = (): Promise< + Array<{ + tid: string; + pid: string; + funName: string; + frequency: string; + minDur: string; + maxDur: string; + avgDur: string; + }> +> => + query( + 'querySystemCallsTop', + `SELECT + cpu.tid AS tid, + cpu.pid AS pid, + callstack.name AS funName, + count(callstack.name) AS frequency, + min(callstack.dur) AS minDur, + max(callstack.dur) AS maxDur, + round(avg(callstack.dur)) AS avgDur + FROM + callstack + INNER JOIN + (SELECT + itid AS tid, + ipid AS pid, + group_concat(cpu, ',') AS cpu, + group_concat(dur, ',') AS dur, + group_concat(min_freq, ',') AS min_freq, + group_concat(max_freq, ',') AS max_freq, + group_concat(avg_frequency, ',') AS avg_frequency, + sum(dur * avg_frequency) AS sumNum + FROM + (SELECT + itid, + ipid, + cpu, + CAST (SUM(dur) AS INT) AS dur, + CAST (MIN(freq) AS INT) AS min_freq, + CAST (MAX(freq) AS INT) AS max_freq, + CAST ( (SUM(dur * freq) / SUM(dur) ) AS INT) AS avg_frequency + FROM + result + GROUP BY + itid, cpu + ) + GROUP BY + ipid, itid + ORDER BY + sumNum + DESC + LIMIT 10 + ) AS cpu + ON + callstack.callid = cpu.tid + GROUP BY + callstack.name + ORDER BY + frequency + DESC + LIMIT 10` + ); + +export const getTabLiveProcessData = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabLiveProcessData', + `SELECT + process.id as processId, + process.name as processName, + process.ppid as responsibleProcess, + process.uud as userName, + process.usag as cpu, + process.threadN as threads, + process.pss as memory, + process.cpu_time as cpuTime, + process.disk_reads as diskReads, + process.disk_writes as diskWrite + FROM + ( + SELECT + tt.process_id AS id, + tt.process_name AS name, + tt.parent_process_id AS ppid, + tt.uid as uud, + tt.cpu_usage as usag, + tt.thread_num AS threadN, + mt.maxTT - TR.start_ts as endTs, + tt.pss_info as pss, + tt.cpu_time, + tt.disk_reads, + tt.disk_writes + FROM + live_process tt + LEFT JOIN trace_range AS TR + LEFT JOIN (select re.process_id as idd, max(re.ts) as maxTT, min(re.ts) as minTT + from live_process re GROUP BY re.process_name, re.process_id ) mt + on mt.idd = tt.process_id where endTs >= $rightNS + GROUP BY + tt.process_name, + tt.process_id + ) process ;`, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabProcessHistoryData = ( + leftNs: number, + rightNs: number, + processId: number | undefined, + threadId: number | undefined +): Promise> => + query( + 'getTabProcessHistoryData', + `SELECT + process.id as processId, + process.isD as alive, + process.startTS as firstSeen, + process.endTs as lastSeen, + process.name as processName, + process.ppid as responsibleProcess, + process.uuid as userName, + process.cpu_time as cpuTime, + 0 as pss + FROM + ( + SELECT + tt.process_id AS id, + tt.process_name AS name, + tt.parent_process_id AS ppid, + tt.uid AS uuid, + tt.cpu_time, + (mt.minTT - TR.start_ts ) AS startTS, + mt.maxTT - TR.start_ts as endTs, + (mt.maxTT - TR.start_ts - $rightNS) > 0 as isD + FROM + live_process tt + LEFT JOIN trace_range AS TR + LEFT JOIN (select re.process_id as idd, max(re.ts) as maxTT, min(re.ts) as minTT + from live_process re GROUP BY re.process_name, re.process_id ) mt + on mt.idd = tt.process_id + GROUP BY + tt.process_name, + tt.process_id + ) process;`, + { + $leftNS: leftNs, + $rightNS: rightNs, + $processID: processId, + $threadID: threadId, + } + ); + +export const getTabCpuAbilityData = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabCpuAbilityData', + `SELECT + ( n.ts - TR.start_ts ) AS startTime, + n.dur AS duration, + n.total_load AS totalLoad, + n.user_load AS userLoad, + n.system_load AS systemLoad, + n.process_num AS threads + FROM + cpu_usage AS n, + trace_range AS TR + WHERE + ( n.ts - TR.start_ts ) >= ifnull(( + SELECT + ( usage.ts - TR.start_ts ) + FROM + cpu_usage usage, + trace_range TR + WHERE + ( usage.ts - TR.start_ts ) <= $leftNS + ORDER BY + usage.ts DESC + LIMIT 1 + ),0) + AND ( n.ts - TR.start_ts ) <= $rightNS + ORDER BY + startTime ASC; + `, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabMemoryAbilityData = ( + leftNs: number, + rightNs: number +): Promise< + Array<{ + startTime: number; + value: string; + name: string; + }> +> => + query( + 'getTabMemoryAbilityData', + `SELECT + m.ts AS startTime, + GROUP_CONCAT( IFNULL( m.value, 0 ) ) AS value, + GROUP_CONCAT( f.name ) AS name + FROM + sys_mem_measure AS m + INNER JOIN sys_event_filter AS f ON m.filter_id = f.id + AND (f.name = 'sys.mem.total' + or f.name = 'sys.mem.free' + or f.name = 'sys.mem.buffers' + or f.name = 'sys.mem.cached' + or f.name = 'sys.mem.shmem' + or f.name = 'sys.mem.slab' + or f.name = 'sys.mem.swap.total' + or f.name = 'sys.mem.swap.free' + or f.name = 'sys.mem.mapped' + or f.name = 'sys.mem.vmalloc.used' + or f.name = 'sys.mem.page.tables' + or f.name = 'sys.mem.kernel.stack' + or f.name = 'sys.mem.active' + or f.name = 'sys.mem.inactive' + or f.name = 'sys.mem.unevictable' + or f.name = 'sys.mem.vmalloc.total' + or f.name = 'sys.mem.slab.unreclaimable' + or f.name = 'sys.mem.cma.total' + or f.name = 'sys.mem.cma.free' + or f.name = 'sys.mem.kernel.reclaimable' + or f.name = 'sys.mem.zram' + ) + AND m.ts >= ifnull(( + SELECT + m.ts AS startTime + FROM + sys_mem_measure AS m + INNER JOIN sys_event_filter AS f ON m.filter_id = f.id + AND m.ts <= $leftNS + AND (f.name = 'sys.mem.total' + or f.name = 'sys.mem.free' + or f.name = 'sys.mem.buffers' + or f.name = 'sys.mem.cached' + or f.name = 'sys.mem.shmem' + or f.name = 'sys.mem.slab' + or f.name = 'sys.mem.swap.total' + or f.name = 'sys.mem.swap.free' + or f.name = 'sys.mem.mapped' + or f.name = 'sys.mem.vmalloc.used' + or f.name = 'sys.mem.page.tables' + or f.name = 'sys.mem.kernel.stack' + or f.name = 'sys.mem.active' + or f.name = 'sys.mem.inactive' + or f.name = 'sys.mem.unevictable' + or f.name = 'sys.mem.vmalloc.total' + or f.name = 'sys.mem.slab.unreclaimable' + or f.name = 'sys.mem.cma.total' + or f.name = 'sys.mem.cma.free' + or f.name = 'sys.mem.kernel.reclaimable' + or f.name = 'sys.mem.zram' + ) + ORDER BY + m.ts DESC + LIMIT 1 + ),0) + AND m.ts <= $rightNS GROUP BY m.ts;`, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabNetworkAbilityData = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabNetworkAbilityData', + `SELECT + ( n.ts - TR.start_ts ) AS startTime, + n.dur AS duration, + n.rx AS dataReceived, + n.tx_speed AS dataReceivedSec, + n.tx AS dataSend, + n.rx_speed AS dataSendSec, + n.packet_in AS packetsIn, + n.packet_in_sec AS packetsInSec, + n.packet_out AS packetsOut, + n.packet_out_sec AS packetsOutSec + FROM + network AS n, + trace_range AS TR + WHERE + ( n.ts - TR.start_ts ) >= ifnull(( + SELECT + ( nn.ts - T.start_ts ) AS startTime + FROM + network nn, + trace_range T + WHERE + ( nn.ts - T.start_ts ) <= $leftNS + ORDER BY + nn.ts DESC + LIMIT 1 + ),0) + AND ( n.ts - TR.start_ts ) <= $rightNS + ORDER BY + startTime ASC`, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabDiskAbilityData = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabDiskAbilityData', + `SELECT + ( n.ts - TR.start_ts ) AS startTime, + n.dur AS duration, + n.rd AS dataRead, + n.rd_speed AS dataReadSec, + n.wr AS dataWrite, + n.wr_speed AS dataWriteSec, + n.rd_count AS readsIn, + n.rd_count_speed AS readsInSec, + n.wr_count AS writeOut, + n.wr_count_speed AS writeOutSec + FROM + diskio AS n, + trace_range AS TR + WHERE + ( n.ts - TR.start_ts ) >= ifnull(( + SELECT + ( nn.ts - T.start_ts ) AS startTime + FROM + diskio AS nn, + trace_range AS T + WHERE + ( nn.ts - T.start_ts ) <= $leftNS + ORDER BY + nn.ts DESC + LIMIT 1 + ),0) + AND ( n.ts - TR.start_ts ) <= $rightNS + ORDER BY + startTime ASC; + `, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const queryCpuAbilityData = (): Promise> => + query( + 'queryCpuAbilityData', + `select + (t.total_load) as value, + (t.ts - TR.start_ts) as startNS + from cpu_usage t, trace_range AS TR;` + ); + +export const queryCpuAbilityUserData = (): Promise> => + query( + 'queryCpuAbilityUserData', + `select + t.user_load as value, + (t.ts - TR.start_ts) as startNS + from cpu_usage t, trace_range AS TR;` + ); + +export const queryCpuAbilitySystemData = (): Promise> => + query( + 'queryCpuAbilitySystemData', + `select + t.system_load as value, + (t.ts - TR.start_ts) as startNS + from cpu_usage t, trace_range AS TR;` + ); + +export const queryMemoryUsedAbilityData = (id: string): Promise> => + query( + 'queryMemoryUsedAbilityData', + `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from sys_mem_measure t, trace_range AS TR where t.filter_id = $id;`, + { $id: id } + ); + +export const queryCachedFilesAbilityData = (id: string): Promise> => + query( + 'queryCachedFilesAbilityData', + `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from sys_mem_measure t, trace_range AS TR where t.filter_id = $id;`, + { $id: id } + ); + +export const queryCompressedAbilityData = (id: string): Promise> => + query( + 'queryCompressedAbilityData', + `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from sys_mem_measure t, trace_range AS TR where t.filter_id = $id;`, + { $id: id } + ); + +export const querySwapUsedAbilityData = (id: string): Promise> => + query( + 'querySwapUsedAbilityData', + `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from sys_mem_measure t, trace_range AS TR where t.filter_id = $id;`, + { $id: id } + ); + +export const queryBytesReadAbilityData = (): Promise> => + query( + 'queryBytesReadAbilityData', + `select + t.rd_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_range AS TR;` + ); + +export const queryBytesWrittenAbilityData = (): Promise> => + query( + 'queryBytesWrittenAbilityData', + `select + t.wr_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_range AS TR;` + ); + +export const queryReadAbilityData = (): Promise> => + query( + 'queryReadAbilityData', + `select + t.rd_count_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_range AS TR;` + ); + +export const queryWrittenAbilityData = (): Promise> => + query( + 'queryWrittenAbilityData', + `select + t.wr_count_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_range AS TR;` + ); + +export const queryBytesInAbilityData = (): Promise> => + query( + 'queryBytesInAbilityData', + `select + t.tx_speed as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_range AS TR;` + ); + +export const queryBytesOutAbilityData = (): Promise> => + query( + 'queryBytesOutAbilityData', + `select + t.rx_speed as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_range AS TR;` + ); + +export const queryPacketsInAbilityData = (): Promise> => + query( + 'queryPacketsInAbilityData', + `select + t.packet_in_sec as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_range AS TR;` + ); + +export const queryPacketsOutAbilityData = (): Promise> => + query( + 'queryPacketsOutAbilityData', + `select + t.packet_out_sec as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_range AS TR;` + ); + +export const queryNetWorkMaxData = (): Promise> => + query( + 'queryNetWorkMaxData', + `select + ifnull(max(tx_speed),0) as maxIn, + ifnull(max(rx_speed),0) as maxOut, + ifnull(max(packet_in_sec),0) as maxPacketIn, + ifnull(max(packet_in_sec),0) as maxPacketOut + from network` + ); + +export const queryMemoryMaxData = (memoryName: string): Promise> => + query( + 'queryMemoryMaxData', + `SELECT ifnull(max(m.value),0) as maxValue, + filter_id + from sys_mem_measure m + WHERE m.filter_id = + (SELECT id FROM sys_event_filter WHERE name = $memoryName) +`, + { $memoryName: memoryName } + ); + +export const queryDiskIoMaxData = (): Promise> => + query( + 'queryDiskIoMaxData', + `select + ifnull(max(rd_speed),0) as bytesRead, + ifnull(max(wr_speed),0) as bytesWrite, + ifnull(max(rd_count_speed),0) as readOps, + ifnull(max(wr_count_speed),0) as writeOps + from diskio` + ); + +export const queryAbilityExits = (): Promise> => + query( + 'queryAbilityExits', + `select + event_name + from stat s + where s.event_name in ('trace_diskio','trace_network', 'trace_cpu_usage','sys_memory') + and s.stat_type ='received' and s.count > 0` + ); + +export const queryStartTime = (): Promise> => query('queryStartTime', `SELECT start_ts FROM trace_range`); + +export const queryPerfFiles = (): Promise> => + query('queryPerfFiles', `select file_id as fileId,symbol,path from perf_files`, {}); + +export const queryPerfProcess = (): Promise> => + query( + 'queryPerfThread', + `select process_id as pid,thread_name as processName from perf_thread where process_id = thread_id`, + {} + ); + +export const queryPerfThread = (): Promise> => + query( + 'queryPerfThread', + `select a.thread_id as tid,a.thread_name as threadName,a.process_id as pid,b.thread_name as processName from perf_thread a left join (select * from perf_thread where thread_id = process_id) b on a.process_id = b.thread_id`, + {} + ); + +export const queryPerfSampleListByTimeRange = ( + leftNs: number, + rightNs: number, + cpus: Array, + processes: Array, + threads: Array +): Promise> => { + let sql = ` +select A.callchain_id as sampleId, + A.thread_id as tid, + C.thread_name as threadName, + A.thread_state as state, + C.process_id as pid, + (timestamp_trace - R.start_ts) as time, + cpu_id as core +from perf_sample A,trace_range R +left join perf_thread C on A.thread_id = C.thread_id +where time >= $leftNs and time <= $rightNs and A.thread_id != 0 + `; + if (cpus.length != 0 || processes.length != 0 || threads.length != 0) { + let arg1 = cpus.length > 0 ? `or core in (${cpus.join(',')}) ` : ''; + let arg2 = processes.length > 0 ? `or pid in (${processes.join(',')}) ` : ''; + let arg3 = threads.length > 0 ? `or tid in (${threads.join(',')})` : ''; + let arg = `${arg1}${arg2}${arg3}`.substring(3); + sql = `${sql} and (${arg})`; + } + return query('queryPerfSampleListByTimeRange', sql, { + $leftNs: leftNs, + $rightNs: rightNs, + }); +}; + +export const queryPerfSampleIdsByTimeRange = ( + leftNs: number, + rightNs: number, + cpus: Array, + processes: Array, + threads: Array +): Promise> => { + let sql = ` +select A.callchain_id as sampleId +from perf_sample A,trace_range R +left join perf_thread C on A.thread_id = C.thread_id +where (timestamp_trace - R.start_ts) >= $leftNs and (timestamp_trace - R.start_ts) <= $rightNs and A.thread_id != 0 + `; + if (cpus.length != 0 || processes.length != 0 || threads.length != 0) { + let arg1 = cpus.length > 0 ? `or A.cpu_id in (${cpus.join(',')}) ` : ''; + let arg2 = processes.length > 0 ? `or C.process_id in (${processes.join(',')}) ` : ''; + let arg3 = threads.length > 0 ? `or A.thread_id in (${threads.join(',')})` : ''; + let arg = `${arg1}${arg2}${arg3}`.substring(3); + sql = `${sql} and (${arg})`; + } + return query('queryPerfSampleIdsByTimeRange', sql, { + $leftNs: leftNs, + $rightNs: rightNs, + }); +}; + +export const queryPerfSampleCallChain = (sampleId: number): Promise> => + query( + 'queryPerfSampleCallChain', + ` + select + callchain_id as callChainId, + callchain_id as sampleId, + file_id as fileId, + symbol_id as symbolId, + vaddr_in_file as vaddrInFile, + name as symbol +from perf_callchain where callchain_id = $sampleId and symbol_id != -1 and vaddr_in_file != 0; + `, + { $sampleId: sampleId } + ); + +export const queryPerfCmdline = (): Promise> => + query( + 'queryPerfCmdline', + ` + select report_value from perf_report where report_type = 'cmdline' + `, + {} + ); + +export const queryCPuAbilityMaxData = (): Promise> => + query( + 'queryCPuAbilityMaxData', + `select ifnull(max(total_load),0) as totalLoad, + ifnull(max(user_load),0) as userLoad, + ifnull(max(system_load),0) as systemLoad + from cpu_usage` + ); + +export const querySearchFunc = (search: string): Promise> => + query( + 'querySearchFunc', + ` + select c.cookie,c.id,c.name as funName,c.ts - r.start_ts as startTime,c.dur,c.depth,t.tid,t.name as threadName + ,p.pid ,'func' as type from callstack c left join thread t on c.callid = t.id left join process p on t.ipid = p.id + left join trace_range r + where c.name like '%${search}%' and startTime > 0; + `, + { $search: search } + ); + +export const querySceneSearchFunc = (search: string, processList: Array): Promise> => + query( + 'querySearchFunc', + ` + select c.cookie,c.id,c.name as funName,c.ts - r.start_ts as startTime,c.dur,c.depth,t.tid,t.name as threadName + ,p.pid ,'func' as type from callstack c left join thread t on c.callid = t.id left join process p on t.ipid = p.id + left join trace_range r + where c.name like '%${search}%' and startTime > 0 and p.pid in (${processList.join(',')}); + `, + { $search: search } + ); + +export const queryBinderBySliceId = (id: number): Promise> => + query( + 'queryBinderBySliceId', + `select c.ts-D.start_ts as startTime, + c.dur, + t.tid,p.pid,c.depth + from callstack c,trace_range D + left join thread t on c.callid = t.id + left join process p on p.id = t.ipid +where cat = 'binder' and c.id = $id;`, + { $id: id } + ); + +export const queryBinderByArgsId = (id: number, startTime: number, isNext: boolean): Promise> => { + let sql = `select c.ts - D.start_ts as startTime, + c.dur, + t.tid,p.pid,c.depth + from callstack c,trace_range D + left join thread t on c.callid = t.id + left join process p on p.id = t.ipid +where cat = 'binder' and c.argsetid = $id`; + if (isNext) { + sql += ' and c.ts > $startTime + D.start_ts'; + } else { + sql += ' and c.ts < $startTime + D.start_ts'; + } + return query('queryBinderByArgsId', sql, { + $id: id, + $startTime: startTime, + }); +}; + +export const getTabPaneFilesystemStatisticsFather = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabPaneFilesystemStatisticsFather', + ` + select SUM(dur) as allDuration, + count(f.type) as count, + min(dur) as minDuration, + max(dur) as maxDuration, + round(avg(dur),2) as avgDuration, + p.name, + f.type, + p.pid, + sum(ifnull(size,0)) as size + from file_system_sample as f left join process as p on f.ipid=p.ipid + where f.start_ts >= $leftNs + and end_ts <= $rightNs + group by f.type; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const getTabPaneFilesystemStatisticsChild = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabPaneFilesystemStatisticsChild', + ` + select SUM(dur) as allDuration, + count(f.type) as count, + min(dur) as minDuration, + max(dur) as maxDuration, + round(avg(dur),2) as avgDuration, + p.name, + f.type, + p.pid, + sum(ifnull(size,0)) as size + from file_system_sample as f left join process as p on f.ipid=p.ipid + where f.start_ts >= $leftNs + and end_ts <= $rightNs + group by f.type, f.ipid; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const getTabPaneFilesystemStatisticsAll = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabPaneFilesystemStatisticsAll', + ` + select SUM(dur) as allDuration, + count(type) as count, + min(dur) as minDuration, + max(dur) as maxDuration, + round(avg(dur),2) as avgDuration, + type + from file_system_sample + where start_ts >= $leftNs + and end_ts <= $rightNs; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const getTabPaneFilesystemStatistics = (leftNs: number, rightNs: number, types: number[]): Promise> => + query( + 'getTabPaneFilesystemStatistics', + ` + select p.pid, + ifnull(p.name,'Process') as name, + f.type, + count(f.ipid) as count, + sum(ifnull(size,0)) as size, + sum(case when f.type = 2 then ifnull(size,0) else 0 end) as logicalReads, + sum(case when f.type = 3 then ifnull(size,0) else 0 end) as logicalWrites, + sum(case when f.type != 2 and f.type != 3 then ifnull(size,0) else 0 end) as otherFile, + sum(dur) as allDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + avg(dur) as avgDuration + from file_system_sample as f left join process as p on f.ipid=p.ipid + where end_ts >= $leftNs + and end_ts <= $rightNs + and f.type in (${types.join(',')}) + group by f.type,f.ipid + order by f.type; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const getTabPaneVirtualMemoryStatisticsData = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabPaneVirtualMemoryStatisticsData', + ` + select p.pid, + t.tid, + ifnull(p.name,'Process') as pname, + ifnull(t.name,'Thread') as tname, + f.type, + f.ipid, + f.itid, + count(f.ipid) as count, + sum(dur) as allDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + avg(dur) as avgDuration + from paged_memory_sample as f left join process as p on f.ipid=p.ipid left join thread as t on f.itid=t.itid + where f.end_ts >= $leftNs + and f.end_ts <= $rightNs + group by f.type,f.ipid,f.itid + order by f.type; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); + +export const getTabPaneIOTierStatisticsData = ( + leftNs: number, + rightNs: number, + diskIOipids: Array +): Promise> => { + let str = ''; + if (diskIOipids.length > 0) { + str = ` and i.ipid in (${diskIOipids.join(',')})`; + } + return query( + 'getTabPaneIOTierStatisticsData', + ` + select p.pid, + ifnull(p.name,'Process') as pname, + i.tier, + i.ipid, + path_id as path, + count(i.ipid) as count, + sum(latency_dur) as allDuration, + min(latency_dur) as minDuration, + max(latency_dur) as maxDuration, + avg(latency_dur) as avgDuration + from bio_latency_sample as i left join process as p on i.ipid=p.ipid + where i.start_ts+latency_dur >= $leftNs + and i.start_ts+latency_dur <= $rightNs + ${str} + group by i.tier,i.ipid,i.path_id + order by i.tier; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); +}; + +export const getTabPaneCounterSampleData = ( + leftNs: number, + rightNs: number, + cpuStateFilterIds: Array +): Promise> => { + let str = ''; + if (cpuStateFilterIds.length > 0) { + str = ` and filter_id in (${cpuStateFilterIds.join(',')})`; + } + return query( + 'getTabPaneCounterSampleData', + ` + select value, filter_id as filterId, ts, f.cpu + from measure left join cpu_measure_filter as f on f.id=filter_id + where + ts <= $rightNs${str} order by ts asc; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); +}; + +export const getTabPaneFrequencySampleData = ( + leftNs: number, + rightNs: number, + cpuFreqFilterIds: Array +): Promise> => { + let str = ''; + if (cpuFreqFilterIds.length > 0) { + str = ` and filter_id in (${cpuFreqFilterIds.join(',')})`; + } + return query( + 'getTabPaneFrequencySampleData', + ` + select value, filter_id as filterId, ts, f.cpu + from measure left join cpu_measure_filter as f on f.id=filter_id + where + ts <= $rightNs${str} order by ts asc; +`, + { $leftNs: leftNs, $rightNs: rightNs } + ); +}; + +export const hasFileSysData = (): Promise> => + query( + 'hasFileSysData', + ` + select + fsCount, + vmCount, + ioCount from + (select count(1) as fsCount from file_system_sample s,trace_range t where (s.start_ts between t.start_ts and t.end_ts) or (s.end_ts between t.start_ts and t.end_ts) ) + ,(select count(1) as vmCount from paged_memory_sample s,trace_range t where (s.start_ts between t.start_ts and t.end_ts) or (s.end_ts between t.start_ts and t.end_ts) ) + ,(select count(1) as ioCount from bio_latency_sample s,trace_range t where (s.start_ts between t.start_ts and t.end_ts) or (s.end_ts between t.start_ts and t.end_ts) ); + `, + {} + ); + +export const getFileSysChartDataByType = (type: number): Promise> => + query( + 'getFileSysChartData', + ` + select + (A.start_ts -B.start_ts) as startNS, + (A.end_ts - B.start_ts) as endNS, + dur + from file_system_sample A,trace_range B + where type = $type and startNS > 0;`, + { $type: type }, + 'exec' + ); + +export const getFileSysVirtualMemoryChartData = (): Promise> => + query( + 'getFileSysVirtualMemoryChartData', + ` + select + (A.start_ts -B.start_ts) as startNS, + (A.end_ts - B.start_ts) as endNS, + dur as dur + from paged_memory_sample A,trace_range B + where startNS > 0 + order by A.start_ts;`, + {}, + 'exec' + ); + +export const getDiskIOProcess = (): Promise> => + query( + 'getDiskIOProcess', + ` + select name,B.ipid,pid + from (select distinct ipid from bio_latency_sample A,trace_range B where A.start_ts between B.start_ts and B.end_ts) A + left join process B on A.ipid = B.ipid;`, + {} + ); + +export const getDiskIOLatencyChartDataByProcess = ( + all: boolean, + ipid: number, + typeArr: Array +): Promise> => + query( + 'getDiskIOLatencyChartDataByProcess', + ` + select + (A.start_ts -B.start_ts) as startNS, + (A.start_ts - B.start_ts + A.latency_dur) as endNS, + latency_dur as dur + from bio_latency_sample A,trace_range B + where type in (${typeArr.join(',')}) and startNS > 0 + ${all ? '' : 'and ipid = ' + ipid} + order by A.start_ts;`, + {}, + 'exec' + ); + +export const querySdkCount = (sql: string, componentId: number, args?: any): Promise> => + query('querySdkCount', sql, args, 'exec-sdk-' + componentId); + +export const querySdkCounterData = ( + sql: string, + counter_id: number, + componentId: number +): Promise> => + query('querySdkCounterData', sql, { $counter_id: counter_id }, 'exec-sdk-' + componentId); + +export const getTabSdkCounterData = ( + sqlStr: string, + startTime: number, + leftNs: number, + rightNs: number, + counters: Array, + componentId: number +): Promise> => + query( + 'getTabSdkCounterData', + sqlStr, + { + $startTime: startTime, + $leftNs: leftNs, + $rightNs: rightNs, + $counters: counters, + }, + 'exec-sdk-' + componentId + ); + +export const getTabSdkCounterLeftData = ( + sqlStr: string, + leftNs: number, + counters: Array, + componentId: number +): Promise> => + query( + 'getTabSdkCounterLeftData', + sqlStr, + { + $leftNs: leftNs, + $counters: counters, + }, + 'exec-sdk-' + componentId + ); + +export const getTabSdkSliceData = ( + sqlStr: string, + startTime: number, + leftNs: number, + rightNs: number, + slices: Array, + componentId: number +): Promise> => + query( + 'getTabSdkSliceData', + sqlStr, + { + $startTime: startTime, + $leftNs: leftNs, + $rightNs: rightNs, + $slices: slices, + }, + 'exec-sdk-' + componentId + ); + +export const querySdkSliceData = ( + sqlStr: string, + column_id: number, + startNS: number, + endNS: number, + componentId: number +): Promise> => + query( + 'querySdkSliceData', + sqlStr, + { $column_id: column_id, $startNS: startNS, $endNS: endNS }, + 'exec-sdk-' + componentId + ); + +export const queryCounterMax = (sqlStr: string, counter_id: number, componentId: number): Promise> => + query('queryCounterMax', sqlStr, { $counter_id: counter_id }, 'exec-sdk-' + componentId); + +export const queryAnomalyData = (): Promise> => + query( + 'queryAnomalyData', + `select + (S.ts - TR.start_ts) as startNS, + D.data as eventName, + D2.data as appKey, + (case when S.type==1 then group_concat(S.string_value,',') else group_concat(S.int_value,',') end) as Value + from trace_range AS TR,hisys_event_measure as S + left join data_dict as D on D.id=S.name_id + left join app_name as APP on APP.id=S.key_id + left join data_dict as D2 on D2.id=APP.app_key + where D.data in ('ANOMALY_SCREEN_OFF_ENERGY','ANOMALY_KERNEL_WAKELOCK','ANOMALY_CPU_HIGH_FREQUENCY','ANOMALY_WAKEUP') + or (D.data in ('ANOMALY_RUNNINGLOCK','ANORMALY_APP_ENERGY','ANOMALY_GNSS_ENERGY','ANOMALY_CPU_ENERGY','ANOMALY_ALARM_WAKEUP') and D2.data in ("APPNAME")) + group by S.serial,D.data` + ); + +export const querySystemLocationData = (): Promise< + Array<{ + startNs: string; + eventName: string; + type: string; + state: string; + }> +> => + query( + 'querySystemLocationData', + `SELECT + ( S.ts - TR.start_ts ) AS ts, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS Value + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + D.data = 'GNSS_STATE' AND D2.data = 'STATE' + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data;` + ); + +export const querySystemLockData = (): Promise< + Array<{ + startNs: string; + eventName: string; + type: string; + state: string; + }> +> => + query( + 'querySystemLockData', + `SELECT + ( S.ts - TR.start_ts ) AS ts, + D.data AS eventName, + D2.data AS appKey, + group_concat(( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS Value + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + ( D.data = 'POWER_RUNNINGLOCK' AND D2.data in ('TAG','MESSAGE')) + GROUP BY + S.serial;` + ); + +export const querySystemSchedulerData = (): Promise< + Array<{ + startNs: string; + eventName: string; + appKey: string; + Value: string; + }> +> => + query( + 'querySystemSchedulerData', + `SELECT + ( S.ts - TR.start_ts ) AS startNs, + D.data AS eventName, + group_concat(D2.data, ',') AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS Value + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + D.data IN ( 'WORK_REMOVE', 'WORK_STOP', 'WORK_ADD' ) AND D2.data in ('NAME','TYPE','WORKID') + GROUP BY + S.serial;` + ); + +export const querySystemDetailsData = (rightNs: number, eventName: string): Promise> => + query( + 'querySystemDetailsData', + `SELECT + ( S.ts - TR.start_ts ) AS ts, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS appValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + D.data in ($eventName) + and + D2.data in ('UID', 'TYPE', 'WORKID', 'NAME', 'INTERVAL', 'TAG', 'STATE', 'STACK', 'APPNAME', 'MESSAGE', 'PID', 'LOG_LEVEL') + and (S.ts - TR.start_ts) <= $rightNS + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data;`, + { $rightNS: rightNs, $eventName: eventName } + ); + +export const querySystemWorkData = (rightNs: number): Promise> => + query( + 'querySystemWorkData', + `SELECT + ( S.ts - TR.start_ts ) AS ts, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS appValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + D.data in ("WORK_REMOVE", "WORK_STOP", "WORK_ADD", "WORK_START") + and + D2.data in ('UID', 'TYPE', 'WORKID', 'NAME', 'INTERVAL', 'TAG', 'STATE', 'STACK', 'APPNAME', 'MESSAGE', 'PID', 'LOG_LEVEL') + and (S.ts - TR.start_ts) <= $rightNS + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data;`, + { $rightNS: rightNs } + ); + +export const queryMaxPowerValue = ( + appName: string +): Promise< + Array<{ + maxValue: number; + }> +> => + query( + 'queryMaxPowerValue', + `SELECT + max( item ) AS maxValue + FROM + ( + SELECT + sum( energy + background_energy + screen_on_energy + screen_off_energy + foreground_energy ) AS item + FROM + energy + WHERE + app_name = $appName + GROUP BY + startNs);`, + { $appName: appName } + ); + +export const queryPowerData = (): Promise< + Array<{ + startNS: number; + eventName: string; + appKey: string; + eventValue: string; + }> +> => + query( + 'queryPowerData', + `SELECT + ( S.ts - TR.start_ts ) AS startNS, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS eventValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + where + D.data in ('POWER_IDE_CPU','POWER_IDE_LOCATION','POWER_IDE_GPU','POWER_IDE_DISPLAY','POWER_IDE_CAMERA','POWER_IDE_BLUETOOTH','POWER_IDE_FLASHLIGHT','POWER_IDE_AUDIO','POWER_IDE_WIFISCAN') + and + D2.data in ('BACKGROUND_ENERGY','FOREGROUND_ENERGY','SCREEN_ON_ENERGY','SCREEN_OFF_ENERGY','ENERGY','APPNAME') + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data + ORDER BY + eventName;`, + {} + ); + +export const getTabPowerDetailsData = ( + leftNs: number, + rightNs: number +): Promise< + Array<{ + startNS: number; + eventName: string; + appKey: string; + eventValue: string; + }> +> => + query( + 'getTabPowerDetailsData', + `SELECT + ( S.ts - TR.start_ts ) AS startNS, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS eventValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + where + D.data in ('POWER_IDE_CPU','POWER_IDE_LOCATION','POWER_IDE_GPU','POWER_IDE_DISPLAY','POWER_IDE_CAMERA','POWER_IDE_BLUETOOTH','POWER_IDE_FLASHLIGHT','POWER_IDE_AUDIO','POWER_IDE_WIFISCAN') + and + D2.data in ('APPNAME') + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data + UNION + SELECT + ( S.ts - TR.start_ts ) AS startNS, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS eventValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + where + D.data in ('POWER_IDE_CPU','POWER_IDE_LOCATION','POWER_IDE_GPU','POWER_IDE_DISPLAY','POWER_IDE_CAMERA','POWER_IDE_BLUETOOTH','POWER_IDE_FLASHLIGHT','POWER_IDE_AUDIO','POWER_IDE_WIFISCAN') + and + D2.data in ('CHARGE','BACKGROUND_TIME','SCREEN_ON_TIME','SCREEN_OFF_TIME','LOAD','USAGE','DURATION','CAMERA_ID', + 'FOREGROUND_COUNT','BACKGROUND_COUNT','SCREEN_ON_COUNT','SCREEN_OFF_COUNT','COUNT','UID','FOREGROUND_DURATION', + 'FOREGROUND_ENERGY','BACKGROUND_DURATION','BACKGROUND_ENERGY','SCREEN_ON_DURATION','SCREEN_ON_ENERGY', + 'SCREEN_OFF_DURATION','SCREEN_OFF_ENERGY','ENERGY') + and + (S.ts - TR.start_ts) >= $leftNS + and (S.ts - TR.start_ts) <= $rightNS + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data + ORDER BY + eventName;`, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const getTabPowerBatteryData = ( + rightNs: number +): Promise< + Array<{ + ts: number; + eventName: string; + appKey: string; + eventValue: string; + }> +> => + query( + 'getTabPowerBatteryData', + `select + MAX(S.ts) as ts, + D.data as eventName, + D2.data as appKey, + group_concat((case when S.type==1 then S.string_value else S.int_value end), ',') as eventValue + from + trace_range AS TR, + hisys_event_measure as S + left join + data_dict as D + on + D.id=S.name_id + left join + app_name as APP + on + APP.id=S.key_id + left join + data_dict as D2 + on + D2.id=APP.app_key + where + D.data = 'POWER_IDE_BATTERY' + and D2.data in ('GAS_GAUGE','CHARGE','SCREEN','LEVEL','CURRENT','CAPACITY','UID') + and (S.ts - TR.start_ts) >= 0 + and (S.ts - TR.start_ts) <= $rightNS + group by APP.app_key,D.data,D2.data;`, + { $rightNS: rightNs } + ); + +export const queryMaxStateValue = ( + eventName: string +): Promise< + Array<{ + type: string; + maxValue: number; + }> +> => + query( + 'queryMaxStateValue', + `select + D.data as type, + max(S.int_value) as maxValue + from trace_range AS TR,hisys_event_measure as S + left join data_dict as D on D.id=S.name_id + left join app_name as APP on APP.id=S.key_id + left join data_dict as D2 on D2.id=APP.app_key + where (case when 'SENSOR_STATE'==$eventName then D.data like '%SENSOR%' else D.data = $eventName end) + and D2.data in ('BRIGHTNESS','STATE','VALUE','LEVEL','VOLUME','OPER_TYPE','VOLUME') + group by APP.app_key,D.data,D2.data;`, + { $eventName: eventName } + ); + +export const queryStateData = (eventName: string): Promise> => + query( + 'queryStateData', + `select + (S.ts-TR.start_ts) as startNs, + D.data as type, + D2.data as appKey, + S.int_value as value + from trace_range AS TR,hisys_event_measure as S + left join data_dict as D on D.id=S.name_id + left join app_name as APP on APP.id=S.key_id + left join data_dict as D2 on D2.id=APP.app_key + where (case when 'SENSOR_STATE'==$eventName then D.data like '%SENSOR%' else D.data = $eventName end) + and D2.data in ('BRIGHTNESS','STATE','VALUE','LEVEL','VOLUME','OPER_TYPE','VOLUME') + group by S.serial,APP.app_key,D.data,D2.data;`, + { $eventName: eventName } + ); + +export const querySyseventAppName = (): Promise< + Array<{ + string_value: string | null; + }> +> => + query( + 'querySyseventAppName', + ` + SELECT + DISTINCT hisys_event_measure.string_value from data_dict + left join app_name on app_name.app_key=data_dict.id + left join hisys_event_measure on hisys_event_measure.key_id = app_name.id + where data_dict.data = "APPNAME"` + ); + +export const queryAnomalyDetailedData = (leftNs: number, rightNs: number): Promise> => + query( + 'queryAnomalyDetailedData', + `select + S.ts, + D.data as eventName, + D2.data as appKey, + group_concat((case when S.type==1 then S.string_value else S.int_value end), ',') as Value + from trace_range AS TR,hisys_event_measure as S + left join data_dict as D on D.id=S.name_id + left join app_name as APP on APP.id=S.key_id + left join data_dict as D2 on D2.id=APP.app_key + where D.data in ('ANOMALY_SCREEN_OFF_ENERGY','ANOMALY_ALARM_WAKEUP','ANOMALY_KERNEL_WAKELOCK', + 'ANOMALY_RUNNINGLOCK','ANORMALY_APP_ENERGY','ANOMALY_GNSS_ENERGY','ANOMALY_CPU_HIGH_FREQUENCY','ANOMALY_CPU_ENERGY','ANOMALY_WAKEUP') + and D2.data in ('APPNAME') + and (S.ts - TR.start_ts) >= $leftNS + and (S.ts - TR.start_ts) <= $rightNS + group by S.serial,APP.app_key,D.data,D2.data + union + select + S.ts, + D.data as eventName, + D2.data as appKey, + group_concat((case when S.type==1 then S.string_value else S.int_value end), ',') as Value + from trace_range AS TR,hisys_event_measure as S + left join data_dict as D on D.id=S.name_id + left join app_name as APP on APP.id=S.key_id + left join data_dict as D2 on D2.id=APP.app_key + where D.data in ('ANOMALY_SCREEN_OFF_ENERGY','ANOMALY_ALARM_WAKEUP','ANOMALY_KERNEL_WAKELOCK', + 'ANOMALY_RUNNINGLOCK','ANORMALY_APP_ENERGY','ANOMALY_GNSS_ENERGY','ANOMALY_CPU_HIGH_FREQUENCY','ANOMALY_CPU_ENERGY','ANOMALY_WAKEUP') + and D2.data not in ('pid_','tid_','type_','tz_','uid_','domain_', 'id_', 'level_', 'info_', 'tag_', 'APPNAME') + and (S.ts - TR.start_ts) >= $leftNS + and (S.ts - TR.start_ts) <= $rightNS + group by S.serial,APP.app_key,D.data,D2.data;`, + { $leftNS: leftNs, $rightNS: rightNs } + ); + +export const querySmapsExits = (): Promise> => + query( + 'querySmapsExits', + `select + event_name + from stat s + where s.event_name = 'trace_smaps' + and s.stat_type ='received' and s.count > 0` + ); + +export const querySmapsData = (columnName: string): Promise> => + query( + 'querySmapsCounterData', + `SELECT (A.timestamp - B.start_ts) as startNS, sum(${columnName}) as value FROM smaps A,trace_range B GROUP by A.timestamp;` + ); + +export const querySmapsDataMax = (columnName: string): Promise> => + query( + 'querySmapsDataMax', + ` + SELECT (A.timestamp - B.start_ts) as startNS,sum(${columnName}) as max_value FROM smaps A,trace_range B GROUP by A.timestamp order by max_value desc LIMIT 1` + ); + +export const getTabSmapsMaxRss = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabSmapsMaxRss', + ` +SELECT (A.timestamp - B.start_ts) as startNS, sum(resident_size) as max_value FROM smaps A,trace_range B where startNS <= $rightNs`, + { $rightNs: rightNs } + ); + +export const getTabSmapsData = (leftNs: number, rightNs: number): Promise> => + query( + 'getTabSmapsData', + ` + SELECT + (A.timestamp - t.start_ts) AS tsNS, + start_addr, + end_addr, + dirty, + swapper, + resident_size AS rss, + pss,virtaul_size AS size,reside,f.data AS permission,d.data AS path + FROM smaps A + LEFT JOIN data_dict d ON a.path_id = d.id LEFT + JOIN data_dict f ON a.protection_id = f.id, + trace_range AS t + WHERE tsNS <= $rightNs`, + { $rightNs: rightNs }, + 'exec' + ); + +export const getTabVirtualMemoryType = (startTime: number, endTime: number): Promise> => + query( + 'getTabVirtualMemoryType', + ` + SELECT type from paged_memory_sample s,trace_range t + WHERE s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts group by type`, + { $startTime: startTime, $endTime: endTime }, + 'exec' + ); + +export const getTabIoCompletionTimesType = (startTime: number, endTime: number): Promise> => + query( + 'getTabIoCompletionTimesType', + ` + SELECT tier from bio_latency_sample s,trace_range t + WHERE s.start_ts + s.latency_dur between $startTime + t.start_ts and $endTime + t.start_ts group by tier`, + { $startTime: startTime, $endTime: endTime }, + 'exec' + ); + +export const getCpuLimitFreqId = (): Promise> => + query( + 'getCpuMaxMinFreqId', + ` + select cpu,MAX(iif(name = 'cpu_frequency_limits_max',id,0)) as maxFilterId,MAX(iif(name = 'cpu_frequency_limits_min',id,0)) as minFilterId from cpu_measure_filter where name in ('cpu_frequency_limits_max','cpu_frequency_limits_min') group by cpu +`, + {} + ); + +export const getCpuLimitFreqMax = (filterIds: string): Promise> => { + return query( + 'getCpuLimitFreqMax', + ` + select max(value) as maxValue,filter_id as filterId from measure where filter_id in (${filterIds}) group by filter_id +`, + {} + ); +}; + +export const getCpuLimitFreq = (maxId: number, minId: number, cpu: number): Promise> => + query( + 'getCpuLimitFreq', + ` + select ts - T.start_ts as startNs,dur,max(value) as max,min(value) as min,$cpu as cpu from measure,trace_range T where filter_id in ($maxId,$minId) group by ts +`, + { $maxId: maxId, $minId: minId, $cpu: cpu } + ); + +export const queryHisystemEventExits = (): Promise> => + query( + 'queryHisystemEventExits', + `select + event_name + from stat s + where s.event_name = 'trace_hisys_event' + and s.stat_type ='received' and s.count > 0` + ); + +export const queryEbpfSamplesCount = (startTime: number, endTime: number, ipids: number[]): Promise> => + query( + 'queryEbpfSamplesCount', + ` + select +fsCount, + vmCount from +(select count(1) as fsCount from file_system_sample s,trace_range t where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${ + ipids.length > 0 ? `and s.ipid in (${ipids.join(',')})` : '' + }) +,(select count(1) as vmCount from paged_memory_sample s,trace_range t where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${ + ipids.length > 0 ? `and s.ipid in (${ipids.join(',')})` : '' + }); +`, + { $startTime: startTime, $endTime: endTime } + ); + +export const querySysLockDetailsData = (rightNs: number, eventName: string): Promise> => + query( + 'querySysLockDetailsData', + `SELECT + ( S.ts - TR.start_ts ) AS ts, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS appValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + D.data in ($eventName) + and + D2.data in ('UID', 'TYPE', 'WORKID', 'NAME', 'INTERVAL', 'TAG', 'STATE', 'STACK', 'APPNAME', 'MESSAGE', 'PID', 'LOG_LEVEL') + and (S.ts - TR.start_ts) <= $rightNS + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data;`, + { $rightNS: rightNs, $eventName: eventName } + ); + +export const queryStateInitValue = (eventName: string, keyName: string): Promise> => + query( + 'queryStateInitValue', + `select + 0 as startNs, + $eventName as type, + '' as appKey, + (case $keyName + when 'brightness' then device_state.brightness + when 'wifi' then device_state.wifi + when 'bt_state' then device_state.bt_state + when 'location' then device_state.location + else 0 end) as value + from device_state;`, + { $eventName: eventName, $keyName: keyName } + ); + +export const querySysLocationDetailsData = (rightNs: number, eventName: string): Promise> => + query( + 'querySysLocationDetailsData', + `SELECT + ( S.ts - TR.start_ts ) AS ts, + D.data AS eventName, + D2.data AS appKey, + group_concat( ( CASE WHEN S.type == 1 THEN S.string_value ELSE S.int_value END ), ',' ) AS appValue + FROM + trace_range AS TR, + hisys_event_measure AS S + LEFT JOIN data_dict AS D ON D.id = S.name_id + LEFT JOIN app_name AS APP ON APP.id = S.key_id + LEFT JOIN data_dict AS D2 ON D2.id = APP.app_key + WHERE + D.data in ($eventName) + and + D2.data in ('UID', 'TYPE', 'WORKID', 'NAME', 'INTERVAL', 'TAG', 'STATE', 'STACK', 'APPNAME', 'MESSAGE', 'PID', 'LOG_LEVEL') + and (S.ts - TR.start_ts) <= $rightNS + GROUP BY + S.serial, + APP.app_key, + D.data, + D2.data;`, + { $rightNS: rightNs, $eventName: eventName } + ); +export const queryNativeMemoryRealTime = (): Promise> => + query( + 'queryNativeMemoryRealTime', + `select cs.ts,cs.clock_name from datasource_clockid dc left join clock_snapshot cs on dc.clock_id = cs.clock_id where data_source_name = 'memory-plugin' or data_source_name = 'nativehook' +`, + {} + ); + +export const queryBootTime = (): Promise> => + query( + 'queryBootTime', + `select ts,clock_name from clock_snapshot where clock_name = 'boottime' +`, + {} + ); + +export const queryConfigSysEventAppName = (): Promise< + Array<{ + process_name: string; + }> +> => + query( + 'queryConfigSysEventAppName', + ` + SELECT value from trace_config where trace_source = 'hisys_event' and key = 'process_name'` + ); + +export const queryClockData = (): Promise< + Array<{ + name: string; + num: number; + srcname: string; + }> +> => + query( + 'queryClockData', + ` + with freq as( + select measure.filter_id, measure.ts, measure.type, measure.value , clock_event_filter.name from clock_event_filter + left join measure + where clock_event_filter.type = 'clock_set_rate' and clock_event_filter.id = measure.filter_id + order by measure.ts +),state as ( + select filter_id, ts, endts, endts-ts as dur, type, value,name from + (select measure.filter_id, measure.ts, lead(ts, 1, null) over( order by measure.ts) endts, measure.type, measure.value,clock_event_filter.name from clock_event_filter,trace_range + left join measure + where clock_event_filter.type != 'clock_set_rate' and clock_event_filter.id = measure.filter_id + order by measure.ts) +),count_freq as ( + select COUNT(*) num,name srcname from freq group by name +),count_state as ( + select COUNT(*) num,name srcname from state group by name +) +select count_freq.srcname||' Frequency' as name,* from count_freq union select count_state.srcname||' State' as name,* from count_state order by name` + ); + +export const queryClockFrequency = (clockName: string): Promise> => + query( + 'queryClockFrequency', + `with freq as ( select measure.filter_id, measure.ts, measure.type, measure.value from clock_event_filter +left join measure +where clock_event_filter.name = $clockName and clock_event_filter.type = 'clock_set_rate' and clock_event_filter.id = measure.filter_id +order by measure.ts) +select freq.filter_id as filterId,freq.ts - r.start_ts as startNS,freq.type,freq.value from freq,trace_range r order by startNS`, + { $clockName: clockName } + ); + +export const queryClockState = (clockName: string): Promise> => + query( + 'queryClockState', + `with state as ( +select filter_id, ts, endts, endts-ts as dur, type, value from +(select measure.filter_id, measure.ts, lead(ts, 1, null) over( order by measure.ts) endts, measure.type, measure.value from clock_event_filter,trace_range +left join measure +where clock_event_filter.name = $clockName and clock_event_filter.type != 'clock_set_rate' and clock_event_filter.id = measure.filter_id +order by measure.ts)) +select s.filter_id as filterId,s.ts-r.start_ts as startNS,s.type,s.value,s.dur from state s,trace_range r`, + { $clockName: clockName } + ); + +export const queryScreenState = (): Promise> => + query( + 'queryScreenState', + `select m.type, m.ts-r.start_ts as startNS, value, filter_id as filterId from measure m,trace_range r where filter_id in (select id from process_measure_filter where name = 'ScreenState') order by startNS; +` + ); + +export const queryIrqList = (): Promise> => + query('queryIrqList', `select cat as name,callid as cpu from irq where cat!= 'ipi' group by cat,callid`); + +export const queryIrqData = (callid: number, cat: string): Promise> => { + let sqlSoftIrq = ` + select i.ts - t.start_ts as startNS,i.dur,i.name,i.depth,argsetid as argSetId,i.id from irq i, +trace_range t where i.callid = ${callid} and i.cat = 'softirq' + `; + let sqlIrq = ` + select i.ts - t.start_ts as startNS,i.dur, + case when i.cat = 'ipi' then 'IPI' || i.name else i.name end as name, + i.depth, + argsetid as argSetId, + i.id + from irq i,trace_range t + where i.callid = ${callid} and ((i.cat = 'irq' and i.flag ='1') or i.cat = 'ipi') + `; + return query('queryIrqData', cat === 'irq' ? sqlIrq : sqlSoftIrq, {}); +}; + +export const queryAllJankProcess = (): Promise< + Array<{ + pid: number; + }> +> => + query( + 'queryAllJankProcess', + ` + SELECT DISTINCT p.pid + FROM frame_slice AS a + LEFT JOIN process AS p ON a.ipid = p.ipid + ` + ); + +export const queryAllExpectedData = (): Promise> => + query( + 'queryAllExpectedData', + ` + SELECT + a.id, + (a.ts - TR.start_ts) AS ts, + a.vsync as name, + a.type, + a.dur, + p.pid, + p.name as cmdline + FROM frame_slice AS a, trace_range AS TR + LEFT JOIN process AS p ON a.ipid = p.ipid + WHERE a.type = 1 + and (a.flag <> 2 or a.flag is null) + ORDER BY a.ipid,ts;` + ); + +export const queryAllActualData = (): Promise> => + query( + 'queryAllActualData', + ` + SELECT + a.id, + (a.ts - TR.start_ts) AS ts, + a.vsync AS name, + a.type, + a.dur, + a.src AS src_slice, + a.flag AS jank_tag, + a.dst AS dst_slice, + p.pid, + p.name AS cmdline, + (case when p.name like '%render_service' then 'render_service' else 'app' end) as frame_type + FROM frame_slice AS a, trace_range AS TR + LEFT JOIN process AS p ON a.ipid = p.ipid + WHERE a.type = 0 + AND a.flag <> 2 + ORDER BY a.ipid, ts;` + ); + +export const queryActualFrameDate = (): Promise> => + query( + 'queryActualFrameDate', + ` + SELECT + sf.id, + 'frameTime' as frame_type, + fs.ipid, + fs.vsync as name, + fs.dur as app_dur, + (sf.ts + sf.dur - fs.ts) as dur, + (fs.ts - TR.start_ts) AS ts, + fs.type, + (case when (sf.flag == 1 or fs.flag == 1 ) then true else false end) as jank_tag, + pro.pid, + pro.name as cmdline, + (sf.ts - TR.start_ts) AS rs_ts, + sf.vsync AS rs_vsync, + sf.dur AS rs_dur, + sf.ipid AS rs_ipid, + proc.pid AS rs_pid, + proc.name AS rs_name + FROM frame_slice AS fs + LEFT JOIN process AS pro ON pro.id = fs.ipid + LEFT JOIN frame_slice AS sf ON fs.dst = sf.id + LEFT JOIN process AS proc ON proc.id = sf.ipid + LEFT JOIN trace_range TR + WHERE fs.dst IS NOT NULL + AND fs.type = 0 + AND fs.flag <> 2 + UNION + SELECT + -1 as id, + 'frameTime' as frame_type, + fs.ipid, + fs.vsync as name, + fs.dur as app_dur, + fs.dur, + (fs.ts - TR.start_ts) AS ts, + fs.type, + fs.flag as jank_tag, + pro.pid, + pro.name as cmdline, + NULL AS rs_ts, + NULL AS rs_vsync, + NULL AS rs_dur, + NULL AS rs_ipid, + NULL AS rs_pid, + NULL AS rs_name + FROM frame_slice AS fs + LEFT JOIN process AS pro ON pro.id = fs.ipid + LEFT JOIN trace_range TR + WHERE fs.dst IS NULL + AND pro.name NOT LIKE '%render_service%' + AND fs.type = 0 + AND fs.flag <> 2 + ORDER BY ts;` + ); + +export const queryExpectedFrameDate = (): Promise> => + query( + 'queryExpectedFrameDate', + ` + SELECT + sf.id, + 'frameTime' as frame_type, + fs.ipid, + fs.vsync as name, + fs.dur as app_dur, + (sf.ts + sf.dur - fs.ts) as dur, + (fs.ts - TR.start_ts) AS ts, + fs.type, + fs.flag, + pro.pid, + pro.name as cmdline, + (sf.ts - TR.start_ts) AS rs_ts, + sf.vsync AS rs_vsync, + sf.dur AS rs_dur, + sf.ipid AS rs_ipid, + proc.pid AS rs_pid, + proc.name AS rs_name + FROM frame_slice AS fs + LEFT JOIN process AS pro ON pro.id = fs.ipid + LEFT JOIN frame_slice AS sf ON fs.dst = sf.id + LEFT JOIN process AS proc ON proc.id = sf.ipid + LEFT JOIN trace_range TR + WHERE fs.dst IS NOT NULL + AND fs.type = 1 + UNION + SELECT + -1 as id, + 'frameTime' as frame_type, + fs.ipid, + fs.vsync as name, + fs.dur as app_dur, + fs.dur, + (fs.ts - TR.start_ts) AS ts, + fs.type, + fs.flag, + pro.pid, + pro.name as cmdline, + NULL AS rs_ts, + NULL AS rs_vsync, + NULL AS rs_dur, + NULL AS rs_ipid, + NULL AS rs_pid, + NULL AS rs_name + FROM frame_slice AS fs + LEFT JOIN process AS pro ON pro.id = fs.ipid + LEFT JOIN trace_range TR + WHERE fs.dst IS NULL + AND pro.name NOT LIKE '%render_service%' + AND fs.type = 1 + ORDER BY ts;` + ); + +export const queryFlowsData = (src_slice: Array): Promise> => + query( + 'queryFlowsData', + ` + SELECT a.vsync AS name, + p.pid, + p.name AS cmdline, + a.type + FROM frame_slice AS a + LEFT JOIN process AS p ON a.ipid = p.ipid + WHERE a.type = 0 + AND a.id IN (${src_slice.join(',')});` + ); + +export const queryPrecedingData = (dst_slice: string): Promise> => + query( + 'queryFlowsData', + ` + SELECT a.vsync AS name, + p.pid, + p.name AS cmdline, + a.type + FROM frame_slice AS a + LEFT JOIN process AS p ON a.ipid = p.ipid + WHERE a.type = 0 + AND a.id = $dst_slice;`, + { $dst_slice: dst_slice } + ); + +export const queryFrameTimeData = (): Promise> => + query( + 'queryFrameTimeData', + ` + SELECT DISTINCT p.pid + FROM frame_slice AS a + LEFT JOIN process AS p + ON a.ipid = p.ipid;` + ); + +export const queryGpuDur = (id: number): Promise => + query( + 'queryGpuDur', + ` + SELECT dur AS gpu_dur + FROM gpu_slice + WHERE frame_row = $id;`, + { $id: id } + ); + + export const queryHeapFile = (): Promise> => + query('queryHeapFile', + `SELECT f.id, f.file_name, f.start_time, f.end_time, f.pid, t.start_ts, t.end_ts + FROM js_heap_files f,trace_range t + where t.end_ts >= f.end_time`); + +export const queryHeapInfo = (fileId: number): Promise> => + query( + 'queryHeapInfo', + `SELECT file_id,key,type,int_value,str_value + FROM js_heap_info WHERE file_id = ${fileId}` + ); + +export const queryHeapNode = (fileId: number): Promise> => + query( + 'queryHeapNode', + `SELECT node_index,type,name,id,self_size,edge_count,trace_node_id,detachedness + FROM js_heap_nodes WHERE file_id = ${fileId}` + ); + +export const queryHeapEdge = (fileId: number): Promise> => + query( + 'queryHeapEdge', + `SELECT edge_index,type,name_or_index,to_node,from_node_id,to_node_id + FROM js_heap_edges WHERE file_id = ${fileId}` + ); + +export const queryHeapFunction = (fileId: number): Promise> => + query( + 'queryHeapFunction', + `SELECT function_index,function_id,name,script_name,script_id,line,column + FROM js_heap_trace_function_info WHERE file_id = ${fileId}` + ); + +export const queryHeapTraceNode = (fileId: number): Promise> => + query( + 'queryHeapTraceNode', + `SELECT F.name, + F.script_name, + F.script_id, + F.column, + F.line, + N.id, + N.function_info_index, + N.parent_id, + N.count, + N.size, + IFNULL( S.live_count, 0 ) AS live_count, + IFNULL( S.live_size, 0 ) AS live_size + FROM + js_heap_trace_node N + LEFT JOIN ( + SELECT + trace_node_id, + SUM( self_size ) AS live_size, + count( * ) AS live_count + FROM + js_heap_nodes + WHERE + file_id = ${fileId} + AND trace_node_id != 0 + GROUP BY + trace_node_id + ) S ON N.id = S.trace_node_id + LEFT JOIN js_heap_trace_function_info F ON (F.file_id = N.file_id + AND F.function_index = N.function_info_index) + WHERE + N.file_id = ${fileId} + ORDER BY + N.id` + ); + +export const queryHeapSample = (fileId: number): Promise> => + query( + 'queryHeapSample', + `SELECT timestamp_us,last_assigned_id + FROM js_heap_sample WHERE file_id = ${fileId}` + ); + +export const queryHeapLocation = (fileId: number): Promise> => + query( + 'queryHeapLocation', + `SELECT object_index,script_id,column + FROM js_heap_location WHERE file_id = ${fileId}` + ); + +export const queryHeapString = (fileId: number): Promise> => + query( + 'queryHeapString', + `SELECT string + FROM js_heap_string WHERE file_id = ${fileId}` + ); +export const queryTraceRange = (): Promise> => + query( + 'queryTraceRange', + `SELECT + t.start_ts, t.end_ts FROM trace_range t` + ); + +export const queryHiPerfProcessCount = ( + leftNs: number, + rightNs: number, + cpus: Array, + threads: Array, + processes: Array +): Promise> => { + let str = ''; + if (cpus.length > 0) { + str = ` and A.cpu_id in (${cpus.join(',')})`; + } + if (processes.length > 0) { + str = ` and C.process_id in (${processes.join(',')})`; + } + if (threads.length > 0) { + str = ` and A.thread_id in (${threads.join(',')}) `; + } + if (processes.length > 0 && threads.length > 0) { + str = ` and (C.process_id in (${processes.join(',')}) or A.thread_id in (${threads.join(',')}))`; + } + return query( + 'queryHiPerfProcessCount', + ` + select C.process_id as pid, + (A.timestamp_trace - R.start_ts) as time, + C.thread_name as threadName, + A.thread_id as tid, + A.id, + A.callchain_id + from perf_sample A,trace_range R + left join perf_thread C on A.thread_id = C.thread_id and A.thread_id != 0 + where time >= $leftNs and time <= $rightNs and A.callchain_id > 0 + ${str} + `, + { $leftNs: leftNs, $rightNs: rightNs } + ); +}; diff --git a/ide/src/trace/database/SqlLiteWorker.ts b/ide/src/trace/database/SqlLiteWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3362f9245794ef01ba367751a8a373ead80d51f --- /dev/null +++ b/ide/src/trace/database/SqlLiteWorker.ts @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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. + */ + +importScripts('sql-wasm.js', 'TempSql.js'); +let conn: any = null; +let encoder = new TextEncoder(); +function initIndexedDB() { + return new Promise((resolve, reject) => { + let request = indexedDB.open('systrace'); + request.onerror = function (event) {}; + request.onsuccess = function (event) { + let db = request.result; + resolve(db); + }; + request.onupgradeneeded = function (event) { + // @ts-ignore + let db = event!.target!.result; + if (!db.objectStoreNames.contains('connection')) { + db.createObjectStore('connection', { autoIncrement: true }); + } + }; + }); +} + +function readConnection(store: IDBObjectStore) { + return new Promise((resolve, reject) => { + let request = store.get(1); + request.onsuccess = function (event) { + // @ts-ignore + resolve(event.target.result); + }; + request.onerror = function (event) { + // @ts-ignore + reject(event.target.result); + }; + }); +} + +function deleteConnection(store: IDBObjectStore, id: number) { + return new Promise((resolve, reject) => { + let request = store.delete(id); + request.onsuccess = function (event) { + // @ts-ignore + resolve(event.target.result); + }; + request.onerror = function (event) { + // @ts-ignore + reject(event.target.result); + }; + }); +} + +let mergedUnitArray = (bufferSlice: Array) => { + let length = 0; + bufferSlice.forEach((item) => { + length += item.length; + }); + let mergedArray = new Uint8Array(length); + let offset = 0; + bufferSlice.forEach((item) => { + mergedArray.set(item, offset); + offset += item.length; + }); + return mergedArray; +}; + +self.onerror = function (error) {}; + +self.onmessage = async (e: any) => { + if (e.data.action === 'open') { + let array = new Uint8Array(e.data.buffer); + // @ts-ignore + initSqlJs({ locateFile: (filename) => `${filename}` }).then((SQL: any) => { + conn = new SQL.Database(array); + // @ts-ignore + self.postMessage({ id: e.data.id, ready: true, index: 0 }); + temp_init_sql_list.forEach((item, index) => { + let r = conn.exec(item); + // @ts-ignore + self.postMessage({ + id: e.data.id, + ready: true, + index: index + 1, + }); + }); + // @ts-ignore + self.postMessage({ id: e.data.id, init: true }); + }); + } else if (e.data.action === 'close') { + } else if (e.data.action === 'exec' || e.data.action === 'exec-buf') { + try { + let action = e.data.action; //: "exec" + let sql = e.data.sql; + let params = e.data.params; + const stmt = conn.prepare(sql); + stmt.bind(params); + let res = []; + while (stmt.step()) { + // + res.push(stmt.getAsObject()); + } + stmt.free(); + // @ts-ignore + self.postMessage({ id: e.data.id, results: res }); + } catch (err: any) { + // @ts-ignore + self.postMessage({ + id: e.data.id, + results: [], + error: err.message, + }); + } + } +}; diff --git a/ide/src/trace/database/TempSql.ts b/ide/src/trace/database/TempSql.ts new file mode 100644 index 0000000000000000000000000000000000000000..a51d3a0d3d6f126ae90fe6957f558f98f4845de1 --- /dev/null +++ b/ide/src/trace/database/TempSql.ts @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2022 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. + */ + +let temp_query_process = `create table temp_query_process as +select distinct process.pid as pid, + process.name as processName +from (select ipid, itid + from sched_slice + group by itid) the_tracks + left join + (select sched_slice.ipid, sum(dur) as total_dur from sched_slice group by ipid) using (ipid) + left join + process using (ipid) +where pid is not null +order by total_dur desc, + the_tracks.ipid, + processName, + the_tracks.itid; +`; +let temp_query_cpu_data = `create table temp_query_cpu_data as +with list as (SELECT IP.name as processName, + IP.name processCmdLine, + IP.pid as processId, + B.cpu, + A.name, + C.id as schedId, + A.tid, + A.id, + A.type, + B.dur, + B.ts - TR.start_ts AS startTime, + C.priority, + C.end_state + from thread_state AS B + left join thread as A on B.itid = A.id + left join sched_slice AS C on B.itid = C.itid and B.ts = C.ts + left join trace_range AS TR + left join process AS IP on A.ipid = IP.id + where C.itid is not null + order by B.id) +select * +from list; +create index temp_query_cpu_data_idx on temp_query_cpu_data (cpu, startTime); +`; + +let temp_query_freq_data = `create table temp_query_freq_data as +select cpu, value, ts - tb.start_ts as startNS +from measure c, + trace_range tb + inner join cpu_measure_filter t on c.filter_id = t.id +where (name = 'cpufreq' or name = 'cpu_frequency') +order by ts; +create index temp_query_freq_data_idx on temp_query_freq_data (cpu); +`; + +let temp_query_process_data = `create table temp_query_process_data as +select ta.id, + type, + ts, + dur, + ta.cpu, + itid as utid, + state, + ts - tb.start_ts as startTime, + tc.tid, + tc.pid, + tc.process, + tc.thread +from thread_state ta, + trace_range tb + left join (select it.id, + tid, + pid, + ip.name as process, + it.name as thread + from thread as it + left join process ip on it.ipid = ip.id) tc on ta.itid = tc.id +where ta.cpu is not null +order by startTime; +create index temp_query_process_data_idx on temp_query_process_data (pid, startTime); +`; +let temp_query_thread_function = `create table temp_query_thread_function as +select tid, + A.name as threadName, + is_main_thread, + c.callid as track_id, + c.ts - D.start_ts as startTs, + c.dur, + c.name as funName, + c.parent_id, + c.id, + c.depth, + c.argsetid +from thread A, + trace_range D + left join callstack C on A.id = C.callid +where startTs not null and c.cookie is null; +create index temp_query_thread_function_idx on temp_query_thread_function (tid); +`; + +let temp_query_thread_data = `create table temp_query_thread_data as +select A.id + , A.type + , A.tid + , A.name + , A.start_ts + , A.end_ts + , A.ipid as upid + , A.is_main_thread + , B.cpu + , B.ts - TR.start_ts AS startTime + , B.dur + , B.state + , IP.pid + , IP.name as processName +from thread_state AS B + left join thread as A on A.id = B.itid + left join trace_range AS TR + left join process AS IP on IP.id = A.ipid; +create index temp_query_thread_data_idx on temp_query_thread_data (tid);`; + +let temp_view = `CREATE VIEW IF NOT EXISTS thread_view AS SELECT id as itid, * FROM thread; +CREATE VIEW IF NOT EXISTS process_view AS SELECT id as ipid, * FROM process; +CREATE VIEW IF NOT EXISTS sched_view AS SELECT *, ts + dur as ts_end FROM sched_slice; +CREATE VIEW IF NOT EXISTS instants_view AS SELECT *, 0.0 as value FROM instant; +CREATE VIEW IF NOT EXISTS trace_section AS select start_ts, end_ts from trace_range;`; + +let temp_query_cpu_freq = `create table temp_query_cpu_freq as +select cpu +from cpu_measure_filter +where (name = 'cpufreq' or name = 'cpu_frequency') +order by cpu;`; +let temp_query_cpu_max_freq = `create table temp_query_cpu_max_freq as +select max(value) as maxFreq +from measure c + inner join cpu_measure_filter t on c.filter_id = t.id +where (name = 'cpufreq' or name = 'cpu_frequency');`; + +let temp_get_tab_states_group_by_process = `create table temp_get_tab_states_group_by_process as +select IP.name as process, + IP.pid as processId, + dur, + Ip.id as id, + (ts - B.start_ts + dur) as end_ts, + (ts - B.start_ts) as start_ts +from thread_state as A, + trace_range as B + left join thread as C on A.itid = C.id + left join process AS IP on C.ipid = IP.id +where A.dur > 0 + and processId not null and (ts - B.start_ts)>0; +create index temp_get_tab_states_group_by_process_idx on temp_get_tab_states_group_by_process (end_ts, start_ts); +`; + +let temp_get_process_thread_state_data = ` create table temp_get_process_thread_state_data as +select IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur, + (B.ts - TR.start_ts + B.dur) as end_ts, + (B.ts - TR.start_ts) as start_ts, + B.cpu, + C.priority, + '-' as note +from thread_state as B + left join thread as A on B.itid = A.id + left join process as IP on A.ipid = IP.id + left join trace_range as TR + left join sched_slice as C on B.itid = C.itid and C.ts = B.ts +where B.dur > 0 + and IP.pid not null and (B.ts - TR.start_ts) >= 0; +create index temp_get_process_thread_state_data_idx on temp_get_process_thread_state_data (end_ts, start_ts); +`; + +let temp_get_tab_states_group_by_state_pid_tid = ` create table temp_get_tab_states_group_by_state_pid_tid as +select IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur as dur, + A.tid as tid, + (B.ts - TR.start_ts + B.dur) as end_ts, + (B.ts - TR.start_ts) as start_ts +from thread_state AS B + left join thread as A on B.itid = A.id + left join process AS IP on A.ipid = IP.id + left join trace_range AS TR +where B.dur > 0 + and IP.pid not null and (B.ts - TR.start_ts > 0); +create index temp_get_tab_states_group_by_state_pid_tid_idx0 on temp_get_tab_states_group_by_state_pid_tid (process, processId, thread, threadId, state); +create index temp_get_tab_states_group_by_state_pid_tid_idx1 on temp_get_tab_states_group_by_state_pid_tid (end_ts, start_ts); +create index temp_get_tab_states_group_by_state_pid_tid_idx3 on temp_get_tab_states_group_by_state_pid_tid (end_ts, start_ts, process, processId, thread, threadId, state); +`; +let temp_get_tab_states_group_by_state_pid = `create table temp_get_tab_states_group_by_state_pid as +select IP.name as process, + IP.pid as processId, + B.state as state, + B.dur as dur, + A.tid as tid, + (ts - TR.start_ts + dur) as end_ts, + (ts - TR.start_ts) as start_ts +from thread_state AS B + left join thread as A on B.itid = A.id + left join process AS IP on A.ipid = IP.id + left join trace_range AS TR +where pid not null and + B.dur > 0 and (ts - TR.start_ts > 0); +create index temp_get_tab_states_group_by_state_pid_idx0 on temp_get_tab_states_group_by_state_pid (process, processId, state); +create index temp_get_tab_states_group_by_state_pid_idx1 on temp_get_tab_states_group_by_state_pid (start_ts, end_ts); +`; +let temp_get_tab_states_group_by_state = `create table temp_get_tab_states_group_by_state as +select state, + dur, + (ts - B.start_ts + dur) as end_ts, + (ts - B.start_ts) as start_ts +from thread_state as A, + trace_range as B + left join thread as C on A.itid = C.id + left join process AS IP on C.ipid = IP.id +where A.dur > 0 + and IP.pid not null and (ts - B.start_ts > 0); +create index temp_get_tab_states_group_by_state_idx0 on temp_get_tab_states_group_by_state (state); +create index temp_get_tab_states_group_by_state_idx1 on temp_get_tab_states_group_by_state (start_ts, end_ts); +`; +let temp_get_tab_states_group_by_process_thread = `create table temp_get_tab_states_group_by_process_thread as +select IP.name as process, + IP.pid as processId, + A.name as thread, + a.tid as threadId, + B.dur as dur, + A.tid as tid, + (ts - TR.start_ts + dur) as end_ts, + (ts - TR.start_ts) as start_ts +from thread_state AS B + left join + thread as A on B.itid = A.id + left join + process AS IP on A.ipid = IP.id + left join + trace_range AS TR +where pid not null + and + B.dur > 0 + and + (ts - TR.start_ts)>0; +create index temp_get_tab_states_group_by_process_thread_idx0 on temp_get_tab_states_group_by_process_thread (process, processId, thread, threadId); +create index temp_get_tab_states_group_by_process_thread_idx1 on temp_get_tab_states_group_by_process_thread (start_ts, end_ts); +`; + +let temp_get_cpu_rate = `create table temp_get_cpu_rate as +with cpu as (select cpu, + ts, + dur, + (case when ro < 99 then ro else 99 end) as ro, + (case when ro < 99 then stime + ro * cell else stime + 99 * cell end) as st, + (case when ro < 99 then stime + (ro + 1) * cell else etime end) as et + from (select cpu, + ts, + A.dur, + ((ts + A.dur) - D.start_ts) / ((D.end_ts - D.start_ts) / 100) as ro, + D.start_ts as stime, + D.end_ts etime, + (D.end_ts - D.start_ts) / 100 as cell + from sched_slice A + left join + trace_range D + left join + thread B on A.itid = B.id + left join + process C on B.ipid = C.id + where tid != 0 + and (A.ts) + between D.start_ts and D.end_ts)) +select cpu, + ro, + sum(case + when ts <= st and ts + dur <= et then (ts + dur - st) + when ts <= st and ts + dur > et then et - st + when ts > st and ts + dur <= et then dur + when ts > st and ts + dur > et then et - ts end) / cast(et - st as float) as rate +from cpu +group by cpu, ro; +`; + +let temp_get_tab_thread_states = `create table temp_get_tab_thread_states as +select IP.name as process, + IP.pid as pid, + A.name as thread, + A.tid as tid, + B.state as state, + B.dur as dur, + (B.ts - TR.start_ts + ifnull(B.dur, 0)) as end_ts, + (B.ts - TR.start_ts) as start_ts +from thread_state AS B + left join + thread as A + on + A.id = B.itid + left join + trace_range AS TR + left join + process AS IP + on + IP.id = A.ipid +where (B.ts - TR.start_ts > 0); +create index temp_get_tab_thread_states_idx0 on temp_get_tab_thread_states (process, pid, thread, tid, state); +create index temp_get_tab_thread_states_idx1 on temp_get_tab_thread_states (start_ts, end_ts); +`; + +let temp_get_tab_slices = `create table temp_get_tab_slices as +select c.name as name, + c.dur as dur, + A.tid as tid, + (C.ts - D.start_ts + C.dur) as end_ts, + (C.ts - D.start_ts) as start_ts +from thread A, + trace_range D + left join + callstack C on A.id = C.callid +where C.ts not null + and c.dur >= 0 + and (C.ts - D.start_ts > 0); +create index temp_get_tab_slices_idx0 on temp_get_tab_slices (name); +`; + +let createProcessNoId = ` + insert into process(id, ipid, type, pid, name, start_ts) + SELECT null, null, 'process' as type, tid as pid, t.name, t.start_ts + from thread t + where ipid is null + and tid != 0; + update process + set id = ROWID - 1, + ipid = ROWID - 1 + where id is null; + update thread + set ipid = (select id from process where thread.tid = process.pid) + where thread.ipid is null; +`; +let temp_create_cpu_freq_view = `CREATE VIEW cpu_freq_view AS SELECT B.cpu, A.ts, LEAD(A.ts, 1, (SELECT end_ts FROM trace_range)) OVER (PARTITION BY A.filter_id ORDER BY ts) AS end_ts,LEAD(A.ts, 1, (SELECT end_ts FROM trace_range)) OVER (PARTITION BY A.filter_id ORDER BY ts) - ts AS dur,value AS freq FROM measure AS A, cpu_measure_filter AS B WHERE B.name = 'cpu_frequency' AND A.filter_id = B.id`; +let temp_create_virtual_table = `CREATE VIRTUAL table result USING SPAN_JOIN(cpu_freq_view partitioned cpu, sched_slice partitioned cpu)`; + +let queryThreadWakeUpFrom = ` + select TB.tid, TB.name as thread, TA.cpu, (TA.ts - TR.start_ts) as ts, TC.pid, TC.name as process + from (select ts as wakeTs, wakeup_from as wakeupFromTid + from instant, + trace_range + where name = 'sched_wakeup' + and ref = $itid + and ts > start_ts + $startTime + and ts < start_ts + $startTime + $dur + order by ts) TW + left join thread_state TA + on TW.wakeupFromTid = TA.itid and TA.ts < TW.wakeTs and TA.ts + TA.dur >= TW.wakeTs + left join thread TB on TA.itid = TB.id + left join process TC on TB.ipid = TC.id + left join trace_range TR + where TB.ipid not null + limit 1; +`; + +let queryThreadWakeUp = ` + select TB.tid, TB.name as thread, min(TA.ts - TR.start_ts) as ts, TC.pid, TC.name as process + from (select min(ts) as wakeTs, ref as itid + from instant, + trace_range + where name = 'sched_wakeup' + and wakeup_from = $itid + and ts > start_ts + $startTime + and ts < start_ts + $startTime + $dur + group by ref) TW + left join thread_state TA on TW.itid = TA.itid and TA.ts > TW.wakeTs + left join thread TB on TA.itid = TB.id + left join process TC on TB.ipid = TC.id + left join trace_range TR + where TB.ipid not null + group by TB.tid, TB.name, TC.pid, TC.name; +`; + +let delete_callstack_binder_data = `DELETE + FROM callstack + WHERE dur < -1 + or name = 'binder transaction async' + or name = 'binder async rcv';`; + +let temp_init_sql_list = [temp_query_process]; +let translateJsonString = (str: string): string => { + return str.replace(/[\t\r\n]/g, '').replace(/\\/g, '\\\\'); +}; diff --git a/ide/src/trace/database/TraceWorker.ts b/ide/src/trace/database/TraceWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..efe4dab1897833fb498f22d3d9575c5fc94703dc --- /dev/null +++ b/ide/src/trace/database/TraceWorker.ts @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2022 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. + */ + +importScripts('trace_streamer_builtin.js', 'TempSql.js'); + +let Module: any = null; +let enc = new TextEncoder(); +let dec = new TextDecoder(); +let arr: Uint8Array; +let start: number; +const REQ_BUF_SIZE = 4 * 1024 * 1024; +let reqBufferAddr: number = -1; +let bufferSlice: Array = []; +let json: string; + +let headUnitArray: Uint8Array; +let thirdWasmMap = new Map(); +let thirdJsonResult = new Map(); + +let currentAction: string = ''; +let currentActionId: string = ''; +self.addEventListener('unhandledrejection', (err) => { + self.postMessage({ + id: currentActionId, + action: currentAction, + init: false, + status: false, + msg: err.reason.message, + }); +}); + +function initWASM() { + return new Promise((resolve, reject) => { + // @ts-ignore + let wasm = trace_streamer_builtin_wasm; + Module = wasm({ + locateFile: (s: any) => { + return s; + }, + print: (line: any) => {}, + printErr: (line: any) => {}, + onRuntimeInitialized: () => { + resolve('ok'); + }, + onAbort: () => { + reject('on abort'); + }, + }); + }); +} + +function initThirdWASM(wasmFunctionName: string) { + function callModelFun(functionName: string) { + let func = eval(functionName); + return new func({ + locateFile: (s: any) => { + return s; + }, + print: (line: any) => {}, + printErr: (line: any) => {}, + onRuntimeInitialized: () => {}, + onAbort: () => {}, + }); + } + return callModelFun(wasmFunctionName); +} + +let merged = () => { + let length = 0; + bufferSlice.forEach((item) => { + length += item.length; + }); + let mergedArray = new Uint8Array(length); + let offset = 0; + bufferSlice.forEach((item) => { + mergedArray.set(item, offset); + offset += item.length; + }); + return mergedArray; +}; +let convertJSON = () => { + let str = dec.decode(arr); + let jsonArray = []; + str = str.substring(str.indexOf('\n') + 1); + if (!str) { + } else { + let parse = JSON.parse(translateJsonString(str)); + let columns = parse.columns; + let values = parse.values; + for (let i = 0; i < values.length; i++) { + let obj: any = {}; + for (let j = 0; j < columns.length; j++) { + obj[columns[j]] = values[i][j]; + } + jsonArray.push(obj); + } + } + return jsonArray; +}; +self.onmessage = async (e: MessageEvent) => { + currentAction = e.data.action; + currentActionId = e.data.id; + if (e.data.action === 'open') { + await initWASM(); + // @ts-ignore + self.postMessage({ + id: e.data.id, + action: e.data.action, + ready: true, + index: 0, + }); + let uint8Array = new Uint8Array(e.data.buffer); + let callback = (heapPtr: number, size: number, isEnd: number) => { + let out: Uint8Array = Module.HEAPU8.slice(heapPtr, heapPtr + size); + bufferSlice.push(out); + if (isEnd == 1) { + arr = merged(); + bufferSlice.length = 0; + } + }; + let fn = Module.addFunction(callback, 'viii'); + reqBufferAddr = Module._Initialize(fn, REQ_BUF_SIZE); + let wasmConfigStr = e.data.wasmConfig; + if (wasmConfigStr != '' && wasmConfigStr.indexOf('WasmFiles') != -1) { + let wasmConfig = JSON.parse(wasmConfigStr); + let wasmConfigs = wasmConfig.WasmFiles; + let itemArray = wasmConfigs.map((item: any) => { + return item.componentId + ';' + item.pluginName; + }); + let thirdWasmStr: string = itemArray.join(';'); + let configUintArray = enc.encode(thirdWasmStr + ';'); + Module.HEAPU8.set(configUintArray, reqBufferAddr); + Module._TraceStreamer_Init_ThirdParty_Config(configUintArray.length); + let first = true; + let sendDataCallback = (heapPtr: number, size: number, componentID: number) => { + if (componentID == 100) { + if (first) { + first = false; + headUnitArray = Module.HEAPU8.slice(heapPtr, heapPtr + size); + } + return; + } + let configs = wasmConfigs.filter((wasmConfig: any) => { + return wasmConfig.componentId == componentID; + }); + if (configs.length > 0) { + let config = configs[0]; + let model = thirdWasmMap.get(componentID); + if (model == null && config.componentId == componentID) { + importScripts(config.wasmJsName); + let thirdMode = initThirdWASM(config.wasmName); + let configPluginName = config.pluginName; + let pluginNameUintArray = enc.encode(configPluginName); + let pluginNameBuffer = thirdMode._InitPluginName(pluginNameUintArray.length); + thirdMode.HEAPU8.set(pluginNameUintArray, pluginNameBuffer); + thirdMode._TraceStreamerGetPluginNameEx(configPluginName.length); + let thirdQueryDataCallBack = (heapPtr: number, size: number, isEnd: number, isConfig: number) => { + if (isConfig == 1) { + let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size); + thirdJsonResult.set(componentID, { + jsonConfig: dec.decode(out), + disPlayName: config.disPlayName, + pluginName: config.pluginName, + }); + } else { + let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size); + bufferSlice.push(out); + if (isEnd == 1) { + arr = merged(); + bufferSlice.length = 0; + } + } + }; + let fn = thirdMode.addFunction(thirdQueryDataCallBack, 'viiii'); + let thirdreqBufferAddr = thirdMode._Init(fn, REQ_BUF_SIZE); + let updateTraceTimeCallBack = (heapPtr: number, size: number) => { + let out: Uint8Array = thirdMode.HEAPU8.slice(heapPtr, heapPtr + size); + Module.HEAPU8.set(out, reqBufferAddr); + Module._UpdateTraceTime(out.length); + }; + let traceRangeFn = thirdMode.addFunction(updateTraceTimeCallBack, 'vii'); + let mm = thirdMode._InitTraceRange(traceRangeFn, 1024); + thirdMode._TraceStreamer_In_JsonConfig(); + thirdMode.HEAPU8.set(headUnitArray, thirdreqBufferAddr); + thirdMode._ParserData(headUnitArray.length, 100); + let out: Uint8Array = Module.HEAPU8.slice(heapPtr, heapPtr + size); + thirdMode.HEAPU8.set(out, thirdreqBufferAddr); + thirdMode._ParserData(out.length, componentID); + thirdWasmMap.set(componentID, { + model: thirdMode, + bufferAddr: thirdreqBufferAddr, + }); + } else { + let mm = model.model; + let out: Uint8Array = Module.HEAPU8.slice(heapPtr, heapPtr + size); + mm.HEAPU8.set(out, model.bufferAddr); + mm._ParserData(out.length, componentID); + } + } + }; + let fn1 = Module.addFunction(sendDataCallback, 'viii'); + let reqBufferAddr1 = Module._TraceStreamer_Set_ThirdParty_DataDealer(fn1, REQ_BUF_SIZE); + } + let wrSize = 0; + let r2 = -1; + while (wrSize < uint8Array.length) { + const sliceLen = Math.min(uint8Array.length - wrSize, REQ_BUF_SIZE); + const dataSlice = uint8Array.subarray(wrSize, wrSize + sliceLen); + Module.HEAPU8.set(dataSlice, reqBufferAddr); + wrSize += sliceLen; + r2 = Module._TraceStreamerParseDataEx(sliceLen); + if (r2 == -1) { + break; + } + } + Module._TraceStreamerParseDataOver(); + for (let value of thirdWasmMap.values()) { + value.model._TraceStreamer_In_ParseDataOver(); + } + if (r2 == -1) { + // @ts-ignore + self.postMessage({ + id: e.data.id, + action: e.data.action, + init: false, + msg: 'parse data error', + }); + return; + } + // @ts-ignore + temp_init_sql_list.forEach((item, index) => { + let r = createView(item); + // @ts-ignore + self.postMessage({ id: e.data.id, ready: true, index: index + 1 }); + }); + self.postMessage( + { + id: e.data.id, + action: e.data.action, + init: true, + msg: 'ok', + configSqlMap: thirdJsonResult, + buffer: e.data.buffer, + }, + // @ts-ignore + [e.data.buffer] + ); + } else if (e.data.action === 'exec') { + query(e.data.name, e.data.sql, e.data.params); + let jsonArray = convertJSON(); + // @ts-ignore + self.postMessage({ + id: e.data.id, + action: e.data.action, + results: jsonArray, + }); + } else if (e.data.action == 'exec-buf') { + query(e.data.name, e.data.sql, e.data.params); + self.postMessage( + { id: e.data.id, action: e.data.action, results: arr.buffer }, + // @ts-ignore + [arr.buffer] + ); + } else if (e.data.action.startsWith('exec-sdk')) { + querySdk(e.data.name, e.data.sql, e.data.params, e.data.action); + let jsonArray = convertJSON(); + // @ts-ignore + self.postMessage({ + id: e.data.id, + action: e.data.action, + results: jsonArray, + }); + } else if (e.data.action == 'init-port') { + let port = e.ports[0]; + port.onmessage = (me) => { + query(me.data.action, me.data.sql, me.data.params); + let msg = { + id: me.data.id, + action: me.data.action, + results: arr.buffer, + }; + port.postMessage(msg, [arr.buffer]); + }; + } else if (e.data.action == 'download-db') { + let bufferSliceUint: Array = []; + let mergedUint = () => { + let length = 0; + bufferSliceUint.forEach((item) => { + length += item.length; + }); + let mergedArray = new Uint8Array(length); + let offset = 0; + bufferSliceUint.forEach((item) => { + mergedArray.set(item, offset); + offset += item.length; + }); + return mergedArray; + }; + let getDownloadDb = (heapPtr: number, size: number, isEnd: number) => { + let out: Uint8Array = Module.HEAPU8.slice(heapPtr, heapPtr + size); + bufferSliceUint.push(out); + if (isEnd == 1) { + let arr: Uint8Array = mergedUint(); + self.postMessage({ + id: e.data.id, + action: e.data.action, + results: arr, + }); + } + }; + let fn1 = Module.addFunction(getDownloadDb, 'viii'); + Module._WasmExportDatabase(fn1); + } else if (e.data.action === 'upload-so') { + let fileList = e.data.params as Array; + if (fileList) { + uploadSoFile(fileList, () => { + self.postMessage({ + id: e.data.id, + action: e.data.action, + results: 'ok', + }); + }); + } + } +}; + +let uploadFileIndex: number = 0; + +function uploadSoFile(files: Array, callback: () => void) { + let uploadFile = (file: File) => { + let reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onloadend = function (ev) { + if (this.result) { + let fileNameBuffer = enc.encode(file.webkitRelativePath); + let addr = Module._InitFileName(fn, fileNameBuffer.length); + Module.HEAPU8.set(fileNameBuffer, addr); + let data = new Uint8Array(this.result as ArrayBuffer); + let writeSize = 0; + let upRes = -1; + while (writeSize < data.length) { + const sliceLen = Math.min(data.length - writeSize, REQ_BUF_SIZE); + const dataSlice = data.subarray(writeSize, writeSize + sliceLen); + Module.HEAPU8.set(dataSlice, reqBufferAddr); + writeSize += sliceLen; + upRes = Module._TraceStreamerDownloadELFEx( + data.length, + fileNameBuffer.length, + sliceLen, + files.length, + uploadFileIndex === files.length - 1 ? 1 : 0 + ); + } + } + }; + }; + let uploadSoCallBack = (heapPtr: number, size: number, isFinish: number) => { + let out: Uint8Array = Module.HEAPU8.slice(heapPtr, heapPtr + size); + let res = dec.decode(out); + if (res.includes('file send over')) { + if (uploadFileIndex < files.length - 1) { + uploadFileIndex = uploadFileIndex + 1; + uploadFile(files[uploadFileIndex]); + } + } + if (res.includes('ok')) { + callback(); + } + }; + let fn = Module.addFunction(uploadSoCallBack, 'viii'); + uploadFileIndex = 0; + if (files.length > 0) { + uploadFile(files[uploadFileIndex]); + } +} + +function createView(sql: string) { + let array = enc.encode(sql); + Module.HEAPU8.set(array, reqBufferAddr); + let res = Module._TraceStreamerSqlOperateEx(array.length); + return res; +} + +function queryJSON(name: string, sql: string, params: any) { + query(name, sql, params); + return convertJSON(); +} + +function query(name: string, sql: string, params: any) { + if (params) { + Reflect.ownKeys(params).forEach((key: any) => { + if (typeof params[key] === 'string') { + sql = sql.replace(new RegExp(`\\${key}`, 'g'), `'${params[key]}'`); + } else { + sql = sql.replace(new RegExp(`\\${key}`, 'g'), params[key]); + } + }); + } + start = new Date().getTime(); + let sqlUintArray = enc.encode(sql); + Module.HEAPU8.set(sqlUintArray, reqBufferAddr); + Module._TraceStreamerSqlQueryEx(sqlUintArray.length); +} + +function querySdk(name: string, sql: string, params: any, action: string) { + if (params) { + Reflect.ownKeys(params).forEach((key: any) => { + if (typeof params[key] === 'string') { + sql = sql.replace(new RegExp(`\\${key}`, 'g'), `'${params[key]}'`); + } else { + sql = sql.replace(new RegExp(`\\${key}`, 'g'), params[key]); + } + }); + } + let sqlUintArray = enc.encode(sql); + let commentId = action.substring(action.lastIndexOf('-') + 1); + let key = Number(commentId); + let wasm = thirdWasmMap.get(key); + if (wasm != undefined) { + let wasmModel = wasm.model; + wasmModel.HEAPU8.set(sqlUintArray, wasm.bufferAddr); + wasmModel._TraceStreamerSqlQueryEx(sqlUintArray.length); + } +} diff --git a/ide/src/trace/database/TraceWorkerRoot.ts b/ide/src/trace/database/TraceWorkerRoot.ts new file mode 100644 index 0000000000000000000000000000000000000000..07aac33f2de317d6f36907d819547d3b22b7cc93 --- /dev/null +++ b/ide/src/trace/database/TraceWorkerRoot.ts @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 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. + */ + +let worker: Worker; +self.onmessage = (e) => { + if (e.data.action === 'open') { + worker = new Worker('TraceWorker.js'); + worker.onmessage = (msg) => { + self.postMessage(msg.data); + }; + worker.postMessage(e.data, [e.data.buffer]); + } else if (e.data.action === 'exec') { + worker.postMessage(e.data); + } else if (e.data.action == 'exec-buf') { + // @ts-ignore + worker.postMessage(e.data); + } +}; +self.onerror = (event) => { + worker.terminate(); +}; +self.onclose = () => { + worker.terminate(); +}; diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorker.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..6eee6053f0e7da1e6a2063607d8fad8021290834 --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorker.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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 { ProcedureLogicWorkerPerf } from './ProcedureLogicWorkerPerf.js'; +import { ProcedureLogicWorkerNativeMemory } from './ProcedureLogicWorkerNativeNemory.js'; +import { ProcedureLogicWorkerFileSystem } from './ProcedureLogicWorkerFileSystem.js'; +import { ProcedureLogicWorkerSPT } from './ProcedureLogicWorkerSPT.js'; +import { ProcedureLogicWorkerCpuState } from './ProcedureLogicWorkerCpuState.js'; +import { ProcedureLogicWorkerSchedulingAnalysis } from './ProcedureLogicWorkerSchedulingAnalysis.js'; + +let logicWorker: any = { + perf: new ProcedureLogicWorkerPerf(), + 'native-memory': new ProcedureLogicWorkerNativeMemory(), + fileSystem: new ProcedureLogicWorkerFileSystem(), + CpuState: new ProcedureLogicWorkerCpuState(), + spt: new ProcedureLogicWorkerSPT(), + scheduling: new ProcedureLogicWorkerSchedulingAnalysis(), +}; + +function match(req: any) { + Reflect.ownKeys(logicWorker).filter((it) => { + if (req.type && req.type.startsWith(it as string)) { + logicWorker[it].handle(req); + } + }); +} + +self.onmessage = function (e: any) { + match(e.data); +}; diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3b23a14fefe153b8f38ae8008511b43e57ab225 --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCommon.ts @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2022 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. + */ + +export class ChartStruct { + depth: number = 0; + symbol: string = ''; + lib: string = ''; + addr: string = ''; + size: number = 0; + count: number = 0; + dur: number = 0; + parent: ChartStruct | undefined; + children: Array = []; + isSearch: boolean = false; +} + +export class Msg { + tag: string = ''; + index: number = 0; + isSending: boolean = false; + data: Array = []; +} + +export class MerageBean extends ChartStruct { + #parentNode: MerageBean | undefined = undefined; + #total = 0; + currentTreeParentNode: MerageBean | undefined = undefined; + id: string = ''; + parentId: string = ''; + symbolName: string = ''; + symbol: string = ''; + libName: string = ''; + path: string = ''; + self: string = '0s'; + weight: string = ''; + weightPercent: string = ''; + selfDur: number = 0; + dur: number = 0; + pid: number = 0; + canCharge: boolean = true; + isStore = 0; + isSelected: boolean = false; + searchShow: boolean = true; + children: MerageBean[] = []; + initChildren: MerageBean[] = []; + type: number = 0; + set parentNode(data: MerageBean | undefined) { + this.currentTreeParentNode = data; + this.#parentNode = data; + } + + get parentNode() { + return this.#parentNode; + } + + set total(data: number) { + this.#total = data; + this.weight = `${getProbablyTime(this.dur)}`; + this.weightPercent = `${((this.dur / data) * 100).toFixed(1)}%`; + } + + get total() { + return this.#total; + } +} + +class MerageBeanDataSplit { + systmeRuleName = '/system/'; + numRuleName = '/max/min/'; + + //所有的操作都是针对整个树结构的 不区分特定的数据 + splitTree( + splitMapData: any, + data: MerageBean[], + name: string, + isCharge: boolean, + isSymbol: boolean, + currentTreeList: any[], + searchValue: string + ) { + data.forEach((process) => { + process.children = []; + if (isCharge) { + this.recursionChargeInitTree(splitMapData, process, name, isSymbol); + } else { + this.recursionPruneInitTree(splitMapData, process, name, isSymbol); + } + }); + this.resetAllNode(data, currentTreeList, searchValue); + } + + recursionChargeInitTree(splitMapData: any, node: MerageBean, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (splitMapData[symbolName] = splitMapData[symbolName] || []).push(node); + node.isStore++; + } + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionChargeInitTree(splitMapData, child, symbolName, isSymbol); + }); + } + } + + //symbol lib charge + recursionChargeTree(node: MerageBean, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && + node.currentTreeParentNode.children.splice( + node.currentTreeParentNode.children.indexOf(node), + 1, + ...node.children + ); + node.children.forEach((child) => { + child.currentTreeParentNode = node.currentTreeParentNode; + }); + } + if (node.children.length > 0) { + node.children.forEach((child) => { + this.recursionChargeTree(child, symbolName, isSymbol); + }); + } + } + + recursionPruneInitTree(splitMapData: any, node: MerageBean, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (splitMapData[symbolName] = splitMapData[symbolName] || []).push(node); + node.isStore++; + this.pruneChildren(splitMapData, node, symbolName); + } else if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionPruneInitTree(splitMapData, child, symbolName, isSymbol); + }); + } + } + + //symbol lib prune + recursionPruneTree(node: MerageBean, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && + node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1); + } else { + node.children.forEach((child) => { + this.recursionPruneTree(child, symbolName, isSymbol); + }); + } + } + + recursionChargeByRule(splitMapData: any, node: MerageBean, ruleName: string, rule: (node: MerageBean) => boolean) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + if (rule(child)) { + (splitMapData[ruleName] = splitMapData[ruleName] || []).push(child); + child.isStore++; + } + this.recursionChargeByRule(splitMapData, child, ruleName, rule); + }); + } + } + + pruneChildren(splitMapData: any, node: MerageBean, symbolName: string) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + child.isStore++; + (splitMapData[symbolName] = splitMapData[symbolName] || []).push(child); + this.pruneChildren(splitMapData, child, symbolName); + }); + } + } + + hideSystemLibrary(allProcess: MerageBean[], splitMapData: any) { + allProcess.forEach((item) => { + item.children = []; + this.recursionChargeByRule(splitMapData, item, this.systmeRuleName, (node) => { + return node.path.startsWith(this.systmeRuleName); + }); + }); + } + + hideNumMaxAndMin(allProcess: MerageBean[], splitMapData: any, startNum: number, endNum: string) { + let max = endNum == '∞' ? Number.POSITIVE_INFINITY : parseInt(endNum); + allProcess.forEach((item) => { + item.children = []; + this.recursionChargeByRule(splitMapData, item, this.numRuleName, (node) => { + return node.count < startNum || node.count > max; + }); + }); + } + + resotreAllNode(splitMapData: any, symbols: string[]) { + symbols.forEach((symbol) => { + let list = splitMapData[symbol]; + if (list != undefined) { + list.forEach((item: any) => { + item.isStore--; + }); + } + }); + } + + resetAllNode(data: MerageBean[], currentTreeList: any[], searchValue: string) { + this.clearSearchNode(currentTreeList); + data.forEach((process) => { + process.searchShow = true; + process.isSearch = false; + }); + this.resetNewAllNode(data, currentTreeList); + if (searchValue != '') { + this.findSearchNode(data, searchValue, false); + this.resetNewAllNode(data, currentTreeList); + } + } + + resetNewAllNode(data: MerageBean[], currentTreeList: any[]) { + data.forEach((process) => { + process.children = []; + }); + let values = currentTreeList.map((item: any) => { + item.children = []; + return item; + }); + values.forEach((item: any) => { + if (item.parentNode != undefined) { + if (item.isStore == 0 && item.searchShow) { + let parentNode = item.parentNode; + while (parentNode != undefined && !(parentNode.isStore == 0 && parentNode.searchShow)) { + parentNode = parentNode.parentNode; + } + if (parentNode) { + item.currentTreeParentNode = parentNode; + parentNode.children.push(item); + } + } + } + }); + } + + findSearchNode(data: MerageBean[], search: string, parentSearch: boolean) { + data.forEach((node) => { + if ((node.symbolName != undefined && node.symbolName.includes(search)) || parentSearch) { + node.searchShow = true; + node.isSearch = node.symbolName != undefined && node.symbolName.includes(search); + let parentNode = node.currentTreeParentNode; + while (parentNode != undefined && !parentNode.searchShow) { + parentNode.searchShow = true; + parentNode = parentNode.currentTreeParentNode; + } + } else { + node.searchShow = false; + node.isSearch = false; + } + if (node.children.length > 0) { + this.findSearchNode(node.children, search, node.searchShow); + } + }); + } + + clearSearchNode(currentTreeList: any[]) { + currentTreeList.forEach((node) => { + node.searchShow = true; + node.isSearch = false; + }); + } + + splitAllProcess(allProcess: any[], splitMapData: any, list: any[]) { + list.forEach((item: any) => { + allProcess.forEach((process) => { + if (item.select == '0') { + this.recursionChargeInitTree(splitMapData, process, item.name, item.type == 'symbol'); + } else { + this.recursionPruneInitTree(splitMapData, process, item.name, item.type == 'symbol'); + } + }); + if (!item.checked) { + this.resotreAllNode(splitMapData, [item.name]); + } + }); + } +} + +export let merageBeanDataSplit = new MerageBeanDataSplit(); + +export abstract class LogicHandler { + abstract handle(data: any): void; +} + +let dec = new TextDecoder(); + +export let setFileName = (path: string) => { + let fileName = ''; + if (path) { + let number = path.lastIndexOf('/'); + if (number > 0) { + fileName = path.substring(number + 1); + return fileName; + } + } + return path; +}; + +let pagination = (page: number, pageSize: number, source: Array) => { + let offset = (page - 1) * pageSize; + return offset + pageSize >= source.length + ? source.slice(offset, source.length) + : source.slice(offset, offset + pageSize); +}; + +const PAGE_SIZE: number = 50_0000; +export let postMessage = (id: any, action: string, results: Array) => { + if (results.length > PAGE_SIZE) { + let pageCount = Math.ceil(results.length / PAGE_SIZE); + for (let i = 1; i <= pageCount; i++) { + let tag = 'start'; + if (i == 1) { + tag = 'start'; + } else if (i == pageCount) { + tag = 'end'; + } else { + tag = 'sending'; + } + let msg = new Msg(); + msg.tag = tag; + msg.index = i; + msg.isSending = tag != 'end'; + msg.data = pagination(i, PAGE_SIZE, results); + self.postMessage({ + id: id, + action: action, + isSending: msg.tag != 'end', + results: msg, + }); + } + results.length = 0; + } else { + let msg = new Msg(); + msg.tag = 'end'; + msg.index = 0; + msg.isSending = false; + msg.data = results; + self.postMessage({ id: id, action: action, results: msg }); + results.length = 0; + } +}; +let translateJsonString = (str: string): string => { + return str // .padding + .replace(/[\t|\r|\n]/g, '') + .replace(/\\/g, '\\\\'); +}; +export let convertJSON = (arr: ArrayBuffer | Array) => { + if (arr instanceof ArrayBuffer) { + let str = dec.decode(arr); + let jsonArray = []; + str = str.substring(str.indexOf('\n') + 1); + if (!str) { + } else { + let parse = JSON.parse(translateJsonString(str)); + let columns = parse.columns; + let values = parse.values; + for (let i = 0; i < values.length; i++) { + let obj: any = {}; + for (let j = 0; j < columns.length; j++) { + obj[columns[j]] = values[i][j]; + } + jsonArray.push(obj); + } + } + return jsonArray; + } else { + return arr; + } +}; + +export let getByteWithUnit = (bytes: number): string => { + if (bytes < 0) { + return '-' + getByteWithUnit(Math.abs(bytes)); + } + let currentBytes = bytes; + let kb1 = 1 << 10; + let mb1 = (1 << 10) << 10; + let gb1 = ((1 << 10) << 10) << 10; // 1 gb + let res = ''; + if (currentBytes > gb1) { + res += (currentBytes / gb1).toFixed(2) + ' Gb'; + } else if (currentBytes > mb1) { + res += (currentBytes / mb1).toFixed(2) + ' Mb'; + } else if (currentBytes > kb1) { + res += (currentBytes / kb1).toFixed(2) + ' Kb'; + } else { + res += Math.round(currentBytes) + ' byte'; + } + return res; +}; + +export let getTimeString = (ns: number): string => { + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; + let millisecond1 = 1_000_000; + let microsecond1 = 1_000; + let res = ''; + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1) + 'h '; + currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + 'm '; + currentNs = currentNs - Math.floor(ns / minute1) * minute1; + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + 's '; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + } + if (currentNs >= millisecond1) { + res += Math.floor(currentNs / millisecond1) + 'ms '; + currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; + } + if (currentNs >= microsecond1) { + res += Math.floor(currentNs / microsecond1) + 'μs '; + currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; + } + if (currentNs > 0) { + res += currentNs + 'ns '; + } + if (res == '') { + res = ns + ''; + } + return res; +}; + +export function getProbablyTime(ns: number): string { + let currentNs = ns; + let hour1 = 3600_000_000_000; + let minute1 = 60_000_000_000; + let second1 = 1_000_000_000; + let millisecond1 = 1_000_000; + let microsecond1 = 1_000; + let res = ''; + if (currentNs >= hour1) { + res += (currentNs / hour1).toFixed(2) + 'h '; + } else if (currentNs >= minute1) { + res += (currentNs / minute1).toFixed(2) + 'm '; + } else if (currentNs >= second1) { + res += (currentNs / second1).toFixed(2) + 's '; + } else if (currentNs >= millisecond1) { + res += (currentNs / millisecond1).toFixed(2) + 'ms '; + } else if (currentNs >= microsecond1) { + res += (currentNs / microsecond1).toFixed(2) + 'μs '; + } else if (currentNs > 0) { + res += currentNs.toFixed(0) + 'ns '; + } else if (res == '') { + res = ns + ''; + } + return res; +} + +export function timeMsFormat2p(ns: number) { + let currentNs = ns; + let hour1 = 3600_000; + let minute1 = 60_000; + let second1 = 1_000; // 1 second + let res = ''; + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1).toFixed(2) + 'h'; + return res; + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1).toFixed(2) + 'min'; + return res; + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1).toFixed(2) + 's'; + return res; + } + if (currentNs > 0) { + res += currentNs.toFixed(2) + 'ms'; + return res; + } + if (res == '') { + res = '0s'; + } + return res; +} + +export function formatRealDate(date: Date, fmt: string) { + let obj = { + 'M+': date.getMonth() + 1, + 'd+': date.getDate(), + 'h+': date.getHours(), + 'm+': date.getMinutes(), + 's+': date.getSeconds(), + 'q+': Math.floor((date.getMonth() + 3) / 3), + S: date.getMilliseconds(), + }; + if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); + for (let key in obj) { + if (new RegExp('(' + key + ')').test(fmt)) { + // @ts-ignore + fmt = fmt.replace( + RegExp.$1, + // @ts-ignore + RegExp.$1.length == 1 ? obj[key] : ('00' + obj[key]).substr(('' + obj[key]).length) + ); + } + } + return fmt; +} + +export function formatRealDateMs(timeNs: number) { + return formatRealDate(new Date(timeNs / 1000000), 'MM-dd hh:mm:ss.S'); +} diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCpuState.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCpuState.ts new file mode 100644 index 0000000000000000000000000000000000000000..2470a17a12dc58d6bae59a23a425fcad2e67c94d --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerCpuState.ts @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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 { convertJSON, LogicHandler } from './ProcedureLogicWorkerCommon.js'; + +export class ProcedureLogicWorkerCpuState extends LogicHandler { + currentEventId: string = ''; + + handle(data: any): void { + this.currentEventId = data.id; + if (data && data.type) { + switch (data.type) { + case 'CpuState-getCpuState': + if (data.params.list) { + let arr = convertJSON(data.params.list) || []; + self.postMessage({ + id: data.id, + action: data.action, + results: this.supplementCpuState(arr), + }); + arr = []; + } else { + this.getCpuState(data.params.cpu); + } + break; + } + } + } + + queryData(queryName: string, sql: string, args: any) { + self.postMessage({ + id: this.currentEventId, + type: queryName, + isQuery: true, + args: args, + sql: sql, + }); + } + + getCpuState(cpu: number) { + this.queryData( + 'CpuState-getCpuState', + ` + select (A.ts - B.start_ts) as startTs, + A.dur, + (A.ts - B.start_ts + A.dur) as endTs, + (case + when state = 'Running' then 0 + when state = 'S' then 1 + when state = 'R' or state = 'R+' then 2 + else 3 end) as value + from thread_state A,trace_range B + where cpu = $cpu and startTs >= 0; + `, + { $cpu: cpu } + ); + } + + supplementCpuState(arr: Array): Array { + let source: Array = []; + if (arr.length > 0) { + let first = arr[0]; + if (first.startTs > 0) { + let cs: CpuState = new CpuState(); + cs.startTs = 0; + cs.value = 3; + cs.dur = first.startTs; + cs.endTs = first.startTs; + source.push(cs); + } + source.push(first); + for (let i = 1, len = arr.length; i < len; i++) { + let last = arr[i - 1]; + let current = arr[i]; + if (current.startTs > last.endTs) { + let cs: CpuState = new CpuState(); + cs.startTs = last.endTs; + cs.value = 3; + cs.dur = current.startTs - last.endTs; + cs.endTs = current.startTs; + source.push(cs); + } + source.push(current); + } + } + return source; + } +} + +export class CpuState { + startTs: number = 0; + endTs: number = 0; + dur: number = 0; + value: number = 0; +} diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.ts new file mode 100644 index 0000000000000000000000000000000000000000..887280fbdce34e8ccbb605bcb7275b518d531215 --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.ts @@ -0,0 +1,981 @@ +/* + * Copyright (C) 2022 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 { + convertJSON, + getByteWithUnit, + getProbablyTime, + getTimeString, + LogicHandler, + MerageBean, + merageBeanDataSplit, + postMessage, + setFileName, +} from './ProcedureLogicWorkerCommon.js'; + +export let FILE_TYPE_MAP = { + '0': 'OPEN', + '1': 'CLOSE', + '2': 'READ', + '3': 'WRITE', +}; + +export let DISKIO_TYPE_MAP = { + '1': 'DATA_READ', + '2': 'DATA_WRITE', + '3': 'METADATA_READ', + '4': 'METADATA_WRITE', + '5': 'PAGE_IN', + '6': 'PAGE_OUT', +}; + +export let VM_TYPE_MAP = { + '1': 'File Backed In', + '2': 'Page Cache Hit', + '3': 'Swap From Zram', + '4': 'Swap From Disk', + '5': 'Zero Fill Page', + '6': 'Zero FAKE Page', + '7': 'Copy On Write', +}; + +const FS_TYPE = 0; +const PF_TYPE = 1; +const BIO_TYPE = 2; + +export class ProcedureLogicWorkerFileSystem extends LogicHandler { + static data_dict: Map = new Map(); + static callChainsMap: Map = new Map(); + handlerMap: Map = new Map(); + currentEventId: string = ''; + tab: string = ''; + isAnalysis = false; + + handle(data: any): void { + if (data.id) { + this.currentEventId = data.id; + } + if (data && data.type) { + switch (data.type) { + case 'fileSystem-init': + ProcedureLogicWorkerFileSystem.data_dict = data.params as Map; + this.initCallchains(); + break; + case 'fileSystem-queryCallchains': + let callChains = convertJSON(data.params.list) || []; + this.initCallChainTopDown(callChains); + // @ts-ignore + self.postMessage({ + id: data.id, + action: 'fileSystem-init', + results: [], + }); + break; + case 'fileSystem-queryFileSamples': + this.handlerMap.get('fileSystem').samplesList = convertJSON(data.params.list) || []; + if (this.isAnalysis) { + this.isAnalysis = false; + self.postMessage({ + id: this.currentEventId, + action: data.action, + results: this.fileSystemAnalysis(FS_TYPE, this.handlerMap.get('fileSystem').samplesList), + }); + } else { + self.postMessage({ + id: this.currentEventId, + action: data.action, + results: this.handlerMap.get('fileSystem').resolvingAction([ + { + funcName: 'getCallChainsBySampleIds', + funcArgs: [true], + }, + ]), + }); + } + + break; + case 'fileSystem-queryIoSamples': + this.handlerMap.get('io').samplesList = convertJSON(data.params.list) || []; + if (this.isAnalysis) { + this.isAnalysis = false; + self.postMessage({ + id: this.currentEventId, + action: data.action, + results: this.fileSystemAnalysis(BIO_TYPE, this.handlerMap.get('io').samplesList), + }); + } else { + self.postMessage({ + id: this.currentEventId, + action: data.action, + results: this.handlerMap.get('io').resolvingAction([ + { + funcName: 'getCallChainsBySampleIds', + funcArgs: [true], + }, + ]), + }); + } + + break; + case 'fileSystem-queryVirtualMemorySamples': + this.handlerMap.get('virtualMemory').samplesList = convertJSON(data.params.list) || []; + if (this.isAnalysis) { + this.isAnalysis = false; + self.postMessage({ + id: this.currentEventId, + action: data.action, + results: this.fileSystemAnalysis(PF_TYPE, this.handlerMap.get('virtualMemory').samplesList), + }); + } else { + self.postMessage({ + id: this.currentEventId, + action: data.action, + results: this.handlerMap.get('virtualMemory').resolvingAction([ + { + funcName: 'getCallChainsBySampleIds', + funcArgs: [true], + }, + ]), + }); + } + break; + case 'fileSystem-action': + if (data.params) { + let filter = data.params.args.filter((item: any) => item.funcName == 'getCurrentDataFromDb'); + if (filter.length == 0) { + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.handlerMap.get(data.params.callType).resolvingAction(data.params.args), + }); + } else { + if (data.params.isAnalysis) { + this.isAnalysis = true; + } + this.handlerMap.get(data.params.callType).resolvingAction(data.params.args); + } + } + break; + case 'fileSystem-queryStack': + let res = this.getStacksByCallchainId(data.params.callchainId); + self.postMessage({ + id: data.id, + action: data.action, + results: res, + }); + break; + case 'fileSystem-queryFileSysEvents': + if (data.params.list) { + let res = convertJSON(data.params.list) || []; + postMessage(data.id, data.action, this.supplementFileSysEvents(res, this.tab)); + } else { + this.tab = data.params.tab; + this.queryFileSysEvents(data.params.leftNs, data.params.rightNs, data.params.typeArr, data.params.tab); + } + break; + case 'fileSystem-queryVMEvents': + if (data.params.list) { + let res = convertJSON(data.params.list) || []; + postMessage(data.id, data.action, this.supplementVMEvents(res)); + } else { + this.queryVMEvents(data.params.leftNs, data.params.rightNs, data.params.typeArr); + } + break; + case 'fileSystem-queryIOEvents': + if (data.params.list) { + let res = convertJSON(data.params.list) || []; + postMessage(data.id, data.action, this.supplementIoEvents(res)); + } else { + this.queryIOEvents(data.params.leftNs, data.params.rightNs, data.params.diskIOipids); + } + break; + } + } + } + + queryFileSysEvents(leftNs: number, rightNs: number, typeArr: Array, tab: string) { + let types = Array.from(typeArr).join(','); + let sql = ''; + if (tab == 'events') { + sql = ` + select + A.callchain_id as callchainId, + (A.start_ts - B.start_ts) as startTs, + dur, + A.type, + ifnull(C.name,'Process') || '[' || C.pid || ']' as process, + ifnull(D.name,'Thread') || '[' || D.tid || ']' as thread, + first_argument as firstArg, + second_argument as secondArg, + third_argument as thirdArg, + fourth_argument as fourthArg, + return_value as returnValue, + fd, + file_id as fileId, + error_code as error + from file_system_sample A,trace_range B + left join process C on A.ipid = C.id + left join thread D on A.itid = D.id + where A.type in (${types}) + and( + (A.end_ts - B.start_ts) between $leftNS and $rightNS + ) + order by A.end_ts; + `; + } else if (tab == 'history') { + sql = ` + select + A.callchain_id as callchainId, + (A.start_ts - B.start_ts) as startTs, + dur, + fd, + A.type, + A.file_id as fileId, + ifnull(C.name,'Process') || '[' || C.pid || ']' as process + from file_system_sample A,trace_range B + left join process C on A.ipid = C.id + where A.type in (${types}) + and fd not null + and( + (A.start_ts - B.start_ts) between $leftNS and $rightNS + ) + order by A.end_ts; + `; + } else { + sql = ` + select TB.callchain_id as callchainId, + (TB.start_ts - TR.start_ts) as startTs, + (${rightNs} - TB.start_ts) as dur, + TB.fd, + TB.type, + TB.file_id as fileId, + ifnull(TC.name, 'Process') || '[' || TC.pid || ']' as process + from ( + select fd,ipid, + max(case when type = 0 then A.end_ts else 0 end) as openTs, + max(case when type = 1 then A.end_ts else 0 end) as closeTs + from file_system_sample A + where type in (0, 1) and A.end_ts between $leftNS and $rightNS group by fd,ipid + ) TA + left join file_system_sample TB on TA.fd = TB.fd and TA.ipid = TB.ipid and TA.openTs = TB.end_ts + left join process TC on TB.ipid = TC.ipid + left join trace_range TR + where startTs not null and TB.fd not null and TA.closeTs < TA.openTs + order by TB.end_ts; `; + } + this.queryData('fileSystem-queryFileSysEvents', sql, { + $leftNS: leftNs, + $rightNS: rightNs, + }); + } + + queryVMEvents(leftNs: number, rightNs: number, typeArr: Array) { + let types = Array.from(typeArr).join(','); + let sql = `select + A.callchain_id as callchainId, + (A.start_ts - B.start_ts) as startTs, + dur, + addr as address, + C.pid, + T.tid, + size, + A.type, + ifnull(T.name,'Thread') || '[' || T.tid || ']' as thread, + ifnull(C.name,'Process') || '[' || C.pid || ']' as process + from paged_memory_sample A,trace_range B + left join process C on A.ipid = C.id + left join thread T on T.id = A.itid + where ( + (A.end_ts - B.start_ts) between $leftNS and $rightNS + );`; + this.queryData('fileSystem-queryVMEvents', sql, { + $leftNS: leftNs, + $rightNS: rightNs, + }); + } + + queryIOEvents(leftNs: number, rightNs: number, diskIOipids: Array) { + let ipidsSql = ''; + if (diskIOipids.length > 0) { + ipidsSql += `and A.ipid in (${diskIOipids.join(',')})`; + } + let sql = `select + A.callchain_id as callchainId, + (A.start_ts - B.start_ts) as startTs, + latency_dur as dur, + path_id as pathId, + dur_per_4k as durPer4k, + tier, + size, + A.type, + block_number as blockNumber, + T.tid, + C.pid, + ifnull(T.name,'Thread') || '[' || T.tid || ']' as thread, + ifnull(C.name,'Process') || '[' || C.pid || ']' as process + from bio_latency_sample A,trace_range B + left join process C on A.ipid = C.id + left join thread T on T.id = A.itid + where ( + (A.end_ts - B.start_ts) between $leftNS and $rightNS + ) ${ipidsSql};`; + this.queryData('fileSystem-queryIOEvents', sql, { + $leftNS: leftNs, + $rightNS: rightNs, + }); + } + + getStacksByCallchainId(id: number) { + let stacks = ProcedureLogicWorkerFileSystem.callChainsMap.get(id) ?? []; + let arr: Array = []; + for (let s of stacks) { + let st: Stack = new Stack(); + st.path = (ProcedureLogicWorkerFileSystem.data_dict.get(s.pathId) ?? 'Unknown Path').split('/').reverse()[0]; + st.symbol = `${s.symbolsId == null ? s.ip : ProcedureLogicWorkerFileSystem.data_dict.get(s.symbolsId) ?? ''} (${ + st.path + })`; + st.type = st.path.endsWith('.so.1') || st.path.endsWith('.dll') || st.path.endsWith('.so') ? 0 : 1; + arr.push(st); + } + return arr; + } + + supplementIoEvents(res: Array) { + return res.map((event) => { + if (typeof event.pathId == 'string') { + event.pathId = parseInt(event.pathId); + } + event.startTsStr = getTimeString(event.startTs); + event.durPer4kStr = event.durPer4k == 0 ? '-' : getProbablyTime(event.durPer4k); + event.sizeStr = getByteWithUnit(event.size); + event.durStr = getProbablyTime(event.dur); + event.path = event.pathId ? ProcedureLogicWorkerFileSystem.data_dict.get(event.pathId) ?? '-' : '-'; + // @ts-ignore + event.operation = DISKIO_TYPE_MAP[`${event.type}`] || 'UNKNOW'; + let stacks = ProcedureLogicWorkerFileSystem.callChainsMap.get(event.callchainId) || []; + if (stacks.length > 0) { + let stack = stacks[0]; + event.backtrace = [ + stack.symbolsId == null ? stack.ip : ProcedureLogicWorkerFileSystem.data_dict.get(stack.symbolsId) ?? '', + `(${stacks.length} other frames)`, + ]; + } else { + event.backtrace = []; + } + return event; + }); + } + + supplementVMEvents(res: Array) { + return res.map((event) => { + event.startTsStr = getTimeString(event.startTs); + event.sizeStr = getByteWithUnit(event.size * 4096); + event.durStr = getProbablyTime(event.dur); + // @ts-ignore + event.operation = VM_TYPE_MAP[`${event.type}`] || 'UNKNOW'; + return event; + }); + } + + supplementFileSysEvents(res: Array, tab: string) { + res.map((r) => { + let stacks = ProcedureLogicWorkerFileSystem.callChainsMap.get(r.callchainId); + r.startTsStr = getTimeString(r.startTs); + r.durStr = getProbablyTime(r.dur); + if (tab == 'events') { + r.firstArg = r.firstArg ?? '0x0'; + r.secondArg = r.secondArg ?? '0x0'; + r.thirdArg = r.thirdArg ?? '0x0'; + r.fourthArg = r.fourthArg ?? '0x0'; + r.returnValue = r.returnValue ?? '0x0'; + r.error = r.error ?? '0x0'; + r.path = ProcedureLogicWorkerFileSystem.data_dict.get(r.fileId) ?? '-'; + } + // @ts-ignore + r.typeStr = FILE_TYPE_MAP[`${r.type}`] ?? ''; + if (stacks && stacks.length > 0) { + let stack = stacks[0]; + r.depth = stacks.length; + r.symbol = + stack.symbolsId == null ? stack.ip : ProcedureLogicWorkerFileSystem.data_dict.get(stack.symbolsId) ?? ''; + if (tab != 'events') { + r.path = ProcedureLogicWorkerFileSystem.data_dict.get(r.fileId) ?? '-'; + } + r.backtrace = [r.symbol, `(${r.depth} other frames)`]; + } else { + r.depth = 0; + r.symbol = ''; + r.path = ''; + r.backtrace = []; + } + }); + return res; + } + + initCallchains() { + if (this.handlerMap.size > 0) { + this.handlerMap.forEach((value) => { + value.clearAll(); + }); + this.handlerMap.clear(); + } + this.handlerMap.set('fileSystem', new FileSystemCallTreeHandler('fileSystem', this.queryData)); + this.handlerMap.set('io', new FileSystemCallTreeHandler('io', this.queryData)); + this.handlerMap.set('virtualMemory', new FileSystemCallTreeHandler('virtualMemory', this.queryData)); + ProcedureLogicWorkerFileSystem.callChainsMap.clear(); + this.queryData( + 'fileSystem-queryCallchains', + `select callchain_id as callChainId,depth,symbols_id as symbolsId,file_path_id as pathId,ip from ebpf_callstack`, + {} + ); + } + + initCallChainTopDown(list: any[]) { + list.forEach((callchain: FileCallChain) => { + if (ProcedureLogicWorkerFileSystem.callChainsMap.has(callchain.callChainId)) { + ProcedureLogicWorkerFileSystem.callChainsMap.get(callchain.callChainId)!.push(callchain); + } else { + ProcedureLogicWorkerFileSystem.callChainsMap.set(callchain.callChainId, [callchain]); + } + }); + } + + queryData(queryName: string, sql: string, args: any) { + self.postMessage({ + id: this.currentEventId, + type: queryName, + isQuery: true, + args: args, + sql: sql, + }); + } + + fileSystemAnalysis(type: number, samplesList: Array): Array { + let analysisSampleList = new Array(); + for (let sample of samplesList) { + let analysisSample = new FileAnalysisSample(sample); + let callChainList = ProcedureLogicWorkerFileSystem.callChainsMap.get(sample.callChainId); + if (!callChainList || callChainList.length === 0) { + continue; + } + let depth = callChainList.length - 1; + let lastCallChain: FileCallChain | undefined | null; + //let lastFilter + while (true) { + if (depth < 0) { + lastCallChain = callChainList[depth]; + break; + } + lastCallChain = callChainList[depth]; + if (type === BIO_TYPE) { + let symbolName = ProcedureLogicWorkerFileSystem.data_dict.get(lastCallChain.symbolsId); + if (symbolName?.includes('submit_bio')) { + depth--; + } else { + break; + } + } else { + let libPath = ProcedureLogicWorkerFileSystem.data_dict.get(lastCallChain.pathId); + if (libPath?.includes('musl') || libPath?.includes('libc++')) { + depth--; + } else { + break; + } + } + } + if (!lastCallChain) { + continue; + } + analysisSample.libId = lastCallChain.pathId; + analysisSample.symbolId = lastCallChain.symbolsId; + let libPath = ProcedureLogicWorkerFileSystem.data_dict.get(analysisSample.libId) || ''; + let pathArray = libPath.split('/'); + analysisSample.libName = pathArray[pathArray.length - 1]; + let symbolName = ProcedureLogicWorkerFileSystem.data_dict.get(analysisSample.symbolId); + if (!symbolName) { + symbolName = lastCallChain.ip + ' (' + analysisSample.libName + ')'; + } + analysisSample.symbolName = symbolName; + analysisSampleList.push(analysisSample); + } + return analysisSampleList; + } +} + +class FileSystemCallTreeHandler { + currentTreeMapData: any = {}; + allProcess: FileMerageBean[] = []; + dataSource: FileMerageBean[] = []; + currentDataType: string = ''; + currentTreeList: any[] = []; + samplesList: FileSample[] = []; + splitMapData: any = {}; + searchValue: string = ''; + queryData = (action: string, sql: string, args: any) => {}; + + constructor(type: string, queryData: any) { + this.currentDataType = type; + this.queryData = queryData; + } + + queryCallchainsSamples(selectionParam: any) { + switch (this.currentDataType) { + case 'fileSystem': + this.queryFileSamples(selectionParam); + break; + case 'io': + this.queryIOSamples(selectionParam); + break; + case 'virtualMemory': + this.queryEpbfSamples(selectionParam); + break; + } + } + + queryFileSamples(selectionParam: any) { + let sql = ''; + if (selectionParam.fileSystemType != undefined && selectionParam.fileSystemType.length > 0) { + sql += ' and s.type in ('; + sql += selectionParam.fileSystemType.join(','); + sql += ')'; + } + if ( + selectionParam.diskIOipids.length > 0 && + !selectionParam.diskIOLatency && + selectionParam.fileSystemType.length == 0 + ) { + sql += ` and s.ipid in (${selectionParam.diskIOipids.join(',')})`; + } + this.queryData( + 'fileSystem-queryFileSamples', + `select s.callchain_id as callChainId,h.tid,h.name as threadName,s.dur,s.type,p.pid,p.name as processName from file_system_sample s,trace_range t +left join process p on p.id = s.ipid +left join thread h on h.id = s.itid +where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${sql} and callchain_id != -1;`, + { + $startTime: selectionParam.leftNs, + $endTime: selectionParam.rightNs, + } + ); + } + + queryIOSamples(selectionParam: any) { + let sql = ''; + if (selectionParam.diskIOipids.length > 0) { + sql += `and (s.ipid in (${selectionParam.diskIOipids.join(',')}) and s.type in (5,6)) `; + } + if (selectionParam.diskIOReadIds.length > 0) { + sql += `or (s.ipid in (${selectionParam.diskIOReadIds.join(',')}) and s.type in (1,3)) `; + } + if (selectionParam.diskIOWriteIds.length > 0) { + sql += `or (s.ipid in (${selectionParam.diskIOWriteIds.join(',')}) and s.type in (2,4)) `; + } + this.queryData( + 'fileSystem-queryIoSamples', + `select s.callchain_id as callChainId,h.tid,h.name as threadName,s.latency_dur as dur,s.type,p.pid,p.name as processName from bio_latency_sample s,trace_range t +left join process p on p.id = s.ipid +left join thread h on h.id = s.itid +where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${sql} and callchain_id != -1;`, + { + $startTime: selectionParam.leftNs, + $endTime: selectionParam.rightNs, + } + ); + } + + queryEpbfSamples(selectionParam: any) { + let sql = ''; + if ( + selectionParam.diskIOipids.length > 0 && + !selectionParam.diskIOLatency && + !selectionParam.fileSysVirtualMemory + ) { + sql += ` and s.ipid in (${selectionParam.diskIOipids.join(',')})`; + } + this.queryData( + 'fileSystem-queryVirtualMemorySamples', + `select s.callchain_id as callChainId,h.tid,h.name as threadName,s.dur,s.type,p.pid,p.name as processName from paged_memory_sample s,trace_range t +left join process p on p.id = s.ipid +left join thread h on h.id = s.itid +where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${sql} and callchain_id != -1;`, + { + $startTime: selectionParam.leftNs, + $endTime: selectionParam.rightNs, + } + ); + } + + freshCurrentCallchains(samples: FileSample[], isTopDown: boolean) { + this.currentTreeMapData = {}; + this.currentTreeList = []; + this.allProcess = []; + this.dataSource = []; + let totalCount = 0; + + samples.forEach((sample) => { + totalCount += sample.dur; + let callChains = this.createThreadAndType(sample); + if (callChains.length == 2) { + return; + } + let topIndex = isTopDown ? 0 : callChains.length - 1; + if (callChains.length > 1) { + let root = + this.currentTreeMapData[callChains[topIndex].symbolsId + '' + callChains[topIndex].pathId + sample.pid]; + if (root == undefined) { + root = new FileMerageBean(); + this.currentTreeMapData[callChains[topIndex].symbolsId + '' + callChains[topIndex].pathId + sample.pid] = + root; + this.currentTreeList.push(root); + } + FileMerageBean.merageCallChainSample(root, callChains[topIndex], sample, false); + this.merageChildrenByIndex(root, callChains, topIndex, sample, isTopDown); + } + }); + let rootMerageMap: any = {}; + // @ts-ignore + Object.values(this.currentTreeMapData).forEach((merageData: any) => { + if (rootMerageMap[merageData.pid] == undefined) { + let processMerageData = new FileMerageBean(); //新增进程的节点数据 + processMerageData.canCharge = false; + processMerageData.symbolName = merageData.processName; + processMerageData.symbol = processMerageData.symbolName; + processMerageData.children.push(merageData); + processMerageData.initChildren.push(merageData); + processMerageData.dur = merageData.dur; + processMerageData.count = merageData.count; + processMerageData.total = totalCount; + rootMerageMap[merageData.pid] = processMerageData; + } else { + rootMerageMap[merageData.pid].children.push(merageData); + rootMerageMap[merageData.pid].initChildren.push(merageData); + rootMerageMap[merageData.pid].dur += merageData.dur; + rootMerageMap[merageData.pid].count += merageData.count; + rootMerageMap[merageData.pid].total = totalCount; + } + merageData.parentNode = rootMerageMap[merageData.pid]; //子节点添加父节点的引用 + }); + let id = 0; + this.currentTreeList.forEach((node) => { + node.total = totalCount; + this.setMerageName(node); + if (node.id == '') { + node.id = id + ''; + id++; + } + if (node.parentNode) { + if (node.parentNode.id == '') { + node.parentNode.id = id + ''; + id++; + } + node.parentId = node.parentNode.id; + } + }); + // @ts-ignore + this.allProcess = Object.values(rootMerageMap); + } + + createThreadAndType(sample: FileSample) { + let typeCallchain = new FileCallChain(); + typeCallchain.callChainId = sample.callChainId; + let map: any = {}; + if (this.currentDataType == 'fileSystem') { + map = FILE_TYPE_MAP; + } else if (this.currentDataType == 'io') { + map = DISKIO_TYPE_MAP; + } else if (this.currentDataType == 'virtualMemory') { + map = VM_TYPE_MAP; + } + // @ts-ignore + typeCallchain.ip = map[sample.type.toString()] || 'UNKNOW'; + typeCallchain.symbolsId = sample.type; + typeCallchain.pathId = -1; + let threadCallChain = new FileCallChain(); + threadCallChain.callChainId = sample.callChainId; + threadCallChain.ip = (sample.threadName || 'Thread') + `-${sample.tid}`; + threadCallChain.symbolsId = sample.tid; + threadCallChain.pathId = -1; + return [ + typeCallchain, + threadCallChain, + ...(ProcedureLogicWorkerFileSystem.callChainsMap.get(sample.callChainId) || []), + ]; + } + + merageChildrenByIndex( + currentNode: FileMerageBean, + callChainDataList: any[], + index: number, + sample: FileSample, + isTopDown: boolean + ) { + isTopDown ? index++ : index--; + let isEnd = isTopDown ? callChainDataList.length == index + 1 : index == 0; + let node; + if ( + currentNode.initChildren.filter((child: any) => { + if ( + child.ip == callChainDataList[index]?.ip || + (child.symbolsId != null && + child.symbolsId == callChainDataList[index]?.symbolsId && + child.pathId == callChainDataList[index]?.pathId) + ) { + node = child; + FileMerageBean.merageCallChainSample(child, callChainDataList[index], sample, isEnd); + return true; + } + return false; + }).length == 0 + ) { + node = new FileMerageBean(); + FileMerageBean.merageCallChainSample(node, callChainDataList[index], sample, isEnd); + currentNode.children.push(node); + currentNode.initChildren.push(node); + this.currentTreeList.push(node); + node.parentNode = currentNode; + } + if (node && !isEnd) this.merageChildrenByIndex(node, callChainDataList, index, sample, isTopDown); + } + + setMerageName(currentNode: FileMerageBean) { + if (currentNode.pathId == -1) { + currentNode.canCharge = false; + currentNode.symbol = currentNode.ip; + currentNode.symbolName = currentNode.symbol; + currentNode.libName = ''; + currentNode.path = ''; + } else { + currentNode.symbol = + ProcedureLogicWorkerFileSystem.data_dict.get(currentNode.symbolsId) || currentNode.ip || 'unkown'; + currentNode.path = ProcedureLogicWorkerFileSystem.data_dict.get(currentNode.pathId) || 'unkown'; + currentNode.libName = setFileName(currentNode.path); + currentNode.symbolName = `${currentNode.symbol} (${currentNode.libName})`; + } + } + resolvingAction(params: any[]) { + if (params.length > 0) { + params.forEach((item) => { + if (item.funcName && item.funcArgs) { + switch (item.funcName) { + case 'getCallChainsBySampleIds': + this.freshCurrentCallchains(this.samplesList, item.funcArgs[0]); + break; + case 'getCurrentDataFromDb': + this.queryCallchainsSamples(item.funcArgs[0]); + break; + case 'hideSystemLibrary': + merageBeanDataSplit.hideSystemLibrary(this.allProcess, this.splitMapData); + break; + case 'hideNumMaxAndMin': + merageBeanDataSplit.hideNumMaxAndMin( + this.allProcess, + this.splitMapData, + item.funcArgs[0], + item.funcArgs[1] + ); + break; + case 'splitAllProcess': + merageBeanDataSplit.splitAllProcess(this.allProcess, this.splitMapData, item.funcArgs[0]); + break; + case 'resetAllNode': + merageBeanDataSplit.resetAllNode(this.allProcess, this.currentTreeList, this.searchValue); + break; + case 'resotreAllNode': + merageBeanDataSplit.resotreAllNode(this.splitMapData, item.funcArgs[0]); + break; + case 'clearSplitMapData': + this.clearSplitMapData(item.funcArgs[0]); + break; + case 'splitTree': + merageBeanDataSplit.splitTree( + this.splitMapData, + this.allProcess, + item.funcArgs[0], + item.funcArgs[1], + item.funcArgs[2], + this.currentTreeList, + this.searchValue + ); + break; + case 'setSearchValue': + this.searchValue = item.funcArgs[0]; + break; + } + } + }); + this.dataSource = this.allProcess.filter((process) => { + return process.children && process.children.length > 0; + }); + } + return this.dataSource; + } + + clearAll() { + this.samplesList = []; + this.splitMapData = {}; + this.currentTreeMapData = {}; + this.currentTreeList = []; + this.searchValue = ''; + this.allProcess = []; + this.dataSource = []; + this.splitMapData = {}; + this.currentDataType = ''; + } + + clearSplitMapData(symbolName: string) { + delete this.splitMapData[symbolName]; + } +} + +class FileCallChain { + callChainId: number = 0; + depth: number = 0; + symbolsId: number = 0; + pathId: number = 0; + ip: string = ''; +} + +class FileSample { + type: number = 0; + callChainId: number = 0; + dur: number = 0; + pid: number = 0; + tid: number = 0; + threadName: string = ''; + processName: string = ''; +} + +class FileAnalysisSample extends FileSample { + libId = 0; + symbolId = 0; + libName = ''; + symbolName = ''; + constructor(fileSample: FileSample) { + super(); + this.type = fileSample.type; + this.callChainId = fileSample.callChainId; + this.dur = fileSample.dur; + this.pid = fileSample.pid; + this.tid = fileSample.tid; + this.threadName = fileSample.threadName; + this.processName = fileSample.processName; + } +} + +export class FileMerageBean extends MerageBean { + ip: string = ''; + symbolsId: number = 0; + pathId: number = 0; + processName: string = ''; + type: number = 0; + + static merageCallChainSample( + currentNode: FileMerageBean, + callChain: FileCallChain, + sample: FileSample, + isEnd: boolean + ) { + if (currentNode.processName == '') { + currentNode.ip = callChain.ip; + currentNode.pid = sample.pid; + currentNode.canCharge = true; + currentNode.pathId = callChain.pathId; + currentNode.symbolsId = callChain.symbolsId; + currentNode.processName = sample.processName || `Process(${sample.pid})`; + } + if (isEnd) { + currentNode.selfDur += sample.dur; + currentNode.self = getProbablyTime(currentNode.selfDur); + } + currentNode.dur += sample.dur; + currentNode.count++; + } +} + +export class Stack { + type: number = 0; + symbol: string = ''; + path: string = ''; +} + +export class FileSysEvent { + isSelected: boolean = false; + id: number = 0; + callchainId: number = 0; + startTs: number = 0; + startTsStr: string = ''; + durStr: string = ''; + dur: number = 0; + process: string = ''; + thread: string = ''; + type: number = 0; + typeStr: string = ''; + fd: number = 0; + size: number = 0; + depth: number = 0; + firstArg: string = ''; + secondArg: string = ''; + thirdArg: string = ''; + fourthArg: string = ''; + returnValue: string = ''; + error: string = ''; + path: string = ''; + symbol: string = ''; + backtrace: Array = []; + fileId: number = 0; +} + +export class IoCompletionTimes { + isSelected: boolean = false; + type: number = 0; + callchainId: number = 0; + startTs: number = 0; + startTsStr: string = ''; + durStr: string = ''; + dur: number = 0; + tid: number = 0; + pid: number = 0; + process: string = ''; + thread: string = ''; + path: string = ''; + pathId: number = 0; + operation: string = ''; + size: number = 0; + sizeStr: string = ''; + blockNumber: string = ''; + tier: number = 0; + backtrace: Array = []; + durPer4kStr: string = ''; + durPer4k: number = 0; +} + +export class VirtualMemoryEvent { + isSelected: boolean = false; + callchainId: number = 0; + startTs: number = 0; + startTsStr: string = ''; + durStr: string = ''; + dur: number = 0; + process: string = ''; + thread: string = ''; + address: string = ''; + size: number = 0; + sizeStr: string = ''; + type: number = 0; + tid: number = 0; + pid: number = 0; + operation: string = ''; +} diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.ts new file mode 100644 index 0000000000000000000000000000000000000000..ddf4297b48409369a1e7cda7b150ed8ce433481c --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.ts @@ -0,0 +1,1297 @@ +/* + * Copyright (C) 2022 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 { + convertJSON, + formatRealDateMs, + getByteWithUnit, + getTimeString, + LogicHandler, + MerageBean, + merageBeanDataSplit, + postMessage, + setFileName, +} from './ProcedureLogicWorkerCommon.js'; +export class ProcedureLogicWorkerNativeMemory extends LogicHandler { + selectTotalSize = 0; + selectTotalCount = 0; + stackCount = 0; + DATA_DICT: Map = new Map(); + FILE_DICT: Map = new Map(); + HEAP_FRAME_MAP: Map> = new Map>(); + NATIVE_MEMORY_DATA: Array = []; + currentTreeMapData: any = {}; + currentTreeList: any[] = []; + queryAllCallchainsSamples: NativeHookStatistics[] = []; + currentSamples: NativeHookStatistics[] = []; + allThreads: NativeHookCallInfo[] = []; + splitMapData: any = {}; + searchValue: string = ''; + currentEventId: string = ''; + chartComplete: Map = new Map(); + realTimeDif: number = 0; + responseTypes: { key: number; value: string }[] = []; + totalNS: number = 0; + isAnalysis: boolean = false; + isStatistic: boolean = false; + handle(data: any): void { + this.currentEventId = data.id; + if (data && data.type) { + switch (data.type) { + case 'native-memory-init': + this.clearAll(); + if (data.params.isRealtime) { + this.realTimeDif = data.params.realTimeDif; + } + this.initDataDict(); + break; + case 'native-memory-queryDataDICT': + let dict = convertJSON(data.params.list) || []; + dict.map((d: any) => this.DATA_DICT.set(d['id'], d['data'])); + this.initNMChartData(); + break; + case 'native-memory-queryNMChartData': + this.NATIVE_MEMORY_DATA = convertJSON(data.params.list) || []; + this.initNMFrameData(); + break; + case 'native-memory-queryNMFrameData': + let arr = convertJSON(data.params.list) || []; + this.initNMStack(arr); + arr = []; + self.postMessage({ + id: data.id, + action: 'native-memory-init', + results: [], + }); + break; + case 'native-memory-queryCallchainsSamples': + this.searchValue = ''; + if (data.params.list) { + let callchainsSamples = convertJSON(data.params.list) || []; + this.queryAllCallchainsSamples = callchainsSamples; + this.freshCurrentCallchains(callchainsSamples, true); + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.allThreads, + }); + } else { + this.queryCallchainsSamples( + 'native-memory-queryCallchainsSamples', + data.params.leftNs, + data.params.rightNs, + data.params.types + ); + } + break; + case 'native-memory-queryStatisticCallchainsSamples': + this.searchValue = ''; + if (data.params.list) { + let samples = convertJSON(data.params.list) || []; + this.queryAllCallchainsSamples = samples; + this.freshCurrentCallchains(samples, true); + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.allThreads, + }); + } else { + this.queryStatisticCallchainsSamples( + 'native-memory-queryStatisticCallchainsSamples', + data.params.leftNs, + data.params.rightNs, + data.params.types + ); + } + break; + case 'native-memory-queryAnalysis': + if (data.params.list) { + let samples = convertJSON(data.params.list) || []; + this.queryAllCallchainsSamples = samples; + self.postMessage({ + id: data.id, + action: data.action, + results: this.combineStatisticAndCallChain(samples), + }); + } else { + if (data.params.isStatistic) { + this.isStatistic = true; + this.queryStatisticCallchainsSamples( + 'native-memory-queryAnalysis', + data.params.leftNs, + data.params.rightNs, + data.params.types + ); + } else { + this.isStatistic = false; + this.queryCallchainsSamples( + 'native-memory-queryAnalysis', + data.params.leftNs, + data.params.rightNs, + data.params.types + ); + } + } + break; + case 'native-memory-action': + if (data.params) { + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.resolvingAction(data.params), + }); + } + break; + case 'native-memory-chart-action': + if (data.params) { + postMessage(data.id, data.action, this.resolvingActionNativeMemoryChartData(data.params)); + } + break; + case 'native-memory-calltree-action': + if (data.params) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.resolvingNMCallAction(data.params), + }); + } + break; + case 'native-memory-init-responseType': + this.initResponseTypeList(data.params); + self.postMessage({ + id: data.id, + action: data.action, + results: [], + }); + break; + case 'native-memory-get-responseType': + self.postMessage({ + id: data.id, + action: data.action, + results: this.responseTypes, + }); + break; + case 'native-memory-queryNativeHookStatistic': + if (data.params.list) { + let arr = this.statisticDataHandler(convertJSON(data.params.list)); + postMessage(data.id, data.action, this.handleNativeHookStatisticData(arr)); + } else { + this.totalNS = data.params.totalNS; + this.queryNativeHookStatistic(data.params.type); + } + break; + } + } + } + queryData(queryName: string, sql: string, args: any) { + self.postMessage({ + id: this.currentEventId, + type: queryName, + isQuery: true, + args: args, + sql: sql, + }); + } + initDataDict() { + this.queryData('native-memory-queryDataDICT', `select * from data_dict;`, {}); + } + initNMChartData() { + this.queryData( + 'native-memory-queryNMChartData', + ` + select * from ( + select + h.start_ts - t.start_ts as startTime, + h.heap_size as heapSize, + (case when h.event_type = 'AllocEvent' then 0 else 1 end) as eventType + from native_hook h ,trace_range t + where h.start_ts >= t.start_ts + and h.start_ts <= t.end_ts + and (h.event_type = 'AllocEvent' or h.event_type = 'MmapEvent') + union + select + h.end_ts - t.start_ts as startTime, + h.heap_size as heapSize, + (case when h.event_type = 'AllocEvent' then 2 else 3 end) as eventType + from native_hook h ,trace_range t + where h.start_ts >= t.start_ts + and h.start_ts <= t.end_ts + and h.end_ts not null + and (h.event_type = 'AllocEvent' or h.event_type = 'MmapEvent') + ) + order by startTime; + `, + {} + ); + } + queryNativeHookStatistic(type: number) { + let sql = ` +select callchain_id callchainId, + ts - start_ts as ts, + apply_count applyCount, + apply_size applySize, + release_count releaseCount, + release_size releaseSize +from native_hook_statistic,trace_range +where ts between start_ts and end_ts ${type === -1 ? '' : `and type = ${type}`}; + `; + this.queryData('native-memory-queryNativeHookStatistic', sql, {}); + } + + statisticDataHandler(arr: Array) { + let callGroupMap : Map = new Map(); + let obj = {}; + for (let hook of arr) { + if ((obj as any)[hook.ts]) { + let data = (obj as any)[hook.ts] as any; + data.startTime = hook.ts; + data.dur = 0; + if (callGroupMap.has(hook.callchainId)) { + let calls = callGroupMap.get(hook.callchainId); + let last = calls![calls!.length - 1]; + data.heapsize += ((hook.applySize - last.applySize) - (hook.releaseSize - last.releaseSize)); + data.density += ((hook.applyCount - last.applyCount) - (hook.releaseCount - last.releaseCount)); + calls!.push(hook); + } else { + data.heapsize += (hook.applySize - hook.releaseSize); + data.density += (hook.applyCount - hook.releaseCount); + callGroupMap.set(hook.callchainId,[hook]); + } + } else { + let data: any = {}; + data.startTime = hook.ts; + data.dur = 0; + if (callGroupMap.has(hook.callchainId)) { + let calls = callGroupMap.get(hook.callchainId); + let last = calls![calls!.length - 1]; + data.heapsize = (hook.applySize - last.applySize) - (hook.releaseSize - last.releaseSize); + data.density = (hook.applyCount - last.applyCount) - (hook.releaseCount - last.releaseCount); + calls!.push(hook); + } else { + data.heapsize = hook.applySize - hook.releaseSize; + data.density = hook.applyCount - hook.releaseCount; + callGroupMap.set(hook.callchainId,[hook]); + } + (obj as any)[hook.ts] = data; + } + } + return Object.values(obj) as { + startTime: number; + heapsize: number; + density: number; + dur: number; + }[]; + } + + handleNativeHookStatisticData( + arr: { + startTime: number; + heapsize: number; + density: number; + dur: number; + }[] + ) { + let maxSize = 0, + maxDensity = 0, + minSize = 0, + minDensity = 0; + for (let i = 0, len = arr.length; i < len; i++) { + if (i == len - 1) { + arr[i].dur = this.totalNS - arr[i].startTime; + } else { + arr[i + 1].heapsize = arr[i].heapsize + arr[i + 1].heapsize; + arr[i + 1].density = arr[i].density + arr[i + 1].density; + arr[i].dur = arr[i + 1].startTime - arr[i].startTime; + } + maxSize = Math.max(maxSize, arr[i].heapsize); + maxDensity = Math.max(maxDensity, arr[i].density); + minSize = Math.min(minSize, arr[i].heapsize); + minDensity = Math.min(minDensity, arr[i].density); + } + return arr.map((it) => { + (it as any).maxHeapSize = maxSize; + (it as any).maxDensity = maxDensity; + (it as any).minHeapSize = minSize; + (it as any).minDensity = minDensity; + return it; + }); + } + initResponseTypeList(list: any[]) { + this.responseTypes = [ + { + key: -1, + value: 'ALL', + }, + ]; + list.forEach((item) => { + if (item.lastLibId == null) { + this.responseTypes.push({ + key: 0, + value: '-', + }); + } else { + this.responseTypes.push({ + key: item.lastLibId, + value: this.groupCutFilePath(item.lastLibId, item.value) || '-', + }); + } + }); + } + initNMFrameData() { + this.queryData( + 'native-memory-queryNMFrameData', + ` + select h.symbol_id as symbolId, h.file_id as fileId, h.depth, h.callchain_id as eventId, h.vaddr as addr + from native_hook_frame h + `, + {} + ); + } + initNMStack(frameArr: Array) { + frameArr.map((frame) => { + let frameEventId = frame.eventId; + if (this.HEAP_FRAME_MAP.has(frameEventId)) { + this.HEAP_FRAME_MAP.get(frameEventId)!.push(frame); + } else { + this.HEAP_FRAME_MAP.set(frameEventId, [frame]); + } + }); + } + resolvingAction(paramMap: Map): Array { + let actionType = paramMap.get('actionType'); + if (actionType == 'call-info') { + return this.resolvingActionCallInfo(paramMap); + } else if (actionType == 'native-memory') { + return this.resolvingActionNativeMemory(paramMap); + } else if (actionType == 'memory-stack') { + return this.resolvingActionNativeMemoryStack(paramMap); + } else { + return []; + } + } + resolvingActionNativeMemoryChartData(paramMap: Map): Array { + let nativeMemoryType: number = paramMap.get('nativeMemoryType') as number; + let totalNS: number = paramMap.get('totalNS') as number; + let arr: Array = []; + let maxSize = 0, + maxDensity = 0, + minSize = 0, + minDensity = 0; + let tempSize = 0, + tempDensity = 0; + let filterLen = 0, + filterLevel = 0; + let putArr = (ne: NativeEvent, filterLevel: number) => { + let heap = new HeapStruct(); + heap.startTime = ne.startTime; + if (arr.length == 0) { + if (ne.eventType == 0 || ne.eventType == 1) { + heap.density = 1; + heap.heapsize = ne.heapSize; + } else { + heap.density = -1; + heap.heapsize = 0 - ne.heapSize; + } + maxSize = heap.heapsize; + maxDensity = heap.density; + minSize = heap.heapsize; + minDensity = heap.density; + arr.push(heap); + } else { + let last = arr[arr.length - 1]; + last.dur = heap.startTime! - last.startTime!; + if (last.dur > filterLevel) { + if (ne.eventType == 0 || ne.eventType == 1) { + heap.density = last.density! + tempDensity + 1; + heap.heapsize = last.heapsize! + tempSize + ne.heapSize; + } else { + heap.density = last.density! + tempDensity - 1; + heap.heapsize = last.heapsize! + tempSize - ne.heapSize; + } + tempDensity = 0; + tempSize = 0; + if (heap.density > maxDensity) { + maxDensity = heap.density; + } + if (heap.density < minDensity) { + minDensity = heap.density; + } + if (heap.heapsize > maxSize) { + maxSize = heap.heapsize; + } + if (heap.heapsize < minSize) { + minSize = heap.heapsize; + } + arr.push(heap); + } else { + if (ne.eventType == 0 || ne.eventType == 1) { + tempDensity = tempDensity + 1; + tempSize = tempSize + ne.heapSize; + } else { + tempDensity = tempDensity - 1; + tempSize = tempSize - ne.heapSize; + } + } + } + }; + if (nativeMemoryType == 1) { + let temp = this.NATIVE_MEMORY_DATA.filter((ne) => ne.eventType == 0 || ne.eventType == 2); + filterLen = temp.length; + filterLevel = this.getFilterLevel(filterLen); + temp.map((ne) => putArr(ne, filterLevel)); + temp.length = 0; + } else if (nativeMemoryType == 2) { + let temp = this.NATIVE_MEMORY_DATA.filter((ne) => ne.eventType == 1 || ne.eventType == 3); + filterLen = temp.length; + filterLevel = this.getFilterLevel(filterLen); + temp.map((ne) => putArr(ne, filterLevel)); + temp.length = 0; + } else { + filterLen = this.NATIVE_MEMORY_DATA.length; + let filterLevel = this.getFilterLevel(filterLen); + this.NATIVE_MEMORY_DATA.map((ne) => putArr(ne, filterLevel)); + } + if (arr.length > 0) { + arr[arr.length - 1].dur = totalNS - arr[arr.length - 1].startTime!; + } + arr.map((heap) => { + heap.maxHeapSize = maxSize; + heap.maxDensity = maxDensity; + heap.minHeapSize = minSize; + heap.minDensity = minDensity; + }); + this.chartComplete.set(nativeMemoryType, true); + if (this.chartComplete.has(0) && this.chartComplete.has(1) && this.chartComplete.has(2)) { + this.NATIVE_MEMORY_DATA = []; + } + return arr; + } + resolvingActionNativeMemoryStack(paramMap: Map) { + let eventId = paramMap.get('eventId'); + let frameArr = this.HEAP_FRAME_MAP.get(eventId) || []; + let arr: Array = []; + frameArr.map((frame) => { + let target = new NativeHookCallInfo(); + target.eventId = frame.eventId; + target.depth = frame.depth; + target.addr = frame.addr; + target.symbol = this.groupCutFilePath(frame.symbolId, this.DATA_DICT.get(frame.symbolId) || '') ?? ''; + target.library = this.groupCutFilePath(frame.fileId, this.DATA_DICT.get(frame.fileId) || '') ?? ''; + target.title = `[ ${target.symbol} ] ${target.library}`; + target.type = + target.library.endsWith('.so.1') || target.library.endsWith('.dll') || target.library.endsWith('.so') ? 0 : 1; + arr.push(target); + }); + return arr; + } + resolvingActionNativeMemory(paramMap: Map): Array { + let dataSource = paramMap.get('data') as Array; + let filterAllocType = paramMap.get('filterAllocType'); + let filterEventType = paramMap.get('filterEventType'); + let filterResponseType = paramMap.get('filterResponseType'); + let leftNs = paramMap.get('leftNs'); + let rightNs = paramMap.get('rightNs'); + let statisticsSelection = paramMap.get('statisticsSelection'); + let filter = dataSource.filter((item) => { + if (item.subTypeId != null && item.subType == undefined) { + item.subType = this.DATA_DICT.get(item.subTypeId) || '-'; + } + let filterAllocation = true; + if (filterAllocType == '1') { + filterAllocation = + item.startTs >= leftNs && + item.startTs <= rightNs && + (item.endTs > rightNs || item.endTs == 0 || item.endTs == null); + } else if (filterAllocType == '2') { + filterAllocation = + item.startTs >= leftNs && + item.startTs <= rightNs && + item.endTs <= rightNs && + item.endTs != 0 && + item.endTs != null; + } + let filterNative = this.getTypeFromIndex(parseInt(filterEventType), item, statisticsSelection); + let filterLastLib = filterResponseType == -1 ? true : filterResponseType == item.lastLibId; + return filterAllocation && filterNative && filterLastLib; + }); + let data: Array = []; + for (let i = 0, len = filter.length; i < len; i++) { + let hook = filter[i]; + let memory = new NativeMemory(); + memory.index = i; + memory.eventId = hook.eventId; + memory.eventType = hook.eventType; + memory.subType = hook.subType; + memory.heapSize = hook.heapSize; + memory.endTs = hook.endTs; + memory.heapSizeUnit = getByteWithUnit(hook.heapSize); + memory.addr = '0x' + hook.addr; + memory.startTs = hook.startTs; + memory.timestamp = + this.realTimeDif == 0 ? getTimeString(hook.startTs) : formatRealDateMs(hook.startTs + this.realTimeDif); + memory.state = hook.endTs > leftNs && hook.endTs <= rightNs ? 'Freed' : 'Existing'; + memory.threadId = hook.tid; + memory.threadName = hook.threadName; + memory.lastLibId = hook.lastLibId; + (memory as any).isSelected = hook.isSelected; + let arr = this.HEAP_FRAME_MAP.get(hook.eventId) || []; + let frame = Array.from(arr) + .reverse() + .find((item) => { + let fileName = this.DATA_DICT.get(item.fileId); + return !((fileName ?? '').includes('libc++') || (fileName ?? '').includes('musl')); + }); + if (frame == null || frame == undefined) { + if (arr.length > 0) { + frame = arr[0]; + } + } + if (frame != null && frame != undefined) { + memory.symbol = this.groupCutFilePath(frame.symbolId, this.DATA_DICT.get(frame.symbolId) || ''); + memory.library = this.groupCutFilePath(frame.fileId, this.DATA_DICT.get(frame.fileId) || 'Unknown Path'); + } else { + memory.symbol = '-'; + memory.library = '-'; + } + data.push(memory); + } + return data; + } + resolvingActionCallInfo(paramMap: Map): Array { + let dataSource = paramMap.get('data') as Array; + let filterAllocType = paramMap.get('filterAllocType'); + let filterEventType = paramMap.get('filterEventType'); + let leftNs = paramMap.get('leftNs'); + let rightNs = paramMap.get('rightNs'); + let filter: Array = []; + dataSource.map((item) => { + let filterAllocation = true; + let filterNative = true; + if (filterAllocType == '1') { + filterAllocation = + item.startTs >= leftNs && + item.startTs <= rightNs && + (item.endTs > rightNs || item.endTs == 0 || item.endTs == null); + } else if (filterAllocType == '2') { + filterAllocation = + item.startTs >= leftNs && + item.startTs <= rightNs && + item.endTs <= rightNs && + item.endTs != 0 && + item.endTs != null; + } + if (filterEventType == '1') { + filterNative = item.eventType == 'AllocEvent'; + } else if (filterEventType == '2') { + filterNative = item.eventType == 'MmapEvent'; + } + if (filterAllocation && filterNative) { + filter.push(item); + } + }); + this.freshCurrentCallchains(filter, true); + return this.allThreads; + } + groupCutFilePath(fileId: number, path: string): string { + let name = ''; + if (this.FILE_DICT.has(fileId)) { + name = this.FILE_DICT.get(fileId) ?? ''; + } else { + let currentPath = path.substring(path.lastIndexOf('/') + 1); + this.FILE_DICT.set(fileId, currentPath); + name = currentPath; + } + return name == '' ? '-' : name; + } + mergeTree(target: NativeHookCallInfo, src: NativeHookCallInfo) { + let len = src.children.length; + src.size += target.size; + src.heapSizeStr = `${getByteWithUnit(src!.size)}`; + src.heapPercent = `${((src!.size / this.selectTotalSize) * 100).toFixed(1)}%`; + if (len == 0) { + src.children.push(target); + } else { + let index = src.children.findIndex((hook) => hook.symbol == target.symbol && hook.depth == target.depth); + if (index != -1) { + let srcChild = src.children[index]; + srcChild.count += target.count; + srcChild!.countValue = `${srcChild.count}`; + srcChild!.countPercent = `${((srcChild!.count / this.selectTotalCount) * 100).toFixed(1)}%`; + if (target.children.length > 0) { + this.mergeTree(target.children[0], srcChild); + } else { + srcChild.size += target.size; + srcChild.heapSizeStr = `${getByteWithUnit(src!.size)}`; + srcChild.heapPercent = `${((srcChild!.size / this.selectTotalSize) * 100).toFixed(1)}%`; + } + } else { + src.children.push(target); + } + } + } + traverseSampleTree(stack: NativeHookCallInfo, hook: NativeHookStatistics) { + stack.count += 1; + stack.countValue = `${stack.count}`; + stack.countPercent = `${((stack.count / this.selectTotalCount) * 100).toFixed(1)}%`; + stack.size += hook.heapSize; + stack.tid = hook.tid; + stack.threadName = hook.threadName; + stack.heapSizeStr = `${getByteWithUnit(stack.size)}`; + stack.heapPercent = `${((stack.size / this.selectTotalSize) * 100).toFixed(1)}%`; + if (stack.children.length > 0) { + stack.children.map((child) => { + this.traverseSampleTree(child as NativeHookCallInfo, hook); + }); + } + } + traverseTree(stack: NativeHookCallInfo, hook: NativeHookStatistics) { + stack.count = 1; + stack.countValue = `${stack.count}`; + stack.countPercent = `${((stack!.count / this.selectTotalCount) * 100).toFixed(1)}%`; + stack.size = hook.heapSize; + stack.tid = hook.tid; + stack.threadName = hook.threadName; + stack.heapSizeStr = `${getByteWithUnit(stack!.size)}`; + stack.heapPercent = `${((stack!.size / this.selectTotalSize) * 100).toFixed(1)}%`; + if (stack.children.length > 0) { + stack.children.map((child) => { + this.traverseTree(child as NativeHookCallInfo, hook); + }); + } + } + getTypeFromIndex( + indexOf: number, + item: NativeHookStatistics, + statisticsSelection: Array + ): boolean { + if (indexOf == -1) { + return false; + } + if (indexOf < 3) { + if (indexOf == 0) { + return true; + } else if (indexOf == 1) { + return item.eventType == 'AllocEvent'; + } else if (indexOf == 2) { + return item.eventType == 'MmapEvent'; + } + } else if (indexOf - 3 < statisticsSelection.length) { + let selectionElement = statisticsSelection[indexOf - 3]; + if (selectionElement.memoryTap != undefined && selectionElement.max != undefined) { + if (selectionElement.memoryTap.indexOf('Malloc') != -1) { + return item.eventType == 'AllocEvent' && item.heapSize == selectionElement.max; + } else if (selectionElement.memoryTap.indexOf('Mmap') != -1) { + return item.eventType == 'MmapEvent' && item.heapSize == selectionElement.max; + } else { + return item.subType == selectionElement.memoryTap && item.heapSize == selectionElement.max; + } + } + } + return false; + } + clearAll() { + this.DATA_DICT.clear(); + this.FILE_DICT.clear(); + this.splitMapData = {}; + this.currentSamples = []; + this.allThreads = []; + this.queryAllCallchainsSamples = []; + this.HEAP_FRAME_MAP.clear(); + this.NATIVE_MEMORY_DATA = []; + this.chartComplete.clear(); + this.realTimeDif = 0; + } + getCallChainData() { + this.HEAP_FRAME_MAP; + } + queryCallchainsSamples(action: string, leftNs: number, rightNs: number, types: Array) { + this.queryData( + action, + `select A.id, + callchain_id as eventId, + event_type as eventType, + heap_size as heapSize, + (A.start_ts - B.start_ts) as startTs, + (A.end_ts - B.start_ts) as endTs, + tid, + ifnull(last_lib_id,0) as lastLibId, + t.name as threadName, + A.addr + from + native_hook A, + trace_range B + left join + thread t + on + A.itid = t.id + where + A.start_ts - B.start_ts + between ${leftNs} and ${rightNs} and A.event_type in (${types.join(',')}) + `, + {} + ); + } + queryStatisticCallchainsSamples(action: string, leftNs: number, rightNs: number, types: Array) { + this.queryData( + action, + `select A.id, + 0 as tid, + callchain_id as eventId, + (case when type = 0 then 'AllocEvent' else 'MmapEvent' end) as eventType, + apply_size as heapSize, + release_size as freeSize, + apply_count as count, + release_count as freeCount, + (max(A.ts) - B.start_ts) as startTs + from + native_hook_statistic A, + trace_range B + where + A.ts - B.start_ts + between ${leftNs} and ${rightNs} + and A.type in (${types.join(',')}) + group by callchain_id; + `, + {} + ); + } + combineStatisticAndCallChain(samples: NativeHookStatistics[]) { + samples.sort((a, b) => a.id - b.id); + let analysisSampleList = new Array(); + samples.forEach((sample, idx, _) => { + let applySample = sample; + // @ts-ignore + if (['FreeEvent', 'MunmapEvent'].includes(sample.eventType)) { + applySample = this.releaseSetApplyCallChain(idx, samples); + if (!applySample) return; + } + let callChains = this.createThreadSample(applySample); + if (!callChains || callChains.length === 0) { + return; + } + let index = callChains.length - 1; + let lastFilterCallChain: HeapTreeDataBean | undefined | null; + while (true) { + // if all call stack is musl or libc++. use stack top lib + if (index < 0) { + lastFilterCallChain = callChains[callChains.length - 1]; + break; + } + + lastFilterCallChain = callChains[index]; + let libPath = this.DATA_DICT.get(lastFilterCallChain.fileId); + //ignore musl and libc++ so + if (libPath?.includes('musl') || libPath?.includes('libc++')) { + index--; + } else { + lastFilterCallChain = lastFilterCallChain; + break; + } + } + + let filePath = this.DATA_DICT.get(lastFilterCallChain.fileId)!; + let libName = ''; + if (filePath) { + const path = filePath.split('/'); + libName = path[path.length - 1]; + } + let count = this.isStatistic ? sample.count : 1; + let symbolName = this.DATA_DICT.get(lastFilterCallChain.symbolId) || libName + ' (' + sample.addr + ')'; + let analysisSample = new AnalysisSample( + sample.id, + count, + sample.heapSize, + sample.eventId, + 1, + sample.eventType, + lastFilterCallChain.fileId, + libName, + lastFilterCallChain.symbolId, + symbolName + ); + analysisSample.startTs = sample.startTs; + analysisSample.endTs = sample.endTs; + analysisSample.tid = sample.tid; + analysisSample.releaseCount = sample.freeCount; + analysisSample.releaseSize = sample.freeSize; + analysisSample.applyId = applySample.id; + analysisSampleList.push(analysisSample); + }); + analysisSampleList.sort((a, b) => a.id - b.id); + return analysisSampleList; + } + + releaseSetApplyCallChain(idx: number, arr: Array) { + let releaseItem = arr[idx]; + if (releaseItem.id === 15503) { + releaseItem; + } + + for (idx; idx >= 0; idx--) { + let item = arr[idx]; + if (item.endTs === releaseItem.startTs && item.addr === releaseItem.addr) { + return item; + } + } + return null; + } + + freshCurrentCallchains(samples: NativeHookStatistics[], isTopDown: boolean) { + this.currentTreeMapData = {}; + this.currentTreeList = []; + let totalSize = 0; + let totalCount = 0; + samples.forEach((sample) => { + if (sample.eventId == -1) { + return; + } + totalSize += sample.heapSize; + totalCount += sample.count || 1; + let callChains = this.createThreadSample(sample); + let topIndex = isTopDown ? 0 : callChains.length - 1; + if (callChains.length > 0) { + let root = + this.currentTreeMapData[ + sample.tid + '-' + (callChains[topIndex].symbolId || '') + '-' + (callChains[topIndex].fileId || '') + ]; + if (root == undefined) { + root = new NativeHookCallInfo(); + this.currentTreeMapData[ + sample.tid + '-' + (callChains[topIndex].symbolId || '') + '-' + (callChains[topIndex].fileId || '') + ] = root; + this.currentTreeList.push(root); + } + NativeHookCallInfo.merageCallChainSample(root, callChains[topIndex], sample); + if (callChains.length > 1) { + this.merageChildrenByIndex(root, callChains, topIndex, sample, isTopDown); + } + } + }); + let rootMerageMap: any = {}; + // @ts-ignore + let threads = Object.values(this.currentTreeMapData); + threads.forEach((merageData: any) => { + if (rootMerageMap[merageData.tid] == undefined) { + let threadMerageData = new NativeHookCallInfo(); //新增进程的节点数据 + threadMerageData.canCharge = false; + threadMerageData.type = -1; + threadMerageData.symbolName = `${merageData.threadName || 'Thread'} [${merageData.tid}]`; + threadMerageData.symbol = threadMerageData.symbolName; + threadMerageData.children.push(merageData); + threadMerageData.initChildren.push(merageData); + threadMerageData.count = merageData.count || 1; + threadMerageData.heapSize = merageData.heapSize; + threadMerageData.totalCount = totalCount; + threadMerageData.totalSize = totalSize; + rootMerageMap[merageData.tid] = threadMerageData; + } else { + rootMerageMap[merageData.tid].children.push(merageData); + rootMerageMap[merageData.tid].initChildren.push(merageData); + rootMerageMap[merageData.tid].count += merageData.count || 1; + rootMerageMap[merageData.tid].heapSize += merageData.heapSize; + rootMerageMap[merageData.tid].totalCount = totalCount; + rootMerageMap[merageData.tid].totalSize = totalSize; + } + merageData.parentNode = rootMerageMap[merageData.tid]; //子节点添加父节点的引用 + }); + let id = 0; + this.currentTreeList.forEach((node) => { + node.totalCount = totalCount; + node.totalSize = totalSize; + this.setMerageName(node); + if (node.id == '') { + node.id = id + ''; + id++; + } + if (node.parentNode) { + if (node.parentNode.id == '') { + node.parentNode.id = id + ''; + id++; + } + node.parentId = node.parentNode.id; + } + }); + // @ts-ignore + this.allThreads = Object.values(rootMerageMap) as NativeHookCallInfo[]; + } + groupCallchainSample(paramMap: Map) { + let groupMap: any = {}; + let filterAllocType = paramMap.get('filterAllocType'); + let filterEventType = paramMap.get('filterEventType'); + let filterResponseType = paramMap.get('filterResponseType'); + let leftNs = paramMap.get('leftNs'); + let rightNs = paramMap.get('rightNs'); + let nativeHookType = paramMap.get('nativeHookType'); + if (filterAllocType == '0' && filterEventType == '0' && filterResponseType == -1) { + this.currentSamples = this.queryAllCallchainsSamples; + return; + } + let filter = this.queryAllCallchainsSamples.filter((item) => { + let filterAllocation = true; + if (nativeHookType === 'native-hook') { + if (filterAllocType == '1') { + filterAllocation = + item.startTs >= leftNs && + item.startTs <= rightNs && + (item.endTs > rightNs || item.endTs == 0 || item.endTs == null); + } else if (filterAllocType == '2') { + filterAllocation = + item.startTs >= leftNs && + item.startTs <= rightNs && + item.endTs <= rightNs && + item.endTs != 0 && + item.endTs != null; + } + } else { + if (filterAllocType == '1') { + filterAllocation = item.heapSize > item.freeSize; + } else if (filterAllocType == '2') { + filterAllocation = item.heapSize === item.freeSize; + } + } + let filterLastLib = filterResponseType == -1 ? true : filterResponseType == item.lastLibId; + let filterNative = this.getTypeFromIndex(parseInt(filterEventType), item, []); + return filterAllocation && filterNative && filterLastLib; + }); + filter.forEach((sample) => { + let currentNode = groupMap[sample.tid + '-' + sample.eventId] || new NativeHookStatistics(); + if (currentNode.count == 0) { + Object.assign(currentNode, sample); + if (filterAllocType == '1' && nativeHookType !== 'native-hook') { + currentNode.heapSize = sample.heapSize - sample.freeSize; + currentNode.count = sample.count - sample.freeCount; + } + if (currentNode.count === 0) { + currentNode.count++; + } + } else { + currentNode.count++; + currentNode.heapSize += sample.heapSize; + } + groupMap[sample.tid + '-' + sample.eventId] = currentNode; + }); + // @ts-ignore + this.currentSamples = Object.values(groupMap); + } + createThreadSample(sample: NativeHookStatistics) { + return this.HEAP_FRAME_MAP.get(sample.eventId) || []; + } + merageChildrenByIndex( + currentNode: NativeHookCallInfo, + callChainDataList: any[], + index: number, + sample: NativeHookStatistics, + isTopDown: boolean + ) { + isTopDown ? index++ : index--; + let isEnd = isTopDown ? callChainDataList.length == index + 1 : index == 0; + let node; + if ( + currentNode.initChildren.filter((child: any) => { + if (child.symbolId == callChainDataList[index]?.symbolId && child.fileId == callChainDataList[index]?.fileId) { + node = child; + NativeHookCallInfo.merageCallChainSample(child, callChainDataList[index], sample); + return true; + } + return false; + }).length == 0 + ) { + node = new NativeHookCallInfo(); + NativeHookCallInfo.merageCallChainSample(node, callChainDataList[index], sample); + currentNode.children.push(node); + currentNode.initChildren.push(node); + this.currentTreeList.push(node); + node.parentNode = currentNode; + } + if (node && !isEnd) this.merageChildrenByIndex(node, callChainDataList, index, sample, isTopDown); + } + setMerageName(currentNode: NativeHookCallInfo) { + currentNode.symbol = + this.groupCutFilePath(currentNode.symbolId, this.DATA_DICT.get(currentNode.symbolId) || '') ?? 'unkown'; + currentNode.path = this.DATA_DICT.get(currentNode.fileId) || 'unkown'; + currentNode.libName = setFileName(currentNode.path); + currentNode.lib = currentNode.path; + currentNode.symbolName = `[${currentNode.symbol}] ${currentNode.libName}`; + currentNode.type = + currentNode.libName.endsWith('.so.1') || + currentNode.libName.endsWith('.dll') || + currentNode.libName.endsWith('.so') + ? 0 + : 1; + } + clearSplitMapData(symbolName: string) { + delete this.splitMapData[symbolName]; + } + resolvingNMCallAction(params: any[]) { + if (params.length > 0) { + params.forEach((item) => { + if (item.funcName && item.funcArgs) { + switch (item.funcName) { + case 'groupCallchainSample': + this.groupCallchainSample(item.funcArgs[0] as Map); + break; + case 'getCallChainsBySampleIds': + this.freshCurrentCallchains(this.currentSamples, item.funcArgs[0]); + break; + case 'hideSystemLibrary': + merageBeanDataSplit.hideSystemLibrary(this.allThreads, this.splitMapData); + break; + case 'hideNumMaxAndMin': + merageBeanDataSplit.hideNumMaxAndMin( + this.allThreads, + this.splitMapData, + item.funcArgs[0], + item.funcArgs[1] + ); + break; + case 'splitAllProcess': + merageBeanDataSplit.splitAllProcess(this.allThreads, this.splitMapData, item.funcArgs[0]); + break; + case 'resetAllNode': + merageBeanDataSplit.resetAllNode(this.allThreads, this.currentTreeList, this.searchValue); + break; + case 'resotreAllNode': + merageBeanDataSplit.resotreAllNode(this.splitMapData, item.funcArgs[0]); + break; + case 'splitTree': + merageBeanDataSplit.splitTree( + this.splitMapData, + this.allThreads, + item.funcArgs[0], + item.funcArgs[1], + item.funcArgs[2], + this.currentTreeList, + this.searchValue + ); + break; + case 'setSearchValue': + this.searchValue = item.funcArgs[0]; + break; + case 'clearSplitMapData': + this.clearSplitMapData(item.funcArgs[0]); + break; + } + } + }); + } + return this.allThreads.filter((thread) => { + return thread.children && thread.children.length > 0; + }); + } + getFilterLevel(len: number): number { + if (len > 100_0000) { + return 10_0000; + } else if (len > 50_0000) { + return 5_0000; + } else if (len > 30_0000) { + return 3_5000; + } else if (len > 15_0000) { + return 1_5000; + } else { + return 0; + } + } +} +export class HeapTreeDataBean { + MoudleName: string | undefined; + AllocationFunction: string | undefined; + symbolId: number = 0; + fileId: number = 0; + startTs: number = 0; + endTs: number = 0; + eventType: string | undefined; + depth: number = 0; + heapSize: number = 0; + eventId: number = 0; + addr: string = ''; + callChinId: number = 0; +} +export class NativeHookStatistics { + id: number = 0; + eventId: number = 0; + eventType: string = ''; + subType: string = ''; + subTypeId: number = 0; + heapSize: number = 0; + freeSize: number = 0; + addr: string = ''; + startTs: number = 0; + endTs: number = 0; + sumHeapSize: number = 0; + max: number = 0; + count: number = 0; + freeCount: number = 0; + tid: number = 0; + threadName: string = ''; + lastLibId: number = 0; + isSelected: boolean = false; +} +export class NativeHookCallInfo extends MerageBean { + #totalCount: number = 0; + #totalSize: number = 0; + library: string = ''; + symbolId: number = 0; + fileId: number = 0; + title: string = ''; + count: number = 0; + countValue: string = ''; + countPercent: string = ''; + type: number = 0; + heapSize: number = 0; + heapPercent: string = ''; + heapSizeStr: string = ''; + eventId: number = 0; + tid: number = 0; + threadName: string = ''; + eventType: string = ''; + isSelected: boolean = false; + set totalCount(total: number) { + this.#totalCount = total; + this.countValue = this.count + ''; + this.size = this.heapSize; + this.countPercent = `${((this.count / total) * 100).toFixed(1)}%`; + } + get totalCount() { + return this.#totalCount; + } + set totalSize(total: number) { + this.#totalSize = total; + this.heapSizeStr = `${getByteWithUnit(this.heapSize)}`; + this.heapPercent = `${((this.heapSize / total) * 100).toFixed(1)}%`; + } + get totalSize() { + return this.#totalSize; + } + static merageCallChainSample( + currentNode: NativeHookCallInfo, + callChain: HeapTreeDataBean, + sample: NativeHookStatistics + ) { + if (currentNode.symbol == undefined || currentNode.symbol == '') { + currentNode.symbol = callChain.AllocationFunction || ''; + currentNode.addr = callChain.addr; + currentNode.eventId = sample.eventId; + currentNode.eventType = sample.eventType; + currentNode.symbolId = callChain.symbolId; + currentNode.fileId = callChain.fileId; + currentNode.tid = sample.tid; + } + currentNode.count += sample.count || 1; + currentNode.heapSize += sample.heapSize; + } +} +export class NativeMemory { + index: number = 0; + eventId: number = 0; + eventType: string = ''; + subType: string = ''; + addr: string = ''; + startTs: number = 0; + endTs: number = 0; + timestamp: string = ''; + heapSize: number = 0; + heapSizeUnit: string = ''; + symbol: string = ''; + library: string = ''; + lastLibId: number = 0; + isSelected: boolean = false; + state: string = ''; + threadId: number = 0; + threadName: string = ''; +} +export class HeapStruct { + startTime: number | undefined; + endTime: number | undefined; + dur: number | undefined; + density: number | undefined; + heapsize: number | undefined; + maxHeapSize: number = 0; + maxDensity: number = 0; + minHeapSize: number = 0; + minDensity: number = 0; +} +export class NativeEvent { + startTime: number = 0; + heapSize: number = 0; + eventType: number = 0; +} +export class StatisticsSelection { + memoryTap: string = ''; + max: number = 0; +} + +class AnalysisSample { + id: number = 0; + count: number = 1; + size: number = 0; + callChainId: number = 0; + pid: number = 0; + type: number; + + releaseCount?: number; + releaseSize?: number; + + tid?: number; + startTs?: number; + endTs?: number; + applyId?: number; + + libId: number; + libName: string; + symbolId: number; + symbolName: string; + constructor( + id: number, + count: number, + size: number, + callChainId: number, + pid: number, + type: number | string, + libId: number, + libName: string, + symbolId: number, + symbolName: string + ) { + this.id = id; + this.count = count; + this.size = size; + this.callChainId = callChainId; + this.pid = pid; + switch (type) { + case 'AllocEvent': + case '0': + this.type = 0; + break; + case 'MmapEvent': + case '1': + this.type = 1; + break; + case 'FreeEvent': + this.type = 2; + break; + case 'MunmapEvent': + this.type = 3; + break; + default: + this.type = -1; + } + this.libId = libId; + this.libName = libName; + this.symbolId = symbolId; + this.symbolName = symbolName; + } +} diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2c2b5aded65fccf487358ae339848dbda08aaa3 --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerPerf.ts @@ -0,0 +1,980 @@ +/* + * Copyright (C) 2022 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 { LogicHandler, ChartStruct, convertJSON } from './ProcedureLogicWorkerCommon.js'; + +export class ProcedureLogicWorkerPerf extends LogicHandler { + systmeRuleName = '/system/'; + numRuleName = '/max/min/'; + filesData: any = {}; + samplesData: any = {}; + threadData: any = {}; + callChainData: any = {}; + splitMapData: any = {}; + currentTreeMapData: any = {}; + currentTreeList: any[] = []; + searchValue: string = ''; + dataSource: PerfCallChainMerageData[] = []; + allProcess: PerfCallChainMerageData[] = []; + callChainMap: Map = new Map(); + queryFunc: Function | undefined = undefined; + isActualQuery: boolean = false; + static cmdLineResult: any = undefined; + currentEventId: string = ''; + + handle(data: any): void { + this.currentEventId = data.id; + if (data && data.type) { + switch (data.type) { + case 'perf-init': + ProcedureLogicWorkerPerf.cmdLineResult = data.params; + this.initPerfFiles(); + break; + case 'perf-queryPerfFiles': + let files = convertJSON(data.params.list) || []; + files.forEach((file: any) => { + this.filesData[file.fileId] = this.filesData[file.fileId] || []; + PerfFile.setFileName(file); + this.filesData[file.fileId].push(file); + }); + this.initPerfThreads(); + break; + case 'perf-queryPerfThread': + let threads = convertJSON(data.params.list) || []; + threads.forEach((thread: any) => { + this.threadData[thread.tid] = thread; + }); + this.initPerfCalls(); + break; + case 'perf-queryPerfCalls': + let perfCalls = convertJSON(data.params.list) || []; + if (perfCalls.length != 0) { + perfCalls.forEach((perfCall: any) => { + this.callChainMap.set(perfCall.sampleId, perfCall); + }); + } + this.initPerfCallchains(); + break; + case 'perf-queryPerfCallchains': + let arr = convertJSON(data.params.list) || []; + this.initCallChainTopDown(arr); + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.callChainMap, + }); + break; + case 'perf-queryCallchainsGroupSample': + this.samplesData = convertJSON(data.params.list) || []; + self.postMessage({ + id: data.id, + action: data.action, + results: this.resolvingAction([ + { + funcName: 'getCallChainsBySampleIds', + funcArgs: [true], + }, + ]), + }); + break; + case 'perf-action': + if (data.params) { + let filter = data.params.filter((item: any) => item.funcName == 'getCurrentDataFromDb'); + if (filter.length == 0) { + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.resolvingAction(data.params), + }); + } else { + this.resolvingAction(data.params); + } + } + break; + case 'perf-queryPerfAnalysisCallChain': + // @ts-ignore + self.postMessage({ + id: data.id, + action: data.action, + results: this.perfAnalysisCallChain(), + }); + break; + } + } + } + + queryData(queryName: string, sql: string, args: any) { + self.postMessage({ + id: this.currentEventId, + type: queryName, + isQuery: true, + args: args, + sql: sql, + }); + } + + initPerfFiles() { + this.clearAll(); + this.queryData('perf-queryPerfFiles', `select file_id as fileId,symbol,path from perf_files`, {}); + } + + initPerfThreads() { + this.queryData( + 'perf-queryPerfThread', + `select a.thread_id as tid,a.thread_name as threadName,a.process_id as pid,b.thread_name as processName from perf_thread a left join (select * from perf_thread where thread_id = process_id) b on a.process_id = b.thread_id`, + {} + ); + } + + initPerfCalls() { + this.queryData( + 'perf-queryPerfCalls', + `select count(callchain_id) as depth,callchain_id as sampleId,name +from perf_callchain +where callchain_id != -1 +group by callchain_id`, + {} + ); + } + + initPerfCallchains() { + this.queryData( + 'perf-queryPerfCallchains', + `select c.name,c.callchain_id as sampleId,c.vaddr_in_file as vaddrInFile,c.file_id as fileId,c.symbol_id as symbolId +from perf_callchain c +where callchain_id != -1;`, + {} + ); + } + + getCurrentDataFromDb(selectionParam: any) { + let cpus = selectionParam.perfAll ? [] : selectionParam.perfCpus; + let processes = selectionParam.perfAll ? [] : selectionParam.perfProcess; + let threads = selectionParam.perfAll ? [] : selectionParam.perfThread; + let sql = ''; + if (cpus.length != 0 || processes.length != 0 || threads.length != 0) { + let arg1 = cpus.length > 0 ? `or s.cpu_id in (${cpus.join(',')}) ` : ''; + let arg2 = processes.length > 0 ? `or thread.process_id in (${processes.join(',')}) ` : ''; + let arg3 = threads.length > 0 ? `or s.thread_id in (${threads.join(',')})` : ''; + let arg = `${arg1}${arg2}${arg3}`.substring(3); + sql = ` and (${arg})`; + } + this.queryData( + 'perf-queryCallchainsGroupSample', + ` +select p.callchain_id as sampleId, p.thread_state as threadState, p.thread_id as tid, p.count, p.process_id as pid +from (select callchain_id, s.thread_id, thread_state, process_id, count(callchain_id) as count + from perf_sample s, + trace_range t + left join perf_thread thread on s.thread_id = thread.thread_id + where timestamp_trace between $startTime + t.start_ts and $endTime + t.start_ts + and callchain_id != -1 + and s.thread_id != 0 + ${sql} + group by callchain_id, s.thread_id, thread_state, process_id) p`, + { + $startTime: selectionParam.leftNs, + $endTime: selectionParam.rightNs, + $sql: sql, + } + ); + } + + clearAll() { + this.filesData = {}; + this.samplesData = {}; + this.threadData = {}; + this.callChainData = {}; + this.splitMapData = {}; + this.currentTreeMapData = {}; + this.currentTreeList = []; + this.searchValue = ''; + this.dataSource = []; + this.allProcess = []; + this.callChainMap = new Map(); + } + + initCallChainBottomUp(callChains: PerfCallChain[]) { + callChains.forEach((callChain, index) => { + if (this.threadData[callChain.tid] == undefined) { + return; + } + this.setCallChainName(callChain); + this.addGroupData(callChain); + if (index + 1 < callChains.length && callChains[index + 1].sampleId == callChain.sampleId) { + PerfCallChain.setPreviousNode(callChain, callChains[index + 1]); + } + if (callChains.length == index + 1 || callChains[index + 1].sampleId != callChain.sampleId) { + this.addProcessThreadStateData(callChain); + } + }); + } + + initCallChainTopDown(callChains: PerfCallChain[]) { + this.callChainData = {}; + callChains.forEach((callChain, index) => { + this.setCallChainName(callChain); + this.addGroupData(callChain); + let callChainDatum = this.callChainData[callChain.sampleId]; + if (callChainDatum.length > 1) { + PerfCallChain.setNextNode(callChainDatum[callChainDatum.length - 2], callChainDatum[callChainDatum.length - 1]); + } + }); + } + + setCallChainName(callChain: PerfCallChain) { + //设置调用栈的名称 + callChain.canCharge = true; + if (callChain.symbolId == -1) { + if (this.filesData[callChain.fileId] && this.filesData[callChain.fileId].length > 0) { + callChain.fileName = this.filesData[callChain.fileId][0].fileName; + callChain.path = this.filesData[callChain.fileId][0].path; + } else { + callChain.fileName = 'unkown'; + } + } else { + if (this.filesData[callChain.fileId] && this.filesData[callChain.fileId].length > callChain.symbolId) { + callChain.fileName = this.filesData[callChain.fileId][callChain.symbolId].fileName; + callChain.path = this.filesData[callChain.fileId][callChain.symbolId].path; + } else { + callChain.fileName = 'unkown'; + } + } + } + + addProcessThreadStateData(callChain: PerfCallChain) { + //当调用栈为调用的根节点时 + this.addPerfCallData(callChain); + let threadCallChain = new PerfCallChain(); //新增的线程数据 + threadCallChain.depth = 0; + PerfCallChain.merageCallChain(threadCallChain, callChain); + threadCallChain.canCharge = false; + threadCallChain.name = this.threadData[callChain.tid].threadName || 'Thead' + '(' + callChain.tid + ')'; + let threadStateCallChain = new PerfCallChain(); //新增的线程状态数据 + PerfCallChain.merageCallChain(threadStateCallChain, callChain); + threadStateCallChain.name = callChain.threadState || 'Unkown State'; + threadStateCallChain.fileName = threadStateCallChain.name == '-' ? 'Unkown Thead State' : ''; + threadStateCallChain.canCharge = false; + this.addGroupData(threadCallChain); + this.addGroupData(threadStateCallChain); + PerfCallChain.setNextNode(threadCallChain, threadStateCallChain); + PerfCallChain.setNextNode(threadStateCallChain, callChain); + } + + addPerfCallData(callChain: PerfCallChain) { + let perfCall = new PerfCall(); + perfCall.depth = this.callChainData[callChain.sampleId]?.length || 0; + perfCall.sampleId = callChain.sampleId; + perfCall.name = callChain.name; + this.callChainMap.set(callChain.sampleId, perfCall); + } + + addGroupData(callChain: PerfCallChain) { + this.callChainData[callChain.sampleId] = this.callChainData[callChain.sampleId] || []; + this.callChainData[callChain.sampleId].push(callChain); + } + + getCallChainsBySampleIds(sampleIds: string[], isTopDown: boolean) { + this.allProcess = this.groupNewTreeNoId(sampleIds, isTopDown); + return this.allProcess; + } + + addOtherCallchainData(countSample: PerfCountSample, list: any[]) { + let threadCallChain = new PerfCallChain(); //新增的线程数据 + threadCallChain.tid = countSample.tid; + threadCallChain.canCharge = false; + threadCallChain.name = this.threadData[countSample.tid].threadName || 'Thead' + '(' + countSample.tid + ')'; + let threadStateCallChain = new PerfCallChain(); //新增的线程状态数据 + threadStateCallChain.tid = countSample.tid; + threadStateCallChain.name = countSample.threadState || 'Unkown State'; + threadStateCallChain.fileName = threadStateCallChain.name == '-' ? 'Unkown Thead State' : ''; + threadStateCallChain.canCharge = false; + list.unshift(threadCallChain, threadStateCallChain); + } + + freshCurrentCallchains(samples: PerfCountSample[], isTopDown: boolean) { + this.currentTreeMapData = {}; + this.currentTreeList = []; + let totalCount = 0; + samples.forEach((sample) => { + totalCount += sample.count; + let callChains = [...this.callChainData[sample.sampleId]]; + this.addOtherCallchainData(sample, callChains); + let topIndex = isTopDown ? 0 : callChains.length - 1; + if (callChains.length > 0) { + let root = this.currentTreeMapData[callChains[topIndex].name + sample.pid]; + if (root == undefined) { + root = new PerfCallChainMerageData(); + this.currentTreeMapData[callChains[topIndex].name + sample.pid] = root; + this.currentTreeList.push(root); + } + PerfCallChainMerageData.merageCallChainSample(root, callChains[topIndex], sample, false); + this.merageChildrenByIndex(root, callChains, topIndex, sample, isTopDown); + } + }); + let rootMerageMap: any = {}; + // @ts-ignore + Object.values(this.currentTreeMapData).forEach((merageData: any) => { + if (rootMerageMap[merageData.pid] == undefined) { + let processMerageData = new PerfCallChainMerageData(); //新增进程的节点数据 + processMerageData.canCharge = false; + processMerageData.symbolName = this.threadData[merageData.tid].processName || `Process(${merageData.pid})`; + processMerageData.symbol = processMerageData.symbolName; + processMerageData.tid = merageData.tid; + processMerageData.children.push(merageData); + processMerageData.initChildren.push(merageData); + processMerageData.dur = merageData.dur; + processMerageData.count = merageData.dur; + processMerageData.total = totalCount; + rootMerageMap[merageData.pid] = processMerageData; + } else { + rootMerageMap[merageData.pid].children.push(merageData); + rootMerageMap[merageData.pid].initChildren.push(merageData); + rootMerageMap[merageData.pid].dur += merageData.dur; + rootMerageMap[merageData.pid].count += merageData.dur; + rootMerageMap[merageData.pid].total = totalCount; + } + merageData.parentNode = rootMerageMap[merageData.pid]; //子节点添加父节点的引用 + }); + let id = 0; + this.currentTreeList.forEach((node) => { + node.total = totalCount; + if (node.id == '') { + node.id = id + ''; + id++; + } + if (node.parentNode) { + if (node.parentNode.id == '') { + node.parentNode.id = id + ''; + id++; + } + node.parentId = node.parentNode.id; + } + }); + // @ts-ignore + this.allProcess = Object.values(rootMerageMap); + } + + merageChildrenByIndex( + currentNode: PerfCallChainMerageData, + callChainDataList: any[], + index: number, + sample: PerfCountSample, + isTopDown: boolean + ) { + isTopDown ? index++ : index--; + let isEnd = isTopDown ? callChainDataList.length == index + 1 : index == 0; + let node; + if ( + currentNode.initChildren.filter((child: PerfCallChainMerageData) => { + if (child.symbolName == callChainDataList[index]?.name) { + node = child; + PerfCallChainMerageData.merageCallChainSample(child, callChainDataList[index], sample, isEnd); + return true; + } + return false; + }).length == 0 + ) { + node = new PerfCallChainMerageData(); + PerfCallChainMerageData.merageCallChainSample(node, callChainDataList[index], sample, isEnd); + currentNode.children.push(node); + currentNode.initChildren.push(node); + this.currentTreeList.push(node); + node.parentNode = currentNode; + } + if (node && !isEnd) this.merageChildrenByIndex(node, callChainDataList, index, sample, isTopDown); + } + + groupNewTreeNoId(sampleIds: string[], isTopDown: boolean): any[] { + this.currentTreeMapData = {}; + this.currentTreeList = []; + for (let i = 0; i < sampleIds.length; i++) { + let callChains = this.callChainData[sampleIds[i]]; + if (callChains == undefined) continue; + let topIndex = isTopDown ? 0 : callChains.length - 1; + if (callChains.length > 0) { + let root = this.currentTreeMapData[callChains[topIndex].name + callChains[topIndex].pid]; + if (root == undefined) { + root = new PerfCallChainMerageData(); + this.currentTreeMapData[callChains[topIndex].name + callChains[topIndex].pid] = root; + this.currentTreeList.push(root); + } + PerfCallChainMerageData.merageCallChain(root, callChains[topIndex], isTopDown); + this.merageChildren(root, callChains[topIndex], isTopDown); + } + } + let rootMerageMap: any = {}; + // @ts-ignore + Object.values(this.currentTreeMapData).forEach((merageData: any) => { + if (rootMerageMap[merageData.pid] == undefined) { + let processMerageData = new PerfCallChainMerageData(); //新增进程的节点数据 + processMerageData.canCharge = false; + processMerageData.symbolName = this.threadData[merageData.tid].processName || `Process(${merageData.pid})`; + processMerageData.symbol = processMerageData.symbolName; + processMerageData.tid = merageData.tid; + processMerageData.children.push(merageData); + processMerageData.initChildren.push(merageData); + processMerageData.dur = merageData.dur; + processMerageData.count = merageData.dur; + processMerageData.total = sampleIds.length; + rootMerageMap[merageData.pid] = processMerageData; + } else { + rootMerageMap[merageData.pid].children.push(merageData); + rootMerageMap[merageData.pid].initChildren.push(merageData); + rootMerageMap[merageData.pid].dur += merageData.dur; + rootMerageMap[merageData.pid].count += merageData.dur; + rootMerageMap[merageData.pid].total = sampleIds.length; + } + merageData.parentNode = rootMerageMap[merageData.pid]; //子节点添加父节点的引用 + }); + let id = 0; + this.currentTreeList.forEach((node) => { + node.total = sampleIds.length; + if (node.id == '') { + node.id = id + ''; + id++; + } + if (node.parentNode) { + if (node.parentNode.id == '') { + node.parentNode.id = id + ''; + id++; + } + node.parentId = node.parentNode.id; + } + }); + // @ts-ignore + return Object.values(rootMerageMap); + } + + merageChildren(currentNode: PerfCallChainMerageData, callChain: any, isTopDown: boolean) { + let nextNodeKey = isTopDown ? 'nextNode' : 'previousNode'; + if (callChain[nextNodeKey] == undefined) return; + let node; + if ( + currentNode.initChildren.filter((child: PerfCallChainMerageData) => { + if (child.symbolName == callChain[nextNodeKey]?.name) { + node = child; + PerfCallChainMerageData.merageCallChain(child, callChain[nextNodeKey], isTopDown); + return true; + } + return false; + }).length == 0 + ) { + node = new PerfCallChainMerageData(); + PerfCallChainMerageData.merageCallChain(node, callChain[nextNodeKey], isTopDown); + currentNode.children.push(node); + currentNode.initChildren.push(node); + this.currentTreeList.push(node); + node.parentNode = currentNode; + } + if (node) this.merageChildren(node, callChain[nextNodeKey], isTopDown); + } + + //所有的操作都是针对整个树结构的 不区分特定的数据 + splitTree(data: PerfCallChainMerageData[], name: string, isCharge: boolean, isSymbol: boolean) { + data.forEach((process) => { + process.children = []; + if (isCharge) { + this.recursionChargeInitTree(process, name, isSymbol); + } else { + this.recursionPruneInitTree(process, name, isSymbol); + } + }); + this.resetAllNode(data); + } + + recursionChargeInitTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(node); + node.isStore++; + } + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionChargeInitTree(child, symbolName, isSymbol); + }); + } + } + + //symbol lib charge + recursionChargeTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && + node.currentTreeParentNode.children.splice( + node.currentTreeParentNode.children.indexOf(node), + 1, + ...node.children + ); + node.children.forEach((child) => { + child.currentTreeParentNode = node.currentTreeParentNode; + }); + } + if (node.children.length > 0) { + node.children.forEach((child) => { + this.recursionChargeTree(child, symbolName, isSymbol); + }); + } + } + + recursionPruneInitTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(node); + node.isStore++; + this.pruneChildren(node, symbolName); + } else if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionPruneInitTree(child, symbolName, isSymbol); + }); + } + } + + //symbol lib prune + recursionPruneTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && + node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1); + } else { + node.children.forEach((child) => { + this.recursionPruneTree(child, symbolName, isSymbol); + }); + } + } + + recursionChargeByRule( + node: PerfCallChainMerageData, + ruleName: string, + rule: (node: PerfCallChainMerageData) => boolean + ) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + if (rule(child)) { + (this.splitMapData[ruleName] = this.splitMapData[ruleName] || []).push(child); + child.isStore++; + } + this.recursionChargeByRule(child, ruleName, rule); + }); + } + } + + pruneChildren(node: PerfCallChainMerageData, symbolName: string) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + child.isStore++; + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(child); + this.pruneChildren(child, symbolName); + }); + } + } + + hideSystemLibrary() { + this.allProcess.forEach((item) => { + item.children = []; + this.recursionChargeByRule(item, this.systmeRuleName, (node) => { + return node.path.startsWith(this.systmeRuleName); + }); + }); + } + + hideNumMaxAndMin(startNum: number, endNum: string) { + let max = endNum == '∞' ? Number.POSITIVE_INFINITY : parseInt(endNum); + this.allProcess.forEach((item) => { + item.children = []; + this.recursionChargeByRule(item, this.numRuleName, (node) => { + return node.dur < startNum || node.dur > max; + }); + }); + } + + clearSplitMapData(symbolName: string) { + delete this.splitMapData[symbolName]; + } + + resotreAllNode(symbols: string[]) { + symbols.forEach((symbol) => { + let list = this.splitMapData[symbol]; + if (list != undefined) { + list.forEach((item: any) => { + item.isStore--; + }); + } + }); + } + + resetAllNode(data: PerfCallChainMerageData[]) { + this.clearSearchNode(); + data.forEach((process) => { + process.searchShow = true; + process.isSearch = false; + }); + this.resetNewAllNode(data); + if (this.searchValue != '') { + this.findSearchNode(data, this.searchValue, false); + this.resetNewAllNode(data); + } + } + + resetNewAllNode(data: PerfCallChainMerageData[]) { + data.forEach((process) => { + process.children = []; + }); + let values = this.currentTreeList.map((item: any) => { + item.children = []; + return item; + }); + values.forEach((item: any) => { + if (item.parentNode != undefined) { + if (item.isStore == 0 && item.searchShow) { + let parentNode = item.parentNode; + while (parentNode != undefined && !(parentNode.isStore == 0 && parentNode.searchShow)) { + parentNode = parentNode.parentNode; + } + if (parentNode) { + item.currentTreeParentNode = parentNode; + parentNode.children.push(item); + } + } + } + }); + } + + findSearchNode(data: PerfCallChainMerageData[], search: string, parentSearch: boolean) { + data.forEach((node) => { + if ((node.symbol && node.symbol.includes(search)) || parentSearch) { + node.searchShow = true; + let parentNode = node.currentTreeParentNode; + node.isSearch = node.symbol != undefined && node.symbol.includes(search); + while (parentNode != undefined && !parentNode.searchShow) { + parentNode.searchShow = true; + parentNode = parentNode.currentTreeParentNode; + } + } else { + node.searchShow = false; + node.isSearch = false; + } + if (node.children.length > 0) { + this.findSearchNode(node.children, search, node.searchShow); + } + }); + } + + clearSearchNode() { + this.currentTreeList.forEach((node) => { + node.searchShow = true; + node.isSearch = false; + }); + } + + splitAllProcess(list: any[]) { + list.forEach((item: any) => { + this.allProcess.forEach((process) => { + if (item.select == '0') { + this.recursionChargeInitTree(process, item.name, item.type == 'symbol'); + } else { + this.recursionPruneInitTree(process, item.name, item.type == 'symbol'); + } + }); + if (!item.checked) { + this.resotreAllNode([item.name]); + } + }); + } + + resolvingAction(params: any[]) { + if (params.length > 0) { + params.forEach((item) => { + if (item.funcName && item.funcArgs) { + switch (item.funcName) { + case 'getCallChainsBySampleIds': + this.freshCurrentCallchains(this.samplesData, item.funcArgs[0]); + break; + case 'getCurrentDataFromDb': + this.getCurrentDataFromDb(item.funcArgs[0]); + break; + case 'hideSystemLibrary': + this.hideSystemLibrary(); + break; + case 'hideNumMaxAndMin': + this.hideNumMaxAndMin(item.funcArgs[0], item.funcArgs[1]); + break; + case 'splitAllProcess': + this.splitAllProcess(item.funcArgs[0]); + break; + case 'resetAllNode': + this.resetAllNode(this.allProcess); + break; + case 'resotreAllNode': + this.resotreAllNode(item.funcArgs[0]); + break; + case 'clearSplitMapData': + this.clearSplitMapData(item.funcArgs[0]); + break; + case 'splitTree': + this.splitTree(this.allProcess, item.funcArgs[0], item.funcArgs[1], item.funcArgs[2]); + break; + case 'setSearchValue': + this.searchValue = item.funcArgs[0]; + break; + } + } + }); + this.dataSource = this.allProcess.filter((process) => { + return process.children && process.children.length > 0; + }); + } + return this.dataSource; + } + + perfAnalysisCallChain() { + let sampleCallChainMap = new Map(); + // @ts-ignore + for (const [sampleIdStr, callChains] of Object.entries(this.callChainData)) { + const sampleId = parseInt(sampleIdStr); + // @ts-ignore + const lastCallChain = callChains[callChains.length - 1]; + sampleCallChainMap.set(sampleId, lastCallChain); + } + return sampleCallChainMap; + } +} + +export class PerfFile { + fileId: number = 0; + symbol: string = ''; + path: string = ''; + fileName: string = ''; + + static setFileName(data: PerfFile) { + if (data.path) { + let number = data.path.lastIndexOf('/'); + if (number > 0) { + data.fileName = data.path.substring(number + 1); + return; + } + } + data.fileName = data.path; + } + + setFileName() { + if (this.path) { + let number = this.path.lastIndexOf('/'); + if (number > 0) { + this.fileName = this.path.substring(number + 1); + return; + } + } + this.fileName = this.path; + } +} + +export class PerfThread { + tid: number = 0; + pid: number = 0; + threadName: string = ''; + processName: string = ''; +} + +export class PerfCallChain { + tid: number = 0; + pid: number = 0; + name: string = ''; + fileName: string = ''; + threadState: string = ''; + startNS: number = 0; + dur: number = 0; + sampleId: number = 0; + callChainId: number = 0; + vaddrInFile: number = 0; + fileId: number = 0; + symbolId: number = 0; + path: string = ''; + count: number = 0; + parentId: string = ''; //合并之后区分的id + id: string = ''; + topDownMerageId: string = ''; //top down合并使用的id + topDownMerageParentId: string = ''; //top down合并使用的id + bottomUpMerageId: string = ''; //bottom up合并使用的id + bottomUpMerageParentId: string = ''; //bottom up合并使用的id + depth: number = 0; + canCharge: boolean = true; + previousNode: PerfCallChain | undefined = undefined; //将list转换为一个链表结构 + nextNode: PerfCallChain | undefined = undefined; + + static setNextNode(currentNode: PerfCallChain, nextNode: PerfCallChain) { + currentNode.nextNode = nextNode; + nextNode.previousNode = currentNode; + } + + static setPreviousNode(currentNode: PerfCallChain, prevNode: PerfCallChain) { + currentNode.previousNode = prevNode; + prevNode.nextNode = currentNode; + } + + static merageCallChain(currentNode: PerfCallChain, callChain: PerfCallChain) { + currentNode.startNS = callChain.startNS; + currentNode.tid = callChain.tid; + currentNode.pid = callChain.pid; + currentNode.sampleId = callChain.sampleId; + currentNode.dur = callChain.dur; + currentNode.count = callChain.count; + } +} + +export class PerfCallChainMerageData extends ChartStruct { + #parentNode: PerfCallChainMerageData | undefined = undefined; + #total = 0; + id: string = ''; + parentId: string = ''; + currentTreeParentNode: PerfCallChainMerageData | undefined = undefined; + symbolName: string = ''; + symbol: string = ''; + libName: string = ''; + path: string = ''; + self: string = '0s'; + weight: string = ''; + weightPercent: string = ''; + selfDur: number = 0; + dur: number = 0; + tid: number = 0; + pid: number = 0; + isStore = 0; + canCharge: boolean = true; + children: PerfCallChainMerageData[] = []; + initChildren: PerfCallChainMerageData[] = []; + type: number = 0; + vaddrInFile: number = 0; + isSelected: boolean = false; + searchShow: boolean = true; + isSearch: boolean = false; + set parentNode(data: PerfCallChainMerageData | undefined) { + this.currentTreeParentNode = data; + this.#parentNode = data; + } + + get parentNode() { + return this.#parentNode; + } + + set total(data: number) { + this.#total = data; + this.weight = `${timeMsFormat2p(this.dur * (ProcedureLogicWorkerPerf.cmdLineResult?.fValue || 1))}`; + this.weightPercent = `${((this.dur / data) * 100).toFixed(1)}%`; + } + + get total() { + return this.#total; + } + + static merageCallChain(currentNode: PerfCallChainMerageData, callChain: PerfCallChain, isTopDown: boolean) { + if (currentNode.symbolName == '') { + currentNode.symbol = `${callChain.name} ${callChain.fileName ? `(${callChain.fileName})` : ''}`; + currentNode.symbolName = callChain.name; + currentNode.pid = callChain.pid; + currentNode.tid = callChain.tid; + currentNode.libName = callChain.fileName; + currentNode.vaddrInFile = callChain.vaddrInFile; + currentNode.canCharge = callChain.canCharge; + if (callChain.path) { + currentNode.path = callChain.path; + } + } + if (callChain[isTopDown ? 'nextNode' : 'previousNode'] == undefined) { + currentNode.selfDur += callChain.count; + currentNode.self = timeMsFormat2p(currentNode.selfDur * (ProcedureLogicWorkerPerf.cmdLineResult?.fValue || 1)); + } + currentNode.dur += callChain.count; + currentNode.count += callChain.count; + } + + static merageCallChainSample( + currentNode: PerfCallChainMerageData, + callChain: PerfCallChain, + sample: PerfCountSample, + isEnd: boolean + ) { + if (currentNode.symbolName == '') { + currentNode.symbol = `${callChain.name} ${callChain.fileName ? `(${callChain.fileName})` : ''}`; + currentNode.symbolName = callChain.name; + currentNode.pid = sample.pid; + currentNode.tid = sample.tid; + currentNode.libName = callChain.fileName; + currentNode.vaddrInFile = callChain.vaddrInFile; + currentNode.canCharge = callChain.canCharge; + if (callChain.path) { + currentNode.path = callChain.path; + } + } + if (isEnd) { + currentNode.selfDur += sample.count; + currentNode.self = timeMsFormat2p(currentNode.selfDur * (ProcedureLogicWorkerPerf.cmdLineResult?.fValue || 1)); + } + currentNode.dur += sample.count; + currentNode.count += sample.count; + } +} + +export class PerfCountSample { + sampleId: number = 0; + tid: number = 0; + count: number = 0; + threadState: string = ''; + pid: number = 0; +} + +export class PerfStack { + symbol: string = ''; + path: string = ''; + fileId: number = 0; + type: number = 0; + vaddrInFile: number = 0; +} + +export class PerfCmdLine { + report_value: string = ''; +} + +export class PerfCall { + sampleId: number = 0; + depth: number = 0; + name: string = ''; +} + +export function timeMsFormat2p(ns: number) { + let currentNs = ns; + let hour1 = 3600_000; + let minute1 = 60_000; + let second1 = 1_000; // 1 second + let res = ''; + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1).toFixed(2) + 'h'; + return res; + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1).toFixed(2) + 'min'; + return res; + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1).toFixed(2) + 's'; + return res; + } + if (currentNs > 0) { + res += currentNs.toFixed(2) + 'ms'; + return res; + } + if (res == '') { + res = '0s'; + } + return res; +} diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSPT.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSPT.ts new file mode 100644 index 0000000000000000000000000000000000000000..66ecc6c8169fba72b0f710e09adc51c442e673e8 --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSPT.ts @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2022 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 { convertJSON, LogicHandler } from './ProcedureLogicWorkerCommon.js'; + +export class ProcedureLogicWorkerSPT extends LogicHandler { + arrTs: Array = []; + arrTp: Array = []; + currentEventId: string = ''; + + handle(data: any): void { + this.currentEventId = data.id; + if (data && data.type) { + switch (data.type) { + case 'spt-init': + this.getThreadState(); + break; + case 'spt-getThreadStateData': + this.arrTs = convertJSON(data.params.list) || []; + this.getThreadProcessData(); + break; + case 'spt-getThreadProcessData': + this.arrTp = convertJSON(data.params.list) || []; + this.initProcessThreadStateData(); + break; + } + } + } + + queryData(queryName: string, sql: string, args: any) { + self.postMessage({ + id: this.currentEventId, + type: queryName, + isQuery: true, + args: args, + sql: sql, + }); + } + + getThreadState() { + this.queryData( + 'spt-getThreadStateData', + ` + select itid, + state, + dur, + ts, + (ts - start_ts + dur) as end_ts, + (ts - start_ts) as start_ts, + cpu +from thread_state,trace_range where dur > 0 and (ts - start_ts) >= 0; +`, + {} + ); + } + + getThreadProcessData() { + this.queryData( + 'spt-getThreadProcessData', + ` + select A.id, + A.tid as threadId, + A.name as thread, + IP.pid as processId, + IP.name as process +from thread as A left join process as IP on A.ipid = IP.id +where IP.pid not null; +`, + {} + ); + } + + getSPT() { + this.queryData( + 'spt-getStatesProcessThreadData', + ` + select + IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur, + (B.ts - TR.start_ts + B.dur) as end_ts, + (B.ts - TR.start_ts) as start_ts, + B.cpu + from + thread_state as B + left join + thread as A + on + B.itid = A.id + left join + process as IP + on + A.ipid = IP.id + left join + trace_range as TR + where + B.dur > 0 + and + IP.pid not null + and (B.ts - TR.start_ts) >= 0; +`, + {} + ); + } + + initProcessThreadStateData() { + let mapTp: Map = new Map(); + for (let tp of this.arrTp) { + mapTp.set(tp.id, tp); + } + let sptArr: Array = []; + for (let tr of this.arrTs) { + if (mapTp.has(tr.itid)) { + let tp = mapTp.get(tr.itid); + let spt = new SPT(); + spt.processId = tp!.processId; + spt.process = tp!.process; + spt.thread = tp!.thread; + spt.threadId = tp!.threadId; + spt.state = tr.state; + spt.dur = tr.dur; + spt.end_ts = tr.end_ts; + spt.start_ts = tr.start_ts; + spt.cpu = tr.cpu; + sptArr.push(spt); + } + } + this.arrTp = []; + this.arrTs = []; + self.postMessage({ + id: this.currentEventId, + action: 'spt-init', + results: sptArr, + }); + } +} + +export class ThreadState { + itid: number = 0; + state: string = ''; + dur: number = 0; + ts: number = 0; + end_ts: number = 0; + start_ts: number = 0; + cpu: number = 0; +} + +export class ThreadProcess { + id: number = 0; + threadId: number = 0; + thread: string = ''; + processId: number = 0; + process: string = ''; +} + +export class SPT { + process: string = ''; + processId: number = 0; + thread: string = ''; + threadId: number = 0; + state: string = ''; + dur: number = 0; + start_ts: number = 0; + end_ts: number = 0; + cpu: number = 0; + priority: string = '-'; + note: string = '-'; +} diff --git a/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d6f551637a455af5a47c6c181dd016a4d85d5f0 --- /dev/null +++ b/ide/src/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.ts @@ -0,0 +1,885 @@ +/* + * Copyright (C) 2022 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 { convertJSON, getProbablyTime, LogicHandler } from './ProcedureLogicWorkerCommon.js'; + +export class ProcedureLogicWorkerSchedulingAnalysis extends LogicHandler { + currentEventId: string = ''; + endTs: number = 0; + startTs: number = 0; + totalDur: number = 0; + cpu: number = 0; + freq: number = 0; + bigCores: Array = []; + midCores: Array = []; + smallCores: Array = []; + cpuFreqMap: Map> = new Map>(); + cpuIdle0Map: Map> = new Map>(); + threadMap: Map = new Map(); + processMap: Map = new Map(); + cpuAnalysisMap: Map = new Map(); + + handle(data: any): void { + this.currentEventId = data.id; + if (data.params.endTs) { + this.endTs = data.params.endTs; + this.totalDur = data.params.total; + this.startTs = this.endTs - this.totalDur; + } + if (data && data.type) { + switch (data.type) { + case 'scheduling-clearData': + this.cpuAnalysisMap.clear(); + this.threadMap.clear(); + this.processMap.clear(); + this.cpuFreqMap.clear(); + this.cpuIdle0Map.clear(); + self.postMessage({ + id: data.id, + action: data.action, + results: [], + }); + break; + case 'scheduling-initFreqData': + if (data.params.list) { + this.groupFreqByCpu(convertJSON(data.params.list) || []); + self.postMessage({ + id: data.id, + action: data.action, + results: [], + }); + } else { + this.getCpuFrequency('scheduling-initFreqData'); + } + break; + case 'scheduling-getProcessAndThread': + if (data.params.list) { + let arr = convertJSON(data.params.list) || []; + this.handleProcessThread(arr); + self.postMessage({ + id: data.id, + action: data.action, + results: [], + }); + } else { + this.getProcessAndThread(); + } + break; + case 'scheduling-getCpuIdle0': + if (data.params.list) { + let arr = convertJSON(data.params.list) || []; + this.handleCPUIdle0Map(arr); + self.postMessage({ + id: data.id, + action: data.action, + results: [], + }); + } else { + this.getCpuIdle0(); + } + break; + case 'scheduling-getCpuUsage': + if (data.params.list) { + let arr = convertJSON(data.params.list) || []; + self.postMessage({ + id: data.id, + action: data.action, + results: arr, + }); + arr = []; + } else { + this.getCpuUsage(); + } + break; + case 'scheduling-CPU Frequency': + if (this.cpuAnalysisMap.has('freq')) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.cpuAnalysisMap.get('freq') || [], + }); + } else { + if (data.params.list) { + let res = this.computeCpuMeasureDur(convertJSON(data.params.list) || [], 'freq'); + this.cpuAnalysisMap.set('freq', res); + self.postMessage({ + id: data.id, + action: data.action, + results: res, + }); + } else { + this.getCpuFrequency('scheduling-CPU Frequency'); + } + } + break; + case 'scheduling-CPU Frequency Thread': + if (data.params.list) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.handlerFreqThreadData(convertJSON(data.params.list) || []), + }); + } else { + this.cpu = data.params.cpu; + this.freq = data.params.freq; + this.getThreadStateByCpu(data.params.cpu); + } + break; + case 'scheduling-CPU Idle': + if (this.cpuAnalysisMap.has('idle')) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.cpuAnalysisMap.get('idle') || [], + }); + } else { + if (data.params.list) { + let res = this.computeCpuMeasureDur(convertJSON(data.params.list) || []); + this.cpuAnalysisMap.set('idle', res); + self.postMessage({ + id: data.id, + action: data.action, + results: res, + }); + } else { + this.getCpuIdle(); + } + } + break; + case 'scheduling-CPU Irq': + if (this.cpuAnalysisMap.has('irq')) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.cpuAnalysisMap.get('irq') || [], + }); + } else { + if (data.params.list) { + let res = this.groupIrgDataByCpu(convertJSON(data.params.list) || []); + this.cpuAnalysisMap.set('irq', res); + self.postMessage({ + id: data.id, + action: data.action, + results: res, + }); + } else { + this.getCpuIrq(); + } + } + break; + case 'scheduling-Thread CpuUsage': + if (data.params.list) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.handlerThreadCpuUsageData(convertJSON(data.params.list) || []), + }); + } else { + this.bigCores = data.params.bigCores || []; + this.midCores = data.params.midCores || []; + this.smallCores = data.params.smallCores || []; + this.queryThreadCpuUsage( + data.params.bigCores || [], + data.params.midCores || [], + data.params.smallCores || [] + ); + } + break; + case 'scheduling-Thread RunTime': + if (data.params.list) { + let arr = convertJSON(data.params.list) || []; + self.postMessage({ + id: data.id, + action: data.action, + results: arr.map((it) => { + it.maxDurationStr = getProbablyTime(it.maxDuration); + it.pName = this.processMap.get(it.pid) || 'null'; + it.tName = this.threadMap.get(it.tid) || 'null'; + return it; + }), + }); + } else { + this.queryThreadRunTime(data.params.cpuMax); + } + break; + case 'scheduling-Process ThreadCount': + if (data.params.list) { + self.postMessage({ + id: data.id, + action: data.action, + results: convertJSON(data.params.list) || [], + }); + } else { + this.queryProcessThreadCount(); + } + break; + case 'scheduling-Process SwitchCount': + if (data.params.list) { + let arr = convertJSON(data.params.list) || []; + self.postMessage({ + id: data.id, + action: data.action, + results: arr.map((it) => { + it.pName = this.processMap.get(it.pid) || 'null'; + it.tName = this.threadMap.get(it.tid) || 'null'; + return it; + }), + }); + } else { + this.queryProcessSwitchCount(); + } + break; + case 'scheduling-Thread Freq': + if (data.params.list) { + self.postMessage({ + id: data.id, + action: data.action, + results: this.handlerThreadFreqData(convertJSON(data.params.list) || []), + }); + } else { + this.queryThreadStateByTid(data.params.tid); + } + break; + } + } + } + + queryData(queryName: string, sql: string, args: any) { + self.postMessage({ + id: this.currentEventId, + type: queryName, + isQuery: true, + args: args, + sql: sql, + }); + } + + getProcessAndThread() { + this.queryData( + 'scheduling-getProcessAndThread', + ` +select tid id,ifnull(name,'null') name,'t' type from thread +union all +select pid id,ifnull(name,'null') name,'p' type from process; + `, + {} + ); + } + + getCpuUsage() { + this.queryData( + 'scheduling-getCpuUsage', + ` +select cpu, + sum(case + when A.ts < B.start_ts + then (A.ts - B.start_ts + A.dur) + when A.ts >= B.start_ts + and (A.ts + A.dur) <= B.end_ts + then A.dur + when (A.ts + A.dur) > B.end_ts + then (B.end_ts - A.ts) end) / cast(B.end_ts - B.start_ts as float) as usage +from thread_state A, + trace_range B +where (A.ts - B.start_ts) > 0 + and A.dur > 0 + and (A.ts + A.dur) > B.start_ts + and cpu is not null + and A.ts < B.end_ts +group by cpu +order by cpu; +`, + {} + ); + } + + getCpuFrequency(name: string) { + this.queryData( + name, + ` +select cpu,value,ts,dur +from measure left join cpu_measure_filter cmf on measure.filter_id = cmf.id +where cmf.name = 'cpu_frequency' +order by cpu,ts; +`, + {} + ); + } + + getThreadStateByCpu(cpu: number) { + let sql = ` +select st.tid, + st.pid, + dur, + ts - tr.start_ts as ts +from thread_state st,trace_range tr +where cpu not null + and dur > 0 + and ts > tr.start_ts + and ts + st.dur < tr.end_ts + and cpu = ${cpu} +order by ts;`; + this.queryData('scheduling-CPU Frequency Thread', sql, {}); + } + + getCpuIdle0() { + this.queryData( + 'scheduling-getCpuIdle0', + ` +select cpu,value,ts,dur +from measure left join cpu_measure_filter cmf on measure.filter_id = cmf.id +where cmf.name = 'cpu_idle' and value = 0 +`, + {} + ); + } + + getCpuIdle() { + this.queryData( + 'scheduling-CPU Idle', + ` +select cpu,value,ts,dur +from measure left join cpu_measure_filter cmf on measure.filter_id = cmf.id +where cmf.name = 'cpu_idle' and value != 0 +`, + {} + ); + } + + getCpuIrq() { + this.queryData( + 'scheduling-CPU Irq', + ` + SELECT callid AS cpu, + CASE WHEN cat = 'ipi' THEN 'irq' ELSE cat END AS block, + CASE WHEN cat = 'ipi' THEN 'IPI' || name ELSE name END AS value, + sum( dur ) sum, + min( dur ) min, + max( dur ) max, + avg( dur ) avg + FROM + irq + WHERE + cat = 'ipi' + OR cat = 'softirq' + OR ( cat = 'irq' AND flag = '1' ) + GROUP BY + callid, + cat, + name;`, + {} + ); + } + + queryThreadCpuUsage(bigCores: number[], midCores: number[], smallCores: number[]) { + let sql = ` + select A.pid,A.tid,A.cpu, + sum(A.dur) as total +from thread_state A +where cpu not null +group by A.pid, A.tid,A.cpu`; + this.queryData('scheduling-Thread CpuUsage', sql, {}); + } + + queryThreadRunTime(cpuMax: number) { + let sql = ` + select (row_number() over (order by max(A.dur) desc)) no,A.tid, A.cpu,A.ts as timestamp,A.pid, max(A.dur) maxDuration + from thread_state A + where cpu not null + group by A.tid, A.pid + order by maxDuration desc + limit 20`; + this.queryData('scheduling-Thread RunTime', sql, {}); + } + + queryProcessThreadCount() { + this.queryData( + 'scheduling-Process ThreadCount', + ` +select row_number() over (order by count(tid) desc) NO,count(tid) threadNumber,p.pid,ifnull(p.name,'null') pName +from thread t +left join process p on t.ipid = p.ipid +group by p.pid, p.name +order by threadNumber desc limit 20;`, + {} + ); + } + + queryProcessSwitchCount() { + this.queryData( + 'scheduling-Process SwitchCount', + ` +select row_number() over (order by count(a.tid) desc) NO, + count(a.tid) as switchCount, + a.tid, + a.pid +from thread_state a +where cpu not null +group by a.pid,a.tid limit 20;`, + {} + ); + } + + queryThreadStateByTid(tid: number) { + let sql = ` +select cpu,dur,ts - tr.start_ts as ts +from thread_state st,trace_range tr +where cpu not null + and tid = ${tid} + and dur > 0 + and ts > tr.start_ts + and ts + st.dur < tr.end_ts + order by cpu,ts;`; + this.queryData('scheduling-Thread Freq', sql, {}); + } + + groupIrgDataByCpu(arr: Irq[]) { + //首先计算 每个频点的持续时间,并根据Cpu来分组 + let map: Map> = new Map>(); + let sumMap: Map = new Map(); + for (let i = 0, len = arr.length; i < len; i++) { + let ca = arr[i]; + if (map.has(ca.cpu)) { + map.get(ca.cpu)!.push(ca); + } else { + map.set(ca.cpu, [ca]); + } + sumMap.set(ca.cpu, (sumMap.get(ca.cpu) || 0) + ca.sum); + } + let target: Map = new Map(); + for (let key of map.keys()) { + let cpuArr = map + .get(key)! + .sort((a, b) => b.sum - a.sum) + .slice(0, 20); + target.set( + key, + cpuArr.map((it) => { + return { + cpu: it.cpu, + value: it.value, + sum: it.sum, + sumTimeStr: getProbablyTime(it.sum), + min: getProbablyTime(it.min), + max: getProbablyTime(it.max), + avg: getProbablyTime(it.avg), + minValue: it.min, + maxValue: it.max, + avgValue: it.avg, + ratio: ((it.sum / (sumMap.get(key) || 1)) * 100).toFixed(2), + block: it.block, + } as any; + }) + ); + } + return target; + } + + handleProcessThread(arr: { id: number; name: string; type: string }[]) { + this.processMap.clear(); + this.threadMap.clear(); + for (let pt of arr) { + if (pt.type === 'p') { + this.processMap.set(pt.id, pt.name); + } else { + this.threadMap.set(pt.id, pt.name); + } + } + } + + handleCPUIdle0Map(arr: CpuMeasure[]) { + this.cpuIdle0Map.clear(); + for (let i = 0, len = arr.length; i < len; i++) { + let ca = arr[i]; + ca.ts = ca.ts - this.startTs; + if (ca.dur === null || ca.dur === undefined) { + ca.dur = this.totalDur - ca.ts; + } + if (this.cpuIdle0Map.has(ca.cpu)) { + this.cpuIdle0Map.get(ca.cpu)!.push(ca); + } else { + this.cpuIdle0Map.set(ca.cpu, [ca]); + } + } + } + + getEffectiveFrequencyDur(m: CpuMeasure) { + let arr = this.cpuIdle0Map.get(m.cpu) || []; + let filterArr = []; + for (let it of arr) { + if (Math.min(m.ts + m.dur, it.ts + it.dur) - Math.max(m.ts, it.ts) > 0) { + filterArr.push(it); + } + if (it.ts > m.ts + m.dur) { + break; + } + } + let dur = 0; + for (let idle of filterArr) { + dur += Math.min(m.ts + m.dur, idle.ts + idle.dur) - Math.max(m.ts, idle.ts); + } + m.dur = dur; + } + + groupFreqByCpu(arr: CpuMeasure[]) { + let map: Map> = new Map>(); + for (let i = 0, len = arr.length; i < len; i++) { + let ca = arr[i]; + ca.ts = ca.ts - this.startTs; + if (ca.dur === null || ca.dur === undefined) { + ca.dur = this.totalDur - ca.ts; + } + if (ca.dur > 0) { + if (map.has(ca.cpu)) { + map.get(ca.cpu)!.push(ca); + } else { + map.set(ca.cpu, [ca]); + } + } + } + this.cpuFreqMap.clear(); + this.cpuFreqMap = map; + } + + //根据查询的数据,加工出CPU调度分析所需要展示的相关数据 + computeCpuMeasureDur(arr: Array, type?: string) { + //首先计算 每个频点的持续时间,并根据Cpu来分组 + let map: Map> = new Map>(); + let sumMap: Map = new Map(); + for (let i = 0, len = arr.length; i < len; i++) { + let ca = arr[i]; + ca.ts = ca.ts - this.startTs; + if (ca.dur === null || ca.dur === undefined) { + ca.dur = this.totalDur - ca.ts; + } + if (type === 'freq') { + this.getEffectiveFrequencyDur(ca); + } + if (ca.dur > 0) { + if (map.has(ca.cpu)) { + map.get(ca.cpu)!.push(ca); + } else { + map.set(ca.cpu, [ca]); + } + sumMap.set(ca.cpu, (sumMap.get(ca.cpu) || 0) + ca.dur); + } + } + //再根据频点值进行分组求和 + let target: Map = new Map(); + for (let key of map.keys()) { + let obj = map.get(key)!.reduce((group: any, ca) => { + const { value } = ca; + if (group[value]) { + group[value].sum = group[value].sum + ca.dur; + group[value].min = group[value].min < ca.dur ? group[value].min : ca.dur; + group[value].max = group[value].max > ca.dur ? group[value].max : ca.dur; + group[value].count = group[value].count + 1; + group[value].avg = (group[value].sum / group[value].count).toFixed(2); + } else { + group[value] = { + cpu: ca.cpu, + value: ca.value, + sum: ca.dur, + min: ca.dur, + max: ca.dur, + avg: ca.dur, + count: 1, + ratio: '', + block: ca.block, + }; + } + return group; + }, {}); + // @ts-ignore + let cpuArr = (Object.values(obj) as CpuAnalysis[]) + .sort((a, b) => { + if (type === 'freq') { + return b.sum - a.sum; + } else { + return a.value - b.value; + } + }) + .slice(0, 20); + target.set( + key, + cpuArr.map((it) => { + return { + cpu: it.cpu, + value: it.value, + sum: it.sum, + sumTimeStr: getProbablyTime(it.sum), + min: getProbablyTime(it.min), + minValue: it.min, + max: getProbablyTime(it.max), + maxValue: it.max, + avgValue: it.avg, + avg: getProbablyTime(it.avg), + count: it.count, + ratio: ((it.sum / (sumMap.get(key) || 1)) * 100).toFixed(2), + block: it.block, + } as any; + }) + ); + } + return target; + } + + handlerFreqThreadData(arr: FreqThread[]) { + let cpuFreqArr: CpuMeasure[] = (this.cpuFreqMap.get(this.cpu) || []).filter((it) => it.value === this.freq); + let map: Map< + number, + { + tid: number; + tName: string; + pid: number; + pName: string; + dur: number; + durStr: string; + ratio: string; + } + > = new Map< + number, + { + tid: number; + tName: string; + pid: number; + pName: string; + dur: number; + durStr: string; + ratio: string; + } + >(); + let sumFreqDur = 0; + cpuFreqArr.map((it) => { + sumFreqDur += it.dur; + let freqEndTs = it.ts + it.dur; + let threads = arr.filter((f) => Math.min(f.ts + f.dur, freqEndTs) - Math.max(f.ts, it.ts) > 0); + for (let tf of threads) { + let tfEndTs = tf.ts + tf.dur; + let dur = Math.min(tfEndTs, tfEndTs) - Math.max(it.ts, tf.ts); + if (map.has(tf.tid)) { + map.get(tf.tid)!.dur = map.get(tf.tid)!.dur + dur; + map.get(tf.tid)!.durStr = getProbablyTime(map.get(tf.tid)!.dur); + } else { + map.set(tf.tid, { + tid: tf.tid, + tName: this.threadMap.get(tf.tid) || 'null', + pid: tf.pid, + pName: this.processMap.get(tf.pid) || 'null', + dur: dur, + ratio: '0', + durStr: getProbablyTime(dur), + }); + } + } + }); + let target = Array.from(map.values()).sort((a, b) => b.dur - a.dur); + return target + .map((it) => { + it.ratio = ((it.dur / sumFreqDur) * 100).toFixed(2); + return it; + }) + .slice(0, 20); + } + + //加工Top20线程大中小核占用率数据 + handlerThreadCpuUsageData(arr: Array) { + let sumBig = 0, + sumMid = 0, + sumSmall = 0; + let reduceObj = arr.reduce((group: any, item) => { + const { tid } = item; + let tidObj: any = group[`${tid}`]; + let cpuType: string = 'mid'; + // @ts-ignore + if (this.bigCores.includes(item.cpu)) { + cpuType = 'big'; + sumBig += item.total; + } + // @ts-ignore + if (this.midCores.includes(item.cpu)) { + cpuType = 'mid'; + sumMid += item.total; + } + // @ts-ignore + if (this.smallCores.includes(item.cpu)) { + cpuType = 'small'; + sumSmall += item.total; + } + if (tidObj) { + tidObj.big += cpuType === 'big' ? item.total : 0; + tidObj.mid += cpuType === 'mid' ? item.total : 0; + tidObj.small += cpuType === 'small' ? item.total : 0; + tidObj.total += item.total; + tidObj[`cpu${item.cpu}`] = item.total; + } else { + group[`${tid}`] = { + pid: item.pid, + pName: this.processMap.get(item.pid) || 'null', + tid: item.tid, + tName: this.threadMap.get(item.tid) || 'null', + total: item.total, + big: cpuType === 'big' ? item.total : 0, + mid: cpuType === 'mid' ? item.total : 0, + small: cpuType === 'small' ? item.total : 0, + }; + group[`${tid}`][`cpu${item.cpu}`] = item.total; + } + return group; + }, {}); + // @ts-ignore + let source: any[] = Object.values(reduceObj) as any[]; + for (let obj of source) { + obj['bigPercent'] = sumBig === 0 ? '0' : ((obj.big / sumBig) * 100).toFixed(2); + obj['midPercent'] = sumMid === 0 ? '0' : ((obj.mid / sumMid) * 100).toFixed(2); + obj['smallPercent'] = sumSmall === 0 ? '0' : ((obj.small / sumSmall) * 100).toFixed(2); + obj['bigTimeStr'] = getProbablyTime(obj.big); + obj['midTimeStr'] = getProbablyTime(obj.mid); + obj['smallTimeStr'] = getProbablyTime(obj.small); + } + let map: Map> = new Map>(); + map.set('total', source.sort((a, b) => b.total - a.total).slice(0, 20)); + map.set('big', source.sort((a, b) => b.big - a.big).slice(0, 20)); + map.set('mid', source.sort((a, b) => b.mid - a.mid).slice(0, 20)); + map.set('small', source.sort((a, b) => b.small - a.small).slice(0, 20)); + return map; + } + + handlerThreadFreqData( + arr: { + cpu: number; + dur: number; + ts: number; + freqArr: { cpu: number; freq: number; dur: number }[]; + }[] + ) { + let sumDur: number = 0; + arr.map((it) => { + it.freqArr = []; + let itEndTs = it.ts + it.dur; + let freqArr: CpuMeasure[] = this.cpuFreqMap.get(it.cpu) || []; + let threadFreqArr = freqArr.filter( + (f) => + (it.ts >= f.ts && it.ts <= f.ts + f.dur) || + (it.ts <= f.ts && itEndTs >= f.ts + f.dur) || + (itEndTs > f.ts && itEndTs <= f.ts + f.dur) + ); + for (let tf of threadFreqArr) { + let tfEndTs = tf.ts + tf.dur; + it.freqArr.push({ + cpu: it.cpu, + freq: tf.value as number, + dur: Math.min(itEndTs, tfEndTs) - Math.max(it.ts, tf.ts), + }); + } + sumDur += it.dur; + return it; + }); + let obj: any = arr.reduce((group: any, tf) => { + for (let fa of tf.freqArr) { + const { cpu, freq } = fa; + if (group[`${cpu}-${freq}`]) { + group[`${cpu}-${freq}`].time = group[`${cpu}-${freq}`].time + fa.dur; + group[`${cpu}-${freq}`].timeStr = getProbablyTime(group[`${cpu}-${freq}`].time); + group[`${cpu}-${freq}`].ratio = ((group[`${cpu}-${freq}`].time / sumDur) * 100).toFixed(2); + } else { + group[`${cpu}-${freq}`] = { + freq: freq, + cpu: cpu, + time: fa.dur, + timeStr: getProbablyTime(fa.dur), + ratio: ((fa.dur / sumDur) * 100).toFixed(2), + totalDur: sumDur, + }; + } + } + return group; + }, {}); + let target: { + cpu: number; + freq: number; + time: number; + ratio: string; + totalDur: number; + // @ts-ignore + }[] = Object.values(obj); + return target.sort((a, b) => b.time - a.time); + } +} + +export class CpuUsage { + cpu: number = 0; + usage: number = 0; +} + +export class Irq { + cpu: number = 0; + value: string = ''; + block: string = ''; + max: number = 0; + min: number = 0; + avg: number = 0; + sum: number = 0; + ratio: string = ''; +} + +export class CpuMeasure { + cpu: number = 0; + value: number | string = 0; + block: string = ''; + ts: number = 0; + dur: number = 0; +} + +export class CpuAnalysis { + cpu: number = 0; + value: number = 0; + sum: number = 0; + min: number = 0; + max: number = 0; + avg: number = 0; + count: number = 0; + ratio: string = ''; + block: string = ''; +} + +export class ThreadCpuUsage { + cpu: number = 0; + pid: number = 0; + pName: string = ''; + tid: number = 0; + tName: string = ''; + total: number = 0; + big: number = 0; + mid: number = 0; + small: number = 0; + bigPercent: string = ''; + bigTimeStr: string = ''; + midPercent: string = ''; + midTimeStr: string = ''; + smallPercent: string = ''; + smallTimeStr: string = ''; +} + +export class FreqThread { + pid: number = 0; + pName: string = ''; + tid: number = 0; + tName: string = ''; + dur: number = 0; + durStr: string = ''; + ts: number = 0; + freq: number = 0; +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorker.ts b/ide/src/trace/database/ui-worker/ProcedureWorker.ts new file mode 100644 index 0000000000000000000000000000000000000000..14614a7d100d2dc4664b8879c4b6bf28b0b2a642 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorker.ts @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2022 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 { CpuRender, EmptyRender } from './ProcedureWorkerCPU.js'; +import { RequestMessage } from './ProcedureWorkerCommon.js'; +import { FreqRender } from './ProcedureWorkerFreq.js'; +import { ProcessRender } from './ProcedureWorkerProcess.js'; +import { MemRender } from './ProcedureWorkerMem.js'; +import { ThreadRender } from './ProcedureWorkerThread.js'; +import { FuncRender } from './ProcedureWorkerFunc.js'; +import { FpsRender } from './ProcedureWorkerFPS.js'; +import { HeapRender, NativeMemoryRender } from './ProcedureWorkerHeap.js'; +import { CpuAbilityRender } from './ProcedureWorkerCpuAbility.js'; +import { MemoryAbilityRender } from './ProcedureWorkerMemoryAbility.js'; +import { DiskIoAbilityRender } from './ProcedureWorkerDiskIoAbility.js'; +import { NetworkAbilityRender } from './ProcedureWorkerNetworkAbility.js'; +import { HiperfCpuRender } from './ProcedureWorkerHiPerfCPU.js'; +import { HiperfProcessRender } from './ProcedureWorkerHiPerfProcess.js'; +import { HiperfThreadRender } from './ProcedureWorkerHiPerfThread.js'; +import { HiperfEventRender } from './ProcedureWorkerHiPerfEvent.js'; +import { HiperfReportRender } from './ProcedureWorkerHiPerfReport.js'; +import { VirtualMemoryRender } from './ProcedureWorkerVirtualMemory.js'; +import { FileSystemRender } from './ProcedureWorkerFileSystem.js'; +import { info } from '../../../log/Log.js'; +import { SdkSliceRender } from './ProduceWorkerSdkSlice.js'; +import { SdkCounterRender } from './ProduceWorkerSdkCounter.js'; +import { CpuStateRender } from './ProcedureWorkerCpuState.js'; +import { EnergyAnomalyRender } from './ProcedureWorkerEnergyAnomaly.js'; +import { EnergySystemRender } from './ProcedureWorkerEnergySystem.js'; +import { EnergyPowerRender } from './ProcedureWorkerEnergyPower.js'; +import { EnergyStateRender } from './ProcedureWorkerEnergyState.js'; +import { SmapsRender } from './ProcedureWorkerSmaps.js'; +import { CpuFreqLimitRender } from './ProcedureWorkerCpuFreqLimits.js'; +import { ClockRender } from './ProcedureWorkerClock.js'; +import { IrqRender } from './ProcedureWorkerIrq.js'; +import { JankRender } from './ProcedureWorkerJank.js'; +import { HeapTimelineRender } from './ProcedureWorkerHeapTimeline.js'; +import { HeapSnapshotRender } from './ProcedureWorkerHeapSnapshot.js'; + +let dataList: any = {}; +let dataList2: any = {}; +let dataFilter: any = {}; +let canvasList: any = {}; +let contextList: any = {}; +export let renders: any = { + 'cpu-data': new CpuRender(), + 'cpu-state': new CpuStateRender(), + 'cpu-limit-freq': new CpuFreqLimitRender(), + fps: new FpsRender(), + freq: new FreqRender(), + empty: new EmptyRender(), + 'virtual-memory-folder': new EmptyRender(), + 'virtual-memory-cell': new VirtualMemoryRender(), + 'file-system-group': new EmptyRender(), + 'file-system-cell': new FileSystemRender(), + process: new ProcessRender(), + heap: new HeapRender(), + heapTimeline: new HeapTimelineRender(), + heapSnapshot: new HeapSnapshotRender(), + mem: new MemRender(), + thread: new ThreadRender(), + func: new FuncRender(), + native: new NativeMemoryRender(), + 'HiPerf-Group': new EmptyRender(), + monitorGroup: new EmptyRender(), + 'HiPerf-Cpu': new HiperfCpuRender(), + 'HiPerf-Process': new HiperfProcessRender(), + 'HiPerf-Thread': new HiperfThreadRender(), + 'HiPerf-Report-Event': new HiperfEventRender(), + 'HiPerf-Report-Fold': new HiperfReportRender(), + monitorCpu: new CpuAbilityRender(), + monitorMemory: new MemoryAbilityRender(), + monitorDiskIo: new DiskIoAbilityRender(), + monitorNetwork: new NetworkAbilityRender(), + 'sdk-slice': new SdkSliceRender(), + 'sdk-counter': new SdkCounterRender(), + energyAnomaly: new EnergyAnomalyRender(), + energySystem: new EnergySystemRender(), + energyPower: new EnergyPowerRender(), + energyState: new EnergyStateRender(), + smaps: new SmapsRender(), + clock: new ClockRender(), + irq: new IrqRender(), + jank: new JankRender(), +}; + +function match(type: string, req: RequestMessage) { + Reflect.ownKeys(renders).filter((it) => { + if (type.startsWith(it as string)) { + if (dataList[type]) { + req.lazyRefresh = dataList[type].length > 20000; + } + renders[it].render(req, dataList[type], dataFilter[type], dataList2); + } + }); +} + +let dec = new TextDecoder(); +let convertJSON = (arr: any) => { + if (arr instanceof ArrayBuffer) { + let jsonArray = []; + let str = dec.decode(new Uint8Array(arr)); + str = str.substring(str.indexOf('\n') + 1); + if (!str) { + } else { + let parse = JSON.parse(translateJsonString(str)); + let columns = parse.columns; + let values = parse.values; + for (let i = 0; i < values.length; i++) { + let obj: any = {}; + for (let j = 0; j < columns.length; j++) { + obj[columns[j]] = values[i][j]; + } + jsonArray.push(obj); + } + } + return jsonArray; + } else { + return arr; + } +}; +self.onmessage = function (e: any) { + if ((e.data.type as string).startsWith('clear')) { + dataList = {}; + dataList2 = {}; + dataFilter = {}; + canvasList = {}; + contextList = {}; + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: e.data.type, + results: null, + }); + return; + } + if (e.data.params.list) { + dataList[e.data.type] = convertJSON(e.data.params.list); + if (e.data.params.offscreen) { + canvasList[e.data.type] = e.data.params.offscreen; + contextList[e.data.type] = e.data.params.offscreen!.getContext('2d'); + contextList[e.data.type].scale(e.data.params.dpr, e.data.params.dpr); + } + } + if (!dataFilter[e.data.type]) { + dataFilter[e.data.type] = []; + } + let req = new RequestMessage(); + req.canvas = canvasList[e.data.type]; + req.context = contextList[e.data.type]; + req.type = e.data.type as string; + req.params = e.data.params; + req.online = e.data.params.online; + req.buf = e.data.params.buf; + req.isRangeSelect = e.data.params.isRangeSelect; + req.isHover = e.data.params.isHover; + req.xs = e.data.params.xs; + req.frame = e.data.params.frame; + req.flagMoveInfo = e.data.params.flagMoveInfo; + req.flagSelectedInfo = e.data.params.flagSelectedInfo; + req.hoverX = e.data.params.hoverX; + req.hoverY = e.data.params.hoverY; + req.startNS = e.data.params.startNS; + req.endNS = e.data.params.endNS; + req.totalNS = e.data.params.totalNS; + req.slicesTime = e.data.params.slicesTime; + req.range = e.data.params.range; + req.scale = e.data.params.scale; + req.canvasWidth = e.data.params.canvasWidth; + req.canvasHeight = e.data.params.canvasHeight; + req.useCache = e.data.params.useCache; + req.lineColor = e.data.params.lineColor; + req.chartColor = e.data.params.chartColor; + req.wakeupBean = e.data.params.wakeupBean; + req.intervalPerf = e.data.params.intervalPerf; + req.id = e.data.id; + if (!req.frame) { + info(req.frame); + return; + } + if (req.canvas) { + if (req.canvas.width !== req.canvasWidth || req.canvas.height !== req.canvasHeight) { + req.canvas.width = req.canvasWidth; + req.canvas.height = req.canvasHeight; + req.context.scale(e.data.params.dpr, e.data.params.dpr); + } + } + match(req.type, req); +}; +self.onmessageerror = function (e: any) {}; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerCPU.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerCPU.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4bbb893d6d176f430a32b6c656d647ffdcb9c48 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerCPU.ts @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class EmptyRender extends Render { + renderMainThread(req: any, row: TraceRow) { + req.context.beginPath(); + req.context.closePath(); + } + render(req: RequestMessage, list: Array, filter: Array) { + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: null, + }); + } +} + +export class CpuRender { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + translateY: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startTime', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + req.context.font = '11px sans-serif'; + filter.forEach((re) => { + re.translateY = req.translateY; + CpuStruct.draw(req.context, re, req.translateY); + }); + req.context.closePath(); + let currentCpu = parseInt(req.type!.replace('cpu-data-', '')); + drawWakeUp( + req.context, + CpuStruct.wakeupBean, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.type == `cpu-data-${CpuStruct.selectCpuStruct?.cpu || 0}` ? CpuStruct.selectCpuStruct : undefined, + currentCpu + ); + } + + render(req: RequestMessage, list: Array, filter: Array, translateY: number) { + if (req.lazyRefresh) { + this.cpu(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + this.cpu(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startTime, + arr[arr.length - 1].startTime + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + CpuStruct.hoverCpuStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + CpuStruct.hoverCpuStruct = re; + break; + } + } + } else { + CpuStruct.hoverCpuStruct = req.params.hoverCpuStruct; + } + CpuStruct.selectCpuStruct = req.params.selectCpuStruct; + req.context.font = '11px sans-serif'; + for (let re of filter) { + CpuStruct.draw(req.context, re, translateY); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: CpuStruct.hoverCpuStruct, + }); + } + + cpu(list: Array, res: Array, startNS: number, endNS: number, totalNS: number, frame: any, use: boolean) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y + 5; + let height = frame.height - 10; + for (let i = 0, len = res.length; i < len; i++) { + let it = res[i]; + if ((it.startTime || 0) + (it.dur || 0) > startNS && (it.startTime || 0) < endNS) { + if (!res[i].frame) { + res[i].frame = {}; + res[i].frame.y = y; + res[i].frame.height = height; + } + CpuStruct.setCpuFrame(res[i], pns, startNS, endNS, frame); + } else { + res[i].frame = null; + } + } + return; + } + if (list) { + res.length = 0; + let pns = (endNS - startNS) / frame.width; //每个像素多少ns + let y = frame.y + 5; + let height = frame.height - 10; + let left = 0, + right = 0; + for (let i = 0, j = list.length - 1, ib = true, jb = true; i < list.length, j >= 0; i++, j--) { + if (list[j].startTime <= endNS && jb) { + right = j; + jb = false; + } + if (list[i].startTime + list[i].dur >= startNS && ib) { + left = i; + ib = false; + } + if (!ib && !jb) { + break; + } + } + let slice = list.slice(left, right + 1); + let sum = 0; + for (let i = 0; i < slice.length; i++) { + if (!slice[i].frame) { + slice[i].frame = {}; + slice[i].frame.y = y; + slice[i].frame.height = height; + } + if (slice[i].dur >= pns) { + slice[i].v = true; + CpuStruct.setCpuFrame(slice[i], pns, startNS, endNS, frame); + } else { + if (i > 0) { + let c = slice[i].startTime - slice[i - 1].startTime - slice[i - 1].dur; + if (c < pns && sum < pns) { + sum += c + slice[i - 1].dur; + slice[i].v = false; + } else { + slice[i].v = true; + CpuStruct.setCpuFrame(slice[i], pns, startNS, endNS, frame); + sum = 0; + } + } + } + } + res.push(...slice.filter((it) => it.v)); + } + } +} + +export class CpuStruct extends BaseStruct { + static cpuCount: number = 1; //最大cpu数量 + static hoverCpuStruct: CpuStruct | undefined; + static selectCpuStruct: CpuStruct | undefined; + static wakeupBean: WakeupBean | null | undefined = null; + cpu: number | undefined; + dur: number | undefined; + end_state: string | undefined; + id: number | undefined; + name: string | undefined; + priority: number | undefined; + processCmdLine: string | undefined; + processId: number | undefined; + processName: string | undefined; + displayProcess: string | undefined; + displayThread: string | undefined; + measurePWidth: number = 0; + measureTWidth: number = 0; + startTime: number | undefined; + tid: number | undefined; + argSetID: number | undefined; + type: string | undefined; + v: boolean = false; + nofinish: boolean = false; + static draw(ctx: CanvasRenderingContext2D, data: CpuStruct, translateY: number) { + if (data.frame) { + let width = data.frame.width || 0; + if (data.tid === CpuStruct.hoverCpuStruct?.tid || !CpuStruct.hoverCpuStruct) { + ctx.globalAlpha = 1; + ctx.fillStyle = ColorUtils.colorForTid((data.processId || 0) > 0 ? data.processId || 0 : data.tid || 0); + } else if (data.processId === CpuStruct.hoverCpuStruct?.processId) { + ctx.globalAlpha = 0.6; + ctx.fillStyle = ColorUtils.colorForTid((data.processId || 0) > 0 ? data.processId || 0 : data.tid || 0); + } else { + ctx.globalAlpha = 1; + ctx.fillStyle = '#e0e0e0'; + } + ctx.fillRect(data.frame.x, data.frame.y, width, data.frame.height); + ctx.globalAlpha = 1; + let textFillWidth = width - textPadding * 2; + if (textFillWidth > 3) { + if (data.displayProcess === undefined) { + data.displayProcess = `${data.processName || 'Process'} [${data.processId}]`; + data.measurePWidth = ctx.measureText(data.displayProcess).width; + } + if (data.displayThread === undefined) { + data.displayThread = `${data.name || 'Thread'} [${data.tid}] [Prio:${data.priority || 0}]`; + data.measureTWidth = ctx.measureText(data.displayThread).width; + } + let processCharWidth = Math.round(data.measurePWidth / data.displayProcess.length); + let threadCharWidth = Math.round(data.measureTWidth / data.displayThread.length); + ctx.fillStyle = '#ffffff'; + let y = data.frame.height / 2 + data.frame.y; + if (data.measurePWidth < textFillWidth) { + let x1 = Math.floor(width / 2 - data.measurePWidth / 2 + data.frame.x + textPadding); + ctx.textBaseline = 'bottom'; + ctx.fillText(data.displayProcess, x1, y, textFillWidth); + } else { + if (textFillWidth >= processCharWidth) { + let chatNum = textFillWidth / processCharWidth; + let x1 = data.frame.x + textPadding; + ctx.textBaseline = 'bottom'; + if (chatNum < 2) { + ctx.fillText(data.displayProcess.substring(0, 1), x1, y, textFillWidth); + } else { + ctx.fillText(data.displayProcess.substring(0, chatNum - 1) + '...', x1, y, textFillWidth); + } + } + } + ctx.fillStyle = '#ffffff'; + ctx.font = '9px sans-serif'; + if (data.measureTWidth < textFillWidth) { + ctx.textBaseline = 'top'; + let x2 = Math.floor(width / 2 - data.measureTWidth / 2 + data.frame.x + textPadding); + ctx.fillText(data.displayThread, x2, y + 2, textFillWidth); + } else { + if (textFillWidth >= threadCharWidth) { + let chatNum = textFillWidth / threadCharWidth; + let x1 = data.frame.x + textPadding; + ctx.textBaseline = 'top'; + if (chatNum < 2) { + ctx.fillText(data.displayThread.substring(0, 1), x1, y + 2, textFillWidth); + } else { + ctx.fillText(data.displayThread.substring(0, chatNum - 1) + '...', x1, y + 2, textFillWidth); + } + } + } + } + if (data.nofinish && width > 4) { + ctx.fillStyle = '#FFFFFF'; + let ruptureWidth = 4; + let ruptureNode = 8; + ctx.moveTo(data.frame.x + data.frame.width - 1, data.frame.y); + for (let i = 1; i <= ruptureNode; i++) { + ctx.lineTo( + data.frame.x + data.frame.width - 1 - (i % 2 == 0 ? 0 : ruptureWidth), + data.frame.y + (data.frame.height / ruptureNode) * i + ); + } + ctx.closePath(); + ctx.fill(); + } + if (CpuStruct.selectCpuStruct && CpuStruct.equals(CpuStruct.selectCpuStruct, data)) { + ctx.strokeStyle = '#232c5d'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y, width - 2, data.frame.height); + } + } + } + + static setCpuFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startTime || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startTime || 0) - startNS) / pns); + } + if ((node.startTime || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startTime || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static equals(d1: CpuStruct, d2: CpuStruct): boolean { + return ( + d1 && + d2 && + d1.cpu == d2.cpu && + d1.tid == d2.tid && + d1.processId == d2.processId && + d1.startTime == d2.startTime && + d1.dur == d2.dur + ); + } +} + +export class WakeupBean { + wakeupTime: number | undefined; + cpu: number | undefined; + process: string | undefined; + pid: number | undefined; + thread: string | undefined; + tid: number | undefined; + schedulingLatency: number | undefined; + schedulingDesc: string | undefined; +} + +const textPadding = 2; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerClock.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerClock.ts new file mode 100644 index 0000000000000000000000000000000000000000..485a4f3d3567c88f5e40f3aa3541039b50471c0d --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerClock.ts @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 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 { BaseStruct, dataFilterHandler, isFrameContainPoint, Render } from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { ColorUtils } from '../../component/trace/base/ColorUtils.js'; + +export class ClockRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxValue: number; + index: number; + maxName: string; + }, + row: TraceRow + ) { + ClockStruct.index = req.index; + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + ClockStruct.draw(req.context, re, req.maxValue); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + ClockStruct.hoverClockStruct = re; + find = true; + } + } + if (!find && row.isHover) ClockStruct.hoverClockStruct = undefined; + req.context.closePath(); + let s = req.maxName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } +} + +export class ClockStruct extends BaseStruct { + static maxValue: number = 0; + static maxName: string = ''; + static hoverClockStruct: ClockStruct | undefined; + static selectClockStruct: ClockStruct | undefined; + static index = 0; + filterId: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; //自补充,数据库没有返回 + delta: number | undefined; //自补充,数据库没有返回 + + static draw(ctx: CanvasRenderingContext2D, data: ClockStruct, maxValue: number) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = ColorUtils.colorForTid(ClockStruct.index); + ctx.strokeStyle = ColorUtils.colorForTid(ClockStruct.index); + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxValue); + if (drawHeight === 0) { + drawHeight = 1; + } + if (ClockStruct.isHover(data)) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } + + static isHover(clock: ClockStruct) { + return clock === ClockStruct.hoverClockStruct || clock === ClockStruct.selectClockStruct; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerCommon.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerCommon.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef2d50b75e996007af680ca6a70cf0083bbb8e70 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerCommon.ts @@ -0,0 +1,737 @@ +/* + * Copyright (C) 2022 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 { CpuStruct, WakeupBean } from './ProcedureWorkerCPU.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { TimerShaftElement } from '../../component/trace/TimerShaftElement'; +import { TimeRange } from '../../component/trace/timer-shaft/RangeRuler'; + +export abstract class Render { + abstract renderMainThread(req: any, row: TraceRow): void; +} + +export abstract class PerfRender { + abstract render(req: RequestMessage, list: Array, filter: Array, dataList2: Array): void; +} + +export class RequestMessage { + type: string | undefined | null; + lazyRefresh: boolean | undefined; + intervalPerf: any; + canvas: any; + context: any; + params: any; + online: any; + buf: any; + isRangeSelect: any; + isHover: any; + xs: any; + frame: any; + flagMoveInfo: any; + flagSelectedInfo: any; + hoverX: any; + hoverY: any; + startNS: any; + endNS: any; + totalNS: any; + slicesTime: + | { + startTime: number | null; + endTime: number | null; + color: string | null; + } + | undefined; + range: any; + scale: any; + chartColor: any; + canvasWidth: any; + canvasHeight: any; + useCache: any; + lineColor: any; + wakeupBean: WakeupBean | undefined | null; + id: any; + postMessage: + | { + (message: any, targetOrigin: string, transfer?: Transferable[]): void; + (message: any, options?: WindowPostMessageOptions): void; + } + | undefined; +} + +export function ns2s(ns: number): string { + let second1 = 1_000_000_000; // 1 second + let millisecond1 = 1_000_000; // 1 millisecond + let microsecond1 = 1_000; // 1 microsecond + let nanosecond1 = 1000.0; + let res; + if (ns >= second1) { + res = (ns / 1000 / 1000 / 1000).toFixed(1) + ' s'; + } else if (ns >= millisecond1) { + res = (ns / 1000 / 1000).toFixed(1) + ' ms'; + } else if (ns >= microsecond1) { + res = (ns / 1000).toFixed(1) + ' μs'; + } else if (ns > 0) { + res = ns.toFixed(1) + ' ns'; + } else { + res = ns.toFixed(1) + ' s'; + } + return res; +} + +export function isFrameContainPoint(frame: Rect, x: number, y: number): boolean { + return x >= frame.x && x <= frame.x + frame.width && y >= frame.y && y <= frame.y + frame.height; +} + +class FilterConfig { + startNS: number = 0; + endNS: number = 0; + totalNS: number = 0; + frame: any = null; + useCache: boolean = false; + startKey: string = 'startNS'; + durKey: string = 'dur'; + paddingTop: number = 0; +} + +export function fillCacheData(filterData: Array, condition: FilterConfig): boolean { + if (condition.useCache && filterData.length > 0) { + let pns = (condition.endNS - condition.startNS) / condition.frame.width; + let y = condition.frame.y + condition.paddingTop; + let height = condition.frame.height - condition.paddingTop * 2; + for (let i = 0, len = filterData.length; i < len; i++) { + let it = filterData[i]; + if ( + (it[condition.startKey] || 0) + (it[condition.durKey] || 0) > condition.startNS && + (it[condition.startKey] || 0) < condition.endNS + ) { + if (!filterData[i].frame) { + filterData[i].frame = {}; + filterData[i].frame.y = y; + filterData[i].frame.height = height; + } + setNodeFrame( + filterData[i], + pns, + condition.startNS, + condition.endNS, + condition.frame, + condition.startKey, + condition.durKey + ); + } else { + filterData[i].frame = null; + } + } + return true; + } + return false; +} + +export function findRange(fullData: Array, condition: FilterConfig): Array { + let left = 0, + right = 0; + for (let i = 0, j = fullData.length - 1, ib = true, jb = true; i < fullData.length, j >= 0; i++, j--) { + if (fullData[j][condition.startKey] <= condition.endNS && jb) { + right = j; + jb = false; + } + if (fullData[i][condition.startKey] + fullData[i][condition.durKey] >= condition.startNS && ib) { + left = i; + ib = false; + } + if (!ib && !jb) { + break; + } + } + let slice = fullData.slice(left, right + 1); + return slice; +} + +export function dataFilterHandler(fullData: Array, filterData: Array, condition: FilterConfig) { + if (fillCacheData(filterData, condition)) return; + if (fullData) { + filterData.length = 0; + let pns = (condition.endNS - condition.startNS) / condition.frame.width; //每个像素多少ns + let y = condition.frame.y + condition.paddingTop; + let height = condition.frame.height - condition.paddingTop * 2; + let slice = findRange(fullData, condition); + let sum = 0; + for (let i = 0; i < slice.length; i++) { + if (!slice[i].frame) { + slice[i].frame = {}; + slice[i].frame.y = y; + slice[i].frame.height = height; + } + if (i === slice.length - 1) { + if (slice[i][condition.durKey] === undefined || slice[i][condition.durKey] === null) { + slice[i][condition.durKey] = (condition.endNS || 0) - (slice[i][condition.startKey] || 0); + } + } else { + if (slice[i][condition.durKey] === undefined || slice[i][condition.durKey] === null) { + slice[i][condition.durKey] = (slice[i + 1][condition.startKey] || 0) - (slice[i][condition.startKey] || 0); + } + } + if (slice[i][condition.durKey] >= pns || slice.length < 100) { + slice[i].v = true; + setNodeFrame( + slice[i], + pns, + condition.startNS, + condition.endNS, + condition.frame, + condition.startKey, + condition.durKey + ); + } else { + if (i > 0) { + let c = slice[i][condition.startKey] - slice[i - 1][condition.startKey] - slice[i - 1][condition.durKey]; + if (c < pns && sum < pns) { + sum += c + slice[i - 1][condition.durKey]; + slice[i].v = false; + } else { + slice[i].v = true; + setNodeFrame( + slice[i], + pns, + condition.startNS, + condition.endNS, + condition.frame, + condition.startKey, + condition.durKey + ); + sum = 0; + } + } + } + } + filterData.push(...slice.filter((it) => it.v)); + } +} + +function setNodeFrame( + node: any, + pns: number, + startNS: number, + endNS: number, + frame: any, + startKey: string, + durKey: string +) { + if ((node[startKey] || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node[startKey] || 0) - startNS) / pns); + } + if ((node[startKey] || 0) + (node[durKey] || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node[startKey] || 0) + (node[durKey] || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } +} + +export function ns2x(ns: number, startNS: number, endNS: number, duration: number, rect: any) { + // @ts-ignore + if (endNS == 0) { + endNS = duration; + } + let xSize: number = ((ns - startNS) * rect.width) / (endNS - startNS); + if (xSize < 0) { + xSize = 0; + } else if (xSize > rect.width) { + xSize = rect.width; + } + return xSize; +} + +export function ns2xByTimeShaft(ns: number, tse: TimerShaftElement) { + let startNS = tse.getRange()!.startNS; + let endNS = tse.getRange()!.endNS; + let duration = tse.getRange()!.totalNS; + if (endNS == 0) { + endNS = duration; + } + let width = tse.getBoundingClientRect().width - 258; + let xSize: number = ((ns - startNS) * width) / (endNS - startNS); + if (xSize < 0) { + xSize = 0; + } else if (xSize > width) { + xSize = width; + } + return xSize; +} + +export class Rect { + x: number = 0; + y: number = 0; + width: number = 0; + height: number = 0; + + constructor(x: number, y: number, width: number, height: number) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + static contains(rect: Rect, x: number, y: number): boolean { + return rect.x <= x && x <= rect.x + rect.width && rect.y <= y && y <= rect.y + rect.height; + } + + static containsWithPadding( + rect: Rect, + x: number, + y: number, + paddingLeftRight: number, + paddingTopBottom: number + ): boolean { + return ( + rect.x + paddingLeftRight <= x && + x <= rect.x + rect.width - paddingLeftRight && + rect.y + paddingTopBottom <= y && + y <= rect.y + rect.height - paddingTopBottom + ); + } + + static containsWithMargin(rect: Rect, x: number, y: number, t: number, r: number, b: number, l: number): boolean { + return rect.x - l <= x && x <= rect.x + rect.width + r && rect.y - t <= y && y <= rect.y + rect.height + b; + } + + static intersect(r1: Rect, rect: Rect): boolean { + let maxX = r1.x + r1.width >= rect.x + rect.width ? r1.x + r1.width : rect.x + rect.width; + let maxY = r1.y + r1.height >= rect.y + rect.height ? r1.y + r1.height : rect.y + rect.height; + let minX = r1.x <= rect.x ? r1.x : rect.x; + let minY = r1.y <= rect.y ? r1.y : rect.y; + if (maxX - minX <= rect.width + r1.width && maxY - minY <= r1.height + rect.height) { + return true; + } else { + return false; + } + } + + contains(x: number, y: number): boolean { + return this.x <= x && x <= this.x + this.width && this.y <= y && y <= this.y + this.height; + } + + containsWithPadding(x: number, y: number, paddingLeftRight: number, paddingTopBottom: number): boolean { + return ( + this.x + paddingLeftRight <= x && + x <= this.x + this.width - paddingLeftRight && + this.y + paddingTopBottom <= y && + y <= this.y + this.height - paddingTopBottom + ); + } + + containsWithMargin(x: number, y: number, t: number, r: number, b: number, l: number): boolean { + return this.x - l <= x && x <= this.x + this.width + r && this.y - t <= y && y <= this.y + this.height + b; + } + + /** + * 判断是否相交 + * @param rect + */ + intersect(rect: Rect): boolean { + let maxX = this.x + this.width >= rect.x + rect.width ? this.x + this.width : rect.x + rect.width; + let maxY = this.y + this.height >= rect.y + rect.height ? this.y + this.height : rect.y + rect.height; + let minX = this.x <= rect.x ? this.x : rect.x; + let minY = this.y <= rect.y ? this.y : rect.y; + if (maxX - minX <= rect.width + this.width && maxY - minY <= this.height + rect.height) { + return true; + } else { + return false; + } + } +} + +export class Point { + x: number = 0; + y: number = 0; + isRight: boolean = true; + + constructor(x: number, y: number, isRight: boolean = true) { + this.x = x; + this.y = y; + this.isRight = isRight; + } +} + +export class PairPoint { + x: number = 0; + ns: number = 0; + y: number = 0; + offsetY: number = 0; + rowEL: TraceRow; + isRight: boolean = true; + + constructor(rowEL: TraceRow, x: number, y: number, ns: number, offsetY: number, isRight: boolean) { + this.rowEL = rowEL; + this.x = x; + this.y = y; + this.ns = ns; + this.offsetY = offsetY; + this.isRight = isRight; + } +} + +export class BaseStruct { + translateY: number | undefined; + frame: Rect | undefined; + isHover: boolean = false; +} + +export function drawLines(ctx: CanvasRenderingContext2D, xs: Array, height: number, lineColor: string) { + if (ctx) { + ctx.beginPath(); + ctx.lineWidth = 1; + ctx.strokeStyle = lineColor || '#dadada'; + xs?.forEach((it) => { + ctx.moveTo(Math.floor(it), 0); + ctx.lineTo(Math.floor(it), height); + }); + ctx.stroke(); + ctx.closePath(); + } +} + +export function drawFlagLine( + ctx: any, + hoverFlag: any, + selectFlag: any, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + slicesTime: + | { + startTime: number | null | undefined; + endTime: number | null | undefined; + color: string | null | undefined; + } + | undefined +) { + if (ctx) { + if (hoverFlag) { + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.strokeStyle = hoverFlag?.color || '#dadada'; + ctx.moveTo(Math.floor(hoverFlag.x), 0); + ctx.lineTo(Math.floor(hoverFlag.x), frame.height); + ctx.stroke(); + ctx.closePath(); + } + if (selectFlag) { + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.strokeStyle = selectFlag?.color || '#dadada'; + selectFlag.x = ns2x(selectFlag.time, startNS, endNS, totalNS, frame); + ctx.moveTo(Math.floor(selectFlag.x), 0); + ctx.lineTo(Math.floor(selectFlag.x), frame.height); + ctx.stroke(); + ctx.closePath(); + } + if (slicesTime && slicesTime.startTime && slicesTime.endTime) { + ctx.beginPath(); + ctx.lineWidth = 1; + ctx.strokeStyle = slicesTime.color || '#dadada'; + let x1 = ns2x(slicesTime.startTime, startNS, endNS, totalNS, frame); + let x2 = ns2x(slicesTime.endTime, startNS, endNS, totalNS, frame); + ctx.moveTo(Math.floor(x1), 0); + ctx.lineTo(Math.floor(x1), frame.height); + ctx.moveTo(Math.floor(x2), 0); + ctx.lineTo(Math.floor(x2), frame.height); + ctx.stroke(); + ctx.closePath(); + } + } +} + +export function drawFlagLineSegment(ctx: any, hoverFlag: any, selectFlag: any, frame: any) { + if (ctx) { + if (hoverFlag) { + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.strokeStyle = hoverFlag?.color || '#dadada'; + ctx.moveTo(Math.floor(hoverFlag.x), 0); + ctx.lineTo(Math.floor(hoverFlag.x), frame.height); + ctx.stroke(); + ctx.closePath(); + } + if (selectFlag) { + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.strokeStyle = selectFlag?.color || '#dadada'; + selectFlag.x = ns2x( + selectFlag.time, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + frame + ); + ctx.moveTo(Math.floor(selectFlag.x), 0); + ctx.lineTo(Math.floor(selectFlag.x), frame.height); + ctx.stroke(); + ctx.closePath(); + } + if (TraceRow.range!.slicesTime && TraceRow.range!.slicesTime.startTime && TraceRow.range!.slicesTime.endTime) { + ctx.beginPath(); + ctx.lineWidth = 1; + ctx.strokeStyle = TraceRow.range!.slicesTime.color || '#dadada'; + let x1 = ns2x( + TraceRow.range!.slicesTime.startTime, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + frame + ); + let x2 = ns2x( + TraceRow.range!.slicesTime.endTime, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + frame + ); + ctx.moveTo(Math.floor(x1), 0); + ctx.lineTo(Math.floor(x1), frame.height); + ctx.moveTo(Math.floor(x2), 0); + ctx.lineTo(Math.floor(x2), frame.height); + ctx.stroke(); + ctx.closePath(); + } + } +} + +export function drawSelection(context: any, params: any) { + if (params.isRangeSelect && params.rangeSelectObject) { + params.rangeSelectObject!.startX = Math.floor( + ns2x(params.rangeSelectObject!.startNS!, params.startNS, params.endNS, params.totalNS, params.frame) + ); + params.rangeSelectObject!.endX = Math.floor( + ns2x(params.rangeSelectObject!.endNS!, params.startNS, params.endNS, params.totalNS, params.frame) + ); + if (context) { + context.globalAlpha = 0.5; + context.fillStyle = '#666666'; + context.fillRect( + params.rangeSelectObject!.startX!, + params.frame.y, + params.rangeSelectObject!.endX! - params.rangeSelectObject!.startX!, + params.frame.height + ); + context.globalAlpha = 1; + } + } +} + +// draw range select +export function drawSelectionRange(context: any, params: TraceRow) { + if (params.rangeSelect && TraceRow.rangeSelectObject) { + TraceRow.rangeSelectObject!.startX = Math.floor( + ns2x( + TraceRow.rangeSelectObject!.startNS!, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + params.frame + ) + ); + TraceRow.rangeSelectObject!.endX = Math.floor( + ns2x( + TraceRow.rangeSelectObject!.endNS!, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + params.frame + ) + ); + if (context) { + context.globalAlpha = 0.5; + context.fillStyle = '#666666'; + context.fillRect( + TraceRow.rangeSelectObject!.startX!, + params.frame.y, + TraceRow.rangeSelectObject!.endX! - TraceRow.rangeSelectObject!.startX!, + params.frame.height + ); + context.globalAlpha = 1; + } + } +} + +export function drawWakeUp( + context: CanvasRenderingContext2D | any, + wake: WakeupBean | undefined | null, + startNS: number, + endNS: number, + totalNS: number, + frame: Rect, + selectCpuStruct: CpuStruct | undefined = undefined, + currentCpu: number | undefined = undefined +) { + if (wake) { + let x1 = Math.floor(ns2x(wake.wakeupTime || 0, startNS, endNS, totalNS, frame)); + context.beginPath(); + context.lineWidth = 2; + context.fillStyle = '#000000'; + if (x1 > 0 && x1 < frame.x + frame.width) { + context.moveTo(x1, frame.y); + context.lineTo(x1, frame.y + frame.height); + if (currentCpu == wake.cpu) { + let centerY = Math.floor(frame.y + frame.height / 2); + context.moveTo(x1, centerY - 6); + context.lineTo(x1 + 4, centerY); + context.lineTo(x1, centerY + 6); + context.lineTo(x1 - 4, centerY); + context.lineTo(x1, centerY - 6); + context.fill(); + } + } + if (selectCpuStruct) { + let x2 = Math.floor(ns2x(selectCpuStruct.startTime || 0, startNS, endNS, totalNS, frame)); + let y = frame.y + frame.height - 10; + context.moveTo(x1, y); + context.lineTo(x2, y); + + let s = ns2s((selectCpuStruct.startTime || 0) - (wake.wakeupTime || 0)); + let distance = x2 - x1; + if (distance > 12) { + context.moveTo(x1, y); + context.lineTo(x1 + 6, y - 3); + context.moveTo(x1, y); + context.lineTo(x1 + 6, y + 3); + context.moveTo(x2, y); + context.lineTo(x2 - 6, y - 3); + context.moveTo(x2, y); + context.lineTo(x2 - 6, y + 3); + let measure = context.measureText(s); + let tHeight = measure.actualBoundingBoxAscent + measure.actualBoundingBoxDescent; + let xStart = x1 + Math.floor(distance / 2 - measure.width / 2); + if (distance > measure.width + 4) { + context.fillStyle = '#ffffff'; + context.fillRect(xStart - 2, y - 4 - tHeight, measure.width + 4, tHeight + 4); + context.font = '10px solid'; + context.fillStyle = '#000000'; + context.textBaseline = 'bottom'; + context.fillText(s, xStart, y - 2); + } + } + } + context.strokeStyle = '#000000'; + context.stroke(); + context.closePath(); + } +} + +const wid = 5; +const linkLineColor = '#ff0000'; +export function drawLinkLines( + context: CanvasRenderingContext2D, + nodes: PairPoint[][], + tm: TimerShaftElement, + isFavorite: boolean +) { + let percentage = + (tm.getRange()!.totalNS - Math.abs(tm.getRange()!.endNS - tm.getRange()!.startNS)) / tm.getRange()!.totalNS; + let maxWidth = tm.getBoundingClientRect().width - 268; + for (let i = 0; i < nodes.length; i++) { + let it = nodes[i]; + if (isFavorite) { + if (!it[0].rowEL.collect && !it[1].rowEL.collect) { + continue; + } + } + let start = it[0].x > it[1].x ? it[1] : it[0]; + let end = it[0].x > it[1].x ? it[0] : it[1]; + if (start && end) { + //左移到边界,不画线 + if (start.x <= 0) { + start.x = -100; + } + if (end.x <= 0) { + end.x = -100; + } + //右移到边界,不画线 + if (start.x >= maxWidth) { + start.x = maxWidth + 100; + } + if (end.x >= maxWidth) { + end.x = maxWidth + 100; + } + context.beginPath(); + context.lineWidth = 2; + context.fillStyle = linkLineColor; + context.strokeStyle = linkLineColor; + let x0, y0, x1, x2, y1, y2, x3, y3; + x0 = start.x ?? 0; + y0 = start.y ?? 0; + x3 = end.x ?? 0; + y3 = end.y ?? 0; + if (end.isRight) { + x2 = x3 - 100 * percentage; + } else { + x2 = x3 + 100 * percentage; + } + y2 = y3 - 40 * percentage; + if (start.isRight) { + x1 = x0 - 100 * percentage; + } else { + x1 = x0 + 100 * percentage; + } + y1 = y0 + 40 * percentage; + //向右箭头终点在x轴正向有偏移 + if (!start.isRight) { + x0 -= 5; + } + context.moveTo(x0, y0); + //箭头向左还是向右 + if (start.isRight) { + context.lineTo(x0 - wid, y0 + wid); + context.moveTo(x0, y0); + context.lineTo(x0 - wid, y0 - wid); + } else { + context.lineTo(x0 + wid, y0 + wid); + context.moveTo(x0, y0); + context.lineTo(x0 + wid, y0 - wid); + } + context.moveTo(x0, y0); + context.bezierCurveTo(x1, y1, x2, y2, x3, y3); + context.moveTo(x3, y3); + //箭头向左还是向右 + if (end.isRight) { + context.lineTo(x3 - wid, y3 + wid); + context.moveTo(x3, y3); + context.lineTo(x3 - wid, y3 - wid); + } else { + context.lineTo(x3 + wid, y3 + wid); + context.moveTo(x3, y3); + context.lineTo(x3 + wid, y3 - wid); + } + context.moveTo(x3, y3); + context.stroke(); + context.closePath(); + } + } +} + +export function drawLoading( + ctx: CanvasRenderingContext2D, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + left: number, + right: number +) {} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerCpuAbility.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerCpuAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cdced3a0a54057eeb3b62dfd53921ffa2ac0ff7 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerCpuAbility.ts @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { DiskAbilityMonitorStruct } from './ProcedureWorkerDiskIoAbility.js'; + +export class CpuAbilityRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxCpuUtilization: number; + maxCpuUtilizationName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + CpuAbilityMonitorStruct.draw(req.context, re, req.maxCpuUtilization, row.isHover); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = re; + find = true; + } + } + if (!find && row.isHover) CpuAbilityMonitorStruct.hoverCpuAbilityStruct = undefined; + req.context.closePath(); + let textMetrics = req.context.measureText(req.maxCpuUtilizationName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(req.maxCpuUtilizationName, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) {} +} + +export function cpuAbility( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let index = 0; index < res.length; index++) { + let item = res[index]; + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + CpuAbilityMonitorStruct.setCpuAbilityFrame(res[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + res[index].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0); + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0); + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + CpuAbilityMonitorStruct.setCpuAbilityFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } +} + +export class CpuAbilityMonitorStruct extends BaseStruct { + static maxCpuUtilization: number = 0; + static maxCpuUtilizationName: string = '0 %'; + static hoverCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + static selectCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + + type: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; //自补充,数据库没有返回 + + static draw( + context2D: CanvasRenderingContext2D, + data: CpuAbilityMonitorStruct, + maxCpuUtilization: number, + isHover: boolean + ) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === CpuAbilityMonitorStruct.hoverCpuAbilityStruct?.startNS && isHover) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxCpuUtilization); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxCpuUtilization); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setCpuAbilityFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.startNS || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.startNS || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} + +export class CpuAbility { + context: any; + params: any; +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.ts new file mode 100644 index 0000000000000000000000000000000000000000..34e89f7efef8a5002ac9c02ecd92949bc5634e64 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.ts @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { convertJSON } from '../logic-worker/ProcedureLogicWorkerCommon.js'; + +export class CpuFreqLimitRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + cpu: number; + type: string; + maxFreq: number; + maxFreqName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNs', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let maxFreq = req.maxFreq; + let maxFreqName = req.maxFreqName; + if (row.isHover) { + for (let re of filter) { + if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = re; + break; + } + } + } + for (let re of filter) { + CpuFreqLimitsStruct.draw(req.context, re, maxFreq); + } + req.context.closePath(); + let s = maxFreqName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + freqLimits(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + freqLimits(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNs, + arr[arr.length - 1].startNs + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + let maxFreq = req.params.maxFreq; + let maxFreqName = req.params.maxFreqName; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = re; + break; + } + } + } else { + CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = req.params.hoverCpuFreqLimitsStruct; + } + CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = req.params.selectCpuFreqLimitsStruct; + for (let re of filter) { + CpuFreqLimitsStruct.draw(req.context, re, maxFreq); + } + drawSelection(req.context, req.params); + req.context.closePath(); + let s = maxFreqName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct, + }); + } +} + +export function freqLimits( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + res.forEach((it) => CpuFreqLimitsStruct.setFreqLimitFrame(it, 5, startNS || 0, endNS || 0, totalNS || 0, frame)); + return; + } + res.length = 0; + if (list) { + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if (i === list.length - 1) { + it.dur = (endNS || 0) - (it.startNs || 0); + } else { + it.dur = (list[i + 1].startNs || 0) - (it.startNs || 0); + } + if ((it.startNs || 0) + (it.dur || 0) > (startNS || 0) && (it.startNs || 0) < (endNS || 0)) { + CpuFreqLimitsStruct.setFreqLimitFrame(list[i], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) + ) { + } else { + res.push(it); + } + } + } + } +} + +export class CpuFreqLimitsStruct extends BaseStruct { + static hoverCpuFreqLimitsStruct: CpuFreqLimitsStruct | undefined; + static selectCpuFreqLimitsStruct: CpuFreqLimitsStruct | undefined; + static minAlpha = 0.4; + static maxAlpha = 0.8; + startNs: number | undefined; + dur: number = 0; + max: number | undefined; + min: number | undefined; + cpu: number = 0; + + static draw(ctx: CanvasRenderingContext2D, data: CpuFreqLimitsStruct, maxFreq: number) { + if (data.frame) { + let width = data.frame.width || 0; + let drawMaxHeight: number = Math.floor(((data.max || 0) * (data.frame.height || 0)) / maxFreq); + let drawMinHeight: number = Math.floor(((data.min || 0) * (data.frame.height || 0)) / maxFreq); + let index = data.cpu || 0; + index += 2; + ctx.fillStyle = ColorUtils.colorForTid(index); + ctx.strokeStyle = ColorUtils.colorForTid(index); + if ( + data === CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct || + data === CpuFreqLimitsStruct.selectCpuFreqLimitsStruct + ) { + ctx.lineWidth = 1; + ctx.globalAlpha = this.minAlpha; + this.drawArcLine(ctx, data, drawMaxHeight, drawMaxHeight - drawMinHeight); + ctx.globalAlpha = this.maxAlpha; + this.drawArcLine(ctx, data, drawMinHeight, drawMinHeight); + } else { + ctx.globalAlpha = this.minAlpha; + ctx.lineWidth = 1; + ctx.fillRect( + data.frame.x, + data.frame.y + data.frame.height - drawMaxHeight, + width, + drawMaxHeight - drawMinHeight + ); + ctx.globalAlpha = this.maxAlpha; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawMinHeight, width, drawMinHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } + + static drawArcLine( + ctx: CanvasRenderingContext2D, + data: CpuFreqLimitsStruct, + yStartHeight: number, + drawHeight: number + ) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - yStartHeight, width, drawHeight); + ctx.globalAlpha = this.maxAlpha; + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - yStartHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - yStartHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - yStartHeight); + ctx.stroke(); + } + } + + static setFreqLimitFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number, x2: number; + if ((node.startNs || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startNs || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNs || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startNs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(x1); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(getV); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerCpuState.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerCpuState.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9b60ca66053ecee32a51a9fdb638b861732bf68 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerCpuState.ts @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + ns2x, + PerfRender, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { convertJSON } from '../logic-worker/ProcedureLogicWorkerCommon.js'; + +export class CpuStateRender extends PerfRender { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + cpu: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + let chartColor = ColorUtils.colorForTid(req.cpu); + dataFilterHandler(list, filter, { + startKey: 'startTs', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + req.context.font = '11px sans-serif'; + req.context.fillStyle = chartColor; + req.context.strokeStyle = chartColor; + req.context.globalAlpha = 0.6; + let path = new Path2D(); + let find = false; + let offset = 3; + let heights = [4, 12, 21, 30]; + for (let re of filter) { + re.height = heights[(re as any).value]; + CpuStateStruct.draw(req.context, path, re); + if (row.isHover) { + if (re.frame && row.hoverX >= re.frame.x - offset && row.hoverX <= re.frame.x + re.frame.width + offset) { + CpuStateStruct.hoverStateStruct = re; + find = true; + } + } + } + if (!find && row.isHover) CpuStateStruct.hoverStateStruct = undefined; + req.context.fill(path); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + if (req.lazyRefresh) { + this.cpuState( + list, + dataList2, + req.type!, + filter, + req.params.cpu, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + this.cpuState( + list, + dataList2, + req.type!, + filter, + req.params.cpu, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + false + ); + } + } + CpuStateStruct.hoverStateStruct = undefined; + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + if (filter.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + filter[0].startTs, + filter[filter.length - 1].startTs + filter[filter.length - 1].dur + ); + } + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + if (req.isHover) { + let offset = 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + CpuStateStruct.hoverStateStruct = re; + break; + } + } + } + CpuStateStruct.selectStateStruct = req.params.selectStateStruct; + req.context.font = '11px sans-serif'; + req.context.fillStyle = req.chartColor; + req.context.strokeStyle = req.chartColor; + req.context.globalAlpha = 0.6; + let path = new Path2D(); + for (let re of filter) { + CpuStateStruct.draw(req.context, path, re); + } + req.context.fill(path); + drawSelection(req.context, req.params); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + let msg = { + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: CpuStateStruct.hoverStateStruct, + }; + self.postMessage(msg); + } + + cpuState( + arr: Array, + arr2: Array, + type: string, + res: Array, + cpu: number, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean + ) { + if (use && res.length > 0) { + for (let i = 0, len = res.length; i < len; i++) { + if ((res[i].startTs || 0) + (res[i].dur || 0) >= startNS && (res[i].startTs || 0) <= endNS) { + CpuStateStruct.setFrame(res[i], 5, startNS, endNS, totalNS, frame); + } else { + res[i].frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list: Array = arr2; + res.length = 0; + let pns = (endNS - startNS) / frame.width; //每个像素多少ns + let y = frame.y + 5; + let height = frame.height - 10; + let left = 0, + right = 0; + for (let i = 0, j = list.length - 1, ib = true, jb = true; i < list.length, j >= 0; i++, j--) { + if (list[j].startTs <= endNS && jb) { + right = j; + jb = false; + } + if (list[i].startTs + list[i].dur >= startNS && ib) { + left = i; + ib = false; + } + if (!ib && !jb) { + break; + } + } + let slice = list.slice(left, right + 1); + let sum = 0; + for (let i = 0; i < slice.length; i++) { + if (!slice[i].frame) { + slice[i].frame = {}; + slice[i].frame.y = y; + slice[i].frame.height = height; + } + if (slice[i].dur >= pns) { + slice[i].v = true; + CpuStateStruct.setFrame(slice[i], 5, startNS, endNS, totalNS, frame); + } else { + if (i > 0) { + let c = slice[i].startTs - slice[i - 1].startTs - slice[i - 1].dur; + if (c < pns && sum < pns) { + sum += c + slice[i - 1].dur; + slice[i].v = false; + } else { + slice[i].v = true; + CpuStateStruct.setFrame(slice[i], 5, startNS, endNS, totalNS, frame); + sum = 0; + } + } + } + } + res.push(...slice.filter((it) => it.v)); + } + } +} + +export class CpuStateStruct extends BaseStruct { + static hoverStateStruct: CpuStateStruct | undefined; + static selectStateStruct: CpuStateStruct | undefined; + dur: number | undefined; + value: string | undefined; + startTs: number | undefined; + height: number | undefined; + cpu: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: CpuStateStruct) { + if (data.frame) { + if (data === CpuStateStruct.hoverStateStruct || data === CpuStateStruct.selectStateStruct) { + path.rect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0); + ctx.lineWidth = 1; + ctx.globalAlpha = 1.0; + ctx.beginPath(); + ctx.arc(data.frame.x, 35 - (data.height || 0), 3, 0, 2 * Math.PI, true); + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, 35 - (data.height || 0)); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + data.frame.width, 35 - (data.height || 0)); + ctx.stroke(); + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + ctx.fillRect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0); + } else { + ctx.globalAlpha = 0.6; + path.rect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0); + } + } + } + + static setCpuFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startTime || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startTs || 0) - startNS) / pns); + } + if ((node.startTime || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startTs || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + static setFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number, x2: number; + if ((node.startTs || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startTs || 0, startNS, endNS, totalNS, frame); + } + if ((node.startTs || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startTs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.ceil(x1); + node.frame.y = frame.y + padding; + node.frame.width = Math.floor(getV); + node.frame.height = node.height; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..6174066e0c8698937bda8ecf55ad864419d17ad2 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.ts @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class DiskIoAbilityRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxDiskRate: number; + maxDiskRateName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + DiskAbilityMonitorStruct.draw(req.context, re, req.maxDiskRate, row.isHover); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = re; + find = true; + } + } + if (!find && row.isHover) DiskAbilityMonitorStruct.hoverDiskAbilityStruct = undefined; + req.context.closePath(); + let textMetrics = req.context.measureText(req.maxDiskRateName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(req.maxDiskRateName, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + diskIoAbility(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + diskIoAbility(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + let maxDiskRate = req.params.maxDiskRate; + let maxDiskRateName = req.params.maxDiskRateName; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = re; + break; + } + } + } + DiskAbilityMonitorStruct.selectDiskAbilityStruct = req.params.selectDiskAbilityStruct; + for (let re of filter) { + DiskAbilityMonitorStruct.draw(req.context, re, maxDiskRate, true); + } + drawSelection(req.context, req.params); + req.context.closePath(); + let textMetrics = req.context.measureText(maxDiskRateName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxDiskRateName, 4, 5 + 9); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + }); + } +} + +export function diskIoAbility( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let item = res[i]; + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + DiskAbilityMonitorStruct.setDiskIOFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + item.frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0); + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0); + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + DiskAbilityMonitorStruct.setDiskIOFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } +} + +export class DiskAbilityMonitorStruct extends BaseStruct { + static maxDiskRate: number = 0; + static maxDiskRateName: string = '0 KB/S'; + static hoverDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + static selectDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; //自补充,数据库没有返回 + + static draw( + context2D: CanvasRenderingContext2D, + data: DiskAbilityMonitorStruct, + maxDiskRate: number, + isHover: boolean + ) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.startNS && isHover) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxDiskRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxDiskRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setDiskIOFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.startNS || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.startNS || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd1a27a820f3c7d2832c6de96d3417bc4c58b1a5 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.ts @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + isFrameContainPoint, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class EnergyAnomalyRender extends PerfRender { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + appName: string; + canvasWidth: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + anomaly( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.appName, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + let spApplication = document.getElementsByTagName('sp-application')[0]; + let isDark = spApplication.hasAttribute('dark'); + drawLegend(req, isDark); + for (let re of filter) { + EnergyAnomalyStruct.draw(req.context, re); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + EnergyAnomalyStruct.hoverEnergyAnomalyStruct = re; + find = true; + } + } + if (!find && row.isHover) EnergyAnomalyStruct.hoverEnergyAnomalyStruct = undefined; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + if (req.lazyRefresh) { + anomaly( + list, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.params.appName, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + anomaly(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.params.appName, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.canvas.width, req.canvas.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + EnergyAnomalyStruct.hoverEnergyAnomalyStruct = undefined; + if (req.isHover) { + let offset = 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + EnergyAnomalyStruct.hoverEnergyAnomalyStruct = re; + break; + } + } + } else { + EnergyAnomalyStruct.hoverEnergyAnomalyStruct = req.params.hoverStruct; + } + EnergyAnomalyStruct.selectEnergyAnomalyStruct = req.params.selectEnergyAnomalyStruct; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + for (let re of filter) { + EnergyAnomalyStruct.draw(req.context, re); + } + drawLegend(req); + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: EnergyAnomalyStruct.hoverEnergyAnomalyStruct, + }); + } +} + +export function drawLegend(req: any, isDark?: boolean) { + req.context.font = '12px Arial'; + let text = req.context.measureText('System Abnormality'); + req.context.fillStyle = '#E64566'; + req.context.strokeStyle = '#E64566'; + let textColor = isDark ? '#FFFFFF' : '#333'; + let canvasEndX = req.context.canvas.clientWidth - EnergyAnomalyStruct.OFFSET_WIDTH; + let rectPadding: number; + let textPadding: number; + let textMargin: number; + let currentTextWidth: number; + let lastTextMargin: number; + rectPadding = 280; + textPadding = 270; + textMargin = 250; + currentTextWidth = canvasEndX - textMargin + text.width; + lastTextMargin = currentTextWidth + 12; + req!.context.fillRect(canvasEndX - rectPadding, 12, 8, 8); + req.context.globalAlpha = 1; + req.context.fillStyle = textColor; + req.context.textBaseline = 'middle'; + req.context.fillText('System Abnormality', canvasEndX - textPadding, 18); + req.context.fillStyle = '#FFC880'; + req.context.strokeStyle = '#FFC880'; + req.context.fillRect(currentTextWidth, 12, 8, 8); + req.context.globalAlpha = 1; + req.context.fillStyle = textColor; + req.context.textBaseline = 'middle'; + req.context.fillText('Application Abnormality', lastTextMargin, 18); + req.context.fillStyle = '#333'; +} + +export function anomaly( + arr: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + appName: string | undefined, + use: boolean +) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + EnergyAnomalyStruct.setAnomalyFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + + res.length = 0; + if (arr) { + let y = frame.y; + let pns = (endNS - startNS) / frame.width; + for (let index = 0; index < arr.length; index++) { + let item = arr[index]; + if (!item.frame) { + item.frame = {}; + item.frame.y = y; + } + item.frame.height = item.height; + if (item.startNS + 50000 > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + EnergyAnomalyStruct.setAnomalyFrame(item, pns, startNS || 0, endNS || 0, frame); + if (item.appKey === 'APPNAME' && item.Value.split(',').indexOf(appName) >= 0) { + res.push(item); + } + if (item.appKey != 'APPNAME') { + res.push(item); + } + } + } + } +} + +export class EnergyAnomalyStruct extends BaseStruct { + static hoverEnergyAnomalyStruct: EnergyAnomalyStruct | undefined; + static selectEnergyAnomalyStruct: EnergyAnomalyStruct | undefined; + static SYSTEM_EXCEPTION = new Set([ + 'ANOMALY_SCREEN_OFF_ENERGY', + 'ANOMALY_ALARM_WAKEUP', + 'ANOMALY_KERNEL_WAKELOCK', + 'ANOMALY_CPU_HIGH_FREQUENCY', + 'ANOMALY_WAKEUP', + ]); + static OFFSET_WIDTH: number = 266; + type: number | undefined; + startNS: number | undefined; + height: number | undefined; + eventName: string | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: EnergyAnomalyStruct) { + if (data.frame) { + EnergyAnomalyStruct.drawRoundRectPath(ctx, data.frame.x - 7, 20 - 7, 12, data); + } + } + + static drawRoundRectPath( + ctx: CanvasRenderingContext2D, + x: number, + y: number, + radius: number, + data: EnergyAnomalyStruct + ) { + ctx.beginPath(); + ctx.arc(x + 7, y + 22, radius, 0, Math.PI * 2); + ctx.closePath(); + let color = ''; + if (EnergyAnomalyStruct.SYSTEM_EXCEPTION.has(data.eventName)) { + color = '#E64566'; + } else { + color = '#FFC880'; + } + // 填充背景颜色 + ctx.fillStyle = color; + ctx.fill(); + ctx.stroke(); + // 填充文字颜色 + ctx.font = '12px Arial'; + ctx.fillStyle = ColorUtils.GREY_COLOR; + ctx.textAlign = 'center'; + ctx.fillText('E', x + 7, y + 23); + } + + static setAnomalyFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyPower.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyPower.ts new file mode 100644 index 0000000000000000000000000000000000000000..66f63ea1e1e8ac2043c4801f30663c3f8cd9ea15 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyPower.ts @@ -0,0 +1,509 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class EnergyPowerRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + appName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + power( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh, + req.appName + ); + req.context.beginPath(); + let find = false; + for (let i = 0; i < filter.length; i++) { + let re = filter[i]; + EnergyPowerStruct.draw(req, i, re, row); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + EnergyPowerStruct.hoverEnergyPowerStruct = re; + find = true; + } + } + if (!find && row.isHover) EnergyPowerStruct.hoverEnergyPowerStruct = undefined; + TraceRow.range!.refresh = true; + if (EnergyPowerStruct.maxPower != 0) { + let s = EnergyPowerStruct.maxPower + 'mAs'; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 1.0; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } + req.context.closePath(); + let spApplication = document.getElementsByTagName('sp-application')[0]; + let isDark = spApplication.hasAttribute('dark'); + drawLegend(req, isDark); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + power( + list, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.useCache || !req.range.refresh, + req.params.maxPowerName + ); + } else { + if (!req.useCache) { + power(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false, req.params.maxPowerName); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.canvas.width, EnergyPowerStruct.rowHeight); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.beginPath(); + EnergyPowerStruct.hoverEnergyPowerStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + EnergyPowerStruct.hoverEnergyPowerStruct = re; + break; + } + } + } + EnergyPowerStruct.selectEnergyPowerStruct = req.params.selectEnergyPowerStruct; + for (let index = 0; index < filter.length; index++) {} + req.context.stroke(); + drawSelection(req.context, req.params); + req.context.closePath(); + if (EnergyPowerStruct.maxPower != 0) { + let s = EnergyPowerStruct.maxPower + 'mAs'; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 1.0; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } + drawLegend(req); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: EnergyPowerStruct.hoverEnergyPowerStruct, + }); + } +} + +export function drawLegend(req: any, isDark?: boolean) { + let textList = ['CPU', 'LOCATION', 'GPU', 'DISPLAY', 'CAMERA', 'BLUETOOTH', 'FLASHLIGHT', 'AUDIO', 'WIFISCAN']; + for (let index = 0; index < textList.length; index++) { + let text = req.context.measureText(textList[index]); + req.context.fillStyle = EnergyPowerStruct.getHistogramColor(textList[index]); + req.context.globalAlpha = 1; + let canvasEndX = req.context.canvas.clientWidth - EnergyPowerStruct.OFFSET_WIDTH; + let textColor = isDark ? '#FFFFFF' : '#333'; + if (index == 0) { + req!.context.fillRect(canvasEndX - EnergyPowerStruct.powerItemNumber * 80, 12, 8, 8); + req.context.globalAlpha = 1; + req.context.fillStyle = textColor; + req.context.textBaseline = 'middle'; + req.context.fillText(textList[index], canvasEndX - EnergyPowerStruct.powerItemNumber * 80 + 10, 18); + EnergyPowerStruct.currentTextWidth = canvasEndX - EnergyPowerStruct.powerItemNumber * 80 + 40 + text.width; + } else { + req!.context.fillRect(EnergyPowerStruct.currentTextWidth, 12, 8, 8); + req.context.globalAlpha = 1; + req.context.fillStyle = textColor; + req.context.textBaseline = 'middle'; + req!.context.fillText(textList[index], EnergyPowerStruct.currentTextWidth + 12, 18); + EnergyPowerStruct.currentTextWidth = EnergyPowerStruct.currentTextWidth + 40 + text.width; + } + } + req.context.fillStyle = '#333'; +} + +export function power( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean, + appName: string +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let item = res[i]; + let obj = item[appName]; + if (obj != undefined) { + if (obj.ts + 1000000000 > (startNS || 0) && (obj.ts || 0) < (endNS || 0)) { + EnergyPowerStruct.setPowerFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + obj.frame = null; + } + } + } + return; + } + res.length = 0; + if (list) { + let firstList: Array = []; + EnergyPowerStruct.maxPower = 0; + for (let index = 0; index < list.length; index++) { + let item = list[index]; + let obj = item[appName]; + if (obj != undefined) { + if (obj.ts + 1000000000 > (startNS || 0) && (obj.ts || 0) < (endNS || 0)) { + firstList.push(obj); + } + } + } + + let array = firstList.sort((a, b) => a.ts - b.ts); + for (let index = 0; index < array.length; index++) { + if (res.length == 0) { + res.push(array[index]); + } else { + let rightTime = array[index].ts + 500000000; + let leftTime = array[index].ts - 500000000; + let obj = res[res.length - 1]; + if (obj.ts >= leftTime && obj.ts <= rightTime) { + obj.cpu = obj.cpu == 0 ? array[index].cpu : obj.cpu; + obj.location = obj.location == 0 ? array[index].location : obj.location; + obj.gpu = obj.gpu == 0 ? array[index].gpu : obj.gpu; + obj.display = obj.display == 0 ? array[index].display : obj.display; + obj.camera = obj.camera == 0 ? array[index].camera : obj.camera; + obj.bluetooth = obj.bluetooth == 0 ? array[index].bluetooth : obj.bluetooth; + obj.flashlight = obj.flashlight == 0 ? array[index].flashlight : obj.flashlight; + obj.audio = obj.audio ? array[index].audio : obj.audio; + obj.wifiscan = obj.wifiscan == 0 ? array[index].wifiscan : obj.wifiscan; + } else { + res.push(array[index]); + } + } + } + res.forEach((item) => { + EnergyPowerStruct.setPowerFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + let max = + (item.cpu || 0) + + (item.location || 0) + + (item.gpu || 0) + + (item.display || 0) + + (item.camera || 0) + + (item.bluetooth || 0) + + (item.flashlight || 0) + + (item.audio || 0) + + (item.wifiscan || 0); + if (max > EnergyPowerStruct.maxPower) { + EnergyPowerStruct.maxPower = max; + } + }); + } +} + +export class EnergyPowerStruct extends BaseStruct { + static maxPower: number = 0; + static maxPowerName: string = '0'; + static powerItemNumber: number = 9; + static currentTextWidth: number = 0; + static rowHeight: number = 200; + static appName: string | undefined; + static hoverEnergyPowerStruct: EnergyPowerStruct | undefined; + static selectEnergyPowerStruct: EnergyPowerStruct | undefined; + static OFFSET_WIDTH: number = 266; + name: string | undefined; + ts: number = 0; + cpu: number = 0; + location: number = 0; + gpu: number = 0; + display: number = 0; + camera: number = 0; + bluetooth: number = 0; + flashlight: number = 0; + audio: number = 0; + wifiscan: number = 0; + + static draw(req: any, index: number, data: EnergyPowerStruct, row: TraceRow) { + if (data.frame) { + let width = data.frame.width || 0; + req!.context.globalAlpha = 1.0; + req!.context.lineWidth = 1; + this.currentTextWidth = 0; + let cpuHeight = this.drawHistogram(req, data, -1, data.cpu!, 'CPU', row.frame); + let locationHeight = this.drawHistogram(req, data, cpuHeight, data.location!, 'LOCATION', row.frame); + let gpuHeight = this.drawHistogram(req, data, cpuHeight - locationHeight, data.gpu!, 'GPU', row.frame); + let displayHeight = this.drawHistogram( + req, + data, + cpuHeight - locationHeight - gpuHeight, + data.display!, + 'DISPLAY', + row.frame + ); + let cameraHeight = this.drawHistogram( + req, + data, + cpuHeight - locationHeight - gpuHeight - displayHeight, + data.camera!, + 'CAMERA', + row.frame + ); + let bluetoothHeight = this.drawHistogram( + req, + data, + cpuHeight - locationHeight - gpuHeight - displayHeight - cameraHeight, + data.bluetooth!, + 'BLUETOOTH', + row.frame + ); + let flashlightHeight = this.drawHistogram( + req, + data, + cpuHeight - locationHeight - gpuHeight - displayHeight - cameraHeight - bluetoothHeight, + data.flashlight!, + 'FLASHLIGHT', + row.frame + ); + let audioHeight = this.drawHistogram( + req, + data, + cpuHeight - locationHeight - gpuHeight - displayHeight - cameraHeight - bluetoothHeight - flashlightHeight, + data.audio!, + 'AUDIO', + row.frame + ); + let wifiHeight = this.drawHistogram( + req, + data, + cpuHeight - + locationHeight - + gpuHeight - + displayHeight - + cameraHeight - + bluetoothHeight - + flashlightHeight - + audioHeight, + data.wifiscan!, + 'WIFISCAN', + row.frame + ); + let maxPointY = this.drawPolyline(req, index, data, row.frame, wifiHeight); + if (data.ts === EnergyPowerStruct.hoverEnergyPowerStruct?.ts) { + let endPointX = ns2x( + (data.ts || 0) + 500000000, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame + ); + let startPointX = ns2x( + (data.ts || 0) - 500000000, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame + ); + let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + req.context.globalAlpha = 1; + req!.context.lineWidth = 2; + req.context.fillStyle = '#333'; + req!.context.strokeRect(startPointX, maxPointY, frameWidth, req.context.canvas.width - maxPointY); + } + } + req!.context.globalAlpha = 1.0; + req!.context.lineWidth = 1; + } + + static drawHistogram( + req: RequestMessage, + data: EnergyPowerStruct, + height: number, + itemValue: number, + textItem: string, + rowFrame: any + ): number { + let endPointX = ns2x( + (data.ts || 0) + 500000000, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + rowFrame + ); + let startPointX = ns2x( + (data.ts || 0) - 500000000, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + rowFrame + ); + let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + let histogramColor = this.getHistogramColor(textItem); + req!.context.fillStyle = histogramColor; + req!.context.strokeStyle = histogramColor; + let dataHeight: number = Math.floor(((itemValue || 0) * (this.rowHeight - 40)) / EnergyPowerStruct.maxPower); + if (itemValue != 0 && dataHeight < 15) { + dataHeight = 15; + } + let drawStartY = 0; + + if (height == -1) { + drawStartY = data.frame!.y + this.rowHeight - dataHeight + 4; + req!.context.fillRect(startPointX, drawStartY, frameWidth, dataHeight); + return drawStartY; + } else { + drawStartY = height - dataHeight; + req!.context.fillRect(startPointX, drawStartY, frameWidth, dataHeight); + if (textItem == 'WIFISCAN') { + return drawStartY; + } + return dataHeight; + } + } + + static drawPolyline(req: RequestMessage, index: number, data: EnergyPowerStruct, rowFrame: any, totalHeight: number) { + let pointX = ns2x(data.ts || 0, TraceRow.range!.startNS, TraceRow.range!.endNS, TraceRow.range!.totalNS, rowFrame); + let maxHeight = + (data.cpu || 0) + + (data.location || 0) + + (data.gpu || 0) + + (data.display || 0) + + (data.camera || 0) + + (data.bluetooth || 0) + + (data.flashlight || 0) + + (data.audio || 0) + + (data.wifiscan || 0); + let drawHeight: number = Math.floor(((maxHeight || 0) * (this.rowHeight - 40)) / EnergyPowerStruct.maxPower); + let drawY = data.frame!.y + this.rowHeight - drawHeight + 5; + req!.context.fillStyle = '#ED6F21'; + req!.context.strokeStyle = '#ED6F21'; + + if (index == 0) { + req.context.beginPath(); + req.context.arc(pointX, totalHeight, 4, 0, 2 * Math.PI); + req.context.fill(); + req.context.moveTo(pointX, totalHeight); + } else { + req.context.lineTo(pointX, totalHeight); + req.context.stroke(); + req.context.beginPath(); + req.context.arc(pointX, totalHeight, 4, 0, 2 * Math.PI); + req.context.fill(); + } + return totalHeight; + } + + static setPowerFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number; + let endPointX: number; + if ((node.ts || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x((node.ts || 0) - 500000000, startNS, endNS, totalNS, frame); + } + if (node.ts + 500000000 > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x(node.ts + 500000000, startNS, endNS, totalNS, frame); + } + let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } + + static getHistogramColor(textItem: string): string { + switch (textItem) { + case 'CPU': + return '#92D6CC'; + case 'LOCATION': + return '#61CFBE'; + case 'GPU': + return '#86C5E3'; + case 'DISPLAY': + return '#46B1E3'; + case 'CAMERA': + return '#C386F0'; + case 'BLUETOOTH': + return '#8981F7'; + case 'AUDIO': + return '#AC49F5'; + case 'WIFISCAN': + return '#92C4BD'; + default: + return '#564AF7'; + } + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyState.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyState.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf2d457f70cabecbf916277e58cb9bf60e6eb616 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergyState.ts @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class EnergyStateRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + maxState: number; + maxStateName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + state( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + for (let i = 0; i < filter.length; i++) { + let re = filter[i]; + EnergyStateStruct.draw(req.context, re, req.maxState, req.maxStateName); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + EnergyStateStruct.hoverEnergyStateStruct = re; + find = true; + } + } + if (!find && row.isHover) EnergyStateStruct.hoverEnergyStateStruct = undefined; + if (req.maxStateName != 'enable' && req.maxStateName != 'disable' && req.maxStateName != '-1') { + let s = req.maxStateName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 1.0; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + state(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + state(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.canvas.width, req.canvas.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.beginPath(); + EnergyStateStruct.maxState = req.params.maxState; + EnergyStateStruct.maxStateName = req.params.maxStateName; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + EnergyStateStruct.hoverEnergyStateStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + EnergyStateStruct.hoverEnergyStateStruct = re; + break; + } + } + } + EnergyStateStruct.selectEnergyStateStruct = req.params.selectEnergyStateStruct; + for (let re of filter) { + EnergyStateStruct.draw(req.context, re, 0, ''); + } + drawSelection(req.context, req.params); + req.context.closePath(); + if ( + EnergyStateStruct.maxStateName != 'enable' && + EnergyStateStruct.maxStateName != 'disable' && + EnergyStateStruct.maxStateName != '-1' + ) { + let s = EnergyStateStruct.maxStateName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 1.0; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: EnergyStateStruct.hoverEnergyStateStruct, + }); + } +} + +export function state( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let item = res[i]; + if ((item.startNs || 0) + (item.dur || 0) > (startNS || 0) && (item.startNs || 0) < (endNS || 0)) { + EnergyStateStruct.setStateFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + item.frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNs || 0); + } else { + item.dur = (list[index + 1].startNs || 0) - (item.startNs || 0); + } + if ((item.startNs || 0) + (item.dur || 0) > (startNS || 0) && (item.startNs || 0) < (endNS || 0)) { + EnergyStateStruct.setStateFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } +} + +export class EnergyStateStruct extends BaseStruct { + static maxState: number = 0; + static maxStateName: string = '0'; + static hoverEnergyStateStruct: EnergyStateStruct | undefined; + static selectEnergyStateStruct: EnergyStateStruct | undefined; + type: string | undefined; + value: number | undefined; + startNs: number | undefined; + dur: number | undefined; + + sensorType: number | undefined; + pkg_name: string | undefined; + deviceState: number | undefined; + deviceType: number | undefined; + + static draw(context2D: CanvasRenderingContext2D, data: EnergyStateStruct, maxState: number, maxStateName: string) { + if (data.frame) { + let width = data.frame.width || 0; + let drawColor = this.setDrawColor(data.type!); + context2D.fillStyle = drawColor; + context2D.strokeStyle = drawColor; + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxState); + if (maxStateName === 'enable' || maxStateName === 'disable') { + if (data.value == 0) { + drawHeight = data.frame.height; + context2D.fillRect(data.frame.x, data.frame.y + 4, width, data.frame.height); + } + } else { + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + if (data.startNs === EnergyStateStruct.hoverEnergyStateStruct?.startNs) { + let pointy = data.frame.y + data.frame.height + 4; + if (data.value == 0) { + pointy -= drawHeight; + } + context2D.beginPath(); + context2D.arc(data.frame.x, pointy, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, pointy); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, pointy); + context2D.stroke(); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setStateFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.startNs || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.startNs || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNs || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } + + static setDrawColor(eventType: string): string { + switch (eventType) { + case 'BRIGHTNESS_NIT': + return '#92D6CC'; + case 'SIGNAL_LEVEL': + return '#61CFBE'; + case 'WIFI_EVENT_RECEIVED': + return '#46B1E3'; + case 'AUDIO_STREAM_CHANGE': + return '#ED6F21'; + case 'WIFI_STATE': + return '#61CFBE'; + case 'LOCATION_SWITCH_STATE': + return '#61CFBE'; + case 'SENSOR_STATE': + return '#61CFBE'; + default: + return '#61CFBE'; + } + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerEnergySystem.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergySystem.ts new file mode 100644 index 0000000000000000000000000000000000000000..386a3c9ceeda03b8097dfccc0ba4bd498bedade5 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerEnergySystem.ts @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class EnergySystemRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + system( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + let a: any = {}; + for (let i = 0; i < filter.length; i++) { + let re = filter[i]; + + EnergySystemStruct.draw(req.context, re); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + EnergySystemStruct.hoverEnergySystemStruct = re; + if (re.type == 0) { + if (re.count != undefined) { + a.workScheduler = re.count; + } else { + a.workScheduler = '0'; + } + } + if (re.type == 1) { + if (re.count != undefined) { + a.power = re.count + ''; + } else { + a.power = '0'; + } + } + + if (re.type == 2) { + if (re.count != undefined) { + a.location = re.count + ''; + } else { + a.location = '0'; + } + } + find = true; + } + } + if (!find && row.isHover) EnergySystemStruct.hoverEnergySystemStruct = undefined; + if (EnergySystemStruct.hoverEnergySystemStruct) { + EnergySystemStruct.hoverEnergySystemStruct!.workScheduler = a.workScheduler == undefined ? '0' : a.workScheduler; + EnergySystemStruct.hoverEnergySystemStruct!.power = a.power == undefined ? '0' : a.power; + EnergySystemStruct.hoverEnergySystemStruct!.location = a.location == undefined ? '0' : a.location; + } + let spApplication = document.getElementsByTagName('sp-application')[0]; + let isDark = spApplication.hasAttribute('dark'); + drawLegend(req, isDark); + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + system(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + system(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.canvas.width, req.canvas.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.beginPath(); + EnergySystemStruct.hoverEnergySystemStruct = undefined; + if (req.isHover) { + let a: any = {}; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x && req.hoverX <= re.frame.x + re.frame.width) { + EnergySystemStruct.hoverEnergySystemStruct = re; + if (re.type == 0) { + if (re.count != undefined) { + a.workScheduler = re.count; + } else { + a.workScheduler = '0'; + } + } + if (re.type == 1) { + if (re.count != undefined) { + a.power = re.count + ''; + } else { + a.power = '0'; + } + } + + if (re.type == 2) { + if (re.count != undefined) { + a.location = re.count + ''; + } else { + a.location = '0'; + } + } + } + } + if (EnergySystemStruct.hoverEnergySystemStruct) { + EnergySystemStruct.hoverEnergySystemStruct!.workScheduler = + a.workScheduler == undefined ? '0' : a.workScheduler; + EnergySystemStruct.hoverEnergySystemStruct!.power = a.power == undefined ? '0' : a.power; + EnergySystemStruct.hoverEnergySystemStruct!.location = a.location == undefined ? '0' : a.location; + } + } + EnergySystemStruct.selectEnergySystemStruct = req.params.selectEnergySystemStruct; + for (let re of filter) { + EnergySystemStruct.draw(req.context, re); + } + drawLegend(req); + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: EnergySystemStruct.hoverEnergySystemStruct, + }); + } +} + +export function drawLegend(req: RequestMessage | any, isDark?: boolean) { + let textList = ['WORKSCHEDULER', 'POWER_RUNNINGLOCK', 'LOCATION']; + for (let index = 0; index < textList.length; index++) { + let text = req.context.measureText(textList[index]); + req.context.fillStyle = EnergySystemStruct.getColor(index); + let canvasEndX = req.context.canvas.clientWidth - EnergySystemStruct.OFFSET_WIDTH; + let textColor = isDark ? '#FFFFFF' : '#333'; + if (textList[index] == 'WORKSCHEDULER') { + req.context.fillRect(canvasEndX - EnergySystemStruct.itemNumber * 120, 12, 8, 8); + req.context.globalAlpha = 1; + req.context.textBaseline = 'middle'; + req.context.fillStyle = textColor; + req.context.fillText(textList[index], canvasEndX - EnergySystemStruct.itemNumber * 120 + 10, 18); + EnergySystemStruct.currentTextWidth = canvasEndX - EnergySystemStruct.itemNumber * 120 + 40 + text.width; + } else { + req.context.fillRect(EnergySystemStruct.currentTextWidth, 12, 8, 8); + req.context.globalAlpha = 1; + req.context.fillStyle = textColor; + req.context.textBaseline = 'middle'; + req.context.fillText(textList[index], EnergySystemStruct.currentTextWidth + 12, 18); + EnergySystemStruct.currentTextWidth = EnergySystemStruct.currentTextWidth + 40 + text.width; + } + } + req.context.fillStyle = '#333'; +} + +export function system( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let item = res[i]; + if ((item.startNs || 0) + (item.dur || 0) > (startNS || 0) && (item.startNs || 0) < (endNS || 0)) { + EnergySystemStruct.setSystemFrame(item, 10, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + item.frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let i = 0; i < 3; i++) { + let arr = list[i]; + if (arr) { + for (let index = 0; index < arr.length; index++) { + let item = arr[index]; + if (index === arr.length - 1) { + item.dur = (endNS || 0) - (item.startNs || 0); + } else { + item.dur = (arr[index + 1].startNs || 0) - (item.startNs || 0); + } + if (item.count == 0) { + item.dur = 0; + } + if ((item.startNs || 0) + (item.dur || 0) > (startNS || 0) && (item.startNs || 0) < (endNS || 0)) { + EnergySystemStruct.setSystemFrame(item, 10, startNS || 0, endNS || 0, totalNS || 0, frame); + res.push(item); + } + } + } + } + } +} + +export class EnergySystemStruct extends BaseStruct { + static hoverEnergySystemStruct: EnergySystemStruct | undefined; + static selectEnergySystemStruct: EnergySystemStruct | undefined; + static itemNumber: number = 3; + static currentTextWidth: number = 0; + static OFFSET_WIDTH: number = 266; + type: number | undefined; + startNs: number | undefined; + dur: number | undefined; + count: number | undefined; + workScheduler: string | undefined; + power: string | undefined; + location: string | undefined; + + static draw(context2D: CanvasRenderingContext2D, data: EnergySystemStruct) { + if (data.frame) { + let width = data.frame.width || 0; + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + context2D.fillStyle = this.getColor(data.type!); + context2D.strokeStyle = this.getColor(data.type!); + context2D.fillRect(data.frame.x, data.frame.y + 4, width, data.frame.height); + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setSystemFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number; + let endPointX: number; + if ((node.startNs || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.startNs || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNs || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + if (node.type === 0) { + node.frame.y = frame.y + padding * 2.5; + } else if (node.type === 1) { + node.frame.y = frame.y + padding * 4.5; + } else if (node.type === 2) { + node.frame.y = frame.y + padding * 6.5; + } + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(padding); + } + + static getColor(textItem: number): string { + switch (textItem) { + case 0: + return '#E64566'; + case 1: + return '#FFC880'; + default: + return '#564AF7'; + } + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerFPS.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerFPS.ts new file mode 100644 index 0000000000000000000000000000000000000000..7dfb664eeb0d46efa94e920b4100b5ee2ff6be96 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerFPS.ts @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + isFrameContainPoint, + ns2x, + Rect, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class FpsRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + fps( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + for (let re of filter) { + FpsStruct.draw(req.context, re); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + FpsStruct.hoverFpsStruct = re; + find = true; + } + } + if (!find && row.isHover) FpsStruct.hoverFpsStruct = undefined; + req.context.closePath(); + let maxFps = FpsStruct.maxFps + 'FPS'; + let textMetrics = req.context.measureText(maxFps); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxFps, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + fps(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + fps(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + FpsStruct.hoverFpsStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + FpsStruct.hoverFpsStruct = re; + break; + } + } + } else { + FpsStruct.hoverFpsStruct = req.params.hoverFpsStruct; + } + for (let re of filter) { + FpsStruct.draw(req.context, re); + } + drawSelection(req.context, req.params); + req.context.closePath(); + let maxFps = FpsStruct.maxFps + 'FPS'; + let textMetrics = req.context.measureText(maxFps); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxFps, 4, 5 + 9); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: FpsStruct.hoverFpsStruct, + }); + } +} + +export function fps( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + res.forEach((it) => FpsStruct.setFrame(it, 5, startNS, endNS, totalNS, frame)); + return; + } + FpsStruct.maxFps = 0; + res.length = 0; + if (list) { + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.fps || 0) > FpsStruct.maxFps) { + FpsStruct.maxFps = it.fps || 0; + } + if (i === list.length - 1) { + it.dur = (endNS || 0) - (it.startNS || 0); + } else { + it.dur = (list[i + 1].startNS || 0) - (it.startNS || 0); + } + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + FpsStruct.setFrame(list[i], 5, startNS, endNS, totalNS, frame); + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) + ) { + } else { + res.push(list[i]); + } + } + } + } +} + +export class FpsStruct extends BaseStruct { + static maxFps: number = 0; + static maxFpsName: string = '0 FPS'; + static hoverFpsStruct: FpsStruct | undefined; + static selectFpsStruct: FpsStruct | undefined; + fps: number | undefined; + startNS: number | undefined = 0; + dur: number | undefined; //自补充,数据库没有返回 + + static draw(ctx: CanvasRenderingContext2D, data: FpsStruct) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = '#535da6'; + ctx.strokeStyle = '#535da6'; + if (data === FpsStruct.hoverFpsStruct) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = ((data.fps || 0) * (data.frame.height || 0) * 1.0) / FpsStruct.maxFps; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = ((data.fps || 0) * (data.frame.height || 0) * 1.0) / FpsStruct.maxFps; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } + + static setFrame(node: FpsStruct, padding: number, startNS: number, endNS: number, totalNS: number, frame: Rect) { + let x1: number, x2: number; + if ((node.startNS || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startNS || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + let rectangle: Rect = new Rect( + Math.floor(x1), + Math.ceil(frame.y + padding), + Math.ceil(getV), + Math.floor(frame.height - padding * 2) + ); + node.frame = rectangle; + } +} + +const textPadding = 2; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerFileSystem.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerFileSystem.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4a21881eccf2b7e14b41aff15c7590997db3c99 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerFileSystem.ts @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class FileSystemRender extends PerfRender { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + chartColor: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + let groupBy10MS = (TraceRow.range?.scale || 50) > 40_000_000; + let isDiskIO: boolean = req.type.includes('disk-io'); + if (list && row.dataList2.length == 0) { + row.dataList2 = isDiskIO + ? FileSysChartStruct.groupBy10MSWithMaxLatency(list) + : FileSysChartStruct.groupBy10MSWithCount(list); + } + fileSysChart( + list, + row.dataList2, + req.type, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + groupBy10MS, + isDiskIO, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + let find = false; + let hoverRect: FileSysChartStruct | undefined = undefined; + for (let re of filter) { + if (row.isHover && re.frame && row.hoverX >= re.frame.x && row.hoverX <= re.frame.x + re.frame.width) { + if (hoverRect == undefined || re.size! > hoverRect.size!) { + hoverRect = re; + find = true; + } + } + if (re.frame && re.frame!.x > row.hoverX + 3) { + break; + } + } + if (hoverRect) { + FileSysChartStruct.hoverFileSysStruct = hoverRect; + } + for (let re of filter) { + FileSysChartStruct.draw(req.context, re, req.chartColor); + } + if (!find && row.isHover) FileSysChartStruct.hoverFileSysStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + let groupBy10MS = req.scale > 20_000_000; + let isDiskIO: boolean = req.type!.includes('disk-io'); + if (isDiskIO) { + groupBy10MS = true; + } + if (req.lazyRefresh) { + fileSysChart( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + isDiskIO, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + fileSysChart( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + isDiskIO, + false + ); + } + } + let hoverStruct: FileSysChartStruct | undefined; + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + if (req.isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + hoverStruct = re; + break; + } + } + } + for (let re of filter) { + FileSysChartStruct.draw(req.context, re, req.chartColor); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + let msg = { + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: hoverStruct, + }; + self.postMessage(msg); + } +} + +export function fileSysChart( + arr: Array, + arr2: Array, + type: string, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + groupBy10MS: boolean, + isDiskIO: boolean, + use: boolean +) { + if (use && res.length > 0) { + //&& !groupBy10MS + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + FileSysChartStruct.setFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list: Array = []; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + if (groupBy10MS) { + list = arr2.filter((it) => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS); + let groups = list + .map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + FileSysChartStruct.setFrame(it, pns, startNS, endNS, frame); + return it; + }) + .reduce((pre, current, index, arr) => { + (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current); + return pre; + }, {}); + Reflect.ownKeys(groups).map((kv) => { + res.push(groups[kv][0]); + }); + } else { + let filter = arr.filter((it) => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS); + list = isDiskIO + ? FileSysChartStruct.computeHeightNoGroupLatency(filter, totalNS) + : FileSysChartStruct.computeHeightNoGroup(filter, totalNS); + list.map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + FileSysChartStruct.setFrame(it, pns, startNS, endNS, frame); + res.push(it); + }); + } + } +} + +export class FileSysChartStruct extends BaseStruct { + static hoverFileSysStruct: FileSysChartStruct | undefined; + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + size: number | undefined; + height: number | undefined; + group10Ms: boolean | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: FileSysChartStruct, chartColor: string) { + if (data.frame) { + ctx.fillStyle = chartColor; + ctx.strokeStyle = chartColor; + ctx.fillRect(data.frame.x, 40 - (data.height || 0), data.frame.width, data.height || 0); + } + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static computeHeightNoGroup(array: Array, totalNS: number): Array { + if (array.length > 0) { + let time: Array<{ time: number; type: number }> = []; + array.map((item) => { + time.push({ time: item.startNS, type: 1 }); + time.push({ time: item.endNS || totalNS, type: -1 }); + }); + time = time.sort((a, b) => a.time - b.time); + let arr: Array = []; + let first = { + startNS: time[0].time ?? 0, + dur: 0, + size: 1, + group10Ms: false, + height: 1, + }; + arr.push(first); + let max = 2; + for (let i = 1, len = time.length; i < len; i++) { + let heap = { + startNS: time[i].time, + dur: 0, + size: 0, + group10Ms: false, + height: 0, + }; + arr[i - 1].dur = heap.startNS - arr[i - 1].startNS; + if (i == len - 1) { + heap.dur = totalNS - heap.startNS; + } + heap.size = arr[i - 1].size + time[i].type; + heap.height = Math.floor((heap.size / 6) * 36); + max = max > heap.size ? max : heap.size; + arr.push(heap); + } + arr.map((it) => (it.height = Math.floor((it.size / max) * 36))); + return arr; + } else { + return []; + } + } + + static groupBy10MSWithCount(array: Array): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + (pre[current['timestamp_group']] = pre[current['timestamp_group']] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + let max = 1; + for (let aKey in obj) { + max = obj[aKey].length > max ? obj[aKey].length : max; + } + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = Math.floor((obj[aKey].length / max) * 36); + arr.push({ + startNS: ns, + dur: 1_000_000_0, + group10Ms: true, + size: obj[aKey].length, + height: height < 1 ? 1 : height, + }); + } + return arr; + } + + static computeHeightNoGroupLatency(array: Array, totalNS: number): Array { + if (array.length > 0) { + let max = 0; + let arr: Array = []; + for (let io of array) { + let ioItem = { + startNS: io.startNS, + dur: io.endNS > totalNS ? totalNS - io.startNS : io.endNS - io.startNS, + size: io.dur, + group10Ms: false, + height: 0, + }; + max = max > ioItem.size ? max : ioItem.size; + arr.push(ioItem); + } + arr.map((it) => { + let height = Math.floor((it.size / max) * 36); + it.height = height < 1 ? 1 : height; + }); + return arr; + } else { + return []; + } + } + + static groupBy10MSWithMaxLatency(array: Array): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + if (pre[current['timestamp_group']] == undefined || pre[current['timestamp_group']] == null) { + pre[current['timestamp_group']] = []; + } + if (pre[current['timestamp_group']].length > 0) { + let p = pre[current['timestamp_group']][0]; + if (p.dur < current.dur) { + pre[current['timestamp_group']][0] = current; + } + } else { + pre[current['timestamp_group']][0] = current; + } + return pre; + }, {}); + let arr: any[] = []; + let max = 1; + for (let aKey in obj) { + max = obj[aKey][0].dur > max ? obj[aKey][0].dur : max; + } + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = Math.floor((obj[aKey][0].dur / max) * 36); + arr.push({ + startNS: ns, + dur: 1_000_000_0, + group10Ms: true, + size: obj[aKey][0].dur, + height: height < 1 ? 1 : height, + }); + } + return arr; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerFreq.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerFreq.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf7693dc180a92a8e716d81cf05c0d9e7b9f38d3 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerFreq.ts @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { BaseStruct, dataFilterHandler, isFrameContainPoint, Render, RequestMessage } from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class FreqRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + CpuFreqStruct.hoverCpuFreqStruct = re; + find = true; + } + CpuFreqStruct.draw(req.context, re); + } + if (!find && row.isHover) CpuFreqStruct.hoverCpuFreqStruct = undefined; + req.context.closePath(); + let s = CpuFreqStruct.maxFreqName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + } +} + +export class CpuFreqStruct extends BaseStruct { + static maxFreq: number = 0; + static maxFreqName: string = '0 GHz'; + static hoverCpuFreqStruct: CpuFreqStruct | undefined; + static selectCpuFreqStruct: CpuFreqStruct | undefined; + cpu: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; //自补充,数据库没有返回 + + static draw(ctx: CanvasRenderingContext2D, data: CpuFreqStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = data.cpu || 0; + index += 2; + ctx.fillStyle = ColorUtils.colorForTid(index); + ctx.strokeStyle = ColorUtils.colorForTid(index); + if (data === CpuFreqStruct.hoverCpuFreqStruct || data === CpuFreqStruct.selectCpuFreqStruct) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / CpuFreqStruct.maxFreq + ); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / CpuFreqStruct.maxFreq); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} + +const textPadding = 2; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts new file mode 100644 index 0000000000000000000000000000000000000000..72f1a9f95b1ca03ce1f47f72f1ec2aed886d3615 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerFunc.ts @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { BaseStruct, isFrameContainPoint, ns2x, Rect, Render, RequestMessage } from './ProcedureWorkerCommon.js'; + +export class FuncRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + func( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + for (let re of filter) { + FuncStruct.draw(req.context, re); + if (row.isHover) { + if (re.dur == 0 || re.dur == null || re.dur == undefined) { + if ( + re.frame && + row.hoverX >= re.frame.x - 5 && + row.hoverX <= re.frame.x + 5 && + row.hoverY >= re.frame.y && + row.hoverY <= re.frame.y + re.frame.height + ) { + FuncStruct.hoverFuncStruct = re; + find = true; + } + } else { + if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + FuncStruct.hoverFuncStruct = re; + find = true; + } + } + } + } + if (!find && row.isHover) FuncStruct.hoverFuncStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) {} +} + +export function func( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0, len = res.length; i < len; i++) { + if ((res[i].startTs || 0) + (res[i].dur || 0) >= startNS && (res[i].startTs || 0) <= endNS) { + FuncStruct.setFuncFrame(res[i], 0, startNS, endNS, totalNS, frame); + } else { + res[i].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + let groups = list + .filter((it) => (it.startTs ?? 0) + (it.dur ?? 0) >= startNS && (it.startTs ?? 0) <= endNS) + .map((it) => { + FuncStruct.setFuncFrame(it, 0, startNS, endNS, totalNS, frame); + return it; + }) + .reduce((pre, current, index, arr) => { + (pre[`${current.frame.x}-${current.depth}`] = pre[`${current.frame.x}-${current.depth}`] || []).push(current); + return pre; + }, {}); + Reflect.ownKeys(groups).map((kv) => { + let arr = groups[kv].sort((a: any, b: any) => b.dur - a.dur); + res.push(arr[0]); + }); + } +} + +export class FuncStruct extends BaseStruct { + static hoverFuncStruct: FuncStruct | undefined; + static selectFuncStruct: FuncStruct | undefined; + argsetid: number | undefined; // 53161 + depth: number | undefined; // 0 + dur: number | undefined; // 570000 + flag: string | undefined; // 570000 + funName: string | undefined; //"binder transaction" + id: number | undefined; // 92749 + is_main_thread: number | undefined; // 0 + parent_id: number | undefined; // null + startTs: number | undefined; // 9729867000 + threadName: string | undefined; // "Thread-15" + tid: number | undefined; // 2785 + identify: number | undefined; + track_id: number | undefined; // 414 + textMetricsWidth: number | undefined; + + static setFuncFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number, x2: number; + if ((node.startTs || 0) > startNS && (node.startTs || 0) < endNS) { + x1 = ns2x(node.startTs || 0, startNS, endNS, totalNS, frame); + } else { + x1 = 0; + } + if ((node.startTs || 0) + (node.dur || 0) > startNS && (node.startTs || 0) + (node.dur || 0) < endNS) { + x2 = ns2x((node.startTs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } else { + x2 = frame.width; + } + if (!node.frame) { + node.frame = {}; + } + let getV: number = x2 - x1 < 1 ? 1 : x2 - x1; + node.frame.x = Math.floor(x1); + node.frame.y = node.depth * 20; + node.frame.width = Math.ceil(getV); + node.frame.height = 20; + } + + static draw(ctx: CanvasRenderingContext2D, data: FuncStruct) { + if (data.frame) { + let isBinder = FuncStruct.isBinder(data); + if (data.dur == undefined || data.dur == null) { + } else { + ctx.globalAlpha = 1; + ctx.fillStyle = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)]; + let textColor = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)]; + let miniHeight = 20; + if (FuncStruct.hoverFuncStruct && data.funName == FuncStruct.hoverFuncStruct.funName) { + ctx.globalAlpha = 0.7; + } + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + if (data.frame.width > 10) { + ctx.strokeStyle = '#fff'; + ctx.lineWidth = 1; + ctx.strokeRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + ctx.fillStyle = ColorUtils.funcTextColor(textColor); + FuncStruct.drawString(ctx, `${data.funName || ''}`, 5, data.frame, data); + } + if (FuncStruct.isSelected(data)) { + ctx.strokeStyle = '#000'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2); + } + } + } + } + + static drawString( + ctx: CanvasRenderingContext2D, + str: string, + textPadding: number, + frame: Rect, + func: FuncStruct + ): boolean { + if (func.textMetricsWidth === undefined) { + func.textMetricsWidth = ctx.measureText(str).width; + } + let charWidth = Math.round(func.textMetricsWidth / str.length); + let fillTextWidth = frame.width - textPadding * 2; + if (func.textMetricsWidth < fillTextWidth) { + let x2 = Math.floor(frame.width / 2 - func.textMetricsWidth / 2 + frame.x + textPadding); + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), fillTextWidth); + return true; + } else { + if (fillTextWidth >= charWidth) { + let chatNum = fillTextWidth / charWidth; + let x1 = frame.x + textPadding; + if (chatNum < 2) { + ctx.fillText(str.substring(0, 1), x1, Math.floor(frame.y + frame.height / 2 + 2), fillTextWidth); + } else { + ctx.fillText( + str.substring(0, chatNum - 1) + '...', + x1, + Math.floor(frame.y + frame.height / 2 + 2), + fillTextWidth + ); + } + return true; + } + } + return false; + } + + static isSelected(data: FuncStruct): boolean { + return ( + FuncStruct.selectFuncStruct != undefined && + FuncStruct.selectFuncStruct.startTs == data.startTs && + FuncStruct.selectFuncStruct.depth == data.depth + ); + } + + static isBinder(data: FuncStruct): boolean { + if ( + data.funName != null && + (data.funName.toLowerCase().startsWith('binder transaction') || + data.funName.toLowerCase().startsWith('binder async') || + data.funName.toLowerCase().startsWith('binder reply')) + ) { + return true; + } else { + return false; + } + } + + static isBinderAsync(data: FuncStruct): boolean { + if (data.funName != null && data.funName.toLowerCase().includes('async')) { + return true; + } else { + return false; + } + } +} + +const padding = 1; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHeap.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHeap.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ee15780b55c30b8e9bb860759afdd8cee4064d9 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHeap.ts @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Rect, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +export class NativeMemoryRender extends Render { + renderMainThread(req: any, row: TraceRow) {} +} +export class HeapRender { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + heap( + list, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + let find = false; + for (let re of filter) { + if (row.isHover && re.frame && !find && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + HeapStruct.hoverHeapStruct = re; + find = true; + } + } + for (let re of filter) { + HeapStruct.draw(req.context, re, row.drawType); + } + if (!find && row.isHover) HeapStruct.hoverHeapStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + heap(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + heap(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.canvas.width, req.canvas.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startTime, + arr[arr.length - 1].startTime + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + HeapStruct.hoverHeapStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + HeapStruct.hoverHeapStruct = re; + break; + } + } + } else { + HeapStruct.hoverHeapStruct = req.params.hoverHeapStruct; + } + for (let re of filter) { + HeapStruct.draw(req.context, re, req.params.drawType); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: HeapStruct.hoverHeapStruct, + }); + } +} +export function heap( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startTime || 0) + (it.dur || 0) > (startNS || 0) && (it.startTime || 0) < (endNS || 0)) { + HeapStruct.setFrame(res[i], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + res[i].frame = null; + } + } + return; + } + res.length = 0; + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startTime || 0) + (it.dur || 0) > (startNS || 0) && (it.startTime || 0) < (endNS || 0)) { + HeapStruct.setFrame(it, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if (i > 0) { + let last = list[i - 1]; + if (last.frame?.x != it.frame.x || last.frame.width != it.frame.width) { + res.push(it); + } + } else { + res.push(it); + } + } + } +} + +export class HeapStruct extends BaseStruct { + static hoverHeapStruct: HeapStruct | undefined; + static selectHeapStruct: HeapStruct | undefined; + startTime: number | undefined; + endTime: number | undefined; + dur: number | undefined; + heapsize: number | undefined; + density: number | undefined; + maxHeapSize: number = 0; + minHeapSize: number = 0; + maxDensity: number = 0; + minDensity: number = 0; + + static setFrame(node: HeapStruct, padding: number, startNS: number, endNS: number, totalNS: number, frame: Rect) { + let x1: number, x2: number; + if ((node.startTime || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startTime || 0, startNS, endNS, totalNS, frame); + } + if ((node.startTime || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x( + // @ts-ignore + node.startTime + node.dur, + startNS, + endNS, + totalNS, + frame + ); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + let rectangle: Rect = new Rect( + Math.floor(x1), + Math.ceil(frame.y + padding), + Math.ceil(getV), + Math.floor(frame.height - padding * 2) + ); + node.frame = rectangle; + } + + static draw(ctx: CanvasRenderingContext2D, data: HeapStruct, drawType: number) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = '#2db3aa'; + ctx.strokeStyle = '#2db3aa'; + let drawHeight: number = 0; + if (drawType == 0) { + if (data.minHeapSize < 0) { + drawHeight = Math.ceil( + (((data.heapsize || 0) - data.minHeapSize) * (data.frame.height || 0)) / + (data.maxHeapSize - data.minHeapSize) + ); + } else { + drawHeight = Math.ceil(((data.heapsize || 0) * (data.frame.height || 0)) / data.maxHeapSize); + } + } else { + if (data.minDensity < 0) { + drawHeight = Math.ceil( + (((data.density || 0) - data.minDensity) * (data.frame.height || 0)) / (data.maxDensity - data.minDensity) + ); + } else { + drawHeight = Math.ceil(((data.density || 0) * (data.frame.height || 0)) / data.maxDensity); + } + } + if (data == HeapStruct.hoverHeapStruct || data == HeapStruct.selectHeapStruct) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.ts new file mode 100644 index 0000000000000000000000000000000000000000..76257b79bb2cf7dc095401da32a32d9bf4985641 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.ts @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2022 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 { BaseStruct, Rect, Render, isFrameContainPoint } from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +export class HeapSnapshotRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + traceRange: any; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + if (filter.length == 0) { + for (let file of list) { + file.start_time = file.start_time - req.traceRange[0].start_ts; + file.end_time = file.end_time - req.traceRange[0].start_ts; + } + } + HeapSnapshot( + list, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + (TraceRow.range?.endNS ?? 0) - (TraceRow.range?.startNS! ?? 0), + row.frame + ); + req.context!.beginPath(); + for (let re of filter) { + HeapSnapshotStruct.draw(req.context, re); + } + for (let re of filter) { + if (re.frame && !isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + HeapSnapshotStruct.hoverSnapshotStruct = undefined; + } + if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + HeapSnapshotStruct.hoverSnapshotStruct = re; + break; + } + } + req.context!.closePath(); + } +} +export function HeapSnapshot( + list: Array, + filter: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any +) { + for (let i in list) { + HeapSnapshotStruct.setFrame(list[i], startNS || 0, endNS || 0, totalNS || 0, frame); + } + filter.length = 0; + for (let i = 0, len = list.length; i < len; i++) { + if (list[i].frame) { + filter.push(list[i]); + } + } +} +const padding = 3; +export class HeapSnapshotStruct extends BaseStruct { + start_time: number = 0; + end_time: number = 0; + id: number = 0; + pid: number = 0; + file_name: string | undefined; + textMetricsWidth: number | undefined; + static hoverSnapshotStruct: HeapSnapshotStruct | undefined; + static selectSnapshotStruct: HeapSnapshotStruct | undefined; + + static setFrame(node: any, startNS: number, endNS: number, totalNS: number, frame: Rect) { + node.frame = null; + if ((node.start_time - startNS || node.start_time - startNS === 0) && node.end_time - node.start_time) { + let rectangle: Rect = new Rect( + Math.floor(((node.start_time - startNS) / totalNS) * frame.width), + 0, + Math.ceil(((node.end_time - node.start_time) / totalNS) * frame.width), + 40 + ); + node.frame = rectangle; + } + } + + static draw(ctx: CanvasRenderingContext2D, data: HeapSnapshotStruct): void { + if (data.frame) { + ctx.fillStyle = 'rgb(86,192,197)'; + ctx!.fillRect(data.frame!.x, data.frame!.y + padding, data.frame!.width, data.frame!.height - padding * 2); + if (data.frame!.width > 7) { + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + ctx.fillStyle = '#fff'; + HeapSnapshotStruct.drawString(ctx, data.file_name || '', 2, data.frame!, data); + } + if ( + HeapSnapshotStruct.selectSnapshotStruct && + HeapSnapshotStruct.equals(HeapSnapshotStruct.selectSnapshotStruct, data) + ) { + ctx.strokeStyle = '#232c5d'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame!.x, data.frame!.y + padding, data.frame!.width - 2, data.frame!.height - padding * 2); + } + } + } + + static drawString( + ctx: CanvasRenderingContext2D, + str: string, + textPadding: number, + frame: Rect, + data: HeapSnapshotStruct + ) { + if (data.textMetricsWidth === undefined) { + data.textMetricsWidth = ctx.measureText(str).width; + } + let charWidth = Math.round(data.textMetricsWidth / str.length); + let fillTextWidth = frame.width - textPadding * 2; + if (data.textMetricsWidth < fillTextWidth) { + let x2 = Math.floor(frame.width / 2 - data.textMetricsWidth / 2 + frame.x + textPadding); + ctx.textBaseline = 'middle'; + ctx.font = '12px sans-serif'; + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2), fillTextWidth); + } else { + if (fillTextWidth >= charWidth) { + let chatNum = fillTextWidth / charWidth; + let x1 = frame.x + textPadding; + ctx.textBaseline = 'middle'; + ctx.font = '12px sans-serif'; + if (chatNum < 2) { + ctx.fillText(str.substring(0, 1), x1, Math.floor(frame.y + frame.height / 2), fillTextWidth); + } else { + ctx.fillText( + str.substring(0, chatNum - 1) + '...', + x1, + Math.floor(frame.y + frame.height / 2), + fillTextWidth + ); + } + } + } + } + + static equals(d1: HeapSnapshotStruct, d2: HeapSnapshotStruct): boolean { + return ( + d1 && + d2 && + d1.file_name == d2.file_name && + d1.id == d2.id && + d1.pid == d2.pid && + d1.start_time == d2.start_time && + d1.end_time == d2.end_time + ); + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHeapTimeline.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHeapTimeline.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8d247fec459a6c1ec11e27f2493c86561ecaabc --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHeapTimeline.ts @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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 { BaseStruct, Rect } from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { HeapSample } from '../../../js-heap/model/DatabaseStruct.js'; + +export class HeapTimelineRender { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + samples: Array; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + HeapTimelineStruct.samples = req.samples; + HeapTimeline( + list, + filter, + HeapTimelineStruct.samples, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + (TraceRow.range?.endNS ?? 0) - (TraceRow.range?.startNS! ?? 0), + row.frame + ); + for (let re of filter) { + HeapTimelineStruct.draw(req.context, re); + } + } +} +export function HeapTimeline( + list: Array, + filter: Array, + samples: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any +) { + let maxSize = 0; + let index = []; + + for (let i = 1; i < samples.length; i++) { + if (samples[i].size > 0) { + maxSize = Math.max(maxSize, samples[i].size); + index.push(i); + } + } + filter.length = 0; + for (let i of index) { + HeapTimelineStruct.setFrame( + samples[i].timestamp, + samples[i].size, + maxSize, + list[i], + startNS || 0, + endNS || 0, + totalNS || 0, + frame + ); + } + for (let i = 0, len = list.length; i < len; i++) { + if (list[i].frame) { + filter.push(list[i]); + } + } +} +export class HeapTimelineStruct extends BaseStruct { + static samples: Array; + + static setFrame( + timestamp_us: any, + size: number, + maxSize: number, + node: any, + startNS: number, + endNS: number, + totalNS: number, + frame: Rect + ) { + node.frame = null; + // us * 1000 = ns + if (node.timestamp_us * 1000 > startNS && node.timestamp_us * 1000 < endNS && node.timestamp_us == timestamp_us) { + let rectangle: Rect = new Rect( + Math.floor(((timestamp_us * 1000 - startNS) / totalNS) * frame.width), + 0, + 2, + Math.floor((size / maxSize) * frame.height) < 1 ? 1 : Math.floor((size / maxSize) * frame.height) + ); + node.frame = rectangle; + } + } + + static draw(ctx: CanvasRenderingContext2D, node: HeapTimelineStruct): void { + ctx!.beginPath(); + ctx!.lineWidth = 2; + ctx!.strokeStyle = '#0A59F7'; + ctx!.moveTo(node.frame!.x, 40); + ctx!.lineTo(node.frame!.x, 40 - node.frame!.height); + ctx!.stroke(); + ctx!.closePath(); + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4fd4fb927ddb5817d61e1b2a75c06b749068c27 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.ts @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { HiPerfThreadStruct } from './ProcedureWorkerHiPerfThread.js'; + +export class HiperfCpuRender extends PerfRender { + renderMainThread(req: any, row: TraceRow) { + let list = row.dataList; + let filter = row.dataListCache; + let groupBy10MS = req.scale > 30_000_000; + if (list && row.dataList2.length == 0) { + row.dataList2 = HiPerfCpuStruct.groupBy10MS(list, req.maxCpu, req.intervalPerf); + } + hiPerfCpu( + list, + row.dataList2, + req.type!, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + groupBy10MS, + req.maxCpu, + req.intervalPerf, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let path = new Path2D(); + let find = false; + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if ( + row.isHover && + re.frame && + row.hoverX >= re.frame.x - offset && + row.hoverX <= re.frame.x + re.frame.width + offset + ) { + HiPerfCpuStruct.hoverStruct = re; + find = true; + } + HiPerfCpuStruct.draw(req.context, path, re, groupBy10MS); + } + if (!find && row.isHover) HiPerfCpuStruct.hoverStruct = undefined; + if (groupBy10MS) { + req.context.fill(path); + } else { + req.context.stroke(path); + } + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + let groupBy10MS = req.scale > 100_000_000; + if (list && dataList2.length == 0) { + dataList2 = HiPerfCpuStruct.groupBy10MS(list, req.params.maxCpu, req.intervalPerf); + } + if (req.lazyRefresh) { + hiPerfCpu( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.params.maxCpu, + req.intervalPerf, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + hiPerfCpu( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.params.maxCpu, + req.intervalPerf, + false + ); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + HiPerfCpuStruct.hoverStruct = undefined; + if (req.isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfCpuStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfCpuStruct.hoverStruct = req.params.hoverStruct; + } + HiPerfCpuStruct.selectStruct = req.params.selectStruct; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let path = new Path2D(); + for (let re of filter) { + HiPerfCpuStruct.draw(req.context, path, re, groupBy10MS); + } + if (groupBy10MS) { + req.context.fill(path); + } else { + req.context.stroke(path); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: HiPerfCpuStruct.hoverStruct, + }); + } +} + +export function hiPerfCpu( + arr: Array, + arr2: any, + type: string, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + groupBy10MS: boolean, + maxCpu: number | undefined, + intervalPerf: number, + use: boolean +) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfCpuStruct.setFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list: Array = groupBy10MS ? arr2 : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + let filter = list.filter((it) => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS); + if (groupBy10MS) { + filter.map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfCpuStruct.setFrame(it, pns, startNS, endNS, frame); + res.push(it); + }); + } else { + filter + .map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfCpuStruct.setFrame(it, pns, startNS, endNS, frame); + return it; + }) + .reduce((pre, current) => { + if (!pre[`${current.frame.x}`]) { + pre[`${current.frame.x}`] = []; + pre[`${current.frame.x}`].push(current); + if (res.length == 0) { + res.push(current); + } + if (res[res.length - 1] && Math.abs(current.frame.x - res[res.length - 1].frame.x) > 4) { + res.push(current); + } + } + return pre; + }, {}); + } + } +} + +export class HiPerfCpuStruct extends BaseStruct { + static hoverStruct: HiPerfCpuStruct | undefined; + static selectStruct: HiPerfCpuStruct | undefined; + static path = new Path2D('M 100,100 h 50 v 50 h 50'); + id: number | undefined; + callchain_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfCpuStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0); + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfCpuStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3); + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static drawRoundRectPath(cxt: Path2D, x: number, y: number, width: number, height: number, radius: number) { + cxt.arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2); + cxt.lineTo(x + radius, y + height); + cxt.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI); + cxt.lineTo(x + 0, y + radius); + cxt.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2); + cxt.lineTo(x + width - radius, y + 0); + cxt.arc(x + width - radius, y + radius, radius, (Math.PI * 3) / 2, Math.PI * 2); + cxt.lineTo(x + width, y + height - radius); + cxt.moveTo(x + width / 3, y + height / 5); + cxt.lineTo(x + width / 3, y + (height / 5) * 4); + cxt.moveTo(x + width / 3, y + height / 5); + cxt.bezierCurveTo( + x + width / 3 + 7, + y + height / 5 - 2, + x + width / 3 + 7, + y + height / 5 + 6, + x + width / 3, + y + height / 5 + 4 + ); + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, maxCpu: number | undefined, intervalPerf: number): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + (pre[current['timestamp_group']] = pre[current['timestamp_group']] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = 0; + if (maxCpu != undefined) { + height = Math.floor((obj[aKey].length / (10 / intervalPerf) / maxCpu) * 40); + } else { + height = Math.floor((obj[aKey].length / (10 / intervalPerf)) * 40); + } + arr.push({ + startNS: ns, + dur: 1_000_000_0, + height: height, + }); + } + return arr; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ece0d179e9fc201562ce841db6295b087dfac57 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.ts @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class HiperfEventRender extends PerfRender { + renderMainThread(req: any, row: TraceRow) { + let list = row.dataList; + let list2 = row.dataList2; + let filter = row.dataListCache; + let groupBy10MS = req.scale > 30_000_000; + if (list && row.dataList2.length == 0) { + row.dataList2 = HiPerfEventStruct.groupBy10MS(list, req.intervalPerf, req.type); + } + HiPerfEvent( + list, + list2, + req.type!, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let offset = groupBy10MS ? 0 : 3; + let path = new Path2D(); + let find = false; + for (let re of filter) { + HiPerfEventStruct.draw(req.context, path, re, groupBy10MS); + if (row.isHover) { + if (re.frame && row.hoverX >= re.frame.x - offset && row.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfEventStruct.hoverStruct = re; + find = true; + } + } + } + if (!find && row.isHover) HiPerfEventStruct.hoverStruct = undefined; + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + let maxEvent = HiPerfEventStruct.maxEvent!.get(req.type!) || 0; + let textMetrics = req.context.measureText(maxEvent); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxEvent, 4, 5 + 9); + req.context.stroke(); + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + let groupBy10MS = req.scale > 100_000_000; + if (req.lazyRefresh) { + HiPerfEvent( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + HiPerfEvent( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + false + ); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + HiPerfEventStruct.hoverStruct = undefined; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + if (req.isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfEventStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfEventStruct.hoverStruct = req.params.hoverStruct; + } + HiPerfEventStruct.selectStruct = req.params.selectStruct; + let path = new Path2D(); + for (let re of filter) { + HiPerfEventStruct.draw(req.context, path, re, groupBy10MS); + } + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + drawSelection(req.context, req.params); + let maxEvent = HiPerfEventStruct.maxEvent!.get(req.type!) || 0; + let textMetrics = req.context.measureText(maxEvent); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxEvent, 4, 5 + 9); + req.context.stroke(); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: HiPerfEventStruct.hoverStruct, + }); + } +} +export function HiPerfEvent( + arr: Array, + arr2: any, + type: string, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + groupBy10MS: boolean, + intervalPerf: number, + use: boolean +) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfEventStruct.setFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list: Array = groupBy10MS ? arr2 : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + let filter = list.filter((it) => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS); + if (groupBy10MS) { + filter.map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfEventStruct.setFrame(it, pns, startNS, endNS, frame); + res.push(it); + }); + } else { + filter + .map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfEventStruct.setFrame(it, pns, startNS, endNS, frame); + return it; + }) + .reduce((pre, current) => { + if (!pre[`${current.frame.x}`]) { + pre[`${current.frame.x}`] = []; + pre[`${current.frame.x}`].push(current); + if (res.length == 0) { + res.push(current); + } + if (res[res.length - 1] && Math.abs(current.frame.x - res[res.length - 1].frame.x) > 4) { + res.push(current); + } + } + return pre; + }, {}); + } + } +} + +export class HiPerfEventStruct extends BaseStruct { + static hoverStruct: HiPerfEventStruct | undefined; + static selectStruct: HiPerfEventStruct | undefined; + static path = new Path2D('M 100,100 h 50 v 50 h 50'); + id: number | undefined; + callchain_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + static maxEvent: Map | undefined = new Map(); + sum: number | undefined; + max: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfEventStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0); + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfEventStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3); + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static drawRoundRectPath(cxt: Path2D, x: number, y: number, width: number, height: number, radius: number) { + cxt.arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2); + cxt.lineTo(x + radius, y + height); + cxt.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI); + cxt.lineTo(x + 0, y + radius); + cxt.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2); + cxt.lineTo(x + width - radius, y + 0); + cxt.arc(x + width - radius, y + radius, radius, (Math.PI * 3) / 2, Math.PI * 2); + cxt.lineTo(x + width, y + height - radius); + cxt.moveTo(x + width / 3, y + height / 5); + cxt.lineTo(x + width / 3, y + (height / 5) * 4); + cxt.moveTo(x + width / 3, y + height / 5); + cxt.bezierCurveTo( + x + width / 3 + 7, + y + height / 5 - 2, + x + width / 3 + 7, + y + height / 5 + 6, + x + width / 3, + y + height / 5 + 4 + ); + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, intervalPerf: number, type: string): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + (pre[current['timestamp_group']] = pre[current['timestamp_group']] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + let max = 0; + for (let aKey in obj) { + let sum = obj[aKey].reduce((pre: any, cur: any) => { + return pre + cur.event_count; + }, 0); + if (sum > max) max = sum; + let ns = parseInt(aKey); + arr.push({ + startNS: ns, + dur: 1_000_000_0, + height: 0, + sum: sum, + }); + } + if (typeof HiPerfEventStruct.maxEvent!.get(type) === 'undefined') { + HiPerfEventStruct.maxEvent!.set(type, max); + } + arr.map((it) => { + it.height = Math.floor((40 * it.sum) / max); + it.max = max; + return it; + }); + return arr; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.ts new file mode 100644 index 0000000000000000000000000000000000000000..2fc2a35316b59e1b3924eecf521e5982c865f741 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.ts @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { HiPerfCpuStruct } from './ProcedureWorkerHiPerfCPU.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class HiperfProcessRender extends PerfRender { + renderMainThread(req: any, row: TraceRow) { + let list = row.dataList; + let filter = row.dataListCache; + let groupBy10MS = req.scale > 30_000_000; + if (list && row.dataList2.length == 0) { + row.dataList2 = HiPerfProcessStruct.groupBy10MS(list, req.intervalPerf); + } + hiPerfProcess( + list, + row.dataList2, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let path = new Path2D(); + let offset = groupBy10MS ? 0 : 3; + let find = false; + for (let re of filter) { + HiPerfProcessStruct.draw(req.context, path, re, groupBy10MS); + if (row.isHover) { + if (re.frame && row.hoverX >= re.frame.x - offset && row.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfProcessStruct.hoverStruct = re; + find = true; + } + } + } + if (!find && row.isHover) HiPerfProcessStruct.hoverStruct = undefined; + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + let groupBy10MS = req.scale > 100_000_000; + if (req.lazyRefresh) { + hiPerfProcess( + list, + dataList2, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + hiPerfProcess( + list, + dataList2, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + false + ); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + HiPerfProcessStruct.hoverStruct = undefined; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + if (req.isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfProcessStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfProcessStruct.hoverStruct = req.params.hoverStruct; + } + HiPerfProcessStruct.selectStruct = req.params.selectStruct; + let path = new Path2D(); + for (let re of filter) { + HiPerfProcessStruct.draw(req.context, path, re, groupBy10MS); + } + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + req.context.closePath(); + drawSelection(req.context, req.params); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: HiPerfProcessStruct.hoverStruct, + }); + } +} + +export function hiPerfProcess( + arr: Array, + arr2: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + groupBy10MS: boolean, + intervalPerf: number, + use: boolean +) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfProcessStruct.setFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list = groupBy10MS ? arr2 : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!list[i].frame) { + list[i].frame = {}; + list[i].frame.y = y; + } + list[i].frame.height = it.height; + HiPerfProcessStruct.setFrame(list[i], pns, startNS, endNS, frame); + if (groupBy10MS) { + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) && + (list[i - 1].frame?.height || 0) == (list[i].frame?.height || 0) + ) { + } else { + res.push(list[i]); + } + } else { + if (i > 0 && Math.abs((list[i - 1].frame?.x || 0) - (list[i].frame?.x || 0)) < 4) { + } else { + res.push(list[i]); + } + } + } + } + } +} + +export class HiPerfProcessStruct extends BaseStruct { + static hoverStruct: HiPerfProcessStruct | undefined; + static selectStruct: HiPerfProcessStruct | undefined; + id: number | undefined; + callchain_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + group: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfProcessStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0); + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfCpuStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3); + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, intervalPerf: number): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + (pre[current['timestamp_group']] = pre[current['timestamp_group']] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = 0; + height = Math.floor((obj[aKey].length / (10 / intervalPerf)) * 40); + arr.push({ + startNS: ns, + height: height, + dur: 1_000_000_0, + }); + } + return arr; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfReport.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfReport.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5a069d42a91b51b0462ce8a6b5e1c122e956a1f --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfReport.ts @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; + +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class HiperfReportRender extends PerfRender { + renderMainThread(req: any, row: TraceRow) { + let list = row.dataList; + let filter = row.dataListCache; + let groupBy10MS = req.scale > 30_000_000; + if (list && row.dataList2.length == 0) { + row.dataList2 = HiPerfReportStruct.groupBy10MS(list, req.intervalPerf); + } + HiPerfReport( + list, + row.dataList2, + req.type!, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let path = new Path2D(); + let offset = groupBy10MS ? 0 : 3; + let find = false; + for (let re of filter) { + HiPerfReportStruct.draw(req.context, path, re, groupBy10MS); + if (row.isHover) { + if (re.frame && row.hoverX >= re.frame.x - offset && row.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfReportStruct.hoverStruct = re; + find = true; + } + } + } + if (!find && row.isHover) HiPerfReportStruct.hoverStruct = undefined; + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + let groupBy10MS = req.scale > 100_000_000; + if (req.lazyRefresh) { + HiPerfReport( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + HiPerfReport( + list, + dataList2, + req.type!, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + false + ); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + HiPerfReportStruct.hoverStruct = undefined; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + if (req.isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfReportStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfReportStruct.hoverStruct = req.params.hoverStruct; + } + HiPerfReportStruct.selectStruct = req.params.selectStruct; + let path = new Path2D(); + for (let re of filter) { + HiPerfReportStruct.draw(req.context, path, re, groupBy10MS); + } + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + req.context.closePath(); + drawSelection(req.context, req.params); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: HiPerfReportStruct.hoverStruct, + }); + } +} + +export function HiPerfReport( + arr: Array, + arr2: any, + type: string, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + groupBy10MS: boolean, + intervalPerf: number, + use: boolean +) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfReportStruct.setFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list: Array = groupBy10MS ? arr2 : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + list + .filter((it) => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) + .map((it) => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfReportStruct.setFrame(it, pns, startNS, endNS, frame); + return it; + }) + .reduce((pre, current, index, arr) => { + if (!pre[`${current.frame.x}`]) { + pre[`${current.frame.x}`] = []; + pre[`${current.frame.x}`].push(current); + if (groupBy10MS) { + res.push(current); + } else { + if (res.length == 0) { + res.push(current); + } + if (res[res.length - 1] && Math.abs(current.frame.x - res[res.length - 1].frame.x) > 4) { + res.push(current); + } + } + } + return pre; + }, {}); + } +} + +export class HiPerfReportStruct extends BaseStruct { + static hoverStruct: HiPerfReportStruct | undefined; + static selectStruct: HiPerfReportStruct | undefined; + static path = new Path2D('M 100,100 h 50 v 50 h 50'); + id: number | undefined; + callchain_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfReportStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0); + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfReportStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3); + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static drawRoundRectPath(cxt: Path2D, x: number, y: number, width: number, height: number, radius: number) { + cxt.arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2); + cxt.lineTo(x + radius, y + height); + cxt.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI); + cxt.lineTo(x + 0, y + radius); + cxt.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2); + cxt.lineTo(x + width - radius, y + 0); + cxt.arc(x + width - radius, y + radius, radius, (Math.PI * 3) / 2, Math.PI * 2); + cxt.lineTo(x + width, y + height - radius); + cxt.moveTo(x + width / 3, y + height / 5); + cxt.lineTo(x + width / 3, y + (height / 5) * 4); + cxt.moveTo(x + width / 3, y + height / 5); + cxt.bezierCurveTo( + x + width / 3 + 7, + y + height / 5 - 2, + x + width / 3 + 7, + y + height / 5 + 6, + x + width / 3, + y + height / 5 + 4 + ); + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, intervalPerf: number): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + (pre[current['timestamp_group']] = pre[current['timestamp_group']] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + let max = 0; + for (let aKey in obj) { + let sum = obj[aKey].reduce((pre: any, cur: any) => { + return pre + cur.event_count; + }, 0); + if (sum > max) max = sum; + let ns = parseInt(aKey); + arr.push({ + startNS: ns, + dur: 1_000_000_0, + height: 0, + sum: sum, + }); + } + arr.map((it) => { + it.height = Math.floor((40 * it.sum) / max); + return it; + }); + return arr; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfThread.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfThread.ts new file mode 100644 index 0000000000000000000000000000000000000000..0cb8b2c136e509c4cc3f86238b32b0e74ee102ba --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerHiPerfThread.ts @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + PerfRender, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { HiPerfCpuStruct } from './ProcedureWorkerHiPerfCPU.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class HiperfThreadRender extends PerfRender { + renderMainThread(req: any, row: TraceRow) { + let list = row.dataList; + let filter = row.dataListCache; + let groupBy10MS = req.scale > 30_000_000; + if (list && row.dataList2.length == 0) { + row.dataList2 = HiPerfThreadStruct.groupBy10MS(list, req.intervalPerf); + } + hiPerfThread( + list, + row.dataList2, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let path = new Path2D(); + let offset = groupBy10MS ? 0 : 3; + let find = false; + for (let re of filter) { + HiPerfThreadStruct.draw(req.context, path, re, groupBy10MS); + if (row.isHover) { + if (re.frame && row.hoverX >= re.frame.x - offset && row.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfThreadStruct.hoverStruct = re; + find = true; + } + } + } + if (!find && row.isHover) HiPerfThreadStruct.hoverStruct = undefined; + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array, dataList2: Array) { + let groupBy10MS = req.scale > 100_000_000; + if (req.lazyRefresh) { + hiPerfThread( + list, + dataList2, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + req.useCache || !req.range.refresh + ); + } else { + if (!req.useCache) { + hiPerfThread( + list, + dataList2, + filter, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + groupBy10MS, + req.intervalPerf, + false + ); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + req.context.stroke(); + req.context.beginPath(); + HiPerfThreadStruct.hoverStruct = undefined; + req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; + req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + if (req.isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of filter) { + if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) { + HiPerfThreadStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfThreadStruct.hoverStruct = req.params.hoverStruct; + } + HiPerfThreadStruct.selectStruct = req.params.selectStruct; + let path = new Path2D(); + for (let re of filter) { + HiPerfThreadStruct.draw(req.context, path, re, groupBy10MS); + } + groupBy10MS ? req.context.fill(path) : req.context.stroke(path); + req.context.stroke(); + req.context.closePath(); + drawSelection(req.context, req.params); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: HiPerfThreadStruct.hoverStruct, + }); + } +} + +export function hiPerfThread( + arr: Array, + arr2: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + groupBy10MS: boolean, + intervalPerf: number, + use: boolean +) { + if (use && res.length > 0) { + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0; i < res.length; i++) { + let it = res[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfThreadStruct.setFrame(it, pns, startNS, endNS, frame); + } else { + it.frame = null; + } + } + return; + } + res.length = 0; + if (arr) { + let list = groupBy10MS ? arr2 : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!list[i].frame) { + list[i].frame = {}; + list[i].frame.y = y; + } + list[i].frame.height = it.height; + HiPerfThreadStruct.setFrame(list[i], pns, startNS, endNS, frame); + if (groupBy10MS) { + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) && + (list[i - 1].frame?.height || 0) == (list[i].frame?.height || 0) + ) { + } else { + res.push(list[i]); + } + } else { + if (i > 0 && Math.abs((list[i - 1].frame?.x || 0) - (list[i].frame?.x || 0)) < 4) { + } else { + res.push(list[i]); + } + } + } + } + } +} + +export class HiPerfThreadStruct extends BaseStruct { + static hoverStruct: HiPerfThreadStruct | undefined; + static selectStruct: HiPerfThreadStruct | undefined; + id: number | undefined; + callchain_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfThreadStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0); + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfCpuStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3); + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, intervalPerf: number): Array { + let obj = array + .map((it) => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }) + .reduce((pre, current) => { + (pre[current['timestamp_group']] = pre[current['timestamp_group']] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = 0; + height = Math.floor((obj[aKey].length / (10 / intervalPerf)) * 40); + arr.push({ + startNS: ns, + height: height, + dur: 1_000_000_0, + }); + } + return arr; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerIrq.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerIrq.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5195f7f5a4cdd5be66d203e497d44e00d995bc7 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerIrq.ts @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 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 { BaseStruct, dataFilterHandler, isFrameContainPoint, Rect, Render } from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { ColorUtils } from '../../component/trace/base/ColorUtils.js'; + +export class IrqRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + index: number; + }, + row: TraceRow + ) { + IrqStruct.index = req.index; + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + IrqStruct.draw(req.context, re, row.isHover); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + IrqStruct.hoverIrqStruct = re; + find = true; + } + } + if (!find && row.isHover) IrqStruct.hoverIrqStruct = undefined; + req.context.closePath(); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + } +} + +const padding = 3; +export class IrqStruct extends BaseStruct { + static maxValue: number = 0; + static maxName: string = ''; + static hoverIrqStruct: IrqStruct | undefined; + static selectIrqStruct: IrqStruct | undefined; + static index = 0; + id: number | undefined; + startNS: number | undefined; + name: string | undefined; + dur: number | undefined; //自补充,数据库没有返回 + textMetricsWidth: number | undefined; //自补充 + argSetId: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: IrqStruct, isHover: boolean) { + if (data.frame) { + ctx.fillStyle = ColorUtils.colorForName(data.name || ''); + ctx.strokeStyle = '#232c5d'; + if ((data === IrqStruct.hoverIrqStruct && isHover) || data === IrqStruct.selectIrqStruct) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y + padding, data.frame.width - 2, data.frame.height - padding * 2); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + ctx.fillStyle = '#fff'; + data.frame.width > 7 && IrqStruct.drawString(ctx, data.name || '', 2, data.frame, data); + } + } + + static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect, data: IrqStruct) { + if (data.textMetricsWidth === undefined) { + data.textMetricsWidth = ctx.measureText(str).width; + } + let charWidth = Math.round(data.textMetricsWidth / str.length); + let fillTextWidth = frame.width - textPadding * 2; + if (data.textMetricsWidth < fillTextWidth) { + let x2 = Math.floor(frame.width / 2 - data.textMetricsWidth / 2 + frame.x + textPadding); + ctx.textBaseline = 'middle'; + ctx.font = '8px sans-serif'; + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2), fillTextWidth); + } else { + if (fillTextWidth >= charWidth) { + let chatNum = fillTextWidth / charWidth; + let x1 = frame.x + textPadding; + ctx.textBaseline = 'middle'; + ctx.font = '8px sans-serif'; + if (chatNum < 2) { + ctx.fillText(str.substring(0, 1), x1, Math.floor(frame.y + frame.height / 2), fillTextWidth); + } else { + ctx.fillText( + str.substring(0, chatNum - 1) + '...', + x1, + Math.floor(frame.y + frame.height / 2), + fillTextWidth + ); + } + } + } + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerJank.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerJank.ts new file mode 100644 index 0000000000000000000000000000000000000000..e773180cc5a2e211bca7fc995b5d8d6df2fc8db6 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerJank.ts @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { BaseStruct, isFrameContainPoint, ns2x, Rect, Render, RequestMessage } from './ProcedureWorkerCommon.js'; + +export class JankRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + jank( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + let nsScale = ((TraceRow.range!.endNS || 0) - (TraceRow.range!.startNS || 0)) / (TraceRow.range!.totalNS * 9); + for (let re of filter) { + JankStruct.draw(req.context, re, nsScale); + if (row.isHover) { + if (re.dur == 0 || re.dur == null || re.dur == undefined) { + if ( + re.frame && + row.hoverX >= re.frame.x - 5 && + row.hoverX <= re.frame.x + 5 && + row.hoverY >= re.frame.y && + row.hoverY <= re.frame.y + re.frame.height + ) { + JankStruct.hoverJankStruct = re; + find = true; + } + } else { + if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + JankStruct.hoverJankStruct = re; + find = true; + } + } + } + } + if (!find && row.isHover) JankStruct.hoverJankStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) {} +} + +export function jank( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0, len = res.length; i < len; i++) { + if ((res[i].ts || 0) + (res[i].dur || 0) >= startNS && (res[i].ts || 0) <= endNS) { + JankStruct.setJankFrame(res[i], 0, startNS, endNS, totalNS, frame); + } else { + res[i].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + let groups = list + .filter((it) => (it.ts ?? 0) + (it.dur ?? 0) >= startNS && (it.ts ?? 0) <= endNS) + .map((it) => { + JankStruct.setJankFrame(it, 0, startNS, endNS, totalNS, frame); + return it; + }) + .reduce((pre, current, index, arr) => { + (pre[`${current.frame.x}-${current.depth}`] = pre[`${current.frame.x}-${current.depth}`] || []).push(current); + return pre; + }, {}); + Reflect.ownKeys(groups).map((kv) => { + let arr = groups[kv].sort((a: any, b: any) => b.dur - a.dur); + res.push(arr[0]); + }); + } +} + +export class JankStruct extends BaseStruct { + static hoverJankStruct: JankStruct | undefined; + static selectJankStruct: JankStruct | undefined; + static selectJankStructList: Array = new Array(); + static delJankLineFlag: boolean = true; + id: number | undefined; // sliceid + ts: number | undefined; + dur: number | undefined; + name: string | undefined; + depth: number | undefined; + jank_tag: boolean = false; + cmdline: string | undefined; // process + jank_type: string | undefined; + type: string | undefined; + pid: number | undefined; + frame_type: string | undefined; // app、renderService、frameTime + app_dur: number | undefined; + src_slice: string | undefined; + dst_slice: string | undefined; + rs_ts: number | undefined; + rs_vsync: string | undefined; + rs_dur: number | undefined; + rs_pid: number | undefined; + rs_name: string | undefined; + gpu_dur: number | undefined; + + static setJankFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number, x2: number; + if ((node.ts || 0) > startNS && (node.ts || 0) < endNS) { + x1 = ns2x(node.ts || 0, startNS, endNS, totalNS, frame); + } else { + x1 = 0; + } + if ((node.ts || 0) + (node.dur || 0) > startNS && (node.ts || 0) + (node.dur || 0) < endNS) { + x2 = ns2x((node.ts || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } else { + x2 = frame.width; + } + if (!node.frame) { + node.frame = {}; + } + let getV: number = x2 - x1 < 1 ? 1 : x2 - x1; + node.frame.x = Math.floor(x1); + node.frame.y = node.depth * 20; + node.frame.width = Math.ceil(getV); + node.frame.height = 20; + } + + static draw(ctx: CanvasRenderingContext2D, data: JankStruct, nsScale: number) { + if (data.frame) { + if (data.dur == undefined || data.dur == null || data.dur == 0) { + } else { + ctx.globalAlpha = 1; + ctx.fillStyle = ColorUtils.JANK_COLOR[0]; + if (data.jank_tag) { + ctx.fillStyle = ColorUtils.JANK_COLOR[2]; + } + let miniHeight = 20; + if ( + JankStruct.hoverJankStruct && + data.name == JankStruct.hoverJankStruct.name && + JankStruct.hoverJankStruct.type == data.type && + JankStruct.hoverJankStruct.pid == data.pid && + JankStruct.hoverJankStruct.frame_type == data.frame_type + ) { + ctx.globalAlpha = 0.7; + } + if (data.type == '0') { + ctx.fillStyle = ColorUtils.JANK_COLOR[0]; + if (data.jank_tag) { + ctx.fillStyle = ColorUtils.JANK_COLOR[2]; + } + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + } else { + if (data.frame.width * nsScale < 1.5) { + ctx.fillStyle = '#FFFFFF'; + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width * nsScale, miniHeight - padding * 2); + ctx.fillStyle = ColorUtils.JANK_COLOR[0]; + if (data.jank_tag) { + ctx.fillStyle = ColorUtils.JANK_COLOR[2]; + } + ctx.fillRect( + data.frame.x + data.frame.width * nsScale, + data.frame.y, + data.frame.width - nsScale * 2, + miniHeight - padding * 2 + ); + ctx.fillStyle = '#FFFFFF'; + ctx.fillRect( + data.frame.x + data.frame.width * nsScale + data.frame.width - nsScale * 2, + data.frame.y, + data.frame.width * nsScale, + miniHeight - padding * 2 + ); + } else { + ctx.fillStyle = ColorUtils.JANK_COLOR[0]; + if (data.jank_tag) { + ctx.fillStyle = ColorUtils.JANK_COLOR[2]; + } + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); + } + } + + if (data.frame.width > 10) { + ctx.fillStyle = '#fff'; + JankStruct.drawString(ctx, `${data.name || ''}`, 5, data.frame); + } + if (JankStruct.isSelected(data)) { + ctx.strokeStyle = '#000'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2); + } + } + } + } + + static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect): boolean { + let textMetrics = ctx.measureText(str); + let charWidth = Math.round(textMetrics.width / str.length); + if (textMetrics.width < frame.width - textPadding * 2) { + let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding); + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2); + return true; + } + if (frame.width - textPadding * 2 > charWidth * 4) { + let chatNum = (frame.width - textPadding * 2) / charWidth; + let x1 = frame.x + textPadding; + ctx.fillText( + str.substring(0, chatNum - 4) + '...', + x1, + Math.floor(frame.y + frame.height / 2 + 2), + frame.width - textPadding * 2 + ); + return true; + } + return false; + } + + static isSelected(data: JankStruct): boolean { + return ( + JankStruct.selectJankStruct != undefined && + JankStruct.selectJankStruct.ts == data.ts && + JankStruct.selectJankStruct.depth == data.depth && + JankStruct.selectJankStruct.type == data.type && + JankStruct.selectJankStruct.pid == data.pid && + JankStruct.selectJankStruct.frame_type == data.frame_type + ); + } +} + +const padding = 1; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerMem.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerMem.ts new file mode 100644 index 0000000000000000000000000000000000000000..57da3bae72d1caa40e144ee5e968a1e78ce61914 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerMem.ts @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + PerfRender, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { CpuStruct } from './ProcedureWorkerCPU.js'; + +export class MemRender extends Render { + renderMainThread( + req: { + useCache: boolean; + context: CanvasRenderingContext2D; + type: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + mem( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let find = false; + for (let re of filter) { + ProcessMemStruct.draw(req.context, re); + if (row.isHover) { + if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + ProcessMemStruct.hoverProcessMemStruct = re; + find = true; + } + } + } + if (!find && row.isHover) ProcessMemStruct.hoverProcessMemStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + mem(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + mem(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startTime, + arr[arr.length - 1].startTime + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + ProcessMemStruct.hoverProcessMemStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + ProcessMemStruct.hoverProcessMemStruct = re; + break; + } + } + } else { + ProcessMemStruct.hoverProcessMemStruct = req.params.hoverProcessMemStruct; + } + for (let re of filter) { + ProcessMemStruct.draw(req.context, re); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: ProcessMemStruct.hoverProcessMemStruct, + }); + } +} + +function setMemFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number; + let x2: number; + if ((node.startTime || 0) <= startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startTime || 0, startNS, endNS, totalNS, frame); + } + if ((node.startTime || 0) + (node.duration || 0) >= endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startTime || 0) + (node.duration || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(x1); + node.frame.y = Math.floor(frame.y + padding); + node.frame.width = Math.ceil(getV); + node.frame.height = Math.floor(frame.height - padding * 2); +} + +export function mem( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0, len = res.length; i < len; i++) { + if ((res[i].startTime || 0) + (res[i].duration || 0) > startNS && (res[i].startTime || 0) < endNS) { + setMemFrame(res[i], 5, startNS, endNS, totalNS, frame); + } else { + res[i].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startTime || 0) + (it.duration || 0) > startNS && (it.startTime || 0) < endNS) { + setMemFrame(list[i], 5, startNS, endNS, totalNS, frame); + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) + ) { + } else { + res.push(list[i]); + } + } + } + } +} + +export class ProcessMemStruct extends BaseStruct { + static hoverProcessMemStruct: ProcessMemStruct | undefined; + trackId: number | undefined; + processName: string | undefined; + pid: number | undefined; + upid: number | undefined; + trackName: string | undefined; + type: string | undefined; + track_id: string | undefined; + value: number | undefined; + startTime: number | undefined; + duration: number | undefined; + maxValue: number | undefined; + delta: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: ProcessMemStruct) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = ColorUtils.colorForTid(data.maxValue || 0); + ctx.strokeStyle = ColorUtils.colorForTid(data.maxValue || 0); + if ( + data.track_id === ProcessMemStruct.hoverProcessMemStruct?.track_id && + data.startTime === ProcessMemStruct.hoverProcessMemStruct?.startTime + ) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / (data.maxValue || 1) + ); + drawHeight = drawHeight > 0 ? drawHeight : 1; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = ((data.value || 0) * (data.frame.height || 0) * 1.0) / (data.maxValue || 1); + drawHeight = drawHeight > 0 ? drawHeight : 1; + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerMemoryAbility.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerMemoryAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8fccbb4e348214fd29c79dbb6d29f12f8a55722 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerMemoryAbility.ts @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class MemoryAbilityRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxMemoryByte: number; + maxMemoryByteName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + MemoryAbilityMonitorStruct.draw(req.context, re, req.maxMemoryByte, row.isHover); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = re; + find = true; + } + } + if (!find && row.isHover) MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = undefined; + req.context.closePath(); + let textMetrics = req.context.measureText(req.maxMemoryByteName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(req.maxMemoryByteName, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + memoryAbility(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + memoryAbility(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + MemoryAbilityMonitorStruct.maxMemoryByte = req.params.maxMemoryByte; + MemoryAbilityMonitorStruct.maxMemoryByteName = req.params.maxMemoryByteName; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = re; + break; + } + } + } + MemoryAbilityMonitorStruct.selectMemoryAbilityStruct = req.params.selectMemoryAbilityStruct; + for (let re of filter) { + MemoryAbilityMonitorStruct.draw(req.context, re, MemoryAbilityMonitorStruct.maxMemoryByte, true); + } + drawSelection(req.context, req.params); + req.context.closePath(); + let s = MemoryAbilityMonitorStruct.maxMemoryByteName; + let textMetrics = req.context.measureText(s); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(s, 4, 5 + 9); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + }); + } +} + +export function memoryAbility( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let item = res[i]; + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + MemoryAbilityMonitorStruct.setMemoryFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + item.frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0); + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0); + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + MemoryAbilityMonitorStruct.setMemoryFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } +} + +export class MemoryAbilityMonitorStruct extends BaseStruct { + static maxMemoryByte: number = 0; + static maxMemoryByteName: string = '0 MB'; + static hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + static selectMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + cpu: number | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; + + static draw( + context2D: CanvasRenderingContext2D, + data: MemoryAbilityMonitorStruct, + maxMemoryByte: number, + isHover: boolean + ) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.startNS && isHover) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxMemoryByte); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxMemoryByte); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setMemoryFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.startNS || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.startNS || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} + +const textPadding = 2; diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerNetworkAbility.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerNetworkAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..f16e05dade6bfad283b43d18ce1755f562dfe997 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerNetworkAbility.ts @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +export class NetworkAbilityRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxNetworkRate: number; + maxNetworkRateName: string; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let find = false; + for (let re of filter) { + NetworkAbilityMonitorStruct.draw(req.context, re, req.maxNetworkRate, row.isHover); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = re; + find = true; + } + } + if (!find && row.isHover) NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = undefined; + req.context.closePath(); + let textMetrics = req.context.measureText(req.maxNetworkRateName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(req.maxNetworkRateName, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) {} +} + +export class NetworkAbilityMonitorStruct extends BaseStruct { + static maxNetworkRate: number = 0; + static maxNetworkRateName: string = '0 KB/S'; + static hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + static selectNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + value: number | undefined; + startNS: number | undefined; + + static draw( + context2D: CanvasRenderingContext2D, + data: NetworkAbilityMonitorStruct, + maxNetworkRate: number, + isHover: boolean + ) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index); + context2D.strokeStyle = ColorUtils.colorForTid(index); + if (data.startNS === NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.startNS && isHover) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxNetworkRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4); + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxNetworkRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerPerfCallchains.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerPerfCallchains.ts new file mode 100644 index 0000000000000000000000000000000000000000..e676b085fd47d87e21509a5cfe5827e7fd42d60b --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerPerfCallchains.ts @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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. + */ + +class PerfCallChainThread extends Worker { + busy: boolean = false; + taskMap: any = {}; + uuid(): string { + // @ts-ignore + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c: any) => + (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) + ); + } + + queryFunc(name: string, args: any, handler: Function, action: string | null) { + this.busy = true; + let id = this.uuid(); + this.taskMap[id] = handler; + let msg = { + id: id, + name: name, + action: action || 'exec', + params: args, + }; + this.postMessage(msg); + } +} + +export class PerfCallChainPool { + maxThreadNumber: number = 0; + works: Array = []; + + close = async () => { + for (let i = 0; i < this.works.length; i++) { + let thread = this.works[i]; + thread.terminate(); + } + this.works.length = 0; + }; + + init = async () => { + await this.close(); + let thread = new PerfCallChainThread('trace/component/chart/PerfDataQuery.js', { type: 'module' }); //trace/component/chart/PerfDataQuery.js + thread!.onmessage = (event: MessageEvent) => { + thread.busy = false; + let fun = thread.taskMap[event.data.id]; + if (fun) { + fun(event.data.results); + } + Reflect.deleteProperty(thread.taskMap, event.data.id); + }; + thread!.onmessageerror = (e) => {}; + thread!.onerror = (e) => {}; + thread!.busy = false; + this.works?.push(thread!); + }; + + submit(name: string, args: any, handler: Function, action: string | null) { + let noBusyThreads = this.works.filter((it) => !it.busy); + let thread: PerfCallChainThread; + if (noBusyThreads.length > 0) { + //取第一个空闲的线程进行任务 + thread = noBusyThreads[0]; + thread.queryFunc(name, args, handler, action); + } else { + // 随机插入一个线程中 + thread = this.works[Math.floor(Math.random() * this.works.length)]; + thread.queryFunc(name, args, handler, action); + } + } +} + +export const callChainsPool = new PerfCallChainPool(); diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerProcess.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerProcess.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf5a4366ff29842ea8191668850308e84d686fbd --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerProcess.ts @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { CpuStruct } from './ProcedureWorkerCPU.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class ProcessRender extends Render { + renderMainThread(req: any, row: TraceRow) { + let list = row.dataList; + let filter = row.dataListCache; + proc( + list, + filter, + TraceRow.range!.startNS, + TraceRow.range!.endNS, + TraceRow.range!.totalNS, + row.frame, + req.useCache || !TraceRow.range!.refresh + ); + req.context.beginPath(); + let path = new Path2D(); + let miniHeight: number = 0; + miniHeight = Math.round((row.frame.height - CpuStruct.cpuCount * 2) / CpuStruct.cpuCount); + req.context.fillStyle = ColorUtils.colorForTid(req.pid || 0); + for (let re of filter) { + ProcessStruct.draw(req.context, path, re, miniHeight); + } + req.context.fill(path); + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + proc(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + proc(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startTime, + arr[arr.length - 1].startTime + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + CpuStruct.cpuCount = req.params.cpuCount; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + let path = new Path2D(); + let miniHeight: number = 0; + miniHeight = Math.round((req.frame.height - CpuStruct.cpuCount * 2) / CpuStruct.cpuCount); + req.context.fillStyle = ColorUtils.colorForTid(req.params.pid || 0); + for (let re of filter) { + ProcessStruct.draw(req.context, path, re, miniHeight); + } + req.context.fill(path); + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: undefined, + }); + } +} +export function proc( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + res.forEach((it) => ProcessStruct.setProcessFrame(it, 5, startNS || 0, endNS || 0, totalNS || 0, frame)); + return; + } + res.length = 0; + if (list) { + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startTime || 0) + (it.dur || 0) > (startNS || 0) && (it.startTime || 0) < (endNS || 0)) { + ProcessStruct.setProcessFrame(list[i], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) + ) { + } else { + res.push(list[i]); + } + } + } + } +} + +const padding = 1; + +export class ProcessStruct extends BaseStruct { + cpu: number | undefined; + dur: number | undefined; + id: number | undefined; + pid: number | undefined; + process: string | undefined; + startTime: number | undefined; + state: string | undefined; + thread: string | undefined; + tid: number | undefined; + ts: number | undefined; + type: string | undefined; + utid: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: ProcessStruct, miniHeight: number) { + if (data.frame) { + path.rect(data.frame.x, data.frame.y + (data.cpu || 0) * miniHeight + padding, data.frame.width, miniHeight); + } + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startTime || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startTime || 0) - startNS) / pns); + } + if ((node.startTime || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startTime || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static setProcessFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number; + let x2: number; + if ((node.startTime || 0) < startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startTime || 0, startNS, endNS, totalNS, frame); + } + if ((node.startTime || 0) + (node.dur || 0) > endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startTime || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(x1); + node.frame.y = Math.floor(frame.y + 2); + node.frame.width = Math.ceil(getV); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerSmaps.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerSmaps.ts new file mode 100644 index 0000000000000000000000000000000000000000..040a451ddae9861fb4b905502c7f290cf775ca40 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerSmaps.ts @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + dataFilterHandler, + drawFlagLine, + drawLines, + drawSelection, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { CpuAbilityMonitorStruct } from './ProcedureWorkerCpuAbility.js'; + +export class SmapsRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + rowName: string; + maxValue: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startNS', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + let drawColor = '#0A59F7'; + if (req.rowName != undefined) { + switch (req.rowName) { + case 'dirty': + drawColor = '#0A59F7'; + break; + case 'swapper': + drawColor = '#46B1E3'; + break; + case 'resident_size': + drawColor = '#564AF7'; + break; + } + } + let find = false; + for (let re of filter) { + SmapsStruct.draw(req.context, re, req.maxValue, drawColor, row.isHover); + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + SmapsStruct.hoverSmapsStruct = re; + find = true; + } + } + if (!find && row.isHover) SmapsStruct.hoverSmapsStruct = undefined; + + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + smaps(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + smaps(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + req.context.beginPath(); + let maxValue = 0; + let maxValueName = ''; + if (req.params.maxValue != undefined || req.params.maxValueName != undefined) { + maxValue = req.params.maxValue; + maxValueName = req.params.maxValueName; + } + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + SmapsStruct.hoverSmapsStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + SmapsStruct.hoverSmapsStruct = re; + break; + } + } + } + let drawColor = '#0A59F7'; + if (req.params.rowName != undefined) { + switch (req.params.rowName) { + case 'dirty': + drawColor = '#0A59F7'; + break; + case 'swapper': + drawColor = '#46B1E3'; + break; + case 'resident_size': + drawColor = '#564AF7'; + break; + } + } + SmapsStruct.selectSmapsStruct = req.params.selectSmapsStruct; + for (let re of filter) { + SmapsStruct.draw(req.context, re, maxValue, drawColor, true); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: SmapsStruct.hoverSmapsStruct, + }); + } +} + +export function smaps( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0; i < res.length; i++) { + let item = res[i]; + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + SmapsStruct.setSmapsFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + item.frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0); + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0); + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + SmapsStruct.setSmapsFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } +} + +export class SmapsStruct extends BaseStruct { + static maxValue: number = 0; + static maxValueName: string = '0 KB/S'; + static hoverSmapsStruct: SmapsStruct | undefined; + static selectSmapsStruct: SmapsStruct | undefined; + value: number | undefined; + startNS: number | undefined; + dur: number | undefined; + + static draw( + context2D: CanvasRenderingContext2D, + data: SmapsStruct, + maxValue: number, + drawColor: string, + isHover: boolean + ) { + if (data.frame) { + let width = data.frame.width || 0; + context2D.fillStyle = drawColor; + context2D.strokeStyle = drawColor; + if (data.startNS === SmapsStruct.hoverSmapsStruct?.startNS && isHover) { + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxValue); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4); + context2D.stroke(); + } else { + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxValue); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setSmapsFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.startNS || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.startNS || 0, startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerThread.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerThread.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e61d73776b37e8a6037d27369980dcb49308643 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerThread.ts @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + dataFilterHandler, + isFrameContainPoint, + Rect, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { Utils } from '../../component/trace/base/Utils.js'; + +export class ThreadRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + translateY: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + dataFilterHandler(list, filter, { + startKey: 'startTime', + durKey: 'dur', + startNS: TraceRow.range?.startNS ?? 0, + endNS: TraceRow.range?.endNS ?? 0, + totalNS: TraceRow.range?.totalNS ?? 0, + frame: row.frame, + paddingTop: 5, + useCache: req.useCache || !(TraceRow.range?.refresh ?? false), + }); + req.context.beginPath(); + for (let re of filter) { + re.translateY = req.translateY; + ThreadStruct.draw(req.context, re); + if (row.isHover && re.frame && isFrameContainPoint(re.frame!, row.hoverX, row.hoverY)) { + ThreadStruct.hoverThreadStruct = re; + } + } + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) {} +} + +const padding = 3; + +export class ThreadStruct extends BaseStruct { + static runningColor: string = '#467b3b'; + static rColor = '#a0b84d'; + static otherColor = '#673ab7'; + static uninterruptibleSleepColor = '#f19d38'; + static uninterruptibleSleepNonIOColor = '#795548'; + static traceColor = '#0d47a1'; + static sColor = '#FBFBFB'; + static hoverThreadStruct: ThreadStruct | undefined; + static selectThreadStruct: ThreadStruct | undefined; + + hasSched: number | undefined; // 14724852000 + pid: number | undefined; // 2519 + processName: string | undefined; //null + threadName: string | undefined; //"ACCS0" + tid: number | undefined; //2716 + upid: number | undefined; // 1 + utid: number | undefined; // 1 + cpu: number | undefined; // null + dur: number | undefined; // 405000 + argSetID: number | undefined; // 405000 + end_ts: number | undefined; // null + id: number | undefined; // 1 + is_main_thread: number | undefined; // 0 + name: string | undefined; // "ACCS0" + startTime: number | undefined; // 58000 + start_ts: number | undefined; // null + state: string | undefined; // "S" + type: string | undefined; // "thread" + textMetricsWidth: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: ThreadStruct) { + if (data.frame) { + ctx.globalAlpha = 1; + let stateText = ThreadStruct.getEndState(data.state || ''); + ctx.fillStyle = Utils.getStateColor(data.state || ''); + if ('S' === data.state) { + ctx.globalAlpha = 0.2; + } + ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2); + ctx.fillStyle = '#fff'; + if ('S' !== data.state) { + data.frame.width > 7 && ThreadStruct.drawString(ctx, stateText, 2, data.frame, data); + } + if ( + ThreadStruct.selectThreadStruct && + ThreadStruct.equals(ThreadStruct.selectThreadStruct, data) && + ThreadStruct.selectThreadStruct.state != 'S' + ) { + ctx.strokeStyle = '#232c5d'; + ctx.lineWidth = 2; + ctx.strokeRect(data.frame.x, data.frame.y + padding, data.frame.width - 2, data.frame.height - padding * 2); + } + } + } + + static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect, data: ThreadStruct) { + if (data.textMetricsWidth === undefined) { + data.textMetricsWidth = ctx.measureText(str).width; + } + let charWidth = Math.round(data.textMetricsWidth / str.length); + let fillTextWidth = frame.width - textPadding * 2; + if (data.textMetricsWidth < fillTextWidth) { + let x2 = Math.floor(frame.width / 2 - data.textMetricsWidth / 2 + frame.x + textPadding); + ctx.textBaseline = 'middle'; + ctx.font = '8px sans-serif'; + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2), fillTextWidth); + } else { + if (fillTextWidth >= charWidth) { + let chatNum = (frame.width - textPadding * 2) / charWidth; + let x1 = frame.x + textPadding; + ctx.textBaseline = 'middle'; + ctx.font = '8px sans-serif'; + if (chatNum < 2) { + ctx.fillText(str.substring(0, 1), x1, Math.floor(frame.y + frame.height / 2), fillTextWidth); + } else { + ctx.fillText( + str.substring(0, chatNum - 1) + '...', + x1, + Math.floor(frame.y + frame.height / 2), + fillTextWidth + ); + } + } + } + } + + static getEndState(state: string): string { + let statusMapElement = Utils.getEndState(state); + if (statusMapElement) { + return statusMapElement; + } else { + if ('' == statusMapElement || statusMapElement == null) { + return ''; + } + return 'Unknown State'; + } + } + + static equals(d1: ThreadStruct, d2: ThreadStruct): boolean { + if ( + d1 && + d2 && + d1.cpu == d2.cpu && + d1.tid == d2.tid && + d1.state == d2.state && + d1.startTime == d2.startTime && + d1.dur == d2.dur + ) { + return true; + } else { + return false; + } + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerTimeline.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerTimeline.ts new file mode 100644 index 0000000000000000000000000000000000000000..e934d5067449a1fb0bf8848991c70cee2f4fbef8 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerTimeline.ts @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2022 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 { ns2s, Rect, Render, RequestMessage } from './ProcedureWorkerCommon.js'; +import { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { CpuStruct } from './ProcedureWorkerCPU.js'; + +//绘制时间轴 +let timeRuler: TimeRuler | undefined; +let rangeRuler: RangeRuler | undefined; +let sportRuler: SportRuler | undefined; +let offsetTop: number = 0; +let offsetLeft: number = 0; + +export class TimelineRender extends Render { + renderMainThread(req: any, row: TraceRow) {} + render(req: RequestMessage, list: Array, filter: Array) { + timeline( + req.canvas, + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.params.keyPressCode, + req.params.keyUpCode, + req.params.mouseDown, + req.params.mouseUp, + req.params.mouseMove, + req.params.mouseOut, + req.params.offsetLeft, + req.params.offsetTop, + (a: any) => { + //@ts-ignore + self.postMessage({ + id: 'timeline', + type: 'timeline-range-changed', + results: a, + }); + } + ); + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: null, + }); + } +} + +export function timeline( + // @ts-ignore + canvas: OffscreenCanvas, + // @ts-ignore + ctx: OffscreenCanvasRenderingContext2D, + startNS: number, + endNS: number, + totalNS: number, + frame: Rect, + keyPressCode: any, + keyUpCode: any, + mouseDown: any, + mouseUp: any, + mouseMove: any, + mouseOut: any, + _offsetLeft: number, + _offsetTop: number, + changeHandler: Function +) { + offsetLeft = _offsetLeft; + offsetTop = _offsetTop; + if (timeRuler == undefined) { + timeRuler = new TimeRuler(canvas, ctx, new Rect(0, 0, frame.width, 20), totalNS); + } + if (!sportRuler) { + sportRuler = new SportRuler(canvas, ctx, new Rect(0, 100.5, frame.width, frame.height - 100)); + } + if (!rangeRuler) { + rangeRuler = new RangeRuler( + canvas, + ctx!, + new Rect(0, 25, frame.width, 75), + { + startX: 0, + endX: frame.width, + startNS: 0, + endNS: totalNS, + totalNS: totalNS, + xs: [], + xsTxt: [], + }, + (a) => { + if (sportRuler) { + sportRuler.range = a; + } + changeHandler(a); + } + ); + } + + rangeRuler.frame.width = frame.width; + sportRuler.frame.width = frame.width; + timeRuler.frame.width = frame.width; + if (keyPressCode) { + rangeRuler.keyPress(keyPressCode); + } else if (keyUpCode) { + rangeRuler.keyUp(keyUpCode); + } else if (mouseDown) { + rangeRuler.mouseDown(mouseDown); + } else if (mouseUp) { + rangeRuler.mouseUp(mouseUp); + } else if (mouseMove) { + rangeRuler.mouseMove(mouseMove); + } else if (mouseOut) { + rangeRuler.mouseOut(mouseOut); + } else { + timeRuler.draw(); + rangeRuler.draw(); + } +} + +export abstract class Graph { + // @ts-ignore + c: OffscreenCanvasRenderingContext2D; + // @ts-ignore + canvas: OffscreenCanvas | undefined | null; + frame: Rect; + + protected constructor( + // @ts-ignore + canvas: OffscreenCanvas | undefined | null, + // @ts-ignore + c: OffscreenCanvasRenderingContext2D, + frame: Rect + ) { + this.canvas = canvas; + this.frame = frame; + this.c = c; + } + + abstract draw(): void; +} + +export class TimeRuler extends Graph { + totalNS: number; + private stepSmall: number; + private step: number; + private stepNS: number; + + constructor( + // @ts-ignore + canvas: OffscreenCanvas | undefined | null, + // @ts-ignore + c: OffscreenCanvasRenderingContext2D, + frame: Rect, + totalNS: number = 10_000_000_000 + ) { + super(canvas, c, frame); + this.totalNS = totalNS; + this.step = this.frame.width / 10; + this.stepSmall = this.frame.width / 100; + this.stepNS = this.totalNS / 10; + } + + draw() { + this.step = this.frame.width / 10; + this.stepSmall = this.frame.width / 100; + this.stepNS = this.totalNS / 10; + this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height); + this.c.beginPath(); + this.c.strokeStyle = '#999'; + this.c.lineWidth = 1; + for (let i = 0; i <= 10; i++) { + let x = Math.floor(i * this.step) + this.frame.x; + this.c.moveTo(x, 0); + this.c.lineTo(x, this.frame.height); + if (i == 10) break; + for (let j = 1; j < 10; j++) { + this.c.moveTo(x + Math.floor(j * this.stepSmall), 0); + this.c.lineTo(x + Math.floor(j * this.stepSmall), this.frame.height / 4); + } + this.c.fillStyle = '#999'; + this.c.fillText(`${ns2s(i * this.stepNS)}`, x + 5, this.frame.height - 1); + } + this.c.stroke(); + this.c.closePath(); + } +} + +/** + * SportRuler + */ +export class SportRuler extends Graph { + public static rulerFlagObj: Flag | null = null; + public flagList: Array = []; + public flagListIdx: number | null = null; + public obj = [{ x: 3 }, { x: 2 }]; + lineColor: string | null = null; + private rangeFlag = new Flag(0, 0, 0, 0, 0); + private ruler_w = 1022; + private _range: TimeRange = {} as TimeRange; + + constructor( + // @ts-ignore + canvas: OffscreenCanvas | undefined | null, + // @ts-ignore + c: OffscreenCanvasRenderingContext2D, + frame: Rect + ) { + super(canvas, c, frame); + } + + get range(): TimeRange { + return this._range; + } + + set range(value: TimeRange) { + this._range = value; + this.draw(); + } + + modifyFlagList(type: string, flag: any = {}) { + if (type == 'amend') { + if (flag.text && this.flagListIdx !== null) { + this.flagList[this.flagListIdx].text = flag.text; + } + if (flag.color && this.flagListIdx !== null) { + this.flagList[this.flagListIdx].color = flag.color; + } + } else if (type == 'remove') { + if (this.flagListIdx !== null) { + this.flagList.splice(this.flagListIdx, 1); + } + } + this.draw(); + } + + draw(): void { + this.ruler_w = this.frame.width; + this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height); + this.c.beginPath(); + this.lineColor = '#dadada'; + this.c.strokeStyle = this.lineColor; //"#dadada" + this.c.lineWidth = 1; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x + this.frame.width, this.frame.y); + this.c.stroke(); + this.c.closePath(); + this.c.beginPath(); + this.c.lineWidth = 3; + this.c.strokeStyle = '#999999'; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x, this.frame.y + this.frame.height); + this.c.stroke(); + this.c.closePath(); + this.c.beginPath(); + this.c.lineWidth = 1; + this.c.strokeStyle = this.lineColor; //"#999999" + this.c.fillStyle = '#999999'; + this.c.font = '8px sans-serif'; + this.range.xs?.forEach((it, i) => { + this.c.moveTo(it, this.frame.y); + this.c.lineTo(it, this.frame.y + this.frame.height); + this.c.fillText(`+${this.range.xsTxt[i]}`, it + 3, this.frame.y + 12); + }); + + this.c.stroke(); + this.c.closePath(); + } + + // drawTheFlag + drawTheFlag(x: number, color: string = '#999999', isFill: boolean = false, text: string = '') { + this.c.beginPath(); + this.c.fillStyle = color; + this.c.strokeStyle = color; + this.c.moveTo(x, 125); + this.c.lineTo(x + 10, 125); + this.c.lineTo(x + 10, 127); + this.c.lineTo(x + 18, 127); + this.c.lineTo(x + 18, 137); + this.c.lineTo(x + 10, 137); + this.c.lineTo(x + 10, 135); + this.c.lineTo(x + 2, 135); + this.c.lineTo(x + 2, 143); + this.c.lineTo(x, 143); + this.c.closePath(); + if (isFill) { + this.c.fill(); + } + this.c.stroke(); + + if (text !== '') { + this.c.font = '10px Microsoft YaHei'; + const { width } = this.c.measureText(text); + this.c.fillStyle = 'rgba(255, 255, 255, 0.8)'; // + this.c.fillRect(x + 21, 132, width + 4, 12); + this.c.fillStyle = 'black'; + this.c.fillText(text, x + 23, 142); + this.c.stroke(); + } + } + + //随机生成十六位进制颜色 + randomRgbColor() { + const letters = '0123456789ABCDEF'; + let color = '#'; + for (let i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + } + + //鼠标点击绘画旗子、点击旗子 + mouseUp(ev: MouseEvent) {} + + //选中的旗子 + onFlagRangeEvent(flagObj: Flag, idx: number) { + SportRuler.rulerFlagObj = flagObj; + this.flagListIdx = idx; + } + + //鼠标移动 绘画旗子 + mouseMove(ev: MouseEvent) { + let x = ev.offsetX - (offsetLeft || 0); + let y = ev.offsetY - (offsetTop || 0); + if (y >= 50 && y < 200) { + this.draw(); + if (y >= 123 && y < 142 && x > 0) { + let onFlagRange = this.flagList.findIndex((flagObj: Flag) => { + let flag_x = Math.round( + (this.ruler_w * (flagObj.time - this.range.startNS)) / (this.range.endNS - this.range.startNS) + ); + return x >= flag_x && x <= flag_x + 18; + }); + } + } + } +} + +const markPadding = 5; + +export class Mark extends Graph { + name: string | undefined; + inspectionFrame: Rect; + private _isHover: boolean = false; + + constructor( + // @ts-ignore + canvas: OffscreenCanvas | undefined | null, + name: string, + // @ts-ignore + c: OffscreenCanvasRenderingContext2D, + frame: Rect + ) { + super(canvas, c, frame); + this.name = name; + this.inspectionFrame = new Rect(frame.x - markPadding, frame.y, frame.width + markPadding * 2, frame.height); + } + + get isHover(): boolean { + return this._isHover; + } + + set isHover(value: boolean) { + this._isHover = value; + } + + draw(): void { + this.c.beginPath(); + this.c.lineWidth = 7; + this.c.strokeStyle = '#999999'; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x, this.frame.y + this.frame.height / 3); + this.c.stroke(); + this.c.lineWidth = 1; + this.c.strokeStyle = '#999999'; + this.c.moveTo(this.frame.x, this.frame.y); + this.c.lineTo(this.frame.x, this.frame.y + this.frame.height); + this.c.stroke(); + this.c.closePath(); + } +} + +export interface TimeRange { + totalNS: number; + startX: number; + endX: number; + startNS: number; + endNS: number; + xs: Array; + xsTxt: Array; +} + +export class RangeRuler extends Graph { + public rangeRect: Rect; + public markA: Mark; + public markB: Mark; + public range: TimeRange; + mouseDownOffsetX = 0; + mouseDownMovingMarkX = 0; + movingMark: Mark | undefined | null; + isMouseDown: boolean = false; + isMovingRange: boolean = false; + isNewRange: boolean = false; + markAX: number = 0; + markBX: number = 0; + isPress: boolean = false; + pressFrameId: number = -1; + currentDuration: number = 0; + centerXPercentage: number = 0; + animaStartTime: number | undefined; + animTime: number = 100; + p: number = 800; + private readonly notifyHandler: (r: TimeRange) => void; + private scale: number = 0; + //缩放级别 + private scales: Array = [ + 50, 100, 200, 500, 1_000, 2_000, 5_000, 10_000, 20_000, 50_000, 100_000, 200_000, 500_000, 1_000_000, 2_000_000, + 5_000_000, 10_000_000, 20_000_000, 50_000_000, 100_000_000, 200_000_000, 500_000_000, 1_000_000_000, 2_000_000_000, + 5_000_000_000, 10_000_000_000, 20_000_000_000, 50_000_000_000, 100_000_000_000, 200_000_000_000, 500_000_000_000, + ]; + private _cpuUsage: Array<{ cpu: number; ro: number; rate: number }> = []; + + constructor( + // @ts-ignore + canvas: OffscreenCanvas | undefined | null, + // @ts-ignore + c: OffscreenCanvasRenderingContext2D, + frame: Rect, + range: TimeRange, + notifyHandler: (r: TimeRange) => void + ) { + super(canvas, c, frame); + this.range = range; + this.notifyHandler = notifyHandler; + this.markA = new Mark(canvas, 'A', c, new Rect(range.startX, frame.y, 1, frame.height)); + this.markB = new Mark(canvas, 'B', c, new Rect(range.endX, frame.y, 1, frame.height)); + this.rangeRect = new Rect(range.startX, frame.y, range.endX - range.startX, frame.height); + } + + set cpuUsage(value: Array<{ cpu: number; ro: number; rate: number }>) { + this._cpuUsage = value; + this.draw(); + } + + drawCpuUsage() { + let maxNum = Math.round(this._cpuUsage.length / 100); + let miniHeight = Math.round(this.frame.height / CpuStruct.cpuCount); //每格高度 + let miniWidth = Math.ceil(this.frame.width / 100); //每格宽度 + for (let i = 0; i < this._cpuUsage.length; i++) { + //cpu: 0, ro: 0, rate: 0.987620037556431 + let it = this._cpuUsage[i]; + this.c.fillStyle = ColorUtils.MD_PALETTE[it.cpu]; + this.c.globalAlpha = it.rate; + this.c.fillRect(this.frame.x + miniWidth * it.ro, this.frame.y + it.cpu * miniHeight, miniWidth, miniHeight); + } + } + + draw(discardNotify: boolean = false): void { + this.c.clearRect(this.frame.x - markPadding, this.frame.y, this.frame.width + markPadding * 2, this.frame.height); + this.c.beginPath(); + if (this._cpuUsage.length > 0) { + this.drawCpuUsage(); + this.c.globalAlpha = 0; + } else { + this.c.globalAlpha = 1; + } + //绘制选中区域 + this.c.fillStyle = '#ffffff'; + this.rangeRect.x = this.markA.frame.x < this.markB.frame.x ? this.markA.frame.x : this.markB.frame.x; + this.rangeRect.width = Math.abs(this.markB.frame.x - this.markA.frame.x); + this.c.fillRect(this.rangeRect.x, this.rangeRect.y, this.rangeRect.width, this.rangeRect.height); + this.c.globalAlpha = 1; + this.c.globalAlpha = 0.5; + this.c.fillStyle = '#999999'; + this.c.fillRect(this.frame.x, this.frame.y, this.rangeRect.x, this.rangeRect.height); + this.c.fillRect( + this.rangeRect.x + this.rangeRect.width, + this.frame.y, + this.frame.width - this.rangeRect.width, + this.rangeRect.height + ); + this.c.globalAlpha = 1; + this.c.closePath(); + this.markA.draw(); + this.markB.draw(); + if (this.notifyHandler) { + this.range.startX = this.rangeRect.x; + this.range.endX = this.rangeRect.x + this.rangeRect.width; + this.range.startNS = (this.range.startX * this.range.totalNS) / (this.frame.width || 0); + this.range.endNS = (this.range.endX * this.range.totalNS) / (this.frame.width || 0); + let l20 = (this.range.endNS - this.range.startNS) / 20; + let min = 0; + let max = 0; + let weight = 0; + for (let index = 0; index < this.scales.length; index++) { + if (this.scales[index] > l20) { + if (index > 0) { + min = this.scales[index - 1]; + } else { + min = 0; + } + max = this.scales[index]; + weight = ((l20 - min) * 1.0) / (max - min); + if (weight > 0.243) { + this.scale = max; + } else { + this.scale = min; + } + break; + } + } + if (this.scale == 0) { + this.scale = this.scales[0]; + } + let tmpNs = 0; + let yu = this.range.startNS % this.scale; + let realW = (this.scale * this.frame.width) / (this.range.endNS - this.range.startNS); + let startX = 0; + if (this.range.xs) { + this.range.xs.length = 0; + } else { + this.range.xs = []; + } + if (this.range.xsTxt) { + this.range.xsTxt.length = 0; + } else { + this.range.xsTxt = []; + } + if (yu != 0) { + let firstNodeWidth = ((this.scale - yu) / this.scale) * realW; + startX += firstNodeWidth; + tmpNs += yu; + this.range.xs.push(startX); + this.range.xsTxt.push(ns2s(tmpNs)); + } + while (tmpNs < this.range.endNS - this.range.startNS) { + startX += realW; + tmpNs += this.scale; + this.range.xs.push(startX); + this.range.xsTxt.push(ns2s(tmpNs)); + } + if (!discardNotify) { + this.notifyHandler(this.range); + } + } + } + + mouseDown(ev: MouseEvent) { + let x = ev.offsetX - (offsetLeft || 0); + let y = ev.offsetY - (offsetTop || 0); + this.isMouseDown = true; + this.mouseDownOffsetX = x; + if (this.markA.isHover) { + this.movingMark = this.markA; + this.mouseDownMovingMarkX = this.movingMark.frame.x || 0; + } else if (this.markB.isHover) { + this.movingMark = this.markB; + this.mouseDownMovingMarkX = this.movingMark.frame.x || 0; + } else { + this.movingMark = null; + } + if (this.rangeRect.containsWithPadding(x, y, 5, 0)) { + this.isMovingRange = true; + this.markAX = this.markA.frame.x; + this.markBX = this.markB.frame.x; + } else if ( + this.frame.containsWithMargin(x, y, 20, 0, 0, 0) && + !this.rangeRect.containsWithMargin(x, y, 0, markPadding, 0, markPadding) + ) { + this.isNewRange = true; + } + } + + mouseUp(ev: MouseEvent) { + this.isMouseDown = false; + this.isMovingRange = false; + this.isNewRange = false; + this.movingMark = null; + } + + mouseMove(ev: MouseEvent) { + let x = ev.offsetX - (offsetLeft || 0); + let y = ev.offsetY - (offsetTop || 0); + this.centerXPercentage = x / (this.frame.width || 0); + if (this.centerXPercentage <= 0) { + this.centerXPercentage = 0; + } else if (this.centerXPercentage >= 1) { + this.centerXPercentage = 1; + } + let maxX = this.frame.width || 0; + if (this.markA.inspectionFrame.contains(x, y)) { + this.markA.isHover = true; + } else if (this.markB.inspectionFrame.contains(x, y)) { + this.markB.isHover = true; + } else { + this.markA.isHover = false; + this.markB.isHover = false; + } + if (this.movingMark) { + let result = x - this.mouseDownOffsetX + this.mouseDownMovingMarkX; + if (result >= 0 && result <= maxX) { + this.movingMark.frame.x = result; + } else if (result < 0) { + this.movingMark.frame.x = 0; + } else { + this.movingMark.frame.x = maxX; + } + this.movingMark.inspectionFrame.x = this.movingMark.frame.x - markPadding; + requestAnimationFrame(() => this.draw()); + } + if (this.isMovingRange && this.isMouseDown) { + let result = x - this.mouseDownOffsetX; + let mA = result + this.markAX; + let mB = result + this.markBX; + if (mA >= 0 && mA <= maxX) { + this.markA.frame.x = mA; + } else if (mA < 0) { + this.markA.frame.x = 0; + } else { + this.markA.frame.x = maxX; + } + this.markA.inspectionFrame.x = this.markA.frame.x - markPadding; + if (mB >= 0 && mB <= maxX) { + this.markB.frame.x = mB; + } else if (mB < 0) { + this.markB.frame.x = 0; + } else { + this.markB.frame.x = maxX; + } + this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; + requestAnimationFrame(() => this.draw()); + } else if (this.isNewRange) { + this.markA.frame.x = this.mouseDownOffsetX; + this.markA.inspectionFrame.x = this.mouseDownOffsetX - markPadding; + if (x >= 0 && x <= maxX) { + this.markB.frame.x = x; + } else if (x < 0) { + this.markB.frame.x = 0; + } else { + this.markB.frame.x = maxX; + } + this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; + requestAnimationFrame(() => this.draw()); + } + } + + mouseOut(ev: MouseEvent) { + this.movingMark = null; + } + + fillX() { + if (this.range.startNS < 0) this.range.startNS = 0; + if (this.range.endNS < 0) this.range.endNS = 0; + if (this.range.endNS > this.range.totalNS) this.range.endNS = this.range.totalNS; + if (this.range.startNS > this.range.totalNS) this.range.startNS = this.range.totalNS; + this.range.startX = (this.range.startNS * (this.frame.width || 0)) / this.range.totalNS; + this.range.endX = (this.range.endNS * (this.frame.width || 0)) / this.range.totalNS; + this.markA.frame.x = this.range.startX; + this.markA.inspectionFrame.x = this.markA.frame.x - markPadding; + this.markB.frame.x = this.range.endX; + this.markB.inspectionFrame.x = this.markB.frame.x - markPadding; + } + + keyPress(ev: KeyboardEvent) { + if (this.animaStartTime === undefined) { + this.animaStartTime = new Date().getTime(); + } + let startTime = new Date().getTime(); + let duration = startTime - this.animaStartTime; + if (duration < this.animTime) duration = this.animTime; + this.currentDuration = duration; + if (this.isPress) return; + this.isPress = true; + switch (ev.key.toLocaleLowerCase()) { + case 'w': + let animW = () => { + if (this.scale === 50) return; + this.range.startNS += (this.centerXPercentage * this.currentDuration * 2 * this.scale) / this.p; + this.range.endNS -= ((1 - this.centerXPercentage) * this.currentDuration * 2 * this.scale) / this.p; + this.fillX(); + this.draw(); + this.pressFrameId = requestAnimationFrame(animW); + }; + this.pressFrameId = requestAnimationFrame(animW); + break; + case 's': + let animS = () => { + if (this.range.startNS <= 0 && this.range.endNS >= this.range.totalNS) return; + this.range.startNS -= (this.centerXPercentage * this.currentDuration * 2 * this.scale) / this.p; + this.range.endNS += ((1 - this.centerXPercentage) * this.currentDuration * 2 * this.scale) / this.p; + this.fillX(); + this.draw(); + this.pressFrameId = requestAnimationFrame(animS); + }; + this.pressFrameId = requestAnimationFrame(animS); + break; + case 'a': + let animA = () => { + if (this.range.startNS == 0) return; + let s = (this.scale / this.p) * this.currentDuration; + this.range.startNS -= s; + this.range.endNS -= s; + this.fillX(); + this.draw(); + this.pressFrameId = requestAnimationFrame(animA); + }; + this.pressFrameId = requestAnimationFrame(animA); + break; + case 'd': + let animD = () => { + if (this.range.endNS >= this.range.totalNS) return; + this.range.startNS += (this.scale / this.p) * this.currentDuration; + this.range.endNS += (this.scale / this.p) * this.currentDuration; + this.fillX(); + this.draw(); + this.pressFrameId = requestAnimationFrame(animD); + }; + this.pressFrameId = requestAnimationFrame(animD); + break; + } + } + + keyUp(ev: KeyboardEvent) { + this.animaStartTime = undefined; + this.isPress = false; + if (this.pressFrameId != -1) { + cancelAnimationFrame(this.pressFrameId); + } + let startTime = new Date().getTime(); + switch (ev.key) { + case 'w': + let animW = () => { + if (this.scale === 50) return; + let dur = new Date().getTime() - startTime; + this.range.startNS += (this.centerXPercentage * 100 * this.scale) / this.p; + this.range.endNS -= ((1 - this.centerXPercentage) * 100 * this.scale) / this.p; + this.fillX(); + this.draw(); + if (dur < 300) { + requestAnimationFrame(animW); + } + }; + requestAnimationFrame(animW); + break; + case 's': + let animS = () => { + if (this.range.startNS <= 0 && this.range.endNS >= this.range.totalNS) return; + let dur = new Date().getTime() - startTime; + this.range.startNS -= (this.centerXPercentage * 100 * this.scale) / this.p; + this.range.endNS += ((1 - this.centerXPercentage) * 100 * this.scale) / this.p; + this.fillX(); + this.draw(); + if (dur < 300) { + requestAnimationFrame(animS); + } + }; + requestAnimationFrame(animS); + break; + case 'a': + let animA = () => { + if (this.range.startNS <= 0) return; + let dur = new Date().getTime() - startTime; + let s = (this.scale * 80) / this.p; + this.range.startNS -= s; + this.range.endNS -= s; + this.fillX(); + this.draw(); + if (dur < 300) { + requestAnimationFrame(animA); + } + }; + animA(); + break; + case 'd': + let animD = () => { + if (this.range.endNS >= this.range.totalNS) return; + let dur = new Date().getTime() - startTime; + let s = (this.scale * 80) / this.p; + this.range.startNS += s; + this.range.endNS += s; + this.fillX(); + this.draw(); + if (dur < 300) { + requestAnimationFrame(animD); + } + }; + animD(); + break; + } + } +} + +export class Flag { + x: number = 0; + y: number = 0; + width: number = 0; + height: number = 0; + time: number = 0; + color: string = ''; + selected: boolean = false; + text: string = ''; + + constructor( + x: number, + y: number, + width: number, + height: number, + time: number, + color: string = '#999999', + selected = false + ) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.time = time; + this.color = color; + this.selected = selected; + } +} diff --git a/ide/src/trace/database/ui-worker/ProcedureWorkerVirtualMemory.ts b/ide/src/trace/database/ui-worker/ProcedureWorkerVirtualMemory.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5f11276c1fac947316be9bf2b6af5e840a8aa60 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProcedureWorkerVirtualMemory.ts @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2022 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js'; +import { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class VirtualMemoryRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + }, + row: TraceRow + ) { + mem( + row.dataList, + row.dataListCache, + TraceRow.range?.startNS || 0, + TraceRow.range?.endNS || 0, + TraceRow.range?.totalNS || 0, + row.frame, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + let find = false; + for (let re of row.dataListCache) { + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + VirtualMemoryStruct.hoverStruct = re; + find = true; + } + VirtualMemoryStruct.draw(req.context, re); + } + if (!find && row.isHover) VirtualMemoryStruct.hoverStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + mem(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + mem(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startTime, + arr[arr.length - 1].startTime + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + VirtualMemoryStruct.hoverStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + VirtualMemoryStruct.hoverStruct = re; + break; + } + } + } else { + VirtualMemoryStruct.hoverStruct = req.params.hoverStruct; + } + for (let re of filter) { + VirtualMemoryStruct.draw(req.context, re); + } + drawSelection(req.context, req.params); + req.context.closePath(); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: VirtualMemoryStruct.hoverStruct, + }); + } +} + +function setMemFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let x1: number; + let x2: number; + if ((node.startTime || 0) <= startNS) { + x1 = 0; + } else { + x1 = ns2x(node.startTime || 0, startNS, endNS, totalNS, frame); + } + if ((node.startTime || 0) + (node.duration || 0) >= endNS) { + x2 = frame.width; + } else { + x2 = ns2x((node.startTime || 0) + (node.duration || 0), startNS, endNS, totalNS, frame); + } + let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(x1); + node.frame.y = Math.floor(frame.y + padding); + node.frame.width = Math.ceil(getV); + node.frame.height = Math.floor(frame.height - padding * 2); +} + +export function mem( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean +) { + if (use && res.length > 0) { + for (let i = 0, len = res.length; i < len; i++) { + if ((res[i].startTime || 0) + (res[i].duration || 0) > startNS && (res[i].startTime || 0) < endNS) { + setMemFrame(res[i], 5, startNS, endNS, totalNS, frame); + } else { + res[i].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startTime || 0) + (it.duration || 0) > startNS && (it.startTime || 0) < endNS) { + setMemFrame(list[i], 5, startNS, endNS, totalNS, frame); + if ( + i > 0 && + (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && + (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0) + ) { + } else { + res.push(list[i]); + } + } + } + } +} + +export class VirtualMemoryStruct extends BaseStruct { + static hoverStruct: VirtualMemoryStruct | undefined; + filterID: number | undefined; + value: number | undefined; + startTime: number | undefined; + duration: number | undefined; + maxValue: number | undefined; + delta: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: VirtualMemoryStruct) { + if (data.frame) { + let width = data.frame.width || 0; + ctx.fillStyle = ColorUtils.colorForTid(data.maxValue || 0); + ctx.strokeStyle = ColorUtils.colorForTid(data.maxValue || 0); + if (data === VirtualMemoryStruct.hoverStruct) { + ctx.lineWidth = 1; + ctx.globalAlpha = 0.6; + let drawHeight: number = Math.floor( + ((data.value || 0) * (data.frame.height || 0) * 1.0) / (data.maxValue || 1) + ); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight); + ctx.stroke(); + } else { + ctx.globalAlpha = 0.6; + ctx.lineWidth = 1; + let drawHeight: number = ((data.value || 0) * (data.frame.height || 0) * 1.0) / (data.maxValue || 1); + ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight); + } + } + ctx.globalAlpha = 1.0; + ctx.lineWidth = 1; + } +} diff --git a/ide/src/trace/database/ui-worker/ProduceWorkerSdkCounter.ts b/ide/src/trace/database/ui-worker/ProduceWorkerSdkCounter.ts new file mode 100644 index 0000000000000000000000000000000000000000..5aa449c5654a1bc404b61caf25e7211946abb1a6 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProduceWorkerSdkCounter.ts @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; + +export class SdkCounterRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxName: string; + maxValue: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + let maxCounter = req.maxValue; + let maxCounterName = req.maxName; + this.counter( + list, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + let find = false; + for (let re of filter) { + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + CounterStruct.hoverCounterStruct = re; + find = true; + } + CounterStruct.draw(req.context, re, maxCounter); + } + if (!find && row.isHover) CounterStruct.hoverCounterStruct = undefined; + req.context.closePath(); + let textMetrics = req.context.measureText(maxCounterName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxCounterName, 4, 5 + 9); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + this.counter(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + this.counter(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.frame.width, req.frame.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + let maxCounter = req.params.maxCounter; + let maxCounterName = req.params.maxCounterName; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + CounterStruct.hoverCounterStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + CounterStruct.hoverCounterStruct = re; + break; + } + } + } + CounterStruct.selectCounterStruct = req.params.selectCounterStruct; + for (let re of filter) { + CounterStruct.draw(req.context, re, maxCounter); + } + drawSelection(req.context, req.params); + req.context.closePath(); + let textMetrics = req.context.measureText(maxCounterName); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.fillRect(0, 5, textMetrics.width + 8, 18); + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + req.context.fillText(maxCounterName, 4, 5 + 9); + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: CounterStruct.hoverCounterStruct, + }); + } + + counter( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean + ) { + if (use && res.length > 0) { + for (let index = 0; index < res.length; index++) { + let item = res[index]; + if ((item.ts || 0) + (item.dur || 0) > (startNS || 0) && (item.ts || 0) < (endNS || 0)) { + CounterStruct.setCounterFrame(res[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + res[index].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.ts || 0); + } else { + item.dur = (list[index + 1].ts || 0) - (item.ts || 0); + } + if ((item.ts || 0) + (item.dur || 0) > (startNS || 0) && (item.ts || 0) < (endNS || 0)) { + CounterStruct.setCounterFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } + } +} + +export class CounterStruct extends BaseStruct { + static maxCounter: number = 0; + static maxCounterName: string = ''; + static hoverCounterStruct: CounterStruct | undefined; + static selectCounterStruct: CounterStruct | undefined; + + value: number | undefined; + ts: number | undefined; + counter_id: number | undefined; + + static draw(context2D: CanvasRenderingContext2D, data: CounterStruct, maxCounter: number) { + if (data.frame) { + let width = data.frame.width || 0; + context2D.fillStyle = '#67B0FC'; + context2D.strokeStyle = '#67B0FC'; + if (data.ts === CounterStruct.hoverCounterStruct?.ts) { + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxCounter); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + context2D.beginPath(); + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true); + context2D.fill(); + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath(); + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4); + context2D.stroke(); + } else { + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxCounter); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight); + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setCounterFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.ts || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.ts || 0, startNS, endNS, totalNS, frame); + } + if ((node.ts || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.ts || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/ide/src/trace/database/ui-worker/ProduceWorkerSdkSlice.ts b/ide/src/trace/database/ui-worker/ProduceWorkerSdkSlice.ts new file mode 100644 index 0000000000000000000000000000000000000000..fec22a0d98b2ae9456d1ef613f91fb8e796e7b52 --- /dev/null +++ b/ide/src/trace/database/ui-worker/ProduceWorkerSdkSlice.ts @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2022 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 { + BaseStruct, + drawFlagLine, + drawLines, + drawLoading, + drawSelection, + drawWakeUp, + isFrameContainPoint, + ns2x, + Render, + RequestMessage, +} from './ProcedureWorkerCommon.js'; +import { TraceRow } from '../../component/trace/base/TraceRow.js'; +import { CounterStruct } from './ProduceWorkerSdkCounter.js'; + +export class SdkSliceRender extends Render { + renderMainThread( + req: { + context: CanvasRenderingContext2D; + useCache: boolean; + type: string; + maxName: string; + maxValue: number; + }, + row: TraceRow + ) { + let list = row.dataList; + let filter = row.dataListCache; + SdkSliceStruct.maxSdkSlice = req.maxValue; + SdkSliceStruct.maxSdkSliceName = req.maxName; + this.sdkSlice( + list, + filter, + TraceRow.range?.startNS ?? 0, + TraceRow.range?.endNS ?? 0, + TraceRow.range?.totalNS ?? 0, + row.frame, + req.useCache || (TraceRow.range?.refresh ?? false) + ); + req.context.beginPath(); + let find = false; + for (let re of filter) { + if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { + SdkSliceStruct.hoverSdkSliceStruct = re; + find = true; + } + SdkSliceStruct.draw(req.context, re); + } + if (!find && row.isHover) SdkSliceStruct.hoverSdkSliceStruct = undefined; + req.context.closePath(); + } + + render(req: RequestMessage, list: Array, filter: Array) { + if (req.lazyRefresh) { + this.sdkSlice(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh); + } else { + if (!req.useCache) { + this.sdkSlice(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false); + } + } + if (req.canvas) { + req.context.clearRect(0, 0, req.canvas.width, req.canvas.height); + let arr = filter; + if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { + drawLoading( + req.context, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + arr[0].startNS, + arr[arr.length - 1].startNS + arr[arr.length - 1].dur + ); + } + req.context.beginPath(); + SdkSliceStruct.maxSdkSlice = req.params.maxSdkSlice; + SdkSliceStruct.maxSdkSliceName = req.params.maxSdkSliceName; + drawLines(req.context, req.xs, req.frame.height, req.lineColor); + SdkSliceStruct.hoverSdkSliceStruct = undefined; + if (req.isHover) { + for (let re of filter) { + if ( + re.frame && + req.hoverX >= re.frame.x && + req.hoverX <= re.frame.x + re.frame.width && + req.hoverY >= re.frame.y && + req.hoverY <= re.frame.y + re.frame.height + ) { + SdkSliceStruct.hoverSdkSliceStruct = re; + break; + } + } + } + SdkSliceStruct.selectSdkSliceStruct = req.params.selectSdkSliceStruct; + for (let re of filter) { + SdkSliceStruct.draw(req.context, re); + } + drawSelection(req.context, req.params); + req.context.closePath(); + req.context.globalAlpha = 0.8; + req.context.fillStyle = '#f0f0f0'; + req.context.globalAlpha = 1; + req.context.fillStyle = '#333'; + req.context.textBaseline = 'middle'; + drawFlagLine( + req.context, + req.flagMoveInfo, + req.flagSelectedInfo, + req.startNS, + req.endNS, + req.totalNS, + req.frame, + req.slicesTime + ); + } + // @ts-ignore + self.postMessage({ + id: req.id, + type: req.type, + results: req.canvas ? undefined : filter, + hover: SdkSliceStruct.hoverSdkSliceStruct, + }); + } + + sdkSlice( + list: Array, + res: Array, + startNS: number, + endNS: number, + totalNS: number, + frame: any, + use: boolean + ) { + if (use && res.length > 0) { + for (let index = 0; index < res.length; index++) { + let item = res[index]; + if ((item.end_ts || 0) > (startNS || 0) && (item.start_ts || 0) < (endNS || 0)) { + SdkSliceStruct.setSdkSliceFrame(res[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + } else { + res[index].frame = null; + } + } + return; + } + res.length = 0; + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (item.start_ts >= startNS && item.end_ts == 0) { + item.end_ts = endNS; + } + if ((item.end_ts || 0) > (startNS || 0) && (item.start_ts || 0) < (endNS || 0)) { + SdkSliceStruct.setSdkSliceFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame); + if ( + index > 0 && + (list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && + (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0) + ) { + } else { + res.push(item); + } + } + } + } + } +} + +export class SdkSliceStruct extends BaseStruct { + static maxSdkSlice: number = 0; + static maxSdkSliceName: string = ''; + static hoverSdkSliceStruct: SdkSliceStruct | undefined; + static selectSdkSliceStruct: SdkSliceStruct | undefined; + + start_ts: number | undefined; + end_ts: number | undefined; + + value: number | undefined; + slice_message: string | undefined; + + static draw(ctx: CanvasRenderingContext2D, data: SdkSliceStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 4; + ctx.fillStyle = '#6DC0DC'; + ctx.strokeStyle = '#6DC0DC'; + if (data.start_ts === SdkSliceStruct.hoverSdkSliceStruct?.start_ts) { + ctx.lineWidth = 1; + ctx.fillRect(data.frame.x, data.frame.y + 4, width, data.frame.height - 10); + ctx.beginPath(); + ctx.arc(data.frame.x, data.frame.y + 4, 3, 0, 2 * Math.PI, true); + ctx.fill(); + ctx.globalAlpha = 1.0; + ctx.stroke(); + ctx.beginPath(); + ctx.moveTo(data.frame.x + 3, data.frame.y + 4); + ctx.lineWidth = 3; + ctx.lineTo(data.frame.x + width, data.frame.y + 4); + ctx.stroke(); + } else { + ctx.lineWidth = 1; + ctx.fillRect(data.frame.x, data.frame.y + 4, width, data.frame.height - 10); + } + } + } + + static setSdkSliceFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number; + + if ((node.start_ts || 0) < startNS) { + startPointX = 0; + } else { + startPointX = ns2x(node.start_ts || 0, startNS, endNS, totalNS, frame); + } + if ((node.end_ts || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x(node.end_ts || 0, startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/ide/src/trace/grpc/HiProfilerClient.ts b/ide/src/trace/grpc/HiProfilerClient.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad67d750a6068488094ed493b57719fd76a62bdb --- /dev/null +++ b/ide/src/trace/grpc/HiProfilerClient.ts @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 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 { Address, ProfilerClient } from './ProfilerClient.js'; + +export class HiProfilerClient { + private _client: ProfilerClient; + private _address: Address; + + public constructor(clients: ProfilerClient, addr: Address) { + this._client = clients; + this._address = addr; + } + + get client(): ProfilerClient { + return this._client; + } + + set client(value: ProfilerClient) { + this._client = value; + } + + get address(): Address { + return this._address; + } + + set address(value: Address) { + this._address = value; + } + + public getProfilerClient(): ProfilerClient { + return this._client; + } + + public getCapabilities() { + // this.client.start() + // this.client.getCapabilities( + } + + public createSession() { + // this.client.createSession( + } + + public startSession() { + // this.client.startSession( + } + + public stopSession() { + // this.client.stopSession( + } + + public destroySession() { + // this.client.destroySession( + } + + public keepSession() { + // this.client.keepSession( + } +} diff --git a/ide/src/trace/grpc/ProfilerClient.ts b/ide/src/trace/grpc/ProfilerClient.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7e92484b64fe6ea393e12ec06b5d55ddb013f17 --- /dev/null +++ b/ide/src/trace/grpc/ProfilerClient.ts @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import * as path from 'path'; + +const profilerServicePath = path.join( + // @ts-ignore + __dirname, + '../proto', + 'profiler_service.proto' +); + +export class ProfilerClient { + // proto filePaths + private _filePaths: Array | undefined; + // client + private _client: any; + // profiler_proto + private _profiler_proto: any; + + // ProfilerClient constructor + public constructor(address: Address) { + // load client port + let clientPort = this.loadAddress(address); + // load proto file + this.start(clientPort, profilerServicePath); + } + + get filePaths(): Array | undefined { + return this._filePaths; + } + + set filePaths(value: Array | undefined) { + this._filePaths = value; + } + + get client(): any { + return this._client; + } + + set client(value: any) { + this._client = value; + } + + get profiler_proto(): any { + return this._profiler_proto; + } + + set profiler_proto(value: any) { + this._profiler_proto = value; + } + + start(address: string, filePath: string) {} + + // Address + loadAddress(clientAddress: Address): string { + return clientAddress.host + ':' + clientAddress.port; + } + + public getProfilerClient(callback: any): any { + return this._client; + } + + public getCapabilities(callback: any) { + this._client.this._client.getCapabilities(callback); + callback(); + } + + public createSession(callback: any) { + this._client.createSession(callback); + callback(); + } + + public startSession(callback: any) { + this._client.startSession(callback); + callback(); + } + + public stopSession(callback: any) { + this._client.stopSession(callback); + callback(); + } + + public destroySession(callback: any) { + this._client.destroySession(callback); + callback(); + } + + public keepSession(callback: any) { + this._client.keepSession(callback); + callback(); + } + + public shutdown(): void {} + + public getChannel() { + return this._client.channelInterpretation; + } +} + +export interface Address { + // port + port: string | number; + + // host + host?: string | number; +} diff --git a/ide/src/trace/grpc/ProfilerController.ts b/ide/src/trace/grpc/ProfilerController.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab8a568b432b1b11cf19e27d6bcebb12e95a608c --- /dev/null +++ b/ide/src/trace/grpc/ProfilerController.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ + +export class ClientContainer { + private _port: string | number | undefined; + private _host: string | undefined; + + get port(): string | number | undefined { + return this._port; + } + + set port(value: string | number | undefined) { + this._port = value; + } + + get host(): string | undefined { + return this._host; + } + + set host(value: string | undefined) { + this._host = value; + } + + public registryClient(target: any, path: string) {} + + public start() { + this.loadSettings(); + this._registryClient(); + } + + private loadSettings() { + let { host, port } = SettingRegistry.settings; + this._host = host; + this._port = port; + } + + private _registryClient() {} +} + +export class SettingRegistry { + static settings: Settings; + + static registry(settings: Settings) { + this.settings = settings; + } +} + +export interface Settings { + port: string | number; + + host?: string; +} diff --git a/ide/src/trace/proto/common_types.proto b/ide/src/trace/proto/common_types.proto new file mode 100644 index 0000000000000000000000000000000000000000..b78ca892ac9972c5d55fadfbf8ce6083efe2e729 --- /dev/null +++ b/ide/src/trace/proto/common_types.proto @@ -0,0 +1,58 @@ +// 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. + +syntax = "proto3"; + +// option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +// Common message define for profiler tools, imported by profiler and plugin proto file. +message ProfilerPluginConfig { + string name = 1; + string plugin_sha256 = 2; + uint32 sample_interval = 3; + bytes config_data = 4; +} + +message ProfilerPluginState { + string name = 1; + enum State { + INITED = 0; + REGISTERED = 1; // registered to plugin service. + LOADED = 2; // have created session. + IN_SESSION = 3; // have started session. + }; + State state = 2; +} + +// for FetchDataResponse +message ProfilerPluginData { + string name = 1; + uint32 status = 2; + bytes data = 3; + enum ClockId { + CLOCKID_REALTIME = 0; + CLOCKID_REALTIME_ALARM = 1; // since Linux 3.0; Linux-specific + CLOCKID_REALTIME_COARSE = 2; // since Linux 2.6.32; Linux-specific + CLOCKID_TAI = 3; // since Linux 3.10; Linux-specific + CLOCKID_MONOTONIC = 4; + CLOCKID_MONOTONIC_COARSE = 5; // since Linux 2.6.32; Linux-specific + CLOCKID_MONOTONIC_RAW = 6; // since Linux 2.6.28; Linux-specific + CLOCKID_BOOTTIME = 7; // since Linux 2.6.39; Linux-specific + CLOCKID_BOOTTIME_ALARM = 8; // since Linux 3.0; Linux-specific + CLOCKID_PROCESS_CPUTIME_ID = 9; // since Linux 2.6.12 + CLOCKID_THREAD_CPUTIME_ID = 10; // since Linux 2.6.12 + }; + ClockId clock_id = 4; + uint64 tv_sec = 5; + uint64 tv_nsec = 6; +} diff --git a/ide/src/trace/proto/profiler_service.proto b/ide/src/trace/proto/profiler_service.proto new file mode 100644 index 0000000000000000000000000000000000000000..b46d7f235406ca1c91bfe3bdd68c00fb1170567f --- /dev/null +++ b/ide/src/trace/proto/profiler_service.proto @@ -0,0 +1,47 @@ +// 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. + +syntax = "proto3"; + +// option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +import "profiler_service_types.proto"; + +// RPC interface between profiler service and host service +// Use protobuf plug-ins to convert proto define to +// source and header files during the build process. + +package profiler; + +service IProfilerService { + // get all plugin infos and capabilities. + rpc GetCapabilities(GetCapabilitiesRequest) returns (GetCapabilitiesResponse); + + // create tracing sesion and pass tracing config to plugins. + rpc CreateSession(CreateSessionRequest) returns (CreateSessionResponse); + + // start tracing session, active server side tracing triggers. + rpc StartSession(StartSessionRequest) returns (StartSessionResponse); + + // get server-side cached tracing data since current session started. + rpc FetchData(FetchDataRequest) returns (stream FetchDataResponse); + + // stop tracing session, deactivate server side tracing triggers. + rpc StopSession(StopSessionRequest) returns (StopSessionResponse); + + // destroy tracing session. + rpc DestroySession(DestroySessionRequest) returns (DestroySessionResponse); + + // keep tracing session alive, call this interface will restart session expire count down task. + rpc KeepSession(KeepSessionRequest) returns (KeepSessionResponse); +} diff --git a/ide/src/trace/proto/profiler_service_types.proto b/ide/src/trace/proto/profiler_service_types.proto new file mode 100644 index 0000000000000000000000000000000000000000..8273ace2f4f33e4708c58c1cf38e39cdf06c7f47 --- /dev/null +++ b/ide/src/trace/proto/profiler_service_types.proto @@ -0,0 +1,129 @@ +// 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. + +syntax = "proto3"; + +// option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +import "common_types.proto"; + +// Message define for profiler service, imported by profiler service proto file. +// for GetCapabilities +message GetCapabilitiesRequest { + uint32 request_id = 1; +} + +message ProfilerPluginCapability { + string path = 1; + string name = 2; +} + +message GetCapabilitiesResponse { + uint32 status = 1; + repeated ProfilerPluginCapability capabilities = 2; +} + + +// for CreateSessionRequest +message ProfilerSessionConfig { + message BufferConfig { + enum Policy { + RECYCLE = 0; + FLATTEN = 1; + }; + uint32 pages = 1; + Policy policy = 2; + } + repeated BufferConfig buffers = 1; + + enum Mode { + OFFLINE = 0; // save all plugin results to result file. + ONLINE = 1; // push all plugin results to host PC with streamed FetchDataResponse. + }; + Mode session_mode = 2; + string result_file = 3; // for OFFLINE mode, result file path + uint32 result_max_size = 4; // for OFFLINE mode, result file max size in KB + uint32 sample_duration = 5; // for OFFLINE mode, sample duration in ms + uint32 keep_alive_time = 6; // if set to non-zero value, session will auto-destroyed after CreateSession in ms +} + +message CreateSessionRequest { + uint32 request_id = 1; + ProfilerSessionConfig session_config = 2; + repeated ProfilerPluginConfig plugin_configs = 3; +} + +message CreateSessionResponse { + uint32 status = 1; + uint32 session_id = 2; + repeated ProfilerPluginState plugin_status = 3; +} + +// for StartSession +message StartSessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; + repeated ProfilerPluginConfig update_configs = 3; +} + +message StartSessionResponse { + uint32 status = 1; + repeated ProfilerPluginState plugin_status = 3; +} + +// for FetchData +message FetchDataRequest { + uint32 request_id = 1; + uint32 session_id = 2; + bytes addtion_data = 3; +} + +message FetchDataResponse { + uint32 status = 1; + uint32 response_id = 2; + bool has_more = 3; + repeated ProfilerPluginData plugin_data = 4; +} + +// for StopSession +message StopSessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; +} + +message StopSessionResponse { + uint32 status = 1; + repeated ProfilerPluginState plugin_status = 3; +} + +// for DestroySession +message DestroySessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; +} + +message DestroySessionResponse { + uint32 status = 1; + repeated ProfilerPluginState plugin_status = 3; +} + +// for KeepSession +message KeepSessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; + uint32 keep_alive_time = 3; +} + +message KeepSessionResponse { + uint32 status = 1; +} diff --git a/ide/test/base-ui/button/LitButton.test.ts b/ide/test/base-ui/button/LitButton.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab1c2785f3a92ab1b467a2914c03ae20b5a27683 --- /dev/null +++ b/ide/test/base-ui/button/LitButton.test.ts @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitButton } from '../../../dist/base-ui/button/LitButton.js'; + +describe('button Test', () => { + it('buttonTest01', function () { + let litButton = new LitButton(); + expect(litButton).not.toBeUndefined(); + }); + it('buttonTest02', function () { + let litButton = new LitButton(); + litButton.text = ' '; + expect(litButton.text).toBe(' '); + }); + it('buttonTest03', function () { + let litButton = new LitButton(); + litButton.text = 'test'; + expect(litButton.text).toBe('test'); + }); + it('buttonTest04', function () { + let litButton = new LitButton(); + litButton.back = 'test'; + expect(litButton.back).toBe('test'); + }); + it('buttonTest05', function () { + let litButton = new LitButton(); + litButton.icon = 'test'; + expect(litButton.icon).toBe('test'); + }); + it('buttonTest06', function () { + let litButton = new LitButton(); + litButton.height = 'test'; + expect(litButton.height).toBe('test'); + }); + it('buttonTest07', function () { + let litButton = new LitButton(); + litButton.width = 'test'; + expect(litButton.width).toBe('test'); + }); + it('buttonTest08', function () { + let litButton = new LitButton(); + litButton.color = 'test'; + expect(litButton.color).toBeUndefined(); + }); + it('buttonTest09', function () { + let litButton = new LitButton(); + litButton.font_size = 'test'; + expect(litButton.font_size).toBeUndefined(); + }); + it('buttonTest10', function () { + let litButton = new LitButton(); + litButton.border = 'test'; + expect(litButton.border).toBeUndefined(); + }); + it('buttonTest11', function () { + let litButton = new LitButton(); + litButton.padding = 'test'; + expect(litButton.padding).toBeUndefined(); + }); + it('buttonTest12', function () { + let litButton = new LitButton(); + litButton.justify_content = 'test'; + expect(litButton.justify_content).toBeUndefined(); + }); + it('buttonTest13', function () { + let litButton = new LitButton(); + litButton.border_radius = 'test'; + expect(litButton.border_radius).toBeUndefined(); + }); + it('buttonTest14', function () { + let litButton = new LitButton(); + litButton.margin_icon = 'test'; + expect(litButton.margin_icon).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/chart/column/LitChartColumn.test.ts b/ide/test/base-ui/chart/column/LitChartColumn.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..15ce6404201090d8a31b1e63bf608958d6318798 --- /dev/null +++ b/ide/test/base-ui/chart/column/LitChartColumn.test.ts @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitChartColumn } from '../../../../dist/base-ui/chart/column/LitChartColumn.js'; +// @ts-ignore +import { getProbablyTime } from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerCommon.js'; + +// @ts-ignore +jest.mock('../../../../dist/base-ui/chart/column/LitChartColumn.js'); +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const maybeHandler = jest.fn(); + +describe('litChartColumn Test', () => { + it('litChartColumnTest01', function () { + let litChartColumn = new LitChartColumn(); + expect(litChartColumn).not.toBeUndefined(); + }); + + it('litChartColumnTest02', function () { + document.body.innerHTML = ` +
+ 小按钮 +
`; + let clo = document.getElementById('chart-cloumn') as LitChartColumn; + let mouseMoveEvent: MouseEvent = new MouseEvent('mousemove', { movementX: 1, movementY: 2 }); + clo.canvas.dispatchEvent(mouseMoveEvent); + }); + + it('litChartColumnTest03', function () { + document.body.innerHTML = ` +
+ 小按钮 +
`; + let clo = document.getElementById('chart-cloumn') as LitChartColumn; + clo.config = { + data: [ + { + pid: 1, + pName: '1', + tid: 1, + tName: '11', + total: 12, + size: 'big core', + timeStr: '11', + }, + { + pid: 2, + pName: '2', + tid: 2, + tName: '222', + total: 13, + size: 'big core', + timeStr: '22', + }, + ], + appendPadding: 10, + xField: 'tid', + yField: 'total', + seriesField: 'total', + color: (a: any) => { + if (a.size === 'big core') { + return '#2f72f8'; + } else if (a.size === 'middle core') { + return '#ffab67'; + } else if (a.size === 'small core') { + return '#a285d2'; + } else { + return '#0a59f7'; + } + }, + tip: (a: any) => { + if (a && a[0]) { + let tip = ''; + let total = 0; + for (let obj of a) { + total += obj.obj.total; + tip = `${tip} +
+
+
${obj.type}:${obj.obj.timeStr}
+
+ `; + } + tip = `
+
tid:${a[0].obj.tid}
+ ${tip} + ${a.length > 1 ? `
total:${getProbablyTime(total)}
` : ''} +
`; + return tip; + } else { + return ''; + } + }, + label: null, + }; + let mouseOutEvent: MouseEvent = new MouseEvent('mouseout', { movementX: 1, movementY: 2 }); + clo.canvas.dispatchEvent(mouseOutEvent); + expect(clo.config).not.toBeUndefined(); + LitChartColumn.contains = jest.fn().mockResolvedValue(true); + + clo.dataSource = [ + { + pid: 1, + pName: '1', + tid: 1, + tName: '11', + total: 12, + size: 'big core', + timeStr: '11', + }, + { + pid: 2, + pName: '2', + tid: 2, + tName: '222', + total: 13, + size: 'big core', + timeStr: '22', + }, + ]; + expect(clo.data[0].obj.pid).toBe(2); + }); +}); diff --git a/ide/test/base-ui/chart/pagenation/PageNation.test.ts b/ide/test/base-ui/chart/pagenation/PageNation.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5b120fc3b21fedf5d051bd542c7d21daee7825e --- /dev/null +++ b/ide/test/base-ui/chart/pagenation/PageNation.test.ts @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import {PageNation} from '../../../../dist/base-ui/chart/pagenation/PageNation.js'; +//@ts-ignore +import {PaginationBox} from '../../../../dist/base-ui/chart/pagenation/pagination-box.js'; + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('PageNation Test', () => { + it('pageNationTest01', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 1, + totalpage: 9, + pageSize: 50, + change(num: number) {}, + }); + expect(pageNation).not.toBeUndefined(); + }); + + it('pageNationTest01', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 1, + totalpage: 200, + pageSize: 50, + change(num: number) {}, + }); + expect(pageNation.pageInfo.current).toEqual(1); + }); + + it('pageNationTest02', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 1, + totalpage: 1000, + pageSize: 10, + change(num: number) {}, + }); + expect(pageNation.pageInfo.pageSize).toEqual(10); + }); + + it('pageNationTest03', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 5, + totalpage: 1000, + pageSize: 10, + change(num: number) {}, + }); + expect(pageNation).not.toBeUndefined(); + }); + + it('pageNationTest04', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 149, + totalpage: 150, + pageSize: 10, + change(num: number) {}, + }); + expect(pageNation.pageInfo.totalpage).toEqual(150); + }); + + it('pageNationTest05', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 11, + totalpage: 15, + pageSize: 10, + change(num: number) {}, + }); + expect(pageNation.pageInfo.total).toEqual(100); + }); + + it('pageNationTest06', function () { + document.body.innerHTML = ` + `; + let pageInfo = document.getElementById('pagination-info') as PaginationBox; + let pageNation = new PageNation(pageInfo, { + current: 1, + totalpage: 150, + pageSize: 10, + change(num: number) {}, + }); + let mouseMoveEvent: MouseEvent = new MouseEvent('click', { movementX: 1, movementY: 2 }); + pageNation.element.dispatchEvent(mouseMoveEvent); + }); +}) \ No newline at end of file diff --git a/ide/test/base-ui/chart/pagenation/pagination-box.test.ts b/ide/test/base-ui/chart/pagenation/pagination-box.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d73dc5d34c1a0e64686190c7a80182dea438b3e --- /dev/null +++ b/ide/test/base-ui/chart/pagenation/pagination-box.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { PaginationBox } from '../../../../dist/base-ui/chart/pagenation/pagination-box.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('PaginationBox Test', () => { + it('PaginationBoxTest01', () => { + let paginationBox = new PaginationBox(); + expect(paginationBox).not.toBeUndefined(); + }); + it('PaginationBoxTest02', () => { + let paginationBox = new PaginationBox(); + paginationBox.text = '' + expect(paginationBox.text).toBe(''); + }); + it('PaginationBoxTest03', () => { + let paginationBox = new PaginationBox(); + paginationBox.height = '' + expect(paginationBox.height).toBe(''); + }); +}) \ No newline at end of file diff --git a/ide/test/base-ui/chart/pie/LitChartPie.test.ts b/ide/test/base-ui/chart/pie/LitChartPie.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1e580fde2edfe2dc2e11bf538e7c4400bb9e11c3 --- /dev/null +++ b/ide/test/base-ui/chart/pie/LitChartPie.test.ts @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitChartPie } from '../../../../dist/base-ui/chart/pie/LitChartPie.js'; +// @ts-ignore +import { Utils } from '../../../../dist/trace/component/trace/base/Utils.js'; +const LitChartPieData = require('../../../../dist/base-ui/chart/pie/LitChartPieData.js'); +jest.mock('../../../../dist/base-ui/chart/pie/LitChartPieData.js'); + +const scrollHeight = 8000; +const clientHeight = 1000; +const clientWidth = 1000; + +const fakeWindow = { + scrollTop: 0, +}; +beforeAll(() => { + jest.spyOn(document.documentElement, 'scrollHeight', 'get').mockImplementation(() => scrollHeight); + jest.spyOn(document.documentElement, 'clientHeight', 'get').mockImplementation(() => clientHeight); + jest.spyOn(document.documentElement, 'clientWidth', 'get').mockImplementation(() => clientWidth); + jest.spyOn(document.documentElement, 'scrollTop', 'get').mockImplementation(() => fakeWindow.scrollTop); +}); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('litChartPie Test', () => { + it('litChartPieTest01', function () { + let litChartPie = new LitChartPie(); + expect(litChartPie).not.toBeUndefined(); + }); + + // it('litChartPieTest02', function () { + // document.body.innerHTML = ` + //
+ // + //
`; + // let clo = document.getElementById('chart-pie') as LitChartPie; + // let mouseMoveEvent: MouseEvent = new MouseEvent('mousemove', { movementX: 1, movementY: 2 }); + // // this.cfg!.hoverHandler + // clo.canvas.dispatchEvent(mouseMoveEvent); + // }); + + it('litChartPieTest03', function () { + Utils.uuid = jest.fn(() => { + return Math.floor(Math.random() * 10 + 1); + }); + LitChartPieData.isPointIsCircle = jest.fn().mockResolvedValue(true); + document.body.innerHTML = ` +
+ +
`; + let clo = document.getElementById('chart-pie') as LitChartPie; + clo.config = { + appendPadding: 0, + data: [ + { + cpu: 1, + value: 1325000, + sum: 204991136, + sumTimeStr: '204.99ms ', + min: '22.92μs ', + max: '28.37ms ', + avg: '1.09ms ', + count: 188, + ratio: '35.46', + }, + { + cpu: 1, + value: 1700000, + sum: 113649487, + sumTimeStr: '113.65ms ', + min: '9.90μs ', + max: '14.07ms ', + avg: '697.24μs ', + count: 163, + ratio: '19.66', + }, + { + cpu: 1, + value: 1421000, + sum: 100750003, + sumTimeStr: '100.75ms ', + min: '32.81μs ', + max: '25.12ms ', + avg: '3.73ms ', + count: 27, + ratio: '17.43', + }, + { + cpu: 1, + value: 884000, + sum: 66958334, + sumTimeStr: '66.96ms ', + min: '16.82ms ', + max: '27.30ms ', + avg: '22.32ms ', + count: 3, + ratio: '11.58', + }, + { + cpu: 1, + value: 960000, + sum: 62210416, + sumTimeStr: '62.21ms ', + min: '93.23μs ', + max: '20.34ms ', + avg: '6.91ms ', + count: 9, + ratio: '10.76', + }, + { + cpu: 1, + value: 1517000, + sum: 21867712, + sumTimeStr: '21.87ms ', + min: '9.90μs ', + max: '8.28ms ', + avg: '1.21ms ', + count: 18, + ratio: '3.78', + }, + { + cpu: 1, + value: 1604000, + sum: 6372917, + sumTimeStr: '6.37ms ', + min: '33.85μs ', + max: '2.80ms ', + avg: '531.08μs ', + count: 12, + ratio: '1.10', + }, + { + cpu: 1, + value: 1037000, + sum: 1141667, + sumTimeStr: '1.14ms ', + min: '25.00μs ', + max: '1.12ms ', + avg: '570.83μs ', + count: 2, + ratio: '0.20', + }, + { + cpu: 1, + value: 1229000, + sum: 91667, + sumTimeStr: '91.67μs ', + min: '91.67μs ', + max: '91.67μs ', + avg: '91.67μs ', + count: 1, + ratio: '0.02', + }, + { + cpu: 1, + value: 1133000, + sum: 76042, + sumTimeStr: '76.04μs ', + min: '76.04μs ', + max: '76.04μs ', + avg: '76.04μs ', + count: 1, + ratio: '0.01', + }, + ], + angleField: 'sum', + colorField: 'value', + radius: -10, + label: { + type: 'outer', + }, + + tip: (obj: any) => { + return `
+
frequency:${obj.obj.value}
+
min:${obj.obj.min}
+
max:${obj.obj.max}
+
average:${obj.obj.avg}
+
duration:${obj.obj.sumTimeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + angleClick: () => {}, + interactions: [ + { + type: 'element-active', + }, + ], + }; + let mouseOutEvent: MouseEvent = new MouseEvent('mouseout', { movementX: 1, movementY: 2 }); + clo.canvas.dispatchEvent(mouseOutEvent); + expect(clo.config).not.toBeUndefined(); + }); + + it('litChartPieTest04', function () { + Utils.uuid = jest.fn(() => { + return Math.floor(Math.random() * 10 + 1); + }); + LitChartPieData.isPointIsCircle = jest.fn().mockResolvedValue(false); + document.body.innerHTML = ` +
+ +
`; + let clo = document.getElementById('chart-pie') as LitChartPie; + clo.config = { + appendPadding: 0, + data: [ + { + cpu: 1, + value: 1325000, + sum: 204991136, + sumTimeStr: '204.99ms ', + min: '22.92μs ', + max: '28.37ms ', + avg: '1.09ms ', + count: 188, + ratio: '35.46', + }, + { + cpu: 1, + value: 1700000, + sum: 113649487, + sumTimeStr: '113.65ms ', + min: '9.90μs ', + max: '14.07ms ', + avg: '697.24μs ', + count: 163, + ratio: '19.66', + }, + { + cpu: 1, + value: 1421000, + sum: 100750003, + sumTimeStr: '100.75ms ', + min: '32.81μs ', + max: '25.12ms ', + avg: '3.73ms ', + count: 27, + ratio: '17.43', + }, + { + cpu: 1, + value: 884000, + sum: 66958334, + sumTimeStr: '66.96ms ', + min: '16.82ms ', + max: '27.30ms ', + avg: '22.32ms ', + count: 3, + ratio: '11.58', + }, + { + cpu: 1, + value: 960000, + sum: 62210416, + sumTimeStr: '62.21ms ', + min: '93.23μs ', + max: '20.34ms ', + avg: '6.91ms ', + count: 9, + ratio: '10.76', + }, + { + cpu: 1, + value: 1517000, + sum: 21867712, + sumTimeStr: '21.87ms ', + min: '9.90μs ', + max: '8.28ms ', + avg: '1.21ms ', + count: 18, + ratio: '3.78', + }, + { + cpu: 1, + value: 1604000, + sum: 6372917, + sumTimeStr: '6.37ms ', + min: '33.85μs ', + max: '2.80ms ', + avg: '531.08μs ', + count: 12, + ratio: '1.10', + }, + { + cpu: 1, + value: 1037000, + sum: 1141667, + sumTimeStr: '1.14ms ', + min: '25.00μs ', + max: '1.12ms ', + avg: '570.83μs ', + count: 2, + ratio: '0.20', + }, + { + cpu: 1, + value: 1229000, + sum: 91667, + sumTimeStr: '91.67μs ', + min: '91.67μs ', + max: '91.67μs ', + avg: '91.67μs ', + count: 1, + ratio: '0.02', + }, + { + cpu: 1, + value: 1133000, + sum: 76042, + sumTimeStr: '76.04μs ', + min: '76.04μs ', + max: '76.04μs ', + avg: '76.04μs ', + count: 1, + ratio: '0.01', + }, + ], + angleField: 'sum', + colorField: 'value', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj: any) => { + return `
+
frequency:${obj.obj.value}
+
min:${obj.obj.min}
+
max:${obj.obj.max}
+
average:${obj.obj.avg}
+
duration:${obj.obj.sumTimeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + angleClick: () => {}, + interactions: [ + { + type: 'element-active', + }, + ], + }; + let mouseOutEvent: MouseEvent = new MouseEvent('mouseout', { movementX: 1, movementY: 2 }); + clo.canvas.dispatchEvent(mouseOutEvent); + expect(clo.config).not.toBeUndefined(); + // clo.dataSource = [ + // {pid:1, pName:"1", tid:1, tName:"11", total:12, size:"big core",timeStr:'11'}, + // {pid:2, pName:"2", tid:2, tName: "222", total:13, size:"big core",timeStr:'22'} + // ] + // expect(clo.data[0].obj.pid).toBe(2) + }); + + it('litChartPieTest05', function () { + Utils.uuid = jest.fn(() => { + return Math.floor(Math.random() * 10 + 1); + }); + LitChartPieData.isPointIsCircle = jest.fn().mockResolvedValue(true); + document.body.innerHTML = ` +
+ +
`; + let clo = document.getElementById('chart-pie') as LitChartPie; + jest.spyOn(clo, 'clientHeight', 'get').mockImplementation(() => clientHeight); + jest.spyOn(clo, 'clientWidth', 'get').mockImplementation(() => clientWidth); + clo.config = { + appendPadding: 0, + showChartLine: true, + data: [ + { + cpu: 1, + value: 1325000, + sum: 204991136, + sumTimeStr: '204.99ms ', + min: '22.92μs ', + max: '28.37ms ', + avg: '1.09ms ', + count: 188, + ratio: '35.46', + }, + { + cpu: 1, + value: 1700000, + sum: 113649487, + sumTimeStr: '113.65ms ', + min: '9.90μs ', + max: '14.07ms ', + avg: '697.24μs ', + count: 163, + ratio: '19.66', + }, + { + cpu: 1, + value: 1421000, + sum: 100750003, + sumTimeStr: '100.75ms ', + min: '32.81μs ', + max: '25.12ms ', + avg: '3.73ms ', + count: 27, + ratio: '17.43', + }, + { + cpu: 1, + value: 884000, + sum: 66958334, + sumTimeStr: '66.96ms ', + min: '16.82ms ', + max: '27.30ms ', + avg: '22.32ms ', + count: 3, + ratio: '11.58', + }, + { + cpu: 1, + value: 960000, + sum: 62210416, + sumTimeStr: '62.21ms ', + min: '93.23μs ', + max: '20.34ms ', + avg: '6.91ms ', + count: 9, + ratio: '10.76', + }, + { + cpu: 1, + value: 1517000, + sum: 21867712, + sumTimeStr: '21.87ms ', + min: '9.90μs ', + max: '8.28ms ', + avg: '1.21ms ', + count: 18, + ratio: '3.78', + }, + { + cpu: 1, + value: 1604000, + sum: 6372917, + sumTimeStr: '6.37ms ', + min: '33.85μs ', + max: '2.80ms ', + avg: '531.08μs ', + count: 12, + ratio: '1.10', + }, + { + cpu: 1, + value: 1037000, + sum: 1141667, + sumTimeStr: '1.14ms ', + min: '25.00μs ', + max: '1.12ms ', + avg: '570.83μs ', + count: 2, + ratio: '0.20', + }, + { + cpu: 1, + value: 1229000, + sum: 91667, + sumTimeStr: '91.67μs ', + min: '91.67μs ', + max: '91.67μs ', + avg: '91.67μs ', + count: 1, + ratio: '0.02', + }, + { + cpu: 1, + value: 1133000, + sum: 76042, + sumTimeStr: '76.04μs ', + min: '76.04μs ', + max: '76.04μs ', + avg: '76.04μs ', + count: 1, + ratio: '0.01', + }, + ], + angleField: 'sum', + colorField: 'value', + radius: 1, + label: { + type: 'outer', + }, + tip: (obj: any) => { + return `
+
frequency:${obj.obj.value}
+
min:${obj.obj.min}
+
max:${obj.obj.max}
+
average:${obj.obj.avg}
+
duration:${obj.obj.sumTimeStr}
+
ratio:${obj.obj.ratio}%
+
+ `; + }, + angleClick: () => {}, + interactions: [ + { + type: 'element-active', + }, + ], + }; + let mouseOutEvent: MouseEvent = new MouseEvent('mousemove', { movementX: 1, movementY: 2 }); + clo.canvas.dispatchEvent(mouseOutEvent); + expect(clo.config).not.toBeUndefined(); + clo.dataSource = [ + { + cpu: 1, + value: 1325000, + sum: 204991136, + sumTimeStr: '204.99ms ', + min: '22.92μs ', + max: '28.37ms ', + avg: '1.09ms ', + count: 188, + ratio: '35.46', + }, + { + cpu: 1, + value: 1700000, + sum: 113649487, + sumTimeStr: '113.65ms ', + min: '9.90μs ', + max: '14.07ms ', + avg: '697.24μs ', + count: 163, + ratio: '19.66', + }, + ]; + clo.centerX = 10; + clo.centerY = 10; + + let mouseMoveEvent: MouseEvent = new MouseEvent('click', { movementX: 1, movementY: 2 }); + clo.canvas.dispatchEvent(mouseMoveEvent); + }); +}); diff --git a/ide/test/base-ui/chart/pie/LitChartPieData.test.ts b/ide/test/base-ui/chart/pie/LitChartPieData.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..13cbdd707c4b4e1fe2f00ec2b82e1f991ef4debe --- /dev/null +++ b/ide/test/base-ui/chart/pie/LitChartPieData.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { isPointIsCircle, randomRgbColor } from '../../../../dist/base-ui/chart/pie/LitChartPieData.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('LitChartPieData Test', () => { + it('LitChartPieDataTest01', function () { + expect(randomRgbColor()).not.toBeUndefined(); + }); + + it('LitChartPieDataTest02', function () { + expect(isPointIsCircle(1, 2, 1, 2, 3)).toBe(true); + }); + it('LitChartPieDataTest03', function () { + expect(isPointIsCircle(1, 2, 7, 5, 3)).toBe(false); + }); +}); diff --git a/ide/test/base-ui/checkbox/LitCheckBox.test.ts b/ide/test/base-ui/checkbox/LitCheckBox.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..49183bbfd9faafbe39c34fd0bc3649cf53482cc8 --- /dev/null +++ b/ide/test/base-ui/checkbox/LitCheckBox.test.ts @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitCheckBox } from '../../../dist/base-ui/checkbox/LitCheckBox.js'; + +describe('checkBox Test', () => { + it('checkBoxTest01', function () { + let litCheckBox = new LitCheckBox(); + expect(litCheckBox).not.toBeUndefined(); + expect(litCheckBox).not.toBeNull(); + }); + + it('checkBoxTest02', function () { + let litCheckBox = new LitCheckBox(); + expect(litCheckBox.checked).toBeFalsy(); + }); + + it('checkBoxTest03', function () { + let litCheckBox = new LitCheckBox(); + litCheckBox.checked = true; + expect(litCheckBox.checked).toBeTruthy(); + }); + + it('checkBoxTest04', function () { + let litCheckBox = new LitCheckBox(); + expect(litCheckBox.value).toEqual(''); + }); + + it('checkBoxTest04', function () { + let litCheckBox = new LitCheckBox(); + litCheckBox.value = 'test'; + expect(litCheckBox.value).toEqual('test'); + }); + + it('checkBoxTest05', function () { + document.body.innerHTML = ` + `; + let litCheckBox = new LitCheckBox(); + litCheckBox.checked = false; + expect(litCheckBox.checked).toBeFalsy(); + }); + it('checkBoxTest06', function () { + document.body.innerHTML = ` + `; + let litCheckBox = new LitCheckBox(); + litCheckBox.indeterminate = false; + expect(litCheckBox.indeterminate).toBeFalsy(); + }); + + it('checkBoxTest07', function () { + document.body.innerHTML = ` + `; + let litCheckBox = new LitCheckBox(); + litCheckBox.indeterminate = true; + expect(litCheckBox.indeterminate).toBeTruthy(); + }); + + it('checkBoxTest08', function () { + let litCheckBox = new LitCheckBox(); + expect(litCheckBox.initHtml()).toMatchInlineSnapshot(` +" + + + + " +`); + }); +}); diff --git a/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts b/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..70d5cc9621b86c8014676c35a7b47d1f5d9f7e58 --- /dev/null +++ b/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitCheckBoxWithText } from '../../../dist/base-ui/checkbox/LitCheckBoxWithText.js'; + +describe('checkBoxWithText Test', () => { + it('checkBoxWithTextTest01', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText).not.toBeUndefined(); + expect(litCheckBoxWithText).not.toBeNull(); + }); + + it('checkBoxWithTextTest02', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.checked).toBeFalsy(); + }); + + it('checkBoxWithTextTest03', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + litCheckBoxWithText.checked = true; + expect(litCheckBoxWithText.checked).toBeTruthy(); + }); + + it('checkBoxWithTextTest03', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + litCheckBoxWithText.checked = false; + expect(litCheckBoxWithText.checked).toBeFalsy(); + }); + + it('checkBoxWithTextTest04', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.text).toEqual(''); + }); + + it('checkBoxWithTextTest05', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + litCheckBoxWithText.text = 'test'; + expect(litCheckBoxWithText.text).toEqual('test'); + }); + + it('checkBoxWithTextTest05', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.lowerLimit).toEqual('0'); + }); + + it('checkBoxWithTextTest05', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + litCheckBoxWithText.lowerLimit = '111'; + expect(litCheckBoxWithText.lowerLimit).toEqual('111'); + }); + + it('checkBoxWithTextTest05', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + litCheckBoxWithText.upLimit = '111'; + expect(litCheckBoxWithText.upLimit).toEqual('111'); + }); + + it('checkBoxWithTextTest05', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.initHtml()).toMatchInlineSnapshot(` +" + + + + + " +`); + }); + + it('checkBoxWithTextTest06', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback('checked')).toBeUndefined(); + }); + + it('checkBoxWithTextTest07', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback('text')).toBeUndefined(); + }); + + it('checkBoxWithTextTest08', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback('lowerLimit')).toBeUndefined(); + }); + + it('checkBoxWithTextTest09', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback('upLimit')).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/checkbox/LitCheckGroup.test.ts b/ide/test/base-ui/checkbox/LitCheckGroup.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..842819dac256fb450f39278c68f89e8ccc38d453 --- /dev/null +++ b/ide/test/base-ui/checkbox/LitCheckGroup.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitCheckGroup } from '../../../dist/base-ui/checkbox/LitCheckGroup.js'; + +describe('LitCheckGroup Test', () => { + it('LitCheckGroupTest01', function () { + let litCheckGroup = new LitCheckGroup(); + expect(litCheckGroup).not.toBeUndefined(); + expect(litCheckGroup).not.toBeNull(); + }); + + it('LitCheckGroupTest02', function () { + let litCheckGroup = new LitCheckGroup(); + expect(litCheckGroup.direction).toBeNull(); + }); + + it('LitCheckGroupTest03', function () { + let litCheckGroup = new LitCheckGroup(); + expect(litCheckGroup.value).toEqual([]); + }); + + it('LitCheckGroupTest03', function () { + let litCheckGroup = new LitCheckGroup(); + expect(litCheckGroup.initHtml()).toMatchInlineSnapshot(` +" + + " +`); + }); +}); diff --git a/ide/test/base-ui/drawer/LitDrawer.test.ts b/ide/test/base-ui/drawer/LitDrawer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c94664cf9f09bdb447c65a17a23c9ee0610bef66 --- /dev/null +++ b/ide/test/base-ui/drawer/LitDrawer.test.ts @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { LitDrawer } from '../../../dist/base-ui/drawer/LitDrawer.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('LitDrawer Test', () => { + it('LitDrawerTest01', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer).not.toBeUndefined(); + }); + it('LitDrawerTest02', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.contentWidth).toBe('400px'); + }); + it('LitDrawerTest03', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.contentPadding).toBe('20px'); + }); + it('LitDrawerTest04', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.placement).toBe(null); + }); + it('LitDrawerTest05', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.title).toBe(''); + }); + it('LitDrawerTest06', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.visible).toBe(false); + }); + it('LitDrawerTest07', () => { + let litDrawer = new LitDrawer(); + litDrawer.contentWidth = 'content-width' + expect(litDrawer.contentWidth).toBe('content-width'); + }); + it('LitDrawerTest08', () => { + let litDrawer = new LitDrawer(); + litDrawer.contentPadding = 'content-padding'; + expect(litDrawer.contentPadding).toBe('content-padding'); + }); + it('LitDrawerTest09', () => { + let litDrawer = new LitDrawer(); + litDrawer.placement = 'placement' + expect(litDrawer.placement).toBe('placement'); + }); + it('LitDrawerTest10', () => { + let litDrawer = new LitDrawer(); + litDrawer.title = 'title' + expect(litDrawer.title).toBe('title'); + }); + it('LitDrawerTest11', () => { + let litDrawer = new LitDrawer(); + litDrawer.visible = true; + expect(litDrawer.visible).toBe(true); + }); + it('LitDrawerTest12', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.mask).toBe(false); + }); + it('LitDrawerTest13', () => { + let litDrawer = new LitDrawer(); + litDrawer.mask = true; + expect(litDrawer.mask).toBe(true); + }); + it('LitDrawerTest14', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.maskCloseable).toBe(false); + }); + it('LitDrawerTest15', () => { + let litDrawer = new LitDrawer(); + litDrawer.maskCloseable = true; + expect(litDrawer.maskCloseable).toBe(true); + }); + it('LitDrawerTest16', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.closeable).toBe(false); + }); + it('LitDrawerTest17', () => { + let litDrawer = new LitDrawer(); + litDrawer.closeable = true; + expect(litDrawer.closeable).toBe(true); + }); + it('LitDrawerTest18', () => { + let litDrawer = new LitDrawer(); + expect(litDrawer.adoptedCallback()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/base-ui/icon/LitIcon.test.ts b/ide/test/base-ui/icon/LitIcon.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc9e178eda2b14645c82b5ba46bff9a3d20e72cc --- /dev/null +++ b/ide/test/base-ui/icon/LitIcon.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitIcon } from '../../../dist/base-ui/icon/LitIcon.js'; + +describe('testLitIcon Test', () => { + it('testLitIcon01', () => { + let litIcon = new LitIcon(); + expect(litIcon).not.toBeUndefined(); + expect(litIcon).not.toBeNull(); + }); + + it('testLitIcon02', () => { + let litIcon = new LitIcon(); + expect(litIcon.path).toBeUndefined(); + }); + + it('testLitIcon03', () => { + let litIcon = new LitIcon(); + litIcon.path = 'ss'; + expect(litIcon.path).toBeUndefined(); + }); + + it('testLitIcon04', () => { + let litIcon = new LitIcon(); + expect(litIcon.size).toBe(0); + }); + + it('testLitIcon05', () => { + let litIcon = new LitIcon(); + litIcon.size = 1024; + expect(litIcon.size).toBe(1024); + }); + + it('testLitIcon06', () => { + let litIcon = new LitIcon(); + expect(litIcon.name).toBe(''); + }); + + it('testLitIcon07', () => { + let litIcon = new LitIcon(); + litIcon.name = 'sss'; + expect(litIcon.name).toBe('sss'); + }); + + it('testLitIcon07', () => { + let litIcon = new LitIcon(); + expect((litIcon.color = '#FFF')).not.toBeUndefined(); + }); + + it('testLitIcon07', () => { + let litIcon = new LitIcon(); + expect(litIcon.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }); +}); diff --git a/ide/test/base-ui/menu/LitMainMenu.test.ts b/ide/test/base-ui/menu/LitMainMenu.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..91d769fde5941459f736a604de83092112764db5 --- /dev/null +++ b/ide/test/base-ui/menu/LitMainMenu.test.ts @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitMainMenu } from '../../../dist/base-ui/menu/LitMainMenu.js'; +import { MenuItem } from '../../../src/base-ui/menu/LitMainMenu.js'; + +describe('LitMainMenu Test', () => { + it('LitMainMenu01', () => { + let litMainMenu = new LitMainMenu(); + expect(litMainMenu).not.toBeUndefined(); + expect(litMainMenu).not.toBeNull(); + }); + + it('LitMainMenu01', () => { + let litMainMenu = new LitMainMenu(); + expect(litMainMenu).not.toBeUndefined(); + expect(litMainMenu).not.toBeNull(); + }); + + it('LitMainMenu02', () => { + let litMainMenu = new LitMainMenu(); + litMainMenu.menus = [ + { + collapsed: false, + title: 'Navigation', + describe: 'Open or record a new trace', + children: [ + { + title: 'Open trace file', + icon: 'folder', + fileChoose: true, + fileHandler: function (ev: InputEvent) {}, + }, + { + title: 'Record new trace', + icon: 'copyhovered', + clickHandler: function (item: MenuItem) {}, + }, + ], + }, + ]; + expect(litMainMenu.menus.length).toBe(1); + }); + + it('LitMainMenu03', () => { + let litMainMenu = new LitMainMenu(); + expect(litMainMenu.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ +
+
+ +
+
+
+
" +`); + }); + + it('LitMainMenu04', () => { + let litMainMenu = new LitMainMenu(); + litMainMenu.menus = [ + { + collapsed: true, + title: 'Navigation', + describe: 'Open or record a new trace', + children: [ + { + title: 'Open trace file', + icon: 'folder', + fileChoose: true, + fileHandler: function (ev: InputEvent) {}, + }, + { + title: 'Record new trace', + icon: 'copyhovered', + clickHandler: function (item: MenuItem) {}, + }, + ], + }, + ]; + expect(litMainMenu.menus.length).toBe(1); + }); +}); diff --git a/ide/test/base-ui/menu/LitMainMenuGroup.test.ts b/ide/test/base-ui/menu/LitMainMenuGroup.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a981f2a63ed07a732854e79a6a4bd10ebc112308 --- /dev/null +++ b/ide/test/base-ui/menu/LitMainMenuGroup.test.ts @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitMainMenuGroup } from '../../../dist/base-ui/menu/LitMainMenuGroup.js'; + +describe('litMainMenuGroup Test', () => { + it('litMainMenuGroup01', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup).not.toBeUndefined(); + expect(litMainMenuGroup).not.toBeNull(); + }); + + it('litMainMenuGroup02', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.collapsed).toBeFalsy(); + }); + + it('litMainMenuGroup03', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + litMainMenuGroup.collapsed = true; + expect(litMainMenuGroup.collapsed).toBeTruthy(); + }); + + it('litMainMenuGroup04', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + litMainMenuGroup.collapsed = false; + expect(litMainMenuGroup.collapsed).toBeFalsy(); + }); + + it('litMainMenuGroup06', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.radius).toBeFalsy(); + }); + + it('litMainMenuGroup07', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+
+ + " +`); + }); + + it('litMainMenuGroup04', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + litMainMenuGroup.nocollapsed = true; + expect(litMainMenuGroup.nocollapsed).toBeTruthy(); + }); + + it('litMainMenuGroup04', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + litMainMenuGroup.nocollapsed = false; + expect(litMainMenuGroup.nocollapsed).toBeFalsy(); + }); + + it('litMainMenuGroup05', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.collapsed).toBeFalsy(); + }); +}); diff --git a/ide/test/base-ui/menu/LitMainMenuItem.test.ts b/ide/test/base-ui/menu/LitMainMenuItem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0d507e83bc161e370b32d18d836881c2a6f9789 --- /dev/null +++ b/ide/test/base-ui/menu/LitMainMenuItem.test.ts @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitMainMenuItem } from '../../../dist/base-ui/menu/LitMainMenuItem.js'; + +describe('litMainMenuItem Test', () => { + it('litMainMenuItem01', () => { + let litMainMenuItem = new LitMainMenuItem(); + expect(litMainMenuItem).not.toBeUndefined(); + expect(litMainMenuItem).not.toBeNull(); + }); + + it('litMainMenuItem02', () => { + let litMainMenuItem = new LitMainMenuItem(); + expect(litMainMenuItem.title).toEqual(''); + }); + + it('litMainMenuItem03', () => { + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.title = 'test'; + expect(litMainMenuItem.title).toEqual('test'); + }); + + it('litMainMenuItem04', () => { + document.body.innerHTML = ` + `; + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.title = 'test02'; + expect(litMainMenuItem.title).toEqual('test02'); + }); + + it('litMainMenuItem05', () => { + document.body.innerHTML = ` + `; + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.title = 'test03'; + expect(litMainMenuItem.title).toEqual('test03'); + }); + + it('litMainMenuItem06', () => { + document.body.innerHTML = ` + `; + let litMainMenuItem = new LitMainMenuItem(); + expect(litMainMenuItem.isFile()).toBeFalsy(); + }); + + it('litMainMenuItem07', () => { + document.body.innerHTML = ` + `; + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.disabled = true; + expect(litMainMenuItem.disabled).toBeTruthy(); + }); + + it('litMainMenuItem08', () => { + document.body.innerHTML = ` + `; + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.disabled = false; + expect(litMainMenuItem.disabled).toBeFalsy(); + }); + + it('litMainMenuItem09', () => { + let litMainMenuItem = new LitMainMenuItem(); + expect(litMainMenuItem.initHtml()).toMatchInlineSnapshot(` +" + + + + " +`); + }); + it('litMainMenuItem10', () => { + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.back = true; + expect(litMainMenuItem.back).toBeTruthy(); + }); + it('litMainMenuItem11', () => { + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.back = false; + expect(litMainMenuItem.back).toBeFalsy(); + }); + + it('litMainMenuItem12', () => { + const onclick = jest.fn(); + let menuItem = (document.body.innerHTML = ` + + `); + const menu = document.getElementById('menu'); + expect(onclick).not.toBeCalled(); + menu!.onclick = onclick; + menu!.click(); + expect(onclick).toBeCalled(); + expect(onclick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/ide/test/base-ui/modal/LitModal.test.ts b/ide/test/base-ui/modal/LitModal.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..86c159e8cd15770c64f621b55a280cb3ae7665e4 --- /dev/null +++ b/ide/test/base-ui/modal/LitModal.test.ts @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitModal } from '../../../dist/base-ui/modal/LitModal.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('LitModal Test', () => { + it('LitModalTest01', function () { + let litModal = new LitModal(); + expect(litModal).not.toBeUndefined(); + }); + + it('LitModalTest02', function () { + let litModal = new LitModal(); + litModal.resizeable = true; + expect(litModal).not.toBeUndefined(); + }); + + it('LitModalTest03', function () { + let litModal = new LitModal(); + litModal.resizeable = false; + expect(litModal).not.toBeUndefined(); + }); + + it('LitModalTest04', function () { + let litModal = new LitModal(); + litModal.moveable = false; + expect(litModal).not.toBeUndefined(); + }); + + it('LitModalTest05', function () { + let litModal = new LitModal(); + litModal.moveable = true; + expect(litModal).not.toBeUndefined(); + }); + + it('LitModalTest06', function () { + document.body.innerHTML = ` +
+ +
`; + let litmode = document.getElementById('lit-modal') as LitModal; + let mouseOutEvent: MouseEvent = new MouseEvent('mousemove', { movementX: 1, movementY: 2 }); + litmode.dispatchEvent(mouseOutEvent); + }); + + it('LitModalTest06', function () { + document.body.innerHTML = ` +
+ +
`; + let litmode = document.getElementById('lit-modal') as LitModal; + + let mouseOutEvent: MouseEvent = new MouseEvent('mousedown', { movementX: 1, movementY: 2 }); + litmode.dispatchEvent(mouseOutEvent); + }); + + it('LitModalTest07', function () { + document.body.innerHTML = ` +
+ +
`; + let litmode = document.getElementById('lit-modal') as LitModal; + + let mouseOutEvent: MouseEvent = new MouseEvent('mouseleave', { movementX: 1, movementY: 2 }); + litmode.dispatchEvent(mouseOutEvent); + }); + + it('LitModalTest08', function () { + document.body.innerHTML = ` +
+ +
`; + let litmode = document.getElementById('lit-modal') as LitModal; + let mouseOutEvent: MouseEvent = new MouseEvent('mousemove', { clientX: 1, clientY: 2 }); + litmode.dispatchEvent(mouseOutEvent); + }); + it('LitModalTest08', function () { + let litModal = new LitModal(); + litModal.okText = 'ok-text'; + expect(litModal).not.toBeUndefined(); + }); + it('LitModalTest09', function () { + let litModal = new LitModal(); + litModal.cancelText = 'cancel-text'; + expect(litModal).not.toBeUndefined(); + }); + it('LitModalTest10', function () { + let litModal = new LitModal(); + litModal.title = 'title'; + expect(litModal).not.toBeUndefined(); + }); + it('LitModalTest11', function () { + let litModal = new LitModal(); + litModal.visible = false; + expect(litModal).not.toBeUndefined(); + }); + it('LitModalTest12', function () { + let litModal = new LitModal(); + litModal.visible = true; + expect(litModal).not.toBeUndefined(); + }); + it('LitModalTest13', function () { + let litModal = new LitModal(); + litModal.width = 'width'; + expect(litModal).not.toBeUndefined(); + }); + it('LitModalTest14', function () { + let litModal = new LitModal(); + expect(litModal.adoptedCallback()).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/popover/LitPopContent.test.ts b/ide/test/base-ui/popover/LitPopContent.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..66b8a3ee854e637490b8e675f0e2e75f1974158f --- /dev/null +++ b/ide/test/base-ui/popover/LitPopContent.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore + +import { LitPopContent } from '../../../dist/base-ui/popover/LitPopContent.js'; + +describe('LitPopCont Test', () => { + it('LitPopCont01', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent).not.toBeUndefined(); + expect(litPopContent).not.toBeNull(); + }); + + it('LitPopCont02', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent.open).toBeFalsy(); + }); + + it('LitPopCont03', () => { + let litPopContent = new LitPopContent(); + litPopContent.open = false; + expect(litPopContent.open).toBeFalsy(); + }); + + it('LitPopCont04', () => { + let litPopContent = new LitPopContent(); + litPopContent.open = true; + expect(litPopContent.open).toBeTruthy(); + }); + + it('LitPopCont04', () => { + let litPopContent = new LitPopContent(); + litPopContent.name = '11'; + expect(litPopContent.name).toEqual('11'); + }); + + it('LitPopCont05', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ " +`); + }); + + it('LitPopCont06', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent.attributeChangedCallback('open', '', null || 'false')).toBeUndefined(); + }); + + it('LitPopCont07', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent.attributeChangedCallback('name', '', '')).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/popover/LitPopover.test.ts b/ide/test/base-ui/popover/LitPopover.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..94a03a898042c00af22e56f27dfa950e6c4e93bf --- /dev/null +++ b/ide/test/base-ui/popover/LitPopover.test.ts @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitPopover } from '../../../dist/base-ui/popover/LitPopover.js'; + +describe('LitPopover Test', () => { + it('LitPopover01', () => { + let litPopover = new LitPopover(); + expect(litPopover).not.toBeUndefined(); + expect(litPopover).not.toBeNull(); + }); + + it('LitPopover02', () => { + let litPopover = new LitPopover(); + expect(litPopover.open).toBeFalsy(); + }); + + it('LitPopover03', () => { + let litPopover = new LitPopover(); + litPopover.open = true; + expect(litPopover.open).toBeTruthy(); + }); + + it('LitPopover04', () => { + let litPopover = new LitPopover(); + litPopover.open = false; + expect(litPopover.open).toBeFalsy(); + }); + + it('LitPopover05', () => { + let litPopover = new LitPopover(); + litPopover.direction = 'topleft'; + expect(litPopover.direction).toEqual('topleft'); + }); + + it('LitPopover06', () => { + let litPopover = new LitPopover(); + expect(litPopover.direction).toEqual('topright'); + }); + + it('LitPopover07', () => { + let litPopover = new LitPopover(); + litPopover.type = 'multiple'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + expect(litPopover.select).toEqual(['# Samples']); + }); + + it('LitPopover07', () => { + let litPopover = new LitPopover(); + litPopover.type = 'radio'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + expect(litPopover.select).toEqual(['# Samples']); + }); + + it('LitPopover08', () => { + let litPopover = new LitPopover(); + litPopover.type = 'multiple-text'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + expect(litPopover.select).toEqual(['# Samples']); + }); + + it('LitPopover09', () => { + let litPopover = new LitPopover(); + litPopover.type = 'radio'; + litPopover.title = 'tee'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + expect(litPopover.select).toEqual(['# Samples']); + }); + + it('LitPopover10', () => { + let litPopover = new LitPopover(); + litPopover.type = 'multiple-text'; + litPopover.title = 'tee'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + expect(litPopover.trigger).not.toBeUndefined(); + }); + + it('LitPopover11', () => { + let litPopover = new LitPopover(); + litPopover.type = 'multiple-text'; + litPopover.title = 'tee'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: false, + }, + ]; + expect(litPopover.limit).toEqual({ + textLowerLimit: '0', + textUpperLimit: '∞', + }); + }); + + it('LitPopover14', () => { + let litPopover = new LitPopover(); + litPopover.type = 'data-ming'; + litPopover.title = 'tee'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: false, + }, + ]; + expect(litPopover.limit).toEqual({ + textLowerLimit: '', + textUpperLimit: '', + }); + }); + + it('LitPopover15', () => { + let litPopover = new LitPopover(); + litPopover.type = 'multiple-text'; + litPopover.title = 'tee'; + litPopover.dataSource = [ + { + text: '# Samples', + isSelected: true, + }, + ]; + expect(litPopover.limit).toEqual({ + textLowerLimit: '0', + textUpperLimit: '∞', + }); + }); + + it('LitPopover12', () => { + let litPopover = new LitPopover(); + expect(litPopover.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }); + + it('LitPopover13', () => { + let litPopover = new LitPopover(); + expect(litPopover.connectedCallback()).toBeUndefined(); + }); + + it('LitPopover16', () => { + const onclick = jest.fn(); + let litPopover = (document.body.innerHTML = ` + + `); + const popover = document.getElementById('popover'); + expect(onclick).not.toBeCalled(); + popover!.onclick = onclick; + popover!.click(); + expect(onclick).toBeCalled(); + expect(onclick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/ide/test/base-ui/popover/LitPopoverTitle.test.ts b/ide/test/base-ui/popover/LitPopoverTitle.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4d7f456c6ccbb34ff56b091f838efa733edf5b38 --- /dev/null +++ b/ide/test/base-ui/popover/LitPopoverTitle.test.ts @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitPopoverTitle } from '../../../dist/base-ui/popover/LitPopoverTitle'; + +describe('LitPopoverTitle Test', () => { + it('LitPopoverTitle01', () => { + let litPopoverTitle = new LitPopoverTitle(); + expect(litPopoverTitle.attributeChangedCallback('name', 'old', 'new')).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/popover/LitPopoverV.test.ts b/ide/test/base-ui/popover/LitPopoverV.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cfa8d60d259e82844a42f28a5063c13982e37a5 --- /dev/null +++ b/ide/test/base-ui/popover/LitPopoverV.test.ts @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitPopover } from '../../../dist/base-ui/popover/LitPopoverV.js'; + +describe('LitPopoverV Test', () => { + it('LitPopoverV01', () => { + let litPopover = new LitPopover(); + expect(litPopover).not.toBeUndefined(); + expect(litPopover).not.toBeNull(); + }); + it('LitPopoverV02', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.visible).toBe('false'); + }); + it('LitPopoverV03', () => { + let litPopoverV = new LitPopover(); + litPopoverV.visible = true; + expect(litPopoverV.visible).toBe('true'); + }); + it('LitPopoverV04', () => { + let litPopoverV = new LitPopover(); + litPopoverV.visible = false; + expect(litPopoverV.visible).toBe('false'); + }); + it('LitPopoverV05', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.trigger).toBe('hover'); + }); + it('LitPopoverV06', () => { + let litPopoverV = new LitPopover(); + litPopoverV.trigger = 'click'; + expect(litPopoverV.trigger).toBe('click'); + }); + + it('LitPopoverV07', () => { + let litPopoverV = new LitPopover(); + litPopoverV.title = 'test'; + expect(litPopoverV.title).toBe('test'); + }); + + it('LitPopoverV08', () => { + let litPopoverV = new LitPopover(); + litPopoverV.width = '10px'; + expect(litPopoverV.width).toBe('10px'); + }); + + it('LitPopoverV09', () => { + let litPopoverV = new LitPopover(); + litPopoverV.width = '10px'; + expect(litPopoverV.width).toBe('10px'); + }); + + it('LitPopoverV10', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.width).toBe('max-content'); + }); + + it('LitPopoverV11', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.haveRadio).toBeNull(); + }); + + it('LitPopoverV12', () => { + document.body.innerHTML = ``; + let popver = document.querySelector('#litpop') as LitPopover; + expect(popver.haveRadio).toBeNull(); + }); + + it('LitPopoverV13', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.initHtml()).toMatchInlineSnapshot(` +" + + +
+
null
+
+
+ + " +`); + }); + it('LitPopoverV14', () => { + document.body.innerHTML = ``; + let popver = document.querySelector('#litpop') as LitPopover; + expect(popver.adoptedCallback()).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/progress-bar/LitProgressBar.test.ts b/ide/test/base-ui/progress-bar/LitProgressBar.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9efa220a8f96bc931d2521a84241448592f2c40 --- /dev/null +++ b/ide/test/base-ui/progress-bar/LitProgressBar.test.ts @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitProgressBar } from '../../../dist/base-ui/progress-bar/LitProgressBar.js'; + +describe('LitProgressBar Test', () => { + let litProgressBar = new LitProgressBar(); + litProgressBar.loading = ''; + litProgressBar.loading = 'load'; + + it('LitProgressBarTest01', () => { + expect(litProgressBar.loading).toBeTruthy(); + }); + + it('LitProgressBarTest02', () => { + expect(litProgressBar.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+
+ " +`); + }); +}); diff --git a/ide/test/base-ui/radiobox/LitRadioBox.test.ts b/ide/test/base-ui/radiobox/LitRadioBox.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..164a8ef18313423bb900fffd513f6c271c911e9a --- /dev/null +++ b/ide/test/base-ui/radiobox/LitRadioBox.test.ts @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitRadioBox } from '../../../dist/base-ui/radiobox/LitRadioBox.js'; + +// @ts-ignore +import { LitRadioGroup } from '../../../dist/base-ui/radiobox/LitRadioGroup.js'; + +describe('LitRadioBox Test', () => { + let litRadioBox = new LitRadioBox(); + let litRadioGroup = new LitRadioGroup(); + + litRadioGroup.layout = 'layout'; + + litRadioBox.checked = true; + litRadioBox.checked = false; + litRadioBox.value = 'value'; + litRadioBox.dis = 'dis'; + it('LitRadioBoxTest01', () => { + expect(litRadioBox.name).toBeNull(); + }); + + it('LitRadioBoxTest02', () => { + expect(litRadioBox.value).toBe('value'); + }); + + it('LitRadioBoxTest03', () => { + expect(litRadioBox.initHtml()).toMatchInlineSnapshot(` +" + + + + " +`); + }); + + it('litRadioGroupTest01', () => { + let isReturn = litRadioGroup.value.length == 0; + expect(isReturn).toBeTruthy(); + }); + + it('litRadioGroupTest02', () => { + expect(litRadioGroup.initHtml()).toMatchInlineSnapshot(` +" + + " +`); + }); +}); diff --git a/ide/test/base-ui/select/LitAllocationSelect.test.ts b/ide/test/base-ui/select/LitAllocationSelect.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bace49ae9670f0c1b19363e1f8db8e14904d2fc9 --- /dev/null +++ b/ide/test/base-ui/select/LitAllocationSelect.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitAllocationSelect } from '../../../dist/base-ui/select/LitAllocationSelect.js'; + +describe('LitAllocationSelect Test', () => { + let litAllocationSelect = new LitAllocationSelect(); + it('LitAllocationSelectTest01', function () { + expect(litAllocationSelect.value).toBe(''); + }); + it('LitAllocationSelectTest02', () => { + expect(litAllocationSelect.processData).toBeUndefined(); + }); + it('LitAllocationSelectTest03', function () { + expect(litAllocationSelect.placement).toBe(''); + }); + it('LitAllocationSelectTest04', function () { + litAllocationSelect.placement = true; + expect(litAllocationSelect.placement).toBeTruthy(); + }); + it('LitAllocationSelectTest05', function () { + litAllocationSelect.placement = false; + expect(litAllocationSelect.placement).toBeFalsy(); + }); + it('LitAllocationSelectTest06', function () { + expect(litAllocationSelect.listHeight).toBe('256px'); + }); + it('LitAllocationSelectTest07', function () { + litAllocationSelect.listHeight = 'test'; + expect(litAllocationSelect.listHeight).toBe('test'); + }); + it('LitAllocationSelectTest08', function () { + litAllocationSelect.placeholder = 'test'; + expect(litAllocationSelect.placeholder).toBe('test'); + }); + it('LitAllocationSelectTest09', () => { + expect(litAllocationSelect.initElements()).toBeUndefined(); + }); + + it('LitAllocationSelectTest10', () => { + litAllocationSelect.processData = []; + expect(litAllocationSelect.processData).toBe(undefined); + }); + + it('LitAllocationSelectTest12', () => { + litAllocationSelect.processData = ['1', '2', '3']; + expect(litAllocationSelect.processData).toBe(undefined); + }); + + it('LitAllocationSelectTest11', () => { + const onclick = jest.fn(); + let allocationSelect = (document.body.innerHTML = ` + + `); + const select = document.getElementById('select'); + expect(onclick).not.toBeCalled(); + select!.onclick = onclick; + select!.click(); + expect(onclick).toBeCalled(); + expect(onclick).toHaveBeenCalledTimes(1); + }); +}); diff --git a/ide/test/base-ui/select/LitSelect.test.ts b/ide/test/base-ui/select/LitSelect.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee37b13f62b0fe28a4929fb0ed025ff0826f81dd --- /dev/null +++ b/ide/test/base-ui/select/LitSelect.test.ts @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitButton, LitSelect } from '../../../dist/base-ui/select/LitSelect.js'; +import { LitSelectOption } from '../../../src/base-ui/select/LitSelectOption'; + +describe('LitSelect Test', () => { + it('LitSelectTest01', function () { + let litSelect = new LitSelect(); + expect(litSelect).not.toBeUndefined(); + }); + + it('LitSelectTest02', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + expect(select).not.toBeUndefined(); + }); + + it('LitSelectTest03', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.value = 'value'; + expect(select.value).toBe('value'); + }); + + it('LitSelectTest04', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.border = 'value'; + expect(select.border).toBe('true'); + }); + it('LitSelectTest05', function () { + let lit = new LitSelect(); + expect(lit.border).toBe('true'); + }); + it('LitSelectTest06', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.listHeight = true; + expect(select.listHeight).toBe('true'); + }); + + it('LitSelectTest07', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.defaultValue = true; + expect(select.defaultValue).toBe('true'); + }); + + it('LitSelectTest08', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.loading = 1; + expect(select.loading).toBe(true); + }); + + it('LitSelectTest09', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + expect(select.isMultiple()).toBe(false); + }); + + it('LitSelectTest10', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.inputElement.value = '3333'; + select.click(); + expect(select.focused).toBe(true); + }); + + it('LitSelectTest11', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.clear(); + expect(select.inputElement.value).toBe(''); + }); + + it('LitSelectTest12', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + expect(select.reset()).toBeUndefined(); + }); + + it('LitSelectTest13', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + let newTag = select.newTag('111', '111'); + expect(newTag.text).toBe('111'); + }); + it('LitSelectTest14', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.dataSource = [{ key: '111' }]; + let cleart = select.clearElement as HTMLElement; + cleart.click(); + expect(select.inputElement.value).toBe(''); + }); + + it('LitSelectTest15', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + let input = select.inputElement as HTMLInputElement; + input.value = '11'; + expect(select.inputElement.value).toBe('11'); + }); + + it('LitSelectTest16', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.dataSource = [{ key: '111' }]; + expect(select.inputElement.value).toBe(''); + }); + + it('LitSelectTest17', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.placeholder = true; + expect(select.placeholder).toBe('true'); + }); + it('LitSelectTest20', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.rounded = 1; + expect(select.rounded).toBe(true); + }); + + it('LitSelectTest21', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.placement = 1; + expect(select.placement).toBe('1'); + }); + + it('LitSelectTest18', function () { + let litSelect = new LitSelect(); + expect(litSelect.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ + + + +
+
+ + +
+ " +`); + }); + + it('LitSelectTest23', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.canInsert = true; + expect(select.canInsert).toBeTruthy(); + }); + it('LitSelectTest24', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.rounded = false; + expect(select.rounded).toBeFalsy(); + }); + it('LitSelectTest25', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.placement = false; + expect(select.placement).toBeFalsy(); + }); + it('LitSelectTest26', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.border = true; + expect(select.border).toBeTruthy(); + }); + it('LitSelectTest27', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.canInsert = false; + expect(select.canInsert).toBeFalsy(); + }); + it('LitSelectTest28', function () { + document.body.innerHTML = ``; + let select = document.querySelector('#litSelect') as LitSelect; + select.loading = false; + expect(select.loading).toBeFalsy(); + }); + + it('LitSelectTest29', function () { + let lit = new LitSelect(); + lit.border = false; + expect(lit.border).toBe('false'); + }); + + it('LitSelectTest30', function () { + let litSelect = (document.body.innerHTML = ` + + + ` as LitSelect); + let select = document.querySelector('#litSelect') as LitSelect; + expect(select.reset()).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/select/LitSelectOption.test.ts b/ide/test/base-ui/select/LitSelectOption.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a29ba0eb65b8d156e0cdc09eb58fea4400677c66 --- /dev/null +++ b/ide/test/base-ui/select/LitSelectOption.test.ts @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitSelectOption } from '../../../dist/base-ui/select/LitSelectOption.js'; + +describe('LitSelectOption Test', () => { + it('LitSelectOptionTest01', function () { + document.body.innerHTML = ""; + let inner = document.querySelector('#aa') as LitSelectOption; + expect(inner).not.toBeUndefined(); + }); + it('LitSelectOptionTest03', function () { + expect(LitSelectOption.adoptedCallback).toBeUndefined(); + }); + + it('LitSelectOptionTest04', function () { + expect(LitSelectOption.disconnectedCallback).toBeUndefined(); + }); + + it('LitSelectOptionTest05', function () { + expect(LitSelectOption.attributeChangedCallback).toBeUndefined(); + }); + + it('LitSelectOption02', function () { + let litSelect = new LitSelectOption(); + expect(litSelect.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ + + " +`); + }); +}); diff --git a/ide/test/base-ui/select/LitSelectV.test.ts b/ide/test/base-ui/select/LitSelectV.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e66c5ac7d5dfb95572a91c2b8beb3c58e339e836 --- /dev/null +++ b/ide/test/base-ui/select/LitSelectV.test.ts @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitSelectV } from '../../../dist/base-ui/select/LitSelectV.js'; + +describe('LitSelectV Test', () => { + let litSelectV = new LitSelectV(); + it('LitSelectVTest01', function () { + expect(litSelectV.value).not.toBeUndefined(); + }); + it('LitSelectVTest02', function () { + litSelectV.rounded = true; + expect(litSelectV.rounded).toBeTruthy(); + }); + it('LitSelectVTest06', function () { + litSelectV.rounded = false; + expect(litSelectV.rounded).toBeFalsy(); + }); + it('LitSelectVTest03', function () { + expect(litSelectV.placement).toBe(''); + }); + it('LitSelectVTest04', function () { + litSelectV.placement = true; + expect(litSelectV.placement).toBeTruthy(); + }); + it('LitSelectVTest05', function () { + litSelectV.placement = false; + expect(litSelectV.placement).toBeFalsy(); + }); + it('LitSelectVTest07', function () { + litSelectV.boder = true; + expect(litSelectV.border).toBeTruthy(); + }); + it('LitSelectVTest08', function () { + litSelectV.border = false; + expect(litSelectV.border).toBe('false'); + }); + it('LitSelectVTest14', function () { + litSelectV.border = true; + expect(litSelectV.border).toBe('true'); + }); + it('LitSelectVTest09', function () { + litSelectV.defaultValue = 'test'; + expect(litSelectV.defaultValue).toBe('test'); + }); + it('LitSelectVTest010', function () { + litSelectV.placeholder = 'test'; + expect(litSelectV.placeholder).toBe('test'); + }); + it('LitSelectVTest011', function () { + litSelectV.all = true; + expect(litSelectV.all).toBeTruthy(); + }); + it('LitSelectVTest012', function () { + litSelectV.all = false; + expect(litSelectV.all).toBeFalsy(); + }); + it('LitSelectVTest013', function () { + let value = [ + { + length: 1, + }, + ]; + let valueStr = ''; + expect(litSelectV.dataSource(value, valueStr)).toBeUndefined(); + }); + it('LitSelectVTest014', function () { + let value = [ + { + length: 1, + }, + ]; + let valueStr = 'aa'; + expect(litSelectV.dataSource(value, valueStr)).toBeUndefined(); + }); + it('LitSelectVTest015', function () { + expect(litSelectV.connectedCallback()).toBeUndefined(); + }); + it('LitSelectVTest016', function () { + let valueStr = 'aa'; + expect(litSelectV.dataSource([], valueStr)).toBeUndefined(); + }); + it('LitSelectVTest017', function () { + let value = [ + { + length: 1, + }, + ]; + let valueStr = 'aa'; + litSelectV.all = true; + expect(litSelectV.dataSource(value, valueStr)).toBeUndefined(); + }); + it('LitSelectVTest018', function () { + let value = [ + { + length: 1, + }, + ]; + let valueStr = 'aa'; + litSelectV.title = 'Event List'; + expect(litSelectV.dataSource(value, valueStr)).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/slice/lit-slicer.test.ts b/ide/test/base-ui/slice/lit-slicer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..83d7eb2abf706ff38c63608b89100ea90a5b7224 --- /dev/null +++ b/ide/test/base-ui/slice/lit-slicer.test.ts @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitSlicer, LitSlicerTrack } from '../../../dist/base-ui/slicer/lit-slicer.js'; + +describe('slicer Test', () => { + it('slicerTest01', function () { + let litSlicer = new LitSlicer(); + expect(litSlicer).not.toBeUndefined(); + expect(litSlicer).not.toBeNull(); + }); + it('slicerTest02', function () { + let litSlicerTrack = new LitSlicerTrack(); + expect(litSlicerTrack).not.toBeUndefined(); + expect(litSlicerTrack).not.toBeNull(); + }); + it('slicerTest03', function () { + let litSlicerTrack = new LitSlicerTrack(); + expect(litSlicerTrack.rangeLeft).toBe(200); + }); + it('slicerTest04', function () { + let litSlicerTrack = new LitSlicerTrack(); + litSlicerTrack.rangeLeft = true; + expect(litSlicerTrack.rangeLeft).not.toBeTruthy(); + }); + it('slicerTest05', function () { + let litSlicerTrack = new LitSlicerTrack(); + expect(litSlicerTrack.rangeRight).toBe(300); + }); + it('slicerTest09', function () { + let litSlicerTrack = new LitSlicerTrack(); + litSlicerTrack.rangeRight = false; + expect(litSlicerTrack.rangeRight).toBeFalsy(); + }); + it('slicerTest06', function () { + let litSlicer = new LitSlicer(); + expect(litSlicer.attributeChangedCallback()).toBeUndefined(); + }); + it('slicerTest07', function () { + let litSlicerTrack = new LitSlicerTrack(); + expect(litSlicerTrack.adoptedCallback()).toBeUndefined(); + }); + it('slicerTest08', function () { + let litSlicerTrack = new LitSlicerTrack(); + expect(litSlicerTrack.attributeChangedCallback()).toBeUndefined(); + }); + it('slicerTest10', function () { + let litSlicer = new LitSlicer(); + litSlicer.direction = 'h'; + expect(litSlicer.connectedCallback()).toBeUndefined(); + }); + it('slicerTest11', function () { + let litSlicer = new LitSlicer(); + litSlicer.direction = 'v'; + expect(litSlicer.direction).toBeUndefined(); + }); + it('slicerTest12', function () { + let litSlicer = new LitSlicer(); + litSlicer.style = 'v'; + expect(litSlicer.style).toBeUndefined(); + }); + + it('slicerTest13', function () { + let litSlicer = new LitSlicer(); + litSlicer.style = 'v'; + document.body.innerHTML = ` + + + `; + let slice = document.getElementById('slicer') as LitSlicerTrack; + let line = slice.shadowRoot?.querySelector('#root') as HTMLDivElement; + let mouseOutEvent: MouseEvent = new MouseEvent('mousedown', { movementX: 1, movementY: 2 }); + + line.dispatchEvent(mouseOutEvent); + let onmousemove: MouseEvent = new MouseEvent('mousemove', { movementX: 1, movementY: 2 }); + document.dispatchEvent(onmousemove); + let onmouseleave: MouseEvent = new MouseEvent('mouseleave', { movementX: 1, movementY: 2 }); + document.dispatchEvent(onmouseleave); + let onmouseup: MouseEvent = new MouseEvent('mouseup', { + movementX: 1, + movementY: 2, + }); + document.dispatchEvent(onmouseup); + expect(litSlicer.style).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/slider/LitSlider.test.ts b/ide/test/base-ui/slider/LitSlider.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a2800d9a052bdcc90fe1a9af97ef8e383004c9b --- /dev/null +++ b/ide/test/base-ui/slider/LitSlider.test.ts @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitSlider } from '../../../dist/base-ui/slider/LitSlider.js'; + +describe('LitSlider Test', () => { + let litSliderPanel = new LitSlider(); + + litSliderPanel.disabledX = 'disabledX'; + litSliderPanel.customSlider = 'customSlider'; + litSliderPanel.customLine = 'customLine'; + litSliderPanel.customButton = 'customButton'; + litSliderPanel.percent = 'percent'; + litSliderPanel.resultUnit = 'resultUnit'; + + it('LitSliderTest01', () => { + expect(litSliderPanel.disabledX).toEqual(''); + }); + + it('LitSliderTest02', () => { + expect(litSliderPanel.customSlider).toEqual(''); + }); + + it('LitSliderTest03', () => { + expect(litSliderPanel.customLine).toEqual('customLine'); + }); + + it('LitSliderTest04', () => { + expect(litSliderPanel.customButton).toEqual('customButton'); + }); + + it('LitSliderTest05', () => { + expect(litSliderPanel.percent).toEqual('percent'); + }); + + it('LitSliderTest06', () => { + expect(litSliderPanel.resultUnit).toEqual('resultUnit'); + }); + + it('LitSliderTest07', () => { + expect(litSliderPanel.formatSeconds(10)).toBe('00:00:10'); + }); + + it('LitSliderTest08', () => { + litSliderPanel.litSliderStyle = jest.fn(() => true); + litSliderPanel.litSliderStyle.minRange = jest.fn(() => 2); + litSliderPanel.litSliderStyle.maxRange = jest.fn(() => 1); + litSliderPanel.litSliderStyle.stepSize = jest.fn(() => 1); + expect(litSliderPanel.renderDefaultSlider()).toBeUndefined(); + }); + + it('LitSliderTest9', () => { + expect(litSliderPanel.adoptedCallback()).toBeUndefined(); + }); + + it('LitSliderTest10', () => { + expect(litSliderPanel.disconnectedCallback()).toBeUndefined(); + }); + + it('LitSliderTest11', () => { + expect(litSliderPanel.disconnectedCallback()).toBeUndefined(); + }); + + it('LitSliderTest12', function () { + expect(litSliderPanel.attributeChangedCallback('percent', '', '0%' || null)).toBeUndefined(); + }); + + it('LitSliderTest13', function () { + expect(litSliderPanel.initHtml()).toMatchInlineSnapshot(` +" + + +
+ +
+ " +`); + }); + + it('LitSliderTest14', () => { + litSliderPanel.disabledX = false; + expect(litSliderPanel.disabledX).toBeFalsy(); + }); + + it('LitSliderTest15', () => { + litSliderPanel.customSlider = false; + expect(litSliderPanel.customSlider).toBeFalsy(); + }); + + it('LitSliderTest16', () => { + expect(litSliderPanel.formatSeconds(36000)).toBe('10:00:00'); + }); + + it('LitSliderTest17', () => { + expect(litSliderPanel.formatSeconds(4000)).toBe('01:06:40'); + }); +}); diff --git a/ide/test/base-ui/switch/LitSwitch.test.ts b/ide/test/base-ui/switch/LitSwitch.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6bbce7102cf1dc53b6fcfa7b072ce95f70f66c0e --- /dev/null +++ b/ide/test/base-ui/switch/LitSwitch.test.ts @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import LitSwitch from '../../../dist/base-ui/switch/lit-switch'; + +describe('LitSwitch Test', () => { + let litSwitch = new LitSwitch(); + litSwitch.checked = true; + litSwitch.checked = false; + litSwitch.disabled = true; + litSwitch.disabled = false; + + it('LitSwitchTest01', () => { + expect(litSwitch.name).toBeNull(); + }); + + it('LitSwitchTest02', () => { + expect(litSwitch.disabled).toBeFalsy(); + }); + + it('LitSwitchTest03', () => { + expect(litSwitch.checked).toBeFalsy(); + }); + + it('LitSwitchTest04', () => { + LitSwitch.switch = document.querySelector('#switch') as HTMLInputElement; + expect(litSwitch.connectedCallback()).toBeUndefined(); + }); + + it('LitSwitchTest05', () => { + expect(litSwitch.attributeChangedCallback('disabled', 'disabled', '')).toBeUndefined(); + }); + + it('LitSwitchTest06', () => { + expect(litSwitch.attributeChangedCallback('disabled', 'disabled', null)).toBeUndefined(); + }); + + it('LitSwitchTest07', () => { + expect(litSwitch.attributeChangedCallback('checked', 'disabled', '')).toBeUndefined(); + }); + + it('LitSwitchTest08', () => { + expect(litSwitch.attributeChangedCallback('checked', 'disabled', null)).toBeUndefined(); + }); + + it('LitSwitchTest09', () => { + expect(litSwitch.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }); +}); diff --git a/ide/test/base-ui/table/LitTable.test.ts b/ide/test/base-ui/table/LitTable.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb65a10748d7463aa9ab14f99969b32f861ade0b --- /dev/null +++ b/ide/test/base-ui/table/LitTable.test.ts @@ -0,0 +1,842 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitTable } from '../../../dist/base-ui/table/lit-table.js'; +// @ts-ignore +import { LitTableColumn } from '../../../dist/base-ui/table/lit-table-column.js'; +// @ts-ignore +import { TableRowObject } from '../../../dist/base-ui/table/TableRowObject.js'; +// @ts-ignore +import { LitProgressBar } from '../../../dist/base-ui/progress-bar/LitProgressBar.js'; +describe('LitTable Test', () => { + window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + let litTable = new LitTable(); + litTable.selectable = true; + litTable.selectable = false; + litTable.scrollY = 'scrollY'; + + litTable.dataSource = []; + + litTable.dataSource = [ + { + id: 1, + name: 'name', + }, + { + id: 2, + name: 'nameValue', + }, + ]; + const td = { + style: { + position: 'sticky', + left: '0px', + right: '0px', + boxShadow: '3px 0px 5px #33333333', + }, + }; + const placement = 'left'; + + const element = { + style: { + display: 'none', + transform: 'translateY', + }, + childNodes: { forEach: true }, + onclick: 1, + }; + const rowObject = { + children: { + length: 1, + }, + data: [{ isSelected: undefined }], + depth: 1, + top: 1, + }; + const firstElement = + { + style: { + display: 'none', + paddingLeft: '', + transform: 'translateY', + }, + innerHTML: '', + title: '', + firstChild: null, + onclick: 1, + } || undefined; + + litTable.columns = litTable.columns || jest.fn(() => true); + + litTable.tbodyElement = jest.fn(() => ({ + innerHTML: '', + })); + + litTable.tableColumns = jest.fn(() => []); + + litTable.tableColumns.forEach = jest.fn(() => []); + + it('LitTableTest01', () => { + expect(litTable.adoptedCallback()).toBeUndefined(); + }); + + it('LitTableTest02', () => { + litTable.ds = [ + { + name: 'StartTime', + value: '1s 489ms 371μs ', + }, + { + name: 'Duration', + value: '6ms 440μs ', + }, + { + name: 'State', + value: 'Sleeping', + }, + { + name: 'Process', + value: 'hilogd [441] ', + }, + ]; + litTable.setAttribute('selectable', '123'); + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + + let tableColmn2 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn2.setAttribute('title', '3'); + tableColmn2.setAttribute('data-index', '3'); + tableColmn2.setAttribute('key', '3'); + tableColmn2.setAttribute('align', 'flex-start'); + tableColmn2.setAttribute('height', '32px'); + litTable.tableColumns = [tableColmn, tableColmn1, tableColmn2]; + litTable.tbodyElement = document.createElement('div'); + expect(litTable.renderTable()).toBeUndefined(); + }); + + it('LitTableTest04', () => { + litTable.switch = document.querySelector('#switch') as HTMLInputElement; + expect(litTable.connectedCallback()).toBeUndefined(); + }); + + it('LitTableTest05', () => { + let rowLength = litTable.getCheckRows().length == 0; + expect(rowLength).toBeTruthy(); + }); + + it('LitTableTest06', () => { + expect( + litTable.deleteRowsCondition(() => { + return true; + }) + ).toBeUndefined(); + }); + + it('LitTableTest07', () => { + expect(litTable.selectable).not.toBeUndefined(); + }); + + it('LitTableTest08', () => { + litTable.selectable = true; + expect(litTable.selectable).toBeTruthy(); + }); + + it('LitTableTest09', () => { + expect(litTable.scrollY).not.toBeUndefined(); + }); + + it('LitTableTest10', () => { + expect(litTable.dataSource).not.toBeUndefined(); + }); + + it('LitTableTest11', () => { + expect(litTable.recycleDataSource).not.toBeUndefined(); + }); + + it('LitTableTest12', () => { + expect(litTable.fixed(td, placement)).toBeUndefined(); + }); + + it('LitTableTest13', () => { + expect(litTable.fixed(td, 'right')).toBe(undefined); + }); + + it('LitTableTest14', () => { + expect(litTable.meauseElementHeight()).toBe(27); + }); + + it('LitTableTest15', () => { + expect(litTable.meauseTreeElementHeight()).toBe(27); + }); + + it('LitTableTest16', () => { + document.body.innerHTML = ""; + let table = document.querySelector('#tab') as LitTable; + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', '1'); + htmlElement.setAttribute('data-index', '1'); + htmlElement.setAttribute('key', '1'); + htmlElement.setAttribute('align', 'flex-start'); + htmlElement.setAttribute('height', '32px'); + table!.appendChild(htmlElement); + setTimeout(() => { + table.recycleDataSource = [ + { + id: 1, + name: 'name', + }, + { + id: 2, + name: 'nameValue', + }, + ]; + expect(table.meauseTreeElementHeight()).toBe(27); + }, 20); + }); + + it('LitTableTest17', () => { + expect(litTable.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + + + +
+ +
+
+
+
+
+
+
+
+ " +`); + }); + + it('LitTableTest18', () => { + expect(litTable.createExpandBtn({ expanded: false,data:{status:true} })).not.toBeUndefined(); + }); + + it('LitTableTest19', () => { + let newTableElement = document.createElement('div'); + newTableElement.classList.add('tr'); + newTableElement.style.cursor = 'pointer'; + newTableElement.style.gridTemplateColumns = '1,2,3'; + newTableElement.style.position = 'absolute'; + newTableElement.style.top = '0px'; + newTableElement.style.left = '0px'; + litTable.currentRecycleList = [newTableElement]; + litTable.recycleDs = [{ rowHidden: false, data: { isSearch: true } }]; + litTable.tbodyElement = document.createElement('div'); + litTable.treeElement = document.createElement('div'); + litTable.tableElement = document.createElement('div'); + litTable.theadElement = document.createElement('div'); + expect(litTable.reMeauseHeight()).toBeUndefined(); + }); + + it('LitTableTest20', () => { + const rowData = { + data: [ + { + isSelected: undefined, + }, + ], + }; + litTable.columns.forEach = jest.fn(() => true); + expect(litTable.createNewTableElement(rowData)).not.toBeUndefined(); + }); + + it('LitTableTest21', () => { + let element = document.createElement('div'); + let ch = document.createElement('div'); + element.appendChild(ch); + let rowObject = { rowHidden: false, data: { isSearch: true } }; + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + litTable.columns = [tableColmn, tableColmn1]; + expect(litTable.freshCurrentLine(element, rowObject)).toBeUndefined(); + }); + + it('LitTableTest22', () => { + litTable.recycleDs.length = 1; + litTable.setCurrentSelection = jest.fn(() => true); + expect(litTable.scrollToData()).toBeUndefined(); + }); + + it('LitTableTest23', () => { + litTable.recycleDs = [{ rowHidden: false, data: { isSearch: true } }]; + let dataSource = [ + { + id: 1, + name: 'name', + }, + { + id: 2, + name: 'nameValue', + }, + ]; + expect(litTable.expandList(dataSource)).toBeUndefined(); + }); + + it('LitTableTest24', () => { + expect(litTable.clearAllSelection()).toBeUndefined(); + }); + + it('LitTableTest25', () => { + expect(litTable.dispatchRowClickEvent({ data: { isSelected: '' } })).toBeUndefined(); + }); + + it('LitTableTest26', () => { + litTable.treeElement = jest.fn(() => undefined); + litTable.treeElement.children = jest.fn(() => [1]); + litTable.columns.forEach = jest.fn(() => true); + litTable.treeElement.lastChild = jest.fn(() => true); + litTable.treeElement.lastChild.style = jest.fn(() => true); + expect(litTable.createNewTreeTableElement({ data: '' })).not.toBeUndefined(); + }); + + it('LitTableTest27', () => { + litTable.tableElement = jest.fn(() => undefined); + litTable.tableElement.scrollTop = jest.fn(() => 1); + expect(litTable.move1px()).toBeUndefined(); + }); + + it('LitTableTest28', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#aaa') as LitTable; + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + litTable.tableColumns = [tableColmn, tableColmn1]; + litTable.columns = [tableColmn, tableColmn1]; + litTable.selectable = true; + litTable.ds = [ + { id: 1, pid: null, name: '1' }, + { id: 2, pid: 1, name: '2' }, + { id: 3, pid: 1, name: '3' }, + { id: 4, pid: null, name: '4' }, + { id: 5, pid: 4, name: '4' }, + { id: 6, pid: 4, name: '5' }, + { id: 7, pid: 3, name: '7' }, + { id: 8, pid: 4, name: '8' }, + ]; + expect(litTable.renderTreeTable()).toBeUndefined(); + }); + + it('LitTableTest29', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#aaa') as LitTable; + expect(litTable.setMouseIn(true, [])).toBeUndefined(); + }); + + it('LitTableTest30', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#aaa') as LitTable; + const data = { + isSelected: true, + }; + expect(litTable.setCurrentSelection(data)).toBeUndefined(); + }); + + it('LitTableTest31', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#aaa') as LitTable; + litTable.formatName = true; + expect(litTable.formatName).toBeTruthy(); + }); + it('LitTableTest32', () => { + let litTable = new LitTable(); + expect(litTable.formatName()).toBe(''); + }); + + it('LitTableTest33', () => { + let litTable = new LitTable(); + expect(litTable.dataExportInit()).toBeUndefined(); + }); + it('LitTableTest34', () => { + let litTable = new LitTable(); + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', '1'); + htmlElement.setAttribute('data-index', '1'); + htmlElement.setAttribute('key', '1'); + htmlElement.setAttribute('align', 'flex-start'); + htmlElement.setAttribute('height', '32px'); + litTable.columns = [htmlElement]; + document.body.innerHTML = ` `; + let progressBar = document.querySelector('#export_progress_bar') as LitProgressBar; + litTable.exportProgress = progressBar; + expect(litTable.exportData()).toBeUndefined(); + }); + + it('LitTableTest35', () => { + expect(litTable.formatExportData()).not.toBeUndefined(); + }); + + it('LitTableTest36', () => { + expect(litTable.setSelectedRow(true, [])).toBeUndefined(); + }); + + it('LitTableTest37', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#aaa') as LitTable; + litTable.setAttribute('tree', true); + expect(litTable.dataSource).toStrictEqual([]); + }); + + it('LitTableTest38', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#aaa') as LitTable; + litTable.rememberScrollTop = true; + expect(litTable.recycleDataSource).toStrictEqual([]); + }); + + it('LitTableTest39', () => { + let litTable = new LitTable(); + expect(litTable.dataExportInit()).toBeUndefined(); + }); + + it('LitTableTest40', () => { + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + + let tableColmn2 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn2.setAttribute('title', '3'); + tableColmn2.setAttribute('data-index', '3'); + tableColmn2.setAttribute('key', '3'); + tableColmn2.setAttribute('align', 'flex-start'); + tableColmn2.setAttribute('height', '32px'); + litTable.columns = [tableColmn, tableColmn1, tableColmn2]; + let dataSource = [ + { + id: 1, + name: 'name', + }, + { + id: 2, + name: 'nameValue', + }, + ]; + expect(litTable.formatExportData(dataSource)).toBeTruthy(); + }); + + it('LitTableTest41', () => { + let list = [ + { + memoryTap: 'All Heap', + existing: 1938, + existingString: '1.89 Kb', + freeByteString: '4.54 Kb', + allocCount: 46, + freeCount: 103, + freeByte: 4653, + totalBytes: 6591, + totalBytesString: '6.44 Kb', + maxStr: '200 byte', + max: 200, + totalCount: 149, + existingValue: [1938, 6591, 566720], + }, + ]; + LitTable.createNewTreeTableElement = jest.fn().mockResolvedValue({}); + litTable.treeElement = document.createElement('div'); + litTable.tableElement = document.createElement('div'); + litTable.setAttribute('selectable', '123'); + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + + let tableColmn2 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn2.setAttribute('title', '3'); + tableColmn2.setAttribute('data-index', '3'); + tableColmn2.setAttribute('key', '3'); + tableColmn2.setAttribute('align', 'flex-start'); + tableColmn2.setAttribute('height', '32px'); + litTable.columns = [tableColmn, tableColmn1, tableColmn2]; + litTable.tbodyElement = document.createElement('div'); + litTable.theadElement = document.createElement('div'); + expect(litTable.meauseTreeRowElement(list)).toBeTruthy(); + }); + + it('LitTableTest42', () => { + let list = [ + { + memoryTap: 'All Heap', + existing: 1938, + existingString: '1.89 Kb', + freeByteString: '4.54 Kb', + allocCount: 46, + freeCount: 103, + freeByte: 4653, + totalBytes: 6591, + totalBytesString: '6.44 Kb', + maxStr: '200 byte', + max: 200, + totalCount: 149, + existingValue: [1938, 6591, 566720], + }, + ]; + LitTable.createNewTreeTableElement = jest.fn().mockResolvedValue({}); + litTable.treeElement = document.createElement('div'); + litTable.tableElement = document.createElement('div'); + litTable.setAttribute('selectable', '123'); + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + + let tableColmn2 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn2.setAttribute('title', '3'); + tableColmn2.setAttribute('data-index', '3'); + tableColmn2.setAttribute('key', '3'); + tableColmn2.setAttribute('align', 'flex-start'); + tableColmn2.setAttribute('height', '32px'); + litTable.columns = [tableColmn, tableColmn1, tableColmn2]; + litTable.tbodyElement = document.createElement('div'); + litTable.theadElement = document.createElement('div'); + expect(litTable.meauseAllRowHeight(list)).toBeTruthy(); + }); + + it('LitTableTest43', () => { + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + + let tableColmn2 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn2.setAttribute('title', '3'); + tableColmn2.setAttribute('data-index', '3'); + tableColmn2.setAttribute('key', '3'); + tableColmn2.setAttribute('align', 'flex-start'); + tableColmn2.setAttribute('height', '32px'); + litTable.columns = [tableColmn, tableColmn1, tableColmn2]; + let dataSource = [ + { + id: 1, + name: 'name', + }, + { + id: 2, + name: 'nameValue', + }, + ]; + expect(litTable.formatExportCsvData(dataSource)).toBeTruthy(); + }); + + it('LitTableTest44', () => { + let element = document.createElement('div'); + litTable.tableElement = document.createElement('div'); + let firstElement = document.createElement('div'); + let ch = document.createElement('div'); + element.appendChild(ch); + let rowObject = { rowHidden: false, data: { isSearch: true } }; + let tableColmn = document.createElement('lit-table-column') as LitTableColumn; + tableColmn.setAttribute('title', '1'); + tableColmn.setAttribute('data-index', '1'); + tableColmn.setAttribute('key', '1'); + tableColmn.setAttribute('align', 'flex-start'); + tableColmn.setAttribute('height', '32px'); + let tableColmn1 = document.createElement('lit-table-column') as LitTableColumn; + tableColmn1.setAttribute('title', '2'); + tableColmn1.setAttribute('data-index', '2'); + tableColmn1.setAttribute('key', '2'); + tableColmn1.setAttribute('align', 'flex-start'); + tableColmn1.setAttribute('height', '32px'); + litTable.columns = [tableColmn, tableColmn1]; + expect(litTable.freshCurrentLine(element, rowObject, firstElement)).toBeUndefined(); + }); + it('LitTableTest45', () => { + litTable.hideDownload = true; + expect(litTable.hideDownload).toBeTruthy(); + }); + it('LitTableTest46', () => { + litTable.hideDownload = false; + expect(litTable.hideDownload).not.toBeUndefined(); + }); + it('LitTableTest47', () => { + expect(litTable.createBtn({ expanded: false,data:{status:true} })).not.toBeUndefined(); + }); + it('LitTableTest48', () => { + expect(litTable.mouseOut()).toBeUndefined(); + }); + it('LitTableTest49', () => { + expect(litTable.setCurrentHover({})).toBeUndefined(); + }); + it('LitTableTest50', () => { + expect(litTable.clearAllHover({})).toBeUndefined(); + }); +}); diff --git a/ide/test/base-ui/table/LitTableColumn.test.ts b/ide/test/base-ui/table/LitTableColumn.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..26c968cd77d3ecee5ae9a86ac1f6f82cf7a85718 --- /dev/null +++ b/ide/test/base-ui/table/LitTableColumn.test.ts @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitTableColumn } from '../../../dist/base-ui/table/lit-table-column.js'; + +describe('LitTableGroup Test', () => { + let litTableColumn = new LitTableColumn(); + litTableColumn.title = 'title'; + + it('LitTableGroupTest01', () => { + expect(litTableColumn.adoptedCallback()).toBeUndefined(); + }); + + it('LitTableGroupTest02', () => { + expect(litTableColumn.connectedCallback()).toBeUndefined(); + }); + + it('LitTableGroupTest03', () => { + expect(litTableColumn.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + + " +`); + }); +}); diff --git a/ide/test/base-ui/table/LitTableGroup.test.ts b/ide/test/base-ui/table/LitTableGroup.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6677d4f7d82e4252a55f726c370d363b06abada --- /dev/null +++ b/ide/test/base-ui/table/LitTableGroup.test.ts @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitTableGroup } from '../../../dist/base-ui/table/lit-table-group.js'; + +describe('LitTableGroup Test', () => { + let litTableGroup = new LitTableGroup(); + litTableGroup.title = 'title'; + + it('LitTableGroupTest01', () => { + expect(litTableGroup.adoptedCallback()).toBeUndefined(); + }); + + it('LitTableGroupTest02', () => { + expect(litTableGroup.title).toBe('title'); + }); + + it('LitTableGroupTest03', () => { + expect(litTableGroup.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + + " +`); + }); +}); diff --git a/ide/test/base-ui/table/TableRowObject.test.ts b/ide/test/base-ui/table/TableRowObject.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..90cc0ef019107a38705869e3bf112c3b7f855757 --- /dev/null +++ b/ide/test/base-ui/table/TableRowObject.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { TableRowObject } from '../../../dist/base-ui/table/TableRowObject.js'; + +describe('TableRowObject Test', () => { + it('TableRowObjectTest01', () => { + expect(new TableRowObject().top).toBe(0); + }); +}); diff --git a/ide/test/base-ui/tabs/LitTabpane.test.ts b/ide/test/base-ui/tabs/LitTabpane.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b251c32a5715166b0faedc0f1f8611e6fa9013c6 --- /dev/null +++ b/ide/test/base-ui/tabs/LitTabpane.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitTabpane } from '../../../dist/base-ui/tabs/lit-tabpane.js'; + +describe('LitTabPane Test', () => { + let litTabPane = new LitTabpane(); + + litTabPane.tab = 'tab'; + litTabPane.disabled = null || false; + litTabPane.disabled = !null || !false; + litTabPane.hidden = 'hidden'; + litTabPane.closeable = false; + litTabPane.key = 'key'; + + it('LitTabPaneTest1', () => { + expect(litTabPane.attributeChangedCallback('disabled', 'disabled', '')).toBeUndefined(); + }); + + it('LitTabPaneTest2', () => { + expect(litTabPane.tab).toBe('tab'); + }); + + it('LitTabPaneTest3', () => { + expect(litTabPane.icon).toBeNull(); + }); + + it('LitTabPaneTest4', () => { + expect(litTabPane.disabled).toBeTruthy(); + }); + + it('LitTabPaneTest5', () => { + expect(litTabPane.hidden).toBeTruthy(); + }); + + it('LitTabPaneTest6', () => { + litTabPane.closeable = 'closeable'; + expect(litTabPane.closeable).toBeTruthy(); + }); + + it('LitTabPaneTest7', () => { + expect(litTabPane.key).toBe('key'); + }); + + it('LitTabPaneTest9 ', function () { + expect(litTabPane.connectedCallback()).toBeUndefined(); + }); + + it('LitTabPaneTest10 ', function () { + expect(litTabPane.disconnectedCallback()).toBeUndefined(); + }); + + it('LitTabPaneTest11 ', function () { + expect(litTabPane.adoptedCallback()).toBeUndefined(); + }); + it('LitTabPaneTest8', () => { + expect(litTabPane.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }); +}); diff --git a/ide/test/base-ui/tabs/LitTabs.test.ts b/ide/test/base-ui/tabs/LitTabs.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2335f3aa884471eb0fc37b9bd69b7bfc1e2824d0 --- /dev/null +++ b/ide/test/base-ui/tabs/LitTabs.test.ts @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitTabs } from '../../../dist/base-ui/tabs/lit-tabs.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('LitSwitch Test', () => { + let litTabs = new LitTabs(); + + litTabs.position = 'position'; + litTabs.mode = 'mode'; + litTabs.activekey = 'activekey'; + + litTabs.nav = jest.fn(() => { + let el = document.createElement('div'); + let htmlDivElement = document.createElement('div'); + htmlDivElement.setAttribute('class', "nav-item[data-key='${key}']"); + + el.appendChild(htmlDivElement); + return el; + }); + + LitTabs.nav = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + + LitTabs.nav.querySelectorAll = jest.fn(() => { + return ['fd']; + }); + + it('litTabsTest1', () => { + expect(litTabs.activekey).toBe('activekey'); + }); + + it('litTabsTest01', () => { + expect(litTabs.onTabClick).toBeUndefined(); + }); + + it('litTabsTest02', () => { + litTabs.nav = jest.fn(() => true); + litTabs.nav.querySelector = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + litTabs.nav.querySelectorAll = jest.fn(() => true); + expect(litTabs.updateDisabled('key', 'value')).toBeUndefined(); + }); + + it('litTabsTest03', () => { + litTabs.nav = jest.fn(() => true); + litTabs.nav.querySelector = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + litTabs.nav.querySelectorAll = jest.fn(() => true); + expect(litTabs.updateCloseable('key', 'value')).toBeUndefined(); + }); + + it('litTabsTest04', () => { + litTabs.nav = jest.fn(() => true); + litTabs.nav.querySelector = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + litTabs.nav.querySelectorAll = jest.fn(() => true); + + expect(litTabs.updateHidden('key', 'true')).toBeUndefined(); + }); + + it('litTabsTest13', () => { + litTabs.nav = jest.fn(() => true); + litTabs.nav.querySelector = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + litTabs.nav.querySelectorAll = jest.fn(() => true); + + expect(litTabs.updateHidden('key', !'true')).toBeUndefined(); + }); + + it('litTabsTest05', () => { + expect(litTabs.initTabPos()).toBeUndefined(); + }); + + it('litTabsTest07', () => { + expect(litTabs.activeByKey(null || undefined)).toBeUndefined(); + }); + + it('litTabsTest06', () => { + expect(litTabs.activePane('Key')).toBeFalsy(); + }); + + it('litTabsTest007', () => { + expect(litTabs.connectedCallback()).toBeUndefined(); + }); + it('litTabsTest8', () => { + expect(litTabs.attributeChangedCallback('activekey', 'disabled', 'activekey')).toBeUndefined(); + }); + + it('litTabsTest9', () => { + expect(litTabs.adoptedCallback()).toBeUndefined(); + }); + + it('litTabsTest09', () => { + expect(litTabs.disconnectedCallback()).toBeUndefined(); + }); + it('litTabsTest10', () => { + expect(litTabs.position).toBe('position'); + }); + + it('litTabsTest11', () => { + expect(litTabs.mode).toBe('mode'); + }); + + it('litTabsTest12', () => { + expect(litTabs.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + +
+ +
+ NEED CONTENT +
+
+ " +`); + }); + + it('litTabsTest14', () => { + litTabs.nav = jest.fn(() => true); + litTabs.nav.querySelector = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + litTabs.nav.querySelectorAll = jest.fn(() => true); + expect(litTabs.updateDisabled('key', undefined)).toBeUndefined(); + }); + + it('litTabsTest15', () => { + litTabs.nav = jest.fn(() => true); + litTabs.nav.querySelector = jest.fn(() => { + return document.createElement('div') as HTMLDivElement; + }); + litTabs.nav.querySelectorAll = jest.fn(() => true); + expect(litTabs.updateCloseable('key', undefined)).toBeUndefined(); + }); + + it('litTabsTest19', () => { + expect(litTabs.activePane(null)).toBe(false); + }); +}); diff --git a/ide/test/command/Cmd.test.ts b/ide/test/command/Cmd.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..33e9a6981186d55404b13bc160c00f73cd7ec9d5 --- /dev/null +++ b/ide/test/command/Cmd.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { Cmd } from '../../dist/command/Cmd.js'; + +describe('Cmd', () => { + it('CmdTest_01', () => { + expect(Cmd.execObjDump('', '')).toBeUndefined(); + }); + + it('CmdTest_02', () => { + expect(Cmd.execHdcCmd('')).toBeUndefined(); + }); + + it('CmdTest_03', () => { + expect(Cmd.execFileRecv('', '')).toBeTruthy(); + }); + + it('CmdTest_04', () => { + expect(Cmd.execHdcTraceCmd('', '')).toBeUndefined(); + }); + + it('CmdTest_05', () => { + let params = [ + { + length: 0, + }, + ]; + expect(Cmd.formatString('', params)).toBe(''); + }); + + it('CmdTest_06', () => { + expect(Cmd.showSaveFile()).toBeUndefined(); + }); + + it('CmdTest_07', () => { + expect(Cmd.uploadFile()).toBeUndefined(); + }); + + it('CmdTest_08', () => { + expect(Cmd.copyFile('', '')).toBeUndefined(); + }); + + it('CmdTest_09', () => { + expect(Cmd.openFileDialog()).toBeTruthy(); + }); + + it('CmdTest_10', () => { + expect(Cmd.formatString('', [])).toBe(''); + }); +}); diff --git a/ide/test/hdc/HdcDeviceManager.test.ts b/ide/test/hdc/HdcDeviceManager.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..257fbc347eae2b2b304ec7490e539945a21adf54 --- /dev/null +++ b/ide/test/hdc/HdcDeviceManager.test.ts @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { HdcDeviceManager } from '../../dist/hdc/HdcDeviceManager.js'; + +describe('HdcDeviceManager', () => { + it('HdcDeviceManagerTest_01', () => { + expect(HdcDeviceManager.disConnect(1)).toBeTruthy(); + }); + + it('HdcDeviceManagerTest_02', () => { + expect(HdcDeviceManager.fileRecv('1')).toBeTruthy(); + }); +}); diff --git a/ide/test/hdc/common/BaseConversion.test.ts b/ide/test/hdc/common/BaseConversion.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e77a870021588e7f5c4878633bbf9e71948b968a --- /dev/null +++ b/ide/test/hdc/common/BaseConversion.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { toHex8, toHex16, toHex32, toHex64, uint8ArrayToString } from '../../../dist/hdc/common/BaseConversion.js'; + +describe('BaseConversionTest', () => { + it('BaseConversionTest_toHex8_01', () => { + expect(toHex8('0O8')).toEqual('0O8'); + }); + + it('BaseConversionTest_toHex8_02', () => { + expect(toHex8(32)).toEqual('20'); + }); + + it('BaseConversionTest_toHex16_01', () => { + expect(toHex16(8)).toEqual('08'); + }); + + it('BaseConversionTest_toHex16_02', () => { + expect(toHex16(11)).toEqual('0b'); + }); + + it('BaseConversionTest_toHex32_01', () => { + expect(toHex32(33)).toEqual('0021'); + }); + + it('BaseConversionTest_toHex32_02', () => { + expect(toHex32(36)).toEqual('0024'); + }); + + it('BaseConversionTest_toHex64_01', () => { + expect(toHex64('36')).toEqual('00000036'); + }); + + it('BaseConversionTest_toHex64_02', () => { + expect(toHex64(36)).toEqual('00000024'); + }); + + it('BaseConversionTest_uint8ArrayToString_01', () => { + expect(uint8ArrayToString([21, 31], false)).toEqual('2131'); + }); + + it('BaseConversionTest_uint8ArrayToString_02', () => { + expect(uint8ArrayToString([21, 31], true)).toEqual('151f'); + }); +}); diff --git a/ide/test/hdc/common/ObjectToMemory.test.ts b/ide/test/hdc/common/ObjectToMemory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..750e85cb0769da5adffa431aabfd3d2ae9949121 --- /dev/null +++ b/ide/test/hdc/common/ObjectToMemory.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { objectToMemorySize } from '../../../dist/hdc/common/ObjectToMemorySize.js'; +describe('ObjectToMemoryTest', () => { + let obj = new objectToMemorySize(); + it('ObjectToMemoryTest_objectToSize_01', () => { + expect(obj.objectToSize(12)).toEqual(8); + }); + + it('ObjectToMemoryTest_objectToSize_02', () => { + expect(obj.objectToSize(true)).toEqual(4); + }); + + it('ObjectToMemoryTest_objectToSize_03', () => { + expect(obj.objectToSize('abc')).toEqual(6); + }); + + it('ObjectToMemoryTest_objectToSize_04', () => { + expect(obj.objectToSize([1, 2])).toEqual(16); + }); + + it('ObjectToMemoryTest_objectToSize_05', () => { + expect(obj.objectToSize({ name: 'demo', age: 12 })).toEqual(30); + }); + + it('ObjectToMemoryTest_sizeOfObj_01', () => { + expect(obj.sizeOfObj(null)).toEqual(0); + }); + + it('ObjectToMemoryTest_sizeOfObj_02', () => { + expect(obj.sizeOfObj(12)).toEqual(0); + }); + + it('ObjectToMemoryTest_sizeOfObj_03', () => { + expect(obj.sizeOfObj(false)).toEqual(0); + }); + + it('ObjectToMemoryTest_sizeOfObj_04', () => { + expect(obj.sizeOfObj(false)).toEqual(0); + }); + + it('ObjectToMemoryTest_sizeOfObj_05', () => { + expect(obj.sizeOfObj([1, 2])).toEqual(20); + }); + + it('ObjectToMemoryTest_sizeOfObj_06', () => { + expect(obj.sizeOfObj({ name: 'demo', age: 12 })).toEqual(30); + }); + + it('ObjectToMemoryTest_objectToSize_07', () => { + expect(obj.objectToSize(undefined)).toEqual(0); + }); + + it('ObjectToMemoryTest_sizeOfObj_08', () => { + let object = { + [1]: 2, + [3]: 4, + [5]: 6, + [7]: 8, + }; + expect(obj.sizeOfObj(object)).toEqual(40); + }); +}); diff --git a/ide/test/hdc/common/Serialize.test.ts b/ide/test/hdc/common/Serialize.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..862352a0c2cbb8b753399bbb41ff5f5db688606d --- /dev/null +++ b/ide/test/hdc/common/Serialize.test.ts @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { Serialize } from '../../../dist/hdc/common/Serialize.js'; + +describe('Serialize Test', () => { + it('Serialize Test01', function () { + let banne = { + banner: 1, + authType: 1, + sessionId: 1, + connectKey: 1, + buf: '', + }; + expect(Serialize.serializeSessionHandShake(banne)).not.toBeUndefined(); + }); + it('Serialize Test02', function () { + let payloadProtect = { + channelId: 1, + commandFlag: 1, + checkSum: 1, + vCode: 1, + }; + expect(Serialize.serializePayloadProtect(payloadProtect)).not.toBeUndefined(); + }); + it('Serialize Test03', function () { + let transferConfig = { + fileSize: 1, + atime: 1, + mtime: 1, + options: 1, + path: 1, + optionalName: 1, + updateIfNew: 1, + compressType: 1, + holdTimestamp: 1, + functionName: 1, + clientCwd: 1, + reserve1: 1, + reserve2: 1, + }; + expect(Serialize.serializeTransferConfig(transferConfig)).not.toBeUndefined(); + }); + it('Serialize Test04', function () { + let transferPayload = { + index: 1, + compressType: 1, + compressSize: 1, + uncompressSize: 1, + }; + expect(Serialize.serializeTransferPayload(transferPayload)).not.toBeUndefined(); + }); + it('Serialize Test06', function () { + let data = { + buffer: 1, + }; + // @ts-ignore + let uint8Array = new Uint8Array(data); + let dataBuffer = uint8Array.buffer; + expect(Serialize.parseTransferConfig(data)).not.toBeUndefined(); + }); + it('Serialize Test05', function () { + let tagKey = 1; + expect(Serialize.readTagWireType(tagKey)).not.toBeUndefined(); + }); + it('Serialize Test07', function () { + let data = { + buffer: 1, + }; + // @ts-ignore + let uint8Array = new Uint8Array(data); + let dataBuffer = uint8Array.buffer; + expect(Serialize.parsePayloadProtect(data)).not.toBeUndefined(); + }); + + it('Serialize Test08', function () { + expect(Serialize.writeVarIntU64(100_000_000)).not.toBeUndefined(); + }); + + it('Serialize Test09', function () { + let data = { + buffer: 1, + }; + // @ts-ignore + let uint8Array = new Uint8Array(data); + expect(Serialize.parseString(uint8Array, 1)).not.toBeUndefined(); + }); + + it('Serialize Test10', function () { + let data = { + buffer: 1, + }; + // @ts-ignore + let uint8Array = new Uint8Array(data); + expect(Serialize.parseHandshake(uint8Array)).toEqual({ + _authType: -1, + _banner: '', + _buf: '', + _connectKey: '', + _sessionId: -1, + _version: '', + }); + }); + + it('Serialize Test11', function () { + expect(Serialize.writeVarIntU32(100_000_000)).not.toBeUndefined(); + }); +}); diff --git a/ide/test/hdc/common/Utils.test.ts b/ide/test/hdc/common/Utils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a94018fccc7d55ca315d9a5088fe6671589d63ee --- /dev/null +++ b/ide/test/hdc/common/Utils.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { Utils } from '../../../dist/hdc/common/Utils.js'; + +describe('UtilsTest', () => { + it('UtilsTest_getLocalId_01', () => { + expect(Utils.getLocalId()).toBeTruthy(); + }); + + it('UtilsTest_getLocalId_02', () => { + Utils.localId = 4294967295; + expect(Utils.getLocalId()).toBe(1); + }); + + it('UtilsTest_getSessionId_01', () => { + expect(Utils.getSessionId()).toBeTruthy(); + }); + + it('UtilsTest_formatCommand_01', () => { + expect( + Utils.formatCommand( + 'hdc_std shell killall hiprofilerd hiprofiler_plugins native_daemon hiperf' + ' hiprofiler_cmd' + ) + ).toEqual({ + bJumpDo: false, + cmdFlag: 1001, + parameters: 'killall hiprofilerd hiprofiler_plugins native_daemon hiperf hiprofiler_cmd', + }); + }); + + it('UtilsTest_formatCommand_02', () => { + expect(Utils.formatCommand('abc')).toEqual({ + bJumpDo: true, + cmdFlag: -1, + parameters: '', + }); + }); + + it('UtilsTest_formatCommand_03', () => { + expect(Utils.formatCommand('hdc')).toEqual({ + bJumpDo: true, + cmdFlag: -1, + parameters: '', + }); + }); + + it('UtilsTest_numToHexString_01', () => { + expect(Utils.numToHexString(1)).toBe('0x1'); + }); + + it('UtilsTest_numToHexString_02', () => { + expect(Utils.numToHexString(-1)).toBe('0xffffffff'); + }); + + it('UtilsTest_numToHexString_03', () => { + expect(Utils.numToHexString(undefined)).toBe('0x0'); + }); +}); diff --git a/ide/test/hdc/hdcclient/AsyncQueue.test.ts b/ide/test/hdc/hdcclient/AsyncQueue.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c79185ca1d32a9f8c2e72e5c37e52b07a5b17c37 --- /dev/null +++ b/ide/test/hdc/hdcclient/AsyncQueue.test.ts @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { AsyncQueue, DataMessageQueue } from '../../../dist/hdc/hdcclient/AsyncQueue.js'; + +describe('AsyncQueueTest', () => { + let queue = new DataMessageQueue(); + let dataMessageQueue = new DataMessageQueue(); + let asqueue = new AsyncQueue(); + it('AsyncQueueTest_DataMessageQueue_01', () => { + expect(queue.push('abc')).toEqual(true); + }); + + it('AsyncQueueTest_DataMessageQueue_02', () => { + expect(queue.size()).toEqual(1); + }); + + it('AsyncQueueTest_DataMessageQueue_03', () => { + expect(queue.pop()).toEqual('abc'); + }); + + it('AsyncQueueTest_DataMessageQueue_04', () => { + expect(queue.push(null)).toEqual(false); + }); + + it('AsyncQueueTest_AsyncQueue_01', () => { + let dataMessageQueue = new DataMessageQueue(); + dataMessageQueue.push('aaa'); + asqueue.enqueue(dataMessageQueue); + expect(asqueue.dequeue()).toBeTruthy(); + }); +}); diff --git a/ide/test/hdc/hdcclient/FormatCommand.test.ts b/ide/test/hdc/hdcclient/FormatCommand.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6502e38d0f6f62431bdcb582c62645699e92a1d5 --- /dev/null +++ b/ide/test/hdc/hdcclient/FormatCommand.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { FormatCommand } from '../../../dist/hdc/hdcclient/FormatCommand.js'; +// @ts-ignore +import { CmdConstant } from '../../../dist/command/CmdConstant.js'; + +describe('FormatCommandTest', () => { + it('FormatCommandTest_FormatCommand_01', () => { + expect(FormatCommand.string2FormatCommand(CmdConstant.CMD_TRACE_FILE_SIZE)).toEqual({ + bJumpDo: true, + cmdFlag: -1, + parameters: '', + }); + }); + + it('FormatCommandTest_FormatCommand_02', () => { + expect(FormatCommand.string2FormatCommand('shell ps')).toEqual({ + bJumpDo: false, + cmdFlag: 1001, + parameters: 'ps', + }); + }); + + it('FormatCommandTest_FormatCommand_03', () => { + expect(FormatCommand.string2FormatCommand('shell')).toEqual({ + bJumpDo: false, + cmdFlag: 2000, + parameters: '', + }); + }); + + it('FormatCommandTest_FormatCommand_04', () => { + expect(FormatCommand.string2FormatCommand('file recv demo')).toEqual({ + bJumpDo: false, + cmdFlag: 3000, + parameters: 'demo', + }); + }); + + it('FormatCommandTest_FormatCommand_05', () => { + expect(FormatCommand.string2FormatCommand('file send demo')).toEqual({ + bJumpDo: false, + cmdFlag: 3000, + parameters: 'demo', + }); + }); + + it('FormatCommandTest_FormatCommand_06', () => { + expect(FormatCommand.string2FormatCommand(CmdConstant.CMD_GET_HIPERF_EVENTS)).toEqual({ + bJumpDo: true, + cmdFlag: -1, + parameters: '', + }); + }); + + it('FormatCommandTest_FormatCommand_07', () => { + expect(FormatCommand.string2FormatCommand('null')).toEqual({ + bJumpDo: true, + cmdFlag: -1, + parameters: '', + }); + }); +}); diff --git a/ide/test/hdc/hdcclient/HdcClient.test.ts b/ide/test/hdc/hdcclient/HdcClient.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f35a7236804b1ca2e5ef7acbc0c12b7b3008d25 --- /dev/null +++ b/ide/test/hdc/hdcclient/HdcClient.test.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { HdcClient } from '../../../dist/hdc/hdcclient/HdcClient.js'; + +describe('HdcClient Test', () => { + it('HdcClientTest01', function () { + let hdcClient = new HdcClient(); + expect(hdcClient.constructor()).toBeUndefined(); + }); + it('HdcClientTest02', function () { + let hdcClient = new HdcClient(); + expect(hdcClient.bindStream()).toBeUndefined(); + }); + it('HdcClientTest03', function () { + let hdcClient = new HdcClient(); + expect(hdcClient.bindStopStream()).toBeUndefined(); + }); + it('HdcClientTest04', function () { + let hdcClient = new HdcClient(); + expect(hdcClient.unbindStream()).toBeTruthy(); + }); + it('HdcClientTest05', function () { + let hdcClient = new HdcClient(); + expect(hdcClient.unbindStopStream()).toBeTruthy(); + }); + + it('HdcClientTest06', async () => { + let hdcClient = new HdcClient(); + await expect(hdcClient.connectDevice()).rejects.not.toBeUndefined(); + }); + + it('HdcClientTest07', async () => { + let hdcClient = new HdcClient(); + await expect(hdcClient.disconnect()).not; + }); + it('HdcClientTest08', function () { + let hdcClient = new HdcClient(); + let data = { + getChannelId: jest.fn(() => -1), + }; + expect(hdcClient.createDataMessage(data)).toBeUndefined(); + }); +}); diff --git a/ide/test/hdc/message/DataMessage.test.ts b/ide/test/hdc/message/DataMessage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..16cfbdbdf9603a05c8ec39f1e2afee0693a17173 --- /dev/null +++ b/ide/test/hdc/message/DataMessage.test.ts @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { DataMessage } from '../../../dist/hdc/message/DataMessage.js'; +import { TextEncoder } from 'util'; + +describe('DataMessage Test', () => { + let dataMessage = new DataMessage(); + dataMessage.body = true; + it('DataMessageTest01', function () { + expect(dataMessage).not.toBeUndefined(); + }); + + it('DataMessageTest02', function () { + expect(dataMessage.usbHead).toBeUndefined(); + }); + + it('DataMessageTest03', function () { + dataMessage.usbHead = true; + expect(dataMessage.usbHead).toBeTruthy(); + }); + + it('DataMessageTest04', function () { + expect(dataMessage.channelId).toBe(-1); + }); + + it('DataMessageTest05', function () { + dataMessage.channelId = true; + expect(dataMessage.channelId).toBeTruthy(); + }); + + it('DataMessageTest06', function () { + expect(dataMessage.result).toBe(''); + }); + + it('DataMessageTest07', function () { + dataMessage.result = true; + expect(dataMessage.result).toBeTruthy(); + }); + + it('DataMessageTest08', function () { + expect(dataMessage.channelClose).toBeFalsy(); + }); + + it('DataMessageTest09', function () { + dataMessage.channelClose = true; + expect(dataMessage.channelClose).toBeTruthy(); + }); + + it('DataMessageTest10', function () { + expect(dataMessage.commandFlag).toBe(-1); + }); + + it('DataMessageTest11', function () { + dataMessage.commandFlag = true; + expect(dataMessage.commandFlag).toBeTruthy(); + }); + + it('DataMessageTest12', function () { + expect(dataMessage.resArrayBuffer).toBeUndefined(); + }); + + it('DataMessageTest13', function () { + dataMessage.resArrayBuffer = true; + expect(dataMessage.resArrayBuffer).toBeTruthy(); + }); + + it('DataMessageTest14', function () { + expect(dataMessage.toString()).not.toBeUndefined(); + }); + + it('DataMessageTest15', function () { + expect(dataMessage.getChannelId()).not.toBeUndefined(); + }); + + it('DataMessageTest16', function () { + expect(dataMessage.getData()).not.toBeUndefined(); + }); + + it('DataMessageTest17', function () { + let end = new TextEncoder(); + + dataMessage.resArrayBuffer = end.encode('111'); + expect(dataMessage.getDataToString()).toBe('111'); + }); +}); diff --git a/ide/test/hdc/message/PayloadHead.test.ts b/ide/test/hdc/message/PayloadHead.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bbedec022297db376f262149900a52e335f3fe94 --- /dev/null +++ b/ide/test/hdc/message/PayloadHead.test.ts @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { PayloadHead } from '../../../dist/hdc/message/PayloadHead.js'; + +describe('PayloadHead Test', () => { + let payloadHead = new PayloadHead(); + it('PayloadHeadTest01', function () { + expect(payloadHead).not.toBeUndefined(); + }); + + it('PayloadHeadTest02', function () { + expect(payloadHead.flag).toBeUndefined(); + }); + + it('PayloadHeadTest03', function () { + payloadHead.flag = true; + expect(payloadHead.flag).toBeTruthy(); + }); + + it('PayloadHeadTest04', function () { + expect(payloadHead.reserve).toBeUndefined(); + }); + + it('PayloadHeadTest05', function () { + payloadHead.reserve = true; + expect(payloadHead.reserve).toBeTruthy(); + }); + + it('PayloadHeadTest06', function () { + expect(payloadHead.protocolVer).toBeUndefined(); + }); + + it('PayloadHeadTest07', function () { + payloadHead.protocolVer = true; + expect(payloadHead.protocolVer).toBeTruthy(); + }); + + it('PayloadHeadTest08', function () { + expect(payloadHead.headSize).toBeUndefined(); + }); + + it('PayloadHeadTest9', function () { + payloadHead.headSize = true; + expect(payloadHead.headSize).toBeTruthy(); + }); + + it('PayloadHeadTest10', function () { + expect(payloadHead.dataSize).toBeUndefined(); + }); + + it('PayloadHeadTest11', function () { + payloadHead.dataSize = true; + expect(payloadHead.dataSize).toBeTruthy(); + }); + + it('PayloadHeadTest12', function () { + expect(payloadHead.toString()).toBeTruthy(); + }); + + it('PayloadHeadTest13', function () { + expect(payloadHead.getPayloadHeadLength).toBe(undefined); + }); +}); diff --git a/ide/test/hdc/message/PayloadProtect.test.ts b/ide/test/hdc/message/PayloadProtect.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7150129bd7f64431fb165f420cff65778a64acf1 --- /dev/null +++ b/ide/test/hdc/message/PayloadProtect.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { PayloadProtect } from '../../../dist/hdc/message/PayloadProtect.js'; + +describe('PayloadProtect Test', () => { + let payloadProtect = new PayloadProtect(); + it('PayloadProtectTest01', function () { + expect(payloadProtect).not.toBeUndefined(); + }); + + it('PayloadProtectTest02', function () { + expect(payloadProtect.channelId).toBeUndefined(); + }); + + it('PayloadProtectTest03', function () { + payloadProtect.channelId = true; + expect(payloadProtect.channelId).toBeTruthy(); + }); + + it('PayloadProtectTest04', function () { + expect(payloadProtect.commandFlag).toBeUndefined(); + }); + + it('PayloadProtectTest05', function () { + payloadProtect.commandFlag = true; + expect(payloadProtect.commandFlag).toBeTruthy(); + }); + + it('PayloadProtectTest06', function () { + expect(payloadProtect.checkSum).toBeUndefined(); + }); + + it('PayloadProtectTest07', function () { + payloadProtect.checkSum = true; + expect(payloadProtect.checkSum).toBeTruthy(); + }); + + it('PayloadProtectTest08', function () { + expect(payloadProtect.vCode).toBeUndefined(); + }); + + it('PayloadProtectTest9', function () { + payloadProtect.vCode = true; + expect(payloadProtect.vCode).toBeTruthy(); + }); + + it('PayloadProtectTest10', function () { + expect(payloadProtect.toString()).toBeTruthy(); + }); +}); diff --git a/ide/test/hdc/message/SessionHandShake.test.ts b/ide/test/hdc/message/SessionHandShake.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..463d0d5d93059d554b680f5158a9906e5bdd73f5 --- /dev/null +++ b/ide/test/hdc/message/SessionHandShake.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SessionHandShake } from '../../../dist/hdc/message/SessionHandShake.js'; + +describe('SessionHandShake Test', () => { + let sessionHandShake = new SessionHandShake(); + it('SessionHandShakeTest01', function () { + expect(sessionHandShake).not.toBeUndefined(); + }); + + it('SessionHandShakeTest02', function () { + expect(sessionHandShake.banner).toBeUndefined(); + }); + + it('SessionHandShakeTest03', function () { + sessionHandShake.banner = true; + expect(sessionHandShake.banner).toBeTruthy(); + }); + + it('SessionHandShakeTest04', function () { + expect(sessionHandShake.authType).toBeUndefined(); + }); + + it('SessionHandShakeTest05', function () { + sessionHandShake.authType = true; + expect(sessionHandShake.authType).toBeTruthy(); + }); + + it('SessionHandShakeTest06', function () { + expect(sessionHandShake.sessionId).toBeUndefined(); + }); + + it('SessionHandShakeTest07', function () { + sessionHandShake.sessionId = true; + expect(sessionHandShake.sessionId).toBeTruthy(); + }); + + it('SessionHandShakeTest08', function () { + expect(sessionHandShake.connectKey).toBeUndefined(); + }); + + it('SessionHandShakeTest9', function () { + sessionHandShake.connectKey = true; + expect(sessionHandShake.connectKey).toBeTruthy(); + }); + + it('SessionHandShakeTest10', function () { + expect(sessionHandShake.buf).toBeUndefined(); + }); + + it('SessionHandShakeTest11', function () { + sessionHandShake.buf = true; + expect(sessionHandShake.buf).toBeTruthy(); + }); + + it('SessionHandShakeTest12', function () { + expect(sessionHandShake.version).toBe(''); + }); + + it('SessionHandShakeTest13', function () { + sessionHandShake.version = true; + expect(sessionHandShake.version).toBeTruthy(); + }); + + it('SessionHandShakeTest14', function () { + expect(sessionHandShake.toString()).toBeTruthy(); + }); +}); diff --git a/ide/test/hdc/message/TransferConfig.test.ts b/ide/test/hdc/message/TransferConfig.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..30f3f8e3cb4718fc39d8d660b26cccb4f535e2bb --- /dev/null +++ b/ide/test/hdc/message/TransferConfig.test.ts @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TransferConfig } from '../../../dist/hdc/message/TransferConfig.js'; + +describe('TransferConfig Test', () => { + let transferConfig = new TransferConfig(); + it('TransferConfigTest01', function () { + expect(transferConfig).not.toBeUndefined(); + }); + + it('TransferConfigTest02', function () { + expect(transferConfig.fileSize).toBeUndefined(); + }); + + it('TransferConfigTest03', function () { + transferConfig.fileSize = true; + expect(transferConfig.fileSize).toBeTruthy(); + }); + + it('TransferConfigTest04', function () { + expect(transferConfig.atime).toBeUndefined(); + }); + + it('TransferConfigTest05', function () { + transferConfig.atime = true; + expect(transferConfig.atime).toBeTruthy(); + }); + + it('TransferConfigTest06', function () { + expect(transferConfig.mtime).toBeUndefined(); + }); + + it('TransferConfigTest07', function () { + transferConfig.mtime = true; + expect(transferConfig.mtime).toBeTruthy(); + }); + + it('TransferConfigTest08', function () { + expect(transferConfig.options).toBeFalsy(); + }); + + it('TransferConfigTest09', function () { + transferConfig.options = true; + expect(transferConfig.options).toBeTruthy(); + }); + + it('TransferConfigTest10', function () { + expect(transferConfig.path).toBeUndefined(); + }); + + it('TransferConfigTest11', function () { + transferConfig.path = true; + expect(transferConfig.path).toBeTruthy(); + }); + + it('TransferConfigTest12', function () { + expect(transferConfig.optionalName).toBeUndefined(); + }); + + it('TransferConfigTest13', function () { + transferConfig.optionalName = true; + expect(transferConfig.optionalName).toBeTruthy(); + }); + + it('TransferConfigTest14', function () { + expect(transferConfig.updateIfNew).toBeUndefined(); + }); + + it('TransferConfigTest15', function () { + transferConfig.updateIfNew = true; + expect(transferConfig.updateIfNew).toBeTruthy(); + }); + + it('TransferConfigTest16', function () { + expect(transferConfig.compressType).toBeUndefined(); + }); + + it('TransferConfigTest17', function () { + transferConfig.compressType = true; + expect(transferConfig.compressType).toBeTruthy(); + }); + + it('TransferConfigTest18', function () { + expect(transferConfig.holdTimestamp).toBeUndefined(); + }); + + it('TransferConfigTest19', function () { + transferConfig.holdTimestamp = true; + expect(transferConfig.holdTimestamp).toBeTruthy(); + }); + + it('TransferConfigTest20', function () { + expect(transferConfig.functionName).toBeUndefined(); + }); + + it('TransferConfigTest21', function () { + transferConfig.functionName = true; + expect(transferConfig.functionName).toBeTruthy(); + }); + + it('TransferConfigTest22', function () { + expect(transferConfig.clientCwd).toBeUndefined(); + }); + + it('TransferConfigTest23', function () { + transferConfig.clientCwd = true; + expect(transferConfig.clientCwd).toBeTruthy(); + }); + + it('TransferConfigTest24', function () { + expect(transferConfig.reserve1).toBeUndefined(); + }); + + it('TransferConfigTest25', function () { + transferConfig.reserve1 = true; + expect(transferConfig.reserve1).toBeTruthy(); + }); + + it('TransferConfigTest26', function () { + expect(transferConfig.reserve2).toBeUndefined(); + }); + + it('TransferConfigTest27', function () { + transferConfig.reserve2 = true; + expect(transferConfig.reserve2).toBeTruthy(); + }); + + it('TransferConfigTest28', function () { + expect(transferConfig.toString()).not.toBeUndefined(); + }); +}); diff --git a/ide/test/hdc/message/TransferPayload.test.ts b/ide/test/hdc/message/TransferPayload.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..300ec0e1e9008bdcd51f6d221d3a3c50ead77514 --- /dev/null +++ b/ide/test/hdc/message/TransferPayload.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TransferPayload } from '../../../dist/hdc/message/TransferPayload.js'; + +describe('TransferPayload Test', () => { + let transferPayload = new TransferPayload(); + it('TransferPayloadTest01', function () { + expect(transferPayload).not.toBeUndefined(); + }); + + it('TransferPayloadTest02', function () { + expect(transferPayload.index).toBeUndefined(); + }); + + it('TransferPayloadTest03', function () { + transferPayload.index = true; + expect(transferPayload.index).toBeTruthy(); + }); + + it('TransferPayloadTest04', function () { + expect(transferPayload.compressType).toBeUndefined(); + }); + + it('TransferPayloadTest05', function () { + transferPayload.compressType = true; + expect(transferPayload.compressType).toBeTruthy(); + }); + + it('TransferPayloadTest06', function () { + expect(transferPayload.compressSize).toBeUndefined(); + }); + + it('TransferPayloadTest07', function () { + transferPayload.compressSize = true; + expect(transferPayload.compressSize).toBeTruthy(); + }); + + it('TransferPayloadTest08', function () { + expect(transferPayload.uncompressSize).toBeFalsy(); + }); + + it('TransferPayloadTest09', function () { + transferPayload.uncompressSize = true; + expect(transferPayload.uncompressSize).toBeTruthy(); + }); + + it('TransferPayloadTest10', function () { + expect(transferPayload.toString()).not.toBeUndefined(); + }); +}); diff --git a/ide/test/hdc/message/USBHead.test.ts b/ide/test/hdc/message/USBHead.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..46feadf0ccf64d389fc9dc0ca0b14fb1a89c8c10 --- /dev/null +++ b/ide/test/hdc/message/USBHead.test.ts @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { USBHead } from '../../../dist/hdc/message/USBHead.js'; + +describe('USBHead Test', () => { + let usbHead = new USBHead(); + it('USBHeadTest01', function () { + expect(usbHead).not.toBeUndefined(); + }); + + it('USBHeadTest02', function () { + expect(usbHead.flag).toBeUndefined(); + }); + + it('USBHeadTest03', function () { + usbHead.flag = true; + expect(usbHead.flag).toBeTruthy(); + }); + + it('USBHeadTest04', function () { + expect(usbHead.option).toBeUndefined(); + }); + + it('USBHeadTest05', function () { + usbHead.option = true; + expect(usbHead.option).toBeTruthy(); + }); + + it('USBHeadTest06', function () { + expect(usbHead.sessionId).toBeUndefined(); + }); + + it('USBHeadTest07', function () { + usbHead.sessionId = true; + expect(usbHead.sessionId).toBeTruthy(); + }); + + it('USBHeadTest08', function () { + expect(usbHead.dataSize).toBeFalsy(); + }); + + it('USBHeadTest09', function () { + usbHead.dataSize = true; + expect(usbHead.dataSize).toBeTruthy(); + }); + + it('USBHeadTest10', function () { + expect(usbHead.toString()).not.toBeUndefined(); + }); + + it('USBHeadTest11', function () { + usbHead.parseHeadData = jest.fn(() => undefined); + expect(usbHead.parseHeadData()).toBeUndefined(); + }); +}); diff --git a/ide/test/hdc/transmission/DataProcessing.test.ts b/ide/test/hdc/transmission/DataProcessing.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3270f223ddce762288761ca6801b8bf7d8ac2548 --- /dev/null +++ b/ide/test/hdc/transmission/DataProcessing.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { DataProcessing } from '../../../dist/hdc/transmission/DataProcessing.js'; + +describe('DataProcessing Test', () => { + it('DataProcessingTest01', () => { + let dataProcessing = new DataProcessing(); + expect(dataProcessing).not.toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/hdc/transmission/UsbTransmissionChannel.test.ts b/ide/test/hdc/transmission/UsbTransmissionChannel.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd1b50d3a58d1d13e179b8ff7ecfc6c3651701b6 --- /dev/null +++ b/ide/test/hdc/transmission/UsbTransmissionChannel.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { UsbTransmissionChannel } from '../../../dist/hdc/transmission/UsbTransmissionChannel.js'; + +describe('UsbTransmissionChannel Test', () => { + it('UsbTransmissionChannelTest01', () => { + let usbTransmissionChannel = new UsbTransmissionChannel(); + expect(usbTransmissionChannel).not.toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/js-heap/HeapDataInterface.test.ts b/ide/test/js-heap/HeapDataInterface.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..15318b46b6c7d35844c67c1f2b43442471f781fc --- /dev/null +++ b/ide/test/js-heap/HeapDataInterface.test.ts @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { HeapDataInterface } from '../../dist/js-heap/HeapDataInterface.js'; +//@ts-ignore +import { HeapNode } from '../../dist/js-heap/model/DatabaseStruct.js'; + +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +jest.mock('../../dist/js-heap/utils/Utils.js', () => { + return { + HeapNodeToConstructorItem: (node: HeapNode) => {}, + }; +}); + +describe('HeapDataInterface Test', () => { + let data = { + end_ts: 88473497504466, + id: 0, + isParseSuccess: true, + name: 'Test', + path: '', + pid: 4243, + tart_ts: 88473061693464, + type: 0, + heapLoader: { + rootNode: { + detachedness: 0, + displayName: '', + distance: 100000000, + edgeCount: 3575, + fileId: 0, + firstEdgeIndex: 0, + flag: 0, + id: 1, + name: 'Test', + nodeIndex: 0, + nodeOldIndex: 0, + retainedSize: 1898167, + retainsCount: 0, + retainsEdgeIdx: [0], + retainsNodeIdx: [0], + selfSize: 0, + traceNodeId: 0, + type: 9, + edges: [ + { + edgeIndex: 0, + edgeOldIndex: 0, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 152376, + retainEdge: [], + retainsNode: [], + toNodeId: 43537, + type: 5, + }, + { + edgeIndex: 1, + edgeOldIndex: 3, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 155414, + retainEdge: [], + retainsNode: [], + toNodeId: 44405, + type: 5, + }, + ], + }, + }, + snapshotStruct: { + traceNodes: [], + nodeMap: new Map(), + nodeCount: 1, + edges: [ + { + edgeIndex: 0, + edgeOldIndex: 0, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 152376, + retainEdge: [], + retainsNode: [], + toNodeId: 43537, + type: 5, + }, + { + edgeIndex: 1, + edgeOldIndex: 3, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 155414, + retainEdge: [], + retainsNode: [], + toNodeId: 44405, + type: 5, + }, + ], + samples: [], + }, + }; + it('HeapDataInterface01', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getClassesListForSummary(1, 0, 0).length).toBe(0); + }); + it('HeapDataInterface02', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.setFileId(1)).toBeFalsy(); + }); + it('HeapDataInterface03', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.setPraseListener({})).toBeFalsy(); + }); + it('HeapDataInterface04', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getClassesListForSummary(1, 1, 1)).not.toBeUndefined(); + }); + it('HeapDataInterface05', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getClassListForComparison(1, 2)).toEqual([]); + }); + it('HeapDataInterface06', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getParentFunction({})).toBeUndefined(); + }); + it('HeapDataInterface07', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getNextForConstructor({})).not.toBeUndefined(); + }); + it('HeapDataInterface08', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getNextForComparison({})).not.toBeUndefined(); + }); + it('HeapDataInterface09', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getRetains({})).not.toBeUndefined(); + }); + it('HeapDataInterface10', async () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(await heapDataInterface.parseData([])).toBeUndefined(); + }); + it('HeapDataInterface11', () => { + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + expect(heapDataInterface.getFileStructs().length).toBe(1); + }); +}); diff --git a/ide/test/js-heap/LoadDataBase.test.ts b/ide/test/js-heap/LoadDataBase.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6454a5e50686442cf5d4bbba3bf7891ef92d8607 --- /dev/null +++ b/ide/test/js-heap/LoadDataBase.test.ts @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { HeapNode } from '../../dist/js-heap/model/DatabaseStruct.js'; +//@ts-ignore +import { LoadDatabase } from '../../dist/js-heap/LoadDatabase.js'; +//@ts-ignore +import { ParseListener } from '../../dist/js-heap/HeapDataInterface.js'; +//@ts-ignore +import { FileInfo } from '../../dist/js-heap/model/UiStruct.js'; +import { HeapDataInterface } from '../../src/js-heap/HeapDataInterface'; + +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +jest.mock('../../dist/js-heap/utils/Utils.js', () => { + return { + HeapNodeToConstructorItem: (node: HeapNode) => {}, + getTimeForLog: (node: any) => {}, + }; +}); + +jest.mock('../../dist/js-heap/HeapDataInterface.js', () => { + return { + ParseListener: { + parseDone: (fileModule: Array) => {}, + process: (info: string, process: number) => {}, + }, + HeapDataInterface: { + getInstance: (fileModule: any) => { + return { + setPraseListener: (prase: any) => {}, + parseData: (prase: any) => {}, + }; + }, + }, + }; +}); + +const sqlite = require('../../dist/trace/database/SqlLite.js'); +jest.mock('../../dist/trace/database/SqlLite.js'); + +describe('LoadDataBase Test', () => { + let heapFileData = { + id: '', + file_name: '', + start_time: '', + end_time: '', + fpid: '', + }; + let queryHeapFileMock = sqlite.queryHeapFile; + queryHeapFileMock.mockResolvedValue([heapFileData]); + + let heapInfoData = [ + { + key: 'node_count', + int_value: '', + }, + { + key: 'edge_count', + int_value: '', + }, + { + key: 'trace_function_count', + int_value: '', + }, + { + key: 'types', + int_value: '', + }, + ]; + let queryHeapInfoMock = sqlite.queryHeapInfo; + queryHeapInfoMock.mockResolvedValue(heapInfoData); + + let HeapNodeData = [ + { + node_index: '2', + type: '', + name: 'name1', + id: '', + self_size: '', + edge_count: '', + trace_node_id: '', + detachedness: '', + }, + { + node_index: '1', + type: '', + name: 'name2', + id: '', + self_size: '', + edge_count: '', + trace_node_id: '', + detachedness: '', + }, + ]; + let queryHeapNodeMock = sqlite.queryHeapNode; + queryHeapNodeMock.mockResolvedValue(HeapNodeData); + + let heapEdgeData = [ + { + edge_index: '', + type: '', + name_or_index: '0', + to_node: '', + from_node_id: '', + to_node_id: '', + }, + { + edge_index: '', + type: '', + name_or_index: '0', + to_node: '', + from_node_id: '', + to_node_id: '', + }, + ]; + let queryHeapEdgeMock = sqlite.queryHeapEdge; + queryHeapEdgeMock.mockResolvedValue(heapEdgeData); + + let heapFunctionData = [ + { + function_index: '', + name: '', + script_name: '0', + script_id: '', + function_id: '', + line: '', + column: '', + }, + { + function_index: '', + name: '', + script_name: '0', + script_id: '', + function_id: '', + line: '', + column: '', + }, + ]; + let queryHeapFunctionMock = sqlite.queryHeapFunction; + queryHeapFunctionMock.mockResolvedValue(heapFunctionData); + + let heapTraceNodeData = [ + { + id: '', + name: '', + script_name: '0', + script_id: '', + size: '', + line: '', + column: '', + live_count: '', + live_size: '', + }, + { + id: '', + name: '', + script_name: '0', + script_id: '', + size: '', + line: '', + column: '', + live_count: '', + live_size: '', + }, + ]; + let queryHeapTraceNodeMock = sqlite.queryHeapTraceNode; + queryHeapTraceNodeMock.mockResolvedValue(heapTraceNodeData); + + let heapSampleData = [ + { + timestamp_us: '', + last_assigned_id: '', + }, + { + timestamp_us: '', + last_assigned_id: '', + }, + ]; + let queryHeapSampleMock = sqlite.queryHeapSample; + queryHeapSampleMock.mockResolvedValue(heapSampleData); + + let heapLocationData = [ + { + object_index: '', + script_id: '', + line: '', + column: '', + }, + { + object_index: '', + script_id: '', + line: '', + column: '', + }, + ]; + let queryHeapLocationMock = sqlite.queryHeapLocation; + queryHeapLocationMock.mockResolvedValue(heapLocationData); + + let heapStringData = [ + { + string: '', + }, + { + string: '', + }, + ]; + let queryHeapStringMock = sqlite.queryHeapString; + queryHeapStringMock.mockResolvedValue(heapStringData); + + it('LoadDataBase01', async () => { + let instance = LoadDatabase.getInstance(); + let ss: ParseListener = { + process: (info: string, process: number) => {}, + parseDone: (fileModule: Array) => {}, + }; + await instance.loadFile(ss); + }); +}); diff --git a/ide/test/js-heap/logic/Allocation.test.ts b/ide/test/js-heap/logic/Allocation.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..478a62351f12aa2a103e88e239243c5874bebb92 --- /dev/null +++ b/ide/test/js-heap/logic/Allocation.test.ts @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { AllocationLogic } from '../../../dist/js-heap/logic/Allocation.js'; +//@ts-ignore +import { AllocationFunction } from '../../../dist/js-heap/model/UiStruct.js'; + +jest.mock('../../../dist/js-heap/model/UiStruct.js', () => { + return { + AllocationFunction: { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: new Set([]), + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + clone: () => { + return { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: new Set([]), + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + }; + }, + }, + clone: () => { + return { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: new Set([]), + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + }; + }, + }; +}); + +describe('Allocation Test', () => { + let set: Set = new Set([]); + let data = { + end_ts: 88473497504466, + id: 0, + isParseSuccess: true, + name: 'Test', + path: '', + pid: 4243, + tart_ts: 88473061693464, + type: 0, + heapLoader: { + rootNode: { + detachedness: 0, + displayName: '', + distance: 100000000, + edgeCount: 3575, + fileId: 0, + firstEdgeIndex: 0, + flag: 0, + id: 1, + name: 'Test', + nodeIndex: 0, + nodeOldIndex: 0, + retainedSize: 1898167, + retainsCount: 0, + retainsEdgeIdx: [0], + retainsNodeIdx: [0], + selfSize: 0, + traceNodeId: 0, + type: 9, + edges: [ + { + edgeIndex: 0, + edgeOldIndex: 0, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 152376, + retainEdge: [], + retainsNode: [], + toNodeId: 43537, + type: 5, + }, + { + edgeIndex: 1, + edgeOldIndex: 3, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 155414, + retainEdge: [], + retainsNode: [], + toNodeId: 44405, + type: 5, + }, + ], + }, + }, + snapshotStruct: { + traceNodes: [ + { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + clone: () => { + return { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + }; + }, + }, + { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + clone: () => { + return { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + }; + }, + }, + { + fileId: 0, + functionIndex: 22, + parentsId: [1, 2, 3], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + clone: () => { + return { + fileId: 0, + functionIndex: 0, + parentsId: [1, 2, 3], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + }; + }, + }, + ], + nodeMap: new Map(), + nodeCount: 1, + edges: [ + { + edgeIndex: 0, + edgeOldIndex: 0, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 152376, + retainEdge: [], + retainsNode: [], + toNodeId: 43537, + type: 5, + }, + { + edgeIndex: 1, + edgeOldIndex: 3, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 155414, + retainEdge: [], + retainsNode: [], + toNodeId: 44405, + type: 5, + }, + ], + samples: [], + functionInfos: [1], + }, + }; + it('AllocationTest01', () => { + let allocationLogic = new AllocationLogic(data); + let nodeById = allocationLogic.getNodeById(12); + expect(nodeById).not.toBe(null); + }); + + it('AllocationTest02', () => { + let allocationLogic = new AllocationLogic(data); + let nodeById = allocationLogic.getNodeById(11); + expect(nodeById).toBe(null); + }); + it('AllocationTest03', () => { + let allocationLogic = new AllocationLogic(data); + let nodeStack = allocationLogic.getNodeStack(12); + expect(nodeStack.length).toBe(1); + }); + it('AllocationTest04', () => { + let allocationLogic = new AllocationLogic(data); + let nodeStack = allocationLogic.getFunctionNodeIds(12); + expect(nodeStack).not.toBe([]); + }); + it('AllocationTest05', () => { + let allocationLogic = new AllocationLogic(data); + let parentData = data.snapshotStruct.traceNodes[0]; + let nodeStack = allocationLogic.getParent(parentData); + expect(nodeStack).toBeUndefined(); + }); + it('AllocationTest06', () => { + let allocationLogic = new AllocationLogic(data); + let parentData = { + fileId: 0, + functionIndex: 0, + parentsId: [1], + parents: [], + combineId: set, + status: true, + id: '12', + name: 'name1', + scriptName: 'scriptName1', + scriptId: 1, + line: 1, + column: 1, + count: 1, + size: 1, + liveCount: 1, + liveSize: 1, + hasParent: true, + }; + let nodeStack = allocationLogic.getParent(parentData); + expect(nodeStack).toBeUndefined(); + }); + + it('AllocationTest07', () => { + let allocationLogic = new AllocationLogic(data); + let nodeStack = allocationLogic.getFunctionList(); + expect(nodeStack.length).not.toEqual(0); + }); + + it('AllocationTest08', () => { + let allocationLogic = new AllocationLogic(data); + let parentData = data.snapshotStruct.traceNodes[0]; + let nodeStack = allocationLogic.getFunctionStack(parentData, []); + expect(nodeStack).toBeUndefined(); + }); +}); diff --git a/ide/test/js-heap/logic/HeapLoader.test.ts b/ide/test/js-heap/logic/HeapLoader.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..896255a893b8099d1dccc15cc65fafe2c970a0a2 --- /dev/null +++ b/ide/test/js-heap/logic/HeapLoader.test.ts @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { HeapLoader } from '../../../dist/js-heap/logic/HeapLoader.js'; +//@ts-ignore +import { ConstructorItem, FileType } from '../../../dist/js-heap/model/UiStruct.js'; +import { HeapNode } from '../../../src/js-heap/model/DatabaseStruct'; + +jest.mock('../../../dist/js-heap/utils/Utils.js', () => { + return { + HeapNodeToConstructorItem: (node: HeapNode) => { + return {}; + }, + }; +}); + +describe('HeapLoader Test', () => { + let rootNode = { + detachedness: 0, + displayName: '', + distance: 100000000, + edgeCount: 3575, + fileId: 0, + firstEdgeIndex: 0, + flag: 0, + id: 1, + name: 'Test', + nodeIndex: 0, + nodeOldIndex: 0, + retainedSize: 1898167, + retainsCount: 0, + retainsEdgeIdx: [0], + retainsNodeIdx: [0], + selfSize: 0, + traceNodeId: 0, + type: 9, + edges: [ + { + edgeIndex: 0, + edgeOldIndex: 0, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 152376, + retainEdge: [], + retainsNode: [], + toNodeId: 43537, + type: 5, + }, + { + edgeIndex: 1, + edgeOldIndex: 3, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 155414, + retainEdge: [], + retainsNode: [], + toNodeId: 44405, + type: 5, + }, + ], + }; + let data = { + end_ts: 88473497504466, + id: 0, + isParseSuccess: true, + name: 'Test', + path: '', + pid: 4243, + tart_ts: 88473061693464, + type: 0, + heapLoader: { + rootNode: rootNode, + }, + snapshotStruct: { + traceNodes: [], + nodeMap: new Map(), + nodeCount: 1, + edges: [ + { + edgeIndex: 0, + edgeOldIndex: 0, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 152376, + retainEdge: [], + retainsNode: [], + toNodeId: 43537, + type: 5, + }, + { + edgeIndex: 1, + edgeOldIndex: 3, + fromNodeId: 1, + nameOrIndex: '-test-', + nodeId: 155414, + retainEdge: [], + retainsNode: [], + toNodeId: 44405, + type: 5, + }, + ], + samples: [], + }, + }; + + let item = { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 0, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }; + + it('HeapLoaderTest01', () => { + let heapLoader = new HeapLoader(data); + heapLoader.fileId = jest.fn(() => true); + expect(heapLoader).not.toBeUndefined(); + }); + it('HeapLoaderTest02', () => { + let heapLoader = new HeapLoader(data); + expect(heapLoader.loadAllocationParent({})).toBeUndefined(); + }); + + it('HeapLoaderTest03', () => { + let heapLoader = new HeapLoader(data); + heapLoader.rootNode = rootNode; + heapLoader.nodes = [rootNode]; + heapLoader.nodes[0].addEdge = jest.fn(() => true); + heapLoader.isEssentialEdge = jest.fn(() => false); + expect(heapLoader.preprocess()).toBeUndefined(); + }); + + it('HeapLoaderTest04', () => { + let heapLoader = new HeapLoader(data); + heapLoader.nodes = [rootNode]; + expect(heapLoader.getClassesForSummary().keys.length).toEqual(0); + }); + + it('HeapLoaderTest05', () => { + let heapLoader = new HeapLoader(data); + heapLoader.nodes = [rootNode]; + heapLoader.rootNode = rootNode; + expect(heapLoader.getRetains(item).length).toEqual(1); + }); +}); diff --git a/ide/test/js-heap/model/DatabaseStruct.test.ts b/ide/test/js-heap/model/DatabaseStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..782e81e6f9b525d2b208fe0aec8e567980f466b3 --- /dev/null +++ b/ide/test/js-heap/model/DatabaseStruct.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { HeapNode,HeapEdge,HeapTraceFunctionInfo,HeapSample,HeapLocation,HeapSnapshotStruct,FileStruct } from '../../../dist/js-heap/model/DatabaseStruct.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('DatabaseStruct Test', () => { + it('DatabaseStructTest01', () => { + let heapNode = new HeapNode(); + expect(heapNode).not.toBeUndefined(); + }); + it('DatabaseStructTest02', () => { + let heapEdge = new HeapEdge(); + expect(heapEdge).not.toBeUndefined(); + }); + it('DatabaseStructTest03', () => { + let heapTraceFunctionInfo = new HeapTraceFunctionInfo(); + expect(heapTraceFunctionInfo).not.toBeUndefined(); + }); + it('DatabaseStructTest04', () => { + let heapLocation = new HeapLocation(); + expect(heapLocation).not.toBeUndefined(); + }); + it('DatabaseStructTest05', () => { + let heapSnapshotStruct = new HeapSnapshotStruct(); + expect(heapSnapshotStruct).not.toBeUndefined(); + }); + it('DatabaseStructTest06', () => { + let fileStruct = new FileStruct(); + expect(fileStruct).not.toBeUndefined(); + }); + it('DatabaseStructTest07', () => { + let heapNode = new HeapNode(); + expect(heapNode.className()).toBe('(undefined)'); + }); + it('DatabaseStructTest08', () => { + let heapNode = new HeapNode(); + expect(heapNode.classIndex()).toBe(NaN); + }); + it('DatabaseStructTest09', () => { + let heapNode = new HeapNode(); + expect(heapNode.nodeName()).toBeUndefined(); + }); + it('DatabaseStructTest10', () => { + let heapNode = new HeapNode(); + expect(heapNode.addEdge({})).toBeUndefined; + }); + it('DatabaseStructTest11', () => { + let heapNode = new HeapNode(); + expect(heapNode.idHidden()).toBeUndefined; + }); + it('DatabaseStructTest12', () => { + let heapNode = new HeapNode(); + expect(heapNode.isArray()).toBeUndefined; + }); + it('DatabaseStructTest13', () => { + let heapNode = new HeapNode(); + expect(heapNode.isUserRoot()).toBeUndefined; + }); + it('DatabaseStructTest14', () => { + let heapNode = new HeapNode(); + expect(heapNode.isDocumentDOMTreesRoot()).toBeUndefined; + }); + it('DatabaseStructTest15', () => { + let heapNode = new HeapSample(); + expect(HeapSample).not.toBeUndefined; + }); +}) \ No newline at end of file diff --git a/ide/test/js-heap/model/UiStruct.test.ts b/ide/test/js-heap/model/UiStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ca9209720f38e1096bef83d82459bd5dce6ca08 --- /dev/null +++ b/ide/test/js-heap/model/UiStruct.test.ts @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { ConstructorItem, ConstructorComparison,FileInfo,AllocationFunction } from '../../../dist/js-heap/model/UiStruct.js'; + +jest.mock('../../../dist/js-heap/logic/HeapLoader.js', () => { + return {}; +}); + +describe('UiStruct Test', () => { + it('UiStructTest01', () => { + let constructorItem = new ConstructorItem(); + expect(constructorItem).not.toBeUndefined(); + }); + + it('UiStructTest02', () => { + let constructorComparison = new ConstructorComparison(); + expect(constructorComparison).not.toBeUndefined(); + }); + + it('UiStructTest02', () => { + let constructorComparison = new ConstructorComparison(); + expect(constructorComparison).not.toBeUndefined(); + }); + it('UiStructTest03', () => { + let allocationFunction = new AllocationFunction(); + expect(allocationFunction).not.toBeUndefined(); + }); + it('UiStructTest04', () => { + let constructorItem = new ConstructorItem(); + expect(constructorItem.getChildren()).toStrictEqual([]); + }); + it('UiStructTest05', () => { + let constructorItem = new ConstructorItem(); + let data = [ + { + fileId :1, + distance:2, + shallowSize:123, + nodeName: '', + edgeCount:1, + edgeType:'', + childCount:[], + hasNext:true, + } + ] + expect(constructorItem.cloneContent(data)).toBeUndefined(); + }); + it('UiStructTest06', () => { + let constructorComparison = new ConstructorComparison(); + expect(constructorComparison.getChildren()).toStrictEqual([]); + }); + it('UiStructTest07', () => { + let allocationFunction = new AllocationFunction(); + expect(allocationFunction.getChildren()).toStrictEqual([]); + }); +}) \ No newline at end of file diff --git a/ide/test/js-heap/utils/Utils.test.ts b/ide/test/js-heap/utils/Utils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..976831468808a5aea8272b34e97a35b2b3928cf8 --- /dev/null +++ b/ide/test/js-heap/utils/Utils.test.ts @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { HeapNodeToConstructorItem } from "../../../dist/js-heap/utils/Utils.js"; +// @ts-ignore +import {HeapNode} from "../../../dist/js-heap/model/DatabaseStruct.js"; + +jest.mock('../../../dist/js-heap/HeapDataInterface.js', () => { + return {}; +}); + +describe('Utils Test', () => { + it('HeapNodeToConstructorItemTest01', () => { + let data = { + fileId: 1, + nodeIndex: 1, + nodeOldIndex: 1, + type: '', + name: '', + id: 1, + selfSize: 1, + edgeCount: 1, + traceNodeId: 1, + detachedness: 1, + edges: '', + distance: -5, + retainedSize: 1, + displayName: '', + firstEdgeIndex: 1, + flag: 1, + retainsCount: 0, + retainsEdgeIdx: [], + retainsNodeIdx: [], + } + // @ts-ignore + data.nodeName = jest.fn(() => 'test'); + HeapNodeToConstructorItem(data); + }); +}) \ No newline at end of file diff --git a/ide/test/log/Log.test.ts b/ide/test/log/Log.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e44b464a909f8c7dda91b7b338fc5938be1154d8 --- /dev/null +++ b/ide/test/log/Log.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { debug, error, info, log, trace, warn, SpLog, LogLevel } from '../../dist/log/Log.js'; + +describe(' logTest', () => { + ``; + it('LogTest01', () => { + error('111'); + }); + it('LogTest02', () => { + warn('111'); + }); + it('LogTest03', () => { + info('111'); + }); + it('LogTest04', () => { + debug('111'); + }); + it('LogTest05', () => { + trace('111'); + }); + it('LogTest06', () => { + log('111'); + }); +}); diff --git a/ide/test/trace/SpApplication.test.ts b/ide/test/trace/SpApplication.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d618a5048430ac38c31d424a2c233297225693bc --- /dev/null +++ b/ide/test/trace/SpApplication.test.ts @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { SpStatisticsHttpUtil } from '../../dist/statistics/util/SpStatisticsHttpUtil.js'; + +SpStatisticsHttpUtil.initStatisticsServerConfig = jest.fn(() => true); +SpStatisticsHttpUtil.addUserVisitAction = jest.fn(() => true); + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +// @ts-ignore +import { SpApplication } from '../../dist/trace/SpApplication.js'; + +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('spApplication Test', () => { + it('spApplicationTest01', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.dark = true; + expect(SpApplication.name).toEqual('SpApplication'); + }); + + it('spApplicationTest02', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.dark = false; + expect(element.dark).toBeFalsy(); + }); + + it('spApplicationTest03', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.vs = true; + expect(element.vs).toBeTruthy(); + }); + + it('spApplicationTest04', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.vs = false; + expect(element.vs).toBeFalsy(); + }); + + it('spApplicationTest05', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.server = true; + expect(element.server).toBeTruthy(); + }); + + it('spApplicationTest06', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.server = false; + expect(element.server).toBeFalsy(); + }); + + it('spApplicationTest07', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.querySql = true; + expect(element.querySql).toBeTruthy(); + }); + + it('spApplicationTest08', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.querySql = false; + expect(element.querySql).toBeFalsy(); + }); + + it('spApplicationTest09', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.search = true; + expect(element.querySql).toBeTruthy(); + }); + + it('spApplicationTest10', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + element.search = false; + expect(element.search).toBeFalsy(); + }); + + it('spApplicationTest11', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + expect(element.removeSkinListener([])).toBeUndefined(); + }); + + it('spApplicationTest15', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + expect(spApplication.freshMenuDisable()).toBeUndefined(); + }); + + it('spApplicationTest16', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + expect(spApplication.addSkinListener()).toBeUndefined(); + }); + + it('spApplicationTest17', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + expect(spApplication.removeSkinListener()).toBeUndefined(); + }); + + it('spApplicationTest18', function () { + document.body.innerHTML = ""; + let element = document.querySelector('#sp') as SpApplication; + element.dispatchEvent(new Event('dragleave')); + }); + + it('spApplicationTest19', function () { + document.body.innerHTML = ""; + let element = document.querySelector('#sp') as SpApplication; + element.dispatchEvent(new Event('drop')); + SpApplication.removeSkinListener = jest.fn(() => undefined); + expect(element.removeSkinListener({})).toBeUndefined(); + }); + it('spApplicationTest21', function () { + document.body.innerHTML = ""; + let element = document.querySelector('#sp') as SpApplication; + expect(element.vsDownload()).toBeUndefined(); + }); + + it('spApplicationTest22', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + spApplication.showConten = false; + expect(spApplication.showContent).toBeFalsy(); + }); + + it('spApplicationTest25', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + expect(spApplication.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ + + +
+
+ + + + + + + + + + + + +
+
+ " +`); + }); + + it('spApplicationTest26', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + spApplication.dark = false; + spApplication.skinChangeArray = ['item']; + expect(spApplication.dark).toBeFalsy(); + }); + + it('spApplicationTest27', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + spApplication.dark = true; + spApplication.skinChange = jest.fn(() => true); + expect(spApplication.dark).toBeTruthy(); + }); + + it('spApplicationTest28', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + spApplication.dark = false; + spApplication.skinChange2 = jest.fn(() => true); + expect(spApplication.dark).toBeFalsy(); + }); + + it('spApplicationTest29', function () { + document.body.innerHTML = ''; + let spApplication = document.querySelector('#sss') as SpApplication; + spApplication.querySql = false; + expect(spApplication.querySql).toBeFalsy(); + }); + it('spApplicationTest30', function () { + document.body.innerHTML = ``; + let element = new SpApplication(); + expect(element.download({},'',true,'')).toBeFalsy(); + }); +}); diff --git a/ide/test/trace/bean/AbilityMonitor.test.ts b/ide/test/trace/bean/AbilityMonitor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d262851a6a3bbe86014bb064b7443dcdd6400df7 --- /dev/null +++ b/ide/test/trace/bean/AbilityMonitor.test.ts @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { + SystemCpuSummary, + SystemDiskIOSummary, + ProcessHistory, + LiveProcess, + SystemNetworkSummary, + SystemMemorySummary, +} from '../../../dist/trace/bean/AbilityMonitor.js'; + +describe('AbilityMonitor Test', () => { + let systemCpuSummary = new SystemCpuSummary(); + let systemDiskIOSummary = new SystemDiskIOSummary(); + let processHistory = new ProcessHistory(); + let liveProcess = new LiveProcess(); + let systemNetworkSummary = new SystemNetworkSummary(); + let systemMemorySummary = new SystemMemorySummary(); + + it('SystemCpuSummaryTest', function () { + systemCpuSummary = { + startTime: -1, + startTimeStr: 'startTimeStr', + duration: -1, + durationStr: 'durationStr', + totalLoad: -1, + totalLoadStr: 'totalLoadStr', + userLoad: -1, + userLoadStr: 'userLoadStr', + systemLoad: -1, + systemLoadStr: 'systemLoadStr', + threads: -1, + threadsStr: 'threadsStr', + }; + + expect(systemCpuSummary).not.toBeUndefined(); + expect(systemCpuSummary).toMatchInlineSnapshot( +{ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + totalLoad: expect.any(Number), + totalLoadStr: expect.any(String), + userLoad: expect.any(Number), + userLoadStr: expect.any(String), + systemLoad: expect.any(Number), + systemLoadStr: expect.any(String), + threads: expect.any(Number), + threadsStr: expect.any(String) }, ` +{ + "duration": Any, + "durationStr": Any, + "startTime": Any, + "startTimeStr": Any, + "systemLoad": Any, + "systemLoadStr": Any, + "threads": Any, + "threadsStr": Any, + "totalLoad": Any, + "totalLoadStr": Any, + "userLoad": Any, + "userLoadStr": Any, +} +`); + }); + + it('SystemCpuSummaryTest', function () { + systemDiskIOSummary = { + startTime: 1, + startTimeStr: 'startTimeStr', + duration: 1, + durationStr: 'durationStr', + dataRead: 1, + dataReadStr: 'dataReadStr', + dataReadSec: 1, + dataReadSecStr: 'dataReadSecStr', + dataWrite: 1, + dataWriteStr: 'dataWriteStr', + dataWriteSec: 1, + dataWriteSecStr: 'dataWriteSecStr', + readsIn: 1, + readsInStr: 'readsInStr', + readsInSec: 1, + readsInSecStr: 'readsInSecStr', + writeOut: 1, + writeOutStr: 'writeOutStr', + writeOutSec: 1, + writeOutSecStr: 'writeOutSecStr', + }; + expect(systemDiskIOSummary).not.toBeUndefined(); + expect(systemDiskIOSummary).toMatchInlineSnapshot( +{ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + dataRead: expect.any(Number), + dataReadStr: expect.any(String), + dataReadSec: expect.any(Number), + dataReadSecStr: expect.any(String), + dataWrite: expect.any(Number), + dataWriteStr: expect.any(String), + dataWriteSec: expect.any(Number), + dataWriteSecStr: expect.any(String), + readsIn: expect.any(Number), + readsInStr: expect.any(String), + readsInSec: expect.any(Number), + readsInSecStr: expect.any(String), + writeOut: expect.any(Number), + writeOutStr: expect.any(String), + writeOutSec: expect.any(Number), + writeOutSecStr: expect.any(String) }, ` +{ + "dataRead": Any, + "dataReadSec": Any, + "dataReadSecStr": Any, + "dataReadStr": Any, + "dataWrite": Any, + "dataWriteSec": Any, + "dataWriteSecStr": Any, + "dataWriteStr": Any, + "duration": Any, + "durationStr": Any, + "readsIn": Any, + "readsInSec": Any, + "readsInSecStr": Any, + "readsInStr": Any, + "startTime": Any, + "startTimeStr": Any, + "writeOut": Any, + "writeOutSec": Any, + "writeOutSecStr": Any, + "writeOutStr": Any, +} +`); + }); + + it('SystemCpuSummaryTest', function () { + systemDiskIOSummary = { + startTime: 1, + startTimeStr: 'startTimeStr', + duration: 1, + durationStr: 'durationStr', + dataRead: 1, + dataReadStr: 'dataReadStr', + dataReadSec: 1, + dataReadSecStr: 'dataReadSecStr', + dataWrite: 1, + dataWriteStr: 'dataWriteStr', + dataWriteSec: 1, + dataWriteSecStr: 'dataWriteSecStr', + readsIn: 1, + readsInStr: 'readsInStr', + readsInSec: 1, + readsInSecStr: 'readsInSecStr', + writeOut: 1, + writeOutStr: 'writeOutStr', + writeOutSec: 1, + writeOutSecStr: 'writeOutSecStr', + }; + expect(systemDiskIOSummary).not.toBeUndefined(); + expect(systemDiskIOSummary).toMatchInlineSnapshot( +{ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + dataRead: expect.any(Number), + dataReadStr: expect.any(String), + dataReadSec: expect.any(Number), + dataReadSecStr: expect.any(String), + dataWrite: expect.any(Number), + dataWriteStr: expect.any(String), + dataWriteSec: expect.any(Number), + dataWriteSecStr: expect.any(String), + readsIn: expect.any(Number), + readsInStr: expect.any(String), + readsInSec: expect.any(Number), + readsInSecStr: expect.any(String), + writeOut: expect.any(Number), + writeOutStr: expect.any(String), + writeOutSec: expect.any(Number), + writeOutSecStr: expect.any(String) }, ` +{ + "dataRead": Any, + "dataReadSec": Any, + "dataReadSecStr": Any, + "dataReadStr": Any, + "dataWrite": Any, + "dataWriteSec": Any, + "dataWriteSecStr": Any, + "dataWriteStr": Any, + "duration": Any, + "durationStr": Any, + "readsIn": Any, + "readsInSec": Any, + "readsInSecStr": Any, + "readsInStr": Any, + "startTime": Any, + "startTimeStr": Any, + "writeOut": Any, + "writeOutSec": Any, + "writeOutSecStr": Any, + "writeOutStr": Any, +} +`); + }); + + it('ProcessHistoryTest', function () { + processHistory = { + processId: -1, + alive: '', + firstSeen: '', + lastSeen: '', + processName: '', + responsibleProcess: '', + userName: '', + cpuTime: '', + }; + expect(processHistory).not.toBeUndefined(); + expect(processHistory).toMatchInlineSnapshot( +{ + processId: expect.any(Number), + alive: expect.any(String), + firstSeen: expect.any(String), + lastSeen: expect.any(String), + processName: expect.any(String), + responsibleProcess: expect.any(String), + userName: expect.any(String), + cpuTime: expect.any(String) }, ` +{ + "alive": Any, + "cpuTime": Any, + "firstSeen": Any, + "lastSeen": Any, + "processId": Any, + "processName": Any, + "responsibleProcess": Any, + "userName": Any, +} +`); + }); + + it('LiveProcessTest', function () { + liveProcess = { + processId: -1, + processName: '', + responsibleProcess: '', + userName: '', + cpu: '', + threads: -1, + }; + expect(liveProcess).not.toBeUndefined(); + expect(liveProcess).toMatchInlineSnapshot( +{ + processId: expect.any(Number), + processName: expect.any(String), + responsibleProcess: expect.any(String), + userName: expect.any(String), + cpu: expect.any(String), + threads: expect.any(Number) }, ` +{ + "cpu": Any, + "processId": Any, + "processName": Any, + "responsibleProcess": Any, + "threads": Any, + "userName": Any, +} +`); + }); + + it('SystemNetworkSummaryTest', function () { + systemNetworkSummary = { + startTime: -1, + startTimeStr: '', + duration: -1, + durationStr: '', + dataReceived: -1, + dataReceivedStr: '', + dataReceivedSec: -1, + dataReceivedSecStr: '', + dataSend: -1, + dataSendStr: '', + dataSendSec: -1, + dataSendSecStr: '', + packetsIn: -1, + packetsInSec: -1, + packetsOut: -1, + packetsOutSec: -1, + }; + expect(systemNetworkSummary).not.toBeUndefined(); + expect(systemNetworkSummary).toMatchInlineSnapshot( +{ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + dataReceived: expect.any(Number), + dataReceivedStr: expect.any(String), + dataReceivedSec: expect.any(Number), + dataReceivedSecStr: expect.any(String), + dataSend: expect.any(Number), + dataSendStr: expect.any(String), + dataSendSec: expect.any(Number), + dataSendSecStr: expect.any(String), + packetsIn: expect.any(Number), + packetsInSec: expect.any(Number), + packetsOut: expect.any(Number), + packetsOutSec: expect.any(Number) }, ` +{ + "dataReceived": Any, + "dataReceivedSec": Any, + "dataReceivedSecStr": Any, + "dataReceivedStr": Any, + "dataSend": Any, + "dataSendSec": Any, + "dataSendSecStr": Any, + "dataSendStr": Any, + "duration": Any, + "durationStr": Any, + "packetsIn": Any, + "packetsInSec": Any, + "packetsOut": Any, + "packetsOutSec": Any, + "startTime": Any, + "startTimeStr": Any, +} +`); + }); + + it('systemMemorySummaryTest', function () { + systemMemorySummary = { + startTime: -1, + startTimeStr: '', + duration: -1, + durationStr: '', + memoryTotal: -1, + memoryTotalStr: '', + cached: -1, + cachedStr: '', + swapTotal: -1, + swapTotalStr: '', + appMemory: -1, + cachedFiles: -1, + compressed: -1, + memoryUsed: -1, + wiredMemory: -1, + swapUsed: -1, + }; + expect(systemMemorySummary).not.toBeUndefined(); + expect(systemMemorySummary).toMatchInlineSnapshot( +{ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + memoryTotal: expect.any(Number), + memoryTotalStr: expect.any(String), + cached: expect.any(Number), + cachedStr: expect.any(String), + swapTotal: expect.any(Number), + swapTotalStr: expect.any(String), + appMemory: expect.any(Number), + cachedFiles: expect.any(Number), + compressed: expect.any(Number), + memoryUsed: expect.any(Number), + wiredMemory: expect.any(Number), + swapUsed: expect.any(Number) }, ` +{ + "appMemory": Any, + "cached": Any, + "cachedFiles": Any, + "cachedStr": Any, + "compressed": Any, + "duration": Any, + "durationStr": Any, + "memoryTotal": Any, + "memoryTotalStr": Any, + "memoryUsed": Any, + "startTime": Any, + "startTimeStr": Any, + "swapTotal": Any, + "swapTotalStr": Any, + "swapUsed": Any, + "wiredMemory": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/BaseStruct.test.ts b/ide/test/trace/bean/BaseStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..40362efbb8bb6f4234a2e73a3f37af38e075a726 --- /dev/null +++ b/ide/test/trace/bean/BaseStruct.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { BaseStruct } from '../../../dist/trace/bean/BaseStruct.js'; +describe('BaseStruct Test', () => { + let baseStruct = new BaseStruct(); + + it('BaseStructTest01', function () { + baseStruct = { + isHover: false, + }; + expect(baseStruct).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/BoxSelection.test.ts b/ide/test/trace/bean/BoxSelection.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b94384bfa8fd27bdc0e63b346c1ff991a7ec700d --- /dev/null +++ b/ide/test/trace/bean/BoxSelection.test.ts @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SelectionParam, BoxJumpParam, SelectionData, Counter, Fps } from '../../../dist/trace/bean/BoxSelection.js'; + +describe('BoxSelection Test', () => { + let selectionParam = new SelectionParam(); + let boxJumpParam = new BoxJumpParam(); + let selectionData = new SelectionData(); + let counter = new Counter(); + let fps = new Fps(); + it('BoxSelectionTest01', function () { + selectionParam = { + cpus: 1, + threadIds: 2, + trackIds: 1, + funTids: 2, + heapIds: 1, + nativeMemory: 3, + leftNs: 1, + rightNs: 1, + hasFps: true, + statisticsSelectData: 1, + }; + + expect(selectionParam).not.toBeUndefined(); + expect(selectionParam).toMatchInlineSnapshot( +{ + cpus: expect.any(Number), + threadIds: expect.any(Number), + trackIds: expect.any(Number), + funTids: expect.any(Number), + heapIds: expect.any(Number), + nativeMemory: expect.any(Number), + leftNs: expect.any(Number), + rightNs: expect.any(Number), + hasFps: expect.any(Boolean) }, ` +{ + "cpus": Any, + "funTids": Any, + "hasFps": Any, + "heapIds": Any, + "leftNs": Any, + "nativeMemory": Any, + "rightNs": Any, + "statisticsSelectData": 1, + "threadIds": Any, + "trackIds": Any, +} +`); + }); + + it('BoxSelectionTest02', function () { + boxJumpParam = { + leftNs: 0, + rightNs: 0, + state: '', + processId: 0, + threadId: 0, + }; + expect(boxJumpParam).not.toBeUndefined(); + expect(boxJumpParam).toMatchInlineSnapshot( +{ + leftNs: expect.any(Number), + rightNs: expect.any(Number), + state: expect.any(String), + processId: expect.any(Number), + threadId: expect.any(Number) }, ` +{ + "leftNs": Any, + "processId": Any, + "rightNs": Any, + "state": Any, + "threadId": Any, +} +`); + }); + + it('BoxSelectionTest03', function () { + selectionData = { + name: 'name', + process: 'process', + pid: 'pid', + thread: 'thread', + tid: 'tid', + wallDuration: 0, + avgDuration: 'avgDuration', + occurrences: 0, + state: 'state', + trackId: 0, + delta: 'delta', + rate: 'rate', + avgWeight: 'avgWeight', + count: 'count', + first: 'first', + last: 'last', + min: 'min', + max: 'max', + stateJX: 'stateJX', + }; + expect(selectionData).not.toBeUndefined(); + expect(selectionData).toMatchInlineSnapshot( +{ + process: expect.any(String), + pid: expect.any(String), + thread: expect.any(String), + tid: expect.any(String), + wallDuration: expect.any(Number), + avgDuration: expect.any(String), + occurrences: expect.any(Number), + state: expect.any(String), + trackId: expect.any(Number), + delta: expect.any(String), + rate: expect.any(String), + avgWeight: expect.any(String), + count: expect.any(String), + first: expect.any(String), + last: expect.any(String), + min: expect.any(String), + max: expect.any(String), + stateJX: expect.any(String) }, ` +{ + "avgDuration": Any, + "avgWeight": Any, + "count": Any, + "delta": Any, + "first": Any, + "last": Any, + "max": Any, + "min": Any, + "name": "name", + "occurrences": Any, + "pid": Any, + "process": Any, + "rate": Any, + "state": Any, + "stateJX": Any, + "thread": Any, + "tid": Any, + "trackId": Any, + "wallDuration": Any, +} +`); + }); + + it('BoxSelectionTest04', function () { + counter = { + id: 0, + trackId: 0, + name: '', + value: 0, + startTime: 0, + }; + expect(counter).not.toBeUndefined(); + expect(counter).toMatchInlineSnapshot( +{ + id: expect.any(Number), + trackId: expect.any(Number), + name: expect.any(String), + value: expect.any(Number), + startTime: expect.any(Number) }, ` +{ + "id": Any, + "name": Any, + "startTime": Any, + "trackId": Any, + "value": Any, +} +`); + }); + + it('BoxSelectionTest05', function () { + fps = { + startNS: 0, + timeStr: '', + fps: 0, + }; + expect(fps).not.toBeUndefined(); + expect(fps).toMatchInlineSnapshot( +{ + startNS: expect.any(Number), + timeStr: expect.any(String), + fps: expect.any(Number) }, ` +{ + "fps": Any, + "startNS": Any, + "timeStr": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/CpuFreqStruct.test.ts b/ide/test/trace/bean/CpuFreqStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5cbeb2f173842aad85c2dfbff50a9f07f550db71 --- /dev/null +++ b/ide/test/trace/bean/CpuFreqStruct.test.ts @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { CpuFreqStruct } from '../../../dist/trace/bean/CpuFreqStruct.js'; + +describe('CpuFreqStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + CpuFreqStruct.hoverCpuFreqStruct = void 0; + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + value: 50, + maxFreq: 50, + }; + + it('CpuFreqStructTest01', function () { + expect(CpuFreqStruct.draw(ctx, data)).toBeUndefined(); + expect(data).toMatchInlineSnapshot( +{ + startNS: expect.any(Number), + value: expect.any(Number) }, ` +{ + "frame": { + "height": 100, + "width": 100, + "x": 20, + "y": 20, + }, + "startNS": Any, + "value": Any, +} +`); + }); + + it('CpuFreqStructTest02', function () { + expect(CpuFreqStruct.draw(ctx, { startNS: 1 })).toBeUndefined(); + }); + + it('CpuFreqStructTest03 ', function () { + expect(CpuFreqStruct.draw(ctx, dataSource)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/CpuStruct.test.ts b/ide/test/trace/bean/CpuStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..84d0da4c7249d08b2009caed16de70b5bda51140 --- /dev/null +++ b/ide/test/trace/bean/CpuStruct.test.ts @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { CpuStruct } from '../../../dist/trace/bean/CpuStruct.js'; + +describe('CpuStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + CpuStruct.selectCpuStruct = {}; + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + const data1 = { + frame: { + x: 100, + y: 100, + width: 10, + height: 10, + }, + startNS: 1000, + value: 500, + }; + + it('CpuStructTest01', function () { + expect(CpuStruct.draw(ctx, data)).toBeUndefined(); + expect(data).toMatchInlineSnapshot( +{ + startNS: expect.any(Number), + value: expect.any(Number) }, ` +{ + "frame": { + "height": 100, + "width": 100, + "x": 20, + "y": 20, + }, + "startNS": Any, + "value": Any, +} +`); + }); + + it('CpuStructTest02', function () { + expect(CpuStruct.equals({}, data)).toBeTruthy(); + }); + + it('CpuStructTest03', function () { + expect(CpuStruct.equals(data, data)).toBeTruthy(); + }); + + it('CpuStructTest04', function () { + expect(CpuStruct.equals(data, data1)).toBeTruthy(); + }); + + it('CpuStructTest05', function () { + expect(CpuStruct.draw(ctx, data1)).toBeUndefined(); + expect(data1).toMatchInlineSnapshot( +{ + startNS: expect.any(Number), + value: expect.any(Number) }, ` +{ + "frame": { + "height": 10, + "width": 10, + "x": 100, + "y": 100, + }, + "startNS": Any, + "value": Any, +} +`); + }); + + it('CpuStructTest06', function () { + expect(CpuStruct.equals({}, data)).toBeTruthy(); + expect(CpuStruct.draw(ctx, data1)).toBeUndefined(); + expect(data1).toMatchInlineSnapshot( +{ + startNS: expect.any(Number), + value: expect.any(Number) }, ` +{ + "frame": { + "height": 10, + "width": 10, + "x": 100, + "y": 100, + }, + "startNS": Any, + "value": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/CpuUsage.test.ts b/ide/test/trace/bean/CpuUsage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2886f1a677a493a7696418ab4cf769cd30dc6985 --- /dev/null +++ b/ide/test/trace/bean/CpuUsage.test.ts @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { CpuUsage, Freq } from '../../../dist/trace/bean/CpuUsage.js'; + +describe('CpuUsage Test', () => { + let cpuUsage = new CpuUsage(); + let freq = new Freq(); + + it('CpuUsageTest01', function () { + cpuUsage = { + cpu: 0, + usage: 0, + usageStr: '', + top1: 0, + top2: 0, + top3: 0, + top1Percent: 0, + top1PercentStr: '', + top2Percent: 0, + top2PercentStr: '', + top3Percent: 0, + top3PercentStr: '', + }; + expect(cpuUsage).not.toBeUndefined(); + expect(cpuUsage).toMatchInlineSnapshot( +{ + cpu: expect.any(Number), + usage: expect.any(Number), + usageStr: expect.any(String), + top1: expect.any(Number), + top2: expect.any(Number), + top3: expect.any(Number), + top1Percent: expect.any(Number), + top1PercentStr: expect.any(String), + top2Percent: expect.any(Number), + top2PercentStr: expect.any(String), + top3Percent: expect.any(Number), + top3PercentStr: expect.any(String) }, ` +{ + "cpu": Any, + "top1": Any, + "top1Percent": Any, + "top1PercentStr": Any, + "top2": Any, + "top2Percent": Any, + "top2PercentStr": Any, + "top3": Any, + "top3Percent": Any, + "top3PercentStr": Any, + "usage": Any, + "usageStr": Any, +} +`); + }); + + it('CpuUsageTest02', function () { + cpuUsage = { + cpu: 0, + value: 0, + startNs: 0, + dur: 0, + }; + expect(freq).not.toBeUndefined(); + expect(cpuUsage).toMatchInlineSnapshot( +{ + cpu: expect.any(Number), + value: expect.any(Number), + startNs: expect.any(Number), + dur: expect.any(Number) }, ` +{ + "cpu": Any, + "dur": Any, + "startNs": Any, + "value": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/DiskAbilityMonitorStruct.test.ts b/ide/test/trace/bean/DiskAbilityMonitorStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d5625b1feaa23c39f54f449ed85ff985625ca2f --- /dev/null +++ b/ide/test/trace/bean/DiskAbilityMonitorStruct.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { DiskAbilityMonitorStruct } from '../../../dist/trace/bean/DiskAbilityMonitorStruct.js'; + +describe('DiskAbilityMonitorStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + value: 50, + maxDiskRate: 50, + }; + + it('DiskAbilityMonitorStructTest01', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('DiskAbilityMonitorStructTest02', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/EnergyStruct.test.ts b/ide/test/trace/bean/EnergyStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b27aaf534b4d8e4cfaf5d2702a25204c05026be7 --- /dev/null +++ b/ide/test/trace/bean/EnergyStruct.test.ts @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { + EnergyAnomalyStruct, + EnergySystemStruct, + EnergyPowerStruct, + EnergyStateStruct, + PowerDetailsEnergy, + PowerBatteryEnergy, + SystemDetailsEnergy, +} from '../../../dist/trace/bean/EnergyStruct.js'; + +describe('EnergyStruct Test', () => { + let energyAnomalyStruct = new EnergyAnomalyStruct(); + let energySystemStruct = new EnergySystemStruct(); + let energyPowerStruct = new EnergyPowerStruct(); + let energyStateStruct = new EnergyStateStruct(); + let powerDetailsEnergy = new PowerDetailsEnergy(); + let powerBatteryEnergy = new PowerBatteryEnergy(); + let systemDetailsEnergy = new SystemDetailsEnergy(); + + it('energyAnomalyStructTest', function () { + energyAnomalyStruct = { + type: 0, + startNS: 0, + height: 0, + eventName: 'eventName', + }; + expect(energyAnomalyStruct).not.toBeUndefined(); + expect(energyAnomalyStruct).toMatchInlineSnapshot( +{ + type: expect.any(Number), + startNS: expect.any(Number), + height: expect.any(Number), + eventName: expect.any(String) }, ` +{ + "eventName": Any, + "height": Any, + "startNS": Any, + "type": Any, +} +`); + }); + + it('energySystemStructTest', function () { + energySystemStruct = { + type: 0, + startNs: 0, + dur: 0, + workScheduler: '', + power: '', + location: '', + }; + expect(energySystemStruct).not.toBeUndefined(); + expect(energySystemStruct).toMatchInlineSnapshot( +{ + type: expect.any(Number), + startNs: expect.any(Number), + dur: expect.any(Number), + workScheduler: expect.any(String), + power: expect.any(String), + location: expect.any(String) }, ` +{ + "dur": Any, + "location": Any, + "power": Any, + "startNs": Any, + "type": Any, + "workScheduler": Any, +} +`); + }); + + it('energyPowerStructTest', function () { + energyPowerStruct = { + type: 0, + name: '', + ts: 0, + cpu: 0, + location: 0, + gpu: 0, + display: 0, + camera: 0, + bluetooth: 0, + flashlight: 0, + audio: 0, + wifiscan: 0, + }; + expect(energyPowerStruct).not.toBeUndefined(); + expect(energyPowerStruct).toMatchInlineSnapshot( +{ + type: expect.any(Number), + name: expect.any(String), + ts: expect.any(Number), + cpu: expect.any(Number), + location: expect.any(Number), + gpu: expect.any(Number), + display: expect.any(Number), + camera: expect.any(Number), + bluetooth: expect.any(Number), + flashlight: expect.any(Number), + audio: expect.any(Number), + wifiscan: expect.any(Number) }, ` +{ + "audio": Any, + "bluetooth": Any, + "camera": Any, + "cpu": Any, + "display": Any, + "flashlight": Any, + "gpu": Any, + "location": Any, + "name": Any, + "ts": Any, + "type": Any, + "wifiscan": Any, +} +`); + }); + + it('energyStateStructTest', function () { + energyStateStruct = { + type: '', + startNs: 0, + dur: 0, + value: 0, + }; + expect(energyStateStruct).not.toBeUndefined(); + expect(energyStateStruct).toMatchInlineSnapshot( +{ + type: expect.any(String), + startNs: expect.any(Number), + dur: expect.any(Number), + value: expect.any(Number) }, ` +{ + "dur": Any, + "startNs": Any, + "type": Any, + "value": Any, +} +`); + }); + + it('powerDetailsEnergyTest', function () { + powerDetailsEnergy = { + event: '', + charge: 0, + background_time: 0, + screen_on_time: 0, + screen_off_time: 0, + load: '-', + usage: 0, + duration: 0, + camera_id: 0, + foreground_count: 0, + background_count: 0, + screen_on_count: 0, + screen_off_count: 0, + count: 0, + appName: '', + uid: 0, + foreground_duration: 0, + foreground_energy: 0, + background_duration: 0, + background_energy: 0, + screen_on_duration: 0, + screen_on_energy: 0, + screen_off_duration: 0, + screen_off_energy: 0, + energy: 0, + energyConsumptionRatio: '', + }; + expect(powerDetailsEnergy).not.toBeUndefined(); + expect(powerDetailsEnergy).toMatchInlineSnapshot( +{ + event: expect.any(String), + charge: expect.any(Number), + background_time: expect.any(Number), + screen_on_time: expect.any(Number), + screen_off_time: expect.any(Number), + load: expect.any(String), + usage: expect.any(Number), + duration: expect.any(Number), + camera_id: expect.any(Number), + foreground_count: expect.any(Number), + background_count: expect.any(Number), + screen_on_count: expect.any(Number), + screen_off_count: expect.any(Number), + count: expect.any(Number), + appName: expect.any(String), + uid: expect.any(Number), + foreground_duration: expect.any(Number), + foreground_energy: expect.any(Number), + background_duration: expect.any(Number), + background_energy: expect.any(Number), + screen_on_duration: expect.any(Number), + screen_on_energy: expect.any(Number), + screen_off_duration: expect.any(Number), + screen_off_energy: expect.any(Number), + energy: expect.any(Number), + energyConsumptionRatio: expect.any(String) }, ` +{ + "appName": Any, + "background_count": Any, + "background_duration": Any, + "background_energy": Any, + "background_time": Any, + "camera_id": Any, + "charge": Any, + "count": Any, + "duration": Any, + "energy": Any, + "energyConsumptionRatio": Any, + "event": Any, + "foreground_count": Any, + "foreground_duration": Any, + "foreground_energy": Any, + "load": Any, + "screen_off_count": Any, + "screen_off_duration": Any, + "screen_off_energy": Any, + "screen_off_time": Any, + "screen_on_count": Any, + "screen_on_duration": Any, + "screen_on_energy": Any, + "screen_on_time": Any, + "uid": Any, + "usage": Any, +} +`); + }); + + it('powerBatteryEnergyTest', function () { + powerBatteryEnergy = { + gasGauge: -1, + charge: -1, + screen: -1, + level: -1, + current: -1, + capacity: -1, + appName: '', + uid: -1, + }; + expect(powerBatteryEnergy).not.toBeUndefined(); + expect(powerBatteryEnergy).toMatchInlineSnapshot( +{ + gasGauge: expect.any(Number), + charge: expect.any(Number), + screen: expect.any(Number), + level: expect.any(Number), + current: expect.any(Number), + capacity: expect.any(Number), + appName: expect.any(String), + uid: expect.any(Number) }, ` +{ + "appName": Any, + "capacity": Any, + "charge": Any, + "current": Any, + "gasGauge": Any, + "level": Any, + "screen": Any, + "uid": Any, +} +`); + }); + + it('systemDetailsEnergyTest', function () { + systemDetailsEnergy = { + eventName: '', + type: '', + pid: -1, + uid: -1, + state: -1, + workId: '', + name: '', + interval: -1, + level: -1, + tag: '', + message: '', + log_level: '', + }; + expect(systemDetailsEnergy).not.toBeUndefined(); + expect(systemDetailsEnergy).toMatchInlineSnapshot( +{ + eventName: expect.any(String), + type: expect.any(String), + pid: expect.any(Number), + uid: expect.any(Number), + state: expect.any(Number), + workId: expect.any(String), + name: expect.any(String), + interval: expect.any(Number), + level: expect.any(Number), + tag: expect.any(String), + message: expect.any(String), + log_level: expect.any(String) }, ` +{ + "eventName": Any, + "interval": Any, + "level": Any, + "log_level": Any, + "message": Any, + "name": Any, + "pid": Any, + "state": Any, + "tag": Any, + "type": Any, + "uid": Any, + "workId": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/FpsStruct.test.ts b/ide/test/trace/bean/FpsStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..25616b7a89eed98657c930eaea7ea0f6ff3c5046 --- /dev/null +++ b/ide/test/trace/bean/FpsStruct.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { FpsStruct } from '../../../dist/trace/bean/FpsStruct.js'; + +describe('FpsStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + const node = { + startNS: 200, + frame: 2, + dur: 3, + }; + const padding = 1; + const startNs = 1; + const endNS = 1; + const totalNS = 1; + const frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + value: 50, + maxFps: 50, + }; + + it('FpsStructTest01', function () { + expect(FpsStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('FpsStructTest04 ', function () { + expect(FpsStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('FpsStructTest02', function () { + let fpsStruct = new FpsStruct(); + expect(fpsStruct).not.toBeUndefined(); + }); + + it('FpsStructTest03', function () { + expect(FpsStruct.setFrame(node, padding, startNs, endNS, totalNS, frame)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/FuncStruct.test.ts b/ide/test/trace/bean/FuncStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..841cb26382a47123cf71416b5e54086f1842f1c9 --- /dev/null +++ b/ide/test/trace/bean/FuncStruct.test.ts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { FuncStruct } from '../../../dist/trace/bean/FuncStruct.js'; + +describe('FuncStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const dataResource = { + frame: { + x: 20, + y: 20, + }, + }; + + const durData = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + dur: 5, + }; + + FuncStruct.isSelected = jest.fn(() => true); + + it('FuncStructTest01', function () { + expect(FuncStruct.draw(ctx, dataResource)).toBeUndefined(); + }); + + it('FuncStructTest02', function () { + expect(FuncStruct.draw(ctx, durData)).toBeUndefined(); + }); + it('FuncStructTest03', function () { + expect(FuncStruct.drawString(ctx, 2, durData, durData.frame)).toBeUndefined(); + }); + it('FuncStructTest06 ', function () { + expect(FuncStruct.drawString(ctx, 3, durData, durData.frame)).toBeUndefined(); + }); + + it('FuncStructTest04', function () { + expect( + FuncStruct.isSelected({ + startTs: 10, + dur: 10, + funName: '', + }) + ).toBeTruthy(); + }); + + it('FuncStructTest05', function () { + expect( + FuncStruct.isBinder({ + startTs: 10, + dur: 10, + funName: null, + }) + ).toBeFalsy(); + }); + + it('FuncStructTest07', function () { + expect(FuncStruct.drawString(ctx, 300, durData, durData.frame)).toBeUndefined(); + }); + + it('FuncStructTest08', function () { + expect( + FuncStruct.isBinderAsync({ + startTs: 10, + dur: 10, + funName: null, + }) + ).toBeFalsy(); + }); + + it('FuncStructTest09', function () { + expect( + FuncStruct.isBinderAsync({ + startTs: 20, + dur: 20, + funName: 'funName', + }) + ).toBeFalsy(); + }); +}); diff --git a/ide/test/trace/bean/HeapBean.test.ts b/ide/test/trace/bean/HeapBean.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1253fc8edc8c24643c3e9b7c1e103aabc777bf5b --- /dev/null +++ b/ide/test/trace/bean/HeapBean.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { HeapBean } from '../../../dist/trace/bean/HeapBean.js'; + +describe('HeapBean Test', () => { + let heapBean = new HeapBean(); + + it('HeapBeanTest01', function () { + heapBean = { + MoudleName: 'MoudleName', + AllocationFunction: 'AllocationFunction', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + depth: 0, + }; + expect(heapBean).not.toBeUndefined(); + expect(heapBean).toMatchInlineSnapshot( +{ + MoudleName: expect.any(String), + AllocationFunction: expect.any(String), + Allocations: expect.any(Number), + Deallocations: expect.any(Number), + AllocationSize: expect.any(Number), + DeAllocationSize: expect.any(Number), + Total: expect.any(Number), + RemainingSize: expect.any(Number), + depth: expect.any(Number) }, ` +{ + "AllocationFunction": Any, + "AllocationSize": Any, + "Allocations": Any, + "DeAllocationSize": Any, + "Deallocations": Any, + "MoudleName": Any, + "RemainingSize": Any, + "Total": Any, + "depth": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/HeapStruct.test.ts b/ide/test/trace/bean/HeapStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..668b920c945d1e081222ea436fd4b72c48b1d352 --- /dev/null +++ b/ide/test/trace/bean/HeapStruct.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { HeapStruct } from '../../../dist/trace/bean/HeapStruct.js'; + +describe('HeapStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + value: 50, + maxHeapSize: 50, + heapsize: 10, + }; + + const reachData = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + value: 50, + startTime: 1, + }; + + const nodeSource = { + startTime: 10, + dur: 10, + endTime: 20, + frame: { + width: 20, + }, + }; + + const heapStruct = new HeapStruct(); + + it('HeapStructTest01', function () { + expect(HeapStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('HeapStructTest02', function () { + expect(HeapStruct.draw(ctx, reachData)).toBeUndefined(); + }); + + it('HeapStructTest03', function () { + expect(HeapStruct.setFrame(nodeSource, 1, 10, 15, 30, nodeSource.frame)).toBeUndefined(); + }); + + it('HeapStructTest04', function () { + expect(HeapStruct.setFrame(nodeSource, 1, 15, 20, 30, nodeSource.frame)).toBeUndefined(); + }); + + it('HeapStructTest05', function () { + expect(HeapStruct.setFrame(nodeSource, 1, 10, 20, 30, nodeSource.frame)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/HeapTreeDataBean.test.ts b/ide/test/trace/bean/HeapTreeDataBean.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a6fad97354143b3a67855f147e66a4c39eaa3842 --- /dev/null +++ b/ide/test/trace/bean/HeapTreeDataBean.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { HeapTreeDataBean } from '../../../dist/trace/bean/HeapTreeDataBean.js'; + +describe('HeapTreeDataBean Test', () => { + let heapTreeDataBean = new HeapTreeDataBean(); + + it('HeapTreeDataBeanTest01', function () { + heapTreeDataBean = { + MoudleName: 'MoudleName', + AllocationFunction: 'AllocationFunction', + startTs: 0, + endTs: 0, + eventType: 'eventType', + depth: 0, + heapSize: 0, + eventId: 'eventId', + }; + expect(heapTreeDataBean).not.toBeUndefined(); + expect(heapTreeDataBean).toMatchInlineSnapshot( +{ + MoudleName: expect.any(String), + AllocationFunction: expect.any(String), + startTs: expect.any(Number), + endTs: expect.any(Number), + eventType: expect.any(String), + depth: expect.any(Number), + heapSize: expect.any(Number), + eventId: expect.any(String) }, ` +{ + "AllocationFunction": Any, + "MoudleName": Any, + "depth": Any, + "endTs": Any, + "eventId": Any, + "eventType": Any, + "heapSize": Any, + "startTs": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/MemoryAbilityMonitorStruct.test.ts b/ide/test/trace/bean/MemoryAbilityMonitorStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..af81c3820f56bf057481daf47dd3c13cfe51a121 --- /dev/null +++ b/ide/test/trace/bean/MemoryAbilityMonitorStruct.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { MemoryAbilityMonitorStruct } from '../../../dist/trace/bean/MemoryAbilityMonitorStruct.js'; + +describe('MemoryAbilityMonitorStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxMemoryByte: 200, + value: 50, + }; + + it('MemoryAbilityMonitorStructTest01', function () { + expect(MemoryAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('MemoryAbilityMonitorStructTest02', function () { + expect(MemoryAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/NativeHook.test.ts b/ide/test/trace/bean/NativeHook.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..30a3cffb1f1ac3cf369c9855a22539dfcf57aad7 --- /dev/null +++ b/ide/test/trace/bean/NativeHook.test.ts @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { + NativeHookStatistics, + NativeHookMalloc, + NativeEventHeap, + NativeHookProcess, + NativeHookStatisticsTableData, + NativeMemory, + NativeHookSamplerInfo, + NativeHookSampleQueryInfo, + NativeHookCallInfo, + NativeEvent, +} from '../../../dist/trace/bean/NativeHook.js'; + +describe('NativeHook Test', () => { + it('NativeHookStatisticsTest01', function () { + let nativeHookStatistics = new NativeHookStatistics(); + nativeHookStatistics = { + eventId: 0, + eventType: 'eventType', + subType: 'subType', + heapSize: 0, + addr: 'addr', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + isSelected: false, + }; + expect(nativeHookStatistics).not.toBeUndefined(); + expect(nativeHookStatistics).toMatchInlineSnapshot( +{ + eventId: expect.any(Number), + eventType: expect.any(String), + subType: expect.any(String), + heapSize: expect.any(Number), + addr: expect.any(String), + startTs: expect.any(Number), + endTs: expect.any(Number), + sumHeapSize: expect.any(Number), + max: expect.any(Number), + count: expect.any(Number), + tid: expect.any(Number), + isSelected: expect.any(Boolean) }, ` +{ + "addr": Any, + "count": Any, + "endTs": Any, + "eventId": Any, + "eventType": Any, + "heapSize": Any, + "isSelected": Any, + "max": Any, + "startTs": Any, + "subType": Any, + "sumHeapSize": Any, + "tid": Any, +} +`); + }); + + it('NativeEventHeapTest02', function () { + let nativeHookMalloc = new NativeHookMalloc(); + nativeHookMalloc = { + eventType: 'eventType', + subType: 'subType', + heapSize: 0, + allocByte: 0, + allocCount: 0, + freeByte: 0, + freeCount: 0, + }; + expect(nativeHookMalloc).not.toBeUndefined(); + expect(nativeHookMalloc).toMatchInlineSnapshot( +{ + eventType: expect.any(String), + subType: expect.any(String), + heapSize: expect.any(Number), + allocByte: expect.any(Number), + allocCount: expect.any(Number), + freeByte: expect.any(Number), + freeCount: expect.any(Number) }, ` +{ + "allocByte": Any, + "allocCount": Any, + "eventType": Any, + "freeByte": Any, + "freeCount": Any, + "heapSize": Any, + "subType": Any, +} +`); + }); + + it('NativeEventHeapTest03', function () { + let nativeEventHeap = new NativeEventHeap(); + nativeEventHeap = { + eventType: 'eventType', + sumHeapSize: 0, + }; + expect(nativeEventHeap).not.toBeUndefined(); + expect(nativeEventHeap).toMatchInlineSnapshot( +{ + eventType: expect.any(String), + sumHeapSize: expect.any(Number) }, ` +{ + "eventType": Any, + "sumHeapSize": Any, +} +`); + }); + + it('NativeHookProcessTest04', function () { + let nativeHookProcess = new NativeHookProcess(); + nativeHookProcess = { + ipid: 0, + pid: 0, + name: 'name', + }; + expect(nativeHookProcess).not.toBeUndefined(); + expect(nativeHookProcess).toMatchInlineSnapshot( +{ + ipid: expect.any(Number), + pid: expect.any(Number), + name: expect.any(String) }, ` +{ + "ipid": Any, + "name": Any, + "pid": Any, +} +`); + }); + + it('NativeHookStatisticsTableDataTest05', function () { + let nativeHookStatisticsTableData = new NativeHookStatisticsTableData(); + nativeHookStatisticsTableData = { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 0, + totalCount: 0, + }; + expect(nativeHookStatisticsTableData).not.toBeUndefined(); + expect(nativeHookStatisticsTableData).toMatchInlineSnapshot( +{ + memoryTap: expect.any(String), + existing: expect.any(Number), + existingString: expect.any(String), + allocCount: expect.any(Number), + freeCount: expect.any(Number), + totalBytes: expect.any(Number), + totalBytesString: expect.any(String), + maxStr: expect.any(String), + max: expect.any(Number), + totalCount: expect.any(Number) }, ` +{ + "allocCount": Any, + "existing": Any, + "existingString": Any, + "freeCount": Any, + "max": Any, + "maxStr": Any, + "memoryTap": Any, + "totalBytes": Any, + "totalBytesString": Any, + "totalCount": Any, +} +`); + }); + + it('NativeMemoryTest06', function () { + let nativeMemory = new NativeMemory(); + nativeMemory = { + index: 0, + eventId: 0, + eventType: 'eventType', + subType: 'subType', + addr: 'addr', + startTs: 0, + timestamp: 'timestamp', + heapSize: 0, + heapSizeUnit: 'heapSizeUnit', + symbol: 'symbol', + library: 'library', + isSelected: false, + }; + expect(nativeMemory).not.toBeUndefined(); + expect(nativeMemory).toMatchInlineSnapshot( +{ + index: expect.any(Number), + eventId: expect.any(Number), + eventType: expect.any(String), + subType: expect.any(String), + addr: expect.any(String), + startTs: expect.any(Number), + timestamp: expect.any(String), + heapSize: expect.any(Number), + heapSizeUnit: expect.any(String), + symbol: expect.any(String), + library: expect.any(String), + isSelected: expect.any(Boolean) }, ` +{ + "addr": Any, + "eventId": Any, + "eventType": Any, + "heapSize": Any, + "heapSizeUnit": Any, + "index": Any, + "isSelected": Any, + "library": Any, + "startTs": Any, + "subType": Any, + "symbol": Any, + "timestamp": Any, +} +`); + }); + + it('NativeHookCallInfoTest07', function () { + let nativeHookSamplerInfo = new NativeHookSamplerInfo(); + nativeHookSamplerInfo = { + current: 'current', + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: 'snapshot', + growth: 'growth', + total: 0, + totalGrowth: 'totalGrowth', + existing: 0, + timestamp: 'timestamp', + eventId: -1, + }; + expect(nativeHookSamplerInfo).not.toBeUndefined(); + expect(nativeHookSamplerInfo).toMatchInlineSnapshot( +{ + current: expect.any(String), + currentSize: expect.any(Number), + startTs: expect.any(Number), + heapSize: expect.any(Number), + snapshot: expect.any(String), + growth: expect.any(String), + total: expect.any(Number), + totalGrowth: expect.any(String), + existing: expect.any(Number), + timestamp: expect.any(String), + eventId: expect.any(Number) }, ` +{ + "current": Any, + "currentSize": Any, + "eventId": Any, + "existing": Any, + "growth": Any, + "heapSize": Any, + "snapshot": Any, + "startTs": Any, + "timestamp": Any, + "total": Any, + "totalGrowth": Any, +} +`); + }); + + it('NativeHookCallInfoTest08', function () { + let nativeHookSampleQueryInfo = new NativeHookSampleQueryInfo(); + nativeHookSampleQueryInfo = { + eventId: -1, + current: 0, + eventType: 'eventType', + subType: 'subType', + growth: 0, + existing: 0, + addr: 'addr', + startTs: 0, + endTs: 0, + total: 0, + }; + + expect(nativeHookSampleQueryInfo).not.toBeUndefined(); + expect(nativeHookSampleQueryInfo).toMatchInlineSnapshot( +{ + eventId: expect.any(Number), + current: expect.any(Number), + eventType: expect.any(String), + subType: expect.any(String), + growth: expect.any(Number), + existing: expect.any(Number), + addr: expect.any(String), + startTs: expect.any(Number), + endTs: expect.any(Number), + total: expect.any(Number) }, ` +{ + "addr": Any, + "current": Any, + "endTs": Any, + "eventId": Any, + "eventType": Any, + "existing": Any, + "growth": Any, + "startTs": Any, + "subType": Any, + "total": Any, +} +`); + }); + + it('NativeHookCallInfoTest09', function () { + let nativeHookCallInfo = new NativeHookCallInfo(); + nativeHookCallInfo = { + id: 'id', + pid: 'pid', + library: 'library', + title: 'title', + count: 0, + type: 0, + heapSize: 0, + heapSizeStr: 'heapSizeStr', + eventId: 0, + threadId: 0, + isSelected: false, + }; + expect(nativeHookCallInfo).not.toBeUndefined(); + expect(nativeHookCallInfo).toMatchInlineSnapshot( +{ + id: expect.any(String), + pid: expect.any(String), + library: expect.any(String), + title: expect.any(String), + count: expect.any(Number), + type: expect.any(Number), + heapSize: expect.any(Number), + heapSizeStr: expect.any(String), + eventId: expect.any(Number), + threadId: expect.any(Number), + isSelected: expect.any(Boolean) }, ` +{ + "count": Any, + "eventId": Any, + "heapSize": Any, + "heapSizeStr": Any, + "id": Any, + "isSelected": Any, + "library": Any, + "pid": Any, + "threadId": Any, + "title": Any, + "type": Any, +} +`); + }); + + it('NativeHookCallInfoTest10', function () { + let nativeHookSamplerInfo = new NativeHookSamplerInfo(); + expect(nativeHookSamplerInfo.merageObj(NativeHookSamplerInfo)).toBeUndefined(); + }); + + it('NativeEventHeapTest11', function () { + let nativeEvent = new NativeEvent(); + nativeEvent = { + startTime: 0, + heapSize: 0, + eventType: '', + }; + expect(nativeEvent).not.toBeUndefined(); + expect(nativeEvent).toMatchInlineSnapshot( +{ + startTime: expect.any(Number), + heapSize: expect.any(Number), + eventType: expect.any(String) }, ` +{ + "eventType": Any, + "heapSize": Any, + "startTime": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/NetworkAbilityMonitorStruct.test.ts b/ide/test/trace/bean/NetworkAbilityMonitorStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..158b7f0fa94a90ecba8183f5ef3c12e22d461694 --- /dev/null +++ b/ide/test/trace/bean/NetworkAbilityMonitorStruct.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { NetworkAbilityMonitorStruct } from '../../../dist/trace/bean/NetworkAbilityMonitorStruct.js'; + +describe('NetworkAbilityMonitorStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + + const Sourcedate = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + value: 50, + maxNetworkRate: 50, + }; + + it('NetworkAbilityMonitorStructTest01', function () { + expect(NetworkAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('NetworkAbilityMonitorStructTest02', function () { + expect(NetworkAbilityMonitorStruct.draw(ctx, Sourcedate)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/PerfProfile.test.ts b/ide/test/trace/bean/PerfProfile.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7555a2e011dfed9ec8854aa0d33de2ee4434781a --- /dev/null +++ b/ide/test/trace/bean/PerfProfile.test.ts @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { + PerfFile, + PerfThread, + PerfCallChain, + PerfCallChainMerageData, + PerfSample, + PerfStack, + PerfCall, + PerfCmdLine, +} from '../../../dist/trace/bean/PerfProfile.js'; + +describe('PerfProfile Test', () => { + let perfFile = new PerfFile(); + let perfThread = new PerfThread(); + let perfCallChain = new PerfCallChain(); + let perfCallChainMerageData = new PerfCallChainMerageData(); + let perfSample = new PerfSample(); + let perfStack = new PerfStack(); + let perfCall = new PerfCall(); + let perfCmdLine = new PerfCmdLine(); + + it('PerfFile Test', function () { + perfFile = { + fileId: 0, + symbol: 'symbol', + path: 'path', + fileName: 'fileName', + }; + + expect(perfFile).not.toBeUndefined(); + expect(perfFile).toMatchInlineSnapshot( +{ + fileId: expect.any(Number), + symbol: expect.any(String), + path: expect.any(String), + fileName: expect.any(String) }, ` +{ + "fileId": Any, + "fileName": Any, + "path": Any, + "symbol": Any, +} +`); + }); + + it('PerfThread Test', function () { + perfThread = { + tid: 0, + pid: 0, + threadName: 'threadName', + processName: 'processName', + }; + + expect(perfThread).not.toBeUndefined(); + expect(perfThread).toMatchInlineSnapshot( +{ + tid: expect.any(Number), + pid: expect.any(Number), + threadName: expect.any(String), + processName: expect.any(String) }, ` +{ + "pid": Any, + "processName": Any, + "threadName": Any, + "tid": Any, +} +`); + }); + + it('perfCallChain Test', function () { + perfCallChain = { + tid: 0, + pid: 0, + name: 'name', + fileName: 'fileName', + threadState: 'threadState', + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + parentId: 'parentId', + id: 'id', + topDownMerageId: 'topDownMerageId', + topDownMerageParentId: 'topDownMerageParentId', + bottomUpMerageId: 'bottomUpMerageId', + bottomUpMerageParentId: 'bottomUpMerageParentId', + depth: 0, + }; + + expect(perfCallChain).not.toBeUndefined(); + expect(perfCallChain).toMatchInlineSnapshot( +{ + tid: expect.any(Number), + pid: expect.any(Number), + name: expect.any(String), + fileName: expect.any(String), + threadState: expect.any(String), + startNS: expect.any(Number), + dur: expect.any(Number), + sampleId: expect.any(Number), + callChainId: expect.any(Number), + vaddrInFile: expect.any(Number), + fileId: expect.any(Number), + symbolId: expect.any(Number), + parentId: expect.any(String), + id: expect.any(String), + topDownMerageId: expect.any(String), + topDownMerageParentId: expect.any(String), + bottomUpMerageId: expect.any(String), + bottomUpMerageParentId: expect.any(String), + depth: expect.any(Number) }, ` +{ + "bottomUpMerageId": Any, + "bottomUpMerageParentId": Any, + "callChainId": Any, + "depth": Any, + "dur": Any, + "fileId": Any, + "fileName": Any, + "id": Any, + "name": Any, + "parentId": Any, + "pid": Any, + "sampleId": Any, + "startNS": Any, + "symbolId": Any, + "threadState": Any, + "tid": Any, + "topDownMerageId": Any, + "topDownMerageParentId": Any, + "vaddrInFile": Any, +} +`); + }); + + it('perfCallChain Test', function () { + perfCallChainMerageData = { + id: 'id', + parentId: 'parentId', + symbolName: 'symbolName', + symbol: 'symbol', + libName: 'libName', + self: 'self', + weight: 'weight', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + type: 0, + isSelected: false, + }; + + expect(perfCallChainMerageData).not.toBeUndefined(); + expect(perfCallChainMerageData).toMatchInlineSnapshot( +{ + id: expect.any(String), + parentId: expect.any(String), + symbolName: expect.any(String), + symbol: expect.any(String), + libName: expect.any(String), + self: expect.any(String), + weight: expect.any(String), + selfDur: expect.any(Number), + dur: expect.any(Number), + tid: expect.any(Number), + pid: expect.any(Number), + type: expect.any(Number), + isSelected: expect.any(Boolean) }, ` +{ + "dur": Any, + "id": Any, + "isSelected": Any, + "libName": Any, + "parentId": Any, + "pid": Any, + "self": Any, + "selfDur": Any, + "symbol": Any, + "symbolName": Any, + "tid": Any, + "type": Any, + "weight": Any, +} +`); + }); + + it('perfSample Test', function () { + perfSample = { + sampleId: 0, + time: 0, + timeString: 'timeString', + core: 0, + coreName: 'coreName', + state: 'state', + pid: 0, + processName: 'processName', + tid: 0, + threadName: 'threadName', + depth: 0, + addr: 'addr', + fileId: 0, + symbolId: 0, + }; + expect(perfSample).not.toBeUndefined(); + expect(perfSample).toMatchInlineSnapshot( +{ + sampleId: expect.any(Number), + time: expect.any(Number), + timeString: expect.any(String), + core: expect.any(Number), + coreName: expect.any(String), + state: expect.any(String), + pid: expect.any(Number), + processName: expect.any(String), + tid: expect.any(Number), + threadName: expect.any(String), + depth: expect.any(Number), + addr: expect.any(String), + fileId: expect.any(Number), + symbolId: expect.any(Number) }, ` +{ + "addr": Any, + "core": Any, + "coreName": Any, + "depth": Any, + "fileId": Any, + "pid": Any, + "processName": Any, + "sampleId": Any, + "state": Any, + "symbolId": Any, + "threadName": Any, + "tid": Any, + "time": Any, + "timeString": Any, +} +`); + }); + + it('perfStack Test', function () { + perfStack = { + symbol: '', + path: '', + fileId: 0, + type: 0, + }; + expect(perfStack).not.toBeUndefined(); + expect(perfStack).toMatchInlineSnapshot( +{ + symbol: expect.any(String), + path: expect.any(String), + fileId: expect.any(Number), + type: expect.any(Number) }, ` +{ + "fileId": Any, + "path": Any, + "symbol": Any, + "type": Any, +} +`); + }); + + it('perfCall Test', function () { + perfCall = { + sampleId: 0, + depth: 0, + name: 'name', + }; + expect(perfCall).not.toBeUndefined(); + expect(perfCall).toMatchInlineSnapshot( +{ + sampleId: expect.any(Number), + depth: expect.any(Number), + name: expect.any(String) }, ` +{ + "depth": Any, + "name": Any, + "sampleId": Any, +} +`); + }); + + it('PerfFile Test01', function () { + let perfFile = new PerfFile(); + expect(perfFile.setFileName()).toBeUndefined(); + }); + + it('PerfFile Test02', function () { + let perfFile = new PerfFile(); + let perfF = { + fileId: 0, + symbol: 'symbol', + path: 'path', + fileName: 'fileName', + }; + expect(perfFile.setFileName(perfF)).toBeUndefined(); + }); + + it('PerfCmdLine Test', function () { + perfCmdLine = { + report_value: 'report_value', + }; + expect(perfCmdLine).not.toBeUndefined(); + expect(perfCmdLine).toMatchInlineSnapshot( +{ + report_value: expect.any(String) }, ` +{ + "report_value": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/ProcessMemStruct.test.ts b/ide/test/trace/bean/ProcessMemStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..38a8fd976e39618951ee4649621001bfd315e8bf --- /dev/null +++ b/ide/test/trace/bean/ProcessMemStruct.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { ProcessMemStruct } from '../../../dist/trace/bean/ProcessMemStruct.js'; + +describe('ProcessMemStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + it('ProcessMemStructTest01', function () { + expect(ProcessMemStruct.draw(ctx, data)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/ProcessStruct.test.ts b/ide/test/trace/bean/ProcessStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ca63fee6d77ff056c57a7a0ed524c74910370654 --- /dev/null +++ b/ide/test/trace/bean/ProcessStruct.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { ProcessStruct } from '../../../dist/trace/bean/ProcessStruct.js'; + +describe('ProcessStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + it('ProcessStructTest01', function () { + expect(ProcessStruct.draw(ctx, data)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/bean/SdkSummary.test.ts b/ide/test/trace/bean/SdkSummary.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a27a646646d1c270b6c8ea21f60c5c55235e41a --- /dev/null +++ b/ide/test/trace/bean/SdkSummary.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { CounterSummary, SdkSliceSummary } from '../../../dist/trace/bean/SdkSummary.js'; + +describe('SdkSummary Test', () => { + it('SdkSummaryTest01', function () { + let counterSummary = new CounterSummary(); + counterSummary = { + value: 0, + ts: 0, + counter_id: 0, + }; + expect(counterSummary).not.toBeUndefined(); + expect(counterSummary).toMatchInlineSnapshot( +{ + value: expect.any(Number), + ts: expect.any(Number), + counter_id: expect.any(Number) }, ` +{ + "counter_id": Any, + "ts": Any, + "value": Any, +} +`); + }); + + it('SdkSliceSummaryTest02', function () { + let sdkSliceSummary = new SdkSliceSummary(); + sdkSliceSummary = { + start_ts: 0, + end_ts: 0, + value: 0, + column_id: 0, + slice_message: 'slice_message', + }; + expect(sdkSliceSummary).not.toBeUndefined(); + expect(sdkSliceSummary).toMatchInlineSnapshot( +{ + start_ts: expect.any(Number), + end_ts: expect.any(Number), + value: expect.any(Number), + column_id: expect.any(Number), + slice_message: expect.any(String) }, ` +{ + "column_id": Any, + "end_ts": Any, + "slice_message": Any, + "start_ts": Any, + "value": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/SmapsStruct.test.ts b/ide/test/trace/bean/SmapsStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..99668664e5a9e085c74e6e2aa37ef9364ce5b484 --- /dev/null +++ b/ide/test/trace/bean/SmapsStruct.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { Smaps, SmapsTreeObj } from '../../../dist/trace/bean/SmapsStruct.js'; + +describe('SmapsStruct Test', () => { + it('SmapsStructTest01', function () { + let sMaps = new Smaps(); + sMaps = { + tsNS: -1, + start_addr: 'start_addr', + end_addr: 'end_addr', + permission: 'permission', + path: 'path', + size: 0, + rss: 0, + pss: 0, + reside: 0, + dirty: 0, + swapper: 0, + address: 'address', + type: 'type', + dirtyStr: 'dirtyStr', + swapperStr: 'swapperStr', + rssStr: 'rssStr', + pssStr: 'pssStr', + sizeStr: 'sizeStr', + resideStr: 'resideStr', + }; + expect(sMaps).not.toBeUndefined(); + expect(sMaps).toMatchInlineSnapshot( + { + tsNS: expect.any(Number), + start_addr: expect.any(String), + end_addr: expect.any(String), + permission: expect.any(String), + path: expect.any(String), + size: expect.any(Number), + rss: expect.any(Number), + pss: expect.any(Number), + reside: expect.any(Number), + dirty: expect.any(Number), + swapper: expect.any(Number), + address: expect.any(String), + type: expect.any(String), + dirtyStr: expect.any(String), + swapperStr: expect.any(String), + rssStr: expect.any(String), + pssStr: expect.any(String), + sizeStr: expect.any(String), + resideStr: expect.any(String) + }, ` +{ + "address": Any, + "dirty": Any, + "dirtyStr": Any, + "end_addr": Any, + "path": Any, + "permission": Any, + "pss": Any, + "pssStr": Any, + "reside": Any, + "resideStr": Any, + "rss": Any, + "rssStr": Any, + "size": Any, + "sizeStr": Any, + "start_addr": Any, + "swapper": Any, + "swapperStr": Any, + "tsNS": Any, + "type": Any, +} +` + ); + }); + + it('SmapsStructTest02', function () { + let sMapsTreeObj = new SmapsTreeObj(); + sMapsTreeObj = { + id: 'id', + pid: 'pid', + rsspro: 0, + rssproStr: 'rssproStr', + type: 'type', + reg: 0, + regStr: 'regStr', + path: 'path', + rss: 0, + rssStr: 'rssStr', + dirty: 0, + dirtyStr: 'dirtyStr', + swapper: 0, + swapperStr: 'swapperStr', + pss: 0, + pssStr: 'pssStr', + size: 0, + sizeStr: 'sizeStr', + respro: 0, + resproStr: 'resproStr', + children: [], + }; + expect(sMapsTreeObj).not.toBeUndefined(); + expect(sMapsTreeObj).toMatchInlineSnapshot( +{ + id: expect.any(String), + pid: expect.any(String), + rsspro: expect.any(Number), + rssproStr: expect.any(String), + type: expect.any(String), + reg: expect.any(Number), + regStr: expect.any(String), + path: expect.any(String), + rss: expect.any(Number), + rssStr: expect.any(String), + dirty: expect.any(Number), + dirtyStr: expect.any(String), + swapper: expect.any(Number), + swapperStr: expect.any(String), + pss: expect.any(Number), + pssStr: expect.any(String), + size: expect.any(Number), + sizeStr: expect.any(String), + respro: expect.any(Number), + resproStr: expect.any(String), + children: expect.any(Array) }, ` +{ + "children": Any, + "dirty": Any, + "dirtyStr": Any, + "id": Any, + "path": Any, + "pid": Any, + "pss": Any, + "pssStr": Any, + "reg": Any, + "regStr": Any, + "respro": Any, + "resproStr": Any, + "rss": Any, + "rssStr": Any, + "rsspro": Any, + "rssproStr": Any, + "size": Any, + "sizeStr": Any, + "swapper": Any, + "swapperStr": Any, + "type": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/StateProcessThread.test.ts b/ide/test/trace/bean/StateProcessThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b66d46f431a6959808aed525dc36dd81115f0ba --- /dev/null +++ b/ide/test/trace/bean/StateProcessThread.test.ts @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { + StateProcessThread, + SPTChild, + SPT, + ThreadState, + ThreadProcess, + SptSlice, +} from '../../../dist/trace/bean/StateProcessThread.js'; + +describe('StateProcessThread Test', () => { + it('StateProcessThreadTest01', function () { + let stateProcessThread = new StateProcessThread(); + stateProcessThread = { + id: 'id', + pid: 'pid', + title: 'title', + process: 'process', + processId: -1, + thread: 'thread', + threadId: -1, + state: 'state', + wallDuration: 0, + avgDuration: 'avgDuration', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: 'stdDuration', + }; + expect(stateProcessThread).not.toBeUndefined(); + expect(stateProcessThread).toMatchInlineSnapshot( +{ + id: expect.any(String), + pid: expect.any(String), + title: expect.any(String), + process: expect.any(String), + processId: expect.any(Number), + thread: expect.any(String), + threadId: expect.any(Number), + wallDuration: expect.any(Number), + avgDuration: expect.any(String), + count: expect.any(Number), + minDuration: expect.any(Number), + maxDuration: expect.any(Number), + stdDuration: expect.any(String) }, ` +{ + "avgDuration": Any, + "count": Any, + "id": Any, + "maxDuration": Any, + "minDuration": Any, + "pid": Any, + "process": Any, + "processId": Any, + "state": "state", + "stdDuration": Any, + "thread": Any, + "threadId": Any, + "title": Any, + "wallDuration": Any, +} +`); + }); + + it('SPTChildTest02', function () { + let sptChild = new SPTChild(); + sptChild = { + process: 'process', + processId: 0, + processName: 'processName', + thread: 'thread', + threadId: 0, + threadName: 'threadName', + state: 'state', + startNs: 0, + startTime: 'startTime', + duration: 0, + cpu: 1, + core: 'core', + priority: 0, + prior: 'prior', + note: 'note', + }; + expect(sptChild).not.toBeUndefined(); + expect(sptChild).toMatchInlineSnapshot( +{ + process: expect.any(String), + processId: expect.any(Number), + processName: expect.any(String), + thread: expect.any(String), + threadId: expect.any(Number), + threadName: expect.any(String), + state: expect.any(String), + startNs: expect.any(Number), + startTime: expect.any(String), + duration: expect.any(Number), + cpu: expect.any(Number), + core: expect.any(String), + priority: expect.any(Number), + prior: expect.any(String), + note: expect.any(String) }, ` +{ + "core": Any, + "cpu": Any, + "duration": Any, + "note": Any, + "prior": Any, + "priority": Any, + "process": Any, + "processId": Any, + "processName": Any, + "startNs": Any, + "startTime": Any, + "state": Any, + "thread": Any, + "threadId": Any, + "threadName": Any, +} +` + ); + }); + + it('SPTTest03', function () { + let spt = new SPT(); + spt = { + process: 'process', + processId: 0, + thread: 'thread', + threadId: 0, + state: 'state', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: 'priority', + note: 'note', + }; + expect(spt).not.toBeUndefined(); + expect(spt).toMatchInlineSnapshot( +{ + process: expect.any(String), + processId: expect.any(Number), + thread: expect.any(String), + threadId: expect.any(Number), + state: expect.any(String), + dur: expect.any(Number), + start_ts: expect.any(Number), + end_ts: expect.any(Number), + cpu: expect.any(Number), + priority: expect.any(String), + note: expect.any(String) }, ` +{ + "cpu": Any, + "dur": Any, + "end_ts": Any, + "note": Any, + "priority": Any, + "process": Any, + "processId": Any, + "start_ts": Any, + "state": Any, + "thread": Any, + "threadId": Any, +} +` + ); + }); + + it('ThreadStateTest04', function () { + let threadState = new ThreadState(); + threadState = { + itid: 0, + state: 'state', + dur: 0, + ts: 0, + end_ts: 0, + start_ts: 0, + cpu: 0, + }; + expect(threadState).not.toBeUndefined(); + expect(threadState).toMatchInlineSnapshot( +{ + itid: expect.any(Number), + state: expect.any(String), + dur: expect.any(Number), + ts: expect.any(Number), + end_ts: expect.any(Number), + start_ts: expect.any(Number), + cpu: expect.any(Number) }, ` +{ + "cpu": Any, + "dur": Any, + "end_ts": Any, + "itid": Any, + "start_ts": Any, + "state": Any, + "ts": Any, +} +` + ); + }); + + it('ThreadProcessTest05', function () { + let threadProcess = new ThreadProcess(); + threadProcess = { + id: 0, + threadId: 0, + thread: 'thread', + processId: 0, + process: 'process', + }; + expect(threadProcess).not.toBeUndefined(); + expect(threadProcess).toMatchInlineSnapshot( +{ + id: expect.any(Number), + threadId: expect.any(Number), + thread: expect.any(String), + processId: expect.any(Number), + process: expect.any(String) }, ` +{ + "id": Any, + "process": Any, + "processId": Any, + "thread": Any, + "threadId": Any, +} +` + ); + }); + + it('SptSliceTest06', function () { + let sptSlice = new SptSlice(); + sptSlice = { + itid: 0, + ts: 0, + priority: 0, + }; + expect(sptSlice).not.toBeUndefined(); + expect(sptSlice).toMatchInlineSnapshot( +{ + itid: expect.any(Number), + ts: expect.any(Number), + priority: expect.any(Number) }, ` +{ + "itid": Any, + "priority": Any, + "ts": Any, +} +` + ); + }); + +}); diff --git a/ide/test/trace/bean/ThreadStruct.test.ts b/ide/test/trace/bean/ThreadStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ca61bc4d472d27818815660d1611ead977449cb --- /dev/null +++ b/ide/test/trace/bean/ThreadStruct.test.ts @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { ThreadStruct } from '../../../dist/trace/bean/ThreadStruct.js'; + +describe('ThreadStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + state: '', + }; + const equalsData = { + value: 50, + cpu: 1, + tid: 1, + state: 1, + startTime: 1, + dur: 1, + }; + + it('ThreadStructTest01', function () { + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('ThreadStructTest02', function () { + dataSource.state = 'S'; + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('ThreadStructTest03', function () { + dataSource.state = 'R'; + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('ThreadStructTest04', function () { + dataSource.state = 'D'; + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('ThreadStructTest05', function () { + dataSource.state = 'Running'; + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('ThreadStructTest11', function () { + dataSource.state = 'T' || 't'; + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined(); + }); + + it('ThreadStructTest06', function () { + expect(ThreadStruct.drawString(ctx, '', 2, dataSource.frame)).toBeUndefined(); + }); + + it('ThreadStructTest07', function () { + dataSource.frame.width = 10000000000000000; + expect(ThreadStruct.drawString(ctx, 'ThreadStructTest07', 1, dataSource.frame)).toBeUndefined(); + }); + + it('ThreadStructTest08', function () { + expect(ThreadStruct.equals(equalsData, equalsData)).toBeTruthy(); + }); + + it('ThreadStructTest09', function () { + expect(ThreadStruct.equals([], dataSource)).toBeFalsy(); + }); + + it('ThreadStructTest10', function () { + dataSource.state = 'ThreadStructTest10'; + expect(ThreadStruct.getEndState(1)).toBe('Unknown State'); + }); +}); diff --git a/ide/test/trace/bean/WakeUpTimeBean.test.ts b/ide/test/trace/bean/WakeUpTimeBean.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3dd067c7223f6dd1b30b63d60cfca80d8d6af2b7 --- /dev/null +++ b/ide/test/trace/bean/WakeUpTimeBean.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { WakeUpTimeBean } from '../../../dist/trace/bean/WakeUpTimeBean.js'; + +describe('WakeUpTimeBean Test', () => { + let wakeUpTimeBean = new WakeUpTimeBean(); + it('wakeUpTimeBean', function () { + wakeUpTimeBean = { + wakeTs: 0, + startTs: 0, + preRow: 0, + }; + expect(wakeUpTimeBean).not.toBeUndefined(); + expect(wakeUpTimeBean).toMatchInlineSnapshot( +{ + wakeTs: expect.any(Number), + startTs: expect.any(Number), + preRow: expect.any(Number) }, ` +{ + "preRow": Any, + "startTs": Any, + "wakeTs": Any, +} +`); + }); +}); diff --git a/ide/test/trace/bean/WakeupBean.test.ts b/ide/test/trace/bean/WakeupBean.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8add958a9394a5b04b3cad2cf1651a7493da18ac --- /dev/null +++ b/ide/test/trace/bean/WakeupBean.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { WakeupBean } from '../../../dist/trace/bean/WakeupBean.js'; + +describe('WakeupBean Test', () => { + let wakeUpBean = new WakeupBean(); + it('wakeUpBean', function () { + wakeUpBean = { + wakeupTime: 0, + cpu: 0, + process: '', + pid: 0, + thread: '', + tid: 0, + schedulingLatency: 0, + schedulingDesc: '', + ts: 0, + }; + expect(wakeUpBean).not.toBeUndefined(); + expect(wakeUpBean).toMatchInlineSnapshot( +{ + wakeupTime: expect.any(Number), + cpu: expect.any(Number), + process: expect.any(String), + pid: expect.any(Number), + thread: expect.any(String), + tid: expect.any(Number), + schedulingLatency: expect.any(Number), + schedulingDesc: expect.any(String), + ts: expect.any(Number) }, ` +{ + "cpu": Any, + "pid": Any, + "process": Any, + "schedulingDesc": Any, + "schedulingLatency": Any, + "thread": Any, + "tid": Any, + "ts": Any, + "wakeupTime": Any, +} +`); + }); +}); diff --git a/ide/test/trace/component/DisassemblingWindow.test.ts b/ide/test/trace/component/DisassemblingWindow.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d2671379e0cd95717ddab13facccc49e94a43192 --- /dev/null +++ b/ide/test/trace/component/DisassemblingWindow.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { DisassemblingWindow, Disassembling } from '../../../dist/trace/component/DisassemblingWindow.js'; + +describe('DisassemblingWindow Test', () => { + let disassemblingWindow = new DisassemblingWindow(); + + it('DisassemblingWindowTest01', function () { + expect(disassemblingWindow.getMap('', '')).not.toBeUndefined(); + }); + + it('DisassemblingWindowTest02', function () { + expect(disassemblingWindow.resetCanvas(2, 1, 1, 1)).toBeUndefined(); + }); + + it('DisassemblingWindowTest03', function () { + document.body.innerHTML = + '
'; + let disassemblingWindow = document.querySelector('#ccc') as DisassemblingWindow; + expect(disassemblingWindow.showLoading()).toBeUndefined(); + }); + + it('DisassemblingWindowTest04', function () { + expect(disassemblingWindow.removeCloseListener()).toBeUndefined(); + }); + + it('DisassemblingWindowTest05', function () { + expect(disassemblingWindow.showContent('error', '')).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/SpFilter.test.ts b/ide/test/trace/component/SpFilter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7651918dc9a371256fb8a4d190832ae5acff8f3 --- /dev/null +++ b/ide/test/trace/component/SpFilter.test.ts @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpFilter } from '../../../dist/trace/component/SpFilter.js'; + +describe('SpFilter Test', () => { + let spFilter = new SpFilter(); + + it('SpFilterTest01', function () { + expect(spFilter.initElements()).toBeUndefined(); + }); + + it('SSpFilterTest01', function () { + expect(spFilter.initHtml()).toMatchInlineSnapshot(` +" + +
+ Input Filter + +
+ " +`); + }); +}); diff --git a/ide/test/trace/component/SpInfoAndStas.test.ts b/ide/test/trace/component/SpInfoAndStas.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b37bec93137bf6eb8a837f012ef67af86dc9ca5e --- /dev/null +++ b/ide/test/trace/component/SpInfoAndStas.test.ts @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpInfoAndStats } from '../../../dist/trace/component/SpInfoAndStas.js'; + +describe('SpInfoAndStasTest', () => { + document.body.innerHTML = ``; + let spInfoAndStats = document.querySelector('#ddd') as SpInfoAndStats; + it('SpInfoAndStasTest01', function () { + let spInfoAndStats = new SpInfoAndStats(); + expect(spInfoAndStats.initElements()).toBeUndefined(); + }); + + it('SpInfoAndStasTest03', function () { + spInfoAndStats.initMetricItemData = jest.fn(() => true); + expect(spInfoAndStats.initMetricItemData()).toBeTruthy(); + }); + + it('SpInfoAndStasTest04', function () { + let spInfoAndStats = new SpInfoAndStats(); + expect( + spInfoAndStats.initDataTableStyle({ + children: [ + { + length: 1, + style: { + backgroundColor: 'var(--dark-background5,#F6F6F6)', + }, + }, + ], + }) + ).toBeUndefined(); + }); + + it('SpInfoAndStasTest06 ', function () { + expect(spInfoAndStats.connectedCallback()).toBeUndefined(); + }); + + it('SpInfoAndStasTest07 ', function () { + expect(spInfoAndStats.disconnectedCallback()).toBeUndefined(); + }); + + it('SpInfoAndStasTest08 ', function () { + expect(spInfoAndStats.attributeChangedCallback([], [], [])).toBeUndefined(); + }); + + it('SpInfoAndStasTest05', function () { + expect(spInfoAndStats.initHtml()).toMatchInlineSnapshot(` +" + + +
+ + +
+ " +`); + }); + + it('SpInfoAndStasTest9', function () { + expect(spInfoAndStats.initMetricItemData()).toBeTruthy(); + }); + it('SpInfoAndStasTest10', function () { + expect(spInfoAndStats.initMetricItemData()).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/SpMetrics.test.ts b/ide/test/trace/component/SpMetrics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c0f54dab88549cd99c35eda3e9d0c743984a867 --- /dev/null +++ b/ide/test/trace/component/SpMetrics.test.ts @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpMetrics } from '../../../dist/trace/component/SpMetrics.js'; + +describe('SpMetrics Test', () => { + let spMetrics = new SpMetrics(); + it('SpMetricsTest01', function () { + expect(SpMetrics.initElements).toBeUndefined(); + }); + it('SpMetricsTest02', function () { + expect(spMetrics.metric).toBe(''); + }); + it('SpMetricsTest03', function () { + spMetrics.metric = true; + expect(spMetrics.metric).toBe(''); + }); + it('SpMetricsTest04', function () { + expect(spMetrics.metricResult).toBe(''); + }); + it('SpMetricsTest05', function () { + spMetrics.metricResult = true; + expect(spMetrics.metricResult).toBeTruthy(); + }); + + it('SpMetricsTest06', function () { + expect(spMetrics.attributeChangedCallback('metric')).toBeUndefined(); + }); + + it('SpMetricsTest07', function () { + expect(spMetrics.attributeChangedCallback('metricResult')).toBeUndefined(); + }); + + it('SpMetricsTest08', function () { + expect(spMetrics.initHtml()).toMatchInlineSnapshot(` +" + + +
+
+

Select a metric

+ + + +
+
+ +
+
+ " +`); + }); + + it('SpMetricsTest09', function () { + expect(spMetrics.reset()).toBeUndefined(); + }); + + it('SpMetricsTest10', function () { + expect(spMetrics.connectedCallback()).toBeUndefined(); + }); + + it('SpMetricsTest11', function () { + expect(spMetrics.disconnectedCallback()).toBeUndefined(); + }); + + it('SpMetricsTest12', function () { + expect(spMetrics.initMetricSelectOption()).toBeUndefined(); + }); + + it('SpMetricsTest13', function () { + expect(spMetrics.initMetricDataHandle()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/SpQuerySQL.test.ts b/ide/test/trace/component/SpQuerySQL.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d2fa00f0a4729a7f948eb9bdeba36e60f7d50c9b --- /dev/null +++ b/ide/test/trace/component/SpQuerySQL.test.ts @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpQuerySQL } from '../../../dist/trace/component/SpQuerySQL.js'; +// @ts-ignore +import { queryCustomizeSelect } from '../../../dist/trace/database/SqlLite.js'; +// @ts-ignore +import { SpStatisticsHttpUtil } from '../../../dist/statistics/util/SpStatisticsHttpUtil.js'; +const sqlite = require('../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../dist/trace/database/SqlLite.js'); + +SpStatisticsHttpUtil.addOrdinaryVisitAction = jest.fn(() => true); +describe('SpQuerySQL Test', () => { + let spQuerySQL = new SpQuerySQL(); + + it('SpQuerySQLTest01', function () { + expect(spQuerySQL.checkSupportSqlAbility()).toBeFalsy(); + }); + + it('SpQuerySQLTest02', function () { + expect(spQuerySQL.checkSafetySelectSql()).toBeTruthy(); + }); + + it('SpQuerySQLTest03', function () { + expect(spQuerySQL.getSelectSqlField()).toBe(''); + }); + + it('SpQuerySQLTest04', function () { + expect(spQuerySQL.getSelectSqlTableName()).not.toBeUndefined(); + }); + + it('SpQuerySQLTest05', function () { + expect(spQuerySQL.initDataElement()).toBeUndefined(); + }); + + it('SpQuerySQLTest06', function () { + spQuerySQL.statDataArray.length = 1; + expect(spQuerySQL.initData()).toBeUndefined(); + }); + + it('SpQuerySQLTest07', function () { + expect(spQuerySQL.attributeChangedCallback()).toBeUndefined(); + }); + + it('SpQuerySQLTest08', function () { + expect(spQuerySQL.initHtml()).toMatchInlineSnapshot(` +" + +
+
+

Enter query and press cmd/ctrl + Enter

+ + +
+
+
+

Query result - 0 counts

+
+ + +
+
+
+ +
+
+ " +`); + }); + + it('SpQuerySQLTest09', function () { + expect( + spQuerySQL.initDataTableStyle({ + children: [ + { + length: 3, + style: { + backgroundColor: 'var(--dark-background5,#F6F6F6)', + }, + }, + ], + }) + ).toBeUndefined(); + }); + + it('SpQuerySQLTest010', function () { + expect(spQuerySQL.freshTableHeadResizeStyle()).toBeUndefined(); + }); + + it('SpQuerySQLTest011', function () { + expect(spQuerySQL.reset()).toBeUndefined(); + }); + + it('SpQuerySQLTest012', function () { + let spQuerySQL = new SpQuerySQL(); + expect( + spQuerySQL.initDataTableStyle({ + children: [ + { + length: 1, + style: { + backgroundColor: 'var(--dark-background5,#F6F6F6)', + }, + }, + ], + }) + ).toBeUndefined(); + }); + + it('SpQuerySQLTest013', function () { + expect(spQuerySQL.initDataElement()).toBeUndefined(); + }); + + it('SpQuerySQLTest014', function () { + expect(spQuerySQL.connectedCallback()).toBeUndefined(); + }); + + it('SpQuerySQLTest015', function () { + expect(spQuerySQL.disconnectedCallback()).toBeUndefined(); + }); + + it('SpQuerySQLTest016', function () { + expect(spQuerySQL.initData()).toBeUndefined(); + }); + + it('SpQuerySQLTest017', function () { + expect(spQuerySQL.attributeChangedCallback('', '', '')).toBeUndefined(); + }); + + it('SpQuerySQLTest018', function () { + document.body.innerHTML = ` + + `; + let spQuerySql = document.getElementById('query-sql') as SpQuerySQL; + spQuerySql.queryStr = 'select * from trace_range'; + let range = sqlite.queryCustomizeSelect; + let dataTime: Array = [ + { + start_ts: 1000, + end_ts: 12000, + }, + ]; + range.mockResolvedValue(dataTime); + let keyboardEvent: KeyboardEvent = new KeyboardEvent('keydown', { ctrlKey: true, keyCode: 13 }); + spQuerySql.dispatchEvent(keyboardEvent); + expect(spQuerySQL.attributeChangedCallback('', '', '')).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/SpRecordTrace.test.ts b/ide/test/trace/component/SpRecordTrace.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7303de9e2e2d2b48802de1c427cdd337343b2628 --- /dev/null +++ b/ide/test/trace/component/SpRecordTrace.test.ts @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpRecordTrace } from '../../../dist/trace/component/SpRecordTrace.js'; + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpRecordTrace Test', () => { + document.body.innerHTML = ` + + `; + let spRecordTrace = document.querySelector('#aaa') as SpRecordTrace; + it('SpRecordTraceTest01', function () { + expect(SpRecordTrace.initHtml).not.toBe(''); + }); + + it('SpRecordTraceTest02', function () { + SpRecordTrace.patentNode = jest.fn(() => true); + expect(SpRecordTrace.initElements).toBeUndefined(); + }); + + it('SpRecordTraceTest04', function () { + let traceEvents = (SpRecordTrace.createTraceEvents = [ + 'Scheduling details', + 'CPU Frequency and idle states', + 'High frequency memory', + 'Advanced ftrace config', + 'Syscalls', + 'Board voltages & frequency', + ]); + expect(traceEvents[0].indexOf('binder/binder_lock')).toBe(-1); + }); + + it('SpRecordTraceTest05', function () { + spRecordTrace.spAllocations = jest.fn(() => undefined); + spRecordTrace.spAllocations.appProcess = jest.fn(() => ''); + spRecordTrace.spAllocations.appProcess.indexOf = jest.fn(() => ''); + spRecordTrace.spAllocations.appProcess.lastIndexOf = jest.fn(() => 1); + spRecordTrace.spAllocations.appProcess.slice = jest.fn(() => 1); + expect(spRecordTrace.createNativePluginConfig(1)).toEqual({ + configData: { + blocked: true, + fileName: '', + filterSize: undefined, + fpUnwind: undefined, + mallocFreeMatchingCnt: 1000, + mallocFreeMatchingInterval: 1000, + maxStackDepth: undefined, + pid: 1, + processName: '', + saveFile: false, + smbPages: undefined, + stringCompressed: true, + }, + pluginName: 'nativehook', + sampleInterval: 1000, + }); + }); + + it('SpRecordTraceTest06', function () { + expect(spRecordTrace.createFpsPluginConfig()).not.toBeUndefined(); + }); + it('SpRecordTraceTest07', function () { + expect(spRecordTrace.vs).not.toBeUndefined(); + }); + it('SpRecordTraceTest08', function () { + spRecordTrace.vs = true; + expect(spRecordTrace.vs).toBeTruthy(); + }); + + it('SpRecordTraceTest10', function () { + let devs = { + length: 1, + }; + expect(spRecordTrace.compareArray(devs)).toBeTruthy(); + }); + it('SpRecordTraceTest09', function () { + spRecordTrace.vs = false; + expect(spRecordTrace.vs).toBeFalsy(); + }); + it('SpRecordTraceTest11', function () { + let devs = { + length: 1, + }; + expect(spRecordTrace.compareArray(!devs)).toBeTruthy(); + }); + it('SpRecordTraceTest12', function () { + spRecordTrace.showHint = true; + expect(spRecordTrace.showHint).toBeUndefined(); + }); + it('SpRecordTraceTest13', function () { + spRecordTrace.showHint = false; + expect(spRecordTrace.showHint).toBeUndefined(); + }); + it('SpRecordTraceTest14', function () { + let event = { + isTrusted: true, + device: { + serialNumber: 'string', + }, + }; + expect(spRecordTrace.usbDisConnectionListener(event)).toBeUndefined(); + }); + it('SpRecordTraceTest15', function () { + let traceResult = { + indexOf: jest.fn(() => undefined), + }; + + expect(spRecordTrace.isSuccess(traceResult)).toBe(1); + }); + it('SpRecordTraceTest16', function () { + expect(spRecordTrace.createSessionRequest()).toStrictEqual({ + pluginConfigs: [], + requestId: 1, + sessionConfig: { + buffers: [{ pages: 16384, policy: 0 }], + keepAliveTime: 0, + resultFile: '/data/local/tmp/hiprofiler_data.htrace', + resultMaxSize: 0, + sampleDuration: 30000, + sessionMode: 0, + }, + }); + }); + it('SpRecordTraceTest17', function () { + let that = { + createProcessPlugin: jest.fn(() => undefined), + createCpuPlugin: jest.fn(() => undefined), + createDiskIOPlugin: jest.fn(() => undefined), + createNetworkPlugin: jest.fn(() => undefined), + }; + let request = { + pluginConfigs: { + push: jest.fn(() => undefined), + }, + }; + expect(spRecordTrace.createMonitorPlugin(that, request)).toBeUndefined(); + }); + it('SpRecordTraceTest18', function () { + expect(spRecordTrace.createNetworkPlugin()).toStrictEqual({ + configData: { testFile: '/data/local/tmp/' }, + pluginName: 'network-plugin', + sampleInterval: 1000, + }); + }); + it('SpRecordTraceTest19', function () { + expect(spRecordTrace.createDiskIOPlugin()).toStrictEqual({ + configData: { reportIoStats: 'IO_REPORT' }, + pluginName: 'diskio-plugin', + sampleInterval: 1000, + }); + }); + it('SpRecordTraceTest20', function () { + expect(spRecordTrace.createCpuPlugin()).toStrictEqual({ + configData: { pid: 0, reportProcessInfo: true }, + pluginName: 'cpu-plugin', + sampleInterval: 1000, + }); + }); + it('SpRecordTraceTest21', function () { + expect(spRecordTrace.createProcessPlugin()).toStrictEqual({ + configData: { + report_cpu: true, + report_diskio: true, + report_process_tree: true, + report_pss: true, + }, + pluginName: 'process-plugin', + sampleInterval: 1000, + }); + }); + it('SpRecordTraceTest22', function () { + let traceConfig = { + forEach: jest.fn(() => undefined), + }; + expect(spRecordTrace.createTraceEvents(traceConfig)).toStrictEqual([]); + }); + it('SpRecordTraceTest23', function () { + spRecordTrace.spRecordPerf = jest.fn(() => undefined); + spRecordTrace.spRecordPerf.getPerfConfig = jest.fn(() => undefined); + expect(spRecordTrace.createHiperConfig()).toStrictEqual({ + configData: { + isRoot: false, + outfileName: '/data/local/tmp/perf.data', + recordArgs: '-f undefined -a --cpu-limit undefined -e hw-cpu-cycles --call-stack undefined -j undefined', + }, + pluginName: 'hiperf-plugin', + sampleInterval: NaN, + }); + }); + + it('SpRecordTraceTest24', function () { + expect(spRecordTrace.isSuccess('Signal')).toBe(2); + }); + + it('SpRecordTraceTest25', function () { + expect(spRecordTrace.isSuccess('The device is abnormal')).toBe(-1); + }); + + it('SpRecordTraceTest26', function () { + expect(spRecordTrace.isSuccess('')).toBe(0); + }); + it('SpRecordTraceTest27', function () { + expect(spRecordTrace.synchronizeDeviceList()).toBeUndefined(); + }); + it('SpRecordTraceTest28', function () { + expect(spRecordTrace.freshMenuItemsStatus('Trace command')).toBeUndefined(); + }); + it('SpRecordTraceTest29', function () { + expect(spRecordTrace.buttonDisable(true)).toBeUndefined(); + }); + it('SpRecordTraceTest30', function () { + expect(spRecordTrace.startRefreshDeviceList()).toBeUndefined(); + }); + it('SpRecordTraceTest31', function () { + expect(spRecordTrace.freshConfigMenuDisable(true)).toBeUndefined(); + }); + it('SpRecordTraceTest31', function () { + expect(spRecordTrace.createSdkConfig()).toStrictEqual( + {"configData": {}, "pluginName": "", "sampleInterval": 5000} + ); + }); + it('SpRecordTraceTest32', function () { + expect(spRecordTrace.createHtracePluginConfig()).toStrictEqual( + { + "configData": { + "bufferSizeKb": 2048, + "clock": "boot", + "debugOn": false, + "flushIntervalMs": 1000, + "flushThresholdKb": 4096, + "ftraceEvents": [ + "sched/sched_switch", + "power/suspend_resume", + "sched/sched_wakeup", + "sched/sched_wakeup_new", + "sched/sched_waking", + "sched/sched_process_exit", + "sched/sched_process_free", + "task/task_newtask", + "task/task_rename", + "power/cpu_frequency", + "power/cpu_idle", + ], + "hitraceApps": [], + "hitraceCategories": [ + "ability", + "ace", + "app", + "ark", + "binder", + "disk", + "freq", + "graphic", + "idle", + "irq", + "memreclaim", + "mmc", + "multimodalinput", + "ohos", + "pagecache", + "rpc", + "sched", + "sync", + "window", + "workq", + "zaudio", + "zcamera", + "zimage", + "zmedia", + ], + "hitraceTime": 30, + "parseKsyms": true, + "rawDataPrefix": "", + "traceDurationMs": 0, + "tracePeriodMs": 200, + }, + "pluginName": "ftrace-plugin", + "sampleInterval": 1000, + } + ); + }); + it('SpRecordTraceTest33', function () { + expect(spRecordTrace.createJsHeapConfig()).toStrictEqual( + {"configData": {"capture_numeric_value": true, "interval": 10, "pid": 0, "track_allocations": false, "type": 0}, "pluginName": "js-memory", "sampleInterval": 5000} + ); + }); + it('SpRecordTraceTest34', function () { + expect(spRecordTrace.createMemoryPluginConfig(1,true,true,true)).toStrictEqual( + { + "configData": { + "pid": [ + 0, + ], + "reportAppMemByMemoryService": false, + "reportAppMemInfo": false, + "reportProcessMemInfo": true, + "reportProcessTree": true, + "reportSmapsMemInfo": true, + "reportSysmemMemInfo": true, + "reportSysmemVmemInfo": true, + "sysMeminfoCounters": [ + "PMEM_MEM_TOTAL", + "PMEM_MEM_FREE", + "PMEM_BUFFERS", + "PMEM_CACHED", + "PMEM_SHMEM", + "PMEM_SLAB", + "PMEM_SWAP_TOTAL", + "PMEM_SWAP_FREE", + "PMEM_MAPPED", + "PMEM_VMALLOC_USED", + "PMEM_PAGE_TABLES", + "PMEM_KERNEL_STACK", + "PMEM_ACTIVE", + "PMEM_INACTIVE", + "PMEM_UNEVICTABLE", + "PMEM_VMALLOC_TOTAL", + "PMEM_SLAB_UNRECLAIMABLE", + "PMEM_CMA_TOTAL", + "PMEM_CMA_FREE", + "PMEM_KERNEL_RECLAIMABLE", + ], + "sysVmeminfoCounters": [], + }, + "pluginName": "memory-plugin", + "sampleInterval": 1000, + } + ); + }); + it('SpRecordTraceTest35', function () { + expect(spRecordTrace.createSystemConfig()).toStrictEqual( + {"configData": {"cmdLine": "hiebpf --duration 30 --max_stack_depth 10", "outfileName": "/data/local/tmp/ebpf.data"}, "pluginName": "hiebpf-plugin", "sampleInterval": 1000} + ); + }); + it('SpRecordTraceTest36', function () { + expect(spRecordTrace.createSystemConfig({},1)).toStrictEqual( + {"configData": {"cmdLine": "hiebpf --duration 30 --max_stack_depth 10", "outfileName": "/data/local/tmp/ebpf.data"}, "pluginName": "hiebpf-plugin", "sampleInterval": 1000}); + }); + it('SpRecordTraceTest37', function () { + spRecordTrace.record_template = 'record_template'; + expect(spRecordTrace.record_template).toBeTruthy(); + }); + it('SpRecordTraceTest38', function () { + expect(spRecordTrace.setDeviceVersionSelect(true)).toBe(); + }); + it('SpRecordTraceTest39', function () { + expect(spRecordTrace.recordButtonListener()).toBe(); + }); + it('SpRecordTraceTest40', function () { + let evt = { + isTrusted:true, + device:true + } + expect(spRecordTrace.usbConnectionListener(evt)).toBe(); + }); +}); diff --git a/ide/test/trace/component/SpRecyclerSystemTrace.test.ts b/ide/test/trace/component/SpRecyclerSystemTrace.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c279bcd8f868574848c2d1d7d43ac9a8c97ece8 --- /dev/null +++ b/ide/test/trace/component/SpRecyclerSystemTrace.test.ts @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +jest.mock('../../../dist/trace/component/trace/TimerShaftElement.js', () => { + return {}; +}); + +// @ts-ignore +import { TraceRow } from '../../../dist/trace/component/trace/base/TraceRow.js'; +// @ts-ignore +import { SpRecyclerSystemTrace } from '../../../dist/trace/component/SpRecyclerSystemTrace.js'; + +describe('SpRecyclerSystemTrace Test', () => { + let spRecyclerSystemTrace = new SpRecyclerSystemTrace(); + const newEl = 1; + const targetEl = { + parentNode: 1, + nextSibling: 1, + }; + + spRecyclerSystemTrace.initElements = jest.fn(() => true); + + it('SpRecyclerSystemTraceTest01', function () { + expect(spRecyclerSystemTrace.getScrollWidth()).toBe(1); + }); + + it('SpRecyclerSystemTraceTest02', function () { + let resultLength = spRecyclerSystemTrace.getVisibleRows([{}]).length; + expect(resultLength).toBe(0); + }); + + it('SpRecyclerSystemTraceTest03', function () { + expect(spRecyclerSystemTrace.timerShaftELRangeChange('')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest04', function () { + expect(spRecyclerSystemTrace.rowsElOnScroll('Scroll')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest05', function () { + let htmlElement = document.createElement('div'); + spRecyclerSystemTrace.rangeSelect.rowsPaneEL = htmlElement; + spRecyclerSystemTrace.rangeSelect.MouseDown = jest.fn(() => {}); + expect(spRecyclerSystemTrace.documentOnMouseDown('MouseDown')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest06', function () { + expect(spRecyclerSystemTrace.documentOnMouseUp('MouseUp')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest07', function () { + spRecyclerSystemTrace.rangeSelec = jest.fn(() => true); + spRecyclerSystemTrace.rangeSelect.mouseMove = jest.fn(() => true); + expect(spRecyclerSystemTrace.documentOnMouseMove('MouseMove')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest08', function () { + expect(spRecyclerSystemTrace.hoverStructNull('')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest09', function () { + expect(spRecyclerSystemTrace.selectStructNull('')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest10', function () { + spRecyclerSystemTrace.rangeSelec = jest.fn(() => true); + spRecyclerSystemTrace.rangeSelect.mouseMove = jest.fn(() => true); + expect(spRecyclerSystemTrace.documentOnClick('OnClick')).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest11', function () { + expect(spRecyclerSystemTrace.connectedCallback()).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest12', function () { + expect(spRecyclerSystemTrace.disconnectedCallback()).toBeUndefined(); + }); + + it('SpRecyclerSystemTraceTest13', function () { + expect(spRecyclerSystemTrace.init).toBeTruthy(); + }); + + it('SpRecyclerSystemTraceTest15', function () { + spRecyclerSystemTrace.loadDatabaseUrl = jest.fn(() => true); + expect(spRecyclerSystemTrace.loadDatabaseUrl()).toBeTruthy(); + }); + + it('SpRecyclerSystemTraceTest16', function () { + spRecyclerSystemTrace.loadDatabaseArrayBuffer = jest.fn(() => true); + expect(spRecyclerSystemTrace.loadDatabaseArrayBuffer()).toBeTruthy(); + }); + + it('SpRecyclerSystemTraceTest17', function () { + expect(spRecyclerSystemTrace.initHtml()).toMatchInlineSnapshot(` +" + +
+ + + + + + +
+ " +`); + }); + it('SpRecyclerSystemTraceTest18', function () { + const newEl = 1; + const targetEl = { + parentNode: { + insertBefore: jest.fn(() => true), + }, + nextSibling: 1, + }; + + expect(spRecyclerSystemTrace.insertAfter(newEl, targetEl)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/SpSystemTrace.test.ts b/ide/test/trace/component/SpSystemTrace.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..811b9132b1548751db3ab5d3612be0ff6449f2e0 --- /dev/null +++ b/ide/test/trace/component/SpSystemTrace.test.ts @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpSystemTrace } from '../../../dist/trace/component/SpSystemTrace.js'; +// @ts-ignore +import { TraceRow } from '../../../dist/trace/component/trace/base/TraceRow'; +// @ts-ignore +import { procedurePool } from '../../../dist/trace/database/Procedure.js'; + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpSystemTrace Test', () => { + let spSystemTrace = new SpSystemTrace(); + const offset = 1; + const callback = true; + const rowId = ''; + const rowParentId = ''; + const rowType = ''; + let smooth = true; + + spSystemTrace.initElements = jest.fn(() => true); + + it('SpSystemTraceTest01', function () { + expect(spSystemTrace.getScrollWidth()).toBe(0); + }); + + it('SpSystemTraceTest02', function () { + let resultLength = spSystemTrace.getRowsContentHeight(); + expect(resultLength).toBe(0); + }); + + it('SpSystemTraceTest03', function () { + expect(spSystemTrace.timerShaftELRangeChange('')).toBeUndefined(); + }); + + it('SpSystemTraceTest04', function () { + expect(spSystemTrace.rowsElOnScroll('Scroll')).toBeUndefined(); + }); + + it('SpSystemTraceTest05', function () { + expect(spSystemTrace.documentOnMouseDown('MouseDown')).toBeUndefined(); + }); + + it('SpSystemTraceTest06', function () { + spSystemTrace.timerShaftEL = jest.fn(() => null); + spSystemTrace.timerShaftEL.sportRuler = jest.fn(() => undefined); + spSystemTrace.timerShaftEL.sportRuler.frame = jest.fn(() => ''); + spSystemTrace.timerShaftEL.canvas = jest.fn(() => undefined); + spSystemTrace.timerShaftEL.canvas.offsetLeft = jest.fn(() => 1); + spSystemTrace.timerShaftEL.sportRuler.frame.contains = jest.fn(() => true); + spSystemTrace.documentOnMouseUp = jest.fn(() => true); + expect(spSystemTrace.documentOnMouseUp('MouseUp')).toBeTruthy(); + }); + + it('SpSystemTraceTest07', function () { + spSystemTrace.timerShaftEL = jest.fn(() => undefined); + spSystemTrace.timerShaftEL.isScaling = jest.fn(() => true); + expect(spSystemTrace.documentOnMouseMove('MouseMove')).toBeUndefined(); + }); + + it('SpSystemTraceTest08', function () { + expect(spSystemTrace.hoverStructNull('')).toBeUndefined(); + }); + + it('SpSystemTraceTest09', function () { + expect(spSystemTrace.selectStructNull('')).toBeUndefined(); + }); + + it('SpSystemTraceTest11', function () { + expect(spSystemTrace.connectedCallback()).toBeUndefined(); + }); + + it('SpSystemTraceTest12', function () { + spSystemTrace.timerShaftEL.removeEventListener = jest.fn(() => true); + expect(spSystemTrace.disconnectedCallback()).toBeUndefined(); + }); + + it('SpSystemTraceTest14', function () { + expect(spSystemTrace.loadDatabaseUrl).toBeTruthy(); + }); + + it('SpSystemTraceTest15', function () { + spSystemTrace.rowsPaneEL = jest.fn(() => true); + spSystemTrace.rowsPaneEL.scrollTo = jest.fn(() => offset); + spSystemTrace.rowsPaneEL.removeEventListener = jest.fn(() => true); + spSystemTrace.rowsPaneEL.addEventListener = jest.fn(() => true); + expect(spSystemTrace.rowScrollTo(offset, callback)).toBeUndefined(); + }); + + it('SpSystemTraceTest16', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.onClickHandler()).toBeUndefined(); + }); + + it('SpSystemTraceTest17', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.search()).toBeUndefined(); + }); + + it('SpSystemTraceTest18', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.searchCPU()).not.toBeUndefined(); + }); + + it('SpSystemTraceTest19', function () { + expect(spSystemTrace.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+
+ +
+ +
+
+
+
+ +
+ " +`); + }); + + it('SpSystemTraceTest20', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + // @ts-ignore + TraceRow.range = jest.fn(() => undefined); + TraceRow.range.startNS = jest.fn(() => 1); + spSystemTrace.onClickHandler = jest.fn(() => true); + expect(spSystemTrace.showPreCpuStruct(1, [{ length: 0 }])).toBe(0); + }); + + it('SpSystemTraceTest21', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + // @ts-ignore + TraceRow.range = jest.fn(() => undefined); + TraceRow.range.startNS = jest.fn(() => 1); + spSystemTrace.onClickHandler = jest.fn(() => true); + expect(spSystemTrace.showNextCpuStruct(1, [{ length: 0 }])).toBe(0); + }); + + it('SpSystemTraceTest22', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + procedurePool.clearCache = jest.fn(() => true); + expect(spSystemTrace.reset()).toBeUndefined(); + }); + it('SpSystemTraceTest23', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let structs = [ + { + length: 1, + starttime: 1, + }, + ]; + let previous = 1; + let currentIndex = 1; + TraceRow.range = jest.fn(() => undefined); + TraceRow.range.startNS = jest.fn(() => 1); + expect(spSystemTrace.showStruct(previous, currentIndex, structs)).not.toBeUndefined(); + }); + it('SpSystemTraceTest24', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + TraceRow.range = jest.fn(() => undefined); + TraceRow.range.startNS = jest.fn(() => 1); + expect(spSystemTrace.closeAllExpandRows()).toBeUndefined(); + }); + it('SpSystemTraceTest25', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + spSystemTrace.rowsPaneEL = jest.fn(() => true); + spSystemTrace.rowsPaneEL.scroll = jest.fn(() => true); + expect(spSystemTrace.scrollToProcess()).toBeUndefined(); + }); + it('SpSystemTraceTest26', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + spSystemTrace.rowsPaneEL = jest.fn(() => true); + spSystemTrace.rowsPaneEL.scroll = jest.fn(() => true); + let anomalyTraceRow = TraceRow.skeleton(); + anomalyTraceRow.collect = true; + spSystemTrace.appendChild(anomalyTraceRow); + expect(spSystemTrace.scrollToDepth()).toBeUndefined(); + }); + it('SpSystemTraceTest27', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.searchThreadsAndProcesses()).toStrictEqual([]); + }); + it('SpSystemTraceTest28', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.refreshFavoriteCanvas()).toBeUndefined(); + }); + it('SpSystemTraceTest29', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.expansionAllParentRow({id:1})).toBeUndefined(); + }); + it('SpSystemTraceTest30', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let it = { + name:'', + rowType:'', + rowId:'FileSystemLogicalWrite', + rowParentId:'frameTime' + } + expect(spSystemTrace.createPointEvent(it)).toBe(''); + }); + it('SpSystemTraceTest31', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let a = { + rowEL:{ + translateY:1, + offsetTop:0, + }, + y:1, + offsetY:0 + } + let b = { + rowEL:{ + translateY:1, + offsetTop:0, + }, + y:1, + offsetY:0 + } + expect(spSystemTrace.addPointPair(a,b)).toBeUndefined(); + }); + it('SpSystemTraceTest32', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.setSLiceMark()).toBeUndefined(); + }); + it('SpSystemTraceTest33', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.clickEmptyArea()).toBeUndefined(); + }); + it('SpSystemTraceTest34', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.isWASDKeyPress()).toBeFalsy(); + }); + it('SpSystemTraceTest35', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let endParentRow = { + expansion: true + } + let selectJankStruct = { + frame_type:'frameTime', + type:'', + pid:1, + ts:1, + dur:0, + depth:1, + } + let data = { + frame_type:'frameTime', + type:'', + pid:1, + name:'', + children:{ + frame_type:'frameTime', + pid:1, + length:1 + } + } + expect(spSystemTrace.drawJankLine(endParentRow, selectJankStruct, data)).toBeUndefined(); + }); + it('SpSystemTraceTest36', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let ev = { + maxDuration:1, + timestamp:'' + } + expect(spSystemTrace.sliceMarkEventHandler(ev)).toBeUndefined(); + }); + it('SpSystemTraceTest37', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(spSystemTrace.searchSdk([''],'')).toStrictEqual(['']); + }); + it('SpSystemTraceTest38', function () { + let spSystemTrace = new SpSystemTrace({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let funcStract = { + tid:1, + pid:0, + cookie:'', + funName:'', + type:'', + startTime:2, + depth:1 + } + expect(spSystemTrace.scrollToActFunc(funcStract,true)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/SpWelcomePage.test.ts b/ide/test/trace/component/SpWelcomePage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..760a213c94fc972e7e68d70e5f0f720034b855b4 --- /dev/null +++ b/ide/test/trace/component/SpWelcomePage.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpWelcomePage } from '../../../dist/trace/component/SpWelcomePage.js'; + +describe('SpWelcomePage Test', () => { + let spWelcomePage = new SpWelcomePage(); + + it('SpWelcomePageTest01', function () { + expect(spWelcomePage.initElements()).toBeUndefined(); + }); + + it('SpWelcomePageTest01', function () { + expect(spWelcomePage.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ " +`); + }); +}); diff --git a/ide/test/trace/component/Sptext.test.ts b/ide/test/trace/component/Sptext.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..71df73828b9b973dc638b6296113fbd6359473aa --- /dev/null +++ b/ide/test/trace/component/Sptext.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { SpText } from '../../../dist/trace/component/Sptext.js'; + +describe('Sptext Test', () => { + let sptext = new SpText(); + + it('SptextTest01', function () { + expect(sptext.initElements()).toBeUndefined(); + }); + + it('SptextTest01', function () { + expect(sptext.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + + + +
+
+ " +`); + }); +}); diff --git a/ide/test/trace/component/StackBar.test.ts b/ide/test/trace/component/StackBar.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7651da68a48f3407c1b46fbc248a5e59664c5ee5 --- /dev/null +++ b/ide/test/trace/component/StackBar.test.ts @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { StackBar } from '../../../dist/trace/component/StackBar.js'; + +describe('StackBar Test', () => { + let stackBar = new StackBar(); + + it('StackBarTest01', function () { + expect(stackBar.initHtml()).not.toBe(''); + }); + + it('StackBarTest02', function () { + expect(stackBar.initElements()).toBeUndefined(); + }); + + it('StackBarTest03', function () { + let stateWidth = stackBar.getStateWidth('state'); + let hasWidth = stateWidth > 0; + expect(hasWidth).toBeTruthy(); + }); + + it('StackBarTest04', function () { + let htmlDivElement = stackBar.createBarElement( + { + state: '', + color: '', + value: 0, + }, + 5 + ); + let hasDivEl = htmlDivElement.toLocaleString().length > 5; + expect(hasDivEl).toBeTruthy(); + }); + + it('StackBarTest05', function () { + expect(stackBar.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ " +`); + }); +}); diff --git a/ide/test/trace/component/chart/FrameChart.test.ts b/ide/test/trace/component/chart/FrameChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e20f1284eb70d40219127df532386dc024404b8 --- /dev/null +++ b/ide/test/trace/component/chart/FrameChart.test.ts @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { FrameChart } from '../../../../dist/trace/component/chart/FrameChart.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('FrameChart Test', () => { + let node = [{ children: '' }, { children: { length: 0 } }]; + let node1 = [{ children: '' }, { children: { length: 10 } }]; + let selectData = [(length = 1)]; + document.body.innerHTML = ''; + let frameChart = document.querySelector('#ccc') as FrameChart; + + it('FrameChartTest01', function () { + frameChart.tabPaneScrollTop = false; + expect(frameChart.tabPaneScrollTop).toBeFalsy(); + }); + + it('FrameChartTest02', function () { + expect(frameChart.updateFloatHint()).toBeUndefined(); + }); + + it('FrameChartTest03', function () { + frameChart.calculateChartData = jest.fn(() => true); + frameChart.calMaxDepth = jest.fn(() => true); + expect(frameChart.redrawChart(selectData)).toBeUndefined(); + }); + + it('FrameChartTest05', function () { + let index = frameChart.scale(2); + expect(index).toBe(undefined); + }); + + it('FrameChartTest08', function () { + frameChart.translationDraw = jest.fn(() => true); + expect(frameChart.translation()).toBeUndefined(); + }); + + it('FrameChartTest14', function () { + let frameChart = new FrameChart(); + frameChart.translationDraw = jest.fn(() => true); + expect(frameChart.translation(-1)).toBeUndefined(); + }); + + it('FrameChartTest09', function () { + frameChart.selectTotalCount = false; + expect(frameChart.selectTotalCount).toBeFalsy(); + }); + + it('FrameChartTest11', function () { + let frameChart = new FrameChart(); + frameChart._mode = 1; + frameChart.drawScale = jest.fn(() => true); + expect(frameChart.calculateChartData()).not.toBeUndefined(); + }); + + it('FrameChartTest12', function () { + expect(frameChart.updateCanvas()).toBeUndefined(); + }); + + it('FrameChartTest13', function () { + let frameChart = new FrameChart(); + frameChart.translationDraw = jest.fn(() => true); + frameChart.lastCanvasXInScale = 0; + expect(frameChart.translationByScale()).toBe(undefined); + }); + + it('FrameChartTest21', function () { + let frameChart = new FrameChart(); + frameChart.translationDraw = jest.fn(() => true); + frameChart.canvasX = 4; + frameChart.lastCanvasXInScale = 1; + expect(frameChart.translationByScale()).toBe(undefined); + }); + + it('FrameChartTest22', function () { + let frameChart = new FrameChart(); + frameChart.translationDraw = jest.fn(() => true); + expect(frameChart.translationByScale(1)).toBe(undefined); + }); + it('FrameChartTest211', function () { + expect(frameChart.searchData([], 2, 2)).toBeNull(); + }); + + it('FrameChartTest15', function () { + let frameChart = new FrameChart(); + frameChart.calculateChartData = jest.fn(() => true); + frameChart.xPoint = 1; + expect(frameChart.translationDraw()).toBe(undefined); + }); + + it('FrameChartTest16', function () { + expect(frameChart.onMouseClick({ button: 0 })).toBeUndefined(); + }); + + it('FrameChartTest17', function () { + let frameChart = new FrameChart(); + expect(frameChart.initHtml()).toMatchInlineSnapshot(` +" + + +
" +`); + }); + + it('FrameChartTest18', function () { + let frameChart = new FrameChart(); + expect(frameChart.drawFrameChart(node)).toBeUndefined(); + }); + + it('FrameChartTest20', function () { + expect(frameChart.searchData([], 1, 1)).toBeNull(); + }); + + it('FrameChartTest23', function () { + expect(frameChart.onMouseClick({ button: 2 })).toBeUndefined(); + }); + + it('FrameChartTest24', function () { + document.body.innerHTML = ``; + expect(frameChart.drawScale()).toBeUndefined(); + }); + + it('FrameChartTest25', function () { + let frameChart = new FrameChart(); + frameChart.selectTotalSize = false; + expect(frameChart.selectTotalSize).toBeFalsy(); + }); + + it('FrameChartTest26', function () { + let frameChart = new FrameChart(); + frameChart.maxDepth = false; + expect(frameChart.maxDepth).toBeFalsy(); + }); + + it('FrameChartTest27 ', function () { + let frameChart = new FrameChart(); + expect(frameChart.calMaxDepth(node, 1)).toBeUndefined(); + }); + + it('FrameChartTest28 ', function () { + let frameChart = new FrameChart(); + expect(frameChart.mode).toBeUndefined(); + }); + + it('FrameChartTest29', function () { + let frameChart = new FrameChart(); + frameChart.mode = false; + expect(frameChart.mode).toBeFalsy(); + }); + + it('FrameChartTest30', function () { + frameChart.caldrawArgs = jest.fn(() => true); + expect(frameChart.caldrawArgs()).toBeTruthy(); + }); + + it('FrameChartTest31', function () { + let frameChart = new FrameChart(); + frameChart.data = []; + expect(frameChart.data).toBeFalsy(); + }); + + it('FrameChartTest32', function () { + let frameChart = new FrameChart(); + expect(frameChart.addChartClickListener(() => {})).toBeUndefined(); + }); + + it('FrameChartTest33', function () { + let frameChart = new FrameChart(); + expect(frameChart.removeChartClickListener(() => {})).toBeUndefined(); + }); + + it('FrameChartTest34', function () { + let frameChart = new FrameChart(); + expect(frameChart.calMaxDepth(node1, 10)).toBeUndefined(); + }); + + it('FrameChartTest35', function () { + let frameChart = new FrameChart(); + frameChart.drawTriangleOnScale = jest.fn(() => true); + expect(frameChart.drawTriangleOnScale()).toBeTruthy(); + }); + + it('FrameChartTest36', function () { + frameChart._mode = 1; + frameChart.drawScale = jest.fn(() => true); + expect(frameChart.drawScale()).toBeTruthy(); + }); + + it('FrameChartTest37', function () { + frameChart._mode = 2; + frameChart.drawScale = jest.fn(() => true); + expect(frameChart.drawScale()).toBeTruthy(); + }); + + it('FrameChartTest38', function () { + frameChart._mode = 3; + frameChart.drawScale = jest.fn(() => true); + expect(frameChart.drawScale()).toBeTruthy(); + }); + + it('FrameChartTest39', function () { + expect(frameChart.resetTrans()).toBeUndefined(); + }); + + it('FrameChartTest40', function () { + expect(frameChart.onMouseClick({ button: 2 })).toBeUndefined(); + }); + + it('FrameChartTest41', function () { + expect(frameChart.drawDataSet(node, true)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/chart/PerfDataQuery.test.ts b/ide/test/trace/component/chart/PerfDataQuery.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3435e9eddcb16bfcebab1b11b2f27a2e30360749 --- /dev/null +++ b/ide/test/trace/component/chart/PerfDataQuery.test.ts @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { perfDataQuery } from '../../../../dist/trace/component/chart/PerfDataQuery.js'; + +describe('perfDataQuery Test', () => { + it('perfDataQueryTest01 ', function () { + let callChain = { + symbolId: -1, + fileId: 1, + fileName: 'unkown', + vaddrInFile: 1, + pid: 1, + tid: 1, + canCharge: true, + path: '', + }; + expect(perfDataQuery.setCallChainName(callChain)).toBe('+0x1'); + }); + + it('perfDataQueryTest15 ', function () { + let callChain = { + symbolId: 0, + fileId: 1, + fileName: 'unkown', + vaddrInFile: 1, + }; + expect(perfDataQuery.setCallChainName(callChain)).toBe('+0x1'); + }); + + it('perfDataQueryTest02 ', function () { + let callChain = { + tid: 1, + threadState: '', + bottomUpMerageId: '1', + }; + perfDataQuery.threadData[callChain.tid] = jest.fn(() => []); + perfDataQuery.threadData[callChain.tid].threadName = jest.fn(() => ''); + expect(perfDataQuery.addProcessThreadStateData(callChain)).toBeUndefined(); + }); + + it('perfDataQueryTest03 ', function () { + perfDataQuery.groupNewTreeNoId = jest.fn(() => true); + expect(perfDataQuery.getCallChainsBySampleIds([{ length: 1 }], true)).not.toBeUndefined(); + }); + + it('perfDataQueryTest06 ', function () { + let callChain = [{ name: '' }]; + let currentNode = { + initChildren: [], + id: '', + children: [], + }; + expect(perfDataQuery.merageChildren(currentNode, callChain, true)).toBeUndefined(); + }); + + it('perfDataQueryTest07 ', function () { + perfDataQuery.perfDataQuery = jest.fn(() => true); + expect(perfDataQuery.splitTree([], '', true, true)).toBeUndefined(); + }); + + it('perfDataQueryTest08 ', function () { + expect(perfDataQuery.clearSplitMapData('name')).toBeUndefined(); + }); + + it('perfDataQueryTest09 ', function () { + expect(perfDataQuery.resetAllNode([])).toBeUndefined(); + }); + + it('perfDataQueryTest11 ', function () { + expect(perfDataQuery.findSearchNode([], '')).toBeUndefined(); + }); + + it('perfDataQueryTest14 ', function () { + expect(perfDataQuery.initCallChainBottomUp([])).toBeUndefined(); + }); + + it('perfDataQueryTest17 ', function () { + let callChainsData = [ + { + tid: 0, + pid: 0, + name: '', + fileName: '', + threadState: '', + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + { + tid: 1, + pid: 1, + name: '', + fileName: '', + threadState: '', + startNS: 1, + dur: 1, + sampleId: 1, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + ]; + expect(perfDataQuery.initCallChainBottomUp(callChainsData)).toBeUndefined(); + }); + + it('perfDataQueryTest18 ', function () { + let callChainsData = [ + { + tid: 100, + pid: 100, + name: '', + fileName: '', + threadState: '', + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + { + tid: 111, + pid: 111, + name: '', + fileName: '', + threadState: '', + startNS: 11, + dur: 11, + sampleId: 11, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + { + tid: 222, + pid: 222, + name: '', + fileName: '', + threadState: '', + startNS: 22, + dur: 22, + sampleId: 22, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + ]; + expect(perfDataQuery.initCallChainBottomUp(callChainsData)).toBeUndefined(); + }); + + it('perfDataQueryTest19 ', function () { + let callChainsData = [ + { + tid: 100, + pid: 100, + name: '', + fileName: '', + threadState: '', + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + ]; + expect(perfDataQuery.setCallChainName(callChainsData)).not.toBeUndefined(); + }); + + it('perfDataQueryTest21 ', function () { + perfDataQuery.groupNewTreeNoId = jest.fn(() => true); + let sampleIds = [ + { + tid: 10, + pid: 100, + length: 0, + name: '', + fileName: '', + threadState: '', + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + ]; + expect(perfDataQuery.getCallChainsBySampleIds(sampleIds, true)).not.toBeUndefined(); + }); + + it('perfDataQueryTest12 ', function () { + let callChainsData = [ + { + tid: 100, + pid: 100, + name: '', + fileName: '', + threadState: '', + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: '', + parentId: '', + id: '', + topDownMerageId: '', + topDownMerageParentId: '', + bottomUpMerageId: '', + bottomUpMerageParentId: '', + depth: 0, + previousNode: undefined, + nextNode: undefined, + }, + ]; + + let currentData = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.merageChildren(currentData, callChainsData, true)).toBeUndefined(); + }); + it('perfDataQueryTest14 ', function () { + let node = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.recursionChargeInitTree(node, '', true)).toBeUndefined(); + }); + + it('perfDataQueryTest15 ', function () { + let node = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.recursionChargeTree(node, '', true)).toBeUndefined(); + }); + + it('perfDataQueryTest16 ', function () { + let node = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.recursionPruneInitTree(node, '', true)).toBeUndefined(); + }); + + it('perfDataQueryTest17 ', function () { + let node = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.recursionPruneTree(node, '', true)).toBeUndefined(); + }); + + it('perfDataQueryTest18 ', function () { + let node = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.recursionChargeByRule(node, '', true)).toBeUndefined(); + }); + + it('perfDataQueryTest19 ', function () { + let node = { + id: '', + parentId: '', + currentTreeParentNode: undefined, + symbolName: '', + symbol: '', + libName: '', + path: '', + self: '0s', + weight: '', + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + }; + expect(perfDataQuery.pruneChildren(node, '')).toBeUndefined(); + }); + + it('perfDataQueryTest20 ', function () { + expect(perfDataQuery.clearSplitMapData('')).toBeUndefined(); + }); + it('perfDataQueryTest21 ', function () { + expect(perfDataQuery.clearSearchNode()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpAbilityMonitor.test.ts b/ide/test/trace/component/chart/SpAbilityMonitor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c826ec199ae0ea19d7c0d1d4fe1cd1cf0bd7eb1 --- /dev/null +++ b/ide/test/trace/component/chart/SpAbilityMonitor.test.ts @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpAbilityMonitorChart } from '../../../../dist/trace/component/chart/SpAbilityMonitorChart.js'; +import '../../../../dist/trace/component/chart/SpAbilityMonitorChart.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; +import { + queryCPuAbilityMaxData, + queryMemoryMaxData, + queryNetWorkMaxData, +} from '../../../../src/trace/database/SqlLite.js'; +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('SpAbilityMonitorChart Test', () => { + let MockqueryAbilityExits = sqlit.queryAbilityExits; + MockqueryAbilityExits.mockResolvedValue([ + { + event_name: 'trace_cpu_usage', + stat_type: 'received', + count: 1, + }, + { + event_name: 'sys_memory', + stat_type: 'received', + count: 1, + }, + { + event_name: 'trace_diskio', + stat_type: 'received', + count: 1, + }, + { + event_name: 'trace_diskio', + stat_type: 'received', + count: 1, + }, + ]); + let cpudata = sqlit.queryCPuAbilityMaxData; + cpudata.mockResolvedValue([ + { + totalLoad: 1, + userLoad: 1, + systemLoad: 1, + }, + ]); + let memorydata = sqlit.queryMemoryMaxData; + memorydata.mockResolvedValue([ + { + maxValue: 1, + filter_id: 1, + }, + ]); + + let queryDiskIo = sqlit.queryDiskIoMaxData; + queryDiskIo.mockResolvedValue([ + { + bytesRead: 1, + bytesWrite: 1, + readOps: 1, + writeOps: 1, + }, + ]); + + let netWorkDiskIo = sqlit.queryNetWorkMaxData; + netWorkDiskIo.mockResolvedValue([ + { + maxIn: 1, + maxOut: 1, + maxPacketIn: 1, + maxPacketOut: 1, + }, + ]); + let spSystemTrace = new SpSystemTrace(); + let trace = new SpAbilityMonitorChart(spSystemTrace); + it('SpAbilityMonitorChart01', function () { + trace.init(); + expect(trace).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpChartManager.test.ts b/ide/test/trace/component/chart/SpChartManager.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0547c9c5b8b47e7685622f23ba874a4b43d6cde6 --- /dev/null +++ b/ide/test/trace/component/chart/SpChartManager.test.ts @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 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. + */ + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; + +const sqlite = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +describe('SpChartManager Test', () => { + let chartManager = new SpChartManager(new SpSystemTrace()); + + let queryDataDICT = sqlite.queryDataDICT; + let dataDICT = [ + { + id: 251, + data: 'delay', + }, + { + id: 251, + data: 'caller', + }, + ]; + queryDataDICT.mockResolvedValue(dataDICT); + + it('SpChartManager01', function () {}); +}); diff --git a/ide/test/trace/component/chart/SpClockChart.test.ts b/ide/test/trace/component/chart/SpClockChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..abaffd1d2d21a448e0534be2094e0d6aa3b785e7 --- /dev/null +++ b/ide/test/trace/component/chart/SpClockChart.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +// @ts-ignore +import { SpClockChart } from '../../../../dist/trace/component/chart/SpClockChart.js'; + +const sqlite = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpClockChart Test', () => { + let clockChart = new SpClockChart(new SpChartManager()); + + let queryClock = sqlite.queryClockData; + let queryClockData = [ + { + name: 'Frequency', + num: 20, + }, + { + name: 'State', + num: 10, + }, + { + name: 'ScreenState', + num: 10, + }, + ]; + queryClock.mockResolvedValue(queryClockData); + + it('SpClockChart01', function () { + expect(clockChart.init()).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpCpuChart.test.ts b/ide/test/trace/component/chart/SpCpuChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d97f7a354cf9a6e1aebd97abc14caf61ccd3f5f --- /dev/null +++ b/ide/test/trace/component/chart/SpCpuChart.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +// @ts-ignore +import { SpCpuChart } from '../../../../dist/trace/component/chart/SpCpuChart.js'; +// @ts-ignore +import { HeapNode } from '../../../../dist/js-heap/model/DatabaseStruct.js'; + +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +jest.mock('../../../../dist/js-heap/utils/Utils.js', () => { + return { + HeapNodeToConstructorItem: (node: HeapNode) => {}, + }; +}); +describe('SpCpuChart Test', () => { + let MockqueryCpuMax = sqlit.queryCpuMax; + MockqueryCpuMax.mockResolvedValue([{ cpu: 1 }]); + + let mockCpuSlice = sqlit.queryCpuSchedSlice; + mockCpuSlice.mockResolvedValue([]); + let ss = new SpChartManager(); + let trace = new SpCpuChart(ss); + it('SpMpsChart01', async function () { + await trace.init(); + expect(trace).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpFileSystemChart.test.ts b/ide/test/trace/component/chart/SpFileSystemChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ef9afb517236a549fa36a8fcc91229a14dcb5a0 --- /dev/null +++ b/ide/test/trace/component/chart/SpFileSystemChart.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpFileSystemChart } from '../../../../dist/trace/component/chart/SpFileSystemChart.js'; +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpFileSystemChart Test', () => { + let hasFileSysData = sqlit.hasFileSysData; + hasFileSysData.mockResolvedValue([ + { + fsCount: 2, + vmCount: 2, + ioCount: 0, + }, + ]); + + let ss = new SpChartManager(); + let spFileSystemChart = new SpFileSystemChart(ss); + spFileSystemChart.initFileCallchain = jest.fn(() => true); + it('SpMpsChart01', function () { + spFileSystemChart.init(); + expect(spFileSystemChart).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpFpsChart.test.ts b/ide/test/trace/component/chart/SpFpsChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..95c93a0330875792a902969f3bd4f95c3d2cd5e5 --- /dev/null +++ b/ide/test/trace/component/chart/SpFpsChart.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpFpsChart } from '../../../../dist/trace/component/chart/SpFpsChart.js'; +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; + +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('spFpsChart Test', () => { + let spFpsChart = new SpFpsChart(new SpChartManager()); + let fpsMock = sqlit.getFps; + fpsMock.mockResolvedValue([ + { startNS: 0, fps: 1 }, + { startNS: 2, fps: 3 }, + ]); + + it('spFpsChart01', function () { + expect(spFpsChart.init()).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpFrameTimeChart.test.ts b/ide/test/trace/component/chart/SpFrameTimeChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..872ee45616c505dc31af5c5e960f82b2f7b4278c --- /dev/null +++ b/ide/test/trace/component/chart/SpFrameTimeChart.test.ts @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpFrameTimeChart } from '../../../../dist/trace/component/chart/SpFrameTimeChart.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +const sqlite = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpFrameTimeChart Test', () => { + let spSystemTrace = new SpSystemTrace(); + let spFrameTimeChart = new SpFrameTimeChart(spSystemTrace); + + let queryFrameTime = sqlite.queryFrameTimeData; + let queryFrameTimeData = [ + { + pid: 256, + }, + ]; + queryFrameTime.mockResolvedValue(queryFrameTimeData); + + let queryExpectedFrame = sqlite.queryExpectedFrameDate; + let queryExpectedFrameDate = [ + { + dur: 2585, + depth: 1, + }, + { + dur: 6688, + depth: 1, + }, + ]; + queryExpectedFrame.mockResolvedValue(queryExpectedFrameDate); + + let queryActualFrame = sqlite.queryActualFrameDate; + let queryActualFrameDate = [ + { + dur: 6878, + depth: 1, + }, + { + dur: 6238, + depth: 1, + }, + ]; + queryActualFrame.mockResolvedValue(queryActualFrameDate); + + it('TabPaneFramesTest01', function () { + expect(spFrameTimeChart.init()).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/chart/SpFreqChart.test.ts b/ide/test/trace/component/chart/SpFreqChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bbe6e332155a99f21e7ede500d84ee856c9bf832 --- /dev/null +++ b/ide/test/trace/component/chart/SpFreqChart.test.ts @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +// @ts-ignore +import { SpFreqChart } from '../../../../dist/trace/component/chart/SpFreqChart.js'; + +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('spFpsChart Test', () => { + let spFpsChart = new SpFreqChart(new SpChartManager()); + + let mockGetCpuLimitFreq = sqlit.getCpuLimitFreq; + mockGetCpuLimitFreq.mockResolvedValue([ + { + startNs: 1000, + max: 100, + min: 20, + cpu: 0, + }, + { + startNs: 2000, + max: 300, + min: 100, + cpu: 1, + }, + ]); + + let mockCpuLimitFreqId = sqlit.getCpuLimitFreqId; + mockCpuLimitFreqId.mockResolvedValue([ + { + cpu: 0, + maxFilterId: 2, + minFilterId: 1, + }, + { + cpu: 1, + maxFilterId: 2, + minFilterId: 1, + }, + ]); + + let mockCpuFreqData = sqlit.queryCpuFreqData; + mockCpuFreqData.mockResolvedValue([ + { + cpu: 0, + value: 100, + startNS: 2000, + }, + { + cpu: 1, + value: 100, + startNS: 3000, + }, + ]); + + let mockCpuState = sqlit.queryCpuState; + mockCpuState.mockResolvedValue([ + { + startTs: 1000, + value: 100, + }, + { + startTs: 2000, + value: 10, + }, + ]); + + let queryCpuFreqMock = sqlit.queryCpuFreq; + queryCpuFreqMock.mockResolvedValue([ + { + cpu: 0, + filterId: 1, + }, + { + cpu: 1, + filterId: 2, + }, + ]); + + let queryCpuStateFilter = sqlit.queryCpuStateFilter; + queryCpuStateFilter.mockResolvedValue([ + { + cpu: 0, + filterId: 1, + }, + { + cpu: 1, + filterId: 2, + }, + ]); + + let queryCpuMaxFreqMock = sqlit.queryCpuMaxFreq; + queryCpuMaxFreqMock.mockResolvedValue([{ maxFreq: 100 }]); + + let MockgetCpuLimitFreqId = sqlit.getCpuLimitFreqId; + MockgetCpuLimitFreqId.mockResolvedValue([{ cpu: 1, maxFilterId: 9, minFilterId: 1 }]); + + let MockgetCpuLimitFreqMax = sqlit.getCpuLimitFreqMax; + MockgetCpuLimitFreqMax.mockResolvedValue([{ maxValue: 100, filterId: 9 }]); + + it('spFpsChart01', function () { + expect(spFpsChart.init()).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpHiPerf.test.ts b/ide/test/trace/component/chart/SpHiPerf.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2f86b9b0a750a8181a58403a67a59c7a7804a99 --- /dev/null +++ b/ide/test/trace/component/chart/SpHiPerf.test.ts @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpHiPerf } from '../../../../dist/trace/component/chart/SpHiPerf.js'; +import { + queryHiPerfCpuMergeData2, + queryHiPerfEventList, + queryPerfThread, +} from '../../../../src/trace/database/SqlLite.js'; +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpHiPerf Test', () => { + let queryPerfCmdline = sqlit.queryPerfCmdline; + queryPerfCmdline.mockResolvedValue([ + { + report_value: + 'hiperf record --control prepare -o /data/local/tmp…e sched:sched_waking -a -s dwarf -f 1000 --offcpu', + }, + ]); + + let queryPerfThread = sqlit.queryPerfThread; + queryPerfThread.mockResolvedValue([ + { + tid: 2, + threadName: 'threadName', + pid: 2, + processName: 'processName', + }, + { + tid: 1, + threadName: 'threadName111', + pid: 1, + processName: 'processNam111e', + }, + ]); + + let queryHiPerfEventList = sqlit.queryHiPerfEventList; + queryHiPerfEventList.mockResolvedValue([ + { + id: 0, + report_value: 'sched:sched_waking', + }, + { + id: 1, + report_value: 'sched:sched_switch', + }, + ]); + + let queryHiPerfCpuMergeData2 = sqlit.queryHiPerfCpuMergeData2; + queryHiPerfCpuMergeData2.mockResolvedValue([ + { + id: 0, + callchain_id: 1, + timestamp: 3468360924674, + thread_id: 2469, + event_count: 1, + event_type_id: 0, + timestamp_trace: 3468360965799, + cpu_id: 2, + thread_state: 'Running', + startNS: 0, + }, + { + id: 4, + callchain_id: 1, + timestamp: 3468361000799, + thread_id: 2469, + event_count: 1, + event_type_id: 0, + timestamp_trace: 3468361041924, + cpu_id: 2, + thread_state: 'Running', + startNS: 76125, + }, + { + id: 8, + callchain_id: 1, + timestamp: 3468361045716, + thread_id: 2469, + event_count: 1, + event_type_id: 0, + timestamp_trace: 3468361086841, + cpu_id: 2, + thread_state: 'Running', + startNS: 121042, + }, + { + id: 9, + callchain_id: 4, + timestamp: 3468361054466, + thread_id: 1336, + event_count: 1, + event_type_id: 1, + timestamp_trace: 3468361095591, + cpu_id: 3, + thread_state: 'Suspend', + startNS: 129792, + }, + ]); + let ss = new SpChartManager(); + let spHiPerf = new SpHiPerf(ss); + it('SpHiPerf01', function () { + spHiPerf.init(); + expect(spHiPerf).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpHiSysEventChart.test.ts b/ide/test/trace/component/chart/SpHiSysEventChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d306f943dac5b3cd0fb9aeffbcb378d8647a0cec --- /dev/null +++ b/ide/test/trace/component/chart/SpHiSysEventChart.test.ts @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpHiSysEventChart } from '../../../../dist/trace/component/chart/SpHiSysEventChart.js'; +import '../../../../dist/trace/component/chart/SpHiSysEventChart.js'; +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +import '../../../../dist/trace/component/chart/SpChartManager.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; +import '../../../../dist/trace/component/SpSystemTrace.js'; +// @ts-ignore +import { LitPopover } from '../../../../dist/base-ui/popover/LitPopoverV.js'; +import { + querySystemLocationData, + querySystemLockData, + querySystemSchedulerData, + queryConfigSysEventAppName, +} from '../../../../src/trace/database/SqlLite.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlite = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +describe('SpHiSysEventChart Test', () => { + let ss = new SpChartManager(); + let spHiSysEventChart = new SpHiSysEventChart(ss); + + let htmlDivElement = document.createElement('div'); + htmlDivElement.setAttribute('id', 'appNameList'); + + let anomalyData = sqlite.queryAnomalyData; + anomalyData.mockResolvedValue([]); + + let maxStateValue = sqlite.queryMaxStateValue; + let max = [ + { + maxValue: 200, + type: 'state', + }, + { + maxValue: 300, + type: 'sensor', + }, + ]; + maxStateValue.mockResolvedValue(max); + let MockExits = sqlite.queryHisystemEventExits; + MockExits.mockResolvedValue(['trace_hisys_event']); + let powerData = sqlite.queryPowerData; + let power = [ + { + startNS: 5999127353, + eventName: 'POWER_IDE_AUDIO', + appKey: 'APPNAME', + eventValue: 'com.example.himusicdemo,com.example.himusicdemo_js,com.example.himusicdemo_app', + }, + { + startNS: 5999127353, + eventName: 'POWER_IDE_AUDIO', + appKey: 'BACKGROUND_ENERGY', + eventValue: '854,258,141', + }, + ]; + powerData.mockResolvedValue(power); + + let stateData = sqlite.queryStateData; + stateData.mockResolvedValue([]); + + let sysEventAppName = sqlite.querySyseventAppName; + let appName = [ + { + string_value: 'app_name', + }, + ]; + sysEventAppName.mockResolvedValue(appName); + + let querySystemLocationData = sqlite.querySystemLocationData; + let querySystemLockData = sqlite.querySystemLockData; + let querySystemSchedulerData = sqlite.querySystemSchedulerData; + let queryConfigSysEventAppName = sqlite.queryConfigSysEventAppName; + let location = [ + { + ts: 1005938319, + eventName: 'GNSS_STATE', + appKey: 'TYPE', + Value: '1', + }, + { + ts: 3005933657, + eventName: 'GNSS_STATE', + appKey: 'TAG', + Value: '2', + }, + ]; + + let lock = [ + { + ts: 1005938319, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'TYPE', + Value: '1', + }, + { + ts: 3005933657, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'TAG', + Value: '2', + }, + ]; + + let work = [ + { + ts: 1005938319, + eventName: 'WORK_ADD', + appKey: 'TYPE', + Value: '1', + }, + { + ts: 3005933657, + eventName: 'WORK_STOP', + appKey: 'TAG', + Value: '2', + }, + ]; + + let process = [ + { + process_name: 'process1', + }, + ]; + querySystemLocationData.mockResolvedValue(location); + querySystemLockData.mockResolvedValue(lock); + querySystemSchedulerData.mockResolvedValue(work); + queryConfigSysEventAppName.mockResolvedValue(process); + + it('spHiSysEventChartTest01', function () { + spHiSysEventChart.init(); + expect(SpHiSysEventChart.app_name).toBeUndefined(); + }); + + it('spHiSysEventChartTest02', function () { + let result = [ + { + ts: 1005938319, + eventName: 'WORK_START', + appKey: 'TYPE', + Value: '1', + }, + { + ts: 3005933657, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'TAG,', + Value: 'DUBAI_TAG_RUNNINGLOCK_REMOVE', + }, + { + ts: 4005938319, + eventName: 'GNSS_STATE', + appKey: 'STATE', + Value: 'stop', + }, + { + ts: 5005933657, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'TAG', + Value: 'DUBAI_TAG_RUNNINGLOCK_ADD', + }, + { + ts: 6005938319, + eventName: 'GNSS_STATE', + appKey: 'STATE', + Value: 'start', + }, + { + ts: 9005938319, + eventName: 'WORK_STOP', + appKey: 'TYPE', + Value: '1', + }, + { + ts: 10005938319, + eventName: 'WORK_REMOVE', + appKey: 'TYPE', + Value: '1', + }, + ]; + expect(spHiSysEventChart.getSystemData([result, result, result])).toEqual({ + '0': [ + { count: 1, startNs: 5005933657, token: undefined, type: 1 }, + { count: 0, startNs: 6005938319, token: undefined, type: 1 }, + ], + '1': [ + { count: 1, startNs: 1005938319, state: 'start', type: 2 }, + { count: 2, startNs: 3005933657, state: 'start', type: 2 }, + { count: 1, startNs: 4005938319, state: 'stop', type: 2 }, + { count: 2, startNs: 5005933657, state: 'start', type: 2 }, + { count: 3, startNs: 6005938319, state: 'start', type: 2 }, + { count: 4, startNs: 9005938319, state: 'start', type: 2 }, + { count: 5, startNs: 10005938319, state: 'start', type: 2 }, + ], + '2': [ + { count: 1, startNs: 1005938319, type: 0 }, + { count: 0, startNs: undefined, type: 0 }, + ], + }); + }); + + it('spHiSysEventChartTest03', function () { + expect(spHiSysEventChart.getSystemData([]).length).toBeUndefined(); + }); + + it('spHiSysEventChartTest04', function () { + let result = [ + { + startNS: 5999127353, + eventName: 'POWER_IDE_AUDIO', + appKey: 'APPNAME', + eventValue: 'com.example.himusicdemo,com.example.himusicdemo_js,com.example.himusicdemo_app', + }, + { + startNS: 5999127353, + eventName: 'POWER_IDE_AUDIO', + appKey: 'BACKGROUND_ENERGY', + eventValue: '854,258,141', + }, + { + startNS: 5999127353, + eventName: 'POWER_IDE_BLUETOOTH', + appKey: 'APPNAME', + eventValue: 'com.ohos.settings,bt_switch,bt_switch_js,bt_switch_app', + }, + { + startNS: 5999127353, + eventName: 'POWER_IDE_BLUETOOTH', + appKey: 'BACKGROUND_ENERGY', + eventValue: '76,12,43,431', + }, + { + startNS: 5999127388, + eventName: 'POWER_IDE_CAMERA', + appKey: 'APPNAME', + eventValue: 'com.ohos.camera,com.ohos.camera_app,com.ohos.camera_js,com.ohos.camera_ts', + }, + { + startNS: 5999127388, + eventName: 'POWER_IDE_CAMERA', + appKey: 'BACKGROUND_ENERGY', + eventValue: '375,475,255,963', + }, + ]; + expect(spHiSysEventChart.getPowerData(result)).toStrictEqual(Promise.resolve()); + }); + + it('spHiSysEventChartTest05', function () { + expect(spHiSysEventChart.getPowerData([])).toStrictEqual(Promise.resolve()); + }); + + it('spHiSysEventChartTest6', function () { + expect(spHiSysEventChart.initHtml).toMatchInlineSnapshot(`undefined`); + }); + + it('spHiSysEventChartTest7', function () { + expect(htmlDivElement.onclick).toBe(null); + }); +}); diff --git a/ide/test/trace/component/chart/SpIrqChart.test.ts b/ide/test/trace/component/chart/SpIrqChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0596ab9bfed3da91ef76ed9fd45534ffee0060f9 --- /dev/null +++ b/ide/test/trace/component/chart/SpIrqChart.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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. + */ + +const sqlite = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +// @ts-ignore +import { SpIrqChart } from '../../../../dist/trace/component/chart/SpIrqChart.js'; + +describe('SpIrqChart Test', () => { + let irqChart = new SpIrqChart(new SpChartManager()); + let irqList = sqlite.queryIrqList; + let irqListData = [ + { + name: 'test', + cpu: 0, + }, + ]; + irqList.mockResolvedValue(irqListData); + + it('SpIrqChart01', function () { + expect(irqChart.init()).toBeDefined(); + }); + + it('SpIrqChart02', function () { + expect(irqChart.initFolder()).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpJsMemoryChart.test.ts b/ide/test/trace/component/chart/SpJsMemoryChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..af88e6ec9bfff9de469e0ec70ea6f0d98548243f --- /dev/null +++ b/ide/test/trace/component/chart/SpJsMemoryChart.test.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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. + */ + +const sqlite = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +// @ts-ignore +import { SpJsMemoryChart } from '../../../../dist/trace/component/chart/SpJsMemoryChart.js'; +// @ts-ignore +import { SpIrqChart } from '../../../../dist/trace/component/chart/SpIrqChart.js'; + +describe('SpIrqChart Test', () => { + let spJsMemoryChart = new SpJsMemoryChart(); + let irqList = sqlite.queryIrqList; + let irqListData = [ + { + name: 'test', + cpu: 0, + }, + ]; + irqList.mockResolvedValue(irqListData); + it('SpJsMemoryChart01', function () { + expect(spJsMemoryChart).not.toBe({"initChart": [], "loadJsDatabase": {}, "trace": undefined}); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/chart/SpMpsChart.test.ts b/ide/test/trace/component/chart/SpMpsChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d5b6d1e5a42489bd1846c3517d4ae6f161b8f60 --- /dev/null +++ b/ide/test/trace/component/chart/SpMpsChart.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SmapsChart } from '../../../../dist/trace/component/chart/SmapsChart.js'; +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; + +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('SpMpsChart Test', () => { + let MockquerySmapsExits = sqlit.querySmapsExits; + MockquerySmapsExits.mockResolvedValue([ + { + event_name: 'trace_smaps', + stat_type: 'received', + count: 1, + }, + ]); + + let MockquerySmapsDataMax = sqlit.querySmapsDataMax; + MockquerySmapsDataMax.mockResolvedValue([ + { + max_value: 11111, + }, + ]); + let trace = new SpChartManager(); + let spMapsChart = new SmapsChart(trace); + it('SpMpsChart01', function () { + spMapsChart.init(); + expect(SmapsChart).toBeInstanceOf(Function); + }); +}); diff --git a/ide/test/trace/component/chart/SpNativeMemoryChart.test.ts b/ide/test/trace/component/chart/SpNativeMemoryChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..00f2691bbd90d18e388be87a6e41c41ebced0967 --- /dev/null +++ b/ide/test/trace/component/chart/SpNativeMemoryChart.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; +// @ts-ignore +import { SpNativeMemoryChart } from '../../../../dist/trace/component/chart/SpNativeMemoryChart.js'; + +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('SpNativeMemoryChart Test', () => { + let spNativeMemoryChart = new SpNativeMemoryChart(new SpSystemTrace()); + + let nativeHookProcess = sqlit.queryNativeHookProcess; + nativeHookProcess.mockResolvedValue([ + { + ipid: 0, + pid: 0, + name: 'name', + }, + ]); + + let heapGroupByEvent = sqlit.queryHeapGroupByEvent; + heapGroupByEvent.mockResolvedValue([ + { + eventType: 'AllocEvent', + sumHeapSize: 10, + }, + ]); + + it('SpNativeMemoryChart01', function () { + expect(spNativeMemoryChart.initChart()).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpProcessChart.test.ts b/ide/test/trace/component/chart/SpProcessChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb846111d01156d9d401544d374ccf6698912245 --- /dev/null +++ b/ide/test/trace/component/chart/SpProcessChart.test.ts @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpProcessChart } from '../../../../dist/trace/component/chart/SpProcessChart.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; +import { + getMaxDepthByTid, + queryAllActualData, + queryAllExpectedData, + queryAllJankProcess, +} from '../../../../src/trace/database/SqlLite.js'; +// @ts-ignore +import { SpChartManager } from '../../../../dist/trace/component/chart/SpChartManager.js'; +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpProcessChart Test', () => { + let MockqueryProcessAsyncFunc = sqlit.queryProcessAsyncFunc; + + MockqueryProcessAsyncFunc.mockResolvedValue([ + { + tid: 1, + pid: 2, + threadName: '1', + track_id: 3, + startTs: 1111, + dur: 2000000, + funName: 'func', + parent_id: 4, + id: 5, + cookie: 'ff', + depth: 5, + argsetid: 6, + }, + ]); + let processContentCount = sqlit.queryProcessContentCount; + processContentCount.mockResolvedValue([ + { + pid: 1, + switch_count: 2, + thread_count: 3, + slice_count: 4, + mem_count: 5, + }, + ]); + let queryProcessThreads = sqlit.queryProcessThreads; + queryProcessThreads.mockResolvedValue([ + { + utid: 1, + hasSched: 0, + pid: 3, + tid: 4, + processName: 'process', + threadName: 'thread', + }, + ]); + let queryProcessThreadsByTable = sqlit.queryProcessThreadsByTable; + queryProcessThreadsByTable.mockResolvedValue([ + { + pid: 1, + tid: 0, + processName: 'process', + threadName: 'thread', + }, + ]); + let getAsyncEvents = sqlit.getAsyncEvents; + getAsyncEvents.mockResolvedValue([ + { + pid: 1, + startTime: 100000, + }, + ]); + let queryProcessMem = sqlit.queryProcessMem; + queryProcessMem.mockResolvedValue([ + { + trackId: 1, + trackName: 'trackName', + upid: 2, + pid: 3, + processName: 'processName', + }, + ]); + let queryEventCountMap = sqlit.queryEventCountMap; + queryEventCountMap.mockResolvedValue([ + { + eventName: 'eventName', + count: 1, + }, + ]); + let queryProcess = sqlit.queryProcess; + queryProcess.mockResolvedValue([ + { + pid: 1, + processName: 'processName', + }, + ]); + + let queryProcessByTable = sqlit.queryProcessByTable; + queryProcessByTable.mockResolvedValue([ + { + pid: 2, + processName: 'processName', + }, + ]); + + let getMaxDepthByTid = sqlit.getMaxDepthByTid; + getMaxDepthByTid.mockResolvedValue([ + { + tid: 1, + maxDepth: 1, + }, + { + tid: 2, + maxDepth: 2, + }, + ]); + let queryAllJankProcess = sqlit.queryAllJankProcess; + queryAllJankProcess.mockResolvedValue([ + { + pid: 1, + }, + ]); + + let queryAllExpectedData = sqlit.queryAllExpectedData; + queryAllExpectedData.mockResolvedValue([ + { + id: 41, + ts: 749660047, + name: 1159, + type: 1, + dur: 16657682, + pid: 1242, + cmdline: 'render_service', + }, + { + id: 45, + ts: 766321174, + name: 1160, + type: 1, + dur: 16657682, + pid: 1242, + cmdline: 'render_service', + }, + ]); + + let queryAllActualData = sqlit.queryAllActualData; + queryAllActualData.mockResolvedValue([ + { + id: 40, + ts: 750328000, + name: 1159, + type: 0, + dur: 22925000, + src_slice: '36', + jank_tag: 1, + dst_slice: null, + pid: 1242, + cmdline: 'render_service', + frame_type: 'render_service', + }, + { + id: 44, + ts: 773315000, + name: 1160, + type: 0, + dur: 17740000, + src_slice: '38,42', + jank_tag: 1, + dst_slice: null, + pid: 1242, + cmdline: 'render_service', + frame_type: 'render_service', + }, + ]); + + let spSystemTrace = new SpSystemTrace(); + let spProcessChart = new SpProcessChart(spSystemTrace); + it('SpProcessChart01', function () { + spProcessChart.init(); + expect(spProcessChart).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/chart/SpSdkChart.test.ts b/ide/test/trace/component/chart/SpSdkChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c59db6aab97fa35effad9dea07564defa5ddf55b --- /dev/null +++ b/ide/test/trace/component/chart/SpSdkChart.test.ts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpSdkChart } from '../../../../dist/trace/component/chart/SpSdkChart.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpSdkChart Test', () => { + let spSdkChart = new SpSdkChart(); + let MockStartTime = sqlit.queryStartTime; + MockStartTime.mockResolvedValue([ + { + start_ts: 0, + }, + ]); + it('SpSdkChartTest01', function () { + let showType = { + columns: [{ showType: 'counter' }], + }; + expect(spSdkChart.getTableType(showType)).toBe(''); + }); + + it('SpSdkChartTest02', function () { + expect(spSdkChart.createSliceSql(10, 8, [{ length: 5 }], '')).toBe('select undefined from 8 '); + }); + + it('SpSdkChartTest03', function () { + expect(spSdkChart.createMaxValueSql('', '')).toBe('select max(value) as max_value from '); + }); + + it('SpSdkChartTest04', function () { + expect(spSdkChart.createMaxValueSql('a', 'c')).toBe('select max(value) as max_value from a c'); + }); + + it('SpSdkChartTest06', function () { + expect(spSdkChart.createSql(3, 'c', [{ length: 3 }], 'a')).toBe('select undefined from c a'); + }); + + it('SpSdkChartTest07', function () { + expect(spSdkChart.createSql(0, 'c', [{ length: 3 }], '')).toBe('select undefined from c '); + }); + + it('SpSdkChartTest08', function () { + spSdkChart.init(); + expect(spSdkChart).toBeDefined(); + }); + + it('SpSdkChartTest09', function () { + let showType = { + columns: [{ showType: 'slice' }], + }; + expect(spSdkChart.getTableType(showType)).toBe(''); + }); + + it('SpSdkChartTest10', function () { + let spSystemTrace = new SpSdkChart(); + let sdkChart = new SpSdkChart(spSystemTrace); + let map = new Map(); + let jsonCofigStr = + '{"settingConfig":{"configuration":{"counters":{"enum":["ARM_Mali-TTRx_JS1_ACTIVE","ARM_Mali-TTRx_JS0_ACTIVE","ARM_Mali-TTRx_GPU_ACTIVE","ARM_Mali-TTRx_FRAG_ACTIVE"],\n' + + ' "type":"string"},"stop_gator":{"default":"true","description":"stop_gator","type":"boolean"},"version":{"default":"1","description":"gatordversion","type":"number"}},"name":"mailG77"},\n' + + ' "tableConfig":{"showType":[{"columns":[{"column":"ts","displayName":"TimeStamp","showType":[1,3],"type":"INTEGER"},{"column":"counter_id","displayName":"MonitorValue","showType":[1,3],"type":"INTEGER"},\n' + + ' {"column":"value","displayName":"Value","showType":[1,3],"type":"INTEGER"}],"inner":{"columns":[{"column":"counter_name","displayName":"","showType":[0],"type":"STRING"},\n' + + ' {"column":"counter_id","displayName":"","showType":[0],"type":"INTEGER"}],"tableName":"mock_plugin_counterobj_table"},"tableName":"mock_plugin_counter_table"},\n' + + ' {"columns":[{"column":"start_ts","displayName":"startts","showType":[2,3],"type":"INTEGER"},{"column":"end_ts","displayName":"endts","showType":[2,3],"type":"INTEGER"},\n' + + ' {"column":"slice_id","displayName":"slice_id","showType":[2,3],"type":"INTEGER"},{"column":"value","displayName":"Value","showType":[2,3],"type":"INTEGER"}],\n' + + ' "inner":{"columns":[{"column":"slice_name","displayName":"","showType":[0],"type":"STRING"},{"column":"slice_id","displayName":"","showType":[0],"type":"INTEGER"}],\n' + + ' "tableName":"mock_plugin_sliceobj_table"},"tableName":"mock_plugin_slice_table"}]}}'; + let datamap = { + jsonConfig: jsonCofigStr, + disPlayName: 'common_mock', + pluginName: 'mock-plugin', + }; + map.set('1', datamap); + SpSystemTrace.SDK_CONFIG_MAP = map; + sdkChart.parseJson(58512, map); + }); +}); diff --git a/ide/test/trace/component/chart/SpVirtualMemChart.test.ts b/ide/test/trace/component/chart/SpVirtualMemChart.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9df17945ec0756dada0d50393a06626f526874a --- /dev/null +++ b/ide/test/trace/component/chart/SpVirtualMemChart.test.ts @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpVirtualMemChart } from '../../../../dist/trace/component/chart/SpVirtualMemChart.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../dist/trace/component/SpSystemTrace.js'; +// @ts-ignore +import { TraceRow } from '../../../../dist/trace/component/trace/base/TraceRow.js'; + +const sqlit = require('../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../dist/trace/database/SqlLite.js'); + +const intersectionObserverMock = () => ({ + observe: () => null, +}); +window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('SpVirtualMemChart Test', () => { + let spVirtualMemChart = new SpVirtualMemChart(new SpSystemTrace()); + let MockVirtualMemory = sqlit.queryVirtualMemory; + MockVirtualMemory.mockResolvedValue([ + { + id: 0, + name: 'name', + }, + ]); + + let MockVirtualMemoryData = sqlit.queryVirtualMemoryData; + MockVirtualMemoryData.mockResolvedValue([ + { + startTime: 0, + value: 20, + filterID: 0, + }, + ]); + + it('SpVirtualMemChart01', function () { + spVirtualMemChart.init(); + expect(spVirtualMemChart).toBeDefined(); + }); + + it('SpVirtualMemChart02', function () { + let folder = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen, + }); + spVirtualMemChart.initVirtualMemoryRow(folder, 2, 'name', 2); + expect(spVirtualMemChart).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/metrics/CpuStrategy.test.ts b/ide/test/trace/component/metrics/CpuStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..68a9c926b236f905aa3275f103922e2537e93469 --- /dev/null +++ b/ide/test/trace/component/metrics/CpuStrategy.test.ts @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initTest, initCpuStrategyData } from '../../../../dist/trace/component/metrics/CpuStrategy.js'; + +describe('CpuStrategy Test', () => { + const metricData = [ + { + length: 1, + event_name: 'name', + stat_type: 1, + count: 1, + source: 1, + serverity: 0, + avg_frequency: null, + cpu: 1, + min_freq: '', + max_freq: '', + duration: 1, + process_name: '', + thread_name: '', + }, + ]; + + it('initTestTest01', () => { + expect(initTest(metricData)).toBeTruthy(); + }); + + it('initCpuStrategyDataTest02', () => { + expect(initCpuStrategyData(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/DistributeTermStrategy.test.ts b/ide/test/trace/component/metrics/DistributeTermStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..632af51c348f1fe8f4cfc6dc6c764ef24452245d --- /dev/null +++ b/ide/test/trace/component/metrics/DistributeTermStrategy.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initDistributedTermData } from '../../../../dist/trace/component/metrics/DistributeTermStrategy.js'; + +describe('DistributeTermStrategy Test', () => { + let metricData = [ + { + length: 1, + funName: 'name', + ts: 'ts', + dur: '', + flag: 'fd,fdsf.fds', + trace_name: 'name1', + chainId: '1', + spanId: 'span', + parentSpanId: '', + processId: '', + threadId: '', + threadName: '', + processName: '', + }, + ]; + it('initDistributedTermDataTest01', () => { + expect(initDistributedTermData(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/MemAggStrategy.test.ts b/ide/test/trace/component/metrics/MemAggStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..62017c3a85d5ca50cd016a6a230a2462945cadc3 --- /dev/null +++ b/ide/test/trace/component/metrics/MemAggStrategy.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initMemoryAggStrategy } from '../../../../dist/trace/component/metrics/MemAggStrategy.js'; + +describe('MemAggStrategy Test', () => { + it('initMemoryAggStrategyTest01', () => { + const metricData = [ + { + length: 1, + processName: 'name', + name: 'oom_score_adj', + value: '', + ts: '', + }, + ]; + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest02', () => { + const metricData = [ + { + length: 1, + processName: 'name', + name: 'mem.rss.anon', + value: '', + ts: '', + }, + ]; + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest03', () => { + const metricData = [ + { + length: 1, + processName: 'name', + name: 'mem.swap', + value: '', + ts: '', + }, + ]; + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest04', () => { + const metricData = [ + { + length: 1, + processName: 'name', + name: 'mem.rss.file', + value: '', + ts: '', + }, + ]; + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest05', () => { + const metricData = [ + { + length: 1, + processName: 'name', + name: 'oom_score_adj', + value: '', + ts: '', + }, + ]; + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/MemStrategy.test.ts b/ide/test/trace/component/metrics/MemStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5559fb20344da565f9e5a4f6f4dfb63a52084f0 --- /dev/null +++ b/ide/test/trace/component/metrics/MemStrategy.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initMemoryStrategy } from '../../../../dist/trace/component/metrics/MemStrategy.js'; + +describe('MemStrategy Test', () => { + const metricData = [ + { + length: 1, + minNum: 'name', + maxNum: '', + avgNum: '', + processName: '', + }, + ]; + + it('initMemoryStrategyTest01', () => { + expect(initMemoryStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/MetaDataStrategy.test.ts b/ide/test/trace/component/metrics/MetaDataStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4aeb459ec5cdb07b13a1f139a6a0bf8d838d5ba --- /dev/null +++ b/ide/test/trace/component/metrics/MetaDataStrategy.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initMetaDataStrategy } from '../../../../dist/trace/component/metrics/MetaDataStrategy.js'; + +describe('MetaDataStrategy Test', () => { + const metricData = [ + { + length: 1, + name: 'name', + valueText: '', + }, + ]; + + it('initMetaDataStrategyTest01', () => { + expect(initMetaDataStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/SysCallsStrategy.test.ts b/ide/test/trace/component/metrics/SysCallsStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c4f3e606e9f62ec868ab97890f2e540e3228c93 --- /dev/null +++ b/ide/test/trace/component/metrics/SysCallsStrategy.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initSysCallsStrategy } from '../../../../dist/trace/component/metrics/SysCallsStrategy.js'; + +describe('SysCallsStrategy Test', () => { + const metricData = [ + { + length: 1, + funName: 'name', + maxDur: '', + minDur: '', + avgDur: '', + }, + ]; + + it('initMetaDataStrategyTest01', () => { + expect(initSysCallsStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/SysCallsTopStrategy.test.ts b/ide/test/trace/component/metrics/SysCallsTopStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..43cea5bf6f5480f054348ef3caa9084f5c4b31ad --- /dev/null +++ b/ide/test/trace/component/metrics/SysCallsTopStrategy.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initSysCallsTopStrategy } from '../../../../dist/trace/component/metrics/SysCallsTopStrategy.js'; + +describe('SysCallsTopStrategy Test', () => { + const metricData = [ + { + length: 1, + pid: 'pi', + tid: 'ti', + process_name: '', + maxDur: 'name', + minDur: '', + avgDur: '', + funName: '', + }, + ]; + + it('initSysCallsTopStrategyTest01', () => { + expect(initSysCallsTopStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/TraceStatsStrategy.test.ts b/ide/test/trace/component/metrics/TraceStatsStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f63abbf541cb18e9bd2fa4a67cae155a141528cf --- /dev/null +++ b/ide/test/trace/component/metrics/TraceStatsStrategy.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initTraceStateStrategy } from '../../../../dist/trace/component/metrics/TraceStatsStrategy.js'; + +describe('TraceTaskStrategy Test', () => { + let metricData = [ + { + length: 1, + event_name: 'name', + count: 1, + source: 1, + serverity: 0, + }, + ]; + it('initTraceStateStrategyTest01', () => { + expect(initTraceStateStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/metrics/TraceTaskStrategy.test.ts b/ide/test/trace/component/metrics/TraceTaskStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c47e34adbe7722482eba8dada9d618d976e3271 --- /dev/null +++ b/ide/test/trace/component/metrics/TraceTaskStrategy.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { initTraceTaskStrategy } from '../../../../dist/trace/component/metrics/TraceTaskStrategy.js'; + +describe('TraceTaskStrategy Test', () => { + let metricData = [ + { + length: 1, + process_name: '', + thread_name: '', + pid: 3, + }, + ]; + it('initTraceTaskStrategyTest01', () => { + expect(initTraceTaskStrategy(metricData)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/schedulingAnalysis/CheckCpuSetting.test.ts b/ide/test/trace/component/schedulingAnalysis/CheckCpuSetting.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..71a7d384d446212aee0a1ad61d8bcea8d5a890fd --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/CheckCpuSetting.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { CpuSetting, CheckCpuSetting } from '../../../../dist/trace/component/schedulingAnalysis/CheckCpuSetting.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('CheckCpuSetting Test', () => { + it('CheckCpuSettingTest01', () => { + let cpuSetting = new CpuSetting(); + expect(cpuSetting).not.toBeUndefined(); + }); + it('CheckCpuSettingTest02', () => { + let checkCpuSetting = new CheckCpuSetting(); + expect(checkCpuSetting.init()).toBeUndefined(); + }); + it('CheckCpuSettingTest03', () => { + let checkCpuSetting = new CheckCpuSetting(); + expect(checkCpuSetting.initDefaultSetting()).toBeUndefined(); + }); + it('CheckCpuSettingTest04', () => { + let checkCpuSetting = new CheckCpuSetting(); + let cpuSetting = { + cpu: 1, + big: true, + middle: true, + small: true, + } + expect(checkCpuSetting.createTableLine(cpuSetting)).toBeUndefined(); + }); + it('CheckCpuSettingTest05', () => { + let checkCpuSetting = new CheckCpuSetting(); + expect(checkCpuSetting.createHeaderDiv()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/DrawerCpuTabs.test.ts b/ide/test/trace/component/schedulingAnalysis/DrawerCpuTabs.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d2eb1407a6161d47b62b2fba51465810ce71362 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/DrawerCpuTabs.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { DrawerCpuTabs } from '../../../../dist/trace/component/schedulingAnalysis/DrawerCpuTabs.js'; +import crypto from "crypto"; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('DrawerCpuTabs Test', () => { + it('DrawerCpuTabsTest01', () => { + let drawerCpuTabs = new DrawerCpuTabs(); + expect(drawerCpuTabs.init(1,'1')).not.toBe(0); + }); + it('DrawerCpuTabsTest02', () => { + let drawerCpuTabs = new DrawerCpuTabs(); + drawerCpuTabs.init(1,'2'); + expect(drawerCpuTabs.cpuNumber).toEqual(1); + }); + it('DrawerCpuTabsTest03', () => { + let drawerCpuTabs = new DrawerCpuTabs(); + drawerCpuTabs.init(1,'3'); + expect(drawerCpuTabs.cpuNumber).toEqual(1); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/SpSchedulingAnalysis.test.ts b/ide/test/trace/component/schedulingAnalysis/SpSchedulingAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..716e55c5b1f0aa1914430b7ad44e8faa1c7607b8 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/SpSchedulingAnalysis.test.ts @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { SpSchedulingAnalysis } from '../../../../dist/trace/component/schedulingAnalysis/SpSchedulingAnalysis.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('SpSchedulingAnalysis Test', () => { + it('SpSchedulingAnalysisTest01', () => { + let spSchedulingAnalysis = new SpSchedulingAnalysis(); + expect(spSchedulingAnalysis.init()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/TabCpuAnalysis.test.ts b/ide/test/trace/component/schedulingAnalysis/TabCpuAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e1db2de16c7e3b2e63e5c10596ea20ecc687886 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/TabCpuAnalysis.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabCpuAnalysis } from '../../../../dist/trace/component/schedulingAnalysis/TabCpuAnalysis.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('TabCpuAnalysis Test', () => { + it('TabCpuAnalysisTest01', () => { + let tabCpuAnalysis = new TabCpuAnalysis(); + expect(tabCpuAnalysis).not.toBeUndefined(); + }); + it('TabCpuAnalysisTest04', () => { + let tabCpuAnalysis = new TabCpuAnalysis(); + tabCpuAnalysis.queryLogicWorker = jest.fn(); + expect(tabCpuAnalysis.queryLogicWorker('','',{})).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.test.ts b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..22a6931a65bb2d9abdf763beb186512e701db1e4 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabCpuDetailsFrequency } from '../../../../dist/trace/component/schedulingAnalysis/TabCpuDetailsFrequency.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('SpSchedulingAnalysis Test', () => { + it('SpSchedulingAnalysisTest01', () => { + let tabCpuDetailsFrequency = new TabCpuDetailsFrequency(); + expect(tabCpuDetailsFrequency.clearData()).toBeUndefined(); + }); + it('SpSchedulingAnalysisTest02', () => { + let tabCpuDetailsFrequency = new TabCpuDetailsFrequency(); + expect( + tabCpuDetailsFrequency.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsIdle.test.ts b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsIdle.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4694a10b98a8b71e677d7b13ad4a17a88aa3c8c --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsIdle.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabCpuDetailsIdle } from '../../../../dist/trace/component/schedulingAnalysis/TabCpuDetailsIdle.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('TabCpuDetailsIdle Test', () => { + it('TabCpuDetailsIdleTest01', () => { + let tabCpuDetailsIdle = new TabCpuDetailsIdle(); + expect(tabCpuDetailsIdle.clearData()).toBeUndefined(); + }); + it('TabCpuDetailsIdleTest02', () => { + let tabCpuDetailsIdle = new TabCpuDetailsIdle(); + expect( + tabCpuDetailsIdle.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsIrq.test.ts b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsIrq.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9cf49385cad9dad224dfb77146f05ba709c6e0a4 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsIrq.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabCpuDetailsIrq } from '../../../../dist/trace/component/schedulingAnalysis/TabCpuDetailsIrq.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('TabCpuDetailsIrq Test', () => { + it('TabCpuDetailsIrqTest01', () => { + let tabCpuDetailsIrq = new TabCpuDetailsIrq(); + expect(tabCpuDetailsIrq.clearData()).toBeUndefined(); + }); + it('TabCpuDetailsIrqTest02', () => { + let tabCpuDetailsIrq = new TabCpuDetailsIrq(); + expect( + tabCpuDetailsIrq.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsThreads.test.ts b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsThreads.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5ce366b883cb3756d7c072faebde23dc08698dc --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/TabCpuDetailsThreads.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabCpuDetailsThreads } from '../../../../dist/trace/component/schedulingAnalysis/TabCpuDetailsThreads.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('TabCpuDetailsThreads Test', () => { + it('TabCpuDetailsThreadsTest01', () => { + let tabCpuDetailsThreads = new TabCpuDetailsThreads(); + expect( + tabCpuDetailsThreads.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + it('TabCpuDetailsThreadsTest02', () => { + let tabCpuDetailsThreads = new TabCpuDetailsThreads(); + let data = [ + { + pid: 1, + pName: 1, + tid: 2, + tName: '', + total: 1, + size: 'middle core', + no: '', + timeStr: '', + } + ] + tabCpuDetailsThreads.table.reMeauseHeight = jest.fn(); + expect(tabCpuDetailsThreads.queryPieChartDataByType(data)).toBeUndefined(); + }); + it('TabCpuDetailsThreadsTest02', () => { + let tabCpuDetailsThreads = new TabCpuDetailsThreads(); + tabCpuDetailsThreads.init = jest.fn(); + expect(tabCpuDetailsThreads.init(1,{})).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/TabThreadAnalysis.test.ts b/ide/test/trace/component/schedulingAnalysis/TabThreadAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1a3b38e7e03559e80220bff9342c15bc45a8c9af --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/TabThreadAnalysis.test.ts @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabThreadAnalysis } from '../../../../dist/trace/component/schedulingAnalysis/TabThreadAnalysis.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('TabThreadAnalysis Test', () => { + it('TabThreadAnalysisTest01', () => { + let tabThreadAnalysis = new TabThreadAnalysis(); + expect(tabThreadAnalysis.init()).toBeUndefined(); + }); + it('TabThreadAnalysisTest02', () => { + let tabThreadAnalysis = new TabThreadAnalysis(); + expect(tabThreadAnalysis.hideCurrentTab()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/Top20FrequencyThread.test.ts b/ide/test/trace/component/schedulingAnalysis/Top20FrequencyThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..53c9a7c76c132c76d18f479e933c40f715e698c9 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/Top20FrequencyThread.test.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { Top20FrequencyThread } from '../../../../dist/trace/component/schedulingAnalysis/Top20FrequencyThread.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('Top20FrequencyThread Test', () => { + it('Top20FrequencyThreadTest01', () => { + let top20FrequencyThread = new Top20FrequencyThread(); + expect(top20FrequencyThread).not.toBeUndefined(); + }); + it('Top20FrequencyThreadTest02', () => { + let top20FrequencyThread = new Top20FrequencyThread(); + expect( + top20FrequencyThread.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + it('Top20FrequencyThreadTest03', () => { + let top20FrequencyThread = new Top20FrequencyThread(); + top20FrequencyThread.queryLogicWorker = jest.fn(); + expect(top20FrequencyThread.queryData()).toBeUndefined(); + }); + it('Top20FrequencyThreadTest04', () => { + let top20FrequencyThread = new Top20FrequencyThread(); + top20FrequencyThread.queryLogicWorker = jest.fn(); + let res = [ + { + length:21, + time:'', + totalDur:1 + } + ] + expect(top20FrequencyThread.getPieChartData(res)).toStrictEqual([{"length": 21, "time": "", "totalDur": 1}]); + }); + it('Top20FrequencyThreadTest05', () => { + let top20FrequencyThread = new Top20FrequencyThread(); + top20FrequencyThread.queryLogicWorker = jest.fn(); + expect(top20FrequencyThread.queryLogicWorker('','',{})).toBeUndefined(); + }); + it('Top20FrequencyThreadTest06', () => { + let top20FrequencyThread = new Top20FrequencyThread(); + top20FrequencyThread.init = jest.fn(); + expect(top20FrequencyThread.init()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.test.ts b/ide/test/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c97121f96214410e2aba814d5f138a5f08996f9e --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { Top20ProcessSwitchCount } from '../../../../dist/trace/component/schedulingAnalysis/Top20ProcessSwitchCount.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('Top20ProcessSwitchCount Test', () => { + it('Top20ProcessSwitchCountTest01', () => { + let top20ProcessSwitchCount = new Top20ProcessSwitchCount(); + expect(top20ProcessSwitchCount).not.toBeUndefined(); + }); + it('Top20ProcessSwitchCountTest02', () => { + let top20ProcessSwitchCount = new Top20ProcessSwitchCount(); + expect( + top20ProcessSwitchCount.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + it('Top20ProcessSwitchCountTest03', () => { + let top20ProcessSwitchCount = new Top20ProcessSwitchCount(); + top20ProcessSwitchCount.queryLogicWorker = jest.fn(); + expect(top20ProcessSwitchCount.queryLogicWorker('','',{})).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/Top20ProcessThreadCount.test.ts b/ide/test/trace/component/schedulingAnalysis/Top20ProcessThreadCount.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c51a9631d10f76a210776a14039248030317c115 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/Top20ProcessThreadCount.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { Top20ProcessThreadCount } from '../../../../dist/trace/component/schedulingAnalysis/Top20ProcessThreadCount.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('Top20ProcessSwitchCount Test', () => { + it('Top20ProcessSwitchCountTest01', () => { + let top20ProcessThreadCount = new Top20ProcessThreadCount(); + expect(top20ProcessThreadCount).not.toBeUndefined(); + }); + it('Top20ProcessSwitchCountTest02', () => { + let top20ProcessThreadCount = new Top20ProcessThreadCount(); + expect( + top20ProcessThreadCount.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + it('Top20ProcessSwitchCountTest03', () => { + let top20ProcessThreadCount = new Top20ProcessThreadCount(); + top20ProcessThreadCount.queryLogicWorker = jest.fn(); + expect(top20ProcessThreadCount.queryLogicWorker('','',{})).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.test.ts b/ide/test/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c9e897f6f829801aca7d41835126e3f39803ecc --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.test.ts @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { Top20ThreadCpuUsage } from '../../../../dist/trace/component/schedulingAnalysis/Top20ThreadCpuUsage.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('Top20ThreadCpuUsage Test', () => { + it('Top20ThreadCpuUsageTest01', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + expect(top20ThreadCpuUsage).not.toBeUndefined(); + }); + it('Top20ThreadCpuUsageTest02', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + let data = [ + { + pid: 1, + pName: 1, + tid: 2, + tName: '', + total: 1, + size: 'middle core', + no: '', + timeStr: '', + } + ] + expect(top20ThreadCpuUsage.sortByColumn({key: 'bigTimeStr'},{},data)).toBeUndefined(); + }); + it('Top20ThreadCpuUsageTest03', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + top20ThreadCpuUsage.queryLogicWorker = jest.fn(); + expect(top20ThreadCpuUsage.queryData()).toBeUndefined(); + }); + it('Top20ThreadCpuUsageTest04', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + let data = [ + { + pid: 1, + pName: 1, + tid: 2, + tName: '', + total: 1, + size: 'middle core', + no: '', + timeStr: '', + } + ] + expect(top20ThreadCpuUsage.getArrayDataBySize('total',data)).toStrictEqual( + [{"no": "", "pName": 1, "pid": 1, "size": "big core", "tName": "", "tid": 2, "timeStr": undefined, "total": undefined}, {"no": "", "pName": 1, "pid": 1, "size": "middle core", "tName": "", "tid": 2, "timeStr": undefined, "total": undefined}, {"no": "", "pName": 1, "pid": 1, "size": "small core", "tName": "", "tid": 2, "timeStr": undefined, "total": undefined}] + ); + }); + it('Top20ThreadCpuUsageTest05', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + let data = [ + { + pid: 1, + pName: 1, + tid: 2, + tName: '', + total: 1, + size: 'middle core', + no: '', + timeStr: '', + } + ] + expect(top20ThreadCpuUsage.sortByColumn({key: 'midTimeStr'},{},data)).toBeUndefined(); + }); + it('Top20ThreadCpuUsageTest06', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + let data = [ + { + pid: 1, + pName: 1, + tid: 2, + tName: '', + total: 1, + size: 'middle core', + no: '', + timeStr: '', + } + ] + expect(top20ThreadCpuUsage.sortByColumn({key: 'smallTimeStr'},{},data)).toBeUndefined(); + }); + it('Top20ThreadCpuUsageTest07', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + let data = [ + { + pid: 1, + pName: 1, + tid: 2, + tName: '', + total: 1, + size: 'middle core', + no: '', + timeStr: '', + } + ] + expect(top20ThreadCpuUsage.sortByColumn({key: 'bigPercent'},{},data)).toBeUndefined(); + }); + it('Top20ThreadCpuUsageTest08', () => { + let top20ThreadCpuUsage = new Top20ThreadCpuUsage(); + top20ThreadCpuUsage.queryLogicWorker = jest.fn(); + expect(top20ThreadCpuUsage.queryLogicWorker('','',{})).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/schedulingAnalysis/Top20ThreadRunTime.test.ts b/ide/test/trace/component/schedulingAnalysis/Top20ThreadRunTime.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..aab3af83c011c973f5d4b67c8fbd3abb4960f8e5 --- /dev/null +++ b/ide/test/trace/component/schedulingAnalysis/Top20ThreadRunTime.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { Top20ThreadRunTime } from '../../../../dist/trace/component/schedulingAnalysis/Top20ThreadRunTime.js'; +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('Top20ThreadRunTime Test', () => { + it('Top20ThreadRunTimeTest01', () => { + let top20ThreadRunTime = new Top20ThreadRunTime(); + expect(top20ThreadRunTime).not.toBeUndefined(); + }); + it('Top20ThreadRunTimeTest02', () => { + let top20ThreadRunTime = new Top20ThreadRunTime(); + expect( + top20ThreadRunTime.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + it('Top20ThreadRunTimeTest03', () => { + let top20ThreadRunTime = new Top20ThreadRunTime(); + top20ThreadRunTime.queryLogicWorker = jest.fn(); + expect(top20ThreadRunTime.queryLogicWorker('','',{})).toBeUndefined(); + }); + it('Top20ThreadRunTimeTest04', () => { + let top20ThreadRunTime = new Top20ThreadRunTime(); + top20ThreadRunTime.queryLogicWorker = jest.fn(); + top20ThreadRunTime.init = jest.fn(); + expect(top20ThreadRunTime.init()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/setting/SpAllocations.test.ts b/ide/test/trace/component/setting/SpAllocations.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0108aedcba726982f577fda15621b1480526a846 --- /dev/null +++ b/ide/test/trace/component/setting/SpAllocations.test.ts @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpAllocations } from '../../../../dist/trace/component/setting/SpAllocations.js'; + +describe('SpAllocations Test', () => { + beforeAll(() => { + document.body.innerHTML = ` + + `; + }); + + it(' SpAllocations get Default attrValue', function () { + let spEle = document.querySelector('#sp') as SpAllocations; + spEle.unwindEL = jest.fn(() => true); + spEle.unwindEL.value = jest.fn(() => true); + spEle.shareMemory = jest.fn(() => true); + spEle.shareMemory.value = jest.fn(() => true); + spEle.shareMemoryUnit = jest.fn(() => true); + spEle.shareMemoryUnit.value = jest.fn(() => true); + spEle.filterMemory = jest.fn(() => true); + spEle.filterMemory.value = jest.fn(() => true); + spEle.filterMemoryUnit = jest.fn(() => true); + spEle.filterMemoryUnit.value = jest.fn(() => true); + expect(spEle.pid).toEqual(undefined); + expect(spEle.unwind).toBeNaN(); + expect(spEle.shared).toBe(16384); + expect(spEle.filter).toBeNaN(); + }); + + it(' SpAllocations set attrValue', function () { + let spEle = document.querySelector('#sp') as SpAllocations; + spEle.processId.value = '2'; + spEle.unwindEL.value = '111'; + spEle.shareMemory.value = '222'; + spEle.shareMemoryUnit.value = 'MB'; + spEle.filterMemory.value = '111'; + spEle.filterMemoryUnit.value = 'MB'; + expect(spEle.pid).toEqual(undefined); + expect(spEle.unwind).toEqual(111); + expect(spEle.shared).toEqual(222); + expect(spEle.filter).toEqual(111); + }); + + it(' SpAllocations set attrValue2', function () { + let spEle = document.querySelector('#sp') as SpAllocations; + spEle.processId.value = '3'; + spEle.unwindEL.value = '1121'; + spEle.shareMemory!.value = '222'; + spEle.shareMemoryUnit.value = 'KB'; + spEle.filterMemory.value = '111'; + spEle.filterMemoryUnit.value = 'KB'; + expect(spEle.pid).toEqual(undefined); + expect(spEle.unwind).toEqual(1121); + expect(spEle.shared).toEqual(222); + expect(spEle.filter).toEqual(111); + }); + + it(' SpAllocations set attrValue03', function () { + let spEle = new SpAllocations(); + spEle.processId.value = '3'; + spEle.unwindEL.value = '1121'; + spEle.shareMemory.value = '222'; + spEle.filterMemory.value = '111'; + expect(spEle.pid).toEqual(undefined); + expect(spEle.unwind).toEqual(1121); + expect(spEle.shared).toEqual(222); + expect(spEle.filter).toEqual(111); + }); + + it('SpAllocations test04', function () { + let spEle = document.querySelector('#sp') as SpAllocations; + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ Native Memory +
+
+ ProcessId or ProcessName + Record process + + +
+
+ Max unwind level + Max Unwind Level Rang is 0 - 512, default 10 + +
+
+ Shared Memory Size (One page equals 4 KB) + Shared Memory Size Range is 0 - 131072 page, default 16384 page +
+ + Page +
+
+
+ Filter Memory Size + Filter size Range is 0 - 65535 byte, default 4096 byte +
+ + Byte +
+
+
+ Use Fp Unwind + +
+
+ Use Record Accurately (Available on recent OpenHarmony 4.0) + +
+
+ Use Offline Symbolization (Available on recent OpenHarmony 4.0) + +
+ +
+
+ Use Record Statistics (Available on recent OpenHarmony 4.0) + Time between following interval (0 = disabled) +
+ + +
+ + S +
+
+
+ " +`); + }); + + it('SpAllocations test05', function () { + let spAllocations = document.querySelector('#sp') as SpAllocations; + expect(spAllocations.appProcess).toBe('3'); + }); + + it('SpAllocations test06', function () { + let spAllocations = document.querySelector('#sp') as SpAllocations; + expect(spAllocations.convertToValue('0', 'MB')).toBe(0); + }); + + it('SpAllocations test07', function () { + let spAllocations = document.querySelector('#sp') as SpAllocations; + expect(spAllocations.convertToValue('1', 'KB')).toBe(16384); + }); + + it('SpAllocations test08', function () { + let spAllocations = document.querySelector('#sp') as SpAllocations; + expect(spAllocations.convertToValue('1', '')).toBe(0); + }); + it('SpAllocations test09', function () { + let spAllocations = document.querySelector('#sp') as SpAllocations; + expect(spAllocations.fp_unwind).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/setting/SpCheckDesBox.test.ts b/ide/test/trace/component/setting/SpCheckDesBox.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..152b1ae3b451b3c76edcc4fedf96dfae3fb1bd01 --- /dev/null +++ b/ide/test/trace/component/setting/SpCheckDesBox.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { SpCheckDesBox } from '../../../../dist/trace/component/setting/SpCheckDesBox.js'; + +describe('SpCheckDesBox Test', () => { + let spCheckDesBox = new SpCheckDesBox(); + + it('SpCheckDesBoxTest01', function () { + expect(spCheckDesBox.value).toBe(''); + }); + + it('SpCheckDesBoxTest02', function () { + expect(spCheckDesBox.attributeChangedCallback('checked', '', '')).toBeUndefined(); + }); + + it('SpCheckDesBoxTest03', function () { + expect(spCheckDesBox.attributeChangedCallback('value', '', '')).toBeUndefined(); + }); + + it('SpCheckDesBoxTest04', function () { + expect(spCheckDesBox.attributeChangedCallback('des', '', '')).toBeUndefined(); + }); + + it('SpCheckDesBoxTest05', function () { + spCheckDesBox.checked = false; + expect(spCheckDesBox.checked).toBeFalsy(); + }); + + it('SpCheckDesBoxTest07', function () { + spCheckDesBox.checked = true; + expect(spCheckDesBox.checked).toBeTruthy(); + }); + + it('SpCheckDesBoxTest06 ', function () { + expect(spCheckDesBox.connectedCallback()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/setting/SpFileSystem.test.ts b/ide/test/trace/component/setting/SpFileSystem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e95ad6e435a07f2531cf8b5dc2cf0a4047b8537 --- /dev/null +++ b/ide/test/trace/component/setting/SpFileSystem.test.ts @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { SpFileSystem } from '../../../../dist/trace/component/setting/SpFileSystem'; + +describe('spFileSystem Test', () => { + let spFileSystem = new SpFileSystem(); + it('SpFileSystemTest01', function () { + spFileSystem.startSamp = true; + expect(spFileSystem.startSamp).toBeTruthy(); + }); + + it('SpFileSystemTest02', function () { + spFileSystem.startSamp = false; + expect(spFileSystem.startSamp).toBeFalsy(); + }); + + it('SpFileSystemTest03', function () { + expect(spFileSystem.getSystemConfig()).toStrictEqual({ + process: '', + unWindLevel: 10, + }); + }); + + it('SpFileSystemTest04', function () { + expect(spFileSystem.unDisable()).toBeUndefined(); + }); + + it('SpFileSystemTest05', function () { + expect(spFileSystem.disable()).toBeUndefined(); + }); + + it('SpFileSystemTest06', function () { + expect(spFileSystem.initConfigList()).toBeUndefined(); + }); + + it('SpFileSystemTest07', function () { + spFileSystem.startRecord = true; + expect(spFileSystem.startRecord).toBeTruthy(); + }); + + it('SpFileSystemTest08', function () { + spFileSystem.startRecord = false; + expect(spFileSystem.startRecord).toBeFalsy(); + }); + + it('SpFileSystemTest09', function () { + spFileSystem.startFileSystem = true; + expect(spFileSystem.startFileSystem).toBeTruthy(); + }); + + it('SpFileSystemTest10', function () { + spFileSystem.startFileSystem = false; + expect(spFileSystem.startFileSystem).toBeFalsy(); + }); + + it('SpFileSystemTest11', function () { + spFileSystem.startVirtualMemory = true; + expect(spFileSystem.startVirtualMemory).toBeTruthy(); + }); + + it('SpFileSystemTest12', function () { + spFileSystem.startVirtualMemory = false; + expect(spFileSystem.startVirtualMemory).toBeFalsy(); + }); + + it('SpFileSystemTest13', function () { + spFileSystem.startIo = true; + expect(spFileSystem.startIo).toBeTruthy(); + }); + + it('SpFileSystemTest14', function () { + spFileSystem.startIo = false; + expect(spFileSystem.startIo).toBeFalsy(); + }); +}); diff --git a/ide/test/trace/component/setting/SpProbesConfig.test.ts b/ide/test/trace/component/setting/SpProbesConfig.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c953b80a987895d8bd28db44c48c50e82cb685c --- /dev/null +++ b/ide/test/trace/component/setting/SpProbesConfig.test.ts @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpProbesConfig } from '../../../../dist/trace/component/setting/SpProbesConfig.js'; +import { LitCheckBox } from '../../../../src/base-ui/checkbox/LitCheckBox'; + +describe('SpProbesConfig Test', () => { + beforeAll(() => { + document.body.innerHTML = ` + + `; + }); + it('new SpProbesConfig', function () { + expect(new SpProbesConfig()).not.toBeNull(); + }); + + it(' SpProbesConfig get Default attrValue', function () { + let spEle = document.querySelector('#spconfig') as SpProbesConfig; + expect(spEle.traceConfig).toEqual(['Scheduling details', 'CPU Frequency and idle states', 'Hitrace categories']); + expect(spEle.traceEvents).toEqual([ + 'ability', + 'ace', + 'app', + 'ark', + 'binder', + 'disk', + 'freq', + 'graphic', + 'idle', + 'irq', + 'memreclaim', + 'mmc', + 'multimodalinput', + 'ohos', + 'pagecache', + 'rpc', + 'sched', + 'sync', + 'window', + 'workq', + 'zaudio', + 'zcamera', + 'zimage', + 'zmedia', + ]); + expect(spEle.memoryConfig).toEqual([]); + }); + + it(' SpProbesConfig test', function () { + let spEle = document.querySelector('#spconfig') as SpProbesConfig; + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+
Record mode
+
+
+
+
+ + +
+ +
+
+
+
+
+ Memory Config +
+
+
+
+ Ability Config +
+
+
+
+ " +`); + }); +}); diff --git a/ide/test/trace/component/setting/SpRecordPerf.test.ts b/ide/test/trace/component/setting/SpRecordPerf.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..38415d431035b081102e0e476a619d8153ed8d0c --- /dev/null +++ b/ide/test/trace/component/setting/SpRecordPerf.test.ts @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpRecordPerf } from '../../../../dist/trace/component/setting/SpRecordPerf.js'; + +describe('SpRecordPerf Test', () => { + let spRecordPerf = new SpRecordPerf(); + it('SpRecordPerfTest01', function () { + expect(spRecordPerf).not.toBeUndefined(); + }); + + it('SpRecordPerfTest02', function () { + expect(spRecordPerf.show).toBeFalsy(); + }); + + it('SpRecordPerfTest03', function () { + spRecordPerf.show = true; + expect(spRecordPerf.show).toBeTruthy(); + }); + + it('SpRecordPerfTest08', function () { + spRecordPerf.show = false; + expect(spRecordPerf.show).toBeFalsy(); + }); + + it('SpRecordPerfTest09', function () { + expect(spRecordPerf.startSamp).toBeFalsy(); + }); + + it('SpRecordPerfTest10', function () { + spRecordPerf.startSamp = true; + expect(spRecordPerf.startSamp).toBeTruthy(); + }); + + it('SpRecordPerfTest11', function () { + spRecordPerf.startSamp = false; + expect(spRecordPerf.startSamp).toBeFalsy(); + }); + + it('SpRecordPerfTest05', function () { + expect(spRecordPerf.unDisable()).toBeUndefined(); + }); + + it('SpRecordPerfTest04', function () { + expect(spRecordPerf.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ +
+ " +`); + }); + + it('SpRecordPerfTest06', function () { + expect(spRecordPerf.startSamp).toBeFalsy(); + }); + + it('SpRecordPerfTest07', function () { + spRecordPerf.startSamp = true; + expect(spRecordPerf.startSamp).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/setting/SpRecordSetting.test.ts b/ide/test/trace/component/setting/SpRecordSetting.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ab0c0cce875dc9832aae6af2d157055c5d991d6 --- /dev/null +++ b/ide/test/trace/component/setting/SpRecordSetting.test.ts @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpRecordSetting } from '../../../../dist/trace/component/setting/SpRecordSetting.js'; + +describe('SpRecordSetting Test', () => { + beforeAll(() => { + document.body.innerHTML = ` + + `; + }); + it('new SpRecordSetting', function () { + expect(new SpRecordSetting()).not.toBeNull(); + }); + + it(' SpAllocations get Default attrValue', function () { + let spEle = document.querySelector('#setting') as SpRecordSetting; + expect(spEle.recordMod).toBeTruthy(); + expect(spEle.bufferSize).toEqual(64); + expect(spEle.maxDur).toEqual(30); + }); + + it(' SpRecordSetting test', function () { + let spEle = document.querySelector('#setting') as SpRecordSetting; + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ Record mode + Stop when full +
+
+ output file path +
+ /data/local/tmp/ + +
+
+
+
+ In-memory buffer size + (max memory buffer size is 512 MB) +
+ + +
+ + MB +
+
+
+
+ Max duration + (max duration value is 01:00:00) +
+ + +
+ + h:m:s +
+ +
+
+ " +`); + }); + it(' SpRecordSettingTest04', function () { + let spEle = document.querySelector('#setting') as SpRecordSetting; + expect(spEle.resetValue()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/setting/SpRecordTemplate.test.ts b/ide/test/trace/component/setting/SpRecordTemplate.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..93150fda86c7d5f02a4b96f8990edac6cf3d2e06 --- /dev/null +++ b/ide/test/trace/component/setting/SpRecordTemplate.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpRecordTemplate } from '../../../../dist/trace/component/setting/SpRecordTemplate.js'; + +describe('SpRecordTemplate', () => { + let recordTemplate = new SpRecordTemplate(); + recordTemplate.initElements(); + + it('SpRecordTemplate01', function () { + expect(recordTemplate.getTemplateConfig()).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/setting/SpSdkConfig.test.ts b/ide/test/trace/component/setting/SpSdkConfig.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ab4717a189bea17e5a0bb5ff0dc10d1ebad9430 --- /dev/null +++ b/ide/test/trace/component/setting/SpSdkConfig.test.ts @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { SpSdkConfig } from '../../../../dist/trace/component/setting/SpSdkConfig.js'; + +describe('spSdkConfig Test', () => { + let spSdkConfig = new SpSdkConfig(); + it('spSdkConfigTest01', function () { + spSdkConfig.show = true; + expect(spSdkConfig.show).toBeTruthy(); + }); + + it('spSdkConfigTest02', function () { + spSdkConfig.show = false; + expect(spSdkConfig.show).toBeFalsy(); + }); + + it('spSdkConfigTest03', function () { + spSdkConfig.startSamp = true; + expect(spSdkConfig.startSamp).toBeTruthy(); + }); + + it('spSdkConfigTest04', function () { + spSdkConfig.startSamp = false; + expect(spSdkConfig.startSamp).toBeFalsy(); + }); + + it('spSdkConfigTest05', function () { + spSdkConfig.configName = ''; + expect(spSdkConfig.configName).toBeDefined(); + }); + + it('spSdkConfigTest06', function () { + spSdkConfig.configName = 'configName'; + expect(spSdkConfig.configName).toBeDefined(); + }); + + it('spSdkConfigTest07', function () { + spSdkConfig.type = ''; + expect(spSdkConfig.type).toBeDefined(); + }); + + it('spSdkConfigTest08', function () { + spSdkConfig.type = 'configName'; + expect(spSdkConfig.type).toBeDefined(); + }); + + it('spSdkConfigTest09', function () { + expect(spSdkConfig.getPlugName()).not.toBeUndefined(); + }); + + it('spSdkConfigTest10', function () { + expect(spSdkConfig.getSampleInterval()).not.toBeUndefined(); + }); + + it('spSdkConfigTest11', function () { + expect(spSdkConfig.getGpuConfig()).not.toBeUndefined(); + }); + + it('spSdkConfigTest12', function () { + expect(spSdkConfig.checkIntegerInput('')).not.toBeUndefined(); + }); + + it('spSdkConfigTest13', function () { + expect(spSdkConfig.checkIntegerInput('checkIntegerInput')).not.toBeUndefined(); + }); + + it('spSdkConfigTest14', function () { + expect(spSdkConfig.checkFloatInput('checkFloatInput')).not.toBeUndefined(); + }); + + it('spSdkConfigTest15', function () { + expect(spSdkConfig.isAbleShowConfig(false)).toBeUndefined(); + }); + + it('spSdkConfigTest16', function () { + expect(spSdkConfig.isAbleShowConfig(true)).toBeUndefined(); + }); + + it('spSdkConfigTest17', function () { + expect(spSdkConfig.initConfigList()).toBeUndefined(); + }); + it('spSdkConfigTest18', function () { + spSdkConfig.configList = { + name: '', + configuration: { + ss: { + type: 'string', + default: 'strsadsa', + description: 'xxxx', + }, + aa: { + type: 'string', + default: '11', + enum: ['consistent', '11', 'delegated'], + }, + cc: { + type: 'number', + description: 'number1111', + }, + ee: { + type: 'integer', + default: '12', + description: 'integer1222', + }, + ff: { + type: 'boolean', + description: 'switchhh', + }, + }, + }; + expect(spSdkConfig.initConfig()).toBeUndefined(); + }); + it('spSdkConfigTest19', function () { + expect(spSdkConfig.getGpuConfig()).toStrictEqual({ + aa: '11', + cc: 0, + ee: 12, + ff: false, + ss: 'strsadsa', + }); + }); +}); diff --git a/ide/test/trace/component/setting/SpTraceCommand.test.ts b/ide/test/trace/component/setting/SpTraceCommand.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8bfa807f8b1fb022e71ef99ee04fc77de93a529 --- /dev/null +++ b/ide/test/trace/component/setting/SpTraceCommand.test.ts @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpTraceCommand } from '../../../../dist/trace/component/setting/SpTraceCommand.js'; + +describe('SPTraceCommand Test', () => { + beforeAll(() => { + document.body.innerHTML = ` + + `; + }); + it('new SPTraceCommand', function () { + expect(new SpTraceCommand()).not.toBeNull(); + }); + + it(' SpAllocations get Default attrValue', function () { + let spEle = document.querySelector('#command') as SpTraceCommand; + expect(spEle.hdcCommon).toEqual(''); + }); + + it(' SpAllocations set attrValue', function () { + let spEle = document.querySelector('#command') as SpTraceCommand; + spEle.hdcCommon = 'test'; + expect(spEle.hdcCommon).toEqual('test'); + }); + + it(' SpTraceCommand test', function () { + let spEle = document.querySelector('#command') as SpTraceCommand; + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+ + + +
+ " +`); + }); + it(' SpTraceCommandtest01', function () { + let spEle = document.querySelector('#command') as SpTraceCommand; + spEle.show = false; + expect(spEle.show).toBeFalsy(); + }); + it(' SpTraceCommandtest02', function () { + let spEle = document.querySelector('#command') as SpTraceCommand; + spEle.show = true; + expect(spEle.show).toBeTruthy(); + }); + it(' SpTraceCommandtest03', function () { + let spEle = document.querySelector('#command') as SpTraceCommand; + expect(spEle.disconnectedCallback()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/setting/SpVmTracker.test.ts b/ide/test/trace/component/setting/SpVmTracker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6928021a0a5062cc4bf146738b4033a40dfdd3a --- /dev/null +++ b/ide/test/trace/component/setting/SpVmTracker.test.ts @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { SpVmTracker } from '../../../../dist/trace/component/setting/SpVmTracker.js'; + +describe('SpVmTracker Test', () => { + let spVmTracker = new SpVmTracker(); + it('SpVmTrackerTest01', function () { + spVmTracker.startSamp = true; + expect(spVmTracker.startSamp).toBeTruthy(); + }); + + it('SpVmTrackerTest02', function () { + spVmTracker.startSamp = false; + expect(spVmTracker.startSamp).toBeFalsy(); + }); +}); diff --git a/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts b/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3c385f4716e418fa1c3ddf0ede8504c421029f7 --- /dev/null +++ b/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { PluginConvertUtils } from '../../../../../dist/trace/component/setting/utils/PluginConvertUtils.js'; +// @ts-ignore +import { ProfilerSessionConfigMode } from '../../../../../dist/trace/component/setting/bean/ProfilerServiceTypes'; + +import { + ProfilerSessionConfigBufferConfig, + ProfilerSessionConfigBufferConfigPolicy, + TracePluginConfig, + // @ts-ignore +} from '../../../../../dist/trace/component/setting/bean/ProfilerServiceTypes.js'; +import { + HilogConfig, + levelFromJSON, + Type, + // @ts-ignore +} from '../../../../../dist/trace/component/setting/bean/ProfilerServiceTypes.js'; +import { + MemoryConfig, + sysMeminfoTypeFromJSON, + sysVMeminfoTypeFromJSON, + // @ts-ignore +} from '../../../../../dist/trace/component/setting/bean/ProfilerServiceTypes.js'; +// @ts-ignore +import { SpRecordTrace } from '../../../../../dist/trace/component/SpRecordTrace.js'; + +describe('PlugConvertUtils Test', () => { + let bufferConfig: ProfilerSessionConfigBufferConfig = { + pages: 1000, + policy: ProfilerSessionConfigBufferConfigPolicy.RECYCLE, + }; + let sessionConfig = { + buffers: [bufferConfig], + sessionMode: ProfilerSessionConfigMode.OFFLINE, + resultFile: '/data/local/tmp/hiprofiler_data.htrace', + resultMaxSize: 0, + sampleDuration: 1000, + keepAliveTime: 0, + }; + let tracePluginConfig: TracePluginConfig = { + ftraceEvents: [], + bytraceCategories: [], + bytraceApps: [], + bufferSizeKb: 1024, + flushIntervalMs: 1000, + flushThresholdKb: 4096, + parseKsyms: true, + clock: 'mono', + tracePeriodMs: 200, + rawDataPrefix: '', + traceDurationMs: 0, + debugOn: false, + }; + let hilogConfig: HilogConfig = { + deviceType: Type.HI3516, + logLevel: levelFromJSON('Info'), + needClear: true, + }; + let memoryconfig: MemoryConfig = { + reportProcessTree: true, + reportSysmemMemInfo: true, + sysMeminfoCounters: [], + reportSysmemVmemInfo: true, + sysVmeminfoCounters: [], + reportProcessMemInfo: true, + reportAppMemInfo: false, + reportAppMemByMemoryService: false, + pid: [], + }; + + SpRecordTrace.MEM_INFO.forEach((va: any) => { + memoryconfig.sysMeminfoCounters.push(sysMeminfoTypeFromJSON(va)); + }); + SpRecordTrace.VMEM_INFO.forEach((me: any) => { + memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)); + }); + SpRecordTrace.VMEM_INFO_SECOND.forEach((me: any) => { + memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)); + }); + SpRecordTrace.VMEM_INFO_THIRD.forEach((me: any) => { + memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)); + }); + + let request = { + requestId: 1, + sessionConfig: sessionConfig, + pluginConfigs: [tracePluginConfig, hilogConfig, memoryconfig], + }; + + it('PlugConvertUtils01', function () { + expect(PluginConvertUtils.createHdcCmd('aaaa', 11)).not.toBeNull(); + }); + + it('PlugConvertUtils02', function () { + expect(PluginConvertUtils.BeanToCmdTxt(request, true)).not.toBeNull(); + }); + + it('PlugConvertUtils03', function () { + expect(PluginConvertUtils.BeanToCmdTxtWithObjName(request, false, '', 1)).not.toBeNull(); + }); +}); diff --git a/ide/test/trace/component/trace/TimerShaftElement.test.ts b/ide/test/trace/component/trace/TimerShaftElement.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..04f2ed0f657fa6f17130115fb49ee2e70abf3dcb --- /dev/null +++ b/ide/test/trace/component/trace/TimerShaftElement.test.ts @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { TimerShaftElement, ns2s, ns2x } from '../../../../dist/trace/component/trace/TimerShaftElement.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCommon'; + +// @ts-ignore +import { EventCenter } from '../../../../dist/trace/component/trace/base/EventCenter.js'; + +declare global { + interface Window { + SmartEvent: { + UI: { + MenuTrace: string; //selected menu trace + RefreshCanvas: string; //selected menu trace + SliceMark: string; //Set the tag scope + TimeRange: string; //Set the timeline range + TraceRowComplete: string; //Triggered after the row component has finished loading data + }; + }; + + subscribe(evt: string, fn: (b: any) => void): void; + + subscribeOnce(evt: string, fn: (b: any) => void): void; + + unsubscribe(evt: string, fn: (b: any) => void): void; + + publish(evt: string, data: any): void; + + clearTraceRowComplete(): void; + } +} + +window.SmartEvent = { + UI: { + MenuTrace: 'SmartEvent-UI-MenuTrace', + RefreshCanvas: 'SmartEvent-UI-RefreshCanvas', + SliceMark: 'SmartEvent-UI-SliceMark', + TimeRange: 'SmartEvent-UI-TimeRange', + TraceRowComplete: 'SmartEvent-UI-TraceRowComplete', + }, +}; + +Window.prototype.subscribe = (ev, fn) => EventCenter.subscribe(ev, fn); +Window.prototype.unsubscribe = (ev, fn) => EventCenter.unsubscribe(ev, fn); +Window.prototype.publish = (ev, data) => EventCenter.publish(ev, data); +Window.prototype.subscribeOnce = (ev, data) => EventCenter.subscribeOnce(ev, data); +Window.prototype.clearTraceRowComplete = () => EventCenter.clearTraceRowComplete(); + +describe('TimerShaftElement Test', () => { + document.body.innerHTML = ''; + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + timerShaftElement.totalNS = 1000; + timerShaftElement.startNS = 1000; + timerShaftElement.endNS = 2000; + + timerShaftElement.cpuUsage = 'cpuUsage'; + + it('TimerShaftElementTest01', function () { + timerShaftElement.rangeRuler = jest.fn(() => true); + timerShaftElement.rangeRuler.cpuUsage = jest.fn(() => true); + expect(timerShaftElement.cpuUsage).toBeUndefined(); + }); + + it('TimerShaftElementTest03', function () { + timerShaftElement.timeRuler = jest.fn(() => false); + timerShaftElement.rangeRuler = jest.fn(() => false); + timerShaftElement.timeRuler.frame = jest.fn(() => { + return document.createElement('canvas') as HTMLCanvasElement; + }); + timerShaftElement.rangeRuler.frame = jest.fn(() => { + return document.createElement('canvas') as HTMLCanvasElement; + }); + expect(timerShaftElement.connectedCallback()).toBeUndefined(); + }); + + it('TimerShaftElementTest05', function () { + expect(timerShaftElement.disconnectedCallback()).toBeUndefined(); + }); + + it('TimerShaftElementTest06', function () { + expect(timerShaftElement.totalNS).toBe(1000); + }); + + it('TimerShaftElementTest08', function () { + timerShaftElement.startNS = 'startNS'; + expect(timerShaftElement.startNS).toBe('startNS'); + }); + + it('TimerShaftElementTest09', function () { + timerShaftElement.endNS = 'endNS'; + expect(timerShaftElement.endNS).toBe('endNS'); + }); + + it('TimerShaftElementTest14', function () { + expect(ns2s(1_000_0000)).toBe('10.0 ms'); + }); + + it('TimerShaftElementTest15', function () { + expect(timerShaftElement.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+
+ 10 + 0 +
+ +
+
+
+ +
+ " +`); + }); + + it('TimerShaftElementTest16', function () { + expect(ns2s(1)).toBe('1.0 ns'); + }); + + it('TimerShaftElementTest17', function () { + expect(ns2s(1_000)).toBe('1.0 μs'); + }); + + it('TimerShaftElementTest18', function () { + expect(ns2x(1, 3, 4, 4, { width: 1 })).toBe(0); + }); + + it('TimerShaftElementTest19', function () { + expect(timerShaftElement.sportRuler).not.toBeUndefined(); + }); + + it('TimerShaftElementTest20', function () { + expect(timerShaftElement.isScaling()).toBeFalsy(); + }); + + it('TimerShaftElementTest21', function () { + timerShaftElement.rangeRuler = jest.fn(() => undefined); + timerShaftElement.rangeRuler.setRangeNS = jest.fn(() => true); + expect(timerShaftElement.setRangeNS()).toBeFalsy(); + }); + + it('TimerShaftElementTest22', function () { + timerShaftElement.rangeRuler = jest.fn(() => undefined); + timerShaftElement.rangeRuler.getRange = jest.fn(() => true); + expect(timerShaftElement.getRange()).toBeTruthy(); + }); + + it('TimerShaftElementTest23', function () { + timerShaftElement.rangeRuler = jest.fn(() => undefined); + timerShaftElement.rangeRuler.frame = jest.fn(() => Rect); + timerShaftElement.rangeRuler.frame.width = jest.fn(() => 1); + timerShaftElement._sportRuler = jest.fn(() => undefined); + timerShaftElement._sportRuler.frame = jest.fn(() => Rect); + timerShaftElement._sportRuler.frame.width = jest.fn(() => 1); + timerShaftElement.timeRuler = jest.fn(() => undefined); + timerShaftElement.timeRuler.frame = jest.fn(() => Rect); + timerShaftElement.timeRuler.frame.width = jest.fn(() => 1); + timerShaftElement.rangeRuler.fillX = jest.fn(() => true); + timerShaftElement.render = jest.fn(() => true); + expect(timerShaftElement.updateWidth()).toBeUndefined(); + }); + + it('TimerShaftElementTest24', function () { + timerShaftElement._sportRuler = jest.fn(() => undefined); + timerShaftElement._sportRuler.modifyFlagList = jest.fn(() => true); + expect(timerShaftElement.modifyFlagList()).toBeUndefined(); + }); + + it('TimerShaftElementTest25', function () { + timerShaftElement._sportRuler = jest.fn(() => undefined); + timerShaftElement._sportRuler.drawTriangle = jest.fn(() => true); + expect(timerShaftElement.drawTriangle()).toBeTruthy(); + }); + + it('TimerShaftElementTest26', function () { + timerShaftElement._sportRuler = jest.fn(() => undefined); + timerShaftElement._sportRuler.removeTriangle = jest.fn(() => true); + expect(timerShaftElement.removeTriangle()).toBeUndefined(); + }); + + it('TimerShaftElementTest27', function () { + timerShaftElement._sportRuler = jest.fn(() => undefined); + timerShaftElement._sportRuler.setSlicesMark = jest.fn(() => true); + expect(timerShaftElement.setSlicesMark()).toBeUndefined(); + }); + + it('TimerShaftElementTest28', function () { + timerShaftElement.rangeRuler = jest.fn(() => undefined); + timerShaftElement.rangeRuler.render = jest.fn(() => true); + expect(timerShaftElement.render()).not.toBeUndefined(); + }); + + it('TimerShaftElementTest29', function () { + expect(ns2x(1, 3, 0, 4, { width: 1 })).toBe(0); + }); + + it('TimerShaftElementTest30', function () { + timerShaftElement.rangeRuler = jest.fn(() => true); + timerShaftElement.rangeRuler.cpuUsage = jest.fn(() => true); + expect(timerShaftElement.cpuUsage).toBe(undefined); + }); + + it('TimerShaftElementTest31', function () { + timerShaftElement.timeRuler = jest.fn(() => true); + expect(timerShaftElement.totalNS).toBe(1000); + }); + + it('TimerShaftElementTest32', function () { + timerShaftElement.rangeRuler = jest.fn(() => true); + expect(timerShaftElement.totalNS).toBe(1000); + }); + + it('TimerShaftElementTest33', function () { + timerShaftElement.timeTotalEL = jest.fn(() => true); + expect(timerShaftElement.totalNS).toBe(1000); + }); + + it('TimerShaftElementTest35', function () { + timerShaftElement.rangeRuler = jest.fn(() => undefined); + timerShaftElement.rangeRuler.cancelPressFrame = jest.fn(() => undefined); + expect(timerShaftElement.cancelPressFrame()).toBeUndefined(); + }); + + it('TimerShaftElementTest36', function () { + timerShaftElement.rangeRuler = jest.fn(() => undefined); + timerShaftElement.rangeRuler.cancelUpFrame = jest.fn(() => undefined); + expect(timerShaftElement.cancelUpFrame()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/base/ColorUtils.test.ts b/ide/test/trace/component/trace/base/ColorUtils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4f6c5d30d298b3043c46e09623caab5c9be24f3 --- /dev/null +++ b/ide/test/trace/component/trace/base/ColorUtils.test.ts @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { ColorUtils } from '../../../../../dist/trace/component/trace/base/ColorUtils.js'; + +describe('testColorUtils Test', () => { + beforeAll(() => {}); + it('testColorUtils01', () => { + expect(ColorUtils.hash('mm', ColorUtils.MD_PALETTE.length)).toBe(0); + }); + it('testColorUtils02', () => { + // @ts-ignore + expect(ColorUtils.colorForThread(null)).toEqual('#f0f0f0'); + }); + + it('testColorUtils03', () => { + // @ts-ignore + let thread = { processId: 1 }; + expect(ColorUtils.colorForThread(thread)).toEqual('#9785D3'); + }); + + it('testColorUtils03', () => { + // @ts-ignore + let thread = { + processId: 0, + tid: 1, + }; + expect(ColorUtils.colorForThread(thread)).toEqual('#9785D3'); + }); + + it('testColorUtils04', () => { + expect(ColorUtils.formatNumberComma(2)).toEqual('2'); + }); + + afterAll(() => {}); +}); diff --git a/ide/test/trace/component/trace/base/RangeSelect.test.ts b/ide/test/trace/component/trace/base/RangeSelect.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..131f1f647fe71b59f7a81c211f6aba19d5a4ae79 --- /dev/null +++ b/ide/test/trace/component/trace/base/RangeSelect.test.ts @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { RangeSelect } from '../../../../../dist/trace/component/trace/base/RangeSelect.js'; +// @ts-ignore +import { TraceRow } from '../../../../../dist/trace/component/trace/base/TraceRow.js'; + +describe('RangeSelect Test', () => { + beforeAll(() => {}); + + it('Utils Test01', () => { + let rangeSelect = new RangeSelect(); + expect(rangeSelect).not.toBeUndefined(); + }); + + it('Utils Test02', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.rowsEL = document.createElement('div'); + let mouseEvent = new MouseEvent('mousedown', { + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + let htmlElement = document.createElement('div'); + rangeSelect.rowsPaneEL = htmlElement; + rangeSelect.timerShaftDragEL = jest.fn(() => true); + rangeSelect.timerShaftDragEL.timerShaftDragEL = jest.fn(() => true); + expect(rangeSelect.isInRowsEl(mouseEvent)).toBeFalsy(); + }); + it('Utils Test09', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.rowsEL = document.createElement('div'); + let mouseEvent = new MouseEvent('mousedown', { + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + let htmlElement = document.createElement('div'); + rangeSelect.spacerEL = htmlElement; + expect(rangeSelect.isInSpacerEL(mouseEvent)).toBeFalsy(); + }); + + it('Utils Test05', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.isInRowsEl = jest.fn(() => true); + rangeSelect.rowsEL = { + // offsetTop: 100, + offsetHeight: 200, + offsetLeft: 0, + offsetWidth: 100, + }; + let mouseEvent = new MouseEvent('mousedown', { + // @ts-ignore + offsetY: 1, + offsetX: 1, + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + let divElement = document.createElement('div'); + rangeSelect.rowsPaneEL = divElement; + rangeSelect.spacerEL = jest.fn(() => true); + rangeSelect.spacerEL.offsetTop = jest.fn(() => true); + rangeSelect.rowsPaneEL.scrollTop = 0; + rangeSelect.rowsEL.getBoundingClientRect = jest.fn(() => true); + let htmlElement = document.createElement('div'); + rangeSelect.spacerEL = htmlElement; + expect(rangeSelect.mouseDown(mouseEvent)).toBeUndefined(); + }); + + it('Utils Test07', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.isInRowsEl = jest.fn(() => true); + rangeSelect.isDrag = jest.fn(() => true); + + rangeSelect.rowsEL = { + offsetTop: 100, + offsetHeight: 200, + offsetLeft: 0, + offsetWidth: 100, + }; + let mouseEvent = new MouseEvent('mousedown', { + // @ts-ignore + offsetY: 1, + offsetX: 1, + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + rangeSelect.spacerEL = jest.fn(() => true); + rangeSelect.spacerEL.offsetTop = jest.fn(() => 1); + expect(rangeSelect.mouseUp(mouseEvent)).toBeUndefined(); + }); + + it('Utils Test08', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.isInRowsEl = jest.fn(() => true); + rangeSelect.isDrag = jest.fn(() => true); + rangeSelect.isMouseDown = true; + let rowsELDiv = document.createElement('div'); + rangeSelect.rowsEL = rowsELDiv; + let rows = [ + { + frame: { + x: 1, + width: 10, + y: 2, + height: 10, + }, + offsetTop: 100, + offsetHeight: 200, + offsetLeft: 0, + offsetWidth: 100, + }, + ]; + let mouseEvent = new MouseEvent('mousedown', { + // @ts-ignore + offsetY: 1, + offsetX: 1, + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + rangeSelect.timerShaftDragEL = jest.fn(() => true); + rangeSelect.timerShaftEL = jest.fn(() => true); + rangeSelect.timerShaftEL.sportRuler = jest.fn(() => true); + rangeSelect.timerShaftEL.sportRuler.isRangeSelect = jest.fn(() => true); + rangeSelect.timerShaftEL.sportRuler.draw = jest.fn(() => true); + rangeSelect.timerShaftDragEL.timerShaftDragEL = jest.fn(() => 0); + rangeSelect.spacerEL = jest.fn(() => true); + rangeSelect.spacerEL.offsetTop = jest.fn(() => 1); + rangeSelect.ns2x = jest.fn(() => 1); + rangeSelect.mouseX = jest.fn(() => 10); + rangeSelect.markA = jest.fn(() => 8); + rangeSelect.markB = jest.fn(() => 9); + let htmlElement = document.createElement('div'); + rangeSelect.spacerEL = htmlElement; + let rowElement = document.createElement('div'); + rangeSelect.rowsPaneEL = rowElement; + rangeSelect.favoriteRowsEL = rowElement; + let traceRowElement = document.createElement('trace-row') as TraceRow; + expect(rangeSelect.mouseMove([traceRowElement], mouseEvent)).toBeUndefined(); + }); + + it('Utils Test10', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.isInRowsEl = jest.fn(() => true); + rangeSelect.isDrag = jest.fn(() => true); + + rangeSelect.rowsEL = { + offsetTop: 100, + offsetHeight: 200, + offsetLeft: 0, + offsetWidth: 100, + }; + let mouseEvent = new MouseEvent('mousedown', { + // @ts-ignore + offsetY: 1, + offsetX: 1, + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + let htmlElement = document.createElement('div'); + rangeSelect.rowsPaneEL = htmlElement; + rangeSelect.timerShaftDragEL = jest.fn(() => true); + rangeSelect.timerShaftDragEL.timerShaftDragEL = jest.fn(() => 0); + expect(rangeSelect.isTouchMark(mouseEvent)).toBeFalsy(); + }); + + it('Utils Test06', () => { + let rangeSelect = new RangeSelect(); + rangeSelect.isHover = true; + let mouseEvent = new MouseEvent('mousedown', { + // @ts-ignore + offsetY: 1, + offsetX: 1, + button: 0, + buttons: 0, + clientX: 2, + clientY: 100, + screenX: 255, + screenY: 325, + }); + expect(rangeSelect.mouseDown(mouseEvent)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/base/TraceRow.test.ts b/ide/test/trace/component/trace/base/TraceRow.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..969613bd62f97749fd02b248633ad49707a6280f --- /dev/null +++ b/ide/test/trace/component/trace/base/TraceRow.test.ts @@ -0,0 +1,940 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TraceRow } from '../../../../../dist/trace/component/trace/base/TraceRow.js'; +// @ts-ignore +import { Sptext } from '../../../../../dist/trace/component/Sptext.js'; + +describe('TraceRow Test', () => { + beforeAll(() => {}); + const ctx = { + lineWidth: 1, + strokeStyle: true, + }; + it('TraceRow Test01', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow).not.toBeUndefined(); + }); + + it('TraceRow Test02', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.sleeping).toBeFalsy(); + }); + + it('TraceRow Test03', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.sleeping = true; + expect(traceRow.sleeping).toBeTruthy(); + }); + + it('TraceRow Test04', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.sleeping = false; + expect(traceRow.sleeping).toBeFalsy(); + }); + + it('TraceRow Test05', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.rangeSelect).toBeFalsy(); + }); + + it('TraceRow Test06', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rangeSelect = true; + expect(traceRow.rangeSelect).toBeTruthy(); + }); + + it('TraceRow Test10', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.dataList = { + supplier: true, + isLoading: false, + }; + traceRow.supplier = true; + traceRow.isLoading = false; + traceRow.name = '111'; + traceRow.height = 20; + traceRow.height = 30; + expect(traceRow.clearCanvas(ctx)).toBeUndefined(); + }); + + it('TraceRow Test11', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.dataList = { + supplier: true, + isLoading: false, + }; + traceRow.supplier = true; + traceRow.isLoading = false; + traceRow.name = '111'; + traceRow.height = 20; + traceRow.height = 30; + expect(traceRow.drawLines(ctx)).toBeUndefined(); + }); + + it('TraceRow Test12', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.dataList = { + supplier: true, + isLoading: false, + }; + traceRow.supplier = true; + traceRow.isLoading = false; + traceRow.name = '111'; + traceRow.height = 20; + traceRow.height = 30; + expect(traceRow.drawSelection(ctx)).toBeUndefined(); + }); + + it('TraceRow Test13', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.collect).toBeFalsy(); + }); + + it('TraceRow Test14', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.collect = true; + expect(traceRow.collect).toBeTruthy(); + }); + + it('TraceRow Test15', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.rowType).toBeFalsy(); + }); + + it('TraceRow Test16', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowType = true; + expect(traceRow.rowType).toBeTruthy(); + }); + + it('TraceRow Test17', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.rowId).toBeFalsy(); + }); + + it('TraceRow Test18', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowId = true; + expect(traceRow.rowId).toBeTruthy(); + }); + + it('TraceRow Test19', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.rowParentId).toBeFalsy(); + }); + + it('TraceRow Test20', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowParentId = true; + expect(traceRow.rowParentId).toBeTruthy(); + }); + + it('TraceRow Test21', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowHidden = true; + expect(traceRow.rowHidden).toBeUndefined(); + }); + + it('TraceRow Test22', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.name).toBeFalsy(); + }); + + it('TraceRow Test23', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.folder = false; + expect(traceRow.folder).toBeFalsy(); + }); + + it('TraceRow Test24', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.folder = true; + expect(traceRow.folder).toBeTruthy(); + }); + + it('TraceRow Test25', () => { + // let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + // traceRow.expansion = false; + // expect(traceRow.expansion).toBeFalsy(); + }); + + it('TraceRow Test26', () => { + // let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + // traceRow.parentNode = jest.fn(()=>true); + // traceRow.parentNode.lastChild = jest.fn(()=>true); + // traceRow.expansion = true; + // expect(traceRow.expansion).toBeTruthy(); + }); + + it('TraceRow Test27', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.tip = true; + expect(traceRow.tip).toBeUndefined(); + }); + + it('TraceRow Test28', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.frame).not.toBeUndefined(); + }); + + it('TraceRow Test29', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.frame = [0, 0, 0]; + expect(traceRow.frame).toBeTruthy(); + }); + + it('TraceRow Test60', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.disabledCheck).not.toBeUndefined(); + }); + + it('TraceRow Test61', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.disabledCheck = true; + expect(traceRow.disabledCheck).toBeTruthy(); + }); + + it('TraceRow Test62', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.folderPaddingLeft).toBeUndefined(); + }); + + it('TraceRow Test30', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.checkType).not.toBeUndefined(); + }); + + it('TraceRow Test31', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.checkType = '-1'; + expect(traceRow.checkType).toBeTruthy(); + }); + + it('TraceRow Test32', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.drawType).toBe(0); + }); + + it('TraceRow Test33', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.drawType = true; + expect(traceRow.drawType).toBeTruthy(); + }); + + it('TraceRow Test34', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.args = jest.fn(() => true); + traceRow.args.isOffScreen = jest.fn(() => null); + expect(traceRow.updateWidth(1)).toBeUndefined(); + }); + + it('TraceRow Test36', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.onMouseHover()).toBeFalsy(); + }); + + it('TraceRow Test37', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.setTipLeft(1, null)).toBeFalsy(); + }); + + it('TraceRow Test38', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.onMouseLeave(1, 1)).toBeFalsy(); + }); + + it('TraceRow Test39', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.draw(false)).toBeFalsy(); + }); + + it('TraceRow Test40', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.collect = 1; + expect(traceRow.collect).toBeTruthy(); + }); + + it('TraceRow Test41', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.collect = 0; + expect(traceRow.collect).toBeFalsy(); + }); + + it('TraceRow Test42', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.checkType = '0'; + expect(traceRow.checkType).toBe('0'); + }); + + it('TraceRow Test43', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.checkType = '1'; + expect(traceRow.checkType).toBe('1'); + }); + + it('TraceRow Test44', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.checkType = '2'; + expect(traceRow.checkType).toBe('2'); + }); + + it('TraceRow Test45', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.checkType = 0; + expect(traceRow.checkType).toBe(''); + }); + + it('TraceRow Test46', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowHidden = false; + expect(traceRow.rowHidden).toBeUndefined(); + }); + + it('TraceRow Test47', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.highlight = false; + expect(traceRow.highlight).toBeFalsy(); + }); + + it('TraceRow Test48', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.highlight = true; + expect(traceRow.highlight).toBeFalsy(); + }); + + it('TraceRow Test49', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.setCheckBox = true; + expect(traceRow.highlight).toBeFalsy(); + }); + + it('TraceRow Test50', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.initCanvas = jest.fn(() => null); + expect(traceRow.connectedCallback()).toBeUndefined(); + }); + + it('TraceRow Test51', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.isInTimeRange()).toBe(false); + }); + + it('TraceRow Test52', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.getLineColor()).toBe(''); + }); + + it('TraceRow Test53', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let value = traceRow.attributeChangedCallback('name'); + expect(value).toBe(undefined); + }); + + it('TraceRow Test54', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let value = traceRow.attributeChangedCallback('height', '1', '2'); + expect(value).toBe(undefined); + }); + + it('TraceRow Test55', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + let value = traceRow.attributeChangedCallback('check-type', '1', 'check'); + expect(value).toBe(undefined); + }); + + it('TraceRow Test56', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + + + +
+
+ Current Bytes
+
+ Native Memory Density
+
+ +
+ +
+
+ +
+ +
+
+ " +`); + }); + it('TraceRow Test57', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.rowDiscard).toBeFalsy(); + }); + it('TraceRow Test58', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowDiscard = true; + expect(traceRow.rowDiscard).toBeTruthy(); + }); + it('TraceRow Test58', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.rowDiscard = false; + expect(traceRow.rowDiscard).toBeFalsy(); + }); + it('TraceRow Test59', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.disabledCheck = false; + expect(traceRow.disabledCheck).toBeFalsy(); + }); + it('TraceRow Test64', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + traceRow.folderPaddingLeft = 1; + expect(traceRow.folderPaddingLeft).toBeUndefined(); + }); + it('TraceRow Test65', () => { + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: true, + contextId: '2d', + isOffScreen: true, + }); + expect(traceRow.getTransferArray()).toStrictEqual([undefined]); + }); +}); diff --git a/ide/test/trace/component/trace/base/TraceRowConfig.test.ts b/ide/test/trace/component/trace/base/TraceRowConfig.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..196b7574d064877851aac00e06ffb5bdeae668a2 --- /dev/null +++ b/ide/test/trace/component/trace/base/TraceRowConfig.test.ts @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TraceRowConfig } from '../../../../../dist/trace/component/trace/base/TraceRowConfig.js'; +// @ts-ignore +import { TraceRow } from '../../../../../dist/trace/component/trace/base/TraceRow.js'; +// @ts-ignore +import { SpApplication } from '../../../../../dist/trace/SpApplication.js'; + +describe('TraceRowConfig Test', () => { + document.body.innerHTML = `
+ +
+ +
+
`; + let traceRowConfig = document.querySelector('#config') as TraceRowConfig; + + it('TraceRowConfig Test01', () => { + expect(traceRowConfig.init).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/base/TraceRowObject.test.ts b/ide/test/trace/component/trace/base/TraceRowObject.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bb998716964fefc31c3a294deed8acfb7094815 --- /dev/null +++ b/ide/test/trace/component/trace/base/TraceRowObject.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TraceRowObject } from '../../../../../dist/trace/component/trace/base/TraceRowObject.js'; + +describe('TraceRow Test', () => { + beforeAll(() => {}); + + it('Utils Test01', () => { + let traceRow = new TraceRowObject(); + expect(traceRow); + }); +}); diff --git a/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts b/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..240856f42dd33b9d7373ca7b770bcfd0c53c1a4d --- /dev/null +++ b/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TraceRowRecyclerView } from '../../../../../dist/trace/component/trace/base/TraceRowRecyclerView.js'; + +describe('TraceRow Test', () => { + beforeAll(() => {}); + + it('Utils Test01', () => { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow); + }); + + it('Test02', function () { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow.dataSource).toBeTruthy(); + }); + + it('Test03', function () { + let traceRow = new TraceRowRecyclerView(); + traceRow.measureHeight = jest.fn(() => true); + traceRow.dataSource = true; + expect(traceRow.dataSource).toBeTruthy(); + }); + + it('Test04', function () { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow.renderType).toBeTruthy(); + }); + + it('Test05', function () { + let traceRow = new TraceRowRecyclerView(); + traceRow.renderType = false; + expect(traceRow.renderType).toBeFalsy(); + }); + + it('Test06', function () { + let traceRow = new TraceRowRecyclerView(); + const obj = { + folder: false, + top: 0, + name: '', + children: false, + rowId: '', + rowType: '', + rowParentId: '1', + expansion: false, + rowHidden: false, + rowHeight: 40, + }; + const el = { + obj: undefined, + style: { top: 1, visibility: 'visible' }, + name: '', + rowId: '', + rowType: '', + rowParentId: '1', + expansion: false, + rowHidden: false, + setAttribute: '', + removeAttribute: '', + }; + expect(traceRow.refreshRow(el, !obj)).toBeUndefined(); + }); + + it('Test08', function () { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow.initUI()).toBeUndefined(); + }); + + it('Test09', function () { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow.initUI()).toBeUndefined(); + }); + + it('Test09', function () { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/base/TraceSheet.test.ts b/ide/test/trace/component/trace/base/TraceSheet.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..52ee6c4a0aa93417e4faddec5539d4194f95de2f --- /dev/null +++ b/ide/test/trace/component/trace/base/TraceSheet.test.ts @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TraceSheet } from '../../../../../dist/trace/component/trace/base/TraceSheet.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TraceSheet Test', () => { + beforeAll(() => {}); + let val = { + hasFps: 1, + cpus: { length: 1 }, + threadIds: [{ length: 2 }], + funTids: { length: 1 }, + trackIds: { length: 1 }, + heapIds: { length: 1 }, + nativeMemory: { length: 1 }, + cpuAbilityIds: { length: 1 }, + memoryAbilityIds: { length: 1 }, + diskAbilityIds: { length: 1 }, + networkAbilityIds: { length: 1 }, + }; + let e = { + detail: { + title: 1, + state: 0, + threadId: 1, + processId: 2, + }, + }; + let selection = { + hasFps: 1, + cpus: { length: 1 }, + threadIds: [{ length: 2 }], + funTids: { length: 1 }, + trackIds: { length: 1 }, + heapIds: { length: 1 }, + nativeMemory: { length: 1 }, + cpuAbilityIds: { length: 0 }, + memoryAbilityIds: { length: 0 }, + diskAbilityIds: { length: 0 }, + networkAbilityIds: { length: 0 }, + perfSampleIds: { length: 0 }, + processTrackIds: { length: 0 }, + fileSystemType: { length: 0 }, + virtualTrackIds: { length: 0 }, + sdkCounterIds: [ + { + length: 0, + }, + ], + sdkSliceIds: [ + { + length: 0, + }, + ], + }; + it('TraceSheet Test01', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet).not.toBeUndefined(); + }); + + it('TraceSheet Test08', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.connectedCallback()).toBeUndefined(); + }); + it('TraceSheet Test09', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.loadTabPaneData()).toBeUndefined(); + }); + + it('TraceSheet Test19', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+
+ + +
+ + + + + + +
+
+
" +`); + }); +}); diff --git a/ide/test/trace/component/trace/base/Utils.test.ts b/ide/test/trace/component/trace/base/Utils.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab7ddb5b66fc67d1d0b1543d5447da0063bbed24 --- /dev/null +++ b/ide/test/trace/component/trace/base/Utils.test.ts @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { Utils } from '../../../../../dist/trace/component/trace/base/Utils.js'; + +describe('Utils Test', () => { + beforeAll(() => {}); + + it('Utils Test01', () => { + let instance = Utils.getInstance(); + let instance2 = Utils.getInstance(); + expect(instance).toBe(instance2); + }); + + it('Utils Test02', () => { + let instance = Utils.getInstance(); + expect(instance.getStatusMap().get('D')).toBe('Uninterruptible Sleep'); + }); + + it('Utils Test03', () => { + expect(Utils.getEndState('D')).toBe('Uninterruptible Sleep'); + }); + + it('Utils Test04', () => { + expect(Utils.getEndState('')).toBe(''); + }); + + it('Utils Test05', () => { + expect(Utils.getEndState('ggg')).toBe('Unknown State'); + }); + + it('Utils Test06', () => { + expect(Utils.getStateColor('D')).toBe('#f19b38'); + }); + + it('Utils Test07', () => { + expect(Utils.getStateColor('R')).toBe('#a0b84d'); + }); + it('Utils Test08', () => { + expect(Utils.getStateColor('I')).toBe('#673ab7'); + }); + + it('Utils Test09', () => { + expect(Utils.getStateColor('Running')).toBe('#467b3b'); + }); + + it('Utils Test09', () => { + expect(Utils.getStateColor('S')).toBe('#e0e0e0'); + }); + + it('Utils Test10', () => { + expect(Utils.getTimeString(5900_000_000_000)).toBe('1h 38m '); + }); + + it('Utils Test11', () => { + expect(Utils.getByteWithUnit(2_000_000_000)).toBe('1.86 Gb'); + }); + + it('Utils Test12', () => { + expect(Utils.getByteWithUnit(1_000_000_000)).toBe('953.67 Mb'); + }); + + it('Utils Test13', () => { + expect(Utils.getByteWithUnit(1000_000)).toBe('976.56 Kb'); + }); + + it('Utils Test23', () => { + expect(Utils.getByteWithUnit(-2_000)).toBe('-1.95 Kb'); + }); + + it('Utils Test14', () => { + expect(Utils.getTimeString(1_000_000_000_000)).toBe('16m 40s '); + }); + + it('Utils Test15', () => { + expect(Utils.getTimeString(2_000_000)).toBe('2ms '); + }); + + it('Utils Test16', () => { + expect(Utils.getTimeString(3_000)).toBe('3μs '); + }); + + it('Utils Test17', () => { + expect(Utils.getTimeString(300)).toBe('300ns '); + }); + + it('Utils Test18', () => { + expect(Utils.getTimeStringHMS(5900_000_000_000)).toBe('1:38:'); + }); + + it('Utils Test19', () => { + expect(Utils.getTimeStringHMS(3_000_000_000)).toBe('3:'); + }); + + it('Utils Test20', () => { + expect(Utils.getTimeStringHMS(2_000_000)).toBe('2.'); + }); + + it('Utils Test21', () => { + expect(Utils.getTimeStringHMS(5_000)).toBe('5.'); + }); + + it('Utils Test22', () => { + expect(Utils.getTimeStringHMS(90)).toBe('90'); + }); + + it('Utils Test24', () => { + expect(Utils.getBinaryByteWithUnit(0)).toBe('0Bytes'); + }); + + it('Utils Test25', () => { + expect(Utils.getBinaryByteWithUnit(3_000_000_000)).toBe('2.79GB'); + }); + + it('Utils Test26', () => { + expect(Utils.getBinaryByteWithUnit(2_000_000)).toBe('1.91MB'); + }); + + it('Utils Test27', () => { + expect(Utils.getBinaryByteWithUnit(2_000)).toBe('1.95KB'); + }); + + it('Utils Test28', () => { + expect(Utils.getTimeStampHMS(3900_000_000_000)).toBe('01:05:00:000.000'); + }); + + it('Utils Test29', () => { + expect(Utils.getTimeStampHMS(70_000_000_000)).toBe('01:10:000.000'); + }); + + it('Utils Test30', () => { + expect(Utils.getTimeStampHMS(2_000_000_000)).toBe('02:000.000'); + }); + + it('Utils Test31', () => { + expect(Utils.getTimeStampHMS(2_000_000)).toBe('00:002.000'); + }); + + it('Utils Test32', () => { + expect(Utils.getTimeStampHMS(2_000)).toBe('00:000.002.'); + }); + + it('Utils Test33', () => { + expect(Utils.getTimeStampHMS(1)).toBe('00:000.000001'); + }); + + it('Utils Test40', () => { + expect(Utils.getDurString(61_000_000_000)).toBe('61.000 s '); + }); + + it('Utils Test34', () => { + expect(Utils.getDurString(2_000_000_000)).toBe('2.000 s '); + }); + + it('Utils Test35', () => { + expect(Utils.getDurString(1_800_000)).toBe('1 ms '); + }); + + it('Utils Test36', () => { + expect(Utils.timeMsFormat2p(3800_000)).toBe('1.00h'); + }); + + it('Utils Test37', () => { + expect(Utils.timeMsFormat2p(90_000)).toBe('2.00min'); + }); + + it('Utils Test38', () => { + expect(Utils.timeMsFormat2p(2_000)).toBe('2.00s'); + }); + + it('Utils Test39', () => { + expect(Utils.timeMsFormat2p(1)).toBe('1.00ms'); + }); + + it('Utils Test41', () => { + expect(Utils.getProbablyTime(3600_000_000_000)).toBe('1.00h '); + }); + + it('Utils Test42', () => { + expect(Utils.getProbablyTime(60_000_000_000)).toBe('1.00m '); + }); + + it('Utils Test43', () => { + expect(Utils.getProbablyTime(1_000_000_000)).toBe('1.00s '); + }); + + it('Utils Test44', () => { + expect(Utils.getProbablyTime(1_000_000)).toBe('1.00ms '); + }); + + it('Utils Test45', () => { + expect(Utils.getProbablyTime(1_000)).toBe('1.00μs '); + }); + + it('Utils Test46', () => { + expect(Utils.getProbablyTime(0)).toBe('0'); + }); + + it('Utils Test47', () => { + expect(Utils.groupByMap([], '')).not.toBeUndefined(); + }); + + it('Utils Test48', () => { + expect(Utils.uuid).not.toBeUndefined(); + }); + + it('Utils Test49', () => { + expect(Utils.removeDuplicates([10], [11], 'pid')).not.toBeUndefined(); + }); + + it('Utils Test50', () => { + expect(Utils.groupBy([], '')).not.toBeUndefined(); + }); + + it('Utils Test51', () => { + expect(Utils.getTimeStringHMS(0)).toBe('0'); + }); + + it('Utils Test52', () => { + expect(Utils.timeMsFormat2p(0)).toBe('0s'); + }); + + it('Utils Test53', () => { + expect(Utils.getBinaryByteWithUnit(1)).toBe('1.00Bytes'); + }); + + it('Utils Test54', () => { + expect(Utils.getTimeStampHMS(0)).toBe('00:000.000'); + }); + + it('Utils Test55', () => { + expect(Utils.getDurString(1)).toBe('1'); + }); + + it('Utils Test56', () => { + expect(Utils.getCompletionTime(300, 3)).toBe('300'); + }); + + it('Utils Test57', () => { + expect(Utils.getCompletionTime(30, 3)).toBe('030'); + }); + + it('Utils Test58', () => { + expect(Utils.getCompletionTime(0, 0)).toBe('0'); + }); + + it('Utils Test59', () => { + expect(Utils.groupByMap([10], 'pid')).not.toBeUndefined(); + }); + + it('Utils Test60', () => { + expect(Utils.getProbablyTime(1)).toBe('1ns '); + }); + + it('Utils Test61', () => { + expect(Utils.groupBy([10], 'pid')).not.toBeUndefined(); + }); + + afterAll(() => { + // 后处理操作 + }); +}); diff --git a/ide/test/trace/component/trace/search/Search.test.ts b/ide/test/trace/component/trace/search/Search.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8bb7079c704313320ce37a0275e8514f094562b4 --- /dev/null +++ b/ide/test/trace/component/trace/search/Search.test.ts @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { LitSearch } from '../../../../../dist/trace/component/trace/search/Search.js'; + +describe(' SearchTest', () => { + beforeAll(() => {}); + it('Search Test01', () => { + let search = new LitSearch(); + expect(search).not.toBeUndefined(); + }); + + it('Search Test02', () => { + let search = new LitSearch(); + search.list = ['1']; + expect(search.list[0]).toBe('1'); + }); + + it('Search Test03', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.index).toBe(1); + }); + + it('Search Test04', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.total).toBe(0); + }); + + it('Search Test05', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent('1', 2)).toBeUndefined(); + }); + + it('Search Test06', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent('1', 101)).toBeUndefined(); + }); + + it('Search Test07', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent('1', -1)).toBeUndefined(); + }); + + it('Search Test08', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent('1', -2)).toBeUndefined(); + }); + + it('Search Test09', () => { + let search = new LitSearch(); + expect(search.clear()).toBeUndefined(); + }); + + it('Search Test11', function () { + let search = new LitSearch(); + search.search = jest.fn(() => undefined); + search.search.blur = jest.fn(() => true); + expect(search.blur()).toBeUndefined(); + }); + + it('Search Test10', () => { + let search = new LitSearch(); + expect(search.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }); + + it('Search Test12', () => { + let search = new LitSearch(); + expect(search.searchValue).toBe(''); + }); + + it('Search Test13', () => { + let search = new LitSearch(); + expect(search.isLoading).toBeFalsy(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts b/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5304de1e858f66172a371bfcb60bb7b297a8c7be --- /dev/null +++ b/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts @@ -0,0 +1,523 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { getTimeString, TabPaneCurrentSelection } from '../../../../../dist/trace/component/trace/sheet/TabPaneCurrentSelection.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +const sqlite = require('../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPaneCurrentSelection Test', () => { + let tabPaneCurrentSelection = new TabPaneCurrentSelection(); + + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + let context = canvas.getContext('2d'); + + let cpuData = [ + { + cpu: 1, + dur: 1, + end_state: 'string', + id: 12, + name: 'name', + priority: 11, + processCmdLine: 'processCmdLine', + processId: 111, + processName: 'processName', + schedId: 22, + startTime: 0, + tid: 100, + type: 'type', + }, + ]; + let functionData = [ + { + argsetid: 53161, + depth: 0, + dur: 570000, + funName: 'binder transaction', + id: 92749, + is_main_thread: 0, + parent_id: null, + startTs: 9729867000, + threadName: 'Thread-15', + tid: 2785, + }, + ]; + let memData = [ + { + trackId: 100, + processName: 'processName', + pid: 11, + upid: 1, + trackName: 'trackName', + type: 'type', + track_id: 'track_id', + value: 111, + startTime: 0, + duration: 1000, + maxValue: 4000, + delta: 2, + }, + ]; + let threadData = [ + { + hasSched: 14724852000, + pid: 2519, + processName: null, + threadName: 'ACCS0', + tid: 2716, + upid: 1, + utid: 1, + cpu: null, + dur: 405000, + end_ts: null, + id: 1, + is_main_thread: 0, + name: 'ACCS0', + startTime: 58000, + start_ts: null, + state: 'S', + type: 'thread', + }, + ]; + let wakeupBean = [ + { + wakeupTime: 0, + cpu: 1, + process: 'process', + pid: 11, + thread: 'thread', + tid: 22, + schedulingLatency: 33, + schedulingDesc: 'schedulingDesc', + }, + ]; + + let queryData = [ + { + id: 1, + startTime: 0, + hasSched: 14724852000, + pid: 2519, + processName: null, + threadName: 'ACCS0', + tid: 2716, + upid: 1, + utid: 1, + cpu: null, + dur: 405000, + end_ts: null, + is_main_thread: 0, + name: 'ACCS0', + start_ts: null, + state: 'S', + type: 'thread', + }, + ]; + let scrollWakeUp = [ + { + startTime: 0, + pid: 11, + tid: 22, + }, + ]; + let data = [ + { + cpu: 1, + dur: 1, + end_state: 'string', + id: 12, + name: 'name', + priority: 11, + processCmdLine: 'processCmdLine', + processId: 111, + processName: 'processName', + schedId: 22, + startTime: 0, + tid: 100, + type: 'type', + }, + ]; + + let jankData = { + id: 10, + ts: 25415, + dur: 1200, + name: '1523', + depth: 1, + jank_tag: true, + cmdline: 'com.test', + type: '0', + pid: 20, + frame_type: 'app', + app_dur: 110, + dst_slice: 488, + }; + + let jankDataRender = { + id: 25, + ts: 254151, + dur: 1202, + name: '1583', + depth: 1, + jank_tag: true, + cmdline: 'render.test', + type: '0', + pid: 20, + frame_type: 'render_service', + src_slice: '525', + rs_ts: 2569, + rs_vsync: '2569', + rs_dur: 1528, + rs_pid: 1252, + rs_name: 'name', + gpu_dur: 2568, + }; + + let irqData = [ + { + id: 25, + startNS: 1526, + name: 'test', + dur: 125, + argSetId: 526, + }, + ]; + + let clockData = [ + { + filterId: 96, + value: 253, + startNS: 25852, + dur: 125, + delta: 2586, + }, + ]; + + let functionDataTest = { + argsetid: 53161, + depth: 0, + dur: 570000, + funName: 'binder async', + id: 92749, + is_main_thread: 0, + parent_id: null, + startTs: 9729867000, + threadName: 'Thread-15', + tid: 2785, + }; + + tabPaneCurrentSelection.queryWakeUpData = jest.fn(() => 'WakeUpData'); + tabPaneCurrentSelection.queryWakeUpData.wb = jest.fn(() => null); + tabPaneCurrentSelection.setCpuData(cpuData, undefined, 1); + let argsetTest = sqlite.queryBinderArgsByArgset; + let argsetIdTest = sqlite.queryBinderByArgsId; + let argsetData = [ + { + argset: 12, + keyName: 'test', + id: 123, + desc: 'desc', + strValue: 'value', + }, + { + argset: 11, + keyName: 'test', + id: 113, + desc: 'desc', + strValue: 'value', + }, + ]; + + let argsetIdData = [ + { + type: 'func', + startTs: 1258, + dur: 25, + depth: 1, + argsetid: 258, + }, + ]; + argsetTest.mockResolvedValue(argsetData); + argsetIdTest.mockResolvedValue(argsetIdData); + + let gpuDur = sqlite.queryGpuDur; + let gpuDurData = [ + { + gpu_dur: 1528, + }, + ]; + gpuDur.mockResolvedValue(gpuDurData); + + let queryFlows = sqlite.queryFlowsData; + let queryFlowsData = [ + { + name: '25962', + pid: 1885, + cmdline: 'render Test', + type: 1, + }, + ]; + queryFlows.mockResolvedValue(queryFlowsData); + + let queryPreceding = sqlite.queryPrecedingData; + let queryPrecedingData = [ + { + name: '2596562', + pid: 18854, + cmdline: 'app Test', + type: 0, + }, + ]; + queryPreceding.mockResolvedValue(queryPrecedingData); + + tabPaneCurrentSelection.queryWakeUpData = jest.fn(() => 'WakeUpData'); + tabPaneCurrentSelection.queryWakeUpData.wb = jest.fn(() => null); + tabPaneCurrentSelection.setCpuData(cpuData, undefined, 1); + + it('TabPaneCurrentSelectionTest01', function () { + let result = tabPaneCurrentSelection.setFunctionData(functionData); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest02', function () { + let result = tabPaneCurrentSelection.setMemData(memData); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest03', function () { + let result = getTimeString(3600_000_000_002); + expect(result).toBe('1h 2ns '); + }); + + it('TabPaneCurrentSelectionTest04', function () { + let result = getTimeString(60000000001); + expect(result).toBe('1m 1ns '); + }); + + it('TabPaneCurrentSelectionTest05', function () { + let result = getTimeString(1000000001); + expect(result).toBe('1s 1ns '); + }); + + it('TabPaneCurrentSelectionTest06', function () { + let result = getTimeString(1000001); + expect(result).toBe('1ms 1ns '); + }); + + it('TabPaneCurrentSelectionTest07', function () { + let result = getTimeString(1001); + expect(result).toBe('1μs 1ns '); + }); + + it('TabPaneCurrentSelectionTest08', function () { + let result = getTimeString(101); + expect(result).toBe('101ns '); + }); + + it('TabPaneCurrentSelectionTest09', function () { + tabPaneCurrentSelection.setCpuData = jest.fn(() => true); + tabPaneCurrentSelection.data = jest.fn(() => true); + expect(tabPaneCurrentSelection.data).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest10', function () { + expect(tabPaneCurrentSelection.setCpuData(cpuData, undefined, 1)).toBeTruthy(); + }); + + it('TabPaneCurrentSelectionTest13', function () { + expect(tabPaneCurrentSelection.initCanvas()).not.toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest14', function () { + let str = { + length: 0, + }; + expect(tabPaneCurrentSelection.transferString(str)).toBe(''); + }); + + it('TabPaneCurrentSelectionTest15', function () { + expect(tabPaneCurrentSelection.transferString('&')).not.toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest16', function () { + expect(tabPaneCurrentSelection.drawRight(null)).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest01', function () { + let result = tabPaneCurrentSelection.setFunctionData(functionData); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest02', function () { + let result = tabPaneCurrentSelection.setMemData(memData); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest03', function () { + let result = getTimeString(3600_000_000_002); + expect(result).toBe('1h 2ns '); + }); + + it('TabPaneCurrentSelectionTest04', function () { + let result = getTimeString(60000000001); + expect(result).toBe('1m 1ns '); + }); + + it('TabPaneCurrentSelectionTest05', function () { + let result = getTimeString(1000000001); + expect(result).toBe('1s 1ns '); + }); + + it('TabPaneCurrentSelectionTest06', function () { + let result = getTimeString(1000001); + expect(result).toBe('1ms 1ns '); + }); + + it('TabPaneCurrentSelectionTest07', function () { + let result = getTimeString(1001); + expect(result).toBe('1μs 1ns '); + }); + + it('TabPaneCurrentSelectionTest08', function () { + let result = getTimeString(101); + expect(result).toBe('101ns '); + }); + + it('TabPaneCurrentSelectionTest09', function () { + tabPaneCurrentSelection.setCpuData = jest.fn(() => true); + tabPaneCurrentSelection.data = jest.fn(() => true); + expect(tabPaneCurrentSelection.data).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest10', function () { + expect(tabPaneCurrentSelection.setCpuData(cpuData, undefined, 1)).toBeTruthy(); + }); + + it('TabPaneCurrentSelectionTest13', function () { + expect(tabPaneCurrentSelection.initCanvas()).not.toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest14', function () { + let str = { + length: 0, + }; + expect(tabPaneCurrentSelection.transferString(str)).toBe(''); + }); + + it('TabPaneCurrentSelectionTest15', function () { + expect(tabPaneCurrentSelection.transferString('&')).not.toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest16', function () { + expect(tabPaneCurrentSelection.drawRight(null)).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest11', function () { + expect(tabPaneCurrentSelection.initHtml()).toMatchInlineSnapshot(` +" + +
+
+

+

Scheduling Latency

+
+
+
+ + + + + + + + +
+
+ +
+
+
+ " +`); + }); + + it('TabPaneCurrentSelectionTest12', function () { + let result = tabPaneCurrentSelection.setJankData(jankData, undefined, 1); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest13', function () { + let result = tabPaneCurrentSelection.setJankData(jankDataRender, undefined, 1); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest14', function () { + let result = tabPaneCurrentSelection.setIrqData(irqData); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest15', function () { + let result = tabPaneCurrentSelection.setThreadData(threadData, undefined, 1); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest16', function () { + let result = tabPaneCurrentSelection.setClockData(clockData); + expect(result).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest17', function () { + let result = tabPaneCurrentSelection.setFunctionData(functionDataTest); + expect(result).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/TabPaneFilter.test.ts b/ide/test/trace/component/trace/sheet/TabPaneFilter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5175d2bbc6655395fc7553e524fe0be74668afbc --- /dev/null +++ b/ide/test/trace/component/trace/sheet/TabPaneFilter.test.ts @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFilter } from '../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; + +describe('TabPaneFilter Test', () => { + let tabPaneFilter = new TabPaneFilter(); + + it('TabPaneFilterTest01', function () { + expect(tabPaneFilter.firstSelect).toBe(''); + }); + + it('TabPaneFilterTest02', function () { + expect(tabPaneFilter.secondSelect).toBe(''); + }); + + it('TabPaneFilterTest03', function () { + expect(tabPaneFilter.filterValue).toBe(''); + }); + + it('TabPaneFilterTest04', function () { + tabPaneFilter.filterValue = true; + expect(tabPaneFilter.filterValue).toBeTruthy(); + }); + + it('TabPaneFilterTest05', function () { + expect(tabPaneFilter.icon).toBe('tree'); + }); + + it('TabPaneFilterTest08', function () { + tabPaneFilter.iconEL.name = 'menu'; + expect(tabPaneFilter.icon).toBe('block'); + }); + + it('TabPaneFilterTest09', function () { + tabPaneFilter.iconEL.name = ''; + expect(tabPaneFilter.icon).toBe(''); + }); + + it('TabPaneFilterTest06', function () { + tabPaneFilter.icon = true; + expect(tabPaneFilter.icon).toBe(''); + }); + + it('TabPaneFilterTest010', function () { + tabPaneFilter.icon = 'block'; + expect(tabPaneFilter.icon).toBe('block'); + }); + + it('TabPaneFilterTest011', function () { + tabPaneFilter.icon = 'tree'; + expect(tabPaneFilter.icon).toBe('tree'); + }); + + it('TabPaneFilterTest07', function () { + expect(tabPaneFilter.initHtml()).toMatchInlineSnapshot(` +" + + + Input Filter + + +
+ +
+ +
+
Invert
+
Hide System so
+
+ Options +
+ +
+ + + +
+
Constraints:Only enabled with data and while stopped;
+
filters data to thresholds.
+
+ +
+
+ Sample Count Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Symbol Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Library Filter +
+
+ +
Statistics by Thread
+
+ " +`); + }); + + it('TabPaneFilterTest10', function () { + expect(tabPaneFilter.addDataMining({ name: '' }, '')).toBe(-1); + }); + + it('TabPaneFilterTest11', function () { + expect(tabPaneFilter.getFilterTreeData()).not.toBeUndefined(); + }); + + it('TabPaneFilterTest12', function () { + expect(tabPaneFilter.initializeFilterTree(true, true, true)).toBeUndefined(); + }); + + it('TabPaneFilterTest13', function () { + expect(tabPaneFilter.disabledMining).toBeFalsy(); + }); + + it('TabPaneFilterTest14', function () { + tabPaneFilter.disabledMining = true; + expect(tabPaneFilter.disabledMining).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/ability/TabPaneCpuAbility.test.ts b/ide/test/trace/component/trace/sheet/ability/TabPaneCpuAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9682d4e33609dc678d1e7e04959676ba5a04b3ed --- /dev/null +++ b/ide/test/trace/component/trace/sheet/ability/TabPaneCpuAbility.test.ts @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { TabPaneCpuAbility } from '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneCpuAbility.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneCpuAbility Test', () => { + let tabPaneCpuAbility = new TabPaneCpuAbility(); + + it('TabPaneCpuAbilityTest01', function () { + tabPaneCpuAbility.queryResult.length = 2; + expect(tabPaneCpuAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest02', function () { + const systemCpuSummary = { + startTimeStr: '', + durationStr: '', + totalLoadStr: '', + userLoadStr: '', + systemLoadStr: '', + threadsStr: '', + }; + expect(tabPaneCpuAbility.toCpuAbilityArray(systemCpuSummary)).not.toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest03 ', function () { + expect( + tabPaneCpuAbility.sortByColumn({ + key: 'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest04 ', function () { + expect( + tabPaneCpuAbility.sortByColumn({ + key: !'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest05 ', function () { + expect( + tabPaneCpuAbility.sortByColumn({ + key: 'totalLoadStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest06 ', function () { + expect( + tabPaneCpuAbility.sortByColumn({ + key: 'userLoadStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest07 ', function () { + expect( + tabPaneCpuAbility.sortByColumn({ + key: 'systemLoadStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest08 ', function () { + expect( + tabPaneCpuAbility.sortByColumn({ + key: 'durationStr', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/ability/TabPaneDiskAbility.test.ts b/ide/test/trace/component/trace/sheet/ability/TabPaneDiskAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5409e936f18dacd75a70928e8688bf80fbe8b420 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/ability/TabPaneDiskAbility.test.ts @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneDiskAbility } from '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneDiskAbility.js'; +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneDiskAbility Test', () => { + let tabPaneDiskAbility = new TabPaneDiskAbility(); + it('TabPaneDiskAbilityTest01', () => { + tabPaneDiskAbility.queryResult.length = 1; + expect(tabPaneDiskAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest02 ', function () { + const val = { + startTimeStr: '', + durationStr: '', + dataReadStr: '', + dataReadSecStr: '', + dataWriteStr: '', + readsInStr: '', + readsInSecStr: '', + writeOutStr: '', + writeOutSecStr: '', + }; + expect(tabPaneDiskAbility.toDiskAbilityArray(val)).not.toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest03 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest04 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: !'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest05 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'durationStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest06 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'dataReadStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest07 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'dataReadSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest08 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'dataWriteStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest09 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'dataWriteSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest10 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'readsInStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest11 ', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'readsInSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest12', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'writeOutStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest13', function () { + expect( + tabPaneDiskAbility.sortByColumn({ + key: 'writeOutSecStr', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.test.ts b/ide/test/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..884a21960b98c7a1b64ecfc0f65a4196f757afa1 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneHistoryProcesses } from '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneHistoryProcesses.js'; +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneHistoryProcesses Test', function () { + let tabPaneHistoryProcesses = new TabPaneHistoryProcesses(); + it('TabPaneHistoryProcessesTest01 ', function () { + tabPaneHistoryProcesses.queryResult.length = 1; + expect(tabPaneHistoryProcesses.filterData()).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest02 ', function () { + const val = { + processId: -1, + processName: '', + alive: '', + firstSeen: '', + lastSeen: '', + responsibleProcess: '', + userName: '', + cpuTime: '', + }; + expect(tabPaneHistoryProcesses.toProcessHistoryArray(val)).not.toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest03 ', function () { + expect( + tabPaneHistoryProcesses.sortByColumn({ + key: 'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest04 ', function () { + expect( + tabPaneHistoryProcesses.sortByColumn({ + key: 'alive', + }) + ).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest11 ', function () { + expect( + tabPaneHistoryProcesses.sortByColumn({ + key: !'startTime' && !'alive', + }) + ).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest04 ', function () { + expect( + tabPaneHistoryProcesses.sortByColumn({ + key: 'cpuTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest06', function () { + expect(tabPaneHistoryProcesses.timeFormat(3600001)).toBe('1 h 1 ms '); + }); + + it('TabPaneHistoryProcessesTest07', function () { + expect(tabPaneHistoryProcesses.timeFormat(60001)).toBe('1 min 1 ms '); + }); + + it('TabPaneHistoryProcessesTest08', function () { + expect(tabPaneHistoryProcesses.timeFormat(1001)).toBe('1 s 1 ms '); + }); + + it('TabPaneHistoryProcessesTest09', function () { + expect(tabPaneHistoryProcesses.timeFormat(1)).toBe('1 ms '); + }); + + it('TabPaneHistoryProcessesTest10', function () { + expect(tabPaneHistoryProcesses.timeFormat(0)).toBe('0 ms '); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/ability/TabPaneLiveProcesses.test.ts b/ide/test/trace/component/trace/sheet/ability/TabPaneLiveProcesses.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d23e7756bcbedfb81be16e70c2cc39444586a6b4 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/ability/TabPaneLiveProcesses.test.ts @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneLiveProcesses } from '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneLiveProcesses.js'; +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneLiveProcesses Test', function () { + let tabPaneLiveProcesses = new TabPaneLiveProcesses(); + + it('TabPaneLiveProcessesTest01 ', function () { + tabPaneLiveProcesses.queryResult.length = 1; + expect(tabPaneLiveProcesses.filterData()).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest02 ', function () { + const live = { + processId: 1, + processName: '', + responsibleProcess: '', + userName: '', + cpu: '1', + threads: -1, + memory: '', + diskReads: -1, + diskWrite: -1, + }; + expect(tabPaneLiveProcesses.toLiveProcessArray(live)).not.toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest03 ', function () { + expect( + tabPaneLiveProcesses.sortByColumn({ + key: 'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest07 ', function () { + expect( + tabPaneLiveProcesses.sortByColumn({ + key: 'cpuTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest04 ', function () { + expect( + tabPaneLiveProcesses.sortByColumn({ + key: !'startTime' || !'cpuTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest09 ', function () { + expect( + tabPaneLiveProcesses.sortByColumn({ + key: 'memory', + }) + ).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest05', function () { + expect(tabPaneLiveProcesses.timeFormat(70000)).toBe('1 min 10 s 0 ms '); + }); + + it('TabPaneLiveProcessesTest06', function () { + expect(tabPaneLiveProcesses.timeFormat(2000)).toBe('2 s 0 ms '); + }); + + it('TabPaneLiveProcessesTest07', function () { + expect(tabPaneLiveProcesses.timeFormat(3600002)).toBe('1 h 2 ms '); + }); + + it('TabPaneLiveProcessesTest08', function () { + expect(tabPaneLiveProcesses.timeFormat(10)).toBe('10 ms '); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/ability/TabPaneMemoryAbility.test.ts b/ide/test/trace/component/trace/sheet/ability/TabPaneMemoryAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d2e847e8e8135672d070f4b375fd27ccb000ce53 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/ability/TabPaneMemoryAbility.test.ts @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { TabPaneMemoryAbility } from '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneMemoryAbility.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPaneMemoryAbility Test', () => { + let tabPaneMemoryAbility = new TabPaneMemoryAbility(); + let queryStartTime = sqlit.queryStartTime; + queryStartTime.mockResolvedValue([ + { + start_ts: 0, + }, + ]); + + let queryMemoryAbilityData = sqlit.getTabMemoryAbilityData; + queryMemoryAbilityData.mockResolvedValue([ + { + startTime: 0, + name: 's', + value: 'd,ds,f', + }, + { + startTime: 10000, + name: 's', + value: 'd,ds,f', + }, + { + startTime: 20000, + name: 's', + value: 'd,ds,f', + }, + ]); + + tabPaneMemoryAbility.tbl = jest.fn(() => true); + tabPaneMemoryAbility.tbl.recycleDataSource = jest.fn(() => []); + tabPaneMemoryAbility.data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 1000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + + it('TabPaneMemoryAbilityTest01', function () { + tabPaneMemoryAbility.queryResult.length = 1; + expect(tabPaneMemoryAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest02', function () { + const systemMemorySummary = [ + { + startTimeStr: '1', + durationStr: '1', + cached: '1', + swapTotal: '1', + }, + ]; + expect(tabPaneMemoryAbility.toMemoryAbilityArray(systemMemorySummary)).not.toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest03', function () { + expect( + tabPaneMemoryAbility.sortByColumn({ + key: 'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest04', function () { + expect( + tabPaneMemoryAbility.sortByColumn({ + key: !'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest05', function () { + expect( + tabPaneMemoryAbility.sortByColumn({ + key: 'durationStr', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/ability/TabPaneNetworkAbility.test.ts b/ide/test/trace/component/trace/sheet/ability/TabPaneNetworkAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a67b402101ce75b2d83b602a435865516da1bbc9 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/ability/TabPaneNetworkAbility.test.ts @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneNetworkAbility } from '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneNetworkAbility.js'; +import '../../../../../../dist/trace/component/trace/sheet/ability/TabPaneNetworkAbility.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPaneNetworkAbility Test', () => { + let tabPaneNetworkAbility = new TabPaneNetworkAbility(); + let tabNetworkAbilityData = sqlit.getTabNetworkAbilityData; + + tabNetworkAbilityData.mockResolvedValue([ + { + startTime: 1000, + duration: 200, + dataReceived: 100.0, + dataReceivedSec: 100.0, + dataSend: 200.0, + dataSendSec: 100.0, + packetsIn: 100.0, + packetsInSec: 100.0, + packetsOut: 200.0, + packetsOutSec: 100.0, + }, + ]); + + tabPaneNetworkAbility.data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 1000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + + it('TabPaneNetworkAbilityTest01', () => { + tabPaneNetworkAbility.queryResult.length = 1; + let queryResult = [ + { + startTimeStr: 's', + durationStr: 's', + dataReceivedStr: 's', + dataReceivedSecStr: 's', + dataSendSecStr: 's', + dataSendStr: 's', + packetsIn: 's', + packetsOut: 's', + packetsOutSec: 's', + }, + ]; + tabPaneNetworkAbility.search = jest.fn(() => 's'); + tabPaneNetworkAbility.queryResult = jest.fn(() => queryResult); + expect(tabPaneNetworkAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest02 ', function () { + const val = { + startTimeStr: '', + durationStr: '', + dataReceivedStr: '', + dataReceivedSecStr: '', + dataSendSecStr: '', + dataSendStr: '', + packetsIn: -1, + packetsOut: -1, + packetsOutSec: -1, + }; + expect(tabPaneNetworkAbility.toNetWorkAbilityArray(val)).not.toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest03 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest04 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: !'startTime', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest05 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'dataSendSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest06 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'packetsInStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest07 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'packetsInSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest08 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'packetsOutStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest09 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'packetsOutSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest10 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'dataSendStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest11 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'dataReceivedSecStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest12 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'durationStr', + }) + ).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest13 ', function () { + expect( + tabPaneNetworkAbility.sortByColumn({ + key: 'dataReceivedStr', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/clock/TabPaneClockCounter.test.ts b/ide/test/trace/component/trace/sheet/clock/TabPaneClockCounter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..505199ec840c8b8759dccab53d518334058d557e --- /dev/null +++ b/ide/test/trace/component/trace/sheet/clock/TabPaneClockCounter.test.ts @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneClockCounter } from '../../../../../../dist/trace/component/trace/sheet/clock/TabPaneClockCounter.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneClockCounter Test', () => { + let clockCounter = new TabPaneClockCounter(); + let map = new Map(); + map.set('clock', [ + { + filterId: 255, + value: 1252, + startNS: 4515, + dur: 5255, + delta: 415, + }, + ]); + let clockCounterData = { + leftNs: 253, + rightNs: 1252, + clockMapData: map, + }; + + it('TabPaneClockCounterTest01', function () { + clockCounter.data = clockCounterData; + expect(clockCounter.data).toBeUndefined(); + }); + + it('TabPaneClockCounterTest02', function () { + expect( + clockCounter.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneBoxChild.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneBoxChild.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e13d077186024297c9a9ba8d075d98769923383 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneBoxChild.test.ts @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +// import { it } from "mocha" +import { TabPaneBoxChild } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneBoxChild.js'; +import { getTabBoxChildData } from '../../../../../../src/trace/database/SqlLite'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneBoxChild Test', () => { + document.body.innerHTML = `
`; + let element = document.querySelector('#div') as HTMLDivElement; + let tabPaneBoxChild = new TabPaneBoxChild(); + element.appendChild(tabPaneBoxChild); + tabPaneBoxChild.loadDataInCache = true; + tabPaneBoxChild.data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + }; + let val = { + leftNs: 2, + rightNs: 1, + state: '1', + processId: 0, + threadId: 1, + }; + + it('TabPaneBoxChildTest01', function () { + expect( + tabPaneBoxChild.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + + it('TabPaneCounterTest02', function () { + expect( + tabPaneBoxChild.sortByColumn({ + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneCounterTest03', function () { + expect(tabPaneBoxChild.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneContextSwitch.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneContextSwitch.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c909df3aeca9a4f71a978a99ec1123f2eb29f31a --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneContextSwitch.test.ts @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneContextSwitch } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneContextSwitch.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('TabPaneContextSwitch Test', () => { + document.body.innerHTML = `
`; + let tab = document.querySelector('.ddd') as HTMLDivElement; + let tabPaneContextSwitch = new TabPaneContextSwitch(); + tabPaneContextSwitch.tbl = jest.fn(() => tab); + tabPaneContextSwitch.tbl.treeElement = jest.fn(() => tab); + tabPaneContextSwitch.tbl.tableElement = jest.fn(() => tab); + SpSystemTrace.SPT_DATA = [ + { + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 1, + thread: '', + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 2, + thread: '', + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + + let dataArray = { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + }; + + it('TabPaneContextSwitchTest01', function () { + expect(tabPaneContextSwitch).not.toBeUndefined(); + }); + + it('TabPanePTSTest02', function () { + expect(tabPaneContextSwitch.getDataBySPT(0, 0, [])).toBeUndefined(); + }); + + it('TabPaneContextSwitchTest03', function () { + let mockgetProcessThreadDataByRange = sqlit.getStatesProcessThreadDataByRange; + mockgetProcessThreadDataByRange.mockResolvedValue([ + { + process: 'process', + processId: 1, + thread: 'thread', + state: 'state', + threadId: 1, + dur: 1000, + end_ts: 2000, + start_ts: 2000, + cpu: 1111, + }, + ]); + expect((tabPaneContextSwitch.data = dataArray)).toBeTruthy(); + }); + + it('TabPaneContextSwitchTest04', function () { + expect(tabPaneContextSwitch.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`); + }); + + it('TabPaneContextSwitchTest04', function () { + document.body.innerHTML = ``; + let tabPaneContextSwitch = document.querySelector('#Switch') as TabPaneContextSwitch; + expect(tabPaneContextSwitch.data).toBe(tabPaneContextSwitch.dataArray); + }); + + it('TabPaneContextSwitchTest05', function () { + document.body.innerHTML = ``; + let tabPaneContextSwitch = document.querySelector('#Switch') as TabPaneContextSwitch; + tabPaneContextSwitch.loadDataInCache = false; + expect(tabPaneContextSwitch.data).toBe(tabPaneContextSwitch.dataArray); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneCounterSample.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneCounterSample.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1cdfe55c22f5beec8cdaf5f6052c75163a6840c --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneCounterSample.test.ts @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneCounterSample } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneCounterSample.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneCounterSample Test', () => { + document.body.innerHTML = `
`; + let tab = document.querySelector('.ddd') as HTMLDivElement; + let tabPaneCounterSample = new TabPaneCounterSample(); + tabPaneCounterSample.tbl = jest.fn(() => tab); + tabPaneCounterSample.tbl.treeElement = jest.fn(() => tab); + tabPaneCounterSample.tbl.tableElement = jest.fn(() => tab); + SpSystemTrace.SPT_DATA = [ + { + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 1, + thread: '', + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 2, + thread: '', + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + + let dataArray = { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + cpuStateFilterIds: [1, 2, 3], + }; + + it('TabPaneCounterSampleTest01', function () { + let getTabPaneCounterSampleData = sqlit.getTabPaneCounterSampleData; + getTabPaneCounterSampleData.mockResolvedValue([ + { + value: 'process', + filterId: 1, + ts: 1000, + cpu: 'cpu', + }, + ]); + tabPaneCounterSample.tbl.recycleDataSource = jest.fn(() => dataArray); + expect((tabPaneCounterSample.data = dataArray)).toBeTruthy(); + }); + + it('TabPaneCounterSampleTest02', function () { + expect(tabPaneCounterSample.initElements()).toBeUndefined(); + }); + + it('TabPaneCounterSampleTest03', function () { + expect(tabPaneCounterSample.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + +
+ " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cfb182383f2746cb8f35ab25912dba79cfa45cfe --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.test.ts @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneCpuByProcess } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneCpuByProcess.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); +describe('TabPaneCpuByProcess Test', () => { + let tabPaneCpuByProcess = new TabPaneCpuByProcess(); + + it('TabPaneCpuByProcessTest01', function () { + expect( + tabPaneCpuByProcess.sortByColumn({ + key: 'number', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuByProcessTest05', function () { + expect( + tabPaneCpuByProcess.sortByColumn({ + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuByProcessTest04', function () { + expect( + tabPaneCpuByProcess.sortByColumn({ + key: 'pid' || 'wallDuration' || 'avgDuration' || 'occurrences', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuByProcessTest04', function () { + expect(tabPaneCpuByProcess.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuByThread.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuByThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..49348549fd64f63e157048036288bfcbd2f32ef0 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuByThread.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneCpuByThread } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneCpuByThread.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPaneCpuByThread Test', () => { + let tabPaneCpuByThread = new TabPaneCpuByThread(); + + it('TabPaneCpuByThreadTest01', function () { + expect( + tabPaneCpuByThread.sortByColumn({ + key: 'number', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuByThreadTest02', function () { + expect( + tabPaneCpuByThread.sortByColumn({ + key: 'pid' || 'wallDuration' || 'avgDuration' || 'occurrences', + }) + ).toBeUndefined(); + }); + + it('TabPaneCpuByThreadTest03', function () { + let mockgetTabCpuByThread = sqlit.getTabCpuByThread; + mockgetTabCpuByThread.mockResolvedValue([ + { process: 'test', wallDuration: 10, occurrences: 10, thread: '' }, + { process: 'test2', wallDuration: 11, occurrences: 11, thread: '' }, + ]); + let a = { rightNs: 1, cpus: [11, 12, 13] }; + expect((tabPaneCpuByThread.data = a)).toBeTruthy(); + }); + + it('TabPaneCpuByThreadTest04', function () { + let mockgetTabCpuByThread = sqlit.getTabCpuByThread; + mockgetTabCpuByThread.mockResolvedValue([]); + let a = { rightNs: 1, cpus: [11, 12, 13] }; + expect((tabPaneCpuByThread.data = a)).toBeTruthy(); + }); + + it('TabPaneCpuByThreadTest05', function () { + expect(tabPaneCpuByThread.initHtml()).toMatchInlineSnapshot(` +" + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuUsage.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuUsage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1281701b5a8a310131b4a4bc0aec8fdce77216a7 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneCpuUsage.test.ts @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneCpuUsage } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneCpuUsage.js'; +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneCpuUsage Test', () => { + let tabPaneCpuUsage = new TabPaneCpuUsage(); + + let mockGetTabCpuUsage = sqlit.getTabCpuUsage; + let mockGetTabCpuFreq = sqlit.getTabCpuFreq; + + mockGetTabCpuUsage.mockResolvedValue([]); + mockGetTabCpuFreq.mockResolvedValue([]); + + let selectionData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }; + + it('TabPaneCpuUsageTest01', function () { + expect( + tabPaneCpuUsage.sortTable( + [ + [1, 2, 3, 9, 6, 4], + [5, 2, 1, 4, 9, 6], + ], + 0, + true + ) + ).toBeUndefined(); + }); + + it('TabPaneCpuUsageTest08', function () { + expect( + tabPaneCpuUsage.sortTable( + [ + [1, 2, 3, 9, 6, 4], + [5, 2, 1, 4, 9, 6], + ], + 0, + false + ) + ).toBeUndefined(); + }); + + it('TabPaneCpuUsageTest09', function () { + expect( + tabPaneCpuUsage.sortTable( + [ + [1, 2, 3, 9, 6, 4], + [5, 2, 1, 4, 9, 6], + ], + 2, + true + ) + ).toBeUndefined(); + }); + + it('TabPaneCpuUsageTest10', function () { + expect( + tabPaneCpuUsage.sortTable( + [ + [1, 2, 3, 9, 6, 4], + [5, 2, 1, 4, 9, 6], + ], + 2, + false + ) + ).toBeUndefined(); + }); + + it('TabPaneCpuUsageTest02', function () { + expect( + tabPaneCpuUsage.sortTable( + [ + [1, 2, 3, 9, 6, 4], + [5, 2, 1, 4, 9, 6], + ], + 1, + true + ) + ).toBeUndefined(); + }); + + it('TabPaneCpuUsageTest03', function () { + expect( + tabPaneCpuUsage.sortTable( + [ + [1, 2, 3, 9, 6, 4], + [5, 2, 1, 4, 9, 6], + ], + 1, + false + ) + ).toBeUndefined(); + }); + it('TabPaneCpuUsageTest04', function () { + let result = tabPaneCpuUsage.sortFreq([ + { + cpu: 0, + value: 0, + startNs: 0, + dur: 0, + }, + { + cpu: 1, + value: 2, + startNs: 2, + dur: 4, + }, + ]); + expect(result[0][0]).toBe(2); + }); + it('TabPaneCpuUsageTest05', function () { + expect( + tabPaneCpuUsage.getFreqTop3( + { + cpu: 0, + usage: 0, + usageStr: 'usage', + top1: 1, + top2: 2, + top3: 3, + top1Percent: 11, + top1PercentStr: 'Str1', + top2Percent: 22, + top2PercentStr: 'Str2', + top3Percent: 33, + top3PercentStr: 'Str3', + }, + undefined, + undefined, + undefined, + 1 + ) + ).toBeUndefined(); + }); + it('TabPaneCpuUsageTest06', function () { + let result = tabPaneCpuUsage.groupByCpuToMap([ + { + cpu: 0, + value: 0, + startNs: 0, + dur: 0, + }, + { + cpu: 1, + value: 2, + startNs: 2, + dur: 4, + }, + ]); + expect(result.get(0).length).toBe(1); + }); + + it('TabPaneCurrentSelectionTest07', function () { + expect(tabPaneCpuUsage.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + " +`); + }); + + it('TabPaneCpuUsageTest11', function () { + document.body.innerHTML = `
`; + let tabPaneCpuUsage = document.querySelector('#CpuUsage') as TabPaneCpuUsage; + expect(tabPaneCpuUsage.sortFreq).toBe(undefined); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneFrequencySample.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneFrequencySample.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9bf79e9c40cad5779dab43988358596f44e6f142 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneFrequencySample.test.ts @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFrequencySample } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneFrequencySample.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneFrequencySample Test', () => { + document.body.innerHTML = `
`; + let tab = document.querySelector('.ddd') as HTMLDivElement; + let tabPaneFreSample = new TabPaneFrequencySample(); + tabPaneFreSample.tbl = jest.fn(() => tab); + tabPaneFreSample.tbl.treeElement = jest.fn(() => tab); + tabPaneFreSample.tbl.tableElement = jest.fn(() => tab); + SpSystemTrace.SPT_DATA = [ + { + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 1, + thread: '', + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 2, + thread: '', + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + + let dataArray = { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + cpuFreqFilterIds: [1, 2, 3], + }; + + it('TabPaneCounterSampleTest01', function () { + let getTabPaneFrequencySampleData = sqlit.getTabPaneFrequencySampleData; + getTabPaneFrequencySampleData.mockResolvedValue([ + { + value: 'process', + filterId: 1, + ts: 1000, + cpu: 'cpu', + }, + ]); + tabPaneFreSample.tbl.recycleDataSource = jest.fn(() => dataArray); + expect((tabPaneFreSample.data = dataArray)).toBeTruthy(); + }); + + it('TabPaneCounterSampleTest02', function () { + expect(tabPaneFreSample.initElements()).toBeUndefined(); + }); + + it('TabPaneCounterSampleTest03', function () { + expect(tabPaneFreSample.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + +
+ " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPanePTS.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPanePTS.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e7009191ebc580b9c775280a82256594e926f1f --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPanePTS.test.ts @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPanePTS } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPanePTS.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('TabPanePTS Test', () => { + document.body.innerHTML = ``; + let tab = document.querySelector('#tb-states') as LitTable; + + document.body.innerHTML = `
`; + let tabPane = document.querySelector('.pts') as TabPanePTS; + let tabPanePTS = new TabPanePTS(); + + tabPanePTS.tbl = jest.fn(() => tab); + + SpSystemTrace.SPT_DATA = [ + { + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 1, + thread: '', + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 2, + thread: '', + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + + let dataArray = [ + { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + }, + ]; + + it('TabPanePTSTest01', function () { + expect(tabPane.getDataBySPT(0, 0, [])).toBeUndefined(); + }); + + it('TabPanePTSTest02', function () { + let source = [ + { + process: '', + processId: 10, + thread: '', + threadId: 10, + state: '', + dur: 1000, + start_ts: 100_0000, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + expect(tabPane.getDataBySPT(10, 100_000, source)).toBeUndefined(); + }); + + it('TabPaneSPTTest03', function () { + let mockgetProcessThreadDataByRange = sqlit.getStatesProcessThreadDataByRange; + mockgetProcessThreadDataByRange.mockResolvedValue([ + { + process: 'process', + processId: 1, + thread: 'thread', + state: 'state', + threadId: 1, + dur: 1000, + end_ts: 2000, + start_ts: 2000, + cpu: 1111, + }, + ]); + tabPanePTS.tbl.recycleDataSource = jest.fn(() => dataArray); + expect((tabPanePTS.data = dataArray)).toBeTruthy(); + }); + + it('TabPanePTSTest04', function () { + expect(tabPanePTS.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneSPT.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneSPT.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..86066de145e10502f00601bdd98fff3bf06e6556 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneSPT.test.ts @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSPT } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneSPT.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneSPT Test', () => { + document.body.innerHTML = ``; + let tab = document.querySelector('#tb-states') as LitTable; + + document.body.innerHTML = `
`; + let tabPane = document.querySelector('.SPT') as TabPaneSPT; + let tabPaneSPT = new TabPaneSPT(); + tabPaneSPT.tbl = jest.fn(() => tab); + SpSystemTrace.SPT_DATA = [ + { + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 1, + thread: '', + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 2, + thread: '', + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + + let dataList = [ + { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + }, + ]; + + let dataArray = [ + { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + }, + ]; + + it('TabPaneSPTTest01', function () { + expect(tabPane.getDataBySPT(0, 0, [])).toBeUndefined(); + }); + + it('TabPaneSPTTest02', function () { + let source = [ + { + process: '', + processId: 10, + thread: '', + threadId: 10, + state: '', + dur: 1000, + start_ts: 100_0000, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + expect(tabPane.getDataBySPT(10, 100_000, source)).toBeUndefined(); + }); + + it('TabPaneSPTTest03', function () { + let mockgetProcessThreadDataByRange = sqlit.getStatesProcessThreadDataByRange; + mockgetProcessThreadDataByRange.mockResolvedValue([ + { + process: 'process', + processId: 1, + thread: 'thread', + state: 'state', + threadId: 1, + dur: 1000, + end_ts: 2000, + start_ts: 2000, + cpu: 1111, + }, + ]); + tabPaneSPT.tbl.recycleDataSource = jest.fn(() => dataList); + + expect((tabPaneSPT.data = dataList)).toBeTruthy(); + }); + + it('TabPaneSPTTest04', function () { + expect(tabPaneSPT.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.test.ts b/ide/test/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b7be826d9216688f1c3847634003b2db3a62d9b --- /dev/null +++ b/ide/test/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.test.ts @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneThreadSwitch } from '../../../../../../dist/trace/component/trace/sheet/cpu/TabPaneThreadSwitch.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneContextSwitch Test', () => { + document.body.innerHTML = `
`; + let tab = document.querySelector('.ddd') as HTMLDivElement; + let tabPaneThreadSwitch = new TabPaneThreadSwitch(); + tabPaneThreadSwitch.tbl = jest.fn(() => tab); + tabPaneThreadSwitch.tbl.treeElement = jest.fn(() => tab); + tabPaneThreadSwitch.tbl.tableElement = jest.fn(() => tab); + SpSystemTrace.SPT_DATA = [ + { + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 1, + thread: '', + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + { + process: '', + processId: 2, + thread: '', + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: '-', + note: '-', + }, + ]; + + let dataArray = { + id: '', + pid: '', + title: '', + children: [], + process: '', + processId: 0, + thread: '', + threadId: 0, + state: '', + wallDuration: 0, + avgDuration: '', + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: '', + }; + + it('TabPaneThreadSwitchTest03', function () { + expect(tabPaneThreadSwitch.getDataBySPT(0, 0, [])).toBeUndefined(); + }); + + it('TabPaneThreadSwitchTest04', function () { + let mockgetProcessThreadDataByRange = sqlit.getStatesProcessThreadDataByRange; + mockgetProcessThreadDataByRange.mockResolvedValue([ + { + process: 'process', + processId: 1, + thread: 'thread', + state: 'state', + threadId: 1, + dur: 1000, + end_ts: 2000, + start_ts: 2000, + cpu: 1111, + }, + ]); + tabPaneThreadSwitch.tbl.recycleDataSource = jest.fn(() => dataArray); + expect((tabPaneThreadSwitch.data = dataArray)).toBeTruthy(); + }); + + it('TabPaneThreadSwitchTest05', function () { + expect(tabPaneThreadSwitch.initElements()).toBeUndefined(); + }); + + it('TabPaneThreadSwitchTest06', function () { + expect(tabPaneThreadSwitch.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.test.ts b/ide/test/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..09660913a874b8084fbecbf7b92978ebe5c72dd5 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.test.ts @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneEnergyAnomaly } from '../../../../../../dist/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.js'; +import '../../../../../../dist/trace/component/trace/sheet/energy/TabPaneEnergyAnomaly.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPanePowerBattery Test', () => { + it('TabPaneEnergyAnomalyTest01', function () { + let tabPaneEnergyAnomaly = new TabPaneEnergyAnomaly(); + let MockAnomalyDetailedData = sqlit.queryAnomalyDetailedData; + let battery = [ + { + ts: 11611696002, + eventName: 'ANOMALY_SCREEN_OFF_ENERGY', + appKey: 'BATTERY_DRAIN', + Value: '10', + }, + { + ts: 11611696002, + eventName: 'ANOMALY_SCREEN_OFF_ENERGY', + appKey: 'BATTERY_GAS_GUAGE', + Value: '980', + }, + { + ts: 15612568649, + eventName: 'ANOMALY_RUNNINGLOCK', + appKey: 'APPNAME', + Value: 'com.example.powerhap', + }, + { + ts: 15612568649, + eventName: 'ANOMALY_RUNNINGLOCK', + appKey: 'COUNT', + Value: '1', + }, + { + ts: 17611804002, + eventName: 'ANORMALY_APP_ENERGY', + appKey: 'APPNAME', + Value: + '*dpm_others*,*dpm_rom*,/system/bin/hilogd,' + + '/system/bin/render_service,' + + '/system/bin/wifi_hal_service,' + + 'bluetooth_servi,com.example.baseanimation,' + + 'com.example.ohos_location_js,' + + 'com.ohos.launcher,com.ohos.settings,' + + 'hidumper_servic,hwc_host,' + + 'kernel_kworker,softbus_server', + }, + { + ts: 17611804002, + eventName: 'ANORMALY_APP_ENERGY', + appKey: 'BGENERGY', + Value: '11726,79745,6209,249329,1680,8694,3061,457,402,17064,4087,16403,32965,2895', + }, + ]; + MockAnomalyDetailedData.mockResolvedValue(battery); + let tabPaneAnomalyDetailedData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 1000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + + tabPaneEnergyAnomaly.data = tabPaneAnomalyDetailedData; + }); + + it('TabPaneEnergyAnomalyTest02', function () { + let tabPaneEnergyAnomaly = new TabPaneEnergyAnomaly(); + expect(tabPaneEnergyAnomaly.initHtml()).toMatchInlineSnapshot(` +" + +
+
+

+
+
+
+ + + + + + +
+
+
+ " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/energy/TabPanePowerBattery.test.ts b/ide/test/trace/component/trace/sheet/energy/TabPanePowerBattery.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..10d475f15ca499c201ecbbfba88ac4b587c820f9 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/energy/TabPanePowerBattery.test.ts @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPanePowerBattery } from '../../../../../../dist/trace/component/trace/sheet/energy/TabPanePowerBattery.js'; +import '../../../../../../dist/trace/component/trace/sheet/energy/TabPanePowerBattery.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPanePowerBattery Test', () => { + it('TabPanePowerBatteryTest01', function () { + document.body.innerHTML = ``; + let litTable = document.querySelector('#tb-power-battery-energy') as LitTable; + let tabPanePowerBattery = new TabPanePowerBattery(); + tabPanePowerBattery.tbl = jest.fn(() => litTable); + let MockPowerBatteryData = sqlit.getTabPowerBatteryData; + let battery = [ + { + ts: 1000, + eventName: 'POWER_IDE_BATTERY', + appKey: 'appname', + eventValue: 'POWER_IDE,POWER_IDE,POWER_IDE,POWER_IDE', + }, + { + ts: 1000, + eventName: 'POWER_IDE_BATTERY', + appKey: 'appname', + eventValue: 'POWER_IDE,POWER_IDE,POWER_IDE,POWER_IDE', + }, + ]; + MockPowerBatteryData.mockResolvedValue(battery); + let tabPanePowerBatteryData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 1000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + tabPanePowerBattery.tbl.recycleDataSource = jest.fn(() => tabPanePowerBatteryData); + tabPanePowerBattery.data = tabPanePowerBatteryData; + }); + + it('TabPanePowerBatteryTest02', function () { + let tabPanePowerBattery = new TabPanePowerBattery(); + expect(tabPanePowerBattery.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ + + + +
+
+
+ " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/energy/TabPanePowerDetails.test.ts b/ide/test/trace/component/trace/sheet/energy/TabPanePowerDetails.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5d1e189525fe6cd4377ebf0b730af6b8692fd34 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/energy/TabPanePowerDetails.test.ts @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPanePowerDetails } from '../../../../../../dist/trace/component/trace/sheet/energy/TabPanePowerDetails.js'; +import '../../../../../../dist/trace/component/trace/sheet/energy/TabPanePowerDetails.js'; + +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPanePowerDetails Test', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#tb-power-details-energy') as LitTable; + it('TabPanePowerDetailsTest01', function () { + let tabPanePowerDetails = new TabPanePowerDetails(); + tabPanePowerDetails.tbl = jest.fn(() => litTable); + let MockPowerDetailsData = sqlit.getTabPowerDetailsData; + let detail = [ + { + ts: 5999127353, + eventName: 'POWER_IDE_AUDIO', + appKey: 'APPNAME', + eventValue: 'com.example.himusicdemo,com.example.himusicdemo_js,com.example.himusicdemo_app', + }, + { + ts: 5999127353, + eventName: 'POWER_IDE_AUDIO', + appKey: 'BACKGROUND_DURATION', + eventValue: '524,854,612', + }, + { + ts: 5999127353, + eventName: 'POWER_IDE_BLUETOOTH', + appKey: 'APPNAME', + eventValue: 'com.ohos.settings,bt_switch,bt_switch_js,bt_switch_app', + }, + { + ts: 5999127353, + eventName: 'POWER_IDE_BLUETOOTH', + appKey: 'BACKGROUND_DURATION', + eventValue: '325,124,51,52', + }, + { + ts: 5999127353, + eventName: 'POWER_IDE_CAMERA', + appKey: 'APPNAME', + eventValue: 'com.ohos.camera,com.ohos.camera_app,com.ohos.camera_js,com.ohos.camera_ts', + }, + { + ts: 5999127353, + eventName: 'POWER_IDE_CAMERA', + appKey: 'BACKGROUND_DURATION', + eventValue: '356,325,854,365', + }, + ]; + MockPowerDetailsData.mockResolvedValue(detail); + let list = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 1000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + tabPanePowerDetails.tbl.recycleDataSource = jest.fn(() => list); + tabPanePowerDetails.data = list; + expect(tabPanePowerDetails.data).toBeUndefined(); + }); + + it('TabPanePowerDetailsTest02', function () { + let tabPanePowerDetails = new TabPanePowerDetails(); + expect(tabPanePowerDetails.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/energy/TabPaneSystemDetails.test.ts b/ide/test/trace/component/trace/sheet/energy/TabPaneSystemDetails.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..93ba17ffbe97ff892d4fa97c5d419e72ce0973c6 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/energy/TabPaneSystemDetails.test.ts @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSystemDetails } from '../../../../../../dist/trace/component/trace/sheet/energy/TabPaneSystemDetails.js'; +import '../../../../../../dist/trace/component/trace/sheet/energy/TabPaneSystemDetails.js'; + +import { querySysLocationDetailsData, querySysLockDetailsData } from '../../../../../../src/trace/database/SqlLite.js'; +// @ts-ignore +import { SpHiSysEventChart } from '../../../../../../dist/trace/component/chart/SpHiSysEventChart.js'; +import '../../../../../../dist/trace/component/chart/SpHiSysEventChart.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPanePowerBattery Test', () => { + it('TabPaneSystemDetailsTest01', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + tabPaneSystemDetails.tbl = jest.fn(() => true); + tabPaneSystemDetails.detailsTbl = jest.fn(() => true); + tabPaneSystemDetails.tbl!.recycleDataSource = jest.fn(() => []); + tabPaneSystemDetails.detailsTbl!.recycleDataSource = jest.fn(() => []); + let MockquerySystemWorkData = sqlit.querySystemWorkData; + SpHiSysEventChart.app_name = '111'; + + let querySystemWorkData = [ + { + ts: 0, + eventName: 'WORK_ADD', + appKey: 'workid', + appValue: '1', + }, + { + ts: 1005938319, + eventName: 'WORK_ADD', + appKey: 'name', + appValue: 'nnnn', + }, + { + ts: 3005938319, + eventName: 'WORK_START', + appKey: 'workid', + appValue: '1', + }, + { + ts: 3005938319, + eventName: 'WORK_START', + appKey: 'name', + appValue: 'nnnn', + }, + { + ts: 5005938319, + eventName: 'WORK_STOP', + appKey: 'workid', + appValue: '1', + }, + { + ts: 5005938319, + eventName: 'WORK_STOP', + appKey: 'name', + appValue: 'nnnn', + }, + ]; + MockquerySystemWorkData.mockResolvedValue(querySystemWorkData); + + let MockLockData = sqlit.querySysLockDetailsData; + let lockDetails = [ + { + ts: 1005938319, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'tag', + appValue: 'DUBAI_TAG_RUNNINGLOCK_ADD', + }, + { + ts: 1005938319, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'message', + appValue: 'token=123', + }, + { + ts: 3005933657, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'tag', + appValue: 'DUBAI_TAG_RUNNINGLOCK_REMOVE', + }, + { + ts: 3005933657, + eventName: 'POWER_RUNNINGLOCK', + appKey: 'message', + appValue: 'token=123', + }, + ]; + MockLockData.mockResolvedValue(lockDetails); + + let MockLocationData = sqlit.querySysLocationDetailsData; + let locationDetails = [ + { + ts: 1005938319, + eventName: 'GNSS_STATE', + appKey: 'state', + appValue: 'start', + }, + { + ts: 1005938319, + eventName: 'GNSS_STATE', + appKey: 'pid', + appValue: '11', + }, + { + ts: 3005933657, + eventName: 'GNSS_STATE', + appKey: 'state', + appValue: 'stop', + }, + { + ts: 3005933657, + eventName: 'GNSS_STATE', + appKey: 'pid', + appValue: '11', + }, + ]; + MockLocationData.mockResolvedValue(locationDetails); + + let tabPaneSystemDetailsData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 300000000000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + + tabPaneSystemDetails.data = tabPaneSystemDetailsData; + expect(tabPaneSystemDetails.data).toBeUndefined(); + }); + + it('TabPaneSystemDetailsTest02', function () { + let tabPaneSystem = new TabPaneSystemDetails(); + tabPaneSystem.tbl = jest.fn(() => true); + tabPaneSystem.detailsTbl = jest.fn(() => true); + tabPaneSystem.tbl!.recycleDataSource = jest.fn(() => []); + tabPaneSystem.detailsTbl!.recycleDataSource = jest.fn(() => []); + let MockSystemWorkData = sqlit.querySystemWorkData; + MockSystemWorkData.mockResolvedValue([]); + let MockSystemLockData = sqlit.querySysLockDetailsData; + MockSystemLockData.mockResolvedValue([]); + let MockSystemLocationData = sqlit.querySysLocationDetailsData; + MockSystemLocationData.mockResolvedValue([]); + let tabPaneSystemDetailsData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 1000, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + systemEnergy: [0, 1, 2], + powerEnergy: [0, 1, 2], + anomalyEnergy: [0, 1, 2], + }; + + tabPaneSystem.data = tabPaneSystemDetailsData; + expect(tabPaneSystem.data).toBeUndefined(); + }); + + it('TabPaneSystemDetailsTest03', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + tabPaneSystemDetails.tbl = jest.fn(() => true); + tabPaneSystemDetails.detailsTbl = jest.fn(() => true); + tabPaneSystemDetails.tbl!.recycleDataSource = jest.fn(() => []); + tabPaneSystemDetails.detailsTbl!.recycleDataSource = jest.fn(() => []); + let data = { + ts: 0, + eventName: 'Event Name', + type: 'type', + pid: 0, + uid: 0, + state: 0, + workId: 'workId', + name: 'name', + interval: 0, + level: 0, + tag: 'tag:', + message: 'message', + log_level: 'log_level', + }; + + expect(tabPaneSystemDetails.convertData(data)).toBeUndefined(); + }); + + it('TabPaneSystemDetailsTest04', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + tabPaneSystemDetails.tbl = jest.fn(() => true); + tabPaneSystemDetails.detailsTbl = jest.fn(() => true); + tabPaneSystemDetails.tbl!.recycleDataSource = jest.fn(() => []); + tabPaneSystemDetails.detailsTbl!.recycleDataSource = jest.fn(() => []); + let data = { + ts: 0, + eventName: 'GNSS_STATE', + type: 'type', + pid: 0, + uid: 0, + state: 0, + workId: 'workId', + name: 'name', + interval: 0, + level: 0, + tag: 'tag:', + message: 'message', + log_level: 'log_level', + }; + + expect(tabPaneSystemDetails.convertData(data)).toBeUndefined(); + }); + + it('TabPaneSystemDetailsTest05', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + tabPaneSystemDetails.tbl = jest.fn(() => true); + tabPaneSystemDetails.detailsTbl = jest.fn(() => true); + tabPaneSystemDetails.tbl!.recycleDataSource = jest.fn(() => []); + tabPaneSystemDetails.detailsTbl!.recycleDataSource = jest.fn(() => []); + let data = { + ts: 0, + eventName: 'POWER_RUNNINGLOCK', + type: 'type', + pid: 0, + uid: 0, + state: 0, + workId: 'workId', + name: 'name', + interval: 0, + level: 0, + tag: 'tag:', + message: 'message', + log_level: 'log_level', + }; + expect(tabPaneSystemDetails.convertData(data)).toBeUndefined(); + }); + + it('TabPaneSystemDetailsTest06', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + tabPaneSystemDetails.tbl = jest.fn(() => true); + tabPaneSystemDetails.detailsTbl = jest.fn(() => true); + tabPaneSystemDetails.tbl!.recycleDataSource = jest.fn(() => []); + tabPaneSystemDetails.detailsTbl!.recycleDataSource = jest.fn(() => []); + let data = { + ts: 0, + eventName: 'POWER', + type: 'type', + pid: 0, + uid: 0, + state: 0, + workId: 'workId', + name: 'name', + interval: 0, + level: 0, + tag: 'tag:', + message: 'message', + log_level: 'log_level', + }; + + expect(tabPaneSystemDetails.convertData(data)).toBeUndefined(); + }); + + it('TabPaneSystemDetailsTest08', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + let cc = [ + { + ts: -14000, + workId: 44, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_ADD', + }, + { + ts: 10000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_START', + }, + { + ts: 12000, + workId: 22, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_ADD', + }, + { + ts: 14000, + workId: 44, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_START', + }, + { + ts: 20000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_STOP', + }, + { + ts: 22000, + workId: 22, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_START', + }, + { + ts: 30000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_START', + }, + { + ts: 32000, + workId: 22, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_STOP', + }, + { + ts: 40000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_STOP', + }, + { + ts: 42000, + workId: 22, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_START', + }, + { + ts: 50000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_START', + }, + { + ts: 52000, + workId: 22, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_STOP', + }, + { + ts: 60000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_STOP', + }, + { + ts: 62000, + workId: 22, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_REMOVE', + }, + { + ts: 64000, + workId: 44, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_STOP', + }, + { + ts: 70000, + workId: 11, + name: SpHiSysEventChart.app_name, + eventName: 'WORK_REMOVE', + }, + ]; + tabPaneSystemDetails.getConvertData = jest.fn(() => cc); + let systemWorkData = tabPaneSystemDetails.getSystemWorkData(); + + expect(systemWorkData).toStrictEqual([]); + }); + + it('TabPaneSystemDetailsTest07', function () { + let tabPaneSystemDetails = new TabPaneSystemDetails(); + expect(tabPaneSystemDetails.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ +
+ + + + + + +
+ + + + + + + +
+
+ +
+ " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneCallTree.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneCallTree.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5973b0717e35ae78bbc278f157367e29eee23a98 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneCallTree.test.ts @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneCallTree } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneCallTree.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneCallTree.js'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +import '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +import { FrameChart } from '../../../../../../dist/trace/component/chart/FrameChart.js'; +import '../../../../../../dist/trace/component/chart/FrameChart.js'; +import crypto from 'crypto'; + +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabPaneCallTree Test', () => { + let data = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + it('TabPaneCallTreeTest01', function () { + document.body.innerHTML = ``; + let calltree = document.querySelector('#calltree'); + let filter = new TabPaneFilter(); + calltree.filter = filter; + let frameChart = new FrameChart(); + calltree.frameChart = frameChart; + calltree.filter.getDataLibrary = jest.fn(() => true); + calltree.data = data; + expect(calltree.currentSelection).not.toBeUndefined(); + }); + + it('TabPaneCallTreeTest02', function () { + document.body.innerHTML = ``; + let calltree = document.querySelector('#calltree'); + let filter = new TabPaneFilter(); + calltree.filter = filter; + let frameChart = new FrameChart(); + calltree.frameChart = frameChart; + calltree.filter.getDataLibrary = jest.fn(() => true); + calltree.data = data; + let call = { + id: '1', + dur: 1, + children: [], + }; + expect(calltree.setRightTableData(call)).toBeUndefined(); + }); + + it('TabPaneCallTreeTest03', function () { + document.body.innerHTML = ``; + let calltree = document.querySelector('#calltree'); + let filter = new TabPaneFilter(); + calltree.filter = filter; + calltree.showButtomMenu(true); + expect(calltree.filter.getAttribute('tree')).toBe(''); + calltree.showButtomMenu(false); + }); + + it('TabPaneCallTreeTest04', function () { + document.body.innerHTML = ``; + let calltree = document.querySelector('#calltree'); + let resultData = [ + { + addr: '', + canCharge: false, + count: 67, + depth: 0, + drawCount: 0, + drawDur: 0, + drawSize: 0, + dur: 43334510310, + frame: { x: 0, y: 30, width: 594, height: 20 }, + id: '38', + ip: '', + isDraw: false, + isSearch: false, + isSelected: false, + isStore: 0, + lib: '', + libName: '', + parentId: '', + path: '', + pathId: 0, + percent: 0.3642222150324375, + pid: 0, + processName: '', + searchShow: true, + self: '0s', + selfDur: 0, + size: 0, + symbol: 'symbol', + symbolName: 'symbolName', + symbolsId: 0, + textMetricsWidth: 62.7783203125, + type: 0, + weight: '43.33s ', + weightPercent: '36.4%', + children: [], + }, + ]; + calltree.setLTableData(resultData); + expect(calltree.dataSource.length).toEqual(1); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemCalltree.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemCalltree.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b91c81a855fcb6d99b992b7774b972d3a58c5a8 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemCalltree.test.ts @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabpaneFilesystemCalltree } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabpaneFilesystemCalltree.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabpaneFilesystemCalltree.js'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +import { FrameChart } from '../../../../../../dist/trace/component/chart/FrameChart.js'; +import crypto from 'crypto'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabpaneFilesystemCalltree Test', () => { + document.body.innerHTML = ``; + let tabpaneFilesystemCalltree = document.querySelector('#tree'); + let val = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + + it('TabpaneFilesystemCalltreeTest02', function () { + tabpaneFilesystemCalltree!.showButtomMenu = jest.fn(() => ''); + tabpaneFilesystemCalltree.filter = jest.fn(() => ''); + tabpaneFilesystemCalltree.filter.setAttribute = jest.fn(() => ''); + expect(tabpaneFilesystemCalltree.showButtomMenu(true)).toBe(''); + }); + + it('TabpaneFilesystemCalltreeTest03', function () { + TabpaneFilesystemCalltree.getParentTree = jest.fn(() => true); + let call = { + id: '1', + children: [], + }; + let target = { + id: '1', + }; + expect(tabpaneFilesystemCalltree.getParentTree([call], { target }, [])).toBeFalsy(); + }); + + it('TabpaneFilesystemCalltreeTest04', function () { + TabpaneFilesystemCalltree.getParentTree = jest.fn(() => true); + let call = { + children: [], + }; + expect(tabpaneFilesystemCalltree.getParentTree([call], '', [])).not.toBeUndefined(); + }); + + it('TabpaneFilesystemCalltreeTest05', function () { + TabpaneFilesystemCalltree.getChildTree = jest.fn(() => true); + let call = { + id: '1', + children: [], + }; + let id = '1'; + expect(tabpaneFilesystemCalltree.getChildTree([call], { id }, [])).not.toBeUndefined(); + }); + + it('TabpaneFilesystemCalltreeTest06', function () { + TabpaneFilesystemCalltree.getChildTree = jest.fn(() => true); + let call = { + children: [], + }; + expect(tabpaneFilesystemCalltree.getChildTree([call], '', [])).not.toBeUndefined(); + }); + + it('TabpaneFilesystemCalltreeTest07', function () { + let filter = new TabPaneFilter(); + tabpaneFilesystemCalltree.filter = filter; + tabpaneFilesystemCalltree.data = val; + expect(tabpaneFilesystemCalltree.currentSelection).not.toBeUndefined(); + }); + + it('TabpaneFilesystemCalltreeTest08', function () { + let resultData = [ + { + addr: '', + canCharge: false, + count: 67, + depth: 0, + drawCount: 0, + drawDur: 0, + drawSize: 0, + dur: 43334510310, + frame: { x: 0, y: 30, width: 594, height: 20 }, + id: '38', + ip: '', + isDraw: false, + isSearch: false, + isSelected: false, + isStore: 0, + lib: '', + libName: '', + parentId: '', + path: '', + pathId: 0, + percent: 0.3642222150324375, + pid: 0, + processName: '', + searchShow: true, + self: '0s', + selfDur: 0, + size: 0, + symbol: 'symbol', + symbolName: 'symbolName', + symbolsId: 0, + textMetricsWidth: 62.7783203125, + type: 0, + weight: '43.33s ', + weightPercent: '36.4%', + children: [], + }, + ]; + tabpaneFilesystemCalltree.setLTableData(resultData); + expect(tabpaneFilesystemCalltree.dataSource.length).toEqual(1); + }); + + it('TabpaneFilesystemCalltreeTest09', function () { + let switchData = { + firstSelect: '', + icon: 'tree', + inputValue: 'kk', + mark: false, + secondSelect: '', + thirdSelect: '', + type: 'inputValue', + }; + tabpaneFilesystemCalltree.tbl.reMeauseHeight = jest.fn(() => true); + tabpaneFilesystemCalltree.switchFlameChart(switchData); + expect(tabpaneFilesystemCalltree.isChartShow).toBeFalsy(); + }); + + it('TabpaneFilesystemCalltreeTest10', function () { + let switchData = { + firstSelect: '', + icon: 'block', + inputValue: 'kk', + mark: false, + secondSelect: '', + thirdSelect: '', + type: 'inputValue', + }; + tabpaneFilesystemCalltree.tbl.reMeauseHeight = jest.fn(() => true); + let frameChart = new FrameChart(); + tabpaneFilesystemCalltree.frameChart = frameChart; + tabpaneFilesystemCalltree.switchFlameChart(switchData); + expect(tabpaneFilesystemCalltree.isChartShow).toBeTruthy(); + }); + + it('TabpaneFilesystemCalltreeTest11', function () { + let call = { + id: '1', + dur: 1, + children: [], + }; + expect(tabpaneFilesystemCalltree.setRightTableData(call)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2467415474c8724b0db11b6f24767608f050db71 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.test.ts @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFileSystemDescHistory } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFileSystemDescHistory.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabPaneFileSystemDescHistory Test', () => { + document.body.innerHTML = ``; + let tabPane = document.querySelector('#history'); + + let param = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + let filterSource = [ + { + backtrace: ['0x7faa10f228', '(10 other frames)'], + callchainId: 13, + depth: 10, + dur: 240916, + durStr: '240.92μs ', + fd: 14, + fileId: 546, + isHover: false, + path: '/data/local/tmp/test', + process: 'power_host[911]', + startTs: 285141821, + startTsStr: '285ms 141μs 821ns ', + symbol: '0x7faa10f228', + type: 0, + typeStr: 'OPEN', + }, + { + backtrace: ['0x7faa10f228', '(10 other frames)'], + callchainId: 15, + depth: 10, + dur: 7583, + durStr: '7.58μs ', + fd: 14, + fileId: null, + isHover: false, + path: '-', + process: 'test[911]', + startTs: 285449632, + startTsStr: '285ms 449μs 821ns ', + symbol: '0x7faa10f228', + type: 1, + typeStr: 'CLOSE', + }, + ]; + + it('TabPaneFileSystemDescHistoryTest01', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + expect(tabPane.currentSelection).not.toBeUndefined(); + }); + + it('TabPaneFileSystemDescHistoryTest02', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.setProcessFilter(); + expect(tabPane.processList).toEqual(['All Process']); + }); + + it('TabPaneFileSystemDescHistoryTest03', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + expect(tabPane.filterData()).toBeUndefined(); + }); + + it('TabPaneFileSystemDescHistoryTest04', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.filterSource = filterSource; + expect(tabPane.sortTable('startTsStr', 1)).toBeUndefined(); + }); + + it('TabPaneFileSystemDescHistoryTest05', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.filterSource = filterSource; + expect(tabPane.sortTable('durStr', 1)).toBeUndefined(); + }); + + it('TabPaneFileSystemDescHistoryTest06', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.filterSource = filterSource; + expect(tabPane.sortTable('typeStr', 1)).toBeUndefined(); + }); + + it('TabPaneFileSystemDescHistoryTest07', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.filterSource = filterSource; + expect(tabPane.sortTable('fd', 1)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..85e92893ce0849f14f0930e063aa2bc12c9dd495 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.test.ts @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFileSystemDescTimeSlice } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFileSystemDescTimeSlice.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabPaneFileSystemDescTimeSlice Test', () => { + document.body.innerHTML = ``; + let tabPane = document.querySelector('#desc-time-slice'); + + let param = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + + let filterSource = [ + { + backtrace: ['0x7faa10f228', '(10 other frames)'], + callchainId: 13, + depth: 10, + dur: 240916, + durStr: '240.92μs ', + fd: 14, + fileId: 546, + isHover: false, + path: '/data/local/tmp/test', + process: 'power_host[911]', + startTs: 285141821, + startTsStr: '285ms 141μs 821ns ', + symbol: '0x7faa10f228', + type: 0, + typeStr: 'OPEN', + }, + { + backtrace: ['0x7faa10f228', '(10 other frames)'], + callchainId: 15, + depth: 10, + dur: 7583, + durStr: '7.58μs ', + fd: 14, + fileId: null, + isHover: false, + path: '-', + process: 'test[911]', + startTs: 285449632, + startTsStr: '285ms 449μs 821ns ', + symbol: '0x7faa10f228', + type: 1, + typeStr: 'CLOSE', + }, + ]; + + it('descTimeSliceTest01', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + expect(tabPane.currentSelection).not.toBeUndefined(); + }); + + it('descTimeSliceTest02', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.source = filterSource; + expect(tabPane.sortTable('startTsStr', 1)).toBeUndefined(); + }); + + it('descTimeSliceTest03', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.source = filterSource; + expect(tabPane.sortTable('durStr', 1)).toBeUndefined(); + }); + + it('descTimeSliceTest04', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.source = filterSource; + expect(tabPane.sortTable('typeStr', 1)).toBeUndefined(); + }); + + it('descTimeSliceTest05', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + tabPane.source = filterSource; + expect(tabPane.sortTable('fd', 1)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d344314fceb7cfc70104641f1b0be8af2f3045ec --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.test.ts @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2022 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 '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.js'; + +// @ts-ignore +import { TabPaneFileSystemEvents } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFileSystemEvents.js'; +// @ts-ignore +import {LitTable} from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import {TabPaneFilter} from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); +describe('TabPaneFileSystemEvents Test', () => { + document.body.innerHTML = ``; + let tabPaneFileSystemEvents = document.querySelector('#files') as TabPaneFileSystemEvents; + let filterSource = [ + { + backtrace: ['0x7faa10f228', '(10 other frames)'], + callchainId: 13, + depth: 10, + dur: 240916, + durStr: '240.92μs ', + fd: 14, + fileId: 546, + isHover: false, + path: '/data/local/tmp/test', + process: 'power_host[911]', + startTs: 285141821, + startTsStr: '285ms 141μs 821ns ', + symbol: '0x7faa10f228', + type: 0, + typeStr: 'OPEN', + }, + { + backtrace: ['0x7faa10f228', '(10 other frames)'], + callchainId: 15, + depth: 10, + dur: 7583, + durStr: '7.58μs ', + fd: 14, + fileId: null, + isHover: false, + path: '-', + process: 'test[911]', + startTs: 285449632, + startTsStr: '285ms 449μs 821ns ', + symbol: '0x7faa10f228', + type: 1, + typeStr: 'CLOSE', + }, + ]; + + let param = { + anomalyEnergy: [], + clockMapData: {size: 0}, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: {size: 0}, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + fileSystemFsData:{title:'All'} + }; + + it('TabPaneFileStatisticsTest01', function () { + tabPaneFileSystemEvents.filterSource = filterSource; + expect(tabPaneFileSystemEvents.sortTable('', 0)).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest02', function () { + tabPaneFileSystemEvents.filterSource = filterSource; + expect(tabPaneFileSystemEvents.sortTable('startTsStr', 1)).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest03', function () { + tabPaneFileSystemEvents.filterSource = filterSource; + expect(tabPaneFileSystemEvents.sortTable('durStr', 1)).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest04', function () { + tabPaneFileSystemEvents.filterSource = filterSource; + expect(tabPaneFileSystemEvents.sortTable('process', 2)).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest05', function () { + tabPaneFileSystemEvents.filterSource = filterSource; + expect(tabPaneFileSystemEvents.sortTable('thread', 2)).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest06', function () { + tabPaneFileSystemEvents.filterSource = filterSource; + expect(tabPaneFileSystemEvents.sortTable('typeStr', 2)).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest07', function () { + let litTable = new LitTable(); + tabPaneFileSystemEvents.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPaneFileSystemEvents.filter = filter; + tabPaneFileSystemEvents.loadingList = []; + tabPaneFileSystemEvents.data = param; + expect(tabPaneFileSystemEvents.currentSelection).not.toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest08', function () { + let litTable = new LitTable(); + tabPaneFileSystemEvents.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPaneFileSystemEvents.filter = filter; + tabPaneFileSystemEvents.loadingList = []; + tabPaneFileSystemEvents.data = param; + tabPaneFileSystemEvents.setProcessFilter(); + expect(tabPaneFileSystemEvents.pathList).toEqual(['All Path']); + }); + + it('TabPaneFileStatisticsTest09', function () { + let litTable = new LitTable(); + tabPaneFileSystemEvents.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPaneFileSystemEvents.filter = filter; + tabPaneFileSystemEvents.loadingList = []; + tabPaneFileSystemEvents.data = param; + expect(tabPaneFileSystemEvents.filterData()).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest10', function () { + let litTable = new LitTable(); + tabPaneFileSystemEvents.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPaneFileSystemEvents.filter = filter; + tabPaneFileSystemEvents.loadingList = []; + tabPaneFileSystemEvents.data = param; + tabPaneFileSystemEvents.fromStastics(param); + expect(tabPaneFileSystemEvents.filterEventType).toEqual('0'); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..57c5b2641adaf5331cbbea3653c7ec4ed9f23b61 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.test.ts @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFileStatistics } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFilesystemStatistics.js'; +// @ts-ignore +import { Utils } from '../../../../../../dist/trace/component/trace/base/Utils.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('TabPaneFileStatistics Test', () => { + document.body.innerHTML = `
`; + let tabPaneFileStatistics = document.querySelector('#statistics'); + let param = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + + it('TabPaneFileStatisticsTest01', function () { + tabPaneFileStatistics.setInitDua = jest.fn(() => true); + let item = { + allDuration: '', + minDuration: '', + avgDuration: '', + maxDuration: '', + }; + expect(tabPaneFileStatistics.setInitDua(item)).toBeTruthy(); + }); + + it('TabPaneFileStatisticsTest02', function () { + tabPaneFileStatistics.getInitData = jest.fn(() => true); + let item = { + allDuration: '', + minDuration: '', + avgDuration: '', + maxDuration: '', + }; + expect(tabPaneFileStatistics.getInitData(item)).toBeTruthy(); + }); + + it('TabPaneFileStatisticsTest04', function () { + tabPaneFileStatistics.showButtomMenu = jest.fn(() => true); + let isShow = { + filter: { + setAttribute: 'tree, input, inputLeftText', + }, + }; + expect(tabPaneFileStatistics.showButtomMenu(isShow)).toBeTruthy(); + }); + + it('TabPaneFileStatisticsTest08', function () { + let FileStatistics = new TabPaneFileStatistics(); + let item = { + allDuration: '', + minDuration: '', + avgDuration: '', + maxDuration: '', + name: 'as', + logicalWrites: '', + logicalReads: '', + otherFile: '0 Bytes', + pid: 1, + }; + Utils.getBinaryByteWithUnit = jest.fn(() => true); + expect(FileStatistics.getInitData(item)).toEqual({ + allDuration: '', + avgDuration: '', + logicalReads: true, + logicalWrites: true, + maxDuration: '', + minDuration: '', + name: 'as', + node: { + allDuration: '', + avgDuration: '', + children: [], + logicalReads: '', + logicalWrites: '', + maxDuration: '', + minDuration: '', + name: 'as', + otherFile: '0 Bytes', + pid: 1, + }, + otherFile: true, + pid: 1, + title: 'as(1)', + }); + }); + + it('TabPaneFileStatisticsTest09', function () { + let FileStatistics = new TabPaneFileStatistics(); + let node = { + children: [], + }; + expect(FileStatistics.sortTable(node, '')).toBeUndefined(); + }); + + it('TabPaneFileStatisticsTest10', function () { + let litTable = new LitTable(); + tabPaneFileStatistics.appendChild(litTable); + tabPaneFileStatistics.data = param; + expect(tabPaneFileStatistics.selectionParam).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7a4650fd131046216fb38c6946dbe03ed697e548 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.test.ts @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFilesystemStatisticsAnalysis } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneFilesystemStatisticsAnalysis.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabPaneFilesystemStatisticsAnalysis Test', () => { + document.body.innerHTML = ``; + let tabPane = document.querySelector('#statistics-analysis'); + + let param = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + + let item = { + durFormat: '194.23ms ', + duration: 194230478, + isHover: true, + percent: '99.00', + pid: 3744, + tableName: 'test(3744)', + }; + + let res = [ + { + durFormat: '194.23ms ', + duration: 194230478, + isHover: true, + percent: '99.00', + pid: 3744, + tableName: 'test(3744)', + }, + ]; + + let processData = [ + { + callChainId: 13, + dur: 240916, + libId: 539, + libName: 'libName.z.so', + pid: 911, + processName: 'processName(911)', + symbolId: 799, + symbolName: 'symbolName', + threadName: 'threadName', + tid: 404, + type: 0, + }, + ]; + + let threadStatisticsData = { durFormat: '194.23ms ', duration: 0, isHover: false, percent: '100.00', tableName: '' }; + + it('systemStatisticsAnalysis01', function () { + let litTable = new LitTable(); + tabPane.appendChild(litTable); + let filter = new TabPaneFilter(); + tabPane.filter = filter; + tabPane.loadingList = []; + tabPane.data = param; + expect(tabPane.currentSelection).not.toBeUndefined(); + }); + + it('systemStatisticsAnalysis02', function () { + expect(tabPane.clearData()).toBeUndefined(); + }); + + it('systemStatisticsAnalysis03', function () { + tabPane.processData = processData; + tabPane.getFilesystemType(item, param); + expect(tabPane.progressEL.loading).toBeFalsy(); + }); + + it('systemStatisticsAnalysis04', function () { + tabPane.processData = processData; + tabPane.getFilesystemThread(item, param); + expect(tabPane.currentLevel).toEqual(2); + }); + + it('systemStatisticsAnalysis05', function () { + tabPane.processData = processData; + tabPane.getFilesystemSo(item, param); + expect(tabPane.currentLevel).toEqual(3); + }); + + it('systemStatisticsAnalysis06', function () { + tabPane.processData = processData; + tabPane.getFilesystemFunction(item, param); + expect(tabPane.currentLevel).toEqual(4); + }); + + it('systemStatisticsAnalysis07', function () { + expect(tabPane.typeIdToString(0)).toEqual('OPEN'); + }); + + it('systemStatisticsAnalysis08', function () { + expect(tabPane.typeIdToString(2)).toEqual('READ'); + }); + + it('systemStatisticsAnalysis09', function () { + expect(tabPane.typeIdToString(1)).toEqual('CLOSE'); + }); + + it('systemStatisticsAnalysis10', function () { + expect(tabPane.getPieChartData(res).length).toEqual(1); + }); + + it('systemStatisticsAnalysis11', function () { + tabPane.tableProcess.reMeauseHeight = jest.fn(() => true); + tabPane.getFilesystemProcess(param, processData); + expect(tabPane.processData).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ba8ff9296c3f058f5124cd2d5e7173a975569b9 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.test.ts @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneIOTierStatistics } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneIOTierStatistics.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +import {getTabPaneIOTierStatisticsData} from "../../../../../../dist/trace/database/SqlLite.js"; +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +// +// jest.mock('../../../../../../dist/base-ui/table/lit-table.js', () => { +// return {}; +// }); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabPaneIOTierStatistics Test', () => { + document.body.innerHTML = ``; + let tabPane = document.querySelector('#io-tier-statistics'); + + let param = { + anomalyEnergy: [], + clockMapData: { size: 0 }, + cpuAbilityIds: [], + cpuFreqFilterIds: [], + cpuFreqLimitDatas: [], + cpuStateFilterIds: [], + cpus: [], + diskAbilityIds: [], + diskIOLatency: false, + diskIOReadIds: [2, 7, 1, 3, 4, 5, 6], + diskIOWriteIds: [2, 7, 1, 3, 4, 5, 6], + diskIOipids: [2, 7, 1, 3, 4, 5, 6], + fileSysVirtualMemory: false, + fileSystemType: [], + fsCount: 0, + funAsync: [], + funTids: [], + hasFps: false, + irqMapData: { size: 0 }, + jsMemory: [], + leftNs: 964699689, + memoryAbilityIds: [], + nativeMemory: [], + nativeMemoryStatistic: [], + networkAbilityIds: [], + perfAll: false, + perfCpus: [], + perfProcess: [], + perfSampleIds: [], + perfThread: [], + powerEnergy: [], + processTrackIds: [], + promiseList: [], + recordStartNs: 780423789228, + rightNs: 24267556624, + sdkCounterIds: [], + sdkSliceIds: [], + smapsType: [], + systemEnergy: [], + threadIds: [], + virtualTrackIds: [], + vmCount: 0, + }; + it('ioTierStatistics01', function () { + let queryResult = sqlit.getTabPaneIOTierStatisticsData; + queryResult.mockResolvedValue([ + { + "pid": 186, + "pname": "kworker/u8:4", + "tier": 0, + "ipid": 2, + "path": "-", + "count": 3, + "allDuration": 19543418, + "minDuration": 6408209, + "maxDuration": 6668084, + "avgDuration": 6514472.66666667 + }, + { + "pid": 186, + "pname": "kworker/u8:4", + "tier": 0, + "ipid": 2, + "path": "/data/thermal/config/configLevel", + "count": 1, + "allDuration": 5916167, + "minDuration": 5916167, + "maxDuration": 5916167, + "avgDuration": 5916167 + }, + { + "pid": 186, + "pname": "kworker/u8:4", + "tier": 0, + "ipid": 2, + "path": "/data/local/tmp/hiebpf.data", + "count": 2, + "allDuration": 9192751, + "minDuration": 2386417, + "maxDuration": 6806334, + "avgDuration": 4596375.5 + }, + { + "pid": 237, + "pname": "jbd2/mmcblk0p11", + "tier": 0, + "ipid": 7, + "path": "-", + "count": 7, + "allDuration": 32377630, + "minDuration": 2749251, + "maxDuration": 5033292, + "avgDuration": 4625375.71428571 + } + ]); + tabPane.data = param; + expect(tabPane.selectionParam).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.test.ts b/ide/test/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a925f453f7eaed01af796bf4331346c6307df05 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneVirtualMemoryStatistics } from '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.js'; +import '../../../../../../dist/trace/component/trace/sheet/file-system/TabPaneVirtualMemoryStatistics.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('TabPaneVirtualMemoryStatistics Test', () => { + document.body.innerHTML = ` +`; + let tabPaneVirtualMemoryStatistics = document.querySelector('#statistics') as TabPaneVirtualMemoryStatistics; + it('TabPaneVirtualMemoryStatisticsTest01', function () { + expect(tabPaneVirtualMemoryStatistics).toBeDefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/fps/TabPaneCpuFreqLimits.test.ts b/ide/test/trace/component/trace/sheet/fps/TabPaneCpuFreqLimits.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc2c46706031ca929e856654df392b43f2acbef5 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/fps/TabPaneCpuFreqLimits.test.ts @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneCpuFreqLimits } from '../../../../../../dist/trace/component/trace/sheet/freq/TabPaneCpuFreqLimits.js'; +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneCpuFreqLimits Test', () => { + let tabPaneCpuFreqLimits = new TabPaneCpuFreqLimits(); + + it('TabPaneCpuFreqLimitsTest01', function () { + expect((tabPaneCpuFreqLimits.formatData([],1,1))).toBeUndefined(); + }); + it('TabPaneCpuFreqLimitsTest02', function () { + expect((tabPaneCpuFreqLimits.sortTable('',0))).toBeUndefined(); + }); + it('TabPaneCpuFreqLimitsTest03', function () { + expect((tabPaneCpuFreqLimits.sortTable('timeStr',1))).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/trace/sheet/fps/TabPaneFps.test.ts b/ide/test/trace/component/trace/sheet/fps/TabPaneFps.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..20c847a2ad213e6c181a2199d5c242457700e730 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/fps/TabPaneFps.test.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneFps } from '../../../../../../dist/trace/component/trace/sheet/fps/TabPaneFps.js'; +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneFps Test', () => { + let tabPaneFps = new TabPaneFps(); + + it('TabPaneFpsTest01', function () { + let mockgetTabFps = sqlit.getTabFps; + mockgetTabFps.mockResolvedValue([{ leftNs: 10, rightNs: 10 }]); + let a = { rightNs: 1, leftNs: 1 }; + expect((tabPaneFps.data = a)).toBeTruthy(); + }); + + it('TabPaneFpsTest02', function () { + let mockgetTabFps = sqlit.getTabFps; + mockgetTabFps.mockResolvedValue([]); + let a = { rightNs: 1, leftNs: 1 }; + expect((tabPaneFps.data = a)).toBeTruthy(); + }); + + it('TabPaneFpsTest03', function () { + expect(tabPaneFps.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.test.ts b/ide/test/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..74758bb4b9041746001b0fa0118bd69d9cd2fd2c --- /dev/null +++ b/ide/test/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.test.ts @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { TabPanePerfAnalysis } from '../../../../../../dist/trace/component/trace/sheet/hiperf/TabPanePerfAnalysis.js'; +//@ts-ignore +import {queryHiPerfProcessCount} from "../../../../../../dist/trace/database/SqlLite.js"; +import crypto from 'crypto'; + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +jest.mock('../../../../../../dist/base-ui/chart/pie/LitChartPie.js', () => { + return {}; +}); + +jest.mock('../../../../../../dist/base-ui/table/lit-table.js', () => { + return {}; +}); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPanePerfAnalysis Test', () => { + it('TabPanePerfAnalysisTest01 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis() + expect(tabPanePerfAnalysis.clearData()).toBeUndefined(); + }); + it('TabPanePerfAnalysisTest02 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis() + expect(tabPanePerfAnalysis.getBack()).toBeUndefined(); + }); + it('TabPanePerfAnalysisTest03 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis() + expect(tabPanePerfAnalysis.sortByColumn({key: 'startTime'}, {sort: 1})).toBeUndefined(); + }); + it('TabPanePerfAnalysisTest04 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis() + expect(tabPanePerfAnalysis.totalCountData(1)).toStrictEqual( + {"allCount": 1, "count": 0, "countFormat": "1.00ms", "percent": "100.00", "pid": ""} + ); + }); + it('TabPanePerfAnalysisTest05 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis(); + let res = [{ + count:1, + length:1 + }] + expect(tabPanePerfAnalysis.getPieChartData(res)).toStrictEqual( + [{"count": 1, "length": 1}] + ); + }); + + it('TabPanePerfAnalysisTest06 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis() + let queryHiPerf = sqlit.queryHiPerfProcessCount; + queryHiPerf.mockResolvedValue([ + { + "pid": 174, + "time": 11799859602, + "threadName": "sugov:0", + "tid": 174, + "id": 28347, + "callchain_id": 10972, + "processName": "sugov:0(174)" + }, + { + "pid": 388, + "time": 11811453353, + "threadName": "render_service", + "tid": 871, + "id": 28355, + "callchain_id": 10974, + "processName": "render_service(388)" + }, + { + "pid": 28826, + "time": 11820687229, + "threadName": "kworker/2:2-events_freezable", + "tid": 28826, + "id": 28361, + "callchain_id": 10976, + "processName": "kworker/2:2-events_freezable(28826)" + }, + { + "pid": 28917, + "time": 11831719814, + "threadName": "hiperf", + "tid": 28922, + "id": 28372, + "callchain_id": 51, + "processName": "hiperf(28917)" + } + ]) + let para = { + leftNs:11799195238, + rightNs:16844304830, + cpus: [1,2,3], + threads: [4,5,6], + processes: [7,8,9], + perfThread:[4,5,6], + perfProcess:[4,5,6] + } + tabPanePerfAnalysis.tableProcess.reMeauseHeight = jest.fn(() => true); + tabPanePerfAnalysis.getHiperfProcess(para) + expect(tabPanePerfAnalysis.clearData()).toBeUndefined(); + }); + + it('TabPanePerfAnalysisTest07 ', function () { + let tabPanePerfAnalysis = new TabPanePerfAnalysis() + let para = { + count: 5, + tid: 1, + pid: 2, + libId: 3 + } + let processArr = [ + { + "pid": 233, + "time": 7978660718, + "threadName": "hilogd", + "tid": 235, + "id": 19165, + "callchain_id": 7492 + }, + { + "pid": 233, + "time": 8092040146, + "threadName": "hilogd", + "tid": 235, + "id": 19408, + "callchain_id": 7578 + }, + { + "pid": 233, + "time": 8117205732, + "threadName": "hilogd", + "tid": 235, + "id": 19496, + "callchain_id": 7618 + } + ]; + tabPanePerfAnalysis.processData = processArr; + tabPanePerfAnalysis.tableFunction.reMeauseHeight = jest.fn(() => true); + tabPanePerfAnalysis.getHiperfFunction(para, null); + expect(tabPanePerfAnalysis.clearData()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/component/trace/sheet/hiperf/TabPerfProfile.test.ts b/ide/test/trace/component/trace/sheet/hiperf/TabPerfProfile.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bfa65ddcc4ef3522930cebe868ec1c2702c05497 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/hiperf/TabPerfProfile.test.ts @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { TabpanePerfProfile } from '../../../../../../dist/trace/component/trace/sheet/hiperf/TabPerfProfile.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPerfProfile Test', () => { + document.body.innerHTML = ``; + let tabpanePerfProfile = document.querySelector('#perfprofile') as TabpanePerfProfile; + + it('TabpanePerfProfileTest01 ', function () { + TabpanePerfProfile.getParentTree = jest.fn(() => true); + let call = { + id: '1', + dur: 1, + children: [], + }; + let id = '1'; + expect(tabpanePerfProfile.getParentTree([call], { id }, [])).not.toBeUndefined(); + }); + it('TabpanePerfProfileTest02 ', function () { + let call = { + id: '1', + dur: 1, + children: [], + }; + expect(tabpanePerfProfile.getChildTree([call], '1', [])).not.toBeUndefined(); + }); + + it('TabpanePerfProfileTest03 ', function () { + let call = { + id: '1', + dur: 1, + children: [], + }; + expect(tabpanePerfProfile.setRightTableData(call)).toBeUndefined(); + }); + it('TabpanePerfProfileTest04 ', function () { + expect(tabpanePerfProfile.showButtomMenu()).toBeUndefined(); + }); + it('TabpanePerfProfileTest05 ', function () { + let isShow = 1; + expect(tabpanePerfProfile.showButtomMenu(isShow)).toBeUndefined(); + }); + it('TabpanePerfProfileTest06 ', function () { + TabpanePerfProfile.getParentTree = jest.fn(() => true); + let call = { + id: '1', + dur: 1, + children: [], + }; + let id = '2'; + + expect(tabpanePerfProfile.getParentTree([call], { id }, [])).not.toBeUndefined(); + }); + it('TabpanePerfProfileTest08 ', function () { + let data = { + icon: 'tree', + }; + tabpanePerfProfile.tbl!.reMeauseHeight = jest.fn(() => true); + expect(tabpanePerfProfile.switchFlameChart(data)).toBeUndefined(); + }); + it('TabpanePerfProfileTest07 ', function () { + let data = { + icon: 1, + }; + expect(tabpanePerfProfile.switchFlameChart(data)).toBeUndefined(); + }); + it('TabpanePerfProfileTest09 ', function () { + tabpanePerfProfile.sortTree = jest.fn(() => true); + tabpanePerfProfile.sortTree.sort = jest.fn(() => true); + expect(tabpanePerfProfile.setLTableData()).toBeUndefined(); + }); + it('TabpanePerfProfileTest10 ', function () { + tabpanePerfProfile.getDataByWorker = jest.fn(); + tabpanePerfProfile.data = [ + { + leftNs: 2565, + rightNs: 2632, + }, + ]; + expect(tabpanePerfProfile.data).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/hiperf/TabPerfSampleList.test.ts b/ide/test/trace/component/trace/sheet/hiperf/TabPerfSampleList.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..97a41c1d199e6b752225c45a5553149f02d25743 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/hiperf/TabPerfSampleList.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { TabPerfSampleList } from '../../../../../../dist/trace/component/trace/sheet/hiperf/TabPerfSampleList.js'; +import '../../../../../../dist/trace/component/trace/sheet/hiperf/TabPerfSampleList.js'; + +const sqlite = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPerfSampleList Test', () => { + document.body.innerHTML = ``; + let sampleList = document.querySelector('#sampleList') as TabPerfSampleList; + let sampleListData = { + leftNs: 1222, + rightNs: 5286, + }; + + let perfSampleList = [ + { + sampleId: 1, + tid: 1522, + threadName: 'test', + state: 'state', + pid: 44147, + time: 4744, + core: 155, + }, + ]; + let perfSampleListByTimeRange = sqlite.queryPerfSampleListByTimeRange; + + perfSampleListByTimeRange.mockResolvedValue(perfSampleList); + let perfProcess = sqlite.queryPerfProcess; + perfProcess.mockResolvedValue([ + { + pid: 44147, + processName: 'test1', + }, + ]); + let perfSampleCallChainDate = [ + { + callChainId: 255, + csampleId: 5525, + fileId: 4585, + symbolId: 4855, + vaddrInFile: 0, + symbol: 'name', + }, + ]; + let perfSampleCallChain = sqlite.queryPerfSampleCallChain; + perfSampleCallChain.mockResolvedValue(perfSampleCallChainDate); + + it('TabPerfSampleListTest01', function () { + sampleList.data = sampleListData; + expect(sampleList.data).toBeUndefined(); + }); + + it('TabPerfSampleListTest02', function () {}); + + it('TabPerfSampleListTest03', function () { + expect(sampleList.sortTable('timeString', 2)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/irq/TabPaneIrqCounter.test.ts b/ide/test/trace/component/trace/sheet/irq/TabPaneIrqCounter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3156f64ecd2777206850c09e6f00f830f71341c --- /dev/null +++ b/ide/test/trace/component/trace/sheet/irq/TabPaneIrqCounter.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneIrqCounter } from '../../../../../../dist/trace/component/trace/sheet/irq/TabPaneIrqCounter.js'; +// @ts-ignore +import { IrqStruct } from '../../../../../../dist/trace/database/ui-worker/ProcedureWorkerIrq.js'; + +jest.mock('../../../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneIrqCounter Test', () => { + let tabPaneIrqCounter = new TabPaneIrqCounter(); + let map = new Map(); + map.set('irq', [new IrqStruct()]); + let frameData = { + leftNs: 253, + rightNs: 1252, + argSetId: 5, + startNS: 11111, + dur: 22222, + name: 'irq', + irqMapData: map, + framesData: [ + { + id: 25, + ts: 254151, + dur: 1202, + name: '1583', + argSetId: 5, + type: '0', + pid: 20, + gpu_dur: 2568, + app_dur: 110, + }, + ], + }; + + it('TabPaneIrqCounterTest01', function () { + tabPaneIrqCounter.data = frameData; + expect(tabPaneIrqCounter.data).toBeUndefined(); + }); + + it('TabPaneIrqCounterTest02', function () { + expect( + tabPaneIrqCounter.sortByColumn({ + key: 'jankType', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/jank/TabPaneFrames.test.ts b/ide/test/trace/component/trace/sheet/jank/TabPaneFrames.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..292f7fdf74b1c59ff7291abb77aed8a635bc1744 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/jank/TabPaneFrames.test.ts @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneFrames } from '../../../../../../dist/trace/component/trace/sheet/jank/TabPaneFrames.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneFrames Test', () => { + let tabPaneFrames = new TabPaneFrames(); + + let frameData = { + leftNs: 253, + rightNs: 1252, + jankFramesData: [ + [ + { + id: 25, + ts: 254151, + dur: 1202, + name: '1583', + depth: 1, + jank_tag: true, + cmdline: 'render.test', + type: '0', + pid: 20, + frame_type: 'frameTime', + src_slice: '525', + rs_ts: 2569, + rs_vsync: '2569', + rs_dur: 1528, + rs_pid: 1252, + rs_name: 'name', + gpu_dur: 2568, + app_dur: 110, + }, + { + id: 69, + ts: 4244, + dur: 245, + name: '2454', + depth: 1, + jank_tag: true, + cmdline: 'app.jank.test', + type: '0', + pid: 65, + frame_type: 'app', + src_slice: '525', + app_dur: 2345, + }, + { + id: 516, + ts: 2164, + dur: 2153, + name: '1234', + depth: 1, + jank_tag: true, + cmdline: 'render.test', + type: '0', + pid: 135, + frame_type: 'renderService', + src_slice: '446', + rs_ts: 4364, + rs_vsync: '1242', + rs_dur: 642, + rs_pid: 1266, + rs_name: 'name', + gpu_dur: 15646, + }, + { + id: 58, + ts: 2156, + dur: 45, + name: '1452', + depth: 1, + jank_tag: false, + cmdline: 'app.test', + type: '0', + pid: 128, + frame_type: 'app', + src_slice: '213', + app_dur: 4563, + }, + { + id: 56389, + ts: 56, + dur: 563, + name: '4786', + depth: 1, + jank_tag: false, + cmdline: 'render.test', + type: '0', + pid: 456, + frame_type: 'renderService', + src_slice: '4563', + rs_ts: 6356, + rs_vsync: '434', + rs_dur: 5464, + rs_pid: 565, + rs_name: 'name', + gpu_dur: 5465, + }, + { + id: 1635, + ts: 2153, + dur: 13, + name: '3153', + depth: 1, + jank_tag: false, + cmdline: 'render.test', + type: '0', + pid: 123, + frame_type: 'frameTime', + src_slice: '53', + rs_ts: 2135, + rs_vsync: '203', + rs_dur: 516, + rs_pid: 513, + rs_name: 'name', + gpu_dur: 153, + app_dur: 32, + }, + ], + ], + }; + + it('TabPaneFramesTest01', function () { + tabPaneFrames.data = frameData; + expect(tabPaneFrames.data).toBeUndefined(); + }); + + it('TabPaneFramesTest02', function () { + expect( + tabPaneFrames.sortByColumn({ + key: 'jankType', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.test.ts b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a1559847936116e144aaca6cd0cb516c79c05b4 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.test.ts @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneNMCallInfo } from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMCallInfo.js'; +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +// @ts-ignore +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneNMCallInfo Test', () => { + document.body.innerHTML = ''; + let tabPaneNMCallInfo = document.querySelector('#ddd'); + + let nativeHookData = [ + { + eventId: 0, + eventType: '', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + isSelected: false, + }, + { + eventId: 0, + eventType: '', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + isSelected: false, + }, + ]; + + tabPaneNMCallInfo.currentSelection = jest.fn(() => true); + TabPaneNMCallInfo.data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + }; + + it('TabPaneNMCallInfoTest08', function () { + let hookLeft = { + id: '', + pid: '', + library: '', + title: '', + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 2, + symbol: '', + type: 0, + heapSize: 0, + heapSizeStr: '', + eventId: 0, + threadId: 0, + }; + let groupByWithTid = tabPaneNMCallInfo.setRightTableData(hookLeft); + expect(groupByWithTid).toBeUndefined(); + }); + + it('TabPaneNMCallInfoTest10', function () { + expect(tabPaneNMCallInfo.sortTreeByColumn()).toBeUndefined(); + }); + + it('TabPaneNMCallInfoTest11', function () { + let tab = new TabPaneNMCallInfo(); + let MockqueryNativeHookEventTid = sqlit.queryNativeHookEventTid; + MockqueryNativeHookEventTid.mockResolvedValue([ + { + eventId: 0, + eventType: 'AllocEvent', + heap_size: 2, + addr: 'addr', + startTs: 0, + endTs: 500, + tid: 2, + threadName: 'threadName', + }, + ]); + tab.data = { + leftNs: 0, + rightNs: 500, + nativeMemory: 'All Heap & Anonymous VM', + }; + + tab.startWorker = jest.fn(() => true); + expect(tab.data).toBeUndefined(); + }); + + it('TabPaneNMCallInfoTest12', function () { + expect(tabPaneNMCallInfo.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + + + + +
+
+ " +`); + }); + it('TabPaneNMCallInfoTest04', function () { + TabPaneNMCallInfo.getParentTree = jest.fn(() => true); + let hook = { + id: '1', + dur: 1, + children: [], + }; + let id = '1'; + expect(tabPaneNMCallInfo.getParentTree([hook], { id }, [])).not.toBeUndefined(); + }); + it('TabPaneNMCallInfoTest05', function () { + TabPaneNMCallInfo.getChildTree = jest.fn(() => true); + let hook = { + eventId: '1', + dur: 1, + children: [], + }; + expect(tabPaneNMCallInfo.getChildTree([hook], '1', [])).not.toBeUndefined(); + }); + it('TabPaneNMCallInfoTest13', function () { + expect(tabPaneNMCallInfo.showButtomMenu()).toBeUndefined(); + }); + it('TabPaneNMCallInfoTest14', function () { + let isShow = 1; + expect(tabPaneNMCallInfo.showButtomMenu(isShow)).toBeUndefined(); + }); + it('TabPaneNMCallInfoTest15', function () { + expect(tabPaneNMCallInfo.showButtomMenu({},{})).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.test.ts b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8a0628f42ae8710ddb97286525e4d04e5bef1f4 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.test.ts @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2022 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 '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.js'; +// @ts-ignore +import { TabPaneNMCallTree } from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMCallTree.js'; +// @ts-ignore +import { TabPaneFilter } from '../../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js'; +// @ts-ignore +import { FrameChart } from '../../../../../../dist/trace/component/chart/FrameChart.js'; +// @ts-ignore +import { DisassemblingWindow } from '../../../../../../dist/trace/component/DisassemblingWindow.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneNMCallTree Test', () => { + document.body.innerHTML = '
'; + let tabPaneNMCallTree = document.querySelector('#ddd'); + let dom = new FrameChart(); + dom.setAttribute('id', 'framechart'); + tabPaneNMCallTree.frameChart = dom; + tabPaneNMCallTree.modal = new DisassemblingWindow(); + tabPaneNMCallTree.filter = new TabPaneFilter(); + + it('TabPaneNMCallTreeTest01', function () { + let hookLeft = { + ip: '', + symbolsId: 0, + pathId: 0, + processName: '', + type: 0, + children: [], + }; + tabPaneNMCallTree.dataSource = []; + tabPaneNMCallTree.setRightTableData = jest.fn(() => true); + let groupByWithTid = tabPaneNMCallTree.setRightTableData(hookLeft); + expect(groupByWithTid).toBeTruthy(); + }); + + it('TabPaneNMCallTreeTest02', function () { + let data = [ + { size: 10, count: 20, children: [] }, + { size: 11, count: 21, children: [] }, + { size: 21, count: 31, children: [] }, + ]; + expect(tabPaneNMCallTree.sortTree(data).length).toBe(3); + }); + + it('TabPaneNMCallTreeTest03', function () {}); + + it('TabPaneNMCallTreeTest04', function () { + expect(tabPaneNMCallTree.initHtml()).toMatchInlineSnapshot(` +" + +
+ + + +
+ + + + + + + + + + + + + + + + + +
+ + + Heaviest Stack Trace + + + + + +
+ + + + + + + +
+
" +`); + }); + it('TabPaneNMCallTreeTest05', function () { + let hook = { + id: '1', + dur: 1, + children: [], + }; + let id = '1'; + expect(tabPaneNMCallTree.getParentTree([hook], { id }, [])).not.toBeUndefined(); + }); + it('TabPaneNMCallInfoTest06', function () { + let hook = { + eventId: '1', + dur: 1, + children: [], + }; + expect(tabPaneNMCallTree.getChildTree([hook], '1', [])).not.toBeUndefined(); + }); + it('TabPaneNMCallInfoTest07', function () { + document.body.innerHTML = "
"; + let table = document.querySelector('#filter'); + table!.setAttribute('tree', '1'); + tabPaneNMCallTree.filter = table; + tabPaneNMCallTree.filter.showThird = jest.fn(() => { + false; + }); + expect(tabPaneNMCallTree.showButtomMenu()).toBeUndefined(); + }); + it('TabPaneNMCallInfoTest08', function () { + let isShow = 1; + document.body.innerHTML = "
"; + let table = document.querySelector('#filter'); + table!.setAttribute('tree', '1'); + tabPaneNMCallTree.filter = table; + tabPaneNMCallTree.filter.showThird = jest.fn(() => { + false; + }); + expect(tabPaneNMCallTree.showButtomMenu(isShow)).toBeUndefined(); + }); + + it('TabPaneNMCallInfoTest09', function () { + tabPaneNMCallTree.filter.initializeFilterTree = jest.fn(); + tabPaneNMCallTree.initFilterTypes = jest.fn(); + tabPaneNMCallTree.native_type = jest.fn(() => ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM']); + tabPaneNMCallTree.getDataByWorkerQuery = jest.fn(); + tabPaneNMCallTree.data = { + leftNs: 0, + rightNs: 500, + nativeMemory: 'All Heap & Anonymous VM', + }; + expect(tabPaneNMCallTree.data).toBeUndefined(); + }); + it('TabPaneNMCallTreeTest10', function () { + let data = [ + { size: 10, count: 20, children: [] }, + { size: 11, count: 21, children: [] }, + { size: 21, count: 31, children: [] }, + ]; + expect(tabPaneNMCallTree.setLTableData(data)).toBe(); + }); + it('TabPaneNMCallTreeTest11', function () { + let data = [ + { callTreeConstraints:{ + inputs:[1] + } + , dataMining: 20, callTree: [] ,icon : 'block'}, + { callTreeConstraints:{ + inputs:[1] + }, dataMining: 21, callTree: [] ,icon : 'block'}, + { callTreeConstraints:{ + inputs:[1] + }, dataMining: 31, callTree: [] ,icon : 'block'}, + ]; + expect(tabPaneNMCallTree.switchFlameChart(data)).toBe(); + }); + it('TabPaneNMCallTreeTest12', function () { + expect(tabPaneNMCallTree.initFilterTypes()).toBe(); + }); + it('TabPaneNMCallTreeTest13', function () { + let data = [ + { id: 0, count: 20, children: [] }, + { id: 1, count: 21, children: [] }, + { id: 2, count: 31, children: [] }, + ]; + expect(tabPaneNMCallTree.setRightTableData(data)).toBeTruthy(); + }); + it('TabPaneNMCallTreeTest14', function () { + expect(tabPaneNMCallTree.getDataByWorkerQuery({},{})).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.test.ts b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f5e7419517682e441c6cb4b381cf7a54a2a7a4a --- /dev/null +++ b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.test.ts @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneNMSampleList } from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table'; +// @ts-ignore +import { NativeHookSampleQueryInfo, NativeHookSamplerInfo } from '../../../../../../dist/trace/bean/NativeHook.js'; +// @ts-ignore +import { NativeMemory } from '../../../../../../dist/trace/bean/NativeHook.js'; +// @ts-ignore +import { queryAllHookData } from '../../../../../../dist/trace/database/SqlLite.js'; +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('TabPaneNMSampleList Test', () => { + document.body.innerHTML = ''; + let tabPaneNMSampleList = document.querySelector('#ddt'); + + TabPaneNMSampleList.source = [ + { + current: '', + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: '', + growth: '', + total: 0, + totalGrowth: '', + existing: 0, + children: [], + tempList: [], + timestamp: '', + eventId: -1, + }, + ]; + TabPaneNMSampleList.filterSelect = '0'; + + tabPaneNMSampleList.currentSelection = jest.fn(() => true); + let dat = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + }; + + let NativeHookSnapshotTypes = [ + { + eventId: -1, + current: 0, + eventType: '', + subType: '', + growth: 0, + existing: 0, + addr: '', + startTs: 0, + endTs: 0, + total: 0, + children: [], + }, + ]; + + let MockNativeHookSnapshotTypes = sqlit.queryNativeHookSnapshotTypes; + + MockNativeHookSnapshotTypes.mockResolvedValue([new NativeHookSampleQueryInfo()]); + + tabPaneNMSampleList.data = dat; + it('TabPaneNMSampleListTest01', function () { + expect(TabPaneNMSampleList.serSelection(dat)).toBeUndefined(); + }); + + it('TabPaneNMSampleListTest02', function () { + let sampleData = new NativeMemory(); + + let MockqueryAllHookData = sqlit.queryAllHookData; + MockqueryAllHookData.mockResolvedValue([new NativeHookSampleQueryInfo()]); + + expect(TabPaneNMSampleList.addSampleData(sampleData)).toBeUndefined(); + }); + + it('TabPaneNMSampleListTest04', function () { + let snapshot = { + current: '', + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: '', + growth: '', + total: 0, + totalGrowth: '', + existing: 0, + children: [], + tempList: [], + timestamp: '', + eventId: -1, + }; + + let snapshotLeft = { + current: '', + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: '', + growth: '', + total: 0, + totalGrowth: '', + existing: 0, + children: [snapshot], + tempList: [], + timestamp: '', + eventId: -1, + }; + + let snapshotRight = { + current: '', + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: '', + growth: '', + total: 0, + totalGrowth: '', + existing: 0, + children: [snapshot], + tempList: [], + timestamp: '', + eventId: -1, + }; + expect(TabPaneNMSampleList.prepChild(snapshotLeft, snapshotRight)).toBeUndefined(); + }); + + it('TabPaneNMSampleListTest10', function () { + expect(TabPaneNMSampleList.data).toBeUndefined(); + }); + + it('TabPaneNMSampleListTest11', function () { + expect(TabPaneNMSampleList.initTypes()).toBeUndefined(); + }); + + it('TabPaneNMSampleListTest05', function () { + expect(tabPaneNMSampleList.initHtml()).toMatchInlineSnapshot(` +" + + +
+ + + + + + + + + + + + + +
+ + + + + + + + +
+ " +`); + }); + + it('TabPaneNMSampleListTest09', function () { + let rootSample = new NativeHookSamplerInfo(); + + let merageSample = { + growth: 1, + endTs: 2, + startTs: 2, + addr: '1', + eventId: 0, + }; + expect(TabPaneNMSampleList.merageSampleData(1, 1, rootSample, merageSample)).toBeUndefined(); + }); + + it('TabPaneNMSampleListTest12', function () { + let rootSample = new NativeHookSamplerInfo(); + + let MockqueryAllHookData = sqlit.queryAllHookData; + + MockqueryAllHookData.mockResolvedValue([ + { + eventId: 1, + eventType: 'aa', + subType: 1, + addr: 'aaaa', + growth: 2, + startTs: 11111, + endTs: 211111, + }, + ]); + expect(TabPaneNMSampleList.queryAllHookInfo(dat, rootSample)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.test.ts b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd8e5e13d4ca0fa62b9fb0a55c35593de2814433 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.test.ts @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 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 crypto from 'crypto'; +// @ts-ignore +import { TabPaneNMStatisticAnalysis } from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMStatisticAnalysis.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +jest.mock('../../../../../../dist/base-ui/chart/pie/LitChartPie.js', () => { + return {}; +}); + +jest.mock('../../../../../../dist/base-ui/table/lit-table.js', () => { + return {}; +}); + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +describe('TabPaneNMStatisticAnalysis Test', () => { + let tabStatisticAnalysis = new TabPaneNMStatisticAnalysis(); + tabStatisticAnalysis.tableType.reMeauseHeight = jest.fn(() => true); + tabStatisticAnalysis.tableSo.reMeauseHeight = jest.fn(() => true); + tabStatisticAnalysis.tableFunction.reMeauseHeight = jest.fn(() => true); + let dataArray = { + applyCount: 25336, + applyCountPercent: '99', + applySize: 13372754, + applySizeFormat: '12.75MB', + applySizePercent: '25023.87', + existCount: 1011, + existCountPercent: '98.54', + existSize: 809825, + existSizeFormat: '790.84KB', + existSizePercent: '2.36', + releaseCount: 52168, + releaseCountPercent: '99.53', + releaseSize: 12562929, + releaseSizeFormat: '11.98MB', + releaseSizePercent: '1.79', + tableName: 'Test', + typeId: 0, + typeName: 'Test', + }; + let select = { + recordStartNs: 8406282873525, + leftNs: 16648778040, + rightNs: 48320174407, + hasFps: false, + nativeMemory: ['All Heap & Anonymous VM', 'All Heap'], + }; + let processData = [ + { + applyId: 22945, + callChainId: 91, + count: 1, + endTs: 4831690110, + id: 22945, + libId: 420, + libName: 'test.z.so', + pid: 1, + size: 304, + startTs: 4806916233, + symbolId: 429, + symbolName: 'test', + tid: 5211, + type: 0, + }, + ]; + tabStatisticAnalysis.processData = processData; + + it('statisticAnalysis01', function () { + tabStatisticAnalysis.data = select; + expect(tabStatisticAnalysis.currentSelection).toEqual(select); + }); + + it('statisticAnalysis02', function () { + tabStatisticAnalysis.tabName.textContent = 'Statistic By Library Size'; + tabStatisticAnalysis.eventTypeData = [dataArray]; + let mouseMoveEvent: MouseEvent = new MouseEvent('click', { movementX: 1, movementY: 2 }); + tabStatisticAnalysis.back.dispatchEvent(mouseMoveEvent); + tabStatisticAnalysis.back.dispatchEvent(mouseMoveEvent); + }); + + it('statisticAnalysis03', function () { + tabStatisticAnalysis.getLibSize(dataArray, select); + expect(tabStatisticAnalysis.currentLevel).toEqual(1); + }); + + it('statisticAnalysis04', function () { + expect(tabStatisticAnalysis.getNMFunctionSize(dataArray, select)).toBeUndefined(); + }); + + it('statisticAnalysis05', function () { + tabStatisticAnalysis.calTypeSize(select, processData); + expect(tabStatisticAnalysis.processData.length).toBe(1); + }); + + it('statisticAnalysis06', function () { + let processData = [ + { + applyId: 22945, + callChainId: 91, + count: 1, + endTs: 4831690110, + id: 22945, + libId: 420, + libName: 'test.z.so', + pid: 1, + size: 304, + startTs: 4806916233, + symbolId: 429, + symbolName: 'test', + tid: 5211, + type: 1, + }, + ]; + tabStatisticAnalysis.calTypeSize(select, processData); + expect(tabStatisticAnalysis.currentLevelReleaseCount).toBe(0); + }); + + it('statisticAnalysis07', function () { + let processData = [ + { + applyId: 22945, + callChainId: 91, + count: 1, + endTs: 4831690110, + id: 22945, + libId: 420, + libName: 'test.z.so', + pid: 1, + size: 304, + startTs: 4806916233, + symbolId: 429, + symbolName: 'test', + tid: 5211, + type: 2, + }, + ]; + tabStatisticAnalysis.calTypeSize(select, processData); + expect(tabStatisticAnalysis.currentLevelApplySize).toBe(0); + }); + + it('statisticAnalysis08', function () { + let processData = [ + { + applyId: 22945, + callChainId: 91, + count: 1, + endTs: 4831690110, + id: 22945, + libId: 420, + libName: 'test.z.so', + pid: 1, + size: 304, + startTs: 4806916233, + symbolId: 429, + symbolName: 'test', + tid: 5211, + type: 3, + }, + ]; + tabStatisticAnalysis.calTypeSize(select, processData); + expect(tabStatisticAnalysis.processData.length).toBe(1); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.test.ts b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..24571debb9d239cb614b062179ee0b97fa057522 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.test.ts @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneNMStatstics } from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMStatstics.js'; +// @ts-ignore +import { + NativeHookMalloc, + NativeHookStatistics, + NativeHookStatisticsTableData, +} from '../../../../../../dist/trace/bean/NativeHook'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneNMStatstics Test', () => { + let tabPaneNMStatstics = new TabPaneNMStatstics(); + document.body.innerHTML = '
'; + + it('TabPaneNMStatsticsTest01', function () { + expect(tabPaneNMStatstics.setMallocTableData([1], [1])).toBeUndefined(); + }); + it('TabPaneNMStatsticsTest09', function () { + expect(tabPaneNMStatstics.setSubTypeTableData([1], [1])).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest02', function () { + let nativeHookMalloc: Array = [ + { + eventType: '', + subType: '', + heapSize: 0, + allocByte: 0, + allocCount: 0, + freeByte: 0, + freeCount: 0, + }, + ]; + let nativeHookStatisticsTableData: Array = [ + { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 0, + totalCount: 0, + existingValue: [], + }, + ]; + + expect(tabPaneNMStatstics.setSubTypeTableData(nativeHookMalloc, nativeHookStatisticsTableData)).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest03', function () { + expect(tabPaneNMStatstics.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + " +`); + }); + + it('TabPaneNMStatsticsTest04', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }; + let nativeHookStatistics: Array = [ + { + eventId: 0, + eventType: 'AllocEvent', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }, + ]; + + let nativeHookStatisticsTableData: Array = [ + { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 0, + totalCount: 0, + existingValue: [], + }, + ]; + + expect( + tabPaneNMStatstics.setMemoryTypeData(valData, nativeHookStatistics, nativeHookStatisticsTableData) + ).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest05', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ['All Heap'], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }; + let nativeHookStatistics: Array = [ + { + eventId: 0, + eventType: 'FreeEvent', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }, + ]; + + let nativeHookStatisticsTableData: Array = [ + { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 0, + totalCount: 0, + existingValue: [], + }, + ]; + + expect( + tabPaneNMStatstics.setMemoryTypeData(valData, nativeHookStatistics, nativeHookStatisticsTableData) + ).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest06', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ['All Anonymous VM'], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }; + let nativeHookStatistics: Array = [ + { + eventId: 0, + eventType: 'MmapEvent', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }, + ]; + + let nativeHookStatisticsTableData: Array = [ + { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 0, + totalCount: 0, + existingValue: [], + }, + ]; + + expect( + tabPaneNMStatstics.setMemoryTypeData(valData, nativeHookStatistics, nativeHookStatisticsTableData) + ).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest07', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ['All Anonymous VM'], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }; + let nativeHookStatistics: Array = [ + { + eventId: 0, + eventType: 'MunmapEvent', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }, + ]; + + let nativeHookStatisticsTableData: Array = [ + { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 0, + totalCount: 0, + existingValue: [], + }, + ]; + + expect( + tabPaneNMStatstics.setMemoryTypeData(valData, nativeHookStatistics, nativeHookStatisticsTableData) + ).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest08', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }; + let nativeHookStatistics: Array = [ + { + eventId: 0, + eventType: 'FreeEvent', + subType: '', + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }, + ]; + + let nativeHookStatisticsTableData: Array = [ + { + memoryTap: '', + existing: 0, + existingString: '', + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: '', + maxStr: '', + max: 100, + totalCount: 0, + existingValue: [], + }, + ]; + + expect( + tabPaneNMStatstics.setMemoryTypeData(valData, nativeHookStatistics, nativeHookStatisticsTableData) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMemory.test.ts b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMemory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..72dd085242d2350ff8e5919cd02e24f25c40c263 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/native-memory/TabPaneNMemory.test.ts @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + TabPaneNMemory, + initFilterTypes, +} from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMemory.js'; +// @ts-ignore +import { TabPaneNMSampleList } from '../../../../../../dist/trace/component/trace/sheet/native-memory/TabPaneNMSampleList.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +import crypto from 'crypto'; +// @ts-ignore +import { + queryNativeHookEventTid, + queryNativeHookSnapshotTypes, +} from '../../../../../../dist/trace/database/SqlLite.js'; + +Object.defineProperty(global.self, 'crypto', { + value: { + getRandomValues: (arr: string | any[]) => crypto.randomBytes(arr.length), + }, +}); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneNMemory Test', () => { + document.body.innerHTML = + '' + + ''; + let tabPaneNMemory = document.querySelector('#tnm'); + let val = { + statisticsSelectData: { + memoryTap: 1, + }, + }; + let hook = { eventId: 1 }; + + it('TabPaneNMemoryTest01', function () { + expect(tabPaneNMemory.initFilterTypes()).toBeUndefined(); + }); + + it('TabPaneNMemoryTest02', function () { + let MockqueryNativeHookEventTid = sqlit.queryNativeHookEventTid; + MockqueryNativeHookEventTid.mockResolvedValue([ + { + eventId: 0, + eventType: 'MmapEvent', + heap_size: 2, + addr: 'addr', + startTs: 0, + endTs: 500, + tid: 2, + threadName: 'threadName', + }, + ]); + + let MockNativeHookSnapshotTypes = sqlit.queryNativeHookSnapshotTypes; + MockNativeHookSnapshotTypes.mockResolvedValue([ + { + eventType: 'MmapEvent', + subType: '', + }, + ]); + let tab = new TabPaneNMSampleList(); + tabPaneNMemory.startWorker = jest.fn(() => true); + expect(tabPaneNMemory.initFilterTypes()).toBeUndefined(); + }); + + it('TabPaneNMemoryTest08', function () { + expect(tabPaneNMemory.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+
+ + +
+
+ " +`); + }); + + it('TabPaneNMemoryTest09', function () { + tabPaneNMemory.tblData = jest.fn(() => undefined); + tabPaneNMemory.tblData.recycleDataSource = jest.fn(() => true); + tabPaneNMemory.startWorker = jest.fn(() => true); + expect(tabPaneNMemory.setRightTableData(hook)).toBeUndefined(); + }); + it('TabPaneNMemoryTest010', function () { + let column = 'index'; + let sort = 0; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + it('TabPaneNMemoryTest011', function () { + let column = 'index'; + let sort = 1; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + it('TabPaneNMemoryTest012', function () { + let column = 'addr'; + let sort = 1; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + it('TabPaneNMemoryTest013', function () { + let column = 'timestamp'; + let sort = 1; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + it('TabPaneNMemoryTest014', function () { + let column = 'heapSizeUnit'; + let sort = 1; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + it('TabPaneNMemoryTest015', function () { + let column = 'library'; + let sort = 1; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + it('TabPaneNMemoryTest016', function () { + let column = 'symbol'; + let sort = 1; + expect(tabPaneNMemory.sortByColumn(column, sort)).toBeUndefined(); + }); + + it('TabPaneNMemoryTest017', function () { + let a = { + recordStartNs: 1502031374794922000, + rightNs: 1, + leftNs: 0, + nativeMemory: ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'], + }; + let queryNativeHookSnapshotTypes = sqlit.queryNativeHookSnapshotTypes; + queryNativeHookSnapshotTypes.mockResolvedValue( + { event_type: 11, data: 111 }, + { + event_type: 222, + data: 142446, + } + ); + let queryNativeHookEventTid = sqlit.queryNativeHookEventTid; + queryNativeHookEventTid.mockResolvedValue( + { callchain_id: 1, event_type: '2', heap_size: 66 }, + { + callchain_id: 2, + event_type: '5', + heap_size: 666, + } + ); + TabPaneNMSampleList.serSelection = jest.fn().mockResolvedValue({}); + tabPaneNMemory.data = a; + expect(tabPaneNMemory).toBeTruthy(); + }); + + it('TabPaneNMemoryTest018', function () { + expect(tabPaneNMemory.fromStastics(val)).toBeUndefined(); + }); + it('TabPaneNMemoryTest19', function () { + expect(tabPaneNMemory.startWorker({},{})).toBeTruthy(); + }); + it('TabPaneNMemoryTest20', function () { + expect(tabPaneNMemory.startWorker({},{})).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/process/TabPaneCounter.test.ts b/ide/test/trace/component/trace/sheet/process/TabPaneCounter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0791560a26ae53f850df02f49797c4c51237cc34 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/process/TabPaneCounter.test.ts @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneCounter } from '../../../../../../dist/trace/component/trace/sheet/process/TabPaneCounter.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); +describe('TabPaneCounter Test', () => { + let tabPaneCounter = new TabPaneCounter(); + it('TabPaneCounterTest01', function () { + expect( + tabPaneCounter.groupByTrackIdToMap([ + { + id: 0, + trackId: 0, + name: '', + value: 0, + startTime: 0, + }, + ]) + ); + }); + + it('TabPaneCounterTest02', function () { + expect( + tabPaneCounter.createSelectCounterData( + [ + { + id: 0, + trackId: 0, + name: '', + value: 0, + startTime: 0, + }, + ], + 0, + 1 + ) + ); + }); + + it('TabPaneCounterTest03', function () { + expect( + tabPaneCounter.sortByColumn({ + key: 'name', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneCounterTest06', function () { + expect( + tabPaneCounter.sortByColumn({ + key: 'number', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneCounterTest04', function () { + let mockgetTabCounters = sqlit.getTabCounters; + mockgetTabCounters.mockResolvedValue( + { trackId: 11, name: 'test', value: 111, startTime: 142445 }, + { trackId: 11, name: 'test', value: 222, startTime: 142446 } + ); + let a = { rightNs: 1, trackIds: [11, 12, 13] }; + expect((tabPaneCounter.data = a)).toBeTruthy(); + }); + + it('TabPaneCounterTest05', function () { + let mockgetTabCounters = sqlit.getTabCounters; + mockgetTabCounters.mockResolvedValue([]); + let a = { rightNs: 1, trackIds: [11, 12, 13] }; + expect((tabPaneCounter.data = a)).toBeTruthy(); + }); + + it('TabPaneCounterTest06', function () { + expect(tabPaneCounter.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/process/TabPaneSlices.test.ts b/ide/test/trace/component/trace/sheet/process/TabPaneSlices.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..abbb8c042a596932136cb15ce79231a797a9d62f --- /dev/null +++ b/ide/test/trace/component/trace/sheet/process/TabPaneSlices.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSlices } from '../../../../../../dist/trace/component/trace/sheet/process/TabPaneSlices.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneSlices Test', () => { + let tabPaneSlices = new TabPaneSlices(); + + it('TabPaneSlicesTest01', function () { + expect( + tabPaneSlices.sortByColumn({ + key: 'name', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneSlicesTest05', function () { + expect( + tabPaneSlices.sortByColumn({ + key: !'name', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneSlicesTest04', function () { + expect(tabPaneSlices.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/process/TabPaneThreadStates.test.ts b/ide/test/trace/component/trace/sheet/process/TabPaneThreadStates.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e15b483bd6c61e107aca1f718e8ed37a3dde3110 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/process/TabPaneThreadStates.test.ts @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneThreadStates } from '../../../../../../dist/trace/component/trace/sheet/process/TabPaneThreadStates.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); +describe('TabPaneThreadStates Test', () => { + let tabPaneThreadStates = new TabPaneThreadStates(); + + it('TabPaneThreadStatesTest01', function () { + expect( + tabPaneThreadStates.sortByColumn({ + key: 'name' || 'thread' || 'state', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneThreadStatesTest05', function () { + expect( + tabPaneThreadStates.sortByColumn({ + key: !'name' || !'thread' || !'state', + sort: () => {}, + }) + ).toBeUndefined(); + }); + + it('TabPaneThreadStatesTest02', function () { + // @ts-ignore + let mockgetTabThreadStates = sqlit.getTabThreadStates; + mockgetTabThreadStates.mockResolvedValue([ + { + process: '11', + thread: '222', + wallDuration: 10, + occurrences: 10, + state: 'sss', + stateJX: 'mm', + }, + { + process: '11', + thread: '222', + wallDuration: 10, + occurrences: 10, + state: 'sss', + stateJX: 'mm', + }, + ]); + let a = { rightNs: 1, leftNs: 0, threadIds: [11, 12, 13] }; + expect((tabPaneThreadStates.data = a)).toBeTruthy(); + }); + + it('TabPaneThreadStatesTest03', function () { + // @ts-ignore + let mockgetTabThreadStates = sqlit.getTabThreadStates; + mockgetTabThreadStates.mockResolvedValue([]); + let a = { rightNs: 1, leftNs: 0, threadIds: [11, 12, 13] }; + expect((tabPaneThreadStates.data = a)).toBeTruthy(); + }); + + it('TabPaneThreadStatesTest04', function () { + expect(tabPaneThreadStates.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ + + + + + + + + + + + + + + + + + + " +`); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/sdk/TabPaneSdkCounter.test.ts b/ide/test/trace/component/trace/sheet/sdk/TabPaneSdkCounter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..846398d023e13dbc0d5664dd758c9c54d7b5f351 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/sdk/TabPaneSdkCounter.test.ts @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSdkCounter } from '../../../../../../dist/trace/component/trace/sheet/sdk/TabPaneSdkCounter.js'; +// @ts-ignore +import '../../../../../../dist/trace/component/trace/sheet/sdk/TabPaneSdkCounter.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; + +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlite = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPaneSdkCounter Test', () => { + document.body.innerHTML = ``; + let litTable = document.querySelector('#tb-counter') as LitTable; + it('TabPaneSdkCounterTest00', () => { + let tabPaneSdkCounter = new TabPaneSdkCounter(); + tabPaneSdkCounter.tbl = jest.fn(() => litTable); + let a = new Map(); + let jsonCofigStr = + '{"settingConfig":{"configuration":{"counters":{"enum":["ARM_Mali-TTRx_JS1_ACTIVE","ARM_Mali-TTRx_JS0_ACTIVE","ARM_Mali-TTRx_GPU_ACTIVE","ARM_Mali-TTRx_FRAG_ACTIVE"],\n' + + ' "type":"string"},"stop_gator":{"default":"true","description":"stop_gator","type":"boolean"},"version":{"default":"1","description":"gatordversion","type":"number"}},"name":"mailG77"},\n' + + ' "tableConfig":{"showType":[{"columns":[{"column":"ts","displayName":"TimeStamp","showType":[1,3],"type":"INTEGER"},{"column":"counter_id","displayName":"MonitorValue","showType":[1,3],"type":"INTEGER"},\n' + + ' {"column":"value","displayName":"Value","showType":[1,3],"type":"INTEGER"}],"inner":{"columns":[{"column":"counter_name","displayName":"","showType":[0],"type":"STRING"},\n' + + ' {"column":"counter_id","displayName":"","showType":[0],"type":"INTEGER"}],"tableName":"mock_plugin_counterobj_table"},"tableName":"mock_plugin_counter_table"},\n' + + ' {"columns":[{"column":"start_ts","displayName":"startts","showType":[2,3],"type":"INTEGER"},{"column":"end_ts","displayName":"endts","showType":[2,3],"type":"INTEGER"},\n' + + ' {"column":"slice_id","displayName":"slice_id","showType":[2,3],"type":"INTEGER"},{"column":"value","displayName":"Value","showType":[2,3],"type":"INTEGER"}],\n' + + ' "inner":{"columns":[{"column":"slice_name","displayName":"","showType":[0],"type":"STRING"},{"column":"slice_id","displayName":"","showType":[0],"type":"INTEGER"}],\n' + + ' "tableName":"mock_plugin_sliceobj_table"},"tableName":"mock_plugin_slice_table"}]}}'; + let datamap = { + jsonConfig: jsonCofigStr, + disPlayName: 'common_mock', + pluginName: 'mock-plugin', + }; + a.set(1, datamap); + SpSystemTrace.SDK_CONFIG_MAP = a; + let startTime = sqlite.queryStartTime; + let dataTime: Array = [ + { + start_ts: 1000, + }, + ]; + startTime.mockResolvedValue(dataTime); + + let tabSdkCounterLeftData = sqlite.getTabSdkCounterLeftData; + let data = [ + { + max_value: 1000, + }, + { + max_value: 2000, + }, + { + max_value: 3000, + }, + ]; + tabSdkCounterLeftData.mockResolvedValue(data); + + let tabSdkCounterData = sqlite.getTabSdkCounterData; + let counter = [ + { + ts: 1000, + counter_id: 0, + value: 100, + }, + { + ts: 2000, + counter_id: 0, + value: 100, + }, + { + ts: 3000, + counter_id: 0, + value: 100, + }, + { + ts: 4000, + counter_id: 0, + value: 100, + }, + { + ts: 5000, + counter_id: 0, + value: 100, + }, + ]; + tabSdkCounterData.mockResolvedValue(counter); + + let d = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: [], + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + sdkCounterIds: ['a-1', 'b-1', 'd-1'], + }; + tabPaneSdkCounter.tbl.recycleDataSource = jest.fn(() => d); + tabPaneSdkCounter.tbl.appendChild = jest.fn(() => true); + tabPaneSdkCounter.data = d; + expect(tabPaneSdkCounter.data).toBeUndefined(); + }); + + it('TabPaneSdkCounterTest01', () => { + let tabPaneSdkCounter = new TabPaneSdkCounter(); + expect(tabPaneSdkCounter.parseJson(new Map())).toBe(''); + }); + + it('TabPaneSdkCounterTest02', () => { + let tabPaneSdkCounter = new TabPaneSdkCounter(); + let type = { + columns: [{ showType: 'counter' }], + }; + expect(tabPaneSdkCounter.getTableType(type)).toBe(''); + }); + + it('TabPaneSdkCounterTest03', () => { + let tabPaneSdkCounter = new TabPaneSdkCounter(); + expect(tabPaneSdkCounter.initDataElement()).toBeUndefined(); + }); + + it('TabPaneSdkCounterTest05', () => { + let tabPaneSdkCounter = new TabPaneSdkCounter(); + expect(tabPaneSdkCounter.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ + + " +`); + }); + + it('TabPaneSdkCounterTest04', function () { + let tabPaneSdkCounter = new TabPaneSdkCounter(); + tabPaneSdkCounter.tbl = jest.fn(() => true); + tabPaneSdkCounter.tbl!.recycleDataSource = jest.fn(() => true); + expect( + tabPaneSdkCounter.sortByColumn({ + key: '', + sort: '', + }) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/sdk/TabPaneSdkSlice.test.ts b/ide/test/trace/component/trace/sheet/sdk/TabPaneSdkSlice.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..af3e489733e9fecc4f95f349e3cbbb78c9d061ca --- /dev/null +++ b/ide/test/trace/component/trace/sheet/sdk/TabPaneSdkSlice.test.ts @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSdkSlice } from '../../../../../../dist/trace/component/trace/sheet/sdk/TabPaneSdkSlice.js'; +// @ts-ignore +import { LitTable } from '../../../../../../dist/base-ui/table/lit-table.js'; +// @ts-ignore +import { SpSystemTrace } from '../../../../../../dist/trace/component/SpSystemTrace.js'; + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +const sqlite = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +describe('TabPaneSdkSlice Test', () => { + let tabPaneSdkSlice = new TabPaneSdkSlice(); + document.body.innerHTML = ``; + let litTable = document.querySelector('#tb-counter') as LitTable; + it('TabPaneSdkSliceTest00', () => { + let mockStartTime = sqlite.queryStartTime; + let startTime: Array = [ + { + start_ts: 1000, + }, + ]; + mockStartTime.mockResolvedValue(startTime); + let totalTime = sqlite.queryTotalTime; + let totalData: Array = [ + { + recordStartNS: 1000, + recordEndNS: 3000, + total: 2000, + }, + ]; + totalTime.mockResolvedValue(totalData); + let mockSdkSliceData = sqlite.getTabSdkSliceData; + let sliceData = [ + { + start_ts: 1000, + end_ts: 1500, + type: 0, + value: 100, + }, + { + start_ts: 2000, + end_ts: 2500, + type: 0, + value: 100, + }, + { + start_ts: 3000, + end_ts: 3500, + type: 0, + value: 100, + }, + { + start_ts: 4000, + end_ts: 4500, + type: 0, + value: 100, + }, + { + start_ts: 5000, + end_ts: 5500, + type: 0, + value: 100, + }, + ]; + mockSdkSliceData.mockResolvedValue(sliceData); + let slice = new TabPaneSdkSlice(); + slice.tbl = jest.fn(() => litTable); + slice.tbl.appendChild = jest.fn(() => true); + let map = new Map(); + let jsonCofigStr = + '{"settingConfig":{"configuration":{"counters":{"enum":["ARM_Mali-TTRx_JS1_ACTIVE","ARM_Mali-TTRx_JS0_ACTIVE","ARM_Mali-TTRx_GPU_ACTIVE","ARM_Mali-TTRx_FRAG_ACTIVE"],\n' + + ' "type":"string"},"stop_gator":{"default":"true","description":"stop_gator","type":"boolean"},"version":{"default":"1","description":"gatordversion","type":"number"}},"name":"mailG77"},\n' + + ' "tableConfig":{"showType":[{"columns":[{"column":"ts","displayName":"TimeStamp","showType":[1,3],"type":"INTEGER"},{"column":"counter_id","displayName":"MonitorValue","showType":[1,3],"type":"INTEGER"},\n' + + ' {"column":"value","displayName":"Value","showType":[1,3],"type":"INTEGER"}],"inner":{"columns":[{"column":"counter_name","displayName":"","showType":[0],"type":"STRING"},\n' + + ' {"column":"counter_id","displayName":"","showType":[0],"type":"INTEGER"}],"tableName":"mock_plugin_counterobj_table"},"tableName":"mock_plugin_counter_table"},\n' + + ' {"columns":[{"column":"start_ts","displayName":"startts","showType":[2,3],"type":"INTEGER"},{"column":"end_ts","displayName":"endts","showType":[2,3],"type":"INTEGER"},\n' + + ' {"column":"slice_id","displayName":"slice_id","showType":[2,3],"type":"INTEGER"},{"column":"value","displayName":"Value","showType":[2,3],"type":"INTEGER"}],\n' + + ' "inner":{"columns":[{"column":"slice_name","displayName":"","showType":[0],"type":"STRING"},{"column":"slice_id","displayName":"","showType":[0],"type":"INTEGER"}],\n' + + ' "tableName":"mock_plugin_sliceobj_table"},"tableName":"mock_plugin_slice_table"}]}}'; + let datamap = { + jsonConfig: jsonCofigStr, + disPlayName: 'common_mock', + pluginName: 'mock-plugin', + }; + map.set('1', datamap); + SpSystemTrace.SDK_CONFIG_MAP = map; + let data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: [], + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + sdkSliceIds: ['a-b', 'b-c', 'd-e'], + }; + slice.tbl.recycleDataSource = jest.fn(() => data); + slice.data = data; + expect(slice.data).toBeUndefined(); + }); + + it('TabPaneSdkSliceTest01', () => { + expect(tabPaneSdkSlice.parseJson([])).toBe(''); + }); + + it('TabPaneSdkSliceTest02', () => { + let type = { + columns: [{ showType: 'slice' }], + }; + expect(tabPaneSdkSlice.getTableType(type)).toBe(''); + }); + + it('TabPaneSdkSliceTest03', () => { + expect(tabPaneSdkSlice.initDataElement()).toBeUndefined(); + }); + + it('TabPaneSdkSliceTest04', function () { + tabPaneSdkSlice.tbl = jest.fn(() => true); + tabPaneSdkSlice.tbl!.recycleDataSource = jest.fn(() => true); + expect( + tabPaneSdkSlice.sortByColumn({ + key: '', + sort: '', + }) + ).toBeUndefined(); + }); + + it('TabPaneSdkSliceTest05', () => { + expect(tabPaneSdkSlice.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ + + " +`); + }); + it('TabPaneSdkSliceTest06', () => { + expect(tabPaneSdkSlice.isDateIntersection(5,5,1,6)).toBeTruthy(); + }); + it('TabPaneSdkSliceTest07', () => { + expect(tabPaneSdkSlice.isDateIntersection(5,5,1,6)).toBeTruthy(); + }); + it('TabPaneSdkSliceTest08', () => { + expect(tabPaneSdkSlice.isDateIntersection(1,5,5,3)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.test.ts b/ide/test/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b9bb4cc044b680629c269bc7c576fd9f206ddf2e --- /dev/null +++ b/ide/test/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.test.ts @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSmapsRecord } from '../../../../../../dist/trace/component/trace/sheet/smaps/TabPaneSmapsRecord.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); +describe('TabPaneSmapsRecord Test', () => { + let MockgetTabSmapsData = sqlit.getTabSmapsData; + MockgetTabSmapsData.mockResolvedValue([ + { + tsNS: 0, + start_addr: 'start_addr', + end_addr: 'end_addr', + dirty: 0, + swapper: 0, + rss: 0, + pss: 0, + size: 1, + reside: 1, + permission: 'rw-', + path: 'path', + }, + ]); + + let tabPaneSmapsRecord = new TabPaneSmapsRecord(); + tabPaneSmapsRecord.data = { + leftNs: 0, + rightNs: 500, + smapsType: [0, 1, 2], + }; + + it('tabPaneSmapsRecord01', function () { + tabPaneSmapsRecord.tbl = jest.fn(() => true); + tabPaneSmapsRecord.tbl!.recycleDataSource = jest.fn(() => true); + expect( + tabPaneSmapsRecord.sortByColumn({ + key: '', + sort: '', + }) + ).toBeUndefined(); + }); + + it('tabPaneSmapsRecord02', () => { + expect(tabPaneSmapsRecord.initElements()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.test.ts b/ide/test/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9bc0e5c3706a487198f00fde8704c37c914242a --- /dev/null +++ b/ide/test/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.test.ts @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { TabPaneSmapsStatistics } from '../../../../../../dist/trace/component/trace/sheet/smaps/TabPaneSmapsStatistics.js'; +// @ts-ignore +import { Smaps, SmapsTreeObj } from '../../../../../../dist/trace/bean/SmapsStruct.js'; + +const sqlit = require('../../../../../../dist/trace/database/SqlLite.js'); +jest.mock('../../../../../../dist/trace/database/SqlLite.js'); + +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneSmapsStatistics Test', () => { + let MockgetTabSmapsMaxRss = sqlit.getTabSmapsMaxRss; + MockgetTabSmapsMaxRss.mockResolvedValue([ + { + startNS: 0, + max_value: 100, + }, + ]); + let smaps = new Smaps(); + smaps.tsNS = -1; + smaps.start_addr = 'aaaaa'; + smaps.end_addr = 'bbbbb'; + smaps.permission = 'dddd'; + smaps.path = '/asdasdas'; + smaps.size = 0; + smaps.rss = 0; + smaps.pss = 0; + smaps.reside = 0; + smaps.dirty = 0; + smaps.swapper = 0; + smaps.address = 'aaaaa-bbbbb'; + smaps.type = 'Dta'; + smaps.dirtyStr = '1212'; + smaps.swapperStr = '222'; + smaps.rssStr = '333'; + smaps.pssStr = '444'; + smaps.sizeStr = '555'; + smaps.resideStr = '666'; + smaps.pss = 2; + let MockgetTabSmapsData = sqlit.getTabSmapsData; + MockgetTabSmapsData.mockResolvedValue([smaps]); + + let tabPaneSmapsStatistics = new TabPaneSmapsStatistics(); + let dataTree: SmapsTreeObj = new SmapsTreeObj('DATA', '', 'DATA'); + + it('TabPaneSmapsStatisticsTest01', () => { + tabPaneSmapsStatistics.handleSmapsTreeObj(dataTree, 2); + expect(dataTree.rsspro).toBe(0); + }); + + it('TabPaneSmapsStatisticsTest02', () => { + tabPaneSmapsStatistics.handleAllDataTree(new Smaps(), 0, 'All', dataTree, 3); + expect(dataTree.children.length).toBe(1); + }); + + it('TabPaneSmapsStatisticsTest03', () => { + tabPaneSmapsStatistics.handleTree(smaps, 0, 'TEXT', dataTree, 4); + expect(dataTree.pss).toBe(2); + }); + + it('TabPaneSmapsStatisticsTest04', () => { + let select = { + leftNs: 0, + rightNs: 500, + smapsType: [0, 1, 2], + }; + tabPaneSmapsStatistics.data = select; + expect((tabPaneSmapsStatistics.data = select)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/snapshot/TabPaneComparison.test.ts b/ide/test/trace/component/trace/sheet/snapshot/TabPaneComparison.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e076ed8867096db3ce7d14b72b9357f4a6929ea5 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/snapshot/TabPaneComparison.test.ts @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneComparison } from '../../../../../../dist/trace/component/trace/sheet/snapshot/TabPaneComparison.js'; +import '../../../../../../dist/trace/component/trace/sheet/snapshot/TabPaneComparison.js'; + +//@ts-ignore +import { HeapDataInterface } from '../../../../../../dist/js-heap/HeapDataInterface.js'; + +jest.mock('../../../../../../dist/base-ui/select/LitSelect.js', () => { + return {}; +}); +jest.mock('../../../../../../dist/base-ui/table/lit-table.js', () => { + return { + snapshotDataSource: () => {}, + removeAttribute: () => {}, + }; +}); + +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneComparison Test', () => { + let data = { + end_time: 5373364415, + file_name: 'Snapshot1', + frame: { height: 40, width: 24, x: 272, y: 0 }, + id: 1, + pid: 4243, + start_time: 4937360912, + textMetricsWidth: 60.697265625, + }; + let dataList = [ + { + id: 0, + file_name: 'Snapshot0', + start_time: 0, + end_time: 435811002, + pid: 4243, + textMetricsWidth: 50.5810546875, + }, + ]; + + let childenData = [ + { + addedCount: 649, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: 'edgeName', + fileId: 0, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + { + addedCount: 649, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 1, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + ]; + let ddd = [ + { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: 'edgeName', + fileId: 0, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 1, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 2, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 2, + }, + ]; + let rowObjectData = { + top: 0, + height: 0, + rowIndex: 0, + data: { + status: true, + targetFileId: 12, + children: childenData, + getChildren: () => {}, + }, + expanded: true, + rowHidden: false, + children: childenData, + depth: -1, + }; + let iconClick = new CustomEvent('icon-click', { + detail: { + ...rowObjectData.data, + data: rowObjectData.data, + }, + composed: true, + }); + let iconRowClick = new CustomEvent('row-click', { + detail: { + ...rowObjectData.data, + data: ddd[0], + }, + composed: true, + }); + let iconColumnClickData = new CustomEvent('column-click', { + detail: { + key: 'addedCount', + sort: 1, + }, + composed: true, + }); + let iconColumnClick = new CustomEvent('column-click', { + detail: { + key: 'addedCount', + sort: 1, + }, + composed: true, + }); + let iconkeyUpClick = new CustomEvent('keyup', { + detail: { + key: 'addedCount', + sort: 1, + }, + composed: true, + }); + document.body.innerHTML = ` + `; + let tabPaneComparisons = document.getElementById('sss') as TabPaneComparison; + + HeapDataInterface.getInstance().getClassListForComparison = jest.fn(() => []); + HeapDataInterface.getInstance().getNextForComparison = jest.fn(() => ddd); + let htmlInputElement = document.createElement('input'); + htmlInputElement.value = 'input'; + tabPaneComparisons.search = jest.fn(() => htmlInputElement); + let heapDataInterface = new HeapDataInterface(); + heapDataInterface.fileStructs = [data]; + let htmlDivElement = document.createElement('div'); + tabPaneComparisons.leftTheadTable = jest.fn(() => htmlDivElement); + tabPaneComparisons.rightTheadTable = jest.fn(() => htmlDivElement); + tabPaneComparisons.rightTheadTable.removeAttribute = jest.fn(() => true); + tabPaneComparisons.rightTheadTable.hasAttribute = jest.fn(() => {}); + tabPaneComparisons.leftTheadTable = jest.fn(() => htmlDivElement); + tabPaneComparisons.leftTheadTable.hasAttribute = jest.fn(() => {}); + tabPaneComparisons.leftTheadTable.removeAttribute = jest.fn(() => true); + + it('TabPaneComparisonTest01', () => { + tabPaneComparisons.comparisonsData = jest.fn(() => ddd); + tabPaneComparisons.initComparison(data, dataList); + + let retainsData = [ + { + shallowSize: 10, + retainedSize: 10, + shallowPercent: 10, + retainedPercent: 10, + distance: 1000000001, + nodeName: 'nodeName', + objectName: 'objectName', + edgeName: 'edgeName', + children: childenData, + }, + { + shallowSize: 1, + retainedSize: 1, + shallowPercent: 1, + retainedPercent: 1, + distance: 100000000, + nodeName: 'nodeName', + objectName: 'objectName', + edgeName: 'edgeName', + children: childenData, + }, + ]; + HeapDataInterface.getInstance().getRetains = jest.fn(() => retainsData); + + tabPaneComparisons.comparisonTableEl!.dispatchEvent(iconClick); + tabPaneComparisons.comparisonTableEl!.dispatchEvent(iconRowClick); + tabPaneComparisons.comparisonTableEl!.dispatchEvent(iconColumnClickData); + tabPaneComparisons.retainerTableEl!.dispatchEvent(iconColumnClick); + + tabPaneComparisons.sortComprisonByColumn('addedCount', 0); + tabPaneComparisons.sortComprisonByColumn('removedCount', 1); + tabPaneComparisons.sortComprisonByColumn('addedCount', 1); + tabPaneComparisons.sortComprisonByColumn('deltaCount', 1); + tabPaneComparisons.sortComprisonByColumn('objectName', 1); + tabPaneComparisons.sortComprisonByColumn('addedSize', 1); + tabPaneComparisons.sortComprisonByColumn('removedSize', 1); + tabPaneComparisons.sortComprisonByColumn('deltaSize', 1); + + tabPaneComparisons.sortRetainerByColumn('distance', 0); + tabPaneComparisons.sortRetainerByColumn('shallowSize', 1); + tabPaneComparisons.sortRetainerByColumn('retainedSize', 1); + tabPaneComparisons.sortRetainerByColumn('objectName', 1); + expect(tabPaneComparisons.comparisonTableEl!.snapshotDataSource).toEqual([]); + }); + + it('TabPaneComparisonTest2', () => { + tabPaneComparisons.retainsData = [ + { + distance: 1, + }, + ]; + tabPaneComparisons.retainerTableEl!.dispatchEvent(iconClick); + expect(tabPaneComparisons.retainsData).not.toBe([]); + }); + + it('TabPaneComparisonTest12', () => { + let tabPaneComparison = new TabPaneComparison(); + let data = [ + { + end_time: 5373364415, + file_name: 'Snapshot1', + frame: { height: 40, width: 24, x: 272, y: 0 }, + id: 1, + pid: 4243, + start_time: 4937360912, + textMetricsWidth: 60.697265625, + }, + ]; + expect(tabPaneComparison.initSelect(0, data)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/sheet/snapshot/TabPaneSummary.test.ts b/ide/test/trace/component/trace/sheet/snapshot/TabPaneSummary.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b6799f77d853da595d6b57193fb86d994a78399 --- /dev/null +++ b/ide/test/trace/component/trace/sheet/snapshot/TabPaneSummary.test.ts @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2022 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. + */ +//@ts-ignore +import { TabPaneSummary } from '../../../../../../dist/trace/component/trace/sheet/snapshot/TabPaneSummary.js'; +//@ts-ignore +import { HeapDataInterface } from '../../../../../../dist/js-heap/HeapDataInterface.js'; +//@ts-ignore +import { SpJsMemoryChart } from '../../../../../../dist/trace/component/chart/SpJsMemoryChart.js'; + +jest.mock('../../../../../../dist/base-ui/select/LitSelect.js', () => { + return {}; +}); +// @ts-ignore +window.ResizeObserver = + window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneSummary Test', () => { + let tabPaneSummary = new TabPaneSummary(); + it('TabPaneSummaryTest01', () => { + document.body.innerHTML = ` `; + let tabPaneSummary = document.querySelector('#sss') as TabPaneSummary; + tabPaneSummary.tbsTable = jest.fn(() => { + return { + scrollTop: 0, + }; + }); + let childenData = [ + { + addedCount: 649, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: 'edgeName', + fileId: 0, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + { + addedCount: 649, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 1, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + ]; + let retainsData = [ + { + shallowSize: 10, + retainedSize: 10, + shallowPercent: 10, + retainedPercent: 10, + distance: 1000000001, + nodeName: 'nodeName', + objectName: 'objectName', + edgeName: 'edgeName', + children: childenData, + }, + { + shallowSize: 1, + retainedSize: 1, + shallowPercent: 1, + retainedPercent: 1, + distance: 100000000, + nodeName: 'nodeName', + objectName: 'objectName', + edgeName: 'edgeName', + children: childenData, + }, + ]; + let ddd = [ + { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: 'edgeName', + fileId: 0, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 1, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 4, + }, + { + addedCount: 648, + addedIndx: [319, 326], + addedSize: 38936, + childCount: 1296, + children: [], + classChildren: [], + deletedIdx: [325, 338], + deltaCount: 0, + deltaSize: -16, + distance: -1, + edgeCount: 0, + edgeName: '', + fileId: 2, + hasNext: true, + id: -1, + index: 0, + isAdd: false, + isHover: false, + isSelected: false, + nextId: [], + nodeName: 'nodeName', + objectName: 'objectName', + removedCount: 648, + removedSize: 38952, + retainedSize: -1, + retains: [], + shallowSize: -1, + showBox: false, + showCut: false, + status: true, + targetFileId: 1, + traceNodeId: -1, + type: 2, + }, + ]; + let htmlDivElement = document.createElement('div'); + tabPaneSummary.leftTheadTable = jest.fn(() => htmlDivElement); + tabPaneSummary.rightTheadTable = jest.fn(() => htmlDivElement); + tabPaneSummary.tbsTable = jest.fn(() => { + return { + scrollTop: 0, + }; + }); + + tabPaneSummary.rightTheadTable.removeAttribute = jest.fn(() => true); + tabPaneSummary.rightTheadTable.hasAttribute = jest.fn(() => {}); + + tabPaneSummary.leftTheadTable.hasAttribute = jest.fn(() => {}); + tabPaneSummary.leftTheadTable.removeAttribute = jest.fn(() => true); + + SpJsMemoryChart.file = { + file_name: 'Timeline', + id: '', + }; + HeapDataInterface.getInstance().getAllocationStackData = jest.fn(() => { + return [ + { + id: 0, + index: 0, + name: '', + scriptName: '', + scriptId: 0, + line: 0, + column: 0, + }, + { + id: 0, + index: 0, + name: '', + scriptName: 'string', + scriptId: 0, + line: 0, + column: 0, + }, + ]; + }); + + let htmlDivElement1 = document.createElement('div'); + htmlDivElement1.className = 'table'; + tabPaneSummary.tbs.meauseTreeRowElement = jest.fn(() => { + return []; + }); + tabPaneSummary.tbl.meauseTreeRowElement = jest.fn(() => { + return []; + }); + let rowObjectData = { + top: 0, + height: 0, + rowIndex: 0, + data: { + status: true, + targetFileId: 12, + children: childenData, + getChildren: () => {}, + }, + expanded: true, + rowHidden: false, + children: childenData, + depth: -1, + }; + HeapDataInterface.getInstance().getRetains = jest.fn(() => retainsData); + let iconRowClick = new CustomEvent('row-click', { + detail: { + data: rowObjectData.data, + }, + composed: true, + }); + + let iconClick = new CustomEvent('icon-click', { + detail: { + data: rowObjectData.data, + }, + composed: true, + }); + tabPaneSummary.tbl.dispatchEvent(iconRowClick); + tabPaneSummary.tbl.dispatchEvent(iconClick); + tabPaneSummary.tbs.dispatchEvent(iconClick); + tabPaneSummary.sortByLeftTable('distance', 0); + tabPaneSummary.sortByLeftTable('shallowSize', 1); + tabPaneSummary.sortByLeftTable('retainedSize', 1); + tabPaneSummary.sortByLeftTable('objectName', 1); + HeapDataInterface.getInstance().getClassesListForSummary = jest.fn(() => { + return retainsData; + }); + + expect(tabPaneSummary.initSummaryData(1, 0, 0)).toBeUndefined(); + }); + it('TabPaneSummaryTest12', () => { + document.body.innerHTML = ` `; + let tabPaneSummary = document.querySelector('#sss') as TabPaneSummary; + expect(tabPaneSummary.sortByLeftTable('shallowSize', 1)).toBeUndefined(); + }); + it('TabPaneSummaryTest03', () => { + document.body.innerHTML = ` `; + let tabPaneSummary = document.querySelector('#sss') as TabPaneSummary; + expect(tabPaneSummary.sortByLeftTable('retainedSize', 1)).toBeUndefined(); + }); + it('TabPaneSummaryTest04', () => { + document.body.innerHTML = ` `; + let tabPaneSummary = document.querySelector('#sss') as TabPaneSummary; + expect(tabPaneSummary.sortByLeftTable('objectName', 1)).toBeUndefined(); + }); + it('TabPaneSummaryTest09', () => { + expect(tabPaneSummary.clickToggleTable()).toBeUndefined(); + }); + it('TabPaneSummaryTest10', () => { + expect(tabPaneSummary.classFilter()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/Flag.test.ts b/ide/test/trace/component/trace/timer-shaft/Flag.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9be74dc94bf0ad7612ebb104fa82e34f784dbff5 --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/Flag.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { Flag } from '../../../../../dist/trace/component/trace/timer-shaft/Flag.js'; + +describe('Flag Test', () => { + it('FlagTest01 ', function () { + let flag = new Flag(); + expect(flag).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/Graph.test.ts b/ide/test/trace/component/trace/timer-shaft/Graph.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c71f64f1bb6dbdbf46e8e2fd56870280d5246f12 --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/Graph.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { Graph } from '../../../../../dist/trace/component/trace/timer-shaft/Graph.js'; + +describe('Flag Test', () => { + it('FlagTest01 ', function () { + let graph = new Graph(); + expect(graph).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts b/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..da0f4a56e59009d7f4cfa3ff971d0758abf5b60e --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { RangeRuler } from '../../../../../dist/trace/component/trace/timer-shaft/RangeRuler.js'; +// @ts-ignore +import { Mark } from '../../../../../dist/trace/component/trace/timer-shaft/RangeRuler.js'; +import { TimerShaftElement } from '../../../../../src/trace/component/trace/TimerShaftElement'; + +describe('RangeRuler Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + document.body.innerHTML = ''; + + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + + let rangeRuler = new RangeRuler( + timerShaftElement, + { + x: 20, + y: 20, + width: 100, + height: 100, + }, + { + startX: 10, + endX: 30, + }, + () => {} + ); + let mark = new Mark(canvas, ctx, '', { + x: 20, + y: 20, + width: 100, + height: 100, + }); + + rangeRuler.cpuUsage = [ + { + cpu: 1, + ro: 2, + rate: 2, + }, + ]; + + mark.isHover = true; + + it('RangeRulerTest01', function () { + expect(rangeRuler.drawCpuUsage()).toBeUndefined(); + }); + + it('RangeRulerTest02', function () { + expect(rangeRuler.fillX()).toBeUndefined(); + }); + + it('RangeRulerTest21', function () { + rangeRuler.range.startNS = -1; + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest22', function () { + rangeRuler.range.endNS = -1; + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest23', function () { + rangeRuler.range.endNS = -1; + rangeRuler.range.totalNS = -2; + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest24', function () { + rangeRuler.range.startNS = -1; + rangeRuler.range.totalNS = -2; + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest03', function () { + expect( + rangeRuler.keyPress({ + key: 'w', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest04', function () { + expect( + rangeRuler.keyPress({ + key: 's', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest05', function () { + expect( + rangeRuler.keyPress({ + key: 'a', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest06', function () { + expect( + rangeRuler.keyPress({ + key: 'd', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest07', function () { + expect( + rangeRuler.keyUp({ + key: 'w', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest08', function () { + expect( + rangeRuler.keyUp({ + key: 's', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest09', function () { + expect( + rangeRuler.keyUp({ + key: 'a', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest10', function () { + expect( + rangeRuler.keyUp({ + key: 'd', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest11', function () { + expect( + rangeRuler.mouseUp({ + key: '', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest12', function () { + expect( + rangeRuler.mouseOut({ + key: '', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest13', function () { + rangeRuler.markA = jest.fn(() => true); + rangeRuler.rangeRect = jest.fn(() => true); + rangeRuler.rangeRect.containsWithPadding = jest.fn(() => true); + + rangeRuler.markA = jest.fn(() => { + return { + frame: { + x: 20, + }, + }; + }); + rangeRuler.markA.isHover = jest.fn(() => true); + rangeRuler.markA.frame = jest.fn(() => []); + rangeRuler.markA.frame.x = jest.fn(() => true); + + expect( + rangeRuler.mouseDown({ + key: '', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest14', function () { + rangeRuler.markA = jest.fn(() => true); + rangeRuler.rangeRect = jest.fn(() => true); + rangeRuler.rangeRect.containsWithPadding = jest.fn(() => false); + rangeRuler.frame = jest.fn(() => false); + rangeRuler.frame.containsWithMargin = jest.fn(() => true); + rangeRuler.rangeRect.containsWithMargin = jest.fn(() => false); + rangeRuler.markB.isHover = jest.fn(() => true); + rangeRuler.markB.frame = jest.fn(() => true); + rangeRuler.markB.frame.x = jest.fn(() => true); + expect( + rangeRuler.mouseDown({ + key: '', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest15', function () { + rangeRuler.markA = jest.fn(() => true); + rangeRuler.markA.inspectionFrame = jest.fn(() => true); + rangeRuler.markA.inspectionFrame.contains = jest.fn(() => true); + rangeRuler.markA.frame = jest.fn(() => true); + rangeRuler.markA.frame.x = jest.fn(() => true); + rangeRuler.markA.draw = jest.fn(() => true); + rangeRuler.centerXPercentage = jest.fn(() => -1); + expect( + rangeRuler.mouseMove({ + key: '', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest16', () => { + rangeRuler.markA = jest.fn(() => false); + rangeRuler.markA.draw = jest.fn(() => true); + rangeRuler.markA.frame = jest.fn(() => true); + rangeRuler.markA.frame.x = jest.fn(() => true); + rangeRuler.markA.inspectionFrame = jest.fn(() => false); + rangeRuler.markA.inspectionFrame.contains = jest.fn(() => false); + rangeRuler.movingMark = jest.fn(() => false); + rangeRuler.movingMark.frame = jest.fn(() => false); + rangeRuler.movingMark.frame.x = jest.fn(() => false); + rangeRuler.rangeRect = jest.fn(() => true); + rangeRuler.rangeRect.containsWithPadding = jest.fn(() => true); + rangeRuler.movingMark.inspectionFrame = jest.fn(() => false); + rangeRuler.movingMark.inspectionFrame.x = jest.fn(() => false); + expect( + rangeRuler.mouseMove({ + key: '', + }) + ).toBeUndefined(); + }); + + it('RangeRulerTest17', () => { + rangeRuler.notifyHandler = jest.fn(() => true); + rangeRuler.movingMark.inspectionFrame.x = jest.fn(() => false); + rangeRuler.frame = jest.fn(() => true); + rangeRuler.frame.x = jest.fn(() => true); + rangeRuler.frame.y = jest.fn(() => true); + expect(rangeRuler.draw()).toBeUndefined(); + }); + + it('RangeRulerTest18', function () { + expect(mark.isHover).toBeTruthy(); + }); + it('RangeRulerTest19', function () { + rangeRuler.clearRect = jest.fn(() => true); + expect(rangeRuler.draw()).toBeUndefined(); + }); + + it('RangeRulerTest20', function () { + rangeRuler.setRangeNS(0, 2000); + expect(rangeRuler.getRange().startX).toBe(0); + }); + + it('RangeRulerTest25', function () { + expect(rangeRuler.delayDraw()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/Rect.test.ts b/ide/test/trace/component/trace/timer-shaft/Rect.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3b0f8c5e168bb3f355f6041c10a67cd6c2b0971 --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/Rect.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { Rect, Point } from '../../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe('Rect Test', () => { + let rect = new Rect(20, 20, 100, 100); + let point = new Point(); + + it('RectTest01', function () { + expect(rect.contains(4, 5)).toBeFalsy(); + }); + + it('RectTest02', function () { + expect(Rect.contains(rect, 4, 4)).toBeFalsy(); + }); + + it('RectTest03', function () { + expect(rect.containsWithPadding(4, 5, 2, 2)).toBeFalsy(); + }); + + it('RectTest04', function () { + expect(Rect.containsWithPadding(rect, 4, 4, 2, 2)).toBeFalsy(); + }); + + it('RectTest05', function () { + expect(rect.containsWithMargin(1, 2, 1, 2, 4, 5)).toBeFalsy(); + }); + + it('RectTest06', function () { + expect(Rect.containsWithMargin(1, 2, 1, 2, 4, 5)).toBeFalsy(); + }); + + it('RectTest07', function () { + expect(rect.intersect([])).toBeFalsy(); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts b/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c3fd10bb4e853a29119be3e7326c9321ff56891 --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { EventCenter } from '../../../../../dist/trace/component/trace/base/EventCenter.js'; + +jest.mock('../../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { SportRuler } from '../../../../../dist/trace/component/trace/timer-shaft/SportRuler.js'; +// @ts-ignore +import { TimerShaftElement } from '../../../../../dist/trace/component/trace/TimerShaftElement.js'; +// @ts-ignore +import { Flag } from '../../../../../dist/trace/component/trace/timer-shaft/Flag.js'; +// @ts-ignore +import { TraceRow, RangeSelectStruct } from '../../../../../dist/trace/component/trace/base/TraceRow.js'; + +declare global { + interface Window { + SmartEvent: { + UI: { + MenuTrace: string; //selected menu trace + RefreshCanvas: string; //selected menu trace + SliceMark: string; //Set the tag scope + TimeRange: string; //Set the timeline range + TraceRowComplete: string; //Triggered after the row component has finished loading data + }; + }; + + subscribe(evt: string, fn: (b: any) => void): void; + + subscribeOnce(evt: string, fn: (b: any) => void): void; + + unsubscribe(evt: string, fn: (b: any) => void): void; + + publish(evt: string, data: any): void; + + clearTraceRowComplete(): void; + } +} + +window.SmartEvent = { + UI: { + MenuTrace: 'SmartEvent-UI-MenuTrace', + RefreshCanvas: 'SmartEvent-UI-RefreshCanvas', + SliceMark: 'SmartEvent-UI-SliceMark', + TimeRange: 'SmartEvent-UI-TimeRange', + TraceRowComplete: 'SmartEvent-UI-TraceRowComplete', + }, +}; + +Window.prototype.subscribe = (ev, fn) => EventCenter.subscribe(ev, fn); +Window.prototype.unsubscribe = (ev, fn) => EventCenter.unsubscribe(ev, fn); +Window.prototype.publish = (ev, data) => EventCenter.publish(ev, data); +Window.prototype.subscribeOnce = (ev, data) => EventCenter.subscribeOnce(ev, data); +Window.prototype.clearTraceRowComplete = () => EventCenter.clearTraceRowComplete(); + +describe('SportRuler Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + document.body.innerHTML = ''; + + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + + let sportRuler = new SportRuler( + timerShaftElement, + { + x: 20, + y: 20, + width: 100, + height: 100, + }, + () => {}, + () => {} + ); + sportRuler.c = ctx; + sportRuler.range = { + totalNS: 20, + startX: 0, + endX: 10, + startNS: 10, + endNS: 20, + xs: [], + xsTxt: [], + }; + + it('SportRulerTest04', function () { + expect( + sportRuler.mouseMove({ + offsetY: 20, + offsetX: 20, + }) + ).toBeUndefined(); + }); + + it('SportRulerTest05', function () { + let ranges = sportRuler.range; + expect(ranges.endNS).toBe(20); + }); + + it('SportRulerTest07', function () { + sportRuler.flagList.splice = jest.fn(() => true); + expect(sportRuler.modifyFlagList('remove')).toBeUndefined(); + }); + + it('SportRulerTest08', function () { + let numbers = Array(); + numbers.push(12); + numbers.push(56); + sportRuler.flagList = [ + { + totalNS: 10000, + startX: 0, + endX: 1000, + startNS: 0, + endNS: 10000, + xs: numbers, + xsTxt: ['s', 'f'], + }, + ]; + sportRuler.flagList.xs = jest.fn(() => numbers); + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 20, + color: '', + selected: false, + text: '', + hidden: false, + type: '', + }); + sportRuler.flagList = flags; + expect(sportRuler.draw()).toBeUndefined(); + }); + + it('SportRulerTest09', function () { + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 20, + color: '', + selected: false, + text: '', + hidden: false, + type: '', + }); + sportRuler.flagList = flags; + sportRuler.edgeDetection = jest.fn(() => true); + + expect(sportRuler.mouseUp({ offsetX: 20 })).toBeUndefined(); + }); + + it('SportRulerTest10', function () { + sportRuler.draw = jest.fn(() => true); + expect( + sportRuler.mouseMove({ + offsetX: 10000, + offsetY: 10000, + }) + ).toBeUndefined(); + }); + + it('SportRulerTest11', function () { + let range = sportRuler.range; + expect(sportRuler.range.endNS).toBe(20); + }); + + it('SportRulerTest12', function () { + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: '', + selected: false, + text: '', + hidden: false, + type: '', + }); + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'triangle'); + }); + + it('SportRulerTest13', function () { + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 1000, + color: '', + selected: false, + text: '', + hidden: false, + type: 'triangle', + }); + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'triangle'); + }); + + it('SportRulerTest14', function () { + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: '', + selected: false, + text: '', + hidden: false, + type: 'triangle', + }); + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'square'); + }); + + it('SportRulerTest22', function () { + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: '', + selected: false, + text: '', + hidden: false, + type: 'triangle', + }); + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'inverted'); + }); + + it('SportRulerTest17', function () { + sportRuler.removeTriangle('inverted'); + }); + + it('SportRulerTest18', function () { + sportRuler.flagList.findIndex = jest.fn(() => 0); + sportRuler.removeTriangle('square'); + }); + + it('SportRulerTest19', function () { + sportRuler.drawInvertedTriangle(100, '#000000'); + }); + + it('SportRulerTest20', function () { + sportRuler.drawFlag(100, '#000000', false, 'text', ''); + }); + + it('SportRulerTest23', function () { + sportRuler.drawFlag(100, '#000000', false, 'text', 'triangle'); + }); + + it('SportRulerTest21', function () { + let flags = new Array(); + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 20, + color: '', + selected: false, + text: '', + hidden: false, + type: '', + }); + sportRuler.flagList = flags; + sportRuler.flagList.find = jest.fn(() => false); + expect(sportRuler.mouseUp({ offsetX: 20 })).toBeUndefined(); + }); + + it('SportRulerTest24', function () { + sportRuler.drawSlicesMark(null, null); + }); + + it('SportRulerTest25', function () { + sportRuler.setSlicesMark(null, null); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts b/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c97d01e248f5f98d1fa988ec4c00e2ddc23a9481 --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { TabPaneFlag } from '../../../../../dist/trace/component/trace/timer-shaft/TabPaneFlag.js'; + +describe('TabPaneFlag Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let tabPaneFlag = new TabPaneFlag(); + + it('TabPaneFlagTest01', function () { + document.body.innerHTML = ' '; + tabPaneFlag = document.querySelector('#remove-flag') as TabPaneFlag; + let htmlButtonElement = document.createElement('button') as HTMLButtonElement; + document.body.appendChild(htmlButtonElement); + htmlButtonElement.dispatchEvent(new Event('click')); + expect(tabPaneFlag.initElements()).toBeUndefined(); + }); + + it('TabPaneFlagTest02', function () { + expect(tabPaneFlag.initHtml()).not.toBe(''); + }); + + it('TabPaneFlagTest03', function () { + expect( + tabPaneFlag.setFlagObj({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: '', + selected: false, + text: '', + }) + ).toBeUndefined(); + }); + + it('TabPaneFlagTest04', function () { + expect(tabPaneFlag.initHtml()).toMatchInlineSnapshot(` +" + +
+
Annotation at
+ + Change color: + +
+ " +`); + }); +}); diff --git a/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts b/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..217faceebbbc76a78d7d27cc6eed28de19aa536d --- /dev/null +++ b/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { EventCenter } from '../../../../../dist/trace/component/trace/base/EventCenter.js'; + +jest.mock('../../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { TimeRuler } from '../../../../../dist/trace/component/trace/timer-shaft/TimeRuler.js'; +// @ts-ignore +import { TimerShaftElement } from '../../../../../dist/trace/component/trace/TimerShaftElement.js'; + +declare global { + interface Window { + SmartEvent: { + UI: { + MenuTrace: string; //selected menu trace + RefreshCanvas: string; //selected menu trace + SliceMark: string; //Set the tag scope + TimeRange: string; //Set the timeline range + TraceRowComplete: string; //Triggered after the row component has finished loading data + }; + }; + + subscribe(evt: string, fn: (b: any) => void): void; + + subscribeOnce(evt: string, fn: (b: any) => void): void; + + unsubscribe(evt: string, fn: (b: any) => void): void; + + publish(evt: string, data: any): void; + + clearTraceRowComplete(): void; + } +} + +window.SmartEvent = { + UI: { + MenuTrace: 'SmartEvent-UI-MenuTrace', + RefreshCanvas: 'SmartEvent-UI-RefreshCanvas', + SliceMark: 'SmartEvent-UI-SliceMark', + TimeRange: 'SmartEvent-UI-TimeRange', + TraceRowComplete: 'SmartEvent-UI-TraceRowComplete', + }, +}; + +Window.prototype.subscribe = (ev, fn) => EventCenter.subscribe(ev, fn); +Window.prototype.unsubscribe = (ev, fn) => EventCenter.unsubscribe(ev, fn); +Window.prototype.publish = (ev, data) => EventCenter.publish(ev, data); +Window.prototype.subscribeOnce = (ev, data) => EventCenter.subscribeOnce(ev, data); +Window.prototype.clearTraceRowComplete = () => EventCenter.clearTraceRowComplete(); + +describe('TimeRuler Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + document.body.innerHTML = ''; + + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + + let timeRuler = new TimeRuler( + timerShaftElement, + { + x: 20, + y: 20, + width: 100, + height: 100, + }, + 10000000000 + ); + + timeRuler.c = ctx; + + it('TimeRulerTest01', function () { + expect(timeRuler.draw()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/Procedure.test.ts b/ide/test/trace/database/Procedure.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..66452d72194530eb3eb98415f407ac0167adc7bc --- /dev/null +++ b/ide/test/trace/database/Procedure.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { procedurePool, ProcedureThread } from '../../../dist/trace/database/Procedure.js'; + +describe('procedure Test', () => { + it('ProfilerClientTest02', function () { + expect(procedurePool.isIdle()).not.toBeUndefined(); + }); + + it('ProfilerClientTest01', function () { + expect(procedurePool.submitWithName()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/SqlLite.test.ts b/ide/test/trace/database/SqlLite.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed4884a74fc34190d6633bbcaa6335c7c36fad67 --- /dev/null +++ b/ide/test/trace/database/SqlLite.test.ts @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { threadPool, DbThread, DbPool } from '../../../dist/trace/database/SqlLite.js'; + +describe('SqlLite Test', () => { + it('SqlLiteTest01', function () { + expect(DbThread).not.toBeTruthy(); + }); + it('SqlLiteTest02', function () { + expect(DbPool).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerCommon.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerCommon.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..43bb9e4d82d575a4f7bbd22aa5146a3e404e61b4 --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerCommon.test.ts @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + ChartStruct, + Msg, + MerageBean, + merageBeanDataSplit, + getByteWithUnit, + getTimeString, + timeMsFormat2p, + getProbablyTime, + convertJSON, + //@ts-ignore +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerCommon.js'; +describe('ProcedureLogicWorkerCommon Test', () => { + it('ChartStructTest', function () { + let chartStruct = new ChartStruct(); + expect(chartStruct).not.toBeUndefined(); + }); + + it('MsgTest', function () { + let msg = new Msg(); + expect(msg).not.toBeUndefined(); + }); + + it('MerageBeanTest01', function () { + let merageBean = new MerageBean(); + expect(merageBean).not.toBeUndefined(); + }); + + it('MerageBeanTest02', function () { + let merageBean = new MerageBean(); + merageBean.parentNode = true; + expect(merageBean.parentNode).toBeTruthy(); + }); + + it('MerageBeanTest03', function () { + let merageBean = new MerageBean(); + merageBean.parentNode = false; + expect(merageBean.parentNode).toBeFalsy(); + }); + + it('MerageBeanTest04', function () { + let merageBean = new MerageBean(); + merageBean.total = true; + expect(merageBean.total).toBeTruthy(); + }); + + it('MerageBeanTest05', function () { + let merageBean = new MerageBean(); + merageBean.total = false; + expect(merageBean.total).toBeFalsy(); + }); + + it('MerageBeanTest06', function () { + merageBeanDataSplit.recursionChargeInitTree = jest.fn(() => true); + merageBeanDataSplit.resetAllNode = jest.fn(() => true); + expect(merageBeanDataSplit.splitTree('', [{ children: [] }], '', true, [''], '')).toBeUndefined(); + }); + it('MerageBeanTest30', function () { + merageBeanDataSplit.recursionPruneInitTree = jest.fn(() => true); + merageBeanDataSplit.resetAllNode = jest.fn(() => true); + expect(merageBeanDataSplit.splitTree('', [{ children: [] }], '', false, [''], '')).toBeUndefined(); + }); + + it('MerageBeanTest07', function () { + merageBeanDataSplit.recursionChargeInitTree = jest.fn(() => true); + let node = { + symbolName: '', + libName: '', + }; + expect(merageBeanDataSplit.recursionChargeInitTree('', node, '', true)).toBeTruthy(); + }); + + it('MerageBeanTest47', function () { + merageBeanDataSplit.recursionChargeInitTree = jest.fn(() => undefined); + merageBeanDataSplit.resetAllNode = jest.fn(() => true); + let node = { + symbolName: '', + libName: '', + initChildren: { + length: 1, + }, + }; + expect(merageBeanDataSplit.recursionChargeInitTree('', node, [], true)).toBeUndefined(); + }); + + it('MerageBeanTest30', function () { + expect(getByteWithUnit(-1_000_000_001)).toBe('-953.67 Mb'); + }); + + it('MerageBeanTest08', function () { + expect(getByteWithUnit(1_000_000_001)).toBe('953.67 Mb'); + }); + + it('MerageBeanTest09', function () { + expect(getByteWithUnit(1_000_001)).toBe('976.56 Kb'); + }); + + it('MerageBeanTest10', function () { + expect(getByteWithUnit(1_001)).toBe('1001 byte'); + }); + + it('MerageBeanTest11', function () { + expect(getByteWithUnit(1_000_000_000_1)).toBe('9.31 Gb'); + }); + + it('MerageBeanTest12', function () { + expect(getTimeString(3600_000_000_002)).toBe('1h 2ns '); + }); + + it('MerageBeanTest13', function () { + expect(getTimeString(60_000_000_002)).toBe('1m 2ns '); + }); + + it('MerageBeanTest14', function () { + expect(getTimeString(1_000_000_003)).toBe('1s 3ns '); + }); + + it('MerageBeanTest15', function () { + expect(getTimeString(1_000_004)).toBe('1ms 4ns '); + }); + + it('MerageBeanTest16', function () { + expect(getTimeString(1_003)).toBe('1μs 3ns '); + }); + + it('MerageBeanTest31', function () { + expect(convertJSON('')).toBe(''); + }); + + it('MerageBeanTest33', function () { + expect(getProbablyTime('')).toBe(''); + }); + + it('MerageBeanTest34', function () { + expect(getProbablyTime(3600_000_000_000)).toBe('1.00h '); + }); + + it('MerageBeanTest35', function () { + expect(getProbablyTime(60_000_000_002)).toBe('1.00m '); + }); + + it('MerageBeanTest36', function () { + expect(getProbablyTime(1_000_000_000)).toBe('1.00s '); + }); + + it('MerageBeanTest37', function () { + expect(getProbablyTime(1_000_000)).toBe('1.00ms '); + }); + + it('MerageBeanTest38', function () { + expect(getProbablyTime(1_000)).toBe('1.00μs '); + }); + + it('MerageBeanTest44', function () { + expect(getProbablyTime(100)).toBe('100ns '); + }); + + it('MerageBeanTest39', function () { + expect(timeMsFormat2p('')).toBe('0s'); + }); + + it('MerageBeanTest40', function () { + expect(timeMsFormat2p(3600_000)).toBe('1.00h'); + }); + + it('MerageBeanTest41', function () { + expect(timeMsFormat2p(60_000)).toBe('1.00min'); + }); + + it('MerageBeanTest42', function () { + expect(timeMsFormat2p(1_000)).toBe('1.00s'); + }); + + it('MerageBeanTest43', function () { + expect(timeMsFormat2p(100)).toBe('100.00ms'); + }); + + it('MerageBeanTest17', function () { + merageBeanDataSplit.recursionChargeTree = jest.fn(() => true); + let node = [ + { + initChildren: { + length: 1, + }, + }, + ]; + expect(merageBeanDataSplit.recursionChargeTree(node, '', true)).toBeTruthy(); + }); + + it('MerageBeanTest18', function () { + merageBeanDataSplit.recursionPruneInitTree = jest.fn(() => true); + let node = [ + { + initChildren: { + length: 1, + }, + }, + ]; + expect(merageBeanDataSplit.recursionPruneInitTree('', node, '', true)).toBeTruthy(); + }); + + it('MerageBeanTest19', function () { + merageBeanDataSplit.recursionPruneTree = jest.fn(() => true); + let node = [ + { + initChildren: { + length: 1, + }, + }, + ]; + expect(merageBeanDataSplit.recursionPruneTree(node, '', true)).toBeTruthy(); + }); + + it('MerageBeanTest20', function () { + merageBeanDataSplit.recursionChargeByRule = jest.fn(() => true); + let node = [ + { + initChildren: { + length: 1, + }, + }, + ]; + expect(merageBeanDataSplit.recursionChargeByRule('', node, '', true)).toBeTruthy(); + }); + + it('MerageBeanTest21', function () { + merageBeanDataSplit.pruneChildren = jest.fn(() => true); + let node = [ + { + initChildren: { + length: 1, + }, + }, + ]; + expect(merageBeanDataSplit.pruneChildren('', node, '')).toBeTruthy(); + }); + + it('MerageBeanTest22', function () { + merageBeanDataSplit.hideSystemLibrary = jest.fn(() => true); + expect(merageBeanDataSplit.hideSystemLibrary('', '')).toBeTruthy(); + }); + + it('MerageBeanTest23', function () { + merageBeanDataSplit.hideNumMaxAndMin = jest.fn(() => true); + expect(merageBeanDataSplit.hideNumMaxAndMin('', '', 1, 1)).toBeTruthy(); + }); + + it('MerageBeanTest24', function () { + merageBeanDataSplit.resotreAllNode = jest.fn(() => true); + expect(merageBeanDataSplit.resotreAllNode('', true)).toBeTruthy(); + }); + + it('MerageBeanTest25', function () { + merageBeanDataSplit.resetAllNode = jest.fn(() => true); + expect(merageBeanDataSplit.resetAllNode('', [], '')).toBeTruthy(); + }); + + it('MerageBeanTest26', function () { + merageBeanDataSplit.resetNewAllNode = jest.fn(() => true); + expect(merageBeanDataSplit.resetNewAllNode('', [])).toBeTruthy(); + }); + + it('MerageBeanTest27', function () { + merageBeanDataSplit.clearSearchNode = jest.fn(() => true); + expect(merageBeanDataSplit.clearSearchNode('')).toBeTruthy(); + }); + + it('MerageBeanTest28', function () { + merageBeanDataSplit.splitAllProcess = jest.fn(() => true); + expect(merageBeanDataSplit.splitAllProcess('', '', [])).toBeTruthy(); + }); + + it('MerageBeanTest29', function () { + merageBeanDataSplit.splitAllProcess = jest.fn(() => true); + expect(merageBeanDataSplit.splitAllProcess('', '', [])).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerCpuState.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerCpuState.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7da13dd17b77c5e67f38bb567814862bab5a3841 --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerCpuState.test.ts @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + ProcedureLogicWorkerCpuState, + CpuState, +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerCpuState.js'; +describe('ProcedureLogicWorkerCpuState Test', () => { + it('ProcedureLogicWorkerCpuStateTest01', function () { + let procedureLogicWorkerCpuState = new ProcedureLogicWorkerCpuState(); + expect(procedureLogicWorkerCpuState).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerCpuStateTest02', function () { + let procedureLogicWorkerCpuState = new ProcedureLogicWorkerCpuState(); + let arr = [ + { + startTs: 1, + endTs: 1, + length: 1, + }, + ]; + expect(procedureLogicWorkerCpuState.supplementCpuState(arr)).toEqual([ + { dur: 1, endTs: 1, startTs: 0, value: 3 }, + { endTs: 1, length: 1, startTs: 1 }, + ]); + }); + + it('ProcedureLogicWorkerCpuStateTest03', function () { + let procedureLogicWorkerCpuState = new ProcedureLogicWorkerCpuState(); + let data = { + type: 'CpuState-getCpuState', + params: { + list: true, + }, + }; + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerCpuState.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerCpuStateTest04', function () { + let cpuState = new CpuState(); + cpuState = { + startTs: 0, + endTs: 0, + dur: 0, + value: 0, + }; + expect(cpuState).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerCpuStateTest05', function () { + let procedureLogicWorkerCpuState = new ProcedureLogicWorkerCpuState(); + let data = { + type: 'CpuState-getCpuState', + params: { + list: false, + }, + }; + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerCpuState.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerCpuStateTest06', function () { + let procedureLogicWorkerCpuState = new ProcedureLogicWorkerCpuState(); + + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerCpuState.queryData()).toBeUndefined(); + }); + it('ProcedureLogicWorkerCpuStateTest07', function () { + let procedureLogicWorkerCpuState = new ProcedureLogicWorkerCpuState(); + + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerCpuState.getCpuState()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4c7c6a8c33eede9da0c12df5433d923bc7f7019 --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.test.ts @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + ProcedureLogicWorkerFileSystem, + FileCallChain, + FileSample, + Stack, + FileSysEvent, + FileMerageBean, + IoCompletionTimes, + VirtualMemoryEvent, + //@ts-ignore +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerFileSystem.js'; + +describe('ProcedureLogicWorkerFileSystem Test', () => { + let procedureLogicWorkerF = new ProcedureLogicWorkerFileSystem(); + + procedureLogicWorkerF.queryData = jest.fn(); + procedureLogicWorkerF.initCallchains(); + it('procedureLogicWorkerFileSystemTest', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + expect(procedureLogicWorkerFileSystem).not.toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest01', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + window.postMessage = jest.fn(() => true); + let data = { + type: 'fileSystem-init', + }; + expect(procedureLogicWorkerFileSystem.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest35', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + window.postMessage = jest.fn(() => true); + let data = { + type: 'fileSystem-queryCallchains', + params: { + list: [], + }, + }; + expect(procedureLogicWorkerFileSystem.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest36', function () { + window.postMessage = jest.fn(() => true); + let data = { + type: 'fileSystem-queryFileSamples', + params: { + list: [], + }, + }; + expect(procedureLogicWorkerF.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest37', function () { + window.postMessage = jest.fn(() => true); + let data = { + type: 'fileSystem-action', + length: 0, + params: { + callType: 'fileSystem', + args: [], + list: [], + filter: () => { + return []; + }, + }, + }; + expect(procedureLogicWorkerF.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest38', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + window.postMessage = jest.fn(() => true); + let data = { + type: 'fileSystem-queryStack', + params: { + list: [], + }, + }; + expect(procedureLogicWorkerFileSystem.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest39', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + window.postMessage = jest.fn(() => true); + let data = { + type: 'fileSystem-queryFileSysEvents', + params: { + list: [], + }, + }; + expect(procedureLogicWorkerFileSystem.handle(data)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest07', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + expect(handlerMap.clearSplitMapData([true])).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest08', function () { + let fileCallChain = { + callChainId: 0, + depth: 0, + symbolsId: 0, + pathId: 0, + ip: '', + }; + expect(fileCallChain).not.toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest09', function () { + let stack = new Stack(); + stack = { + type: 0, + symbol: '', + path: '', + }; + expect(stack).not.toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest10', function () { + let fileSysEvent = new FileSysEvent(); + fileSysEvent = { + id: 0, + callchainId: 0, + startTs: 0, + startTsStr: '', + durStr: '', + dur: 0, + process: 0, + type: 0, + typeStr: '', + fd: '', + size: 0, + depth: 0, + firstArg: '', + secondArg: '', + thirdArg: '', + fourthArg: '', + returnValue: '', + error: '', + path: '', + symbol: '', + backtrace: [], + }; + expect(fileSysEvent).not.toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest11', function () { + let fileMerageBean = new FileMerageBean(); + expect(fileMerageBean).not.toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest13', function () { + let fileSample = { + callChainId: 0, + dur: 0, + pid: 0, + processName: '', + }; + expect(fileSample).not.toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest14', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + expect(handlerMap.clearAll()).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest15', function () { + window.postMessage = jest.fn(() => true); + let map = new Map(); + map.set('symbol', ''); + map.set('path', ''); + map.set('libName', ''); + map.set('symbolName', ''); + let data = { + type: 'fileSystem-init', + params: map, + }; + procedureLogicWorkerF.handle(data); + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let currentNode = { + symbol: 'symbol', + path: 'path', + libName: 'libName', + symbolName: 'symbolName', + }; + expect(handlerMap.setMerageName(currentNode)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest33', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let currentNode = { + pathId: -1, + symbol: '', + path: '', + libName: '', + symbolName: '', + }; + expect(handlerMap.setMerageName(currentNode)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest17', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + expect(handlerMap.freshCurrentCallchains([], 1)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest18', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + expect(procedureLogicWorkerFileSystem.initCallChainTopDown([])).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest19', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + expect(procedureLogicWorkerFileSystem.supplementFileSysEvents([], 'events')); + }); + + it('procedureLogicWorkerFileSystemTest21', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + expect(procedureLogicWorkerFileSystem.supplementFileSysEvents([], '')); + }); + it('procedureLogicWorkerFileSystemTest22', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + expect(procedureLogicWorkerFileSystem.supplementFileSysEvents([])); + }); + + it('procedureLogicWorkerFileSystemTest20', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem(); + expect(procedureLogicWorkerFileSystem.getStacksByCallchainId([])); + }); + + it('procedureLogicWorkerFileSystemTest23', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'getCallChainsBySampleIds', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest24', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'getCurrentDataFromDb', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest25', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'hideSystemLibrary', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest26', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'hideNumMaxAndMin', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest27', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'splitAllProcess', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest28', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'resetAllNode', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest29', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'resotreAllNode', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest30', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'clearSplitMapData', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest31', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'splitTree', + }; + expect(handlerMap.resolvingAction(params)); + }); + + it('procedureLogicWorkerFileSystemTest32', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + funcName: 'setSearchValue', + }; + expect(handlerMap.resolvingAction(params)); + }); + it('procedureLogicWorkerFileSystemTest34', function () { + let currentNode = { + processName: '', + ip: '', + pid: 1, + pathId: '', + symbolsId: '', + selfDur: 1, + self: 1, + count: 1, + }; + let callChain = { + ip: '', + pid: 1, + pathId: '', + symbolsId: '', + }; + let sample = { + processName: '', + dur: 1, + }; + let isEnd = true; + expect(FileMerageBean.merageCallChainSample(currentNode, callChain, sample, isEnd)); + }); + it('procedureLogicWorkerFileSystemTest40', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let selectionParam = { + diskIOipids: { + length: 1, + join: jest.fn(() => true), + }, + fileSystemType: { + length: 1, + join: jest.fn(() => true), + }, + }; + window.postMessage = jest.fn(() => true); + expect(handlerMap.queryFileSamples(selectionParam)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest41', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let sample = { + callChainId: 1, + type: { + toString, + }, + }; + window.postMessage = jest.fn(() => true); + expect(handlerMap.createThreadAndType(sample)).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest42', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let currentNode = { + initChildren: { + filter: jest.fn(() => -1), + }, + }; + let callChainDataList = { + length: 1, + }; + let index = 0; + let sample = {}; + let isTopDown = {}; + window.postMessage = jest.fn(() => true); + expect(handlerMap.merageChildrenByIndex(currentNode, callChainDataList, index, sample, isTopDown)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest43', function () { + let handlerMap = procedureLogicWorkerF.handlerMap.get('fileSystem'); + let params = { + length: 1, + forEach: jest.fn(() => true), + }; + window.postMessage = jest.fn(() => true); + expect(handlerMap.resolvingAction(params)).toStrictEqual([]); + }); + + it('procedureLogicWorkerFileSystemTest45', function () { + let ioCompletionTimes = new IoCompletionTimes(); + expect(ioCompletionTimes).toBeDefined(); + }); + + it('procedureLogicWorkerFileSystemTest46', function () { + let virtualMemoryEvent = new VirtualMemoryEvent(); + expect(virtualMemoryEvent).toBeDefined(); + }); + it('procedureLogicWorkerFileSystemTest47', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem (); + expect(procedureLogicWorkerFileSystem.queryFileSysEvents(1,0,[1],true)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest48', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem (); + expect(procedureLogicWorkerFileSystem.queryVMEvents(1,0,[1])).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest49', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem (); + expect(procedureLogicWorkerFileSystem.queryVMEvents(1,0,[1])).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest50', function () { + let procedureLogicWorkerFileSystem = new ProcedureLogicWorkerFileSystem (); + expect(procedureLogicWorkerFileSystem.queryIOEvents(1,0,[1])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..622306271e3f2f35ef1bcfcc5b3b45e6bef7849c --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.test.ts @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + HeapTreeDataBean, + NativeHookStatistics, + NativeHookCallInfo, + ProcedureLogicWorkerNativeMemory, + NativeMemory, + HeapStruct, + NativeEvent, + StatisticsSelection, +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerNativeNemory.js'; + +describe('ProcedureLogicWorkerNativeNemory Test', () => { + it('ProcedureLogicWorkerNativeNemoryTest01', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + expect(procedureLogicWorkerNativeMemory).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest02', function () { + let nativeHookStatistics = new NativeHookStatistics(); + nativeHookStatistics = { + eventId: 0, + eventType: '', + subType: '', + subTypeId: 0, + heapSize: 0, + addr: '', + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + threadName: '', + sSelected: false, + }; + expect(nativeHookStatistics).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest03', function () { + let nativeHookCallInfo = new NativeHookCallInfo(); + expect(nativeHookCallInfo).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest04', function () { + let heapTreeDataBean = new HeapTreeDataBean(); + heapTreeDataBean = { + symbolId: 0, + fileId: 0, + startTs: 0, + endTs: 0, + depth: 0, + heapSize: 0, + eventId: '', + }; + expect(heapTreeDataBean).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest05', function () { + let nativeMemory = new NativeMemory(); + nativeMemory = { + index: 0, + eventId: 0, + eventType: '', + subType: '', + addr: '', + startTs: 0, + endTs: 0, + timestamp: '', + heapSize: 0, + heapSizeUnit: '', + symbol: '', + library: '', + isSelected: false, + state: '', + threadId: 0, + threadName: '', + }; + expect(nativeMemory).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest06', function () { + let heapStruct = new HeapStruct(); + expect(heapStruct).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest07', function () { + let nativeEvent = new NativeEvent(); + expect(nativeEvent).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest08', function () { + let statisticsSelection = new StatisticsSelection(); + expect(statisticsSelection).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest09', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + expect(procedureLogicWorkerNativeMemory.clearAll()).toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest11', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + expect(procedureLogicWorkerNativeMemory.getTypeFromIndex(-1, '', '')).toBeFalsy(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest12', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + expect(procedureLogicWorkerNativeMemory.getTypeFromIndex(0, '', '')).toBeTruthy(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest13', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let item = { + eventType: 'AllocEvent', + }; + expect(procedureLogicWorkerNativeMemory.getTypeFromIndex(1, item, '')).toBeTruthy(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest14', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let item = { + eventType: 'MmapEvent', + }; + expect(procedureLogicWorkerNativeMemory.getTypeFromIndex(2, item, '')).toBeTruthy(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest15', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let stack = { + children: [], + count: 1, + countValue: '', + countPercent: '', + size: 0, + threadId: 0, + threadName: '', + heapSizeStr: '', + heapPercent: '', + }; + expect(procedureLogicWorkerNativeMemory.traverseTree(stack, 1)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest16', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let stack = { + children: [], + count: 1, + countValue: '', + countPercent: '', + size: 0, + threadId: 0, + threadName: '', + heapSizeStr: '', + heapPercent: '', + }; + expect(procedureLogicWorkerNativeMemory.traverseSampleTree(stack, 1)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerNativeNemoryTest17', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let target = { + depth: 1, + children: [], + count: 1, + countValue: '', + countPercent: '', + size: 0, + threadId: 0, + threadName: '', + heapSizeStr: '', + heapPercent: '', + }; + let src = { + depth: 1, + children: [], + count: 1, + countValue: '', + countPercent: '', + size: 0, + threadId: 0, + threadName: '', + heapSizeStr: '', + heapPercent: '', + }; + expect(procedureLogicWorkerNativeMemory.mergeTree(target, src)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest18', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-init', + }; + procedureLogicWorkerNativeMemory.initDataDict = jest.fn(() => true); + procedureLogicWorkerNativeMemory.clearAll = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest19', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-queryDataDICT', + }; + procedureLogicWorkerNativeMemory.initNMChartData = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest20', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-queryNMChartData', + }; + procedureLogicWorkerNativeMemory.initNMFrameData = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest21', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-queryNMFrameData', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerNativeMemory.initNMStack = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + + it('procedureLogicWorkerFileSystemTest22', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-action', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingAction = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest23', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.queryData()).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest24', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.initDataDict()).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest25', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.initNMChartData() + ).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest26', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.initNMFrameData() + ).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest27', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + let frameArr = { + map: jest.fn(() => true), + }; + expect( + procedureLogicWorkerNativeMemory.initNMStack(frameArr) + ).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest28', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = { + get: jest.fn(() => 'call-info'), + }; + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingAction(paramMap) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest29', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = new Map(); + paramMap.set('actionType', 'info'); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingAction(paramMap) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest30', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = { + get: jest.fn(() => 'memory-stack'), + }; + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingAction(paramMap) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest31', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = { + get: jest.fn(() => 'memory-chart'), + }; + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingAction(paramMap) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest32', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = { + get: jest.fn(() => true), + }; + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingAction(paramMap) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest33', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = { + get: jest.fn(() => 0), + }; + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingActionNativeMemoryChartData( + paramMap + ) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest34', function () { + let procedureLogicWorkerNativeMemory = + new ProcedureLogicWorkerNativeMemory(); + let paramMap = { + get: jest.fn(() => 1), + }; + // @ts-ignore + procedureLogicWorkerNativeMemory.resolvingActionCallInfo = jest.fn( + () => true + ); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource = + jest.fn(() => true); + procedureLogicWorkerNativeMemory.resolvingActionCallInfo.dataSource.map = + jest.fn(() => true); + expect( + procedureLogicWorkerNativeMemory.resolvingActionNativeMemoryChartData( + paramMap + ) + ).toBeTruthy(); + }); + it('procedureLogicWorkerFileSystemTest35', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.queryCallchainsSamples('',1,1,[''])).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest36', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.getCallChainData()).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest37', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.queryStatisticCallchainsSamples('',1,1,[''])).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest38', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.getFilterLevel(1000001)).toBe(100000); + }); + it('procedureLogicWorkerFileSystemTest39', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.getFilterLevel(5000001)).toBe(100000); + }); + it('procedureLogicWorkerFileSystemTest40', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.getFilterLevel(3000001)).toBe(100000); + }); + it('procedureLogicWorkerFileSystemTest41', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.getFilterLevel(150000)).toBe(0); + }); + it('procedureLogicWorkerFileSystemTest42', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + let params = [ + { + length: 1 + } + ] + expect(procedureLogicWorkerNativeMemory.resolvingNMCallAction(params)).toStrictEqual([]); + }); + it('procedureLogicWorkerFileSystemTest43', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + let params = { + symbol: '', + path:'', + symbolId:1, + fileId:1, + lib:'', + symbolName:'', + type:0, + } + expect(procedureLogicWorkerNativeMemory.setMerageName(params)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest44', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.clearSplitMapData('')).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest49', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-calltree-action', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerNativeMemory.initNMStack = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest50', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-init-responseType', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerNativeMemory.initNMStack = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest51', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-get-responseType', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerNativeMemory.initNMStack = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest52', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'native-memory-queryNativeHookStatistic', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerNativeMemory.initNMStack = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.handle(data)).toBeUndefined(); + }); + it('procedureLogicWorkerFileSystemTest53', function () { + let procedureLogicWorkerNativeMemory = new ProcedureLogicWorkerNativeMemory(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerNativeMemory.queryNativeHookStatistic(1)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerPerf.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerPerf.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..15c56770baa21e3f3995ca737ac9957c4c01b138 --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerPerf.test.ts @@ -0,0 +1,591 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + ProcedureLogicWorkerPerf, + PerfCountSample, + PerfCallChainMerageData, + PerfStack, + PerfCmdLine, + PerfCall, + timeMsFormat2p, + PerfFile, + PerfThread, + PerfCallChain, +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerPerf.js'; + +describe('ProcedureLogicWorkerPerf Test', () => { + it('ProcedureLogicWorkerPerfTest', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest01', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-init', + }; + procedureLogicWorkerPerf.initPerfFiles = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest02', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-queryPerfFiles', + }; + procedureLogicWorkerPerf.initPerfThreads = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest03', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-queryPerfThread', + }; + procedureLogicWorkerPerf.initPerfCalls = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest04', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-queryPerfCalls', + }; + procedureLogicWorkerPerf.initPerfCallchains = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest05', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-queryPerfCallchains', + }; + window.postMessage = jest.fn(() => true); + procedureLogicWorkerPerf.initCallChainTopDown = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest06', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-queryCallchainsGroupSample', + }; + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest07', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + action: '', + type: 'perf-action', + }; + procedureLogicWorkerPerf.resolvingAction = jest.fn(() => true); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerPerf.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest08', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.clearAll()).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest09', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let callChain = [ + { + sampleId: '', + depth: 0, + canCharge: false, + name: '', + tid: '', + fileName: '', + threadName: '', + }, + ]; + expect(procedureLogicWorkerPerf.initCallChainBottomUp(callChain)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest10', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let callChain = [ + { + sampleId: '', + depth: 0, + canCharge: false, + name: '', + tid: '', + fileName: '', + threadName: '', + }, + ]; + expect(procedureLogicWorkerPerf.initCallChainTopDown([callChain])).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest11', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let callChain = { + sampleId: -1, + depth: 0, + canCharge: true, + name: '', + tid: '', + fileName: '', + threadName: '', + symbolId: -1, + }; + expect(procedureLogicWorkerPerf.setCallChainName(callChain)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest12', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let callChain = { + sampleId: 0, + }; + expect(procedureLogicWorkerPerf.setCallChainName(callChain)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest14', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let callChain = { + sampleId: '', + depth: 0, + canCharge: false, + name: '', + tid: '', + fileName: '', + threadName: '', + }; + expect(procedureLogicWorkerPerf.addPerfCallData(callChain)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest15', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let callChain = { + sampleId: '', + }; + expect(procedureLogicWorkerPerf.addGroupData(callChain)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest16', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.getCallChainsBySampleIds([], [])).toBeTruthy(); + }); + + it('ProcedureLogicWorkerPerfTest17', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.freshCurrentCallchains([], 1)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest19', function () { + let perfCountSample = new PerfCountSample(); + perfCountSample = { + sampleId: 0, + count: 0, + pid: 0, + tid: 0, + threadState: '', + }; + expect(perfCountSample).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest20', function () { + let perfStack = new PerfStack(); + perfStack = { + sample: '', + path: '', + fileId: 0, + type: 0, + vaddrInFile: 0, + }; + expect(perfStack).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest21', function () { + let perfCmdLine = new PerfCmdLine(); + perfCmdLine = { + report_value: '', + }; + expect(perfCmdLine).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest21', function () { + let perfCmdLine = new PerfCmdLine(); + perfCmdLine = { + report_value: '', + }; + expect(perfCmdLine).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest21', function () { + let perfCall = new PerfCall(); + perfCall = { + sampleId: 0, + name: '', + depth: 0, + }; + expect(perfCall).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest22', function () { + expect(timeMsFormat2p('')).toBe('0s'); + }); + + it('ProcedureLogicWorkerPerfTest23', function () { + expect(timeMsFormat2p(3600_000)).toBe('1.00h'); + }); + + it('ProcedureLogicWorkerPerfTest24', function () { + expect(timeMsFormat2p(60_000)).toBe('1.00min'); + }); + + it('ProcedureLogicWorkerPerfTest25', function () { + expect(timeMsFormat2p(1_000)).toBe('1.00s'); + }); + + it('ProcedureLogicWorkerPerfTest26', function () { + expect(timeMsFormat2p(100)).toBe('100.00ms'); + }); + + it('ProcedureLogicWorkerPerfTest31', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.recursionChargeInitTree = jest.fn(() => undefined); + let node = [ + { + symbolName: '', + libName: '', + length: 1, + initChildren: { + length: 1, + }, + }, + ]; + expect(procedureLogicWorkerPerf.recursionChargeInitTree(node, '', true)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest32', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.splitTree([], '', '', true)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest33', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.recursionPruneInitTree = jest.fn(() => undefined); + let node = { + symbolName: '', + libName: '', + length: 1, + initChildren: { + length: 1, + }, + }; + expect(procedureLogicWorkerPerf.recursionPruneInitTree(node, '', true)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest34', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.recursionChargeByRule = jest.fn(() => undefined); + let node = { + initChildren: [ + { + length: 1, + }, + ], + }; + let rule = { + child: { + isStore: 1, + }, + }; + expect(procedureLogicWorkerPerf.recursionChargeByRule(node, '', rule)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest35', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerPerf.queryData('', '', '')).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest36', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.queryData = jest.fn(() => true); + expect(procedureLogicWorkerPerf.initPerfFiles()).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest37', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.queryData = jest.fn(() => true); + expect(procedureLogicWorkerPerf.initPerfThreads()).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest38', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.queryData = jest.fn(() => true); + expect(procedureLogicWorkerPerf.initPerfCalls()).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest39', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.queryData = jest.fn(() => true); + expect(procedureLogicWorkerPerf.initPerfCallchains()).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest40', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + procedureLogicWorkerPerf.queryData = jest.fn(() => true); + let selectionParam = { + perfAll: '', + perfCpus: [1], + perfProcess: [2], + perfThread: [1], + leftNs: 0, + rightNs: 0, + }; + expect(procedureLogicWorkerPerf.getCurrentDataFromDb(selectionParam)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerPerfTest41', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let currentNode = { + children: [], + initChildren: [], + }; + let list = [ + { + length: 1, + name: '', + }, + ]; + expect(procedureLogicWorkerPerf.merageChildren(currentNode, list, true)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest42', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let sampleIds = { + length: 1, + }; + let isTopDown = {}; + expect(procedureLogicWorkerPerf.groupNewTreeNoId(sampleIds, isTopDown)).toStrictEqual([]); + }); + it('ProcedureLogicWorkerPerfTest43', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let node = { + initChildren: { + length: 1, + forEach: jest.fn(() => true), + }, + libName: 1, + }; + let symbolName = 1; + + let isSymbol = true; + expect(procedureLogicWorkerPerf.recursionChargeInitTree(node, symbolName, isSymbol)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest44', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let node = { + children: { + length: 1, + forEach: jest.fn(() => true), + }, + libName: 1, + }; + let symbolName = 1; + + let isSymbol = true; + expect(procedureLogicWorkerPerf.recursionChargeTree(node, symbolName, isSymbol)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest45', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let node = { + initChildren: { + length: 1, + forEach: jest.fn(() => true), + }, + libName: 1, + }; + let symbolName = 1; + + let isSymbol = true; + expect(procedureLogicWorkerPerf.recursionPruneInitTree(node, symbolName, isSymbol)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest46', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let node = { + children: { + length: 1, + forEach: jest.fn(() => true), + }, + libName: 1, + }; + let symbolName = 1; + + let isSymbol = true; + expect(procedureLogicWorkerPerf.recursionPruneTree(node, symbolName, isSymbol)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest47', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let node = { + initChildren: { + length: 1, + forEach: jest.fn(() => true), + }, + }; + let ruleName = 1; + + let rule = true; + expect(procedureLogicWorkerPerf.recursionChargeByRule(node, ruleName, rule)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest48', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + let node = { + initChildren: { + length: 1, + forEach: jest.fn(() => true), + }, + }; + let symbolName = 1; + expect(procedureLogicWorkerPerf.pruneChildren(node, symbolName)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest49', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.clearSplitMapData()).toBeUndefined(); + }); + it('PerfFileTest01', function () { + let perfFile = new PerfFile(); + expect(perfFile.constructor()).toBeUndefined(); + }); + it('PerfFileTest02', function () { + let perfFile = new PerfFile(); + let path = true; + expect(perfFile.setFileName(path)).toBeUndefined(); + }); + it('PerfThreadTest01', function () { + let perfThread = new PerfThread(); + expect(perfThread.constructor()).toBeUndefined(); + }); + it('PerfCallChainTest01', function () { + let perfCallChain = new PerfCallChain(); + expect(perfCallChain.constructor()).toBeUndefined(); + }); + it('PerfCallChainMerageDataTest01', function () { + let perfCallChainMerageData = new PerfCallChainMerageData(); + expect(perfCallChainMerageData.constructor()).toEqual({ + addr: '', + canCharge: true, + children: [], + count: 0, + currentTreeParentNode: undefined, + depth: 0, + dur: 0, + id: '', + initChildren: [], + isSearch: false, + isSelected: false, + isStore: 0, + lib: '', + libName: '', + parentId: '', + path: '', + pid: 0, + searchShow: true, + self: '0s', + selfDur: 0, + size: 0, + symbol: '', + symbolName: '', + tid: 0, + type: 0, + vaddrInFile: 0, + weight: '', + weightPercent: '', + }); + }); + it('PerfCallChainMerageDataTest03', function () { + let perfCallChainMerageData = new PerfCallChainMerageData(); + perfCallChainMerageData.parentNode = true; + expect(perfCallChainMerageData.parentNode).toBeTruthy(); + }); + it('PerfCallChainMerageDataTest04', function () { + let perfCallChainMerageData = new PerfCallChainMerageData(); + perfCallChainMerageData.total = true; + expect(perfCallChainMerageData.total).toBeTruthy(); + }); + it('ProcedureLogicWorkerPerfTest53', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.hideSystemLibrary()).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest54', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.hideNumMaxAndMin(1,'∞')).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest55', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.findSearchNode([],'',true)).toBeUndefined(); + }); + it('ProcedureLogicWorkerPerfTest56', function () { + let procedureLogicWorkerPerf = new ProcedureLogicWorkerPerf(); + expect(procedureLogicWorkerPerf.splitAllProcess([])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerSPT.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerSPT.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..477ff779221e158b32445ea71932584635e6169e --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerSPT.test.ts @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { + ProcedureLogicWorkerSPT, + ThreadState, + ThreadProcess, + SPT, +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerSPT.js'; + +describe('ProcedureLogicWorkerSPT Test', () => { + it('ProcedureLogicWorkerSPTTest01', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + expect(procedureLogicWorkerSPT).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerSPTTest03', function () { + let threadState = new ThreadState(); + expect(threadState).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerSPTTest04', function () { + let threadProcess = new ThreadProcess(); + expect(threadProcess).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerSPTTest05', function () { + let sPT = new SPT(); + expect(sPT).not.toBeUndefined(); + }); + + it('ProcedureLogicWorkerSPTTest06', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + type: 'spt-init', + }; + procedureLogicWorkerSPT.getThreadState = jest.fn(() => true); + expect(procedureLogicWorkerSPT.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerSPTTest07', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + type: 'spt-getThreadStateData', + }; + procedureLogicWorkerSPT.getThreadProcessData = jest.fn(() => true); + expect(procedureLogicWorkerSPT.handle(data)).toBeUndefined(); + }); + + it('ProcedureLogicWorkerSPTTest08', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + let data = { + id: 1, + params: [ + { + list: '', + }, + ], + type: 'spt-getThreadProcessData', + }; + procedureLogicWorkerSPT.initProcessThreadStateData = jest.fn(() => true); + expect(procedureLogicWorkerSPT.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSPTTest09', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSPT.queryData()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSPTTest10', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSPT.getThreadState()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSPTTest11', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSPT.getThreadProcessData()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSPTTest12', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSPT.getSPT()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSPTTest13', function () { + let procedureLogicWorkerSPT = new ProcedureLogicWorkerSPT(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSPT.initProcessThreadStateData()).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.test.ts b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf14b2db6c1038410142361291dabd293f67be0f --- /dev/null +++ b/ide/test/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.test.ts @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2022 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. + */ + +//@ts-ignore +import { ProcedureLogicWorkerSchedulingAnalysis, + FreqThread, + ThreadCpuUsage, + CpuAnalysis, + CpuMeasure, + Irq, + CpuUsage, +} from '../../../../dist/trace/database/logic-worker/ProcedureLogicWorkerSchedulingAnalysis.js'; + +describe('ProcedureLogicWorkerSchedulingAnalysis Test', () => { + it('ProcedureLogicWorkerSchedulingAnalysisTest01', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + expect(procedureLogicWorkerSchedulingAnalysis).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest02', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest03', function () { + let freqThread = new FreqThread (); + expect(freqThread).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest04', function () { + let threadCpuUsage = new ThreadCpuUsage(); + expect(threadCpuUsage).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest05', function () { + let cpuAnalysis = new CpuAnalysis(); + expect(cpuAnalysis).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest06', function () { + let cpuMeasure = new CpuMeasure(); + expect(cpuMeasure).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest07', function () { + let irq = new Irq(); + expect(irq).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest08', function () { + let cpuUsage = new CpuUsage(); + expect(cpuUsage).not.toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest09', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let arr = [{ + cpu: 1, + dur: 1, + ts: 1, + freqArr: { cpu: 1, freq: 1, dur: 1 } + }] + expect(procedureLogicWorkerSchedulingAnalysis.handlerThreadFreqData(arr)).toStrictEqual([]); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest10', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let arr = [{ + cpu: 1, + dur: 1, + ts: 1, + freqArr: { cpu: 1, freq: 1, dur: 1 } + }] + expect(procedureLogicWorkerSchedulingAnalysis.handlerFreqThreadData(arr)).toStrictEqual([]); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest11', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let arr = [{ + cpu: 1, + dur: 1, + ts: 1, + freqArr: { cpu: 1, freq: 1, dur: 1 } + }] + expect(procedureLogicWorkerSchedulingAnalysis.groupFreqByCpu(arr)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest12', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let arr = [{ + cpu: 1, + dur: 1, + ts: 1, + freqArr: { cpu: 1, freq: 1, dur: 1 } + }] + expect(procedureLogicWorkerSchedulingAnalysis.handleCPUIdle0Map(arr)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest13', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let arr = [{ + cpu: 1, + dur: 1, + ts: 1, + freqArr: { cpu: 1, freq: 1, dur: 1 } + }] + expect(procedureLogicWorkerSchedulingAnalysis.getEffectiveFrequencyDur(arr)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest14', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let arr = [{ + cpu: 1, + dur: 1, + ts: 1, + freqArr: { cpu: 1, freq: 1, dur: 1 } + }] + expect(procedureLogicWorkerSchedulingAnalysis.handleProcessThread(arr)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest15', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getCpuFrequency('')).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest16', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getProcessAndThread()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest17', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getCpuUsage()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest18', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.queryData('','',[])).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest19', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getThreadStateByCpu(1)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest20', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getCpuIdle0()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest21', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getCpuIdle()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest22', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.getCpuIrq()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest23', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.queryThreadCpuUsage([1],[0],[2])).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest24', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.queryThreadRunTime(1)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest25', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.queryProcessThreadCount()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest26', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.queryProcessSwitchCount()).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest27', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.queryThreadStateByTid(1)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest28', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-clearData', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest29', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-initFreqData', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest30', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-getProcessAndThread', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest31', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-getCpuIdle0', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest32', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-getCpuUsage', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest33', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-CPU Frequency', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest34', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-CPU Frequency Thread', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest35', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-CPU Idle', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest37', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-CPU Irq', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest38', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-Thread CpuUsage', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest39', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-Thread RunTime', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest40', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-Process ThreadCount', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest41', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-Process SwitchCount', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); + it('ProcedureLogicWorkerSchedulingAnalysisTest42', function () { + let procedureLogicWorkerSchedulingAnalysis = new ProcedureLogicWorkerSchedulingAnalysis(); + let data = { + params: [{ + endTs:1, + total:2, + list:'', + }, + ], + type:'scheduling-Thread Freq', + id:1, + action:'', + } + window.postMessage = jest.fn(() => true); + expect(procedureLogicWorkerSchedulingAnalysis.handle(data)).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/ide/test/trace/database/ui-worker/ProcedureWorker.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b3335ae605ca7b20330d9623f8b77c5337e42cd --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorker.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { ProcedureWorker, drawSelection } from '../../../dist/trace/database/ProcedureWorker.js'; + +describe('ProcedureWorker Test', () => { + it('ProcedureWorkerTest01', function () { + const context = { + globalAlpha: 0.5, + fillStyle: '#666666', + fillRect: '', + }; + const params = { + isRangeSelect: {}, + rangeSelectObject: { + startX: '', + endX: '', + startNS: '', + endNS: '', + }, + startNS: '', + endNS: '', + totalNS: 1, + frame: { + x: '', + y: '', + height: 1, + width: 1, + }, + }; + let drawSelection = jest.fn(() => true); + // @ts-ignore + expect(drawSelection(context, params)).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerCPU.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerCPU.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e51ea967f73ffa6111505c42d678e72d7a6c4b3 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerCPU.test.ts @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + cpu, + CpuStruct, + CpuRender, + rtCpu, + EmptyRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCPU.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe(' Test', () => { + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + processId: '', + }; + + it('CPUTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + expect(CpuStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('CPUTest04', () => { + expect(CpuStruct.equals(new CpuStruct(), new CpuStruct())).toBeTruthy(); + }); + + it('CPUTest06', () => { + expect(CpuStruct.equals([], dataSource)).toBeFalsy(); + }); + + it('CPUTest05', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + expect(CpuStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('CPUTest07', function () { + let cpuRender = new CpuRender(); + let node = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 2, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let list = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 2, + height: 2, + }, + ]; + expect(cpuRender.cpu(list, node, 1, 1, 1, frame, true)).toBeUndefined(); + }); + + it('CPUTest07', function () { + let cpuRender = new CpuRender(); + let node = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 0, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let list = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 2, + height: 2, + }, + ]; + expect(cpuRender.cpu(list, node, 1, 1, 1, frame, false)).toBeUndefined(); + }); + + it('CPUTest08', () => { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 0, + startTime: 0, + dur: 1, + }; + expect(CpuStruct.setCpuFrame(node, 1, 1, 1, { width: 10 })).toBeUndefined(); + }); + + it('CPUTest09', () => { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 0, + startTime: 2, + dur: 1, + }; + expect(CpuStruct.setCpuFrame(node, 1, 1, 1, { width: 10 })).toBeUndefined(); + }); + + it('CPUTest10', function () { + let emptyRender = new EmptyRender(); + let req = { + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + canvas: '', + context: {}, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(emptyRender.render(req, [], [])).toBeUndefined(); + }); + + it('CPUTest11', function () { + let cpuRender = new CpuRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(cpuRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerClock.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerClock.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd6c170b2efda0015944d6d64315f84d07435c06 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerClock.test.ts @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { ClockStruct } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerClock.js'; + +describe('ProcedureWorkerClock Test', () => { + it('ProcedureWorkerClock01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + filterId: 125, + value: 556, + startNS: 15454, + dur: 14552, + delta: 125, + }; + expect(ClockStruct.draw(ctx!, data, 2)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerCommon.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerCommon.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5419fef2283bfd84b3acf84ae83d0bbc9f783dea --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerCommon.test.ts @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/database/ui-worker/ProcedureWorkerCPU.js', () => {}); +jest.mock('../../../../dist/trace/component/trace/base/TraceSheet.js', () => {}); +jest.mock('../../../../dist/trace/component/SpSystemTrace.js', () => {}); +// @ts-ignore +import { + ChartStruct, + drawFlagLine, + drawLines, + getFrameChartColor, + getHeatColor, + Point, + Rect, + ns2s, + ns2x, + drawSelection, + drawWakeUp, + fillCacheData, + findRange, + FilterConfig, + dataFilterHandler, + drawFlagLineSegment, + drawSelectionRange, + drawLinkLines, + // @ts-ignore +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCommon.js'; +// @ts-ignore +import { Flag } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerTimeline.js'; +// @ts-ignore +import { ColorUtils } from '../../../../dist/trace/component/trace/base/ColorUtils.js'; +// @ts-ignore +import { TraceRow } from '../../../../dist/trace/component/trace/base/TraceRow.js'; +// @ts-ignore +import { TimerShaftElement } from '../../../../dist/trace/component/trace/TimerShaftElement.js'; +// @ts-ignore +import { EventCenter } from '../../../../dist/trace/component/trace/base/EventCenter.js'; + +declare global { + interface Window { + SmartEvent: { + UI: { + MenuTrace: string; //selected menu trace + RefreshCanvas: string; //selected menu trace + SliceMark: string; //Set the tag scope + TimeRange: string; //Set the timeline range + TraceRowComplete: string; //Triggered after the row component has finished loading data + }; + }; + + subscribe(evt: string, fn: (b: any) => void): void; + + subscribeOnce(evt: string, fn: (b: any) => void): void; + + unsubscribe(evt: string, fn: (b: any) => void): void; + + publish(evt: string, data: any): void; + + clearTraceRowComplete(): void; + } +} + +window.SmartEvent = { + UI: { + MenuTrace: 'SmartEvent-UI-MenuTrace', + RefreshCanvas: 'SmartEvent-UI-RefreshCanvas', + SliceMark: 'SmartEvent-UI-SliceMark', + TimeRange: 'SmartEvent-UI-TimeRange', + TraceRowComplete: 'SmartEvent-UI-TraceRowComplete', + }, +}; + +Window.prototype.subscribe = (ev, fn) => EventCenter.subscribe(ev, fn); +Window.prototype.unsubscribe = (ev, fn) => EventCenter.unsubscribe(ev, fn); +Window.prototype.publish = (ev, data) => EventCenter.publish(ev, data); +Window.prototype.subscribeOnce = (ev, data) => EventCenter.subscribeOnce(ev, data); +Window.prototype.clearTraceRowComplete = () => EventCenter.clearTraceRowComplete(); + +describe('ProcedureWorkerCommon Test', () => { + let rect = new Rect(); + let fullData = [ + { + cpu: 2, + dur: 140000, + end_state: 'S', + frame: { + y: 5, + height: 30, + }, + id: 62, + name: '2555', + priority: 100, + processCmdLine: 'com.test', + processId: 2983, + processName: 'com.test', + schedId: 44, + startTime: 3845000, + tid: 2996, + type: 'thread', + }, + ]; + let filterData = [ + { + cpu: 0, + dur: 9030000, + end_state: 'R', + frame: { y: 5, height: 30, x: 1, width: 3 }, + id: 4, + name: 'test', + priority: 120, + processCmdLine: 'test', + processId: 3303, + processName: 'test', + schedId: 55, + startTime: 4060000, + tid: 3303, + translateY: 0, + type: 'thread', + v: true, + }, + ]; + let condition = { + startKey: 'startNS', + durKey: 'dur', + startNS: 20, + endNS: 1000, + totalNS: 2000, + frame: { x: 10, y: 10 }, + paddingTop: 5, + useCache: true, + }; + + document.body.innerHTML = ''; + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + timerShaftElement.totalNS = 1000; + timerShaftElement.startNS = 1000; + timerShaftElement.endNS = 2000; + timerShaftElement.setRangeNS(1522, 5222); + timerShaftElement.getBoundingClientRect = jest.fn(() => { + return { + width: 648, + }; + }); + + it('ProcedureWorkerCommon01', function () { + expect(rect.contains(1, 2)).not.toBeUndefined(); + }); + + it('ProcedureWorkerCommon02', function () { + expect(rect.containsWithPadding()).not.toBeUndefined(); + }); + + it('ProcedureWorkerCommon03', function () { + let point = new Point(); + expect(point).not.toBeUndefined(); + }); + + it('ProcedureWorkerCommon04', function () { + let rect = new Rect(); + expect(Rect.contains(rect, 1, 2)).toBe(false); + }); + + it('ProcedureWorkerCommon05', function () { + let rect = new Rect(); + expect(Rect.containsWithPadding(rect, 1, 2, 1, 2)).toBe(false); + }); + + it('ProcedureWorkerCommon06', function () { + let rect = new Rect(); + expect(Rect.containsWithMargin(rect, 1, 2, 1, 2, 1, 1)).toBe(false); + }); + + it('ProcedureWorkerCommon07', function () { + let rect = new Rect(); + let rect2 = new Rect(); + expect(Rect.intersect(rect, rect2)).toBe(false); + }); + + it('ProcedureWorkerCommon08', function () { + let rect = new Rect(); + expect(rect.containsWithMargin(1, 2, 3, 5, 4, 5)).toBe(false); + }); + + it('ProcedureWorkerCommon09', function () { + let rect = new Rect(); + expect(rect.containsWithPadding(1, 2, 3, 5)).toBe(false); + }); + + it('ProcedureWorkerCommon10', function () { + let rect = new Rect(); + let rect2 = new Rect(); + expect(rect.intersect(rect2)).toBe(false); + }); + + it('ProcedureWorkerCommon011', function () { + expect(ColorUtils.formatNumberComma('11232')).toBe('11,232'); + }); + + it('ProcedureWorkerCommon012', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let aaa = [1, 2, 3]; + drawLines(ctx, aaa, 1, '#ffff'); + expect(ColorUtils.formatNumberComma('11232')).toBe('11,232'); + }); + + it('ProcedureWorkerCommon013', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let aaa = [1, 2, 3]; + let flag = new Flag(1, 2, 3, 4, 5, '#FFF', false); + let rect2 = new Rect(); + drawFlagLine(ctx, aaa, flag, 1, 2, 2, rect2); + expect(ColorUtils.formatNumberComma('11232')).toBe('11,232'); + }); + + it('ProcedureWorkerCommon20', function () { + expect(ns2s(2_000_000_000)).toBe('2.0 s'); + }); + + it('ProcedureWorkerCommon21', function () { + expect(ns2s(2_000_000)).toBe('2.0 ms'); + }); + + it('ProcedureWorkerCommon22', function () { + expect(ns2s(2_000)).toBe('2.0 μs'); + }); + + it('ProcedureWorkerCommon23', function () { + expect(ns2s(1)).toBe('1.0 ns'); + }); + + it('ProcedureWorkerCommon24', function () { + expect(ns2s(-1)).toBe('-1.0 s'); + }); + + it('ProcedureWorkerCommon25', function () { + expect(ColorUtils.hashFunc('', 10, 10)).toBe(3); + }); + + it('ProcedureWorkerCommon26', function () { + expect(ns2x(10, 1, 0, 1, { width: 2 })).toBe(2); + }); + + it('ProcedureWorkerCommon27', function () { + expect(ns2x(-10, 1, 0, 1, { width: 2 })).toBe(0); + }); + + it('ProcedureWorkerCommon28', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let flag = { + color: '', + x: 1, + }; + let select = { + color: '', + x: 1, + time: '', + }; + let frame = { + height: 1, + }; + let slicesTime = { + startTime: 1, + endTime: 1, + color: '#dadada', + }; + expect(drawFlagLine(ctx, flag, select, 1, 2, 1, frame, slicesTime)).toBeUndefined(); + }); + + it('ProcedureWorkerCommon29', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const context = canvas.getContext('2d'); + + let params = { + isRangeSelect: true, + rangeSelectObject: { + startX: 1, + endX: 10, + startNS: 1, + endNS: 10, + }, + startNS: 1, + endNS: 10, + totalNS: 9, + frame: { + y: 0, + }, + }; + expect(drawSelection(context, params)).toBeUndefined(); + }); + + it('ProcedureWorkerCommon30', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const context = canvas.getContext('2d'); + let wake = { + wakeupTime: 2, + cpu: 1, + }; + let frame = new Rect(20, 10, 10, 10); + let selectCpuStruct = [ + { + cpu: 0, + dur: 9030000, + end_state: 'R', + frame: { y: 5, height: 30, x: 1, width: 3 }, + id: 4, + name: 'test', + priority: 120, + processCmdLine: 'test', + processId: 3303, + processName: 'test', + schedId: 55, + startTime: 4060000, + tid: 3303, + translateY: 0, + type: 'thread', + v: true, + }, + ]; + expect(drawWakeUp(context, wake, 1, 2, 1, frame, selectCpuStruct, undefined)).toBeUndefined(); + }); + + it('ProcedureWorkerCommon31', function () { + let fillCache = fillCacheData(filterData, condition); + expect(fillCache).toBe(true); + }); + + it('ProcedureWorkerCommon32', function () { + let slice = findRange(fullData, condition); + expect(slice.length).toBe(1); + }); + + it('ProcedureWorkerCommon33', function () { + let condition = { + startKey: 'startNS', + durKey: 'dur', + startNS: 20, + endNS: 1000, + totalNS: 2000, + frame: { x: 10, y: 10 }, + paddingTop: 5, + useCache: false, + }; + let dataFilter = dataFilterHandler(fullData, filterData, condition); + expect(dataFilter).toBeUndefined(); + }); + + it('ProcedureWorkerCommon34', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const hoverFlag = { + x: 100, + y: 100, + width: 1000, + height: 1000, + time: 2550, + color: 'red', + selected: false, + text: 'test', + hidden: false, + type: 'type', + }; + const selectFlag = { + x: 10, + y: 10, + width: 100, + height: 100, + time: 255, + color: 'green', + selected: false, + text: 'test', + hidden: false, + type: 'type', + }; + TraceRow.range = { + startNS: 125, + endNS: 25336, + totalNS: 33333, + }; + expect( + drawFlagLineSegment(ctx, hoverFlag, selectFlag, { + y: 5, + height: 30, + x: 1, + width: 3, + }) + ).toBeUndefined(); + }); + + it('ProcedureWorkerCommon35', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const context = canvas.getContext('2d'); + let params = { + rangeSelect: true, + rangeSelectObject: { + startX: 1, + endX: 10, + startNS: 1, + endNS: 10, + }, + startNS: 1, + endNS: 10, + totalNS: 9, + frame: { + y: 0, + }, + }; + TraceRow.rangeSelectObject = { + startX: 125, + endX: 25336, + }; + expect(drawSelectionRange(context, params)).toBeUndefined(); + }); + + it('ProcedureWorkerCommon36', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const context = canvas.getContext('2d'); + let nodes = [ + [ + { + isRight: true, + ns: 1075112000, + offsetY: 30, + rowEL: null, + x: 303.29713978126495, + y: 190, + }, + { + isRight: true, + ns: 5255566, + offsetY: 52, + rowEL: null, + x: 235, + y: 525, + }, + ], + ]; + expect(drawLinkLines(context, nodes, timerShaftElement)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerCpuAbility.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerCpuAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec0713332c9732c4945d16a8c1d89069303dc543 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerCpuAbility.test.ts @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); +// @ts-ignore +import { + CpuAbilityMonitorStruct, + cpuAbility, + CpuAbilityRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCpuAbility.js'; +//@ts-ignore +import { Rect } from '../../../dist/trace/database/ProcedureWorkerCommon'; + +describe('CpuAbilityMonitorStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxCpuUtilization: 200, + value: 50, + }; + it('CpuAbilityMonitorStructTest01', function () { + expect(CpuAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + it('CpuAbilityMonitorStructTest03', function () { + expect(CpuAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined(); + }); + it('CpuAbilityMonitorStructTest02', function () { + let dataList = new Array(); + dataList.push({ + startNs: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNs: 1, dur: 111 }); + cpuAbility(dataList, [{ length: 0 }], 1, 100254, 100254, frame, true); + }); + + it('CpuAbilityMonitorStructTest05', function () { + let dataList = new Array(); + dataList.push({ + startNs: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNs: 1, dur: 111 }); + cpuAbility(dataList, [{ length: 0 }], 1, 100254, 100254, frame, false); + }); + + it('CpuAbilityMonitorStructTest06', function () { + let cpuAbilityRender = new CpuAbilityRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(cpuAbilityRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..769f84cd3a349db6b776965ffbbe96e4b9618941 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + CpuFreqLimitRender, + CpuFreqLimitsStruct, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCpuFreqLimits.js'; + +describe('ProcedureWorkerCpuFreqLimits Test', () => { + let cpuFreqLimits = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNs: 255, + dur: 2545, + max: 14111, + min: 200, + cpu: 10, + }; + it('Test01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNs: 54, + dur: 2453, + max: 3433, + min: 13, + cpu: 3, + }; + expect(CpuFreqLimitsStruct.draw(ctx!, data, 2)).toBeUndefined(); + }); + + it('Test02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(CpuFreqLimitsStruct.drawArcLine(ctx, cpuFreqLimits, 100, 500)).toBeUndefined(); + }); + + it('Test03', () => { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 0, + startTime: 2, + dur: 1, + }; + expect( + CpuFreqLimitsStruct.setFreqLimitFrame(node, 1, 1, 1, 1, { + width: 10, + }) + ).toBeUndefined(); + }); + + it('Test04', function () { + let cpuFreqLimitRender = new CpuFreqLimitRender(); + let req = { + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + canvas: '', + context: {}, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(cpuFreqLimitRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerCpuState.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerCpuState.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..44628852c3649faaa563c34c602bfb56590291ff --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerCpuState.test.ts @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + CpuStateRender, + CpuStateStruct, + cpuState, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCpuState.js'; + +describe('ProcedureWorkerCpuState Test', () => { + it('ProcedureWorkerCpuStateTest01', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + startTs: 1, + dur: 10, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(CpuStateStruct.setFrame(node, 2, 2, 6, 4, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerCpuStateTest01', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + startTs: 3, + dur: 1, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(CpuStateStruct.setFrame(node, 2, 2, 6, 4, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerCpuStateTest02', function () { + let cpuStateRender = new CpuStateRender(); + let node = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 0, + height: 2, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(cpuStateRender.cpuState(node, [{ length: 1 }], '', [], 4, 1, 1, frame, true)).toBeUndefined(); + }); + + it('ProcedureWorkerCpuStateTest03', function () { + let cpuStateRender = new CpuStateRender(); + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + let res = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 1, + length: 1, + height: 2, + dur: 1, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(cpuStateRender.cpuState([], dataList, '', res, 1, 6, 5, frame, true)).toBeUndefined(); + }); + + it('ProcedureWorkerCpuStateTest04', function () { + let cpuStateRender = new CpuStateRender(); + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + let res = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 10, + length: 1, + height: 2, + dur: 1, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(cpuStateRender.cpuState([], dataList, '', res, 1, 6, 5, frame, true)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b72c91314f395fcb2e43026b2b74293c599adb49 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.test.ts @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + DiskAbilityMonitorStruct, + diskIoAbility, + DiskIoAbilityRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerDiskIoAbility.js'; +//@ts-ignore +import { Rect } from '../../../dist/trace/database/ProcedureWorkerCommon'; + +describe('ProcedureWorkerDiskIoAbility Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxDiskRate: 200, + value: 50, + }; + let res = [ + { + startNS: 0, + dur: 10, + frame: { + x: 0, + y: 9, + width: 10, + height: 10, + }, + }, + ]; + + it('ProcedureWorkerDiskIoAbilityTest01', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerDiskIoAbilityTest03', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined(); + }); + it('CpuAbilityMonitorStructTest02', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 111 }); + diskIoAbility(dataList, [{ length: 1 }], 1, 100254, 100254, '', true); + }); + + it('CpuAbilityMonitorStructTest03', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 111 }); + diskIoAbility(dataList, [{ length: 0 }], 1, 100254, 100254, '', false); + }); + + it('CpuAbilityMonitorStructTest04', function () { + let diskIoAbilityRender = new DiskIoAbilityRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(diskIoAbilityRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae1d980a78554dd3d7eb4f97db2f56824ce29080 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.test.ts @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + anomaly, + EnergyAnomalyStruct, + EnergyAnomalyRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerEnergyAnomaly.js'; + +describe('ProcedureWorkerEnergyAnomaly Test', () => { + it('ProcedureWorkerEnergyAnomalyTest01', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + anomaly(dataList, [{ length: 1 }], 1, 3, 2, frame, '', true); + }); + + it('ProcedureWorkerEnergyAnomalyTest02', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + anomaly(dataList, [{ length: 0 }], 1, 3, 2, frame, '', false); + }); + + it('ProcedureWorkerEnergyAnomalyTest03', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + let path = new Path2D(); + expect(EnergyAnomalyStruct.draw(ctx, path, data)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyAnomalyTest04', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 1, + value: 50, + startTs: 3, + dur: 3, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(EnergyAnomalyStruct.setAnomalyFrame(node, 1, 2, 5, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyAnomalyTest05', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 6, + value: 50, + startTs: 3, + dur: 3, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(EnergyAnomalyStruct.setAnomalyFrame(node, 1, 2, 5, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyAnomalyTest06', function () { + let energyAnomalyRender = new EnergyAnomalyRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(energyAnomalyRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyPower.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyPower.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..81504adf0546ae4a09b07b48a381ce481fb13ad7 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyPower.test.ts @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + EnergyPowerStruct, + EnergyPowerRender, + power, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerEnergyPower.js'; + +describe('ProcedureWorkerEnergyPower Test', () => { + it('ProcedureWorkerEnergyPowerTest01', function () { + let req = { + context: { + globalAlpha: 1.0, + lineWidth: 1, + fillStyle: '#333', + }, + }; + let data = { + cpu: 1, + location: 2, + gpu: 1, + display: 1, + camera: 1, + bluetooth: 3, + flashlight: 10, + audio: 16, + wifiscan: 1, + ts: 10, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + let row = { frame: 20 }; + EnergyPowerStruct.drawHistogram = jest.fn(() => true); + EnergyPowerStruct.drawPolyline = jest.fn(() => true); + expect(EnergyPowerStruct.draw(req, 3, data, row)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyPowerTest02', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let node = { + ts: 10, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + expect(EnergyPowerStruct.setPowerFrame(node, 1, 2, 5, 3, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyPowerTest03', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let node = { + ts: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + expect(EnergyPowerStruct.setPowerFrame(node, 1, 2, 2000000002, 2000000000, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyPowerTest04', function () { + expect(EnergyPowerStruct.getHistogramColor('CPU')).toBe('#92D6CC'); + }); + + it('ProcedureWorkerEnergyPowerTest05', function () { + expect(EnergyPowerStruct.getHistogramColor('LOCATION')).toBe('#61CFBE'); + }); + + it('ProcedureWorkerEnergyPowerTest06', function () { + expect(EnergyPowerStruct.getHistogramColor('GPU')).toBe('#86C5E3'); + }); + + it('ProcedureWorkerEnergyPowerTest07', function () { + expect(EnergyPowerStruct.getHistogramColor('DISPLAY')).toBe('#46B1E3'); + }); + + it('ProcedureWorkerEnergyPowerTest08', function () { + expect(EnergyPowerStruct.getHistogramColor('CAMERA')).toBe('#C386F0'); + }); + + it('ProcedureWorkerEnergyPowerTest09', function () { + expect(EnergyPowerStruct.getHistogramColor('BLUETOOTH')).toBe('#8981F7'); + }); + + it('ProcedureWorkerEnergyPowerTest10', function () { + expect(EnergyPowerStruct.getHistogramColor('AUDIO')).toBe('#AC49F5'); + }); + + it('ProcedureWorkerEnergyPowerTest11', function () { + expect(EnergyPowerStruct.getHistogramColor('WIFISCAN')).toBe('#92C4BD'); + }); + + it('ProcedureWorkerEnergyPowerTest12', function () { + expect(EnergyPowerStruct.getHistogramColor('WIFISCANxcda')).toBe('#564AF7'); + }); + + it('ProcedureWorkerEnergyPowerTest13', function () { + expect(EnergyPowerStruct).not.toBeUndefined(); + }); + + it('ProcedureWorkerEnergyPowerTest14', function () { + let energyPowerRender = new EnergyPowerRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(energyPowerRender.render(req, [], [])).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyPowerTest15', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + power(dataList, [{ length: 1 }], 1, 3, 2, frame, true, ''); + }); + + it('ProcedureWorkerEnergyPowerTest16', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + power(dataList, [{ length: 0 }], 1, 3, 2, frame, false, ''); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyState.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyState.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f603afa6c929e787e5bf4a032f5bb6da114e8989 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergyState.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + state, + EnergyStateStruct, + EnergyStateRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerEnergyState.js'; + +describe('ProcedureWorkerEnergyState Test', () => { + it('ProcedureWorkerEnergyStateTest01', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + state(dataList, [{ length: 1 }], 1, 3, 2, frame, true); + }); + + it('ProcedureWorkerEnergyStateTest02', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + state(dataList, [{ length: 0 }], 1, 3, 2, frame, false); + }); + + it('ProcedureWorkerEnergyStateTest03', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + type: '', + value: 0, + startNs: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + expect(EnergyStateStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest04', function () { + expect(EnergyStateStruct.setDrawColor('BRIGHTNESS_NIT')).toBe('#92D6CC'); + }); + + it('ProcedureWorkerEnergyStateTest05', function () { + expect(EnergyStateStruct.setDrawColor('SIGNAL_LEVEL')).toBe('#61CFBE'); + }); + + it('ProcedureWorkerEnergyStateTest06', function () { + expect(EnergyStateStruct.setDrawColor('WIFI_EVENT_RECEIVED')).toBe('#46B1E3'); + }); + + it('ProcedureWorkerEnergyStateTest07', function () { + expect(EnergyStateStruct.setDrawColor('AUDIO_STREAM_CHANGE')).toBe('#ED6F21'); + }); + + it('ProcedureWorkerEnergyStateTest08', function () { + expect(EnergyStateStruct.setDrawColor('WIFI_STATE')).toBe('#61CFBE'); + }); + + it('ProcedureWorkerEnergyStateTest09', function () { + expect(EnergyStateStruct.setDrawColor('LOCATION_SWITCH_STATE')).toBe('#61CFBE'); + }); + + it('ProcedureWorkerEnergyStateTest10', function () { + expect(EnergyStateStruct.setDrawColor('SENSOR_STATE')).toBe('#61CFBE'); + }); + + it('ProcedureWorkerEnergyStateTest11', function () { + expect(EnergyStateStruct.setDrawColor('aaaa')).toBe('#61CFBE'); + }); + + it('ProcedureWorkerEnergyStateTest12', function () { + let energyStateRender = new EnergyStateRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + height: 150, + width: 100, + }, + lineColor: '', + isHover: '', + hoverX: 1, + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + params: { + isLive: false, + maxHeight: 2, + dpr: 1, + hoverFuncStruct: '', + selectFuncStruct: undefined, + }, + }; + window.postMessage = jest.fn(() => true); + expect(energyStateRender.render(req, [{}], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerEnergySystem.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergySystem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae1918d81e15e14d6414555eb989b40315f12411 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerEnergySystem.test.ts @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + system, + EnergySystemStruct, + EnergySystemRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerEnergySystem.js'; + +describe('ProcedureWorkerEnergySystem Test', () => { + it('ProcedureWorkerEnergySystemTest01', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startNs: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNs: 1, dur: 2, length: 1 }); + system(dataList, [{ length: 1 }], 1, 3, 2, frame, true); + }); + + it('ProcedureWorkerEnergySystemTest02', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + + let aa: any = []; + let dataList = new Array(); + dataList.push({ + startNs: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNs: 1, dur: 2 }); + aa[0] = dataList; + aa[1] = dataList; + aa[2] = dataList; + system(aa, [], 1, 3, 2, frame, false); + }); + + it('ProcedureWorkerEnergyStateTest04', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + type: 0, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + expect(EnergySystemStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest05', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + type: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + expect(EnergySystemStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest06', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + type: 2, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }; + expect(EnergySystemStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest07', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 1, + value: 50, + startTs: 3, + dur: 3, + height: 2, + type: 0, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(EnergySystemStruct.setSystemFrame(node, 1, 1, 3, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest08', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 3, + value: 50, + startTs: 3, + dur: 3, + height: 2, + type: 1, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(EnergySystemStruct.setSystemFrame(node, 1, 2, 3, 1, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest09', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 1, + value: 50, + startTs: 3, + dur: 3, + height: 2, + type: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(EnergySystemStruct.setSystemFrame(node, 1, 1, 3, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerEnergyStateTest10', function () { + let energySystemRender = new EnergySystemRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + height: 150, + width: 100, + }, + lineColor: '', + isHover: '', + hoverX: 1, + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + params: { + isLive: false, + maxHeight: 2, + dpr: 1, + hoverFuncStruct: '', + selectFuncStruct: undefined, + }, + }; + window.postMessage = jest.fn(() => true); + expect(energySystemRender.render(req, [{}], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerFPS.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerFPS.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..03b20c15b71146c6a0b805be22512ee1c99a9492 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerFPS.test.ts @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { fps, FpsStruct, FpsRender } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerFPS.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe(' FPSTest', () => { + it('FpsTest01', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + fps(dataList, [{ length: 1 }], 1, 100254, 100254, rect, true); + }); + + it('FpsTest02', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + dur: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + fps(dataList, [{ length: 0 }], 1, 100254, 100254, rect, false); + }); + + it('FpsTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + + expect(FpsStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('FpsTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + new FpsStruct(1); + FpsStruct.hoverFpsStruct = jest.fn(() => { + startNS: 200; + }); + FpsStruct.a = jest.fn(() => data); + expect(FpsStruct.draw(ctx, data)).toBeUndefined(); + }); + it('FpsTest05 ', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const Sourcedate = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxFps: 200, + value: 50, + }; + expect(FpsStruct.draw(ctx, Sourcedate)).toBeUndefined(); + }); + + it('FpsTest06', function () { + let fpsRender = new FpsRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + height: 150, + width: 100, + }, + lineColor: '', + isHover: '', + hoverX: 1, + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + params: { + isLive: false, + maxHeight: 2, + dpr: 1, + hoverFuncStruct: '', + selectFuncStruct: undefined, + }, + }; + window.postMessage = jest.fn(() => true); + expect(fpsRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerFileSystem.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerFileSystem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..19b58568933235533a4e236afaccf60262f2fe52 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerFileSystem.test.ts @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + fileSysChart, + FileSysChartStruct, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerFileSystem.js'; + +describe('ProcedureWorkerFileSystem Test', () => { + it('ProcedureWorkerFileSystemTest01', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(fileSysChart([], [{ length: 1 }], '', [{ length: 1 }], 1, 2, 1, frame, true, true, true)).toBeUndefined(); + }); + + it('ProcedureWorkerFileSystemTest02', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(fileSysChart([], [{ length: 1 }], '', [{ length: 0 }], 1, 2, 1, frame, false, false, false)).toBeUndefined(); + }); + + it('ProcedureWorkerFileSystemTest03', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 1 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + fileSysChart(dataList, dataList, '', [{ length: 0 }], 1, 2, 1, frame, true, false, false); + }); + + it('ProcedureWorkerFileSystemTest03', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 0 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + fileSysChart(dataList, dataList, '', [{ length: 0 }], 1, 2, 1, frame, true, false, false); + }); + + it('ProcedureWorkerFileSystemTest04', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 0, + value: 50, + startTs: 3, + dur: 1, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(FileSysChartStruct.setFrame(node, 2, 1, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerFileSystemTest05', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 2, + value: 50, + startTs: 3, + dur: 3, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(FileSysChartStruct.setFrame(node, 2, 1, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerFileSystemTest06', function () { + expect(FileSysChartStruct.computeHeightNoGroup([{ length: 1 }], 10)).toEqual([ + { + dur: 10, + group10Ms: false, + height: 18, + size: 1, + startNS: 0, + }, + { dur: 0, group10Ms: false, height: 0, size: 0, startNS: 10 }, + ]); + }); + + it('ProcedureWorkerFileSystemTest07', function () { + expect(FileSysChartStruct.groupBy10MSWithMaxLatency([{ id: 1, NS: 3 }, { copy: '1' }])).toEqual([ + { + dur: 10000000, + height: NaN, + startNS: NaN, + group10Ms: true, + size: undefined, + }, + ]); + }); + + it('ProcedureWorkerFileSystemTest08', function () { + expect(FileSysChartStruct.groupBy10MSWithCount([{ id: 1, NS: 3 }, { copy: '1' }])).toEqual([ + { + dur: 10000000, + height: 36, + startNS: NaN, + group10Ms: true, + size: 2, + }, + ]); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerFreq.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerFreq.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc07c94cf02afafc83c846d28b8c972854e152ac --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerFreq.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { CpuFreqStruct, FreqRender, freq } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerFreq.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe('freqTest', () => { + it('freqTest01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + + expect(CpuFreqStruct.draw(ctx, data)).toBeUndefined(); + }); + it('freqTest02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxFreq: 200, + value: 50, + }; + expect(CpuFreqStruct.draw(ctx, Sourcedata)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerFunc.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerFunc.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..cba31a609cd75006e6e4d7990ce7477ea13ac545 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerFunc.test.ts @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { func, FuncStruct, FuncRender } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerFunc.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; +import { markAsUntransferable } from 'worker_threads'; + +describe(' ProcedureWorkerFuncTest', () => { + it('FuncTest01', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + let res = [ + { + startTs: 0, + dur: 10, + length: 1, + frame: '', + }, + ]; + func(dataList, res, 1, 100254, 100254, rect, true); + }); + + it('FuncTest02', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + dur: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + let res = [ + { + startTs: 0, + dur: 10, + length: 0, + frame: '', + }, + ]; + func(dataList, res, 1, 100254, 100254, rect, false); + }); + + it('FuncTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + dur: undefined || null || 0, + }; + expect(FuncStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('FuncTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + dur: 10, + }; + expect(FuncStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('FuncTest05', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let func = { + textMetricsWidth:1 + } + FuncStruct.drawString(ctx, '1', 1, new Rect(0, 0, 100, 100),func); + }); + + it('FuncTest06', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let func = { + textMetricsWidth:1 + } + FuncStruct.drawString(ctx, '1', 2, new Rect(1, 1, 150, 150),func); + }); + + it('FuncTest07', function () { + let str = ''; + expect(FuncStruct.isBinder({})).toBe(false); + }); + + it('FuncTest08', function () { + let data = { + startTs: 2, + depth: 1, + }; + expect(FuncStruct.isSelected(data)).toBe(false); + }); + + it('FuncTest09', function () { + let funcRender = new FuncRender(); + let req = { + lazyRefresh: undefined, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + height: 150, + width: 100, + }, + lineColor: '', + isHover: '', + hoverX: 1, + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + params: { + isLive: false, + maxHeight: 2, + dpr: 1, + hoverFuncStruct: '', + selectFuncStruct: undefined, + }, + }; + window.postMessage = jest.fn(() => true); + expect(funcRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHeap.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHeap.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d6cc4102ad019a62607dff20a9ba179fae346f2 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHeap.test.ts @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + heap, + HeapStruct, + NativeMemoryRender, + HeapRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHeap.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe(' Test', () => { + it('HeapTest01', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + let res = [ + { + startTs: 0, + dur: 10, + length: 1, + frame: '', + }, + ]; + heap(dataList, res, 1, 100254, 100254, rect, true); + }); + + it('HeapTest02', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + dur: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + let res = [ + { + startTs: 0, + dur: 10, + length: 0, + frame: '', + }, + ]; + heap(dataList, res, 1, 100254, 100254, rect, false); + }); + + it('HeapTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + expect(HeapStruct.draw(ctx, data)).toBeUndefined(); + }); + it('HeapTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxHeapSize: 200, + value: 50, + }; + expect(HeapStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('HeapTest05', function () { + let nativeMemoryRender = new HeapRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(nativeMemoryRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..48f87a9ac1cfe8da8be2d12148433cf7c6807963 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.test.ts @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { TraceRow } from '../../../../dist/trace/component/trace/base/TraceRow.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; +// @ts-ignore +import { HeapSnapshot, HeapSnapshotRender, HeapSnapshotStruct} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHeapSnapshot.js'; + +describe('ProcedureWorkerHeapTimeline Test', () => { + it('HeapSnapshotTest', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + let filter = [ + { + end_time: 50, + end_ts: 1520000, + file_name: 'Snapshot0', + frame: { x: 0, y: 0, width: 25, height: 40 }, + id: 0, + pid: 4243, + start_time: 0, + start_ts: 88473061693464, + textMetricsWidth: 50.5810546875, + }, + ]; + let list = [ + { + end_time: 50, + end_ts: 1520000, + file_name: 'Snapshot0', + frame: { x: 0, y: 0, width: 6222, height: 62222 }, + id: 0, + pid: 4243, + start_time: 0, + start_ts: 88473061693464, + textMetricsWidth: 50.5810546875, + }, + ]; + HeapSnapshot(list, filter, 100254, 100254, rect, { height: 40, width: 1407, x: 0, y: 0 }); + }); + + it('HeapSnapshotStructTest01', () => { + const data = { + cpu: 1, + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxValue: undefined, + startTime: 1, + filterID: 2, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HeapSnapshotStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('HeapSnapshotStructTest02', () => { + const data = { + cpu: 1, + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxValue: undefined, + startTime: 1, + filterID: 2, + }; + let node = { + start_time: 1, + end_time: 2, + frame: null, + }; + expect(HeapSnapshotStruct.setFrame(node, 0, 1, 2, data)).toBeUndefined(); + }); + + it('HeapSnapshotRenderTest03', () => { + let canvas = document.createElement('canvas') as HTMLCanvasElement; + let context = canvas.getContext('2d'); + const data = { + context: context!, + useCache: true, + type: '', + traceRange: [], + }; + let heapSnapshotRender = new HeapSnapshotRender(); + expect(heapSnapshotRender.renderMainThread(data, new TraceRow())).toBeUndefined(); + }); + it('HeapSnapshotStructTest04', () => { + expect(HeapSnapshotStruct).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHeapTimeline.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHeapTimeline.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..13c06c1c95b4d54b350df72d33ef20eca4efce6f --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHeapTimeline.test.ts @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; +// @ts-ignore +import { + HeapTimelineRender, + HeapTimelineStruct, + HeapTimeline, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHeapTimeline.js'; + +describe('ProcedureWorkerHeapTimeline Test', () => { + it('HeapTimelineTest', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + HeapTimeline(canvas, ctx, 1, 100254, 100254, rect, (e: any) => {}); + }); + it('HeapTimelineStructTest01', () => { + const data = { + cpu: 1, + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxValue: undefined, + startTime: 1, + filterID: 2, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HeapTimelineStruct.draw(ctx, data)).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..83cf6b4c08800202f5dd41c0242990a9fa0684b8 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.test.ts @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +//@ts-ignore +import { hiPerfCpu, HiPerfCpuStruct } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHiPerfCPU.js'; + +describe('ProcedureWorkerHiPerfCPU Test', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + it('ProcedureWorkerHiPerfCPUTest01', () => { + const data = { + frame: undefined, + cpu: 1, + startNs: 1, + value: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfCpuStruct.draw(ctx, '', data, true)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfCPUTest02', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + let res = [ + { + length: 1, + }, + ]; + hiPerfCpu(dataList, [{ length: 1 }], '1', res, 3, 6, 3, frame, true, 1, 2, true); + }); + + it('ProcedureWorkerHiPerfCPUTest03', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + let res = [ + { + length: 0, + }, + ]; + hiPerfCpu(dataList, [{ length: 1 }], '1', res, 3, 6, 3, frame, false, 1, 2, false); + }); + + it('ProcedureWorkerHiPerfCPUTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfCpuStruct.drawRoundRectPath(ctx, 1, 1, 1, 1, 1)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfCPUTest05', function () { + expect(HiPerfCpuStruct.groupBy10MS([{ id: 1, NS: 3 }, { copy: '1' }], 10, '')).toEqual([ + { dur: 10000000, height: 0, startNS: NaN }, + ]); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9479ecce565c2a2df9e1b753cd1d403742a5f761 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.test.ts @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + HiPerfEvent, + HiPerfEventStruct, + HiperfEventRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHiPerfEvent.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCommon'; + +describe('ProcedureWorkerHiPerfEvent Test', () => { + it('ProcedureWorkerHiPerfEventTest01', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let dataList2 = new Array(); + dataList2.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 1 }, + }); + dataList2.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + HiPerfEvent(dataList, dataList2, '', [{ length: 1 }], 1, 1024, 1024, frame, true, 1, true); + }); + + it('ProcedureWorkerHiPerfEventTest02', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let dataList2 = new Array(); + dataList2.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 1 }, + }); + dataList2.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + HiPerfEvent(dataList, dataList2, '', [{ length: 0 }], 1, 1024, 1024, frame, true, 1, false); + }); + + it('ProcedureWorkerHiPerfEventTest03', () => { + const data = { + frame: { + x: 0, + y: 9, + width: 10, + height: 10, + }, + cpu: 1, + startNs: 1, + value: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfEventStruct.drawRoundRectPath(ctx, 1, 0, 10, 10, 12)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfEventTest04', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 0, + value: 50, + startTs: 3, + dur: 1, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(HiPerfEventStruct.setFrame(node, 2, 1, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfEventTest05', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 2, + value: 50, + startTs: 3, + dur: 3, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(HiPerfEventStruct.setFrame(node, 2, 1, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfEventTest06', function () { + expect(HiPerfEventStruct.groupBy10MS([{ ps: 1 }, { coX: '1' }], 10, '')).toEqual([ + { dur: 10000000, height: NaN, max: 0, startNS: NaN, sum: NaN }, + ]); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..db4b7419b489eef386f0c7d11f5c89e0ac245e30 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.test.ts @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +//@ts-ignore +import { + hiPerfProcess, + HiPerfProcessStruct, + HiperfProcessRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHiPerfProcess.js'; + +describe('ProcedureWorkerHiPerfProcess Test', () => { + it('ProcedureWorkerHiPerfProcessTest01', () => { + const data = { + frame: undefined, + cpu: 1, + startNs: 1, + value: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfProcessStruct.draw(ctx, '', data, true)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfProcessTest02', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + hiPerfProcess(dataList, [{ length: 0 }], dataList, 8, 3, '', true, 1, true); + }); + + it('ProcedureWorkerHiPerfProcessTest03', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + hiPerfProcess(dataList, [{ length: 0 }], dataList, 8, 3, '', false, 1, false); + }); + + it('ProcedureWorkerHiPerfProcessTest04', function () { + expect(HiPerfProcessStruct.groupBy10MS([{ a: '1', b: 2, c: 3 }], 10)).toEqual([ + { dur: 10000000, height: 40, startNS: NaN }, + ]); + }); + + it('ProcedureWorkerHiPerfProcessTest05', function () { + let hiperfProcessRender = new HiperfProcessRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + scale: 100_000_001, + }; + window.postMessage = jest.fn(() => true); + expect(hiperfProcessRender.render(req, [], [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfReport.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfReport.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..58593ac551ccb8ed91b4694a209817c7b4185b0b --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfReport.test.ts @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + HiPerfReport, + HiPerfReportStruct, + HiperfReportRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHiPerfReport.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerCommon'; +import { TraceRow } from '../../../../dist/trace/component/trace/base/TraceRow.js'; + +describe('ProcedureWorkerHiPerfReport Test', () => { + it('ProcedureWorkerHiPerfReportTest01', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let dataList2 = new Array(); + dataList2.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 1 }, + }); + dataList2.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + HiPerfReport(dataList, dataList2, '', [{ length: 1 }], 1, 1024, 1024, frame, true, 1, true); + }); + + it('ProcedureWorkerHiPerfReportTest02', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + dur: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + let dataList2 = new Array(); + dataList2.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 1 }, + }); + dataList2.push({ startTime: 1, dur: 111 }); + HiPerfReport(dataList, dataList2, '', [{ length: 0 }], 1, 1024, 1024, frame, true, 1, false); + }); + + it('ProcedureWorkerHiPerfReportTest07', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + dur: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + let dataList2 = new Array(); + dataList2.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 1 }, + }); + dataList2.push({ startTime: 1, dur: 111 }); + HiPerfReport(dataList, dataList2, '', [{ length: 0 }], 1, 1024, 1024, frame, false, 1, false); + }); + + it('ProcedureWorkerHiPerfReportTest03', () => { + const data = { + frame: { + x: 0, + y: 9, + width: 10, + height: 10, + }, + cpu: 1, + startNs: 1, + value: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfReportStruct.drawRoundRectPath(ctx, 1, 0, 10, 10, 12)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfReportTest04', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 0, + value: 50, + startTs: 3, + dur: 1, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(HiPerfReportStruct.setFrame(node, 2, 1, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfReportTest05', function () { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 2, + value: 50, + startTs: 3, + dur: 3, + height: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(HiPerfReportStruct.setFrame(node, 2, 1, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfReportTest06', function () { + expect(HiPerfReportStruct.groupBy10MS([{ ps: 1 }, { coX: '1' }], 10, '')).toEqual([ + { dur: 10000000, height: NaN, startNS: NaN, sum: NaN }, + ]); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfThread.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2547ae734b6b188c2ec6aae8f2edd72083532d56 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerHiPerfThread.test.ts @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +//@ts-ignore +import { + hiPerfThread, + HiperfThreadRender, + HiPerfThreadStruct, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerHiPerfThread.js'; + +describe('ProcedureWorkerHiPerfThread Test', () => { + let res = [ + { + startNS: 0, + dur: 10, + frame: { + x: 0, + y: 9, + width: 10, + height: 10, + }, + }, + ]; + it('ProcedureWorkerHiPerfThreadTest01', () => { + const data = { + frame: undefined, + cpu: 1, + startNs: 1, + value: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfThreadStruct.draw(ctx, '', data, true)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfThreadTest02', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + hiPerfThread(dataList, [{ length: 0 }], dataList, 8, 3, frame, false, 1, false); + }); + + it('ProcedureWorkerHiPerfThreadTest03', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + length: 1, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2, length: 1 }); + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + hiPerfThread(dataList, [{ length: 1 }], dataList, 8, 3, frame, true, 1, true); + }); + + it('ProcedureWorkerHiPerfThreadTest04', function () { + expect(HiPerfThreadStruct.groupBy10MS([{ ps: 1 }, { coX: '1' }], 10, '')).toEqual([ + { dur: 10000000, height: 80, startNS: NaN }, + ]); + }); + + it('ProcedureWorkerHiPerfThreadTest05', function () { + let hiperfThreadRender = new HiperfThreadRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + scale: 100_000_001, + }; + window.postMessage = jest.fn(() => true); + let a = { + dataList: [ + { + callchain_id: 1329, + thread_name: 'uinput_inject', + tid: 247, + pid: 247, + startNS: 1179247952, + timestamp_group: 1170000000, + }, + { + callchain_id: 1330, + thread_name: 'uinput_inject', + tid: 247, + pid: 247, + startNS: 1179308910, + timestamp_group: 1170000000, + }, + ], + }; + + expect(hiperfThreadRender.render(req, [], [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerIrq.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerIrq.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..570e756ad9bb7e7d0faa132362fef2bb26d8fcab --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerIrq.test.ts @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { IrqRender, IrqStruct } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerIrq.js'; + +describe('ProcedureWorkerIrq Test', () => { + it('ProcedureWorkerIrq01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + id: 155, + startNS: 1745, + name: '4515', + dur: 4555, + argSetId: 10, + }; + expect(IrqStruct.draw(ctx!, data, true)).toBeUndefined(); + }); + + it('ProcedureWorkerIrq02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let data = {textMetricsWidth: 1} + expect( + IrqStruct.drawString(ctx, '253', 2, { + x: 20, + y: 20, + width: 100, + height: 100, + },data) + ).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerJank.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerJank.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e85e5209a637720b89ddb41f1a09f01a0941307 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerJank.test.ts @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2022 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. + */ +// @ts-ignore +import { TraceRow } from '../../../../dist/trace/component/trace/base/TraceRow.js'; +// @ts-ignore +import { jank, JankRender, JankStruct } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerJank.js'; +// @ts-ignore +import { ColorUtils } from '../../../../dist/trace/component/trace/base/ColorUtils.js'; + +describe('ProcedureWorkerJank Test', () => { + const jankData = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + id: 35, + ts: 42545, + dur: 2015, + name: '2145', + depth: 1, + jank_tag: false, + cmdline: 'render.test', + type: '1', + pid: 20, + frame_type: 'render_service', + src_slice: '525', + rs_ts: 2569, + rs_vsync: '2569', + rs_dur: 1528, + rs_pid: 1252, + rs_name: 'name', + gpu_dur: 2568, + }; + let render = new JankRender(); + + it('ProcedureWorkerJank01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + id: 25, + ts: 254151, + dur: 1202, + name: '1583', + depth: 1, + jank_tag: true, + cmdline: 'render.test', + type: '0', + pid: 20, + frame_type: 'render_service', + src_slice: '525', + rs_ts: 2569, + rs_vsync: '2569', + rs_dur: 1528, + rs_pid: 1252, + rs_name: 'name', + gpu_dur: 2568, + }; + expect(JankStruct.draw(ctx!, data, 2)).toBeUndefined(); + }); + + it('ProcedureWorkerJank02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(JankStruct.draw(ctx!, jankData, 2)).toBeUndefined(); + }); + + it('ProcedureWorkerJank09', function () { + let node = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 2, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let list = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 2, + height: 2, + }, + ]; + jank(list, node, 1, 1, 1, frame, true); + }); + + it('ProcedureWorkerJank10', function () { + let node = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 2, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let list = [ + { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 2, + height: 2, + }, + ]; + jank(list, node, 1, 1, 1, frame, false); + }); + + it('ProcedureWorkerJank11', () => { + let node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + length: 1, + height: 0, + startTime: 0, + dur: 1, + }; + expect(JankStruct.setJankFrame(node, 1, 1, 1, 10, { width: 10 })).toBeUndefined(); + }); + + it('ProcedureWorkerJank12', () => { + let canvas = document.createElement('canvas') as HTMLCanvasElement; + let context = canvas.getContext('2d'); + TraceRow.range = { + startNS: 3206163251057, + endNS: 3215676817201, + totalNS: 9513566144, + }; + new JankRender().renderMainThread( + { + context: context!, + useCache: false, + type: `expected_frame_timeline_slice`, + }, + { + dataList: [ + { + id: 7, + frame_type: 'frameTime', + ipid: 84, + name: 36691, + app_dur: 16616797, + dur: 33234127, + ts: 15038992, + type: 1, + flag: null, + pid: 3420, + cmdline: 'com.huawei.wx', + rs_ts: 31656322, + rs_vsync: 28323, + rs_dur: 16616797, + rs_ipid: 25, + rs_pid: 1263, + rs_name: 'render_service', + depth: 0, + frame: { + x: 2, + y: 0, + width: 5, + height: 20, + }, + }, + { + id: 11, + frame_type: 'frameTime', + ipid: 84, + name: 36692, + app_dur: 16616797, + dur: 33233901, + ts: 31656322, + type: 1, + flag: null, + pid: 3420, + cmdline: 'com.huawei.wx', + rs_ts: 48273426, + rs_vsync: 28324, + rs_dur: 16616797, + rs_ipid: 25, + rs_pid: 1263, + rs_name: 'render_service', + depth: 1, + frame: { + x: 4, + y: 20, + width: 5, + height: 20, + }, + }, + { + id: 13, + frame_type: 'frameTime', + ipid: 84, + name: 36693, + app_dur: 16616797, + dur: 33233626, + ts: 48273426, + type: 1, + flag: null, + pid: 3420, + cmdline: 'com.huawei.wx', + rs_ts: 64890255, + rs_vsync: 28325, + rs_dur: 16616797, + rs_ipid: 25, + rs_pid: 1263, + rs_name: 'render_service', + depth: 0, + frame: { + x: 6, + y: 0, + width: 5, + height: 20, + }, + }, + ], + dataListCache: [ + { + id: 7, + frame_type: 'frameTime', + ipid: 84, + name: 36691, + app_dur: 16616797, + dur: 33234127, + ts: 15038992, + type: 1, + flag: null, + pid: 3420, + cmdline: 'com.huawei.wx', + rs_ts: 31656322, + rs_vsync: 28323, + rs_dur: 16616797, + rs_ipid: 25, + rs_pid: 1263, + rs_name: 'render_service', + depth: 0, + frame: { + x: 2, + y: 0, + width: 5, + height: 20, + }, + }, + { + id: 11, + frame_type: 'frameTime', + ipid: 84, + name: 36692, + app_dur: 16616797, + dur: 33233901, + ts: 31656322, + type: 1, + flag: null, + pid: 3420, + cmdline: 'com.huawei.wx', + rs_ts: 48273426, + rs_vsync: 28324, + rs_dur: 16616797, + rs_ipid: 25, + rs_pid: 1263, + rs_name: 'render_service', + depth: 1, + frame: { + x: 4, + y: 20, + width: 5, + height: 20, + }, + }, + { + id: 13, + frame_type: 'frameTime', + ipid: 84, + name: 36693, + app_dur: 16616797, + dur: 33233626, + ts: 48273426, + type: 1, + flag: null, + pid: 3420, + cmdline: 'com.huawei.wx', + rs_ts: 64890255, + rs_vsync: 28325, + rs_dur: 16616797, + rs_ipid: 25, + rs_pid: 1263, + rs_name: 'render_service', + depth: 0, + frame: { + x: 6, + y: 0, + width: 5, + height: 20, + }, + }, + ], + } + ); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerMem.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerMem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf88ca5dd7eaf5c96d655e6d972329b8bb32ec4d --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerMem.test.ts @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { mem, ProcessMemStruct, MemRender } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerMem.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe(' Test', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + it('MemTest01', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + duration: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + duration: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + mem(dataList, [{ length: 0 }], 2, 100254, 100254, frame, false); + }); + + it('MemTest02', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + duration: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + duration: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + mem(dataList, [{ length: 0 }], 2, 100254, 100254, frame, true); + }); + + it('MemTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + expect(ProcessMemStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('MemTest04', function () { + let memRender = new MemRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(memRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerMemoryAbility.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerMemoryAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..95116aaa87e2a74af64193536babdd99368f20cd --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerMemoryAbility.test.ts @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +//@ts-ignore +import { + memoryAbility, + MemoryAbilityMonitorStruct, + MemoryAbilityRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerMemoryAbility.js'; + +describe('ProcedureWorkerMemoryAbility Test', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + it('ProcedureWorkerMemoryAbilityTest01', () => { + const data = { + frame: { + width: 10, + height: 10, + x: 1, + y: 1, + }, + cpu: 1, + startNs: 1, + value: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(MemoryAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerMemoryAbilityTest02', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2 }); + memoryAbility(dataList, [{ length: 0 }], 1, 8, 3, frame, true); + }); + + it('ProcedureWorkerMemoryAbilityTest02', function () { + let dataList = new Array(); + dataList.push({ + startNS: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startNS: 1, dur: 2 }); + memoryAbility(dataList, [{ length: 0 }], 1, 8, 3, frame, false); + }); + + it('ProcedureWorkerMemoryAbilityTest03', function () { + let memoryAbilityRender = new MemoryAbilityRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(memoryAbilityRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerNetworkAbility.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerNetworkAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa3ad2e2b5991df519e336ec45dc5f368733ac0e --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerNetworkAbility.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +//@ts-ignore +import { + NetworkAbilityMonitorStruct, + NetworkAbilityRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerNetworkAbility.js'; + +describe('ProcedureWorkerNetworkAbility Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 2, + y: 2, + width: 10, + height: 10, + }, + startNS: 21, + value: 5, + }; + let res = [ + { + startNS: 0, + dur: 10, + frame: { + x: 0, + y: 9, + width: 10, + height: 10, + }, + }, + ]; + + it('ProcedureWorkerNetworkAbilityTest01', function () { + expect(NetworkAbilityMonitorStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerNetworkAbilityTest02', function () { + let networkAbilityRender = new NetworkAbilityRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(networkAbilityRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerPerfCallchains.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerPerfCallchains.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2637be913b7cc5fa7195044fc451778f186dc723 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerPerfCallchains.test.ts @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { + PerfCallChainThread, + PerfCallChainPool, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerPerfCallchains.js'; + +describe('ProcedureWorkerPerfCallchains Test', () => { + it('ProcedureWorkerPerfCallchainsTest01', () => { + expect(PerfCallChainPool).not.toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerProcess.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerProcess.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e51ff17bf5d935baf241d8e7e6df46056b241ea --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerProcess.test.ts @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + proc, + ProcessStruct, + ProcessRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerProcess.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe(' ProcessTest', () => { + let res = [ + { + startNS: 0, + dur: 10, + frame: { + x: 0, + y: 9, + width: 10, + height: 10, + }, + }, + ]; + it('ProcessTest01', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + proc(dataList, res, 1, 100254, 100254, rect); + }); + + it('ProcessTest02', () => { + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ + startTime: 1, + dur: 111, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + let rect = new Rect(0, 10, 10, 10); + proc(dataList, res, 1, 100254, 100254, rect); + }); + + it('ProcessTest04', () => { + const node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + startTime: 0, + dur: 0, + }; + const frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(ProcessStruct.setFrame(node, 1, 1, 1, frame)).toBeUndefined(); + }); + + it('ProcessTest05', () => { + const node = { + frame: { + x: 20, + y: 20, + width: 0, + height: 100, + }, + startNS: 200, + value: 50, + startTime: 2, + dur: 2, + }; + const frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(ProcessStruct.setFrame(node, 1, 1, 1, frame)).toBeUndefined(); + }); + + it('ProcessTest06', function () { + let processRender = new ProcessRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(processRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerSmaps.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerSmaps.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..54017383bbc8493aac90651216d88fbe24e7b52e --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerSmaps.test.ts @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { smaps, SmapsRender, SmapsStruct } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerSmaps.js'; + +describe('ProcedureWorkerSmaps Test', () => { + it('ProcedureWorkerSmapsTest01', function () { + let List = [ + { + length: 1, + ts: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }, + ]; + let arr = [ + { + frame: null, + length: 1, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(smaps(List, arr, 1, 1, 1, frame, true)).toBeUndefined(); + }); + + it('ProcedureWorkerSmapsTest02', function () { + let List = [ + { + length: 1, + ts: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }, + ]; + let arr = [ + { + frame: null, + length: 0, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(smaps(List, arr, 1, 1, 1, frame, false)).toBeUndefined(); + }); + + it('ProcedureWorkerSmapsTest03', () => { + const data = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startTime: 1, + ts: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(SmapsStruct.draw(ctx, data, 1)).toBeUndefined(); + }); + + it('ProcedureWorkerSmapsTest04', () => { + let node = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + ts: 1, + dur: 1, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(SmapsStruct.setSmapsFrame(node, 2, 1, 2, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerSmapsTest05', () => { + let node = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + ts: 0, + dur: 3, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(SmapsStruct.setSmapsFrame(node, 2, 1, 2, 2, frame)).toBeUndefined(); + }); + + it('ProcedureWorkerSmapsTest06', function () { + let sMapsRender = new SmapsRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ffffff', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: true, + hoverX: 1, + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + params: { + maxValue: 10, + maxValueName: 'maxValueName', + rowName: 'rowName', + }, + }; + window.postMessage = jest.fn(() => true); + expect(sMapsRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerThread.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5fcc3df8a0a248f9eb9acbdeee46d664a32de1b9 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerThread.test.ts @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { thread, ThreadStruct, ThreadRender } from '../../../../dist/trace/database/ui-worker/ProcedureWorkerThread.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe('ProcedureWorkerThread Test', () => { + let frame = { + x: 0, + y: 9, + width: 10, + height: 10, + }; + + it('ProcedureWorkerThreadTest01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + }; + expect(ThreadStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerThreadTest02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + state: 'S', + }; + expect(ThreadStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerThreadTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + state: 'R', + }; + expect(ThreadStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerThreadTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + state: 'D', + }; + expect(ThreadStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerThreadTest05', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + state: 'Running', + }; + expect(ThreadStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerThreadTest06', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startNS: 200, + value: 50, + state: 'T', + }; + expect(ThreadStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerThreadTest07', () => { + const d1 = { + cpu: 1, + tid: 1, + state: '', + startTime: 1, + dur: 1, + }; + const d2 = { + cpu: 1, + tid: 1, + state: '', + startTime: 1, + dur: 1, + }; + expect(ThreadStruct.equals(d1, d2)).toBeTruthy(); + }); + + it('ProcedureWorkerThreadTest08', function () { + let threadRender = new ThreadRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(threadRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerTimeline.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerTimeline.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4575839407617044ed3b306f2c2ad93654fc8b1 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerTimeline.test.ts @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + RangeRuler, + SportRuler, + timeline, + TimelineRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerTimeline.js'; +// @ts-ignore +import { Rect } from '../../../../dist/trace/component/trace/timer-shaft/Rect.js'; + +describe(' ProcedureWorkerTimelineTest', () => { + it('timelineTest', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + let rect = new Rect(0, 10, 10, 10); + timeline(canvas, ctx, 1, 100254, 100254, rect, null, null, null, null, null, null, 0, 0, (e: any) => {}); + }); + + it('SportRulerTest01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect = new Rect(0, 10, 10, 10); + let sportRuler = new SportRuler(canvas, ctx, rect); + sportRuler.modifyFlagList('amend'); + sportRuler.modifyFlagList('remove'); + sportRuler.drawTheFlag(0, '#999999', false, ''); + sportRuler.randomRgbColor(); + sportRuler.mouseMove(new MouseEvent('')); + sportRuler.mouseUp(new MouseEvent('')); + sportRuler.onFlagRangeEvent('1', 2); + }); + + it('SportRulerTest02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect = new Rect(0, 10, 10, 10); + let rangeRuler = new RangeRuler( + canvas, + ctx, + rect, + { + startX: 0, + endX: rect.width, + startNS: 0, + endNS: 111, + totalNS: 111, + xs: [], + xsTxt: [], + }, + (a: any) => {} + ); + rangeRuler.draw(); + rangeRuler.drawCpuUsage(); + rangeRuler.mouseDown({ offsetX: 1, offsetY: 1 }); + rangeRuler.mouseUp(new MouseEvent('')); + rangeRuler.mouseMove(new MouseEvent('')); + rangeRuler.mouseOut(new MouseEvent('')); + rangeRuler.range.startNS = -2; + rangeRuler.range.endNS = -2; + rangeRuler.range.totalNS = -7; + rangeRuler.fillX(); + rangeRuler.keyPress(new KeyboardEvent('')); + rangeRuler.pressFrameId != -1; + rangeRuler.keyUp(new KeyboardEvent('')); + rangeRuler.keyUp({ key: 'w' }); + rangeRuler.keyUp({ key: 's' }); + rangeRuler.keyUp({ key: 'a' }); + rangeRuler.keyUp({ key: 'd' }); + }); + + it('SportRulerTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect = new Rect(0, 10, 10, 10); + let rangeRuler = new RangeRuler( + canvas, + ctx, + rect, + { + startX: 0, + endX: rect.width, + startNS: 0, + endNS: 111, + totalNS: 111, + xs: [], + xsTxt: [], + }, + (a: any) => {} + ); + rangeRuler.cpuUsage = true; + expect(rangeRuler.cpuUsage).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProcedureWorkerVirtualMemory.test.ts b/ide/test/trace/database/ui-worker/ProcedureWorkerVirtualMemory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..25c7d12e9f9c62c708f789c9f1d7e947878ecd68 --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProcedureWorkerVirtualMemory.test.ts @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { + setMemFrame, + mem, + VirtualMemoryStruct, + VirtualMemoryRender, +} from '../../../../dist/trace/database/ui-worker/ProcedureWorkerVirtualMemory.js'; + +describe('ProcedureWorkerVirtualMemory Test', () => { + it('ProcedureWorkerVirtualMemoryTest01', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + mem(dataList, [{ length: 1 }], 1, 1, 1, frame, true); + }); + + it('ProcedureWorkerVirtualMemoryTest02', function () { + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + let dataList = new Array(); + dataList.push({ + startTime: 0, + dur: 10, + frame: { x: 0, y: 9, width: 10, height: 10 }, + }); + dataList.push({ startTime: 1, dur: 111 }); + mem(dataList, [{ length: 0 }], 1, 1, 1, frame, false); + }); + + it('ProcedureWorkerVirtualMemoryTest03', () => { + const data = { + cpu: 1, + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + maxValue: undefined, + startTime: 1, + filterID: 2, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(VirtualMemoryStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProcedureWorkerVirtualMemoryTest04', function () { + let virtualMemoryRender = new VirtualMemoryRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(virtualMemoryRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProduceWorkerSdkCounter.test.ts b/ide/test/trace/database/ui-worker/ProduceWorkerSdkCounter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..faf2a0179b4ec6c0becfa5be96d876afe502a86d --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProduceWorkerSdkCounter.test.ts @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { SdkCounterRender, CounterStruct } from '../../../../dist/trace/database/ui-worker/ProduceWorkerSdkCounter.js'; + +describe('ProduceWorkerSdkCounter Test', () => { + it('ProduceWorkerSdkCounterTest01', function () { + let sdkCounterRender = new SdkCounterRender(); + let List = [ + { + length: 1, + ts: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }, + ]; + let arr = [ + { + frame: null, + length: 1, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(sdkCounterRender.counter(List, arr, 1, 1, 1, frame, true)).toBeUndefined(); + }); + + it('ProduceWorkerSdkCounterTest02', function () { + let sdkCounterRender = new SdkCounterRender(); + let List = [ + { + length: 1, + ts: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }, + ]; + let arr = [ + { + frame: null, + length: 0, + }, + ]; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(sdkCounterRender.counter(List, arr, 1, 1, 1, frame, false)).toBeUndefined(); + }); + + it('ProduceWorkerSdkCounterTest03', () => { + const data = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + startTime: 1, + ts: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(CounterStruct.draw(ctx, data, 1)).toBeUndefined(); + }); + + it('ProduceWorkerSdkCounterTest04', () => { + let node = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + ts: 1, + dur: 1, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(CounterStruct.setCounterFrame(node, 2, 1, 2, 2, frame)).toBeUndefined(); + }); + + it('ProduceWorkerSdkCounterTest05', () => { + let node = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + ts: 0, + dur: 3, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(CounterStruct.setCounterFrame(node, 2, 1, 2, 2, frame)).toBeUndefined(); + }); + + it('ProduceWorkerSdkCounterTest06', function () { + let sdkCounterRender = new SdkCounterRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(sdkCounterRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/database/ui-worker/ProduceWorkerSdkSlice.test.ts b/ide/test/trace/database/ui-worker/ProduceWorkerSdkSlice.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..403e6ac7d4c2b01b5671ac9fc6a1f02c1a5560fa --- /dev/null +++ b/ide/test/trace/database/ui-worker/ProduceWorkerSdkSlice.test.ts @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2022 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. + */ + +jest.mock('../../../../dist/trace/component/trace/base/TraceRow.js', () => { + return {}; +}); + +// @ts-ignore +import { SdkSliceRender, SdkSliceStruct } from '../../../../dist/trace/database/ui-worker/ProduceWorkerSdkSlice.js'; + +describe('ProduceWorkerSdkSlice Test', () => { + it('ProduceWorkerSdkSliceTest01', function () { + let sdkSliceRender = new SdkSliceRender(); + let list = [ + { + length: 1, + frame: { + x: 1, + Y: 10, + width: 100, + height: 20, + }, + }, + ]; + let res = [ + { + length: 1, + frame: null, + }, + ]; + expect(sdkSliceRender.sdkSlice(list, res, 1, 5, 4, true)).toBeUndefined(); + }); + + it('ProduceWorkerSdkSliceTest02', function () { + let sdkSliceRender = new SdkSliceRender(); + let list = [ + { + length: 1, + frame: { + x: 1, + Y: 10, + width: 100, + height: 20, + }, + }, + ]; + let res = [ + { + length: 0, + frame: null, + }, + ]; + expect(sdkSliceRender.sdkSlice(list, res, 1, 5, 4, false)).toBeUndefined(); + }); + + it('ProduceWorkerSdkSliceTest03', () => { + const data = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + start_ts: 1, + }; + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(SdkSliceStruct.draw(ctx, data)).toBeUndefined(); + }); + + it('ProduceWorkerSdkSliceTest04', () => { + let node = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + start_ts: 1, + end_ts: 2, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(SdkSliceStruct.setSdkSliceFrame(node, 2, 2, 3, 1, frame)).toBeUndefined(); + }); + + it('ProduceWorkerSdkSliceTest05', () => { + let node = { + startNs: 1, + value: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + start_ts: 3, + end_ts: 5, + }; + let frame = { + x: 20, + y: 20, + width: 100, + height: 100, + }; + expect(SdkSliceStruct.setSdkSliceFrame(node, 2, 2, 3, 1, frame)).toBeUndefined(); + }); + + it('ProduceWorkerSdkSliceTest06', function () { + let sdkSliceRender = new SdkSliceRender(); + let req = { + lazyRefresh: true, + type: '', + startNS: 1, + endNS: 1, + totalNS: 1, + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + useCache: false, + range: { + refresh: '', + }, + canvas: '', + context: { + font: '11px sans-serif', + fillStyle: '#ec407a', + globalAlpha: 0.6, + }, + lineColor: '', + isHover: '', + hoverX: 1, + params: '', + wakeupBean: undefined, + flagMoveInfo: '', + flagSelectedInfo: '', + slicesTime: 3, + id: 1, + x: 20, + y: 20, + width: 100, + height: 100, + }; + window.postMessage = jest.fn(() => true); + expect(sdkSliceRender.render(req, [], [])).toBeUndefined(); + }); +}); diff --git a/ide/test/trace/grpc/HiProfilerClient.test.ts b/ide/test/trace/grpc/HiProfilerClient.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..67280ce1528d5b3c397d550d2c8dc886ce88c224 --- /dev/null +++ b/ide/test/trace/grpc/HiProfilerClient.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { HiProfilerClient } from '../../../dist/trace/grpc/HiProfilerClient.js'; + +describe('HiProfilerClient Test', () => { + let hiProfilerClient = new HiProfilerClient(); + it('HiProfilerClientTest01', function () { + expect(hiProfilerClient.address).toBeUndefined(); + }); + + it('HiProfilerClientTest02', function () { + hiProfilerClient.address = true; + expect(hiProfilerClient.address).toBeTruthy(); + }); + + it('HiProfilerClientTest03', function () { + expect(hiProfilerClient.client).toBeUndefined(); + }); + + it('HiProfilerClientTest04', function () { + hiProfilerClient.client = true; + expect(hiProfilerClient.client).toBeTruthy(); + }); + + it('HiProfilerClientTest05', function () { + expect(hiProfilerClient.getProfilerClient()).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/grpc/ProfilerClient.test.ts b/ide/test/trace/grpc/ProfilerClient.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..58c79e8ead5fc89fd0d657a772b9c4f707bb1608 --- /dev/null +++ b/ide/test/trace/grpc/ProfilerClient.test.ts @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { ProfilerClient } from '../../../dist/trace/grpc/ProfilerClient.js'; + +describe('HiProfilerClient Test', () => { + it('HiProfilerClientTest01 ', function () { + expect(ProfilerClient.client).toBeUndefined(); + }); + it('HiProfilerClientTest02', function () { + ProfilerClient.client = true; + expect(ProfilerClient.client).toBeTruthy(); + }); + it('HiProfilerClientTest03 ', function () { + expect(ProfilerClient.filePaths).toBeUndefined(); + }); + it('HiProfilerClientTest04', function () { + ProfilerClient.filePaths = true; + expect(ProfilerClient.filePaths).toBeTruthy(); + }); + it('HiProfilerClientTest05', function () { + expect(ProfilerClient.profiler_proto).toBeUndefined(); + }); + it('HiProfilerClientTest06', function () { + ProfilerClient.profiler_proto = true; + expect(ProfilerClient.profiler_proto).toBeTruthy(); + }); + + it('HiProfilerClientTest07 ', function () { + expect(ProfilerClient.shutdown).toBeUndefined(); + }); + it('HiProfilerClientTest08', function () { + ProfilerClient.getChannel = jest.fn(() => true); + expect(ProfilerClient.getChannel()).toBeTruthy(); + }); +}); diff --git a/ide/test/trace/grpc/ProfilerController.test.ts b/ide/test/trace/grpc/ProfilerController.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5de056301d3ae2319e74cc84abb2bc23bc327687 --- /dev/null +++ b/ide/test/trace/grpc/ProfilerController.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2022 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. + */ + +// @ts-ignore +import { ClientContainer, SettingRegistry } from '../../../dist/trace/grpc/ProfilerController.js'; + +describe('HiProfilerClient Test', () => { + let profilerController = new ClientContainer(); + + it('ProfilerClientTest01', function () { + expect(profilerController.port).toBeUndefined(); + }); + + it('ProfilerClientTest02', function () { + profilerController.port = true; + expect(profilerController.port).toBeTruthy(); + }); + + it('ProfilerClientTest03', function () { + expect(profilerController.host).toBeUndefined(); + }); + + it('ProfilerClientTest04', function () { + profilerController.host = true; + expect(profilerController.host).toBeTruthy(); + }); + + it('ProfilerClientTest06', function () { + profilerController.loadSettings = jest.fn(() => true); + expect(profilerController.start()).toBeUndefined(); + }); + + it('ProfilerClientTest07', function () { + profilerController.loadSettings = jest.fn(() => true); + expect(profilerController.loadSettings()).toBeTruthy(); + }); + it('ProfilerClientTest08', function () { + expect(profilerController.registryClient()).toBeUndefined(); + }); + it('ProfilerClientTest09', function () { + expect(SettingRegistry.registry()).toBeUndefined(); + }); +}); diff --git a/ide/tsconfig.json b/ide/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..57e2db39f93c0524745586404c81c2c5b2b28aeb --- /dev/null +++ b/ide/tsconfig.json @@ -0,0 +1,71 @@ +{ + "compilerOptions": { + "experimentalDecorators": true, + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ES2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ +// "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + }, + "include": ["src"] +} diff --git a/trace_streamer/.clang-format b/trace_streamer/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..ad9f68d7903ca75f952875c97d09c712dff4fa9a --- /dev/null +++ b/trace_streamer/.clang-format @@ -0,0 +1,162 @@ +Language: Cpp +BasedOnStyle: LLVM +# 访问说明符(public、private等)的偏移 +AccessModifierOffset: -4 +# 开括号(开圆括号、开尖括号、开方括号)后的对齐 +AlignAfterOpenBracket: Align +# 连续赋值时,等号对齐 +AlignConsecutiveAssignments: false +# 连续赋值时,变量名对齐 +AlignConsecutiveDeclarations: false +# 左对齐逃脱换行(使用反斜杠换行)的反斜杠 +AlignEscapedNewlinesLeft: true +# 水平对齐二元和三元表达式的操作数 +AlignOperands: true +# 对齐连续的尾随的注释 +AlignTrailingComments: true +# 允许函数声明的所有参数在放在下一行 +AllowAllParametersOfDeclarationOnNextLine: false +# 允许短的块放在同一行 +AllowShortBlocksOnASingleLine: false +# 允许短的case标签放在同一行 +AllowShortCaseLabelsOnASingleLine: false +# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All +AllowShortFunctionsOnASingleLine: Empty +# 允许短的if语句保持在同一行 +AllowShortIfStatementsOnASingleLine: false +# 允许短的循环保持在同一行 +AllowShortLoopsOnASingleLine: false +# 总是在定义返回类型后换行(deprecated) +AlwaysBreakAfterDefinitionReturnType: None +# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), +# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) +AlwaysBreakAfterReturnType: None +# 总是在多行string字面量前换行 +AlwaysBreakBeforeMultilineStrings: true +# 总是在template声明后换行 +AlwaysBreakTemplateDeclarations: true +# false表示函数实参要么都在同一行,要么都各自一行 +BinPackArguments: true +# false表示所有形参要么都在同一行,要么都各自一行 +BinPackParameters: false +# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false +# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) +BreakBeforeBinaryOperators: None +# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), +# Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), +# Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom +# 注:这里认为语句块也属于函数 +BreakBeforeBraces: Custom +# 在三元运算符前换行 +BreakBeforeTernaryOperators: true +# 在构造函数的初始化列表的逗号前换行 +BreakConstructorInitializersBeforeComma: false +# 每行字符的限制,0表示没有限制 +ColumnLimit: 120 +# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 +CommentPragmas: "^ IWYU pragma:" +# 构造函数的初始化列表要么都在同一行,要么都各自一行 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# 构造函数的初始化列表的缩进宽度 +ConstructorInitializerIndentWidth: 4 +# 延续的行的缩进宽度 +ContinuationIndentWidth: 4 +# 去除C++11的列表初始化的大括号{后和}前的空格 +Cpp11BracedListStyle: true +# 继承最常用的指针和引用的对齐方式 +DerivePointerAlignment: false +# 关闭格式化 +DisableFormat: false +# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) +ExperimentalAutoDetectBinPacking: false +# 需要被解读为foreach循环而不是函数调用的宏 +ForEachMacros: [foreach, Q_FOREACH, BOOST_FOREACH] +# 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), +# 可以定义负数优先级从而保证某些#include永远在最前面 +# IncludeCategories: +# - Regex: '^"(llvm|llvm-c|clang|clang-c)/' +# Priority: 2 +# - Regex: '^(<|"(gtest|isl|json)/)' +# Priority: 3 +# - Regex: ".*" +# Priority: 1 +# 缩进case标签 +IndentCaseLabels: true +# 缩进宽度 +IndentWidth: 4 +# 函数返回类型换行时,缩进函数声明或函数定义的函数名 +IndentWrappedFunctionNames: true +# 保留在块开始处的空行 +KeepEmptyLinesAtTheStartOfBlocks: true +# 开始一个块的宏的正则表达式 +MacroBlockBegin: "" +# 结束一个块的宏的正则表达式 +MacroBlockEnd: "" +# 连续空行的最大数量 +MaxEmptyLinesToKeep: 1 +# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All +NamespaceIndentation: None +# 使用ObjC块时缩进宽度 +ObjCBlockIndentWidth: 4 +# 在ObjC的@property后添加一个空格 +ObjCSpaceAfterProperty: false +# 在ObjC的protocol列表前添加一个空格 +ObjCSpaceBeforeProtocolList: true +# 在call(后对函数调用换行的penalty +PenaltyBreakBeforeFirstCallParameter: 19 +# 在一个注释中引入换行的penalty +PenaltyBreakComment: 300 +# 第一次在<<前换行的penalty +PenaltyBreakFirstLessLess: 120 +# 在一个字符串字面量中引入换行的penalty +PenaltyBreakString: 1000 +# 对于每个在行字符数限制之外的字符的penalt +PenaltyExcessCharacter: 1000000 +# 将函数的返回类型放到它自己的行的penalty +PenaltyReturnTypeOnItsOwnLine: 120 +# 指针和引用的对齐: Left, Right, Middle +PointerAlignment: Left +# 允许重新排版注释 +ReflowComments: true +# 允许排序#include +SortIncludes: false +# 在C风格类型转换后添加空格 +SpaceAfterCStyleCast: false +# 在赋值运算符之前添加空格 +SpaceBeforeAssignmentOperators: true +# 开圆括号之前添加一个空格: Never, ControlStatements, Always +SpaceBeforeParens: ControlStatements +# 在空的圆括号中添加空格 +SpaceInEmptyParentheses: false +# 在尾随的评论前添加的空格数(只适用于//) +SpacesBeforeTrailingComments: 1 +# 在尖括号的<后和>前添加空格 +SpacesInAngles: false +# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 +SpacesInContainerLiterals: true +# 在C风格类型转换的括号中添加空格 +SpacesInCStyleCastParentheses: false +# 在圆括号的(后和)前添加空格 +SpacesInParentheses: false +# 在C++11的列表初始化的大括号之前添加空格 +# SpaceBeforeCpp11BracedList: true +# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 +SpacesInSquareBrackets: false +# 标准: Cpp03, Cpp11, Auto +Standard: Cpp11 +# tab宽度 +TabWidth: 4 +# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always +UseTab: Never \ No newline at end of file diff --git a/trace_streamer/.clang-tidy b/trace_streamer/.clang-tidy new file mode 100644 index 0000000000000000000000000000000000000000..d8daf0d9d9bea214e008b3a67a7fb5855499f106 --- /dev/null +++ b/trace_streamer/.clang-tidy @@ -0,0 +1,57 @@ +--- +# Ref: https://releases.llvm.org/12.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/list.html +Checks: > + android-*, + bugprone-*, + clang-analyzer-*, + concurrency-mt-unsafe, + cppcoreguidelines-*, + cert-* + hicpp-*, + llvm-*, + modernize*, + performance-*, + portability-*, + readability-*, + -modernize-use-trailing-return-type, + -hicpp-vararg, + -hicpp-no-array-decay, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-type-union-access, + -cppcoreguidelines-pro-type-vararg, + -readability-implicit-bool-conversion, + +CheckOptions: + # Ref: https://releases.llvm.org/12.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/readability-identifier-naming.html + - { key: readability-identifier-naming.NamespaceCase, value: CamelCase } + - { key: readability-identifier-naming.ClassCase, value: CamelCase } + - { key: readability-identifier-naming.StructCase, value: CamelCase } + - { key: readability-identifier-naming.UnionCase, value: CamelCase } + - { key: readability-identifier-naming.EnumCase, value: CamelCase } + - { key: readability-identifier-naming.TypedefCase, value: CamelCase } + - { key: readability-identifier-naming.TypeAliasCase, value: CamelCase } + - { key: readability-identifier-naming.FunctionCase, value: CamelCase } + - { key: readability-identifier-naming.GlobalVariableCase, value: camelBack } + - { key: readability-identifier-naming.GlobalVariablePrefix, value: g_ } + - { key: readability-identifier-naming.MacroDefinitionCase, value: UPPER_CASE } + - { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE } + - { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE } + - { key: readability-identifier-naming.ClassConstantCase, value: UPPER_CASE } + - { key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE } + - { key: readability-identifier-naming.LocalConstantCase, value: camelBack } + - { key: readability-identifier-naming.ParameterCase, value: camelBack } + # 如下例外无法处理:对于struct/union的成员变量,仍采用小驼峰不加后缀的命名方式,与局部变量命名风格一致 + # - { key: readability-identifier-naming.ClassMemberCase, value: camelCase } + # - { key: readability-identifier-naming.PublicMemberSuffix, value: _ } + # - { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ } + # - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } + + # 规则8.1.1 避免函数过长,函数不超过50行(非空非注释) + - { key: readability-function-size.LineThreshold, value: 50 } + # 建议8.3.3 函数的参数个数不超过5个 + - { key: readability-function-size.ParameterThreshold, value: 5 } + - { key: readability-function-size.NestingThreshold, value: 4 } + - { key: bugprone-assert-side-effect.CheckFunctionCalls, value: 1 } + - { key: modernize-use-transparent-functors.SafeMode, value: 1 } + diff --git a/trace_streamer/.gitignore b/trace_streamer/.gitignore new file mode 100755 index 0000000000000000000000000000000000000000..3fa752525c3e6e2d64d2990dfffe69d99ca3e7bf --- /dev/null +++ b/trace_streamer/.gitignore @@ -0,0 +1,18 @@ +out +.vscode +tmp_* +build-* +*.pro.use* +.DS_Store +._.DS_Store +emsdk +prebuilts/dist +prebuilts/linux +third_party +.idea +tools +tmp +out.perf +perf.data +out.floded +./.db \ No newline at end of file diff --git a/trace_streamer/.gn b/trace_streamer/.gn new file mode 100644 index 0000000000000000000000000000000000000000..814190914c15108ecabbd3f4413d318a85ba09d0 --- /dev/null +++ b/trace_streamer/.gn @@ -0,0 +1,14 @@ +# 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. + +buildconfig = "//gn/CONFIG.gn" diff --git a/trace_streamer/BUILD.gn b/trace_streamer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0f1ea928889a39a530c803056af9caf3855ae0f3 --- /dev/null +++ b/trace_streamer/BUILD.gn @@ -0,0 +1,40 @@ +# 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. + +group("trace_streamer") { + if (is_test) { + deps = [ "test:unittest" ] + testonly = true + } else if (is_fuzz) { + deps = [ "test:fuzztest" ] + testonly = true + } else if (is_protoc) { + deps = [ "//third_party/protobuf:protoc" ] + } else if (is_spb) { + deps = [ "src/proto_reader/protoc_plugin:protoreader_plugin" ] + } else if (is_sdkdemo) { + deps = [ "sdk/demo_sdk:trace_streamer_sdk_builtin" ] + } else if (is_dubai_sdk) { + deps = [ "sdk/dubai_sdk:trace_streamer_dubai_builtin" ] + } else if (is_sdkdemo_test) { + deps = [ "sdk/test:sdkunittest" ] + } else if (use_wasm) { + deps = [ "src:trace_streamer_builtin" ] + } else if (use_wasmpb) { + deps = [ "src:trace_streamer_builtin" ] + } else if (is_pbdecoder) { + deps = [ "src:trace_streamer" ] + } else { + deps = [ "src:trace_streamer" ] + } +} diff --git a/trace_streamer/README.md b/trace_streamer/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b975f0b55554f6f7baf7905fd6184259ae051508 --- /dev/null +++ b/trace_streamer/README.md @@ -0,0 +1,168 @@ +# TraceStreamer工具说明 +TraceStreamer是一个trace数据解析程序,可以将一个trace文本文件或者基于proto序列化的二进制文件转换成为sqlite数据库的形式。 TraceStreamer使用C++实现,支持在ohos, linux, mac等系统上使用,具有良好的跨平台特性。 +![GitHub Logo](./figures/trace_streamer_stream.png) +## 关于TraceStreamer的使用说明 +TraceStreamer工具可以2种方式使用: +1. 可以将系统离线trace文件解析并转为db,此工具支持基于文本的trace和基于proto的trace。 +2. TraceStreamer工具还可以WebAssembly的方式在浏览器中运行,需提供相关接口给js文件。 + +### 导出db模式 +在导出db模式下,通过下面的指令: +``` +./trace_streamer trace文件路径名 -e 导出db路径名.db +``` +可以将trace文件转为db文件。 +本应用支持在ohos, linux, mac使用。 +在数据导出之后,会在本地目录下生成一个trace_streamer.log文件,在导出db的目录下生成一个数据库文件同名,.db.ohos.ts后缀的文件。 +文件内容如下: +``` +当前时间戳:执行结果(数字) +应用运行时间 +``` +执行结果解释如下: +``` +0 代表执行成功 1 表示输入文件不匹配, 2 表示解析错误, 3其他错误。 +``` +#### __关于db文件的说明__ +可以使用sqliteexport或DB Browser for SQLite工具加载生成的db,通过查看stat表,可以浏览当前数据一共有多少类数据,各类数据都收到多少条,数据是否正常等情况。在meta表会记录数据库导出时的一些系统信息,比如导入和导出的文件全路径,解析时间等信息。 +meta表可以选择不导出(有些情况下会暴露系统敏感信息),在导出时添加 -nm选项即可。 +更多db文件的介绍,可以参考[doc/des_tables.md](./doc/des_tables.md)。 + +### 内置浏览器模式 +TraceStreamer可以WebAssembly方式在浏览器中运行,相关接口在wasm模式下生成的trace_streamer_builtin.js文件中,js可以使用的接口如下使用如下接口访问trace_streamer: +``` +extern "C" { +/* 初始化wasm,在JS中注册回调函数,并返回一段可复用的内存空间,由JS调用 + * + * @ replyFunction: 回调函数 +* @ reqBufferSize: 返回的内存长度 +* return: 返回一段内存地址给JS +*/ +EMSCRIPTEN_KEEPALIVE uint8_t* Initialize(ReplyFunction replyFunction, uint32_t reqBufferSize) + +/* 更新起始结束时间,由JS调用 + * + * @ len: 起始和结束时间组成的字符串长度 +* return: 成功返回0。 +*/ +EMSCRIPTEN_KEEPALIVE int UpdateTraceTime(int len) + +/* 设置TraceStreamer和第三方wasm通信的回调函数,并返回一段内存,由JS调用 + * + * @ sendDataCallBack:与第三方wasm通信的回调函数 +* @ reqBufferSize: 返回的内存长度 +* return: 成功返回0 +*/ +EMSCRIPTEN_KEEPALIVE uint8_t* TraceStreamer_Set_ThirdParty_DataDealer(SendDataCallBack sendDataCallBack, uint32_t reqBufferSize) + +/* TraceStreamer的数据解析接口,由JS调用 + * +* @ dataLen: 需要解析的数据源长度 +* return: 成功返回0,失败返回-1 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamerParseDataEx(int dataLen) + +/* TraceStreamer停止解析数据,由JS调用 + * +* return: 成功返回0,失败返回-1 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamerParseDataOver() + +/* 数据库操作接口,由JS调用 + * +* @ sqlLen: 需要执行的操作类sql语句长度 +* return: 成功返回0,失败返回-1 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlOperateEx(int sqlLen) + +/*清空wasm内存中的内容,由JS调用 + * +* return: 成功返回0,失败返回-1 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamerReset() + +/*执行查询类sql语句,由JS调用 + * +* @ sqlLen: 需要执行的查询类sql语句长度 +* return: 成功返回0,失败返回-1 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlQueryEx(int sqlLen) + +/*取消sql查询,由JS调用。 + * +* return: 成功返回0。 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamerCancel() + +/*发送数据给第三方wasm解析,由TraceStreamer调用 + * +* @ pluginData: 第三方插件的数据源 +* @ len: 数据源长度 +* @ componentName: 第三方插件名称 +* return: 成功返回0 +*/ +int TraceStreamer_Plugin_Out_SendData(const char* pluginData, int len, const std::string componentName) + +/* 初始化配置接口,由JS调用 + * +* @ dataLen: 配置字符串的长度 +* return: 成功返回0 +*/ +EMSCRIPTEN_KEEPALIVE int TraceStreamer_Init_ThirdParty_Config(int dataLen) + +} // extern "C" +``` + +### 可以执行如下命令查看应用帮助 +```./trace_streamer --help``` + +### TraceStreamer支持解析的事件列表 +通过```./trace_streamer -i``` +查看支持的事件列表。 +支持的事件列表参见[SupportEventList.md](./doc/des_support_event.md)。 +## TraceStreamer重要概念介绍 +### 进程和线程标识符 +``` +在通用操作系统中,进程号(pid/tgid)和线程号(tid)可能会被重复用于标识不同的进程或者线程。所以在trace数据源中,进程号(pid)和线程号(tid)也可能被重用。 +TraceStreamer在解析数据过程中,使用ipid(internal pid)唯一标识进程, itid(internal tid)唯一标识线程。 +``` +### 计量器 +用来记录系统中各种随时间连续变化的数值。例如: CPU的频率, 内存的使用量, 界面刷新频率。 +#### 举例 +CPU频率: +![GitHub Logo](./figures/cpu_frequency.png) +内存占用: +![GitHub Logo](./figures/mem_usage.png) + +### 过滤器 +TraceStreamer设计过程中使用了流式处理的思想,数据从入口进入以后,就像进入一条河流,从上游流向下游,在河道中央有很多过滤器,每种过滤器会将流过的数据中自己关注的内容吸附捕捉到。最终,每个过滤器都拥有了大量同类型的数据,而且这些数据都是按时间序列排列的。TraceStreamer使用filterid来标识同一种用途的数据,可以方便在UI中绘制。 +![GitHub Logo](./figures/filters.png) + +## Stat表设计 +具体内容参见 [des_stat](./doc/des_stat.md)。 +## TraceStreamer开发环境搭建和编译运行指引 + +本应用使用gn作为构建工具。 +### 开发环境 +可以在ubuntu、mac、windows下执行开发和编译,建议使用vscode开发工具。 +在windows平台上,需使用支持c++17标准的clang编译器。 +# 对外部的依赖 +本应用依赖与sqlite、protobuf(htrace解析部分依赖)、nlohmann_json。 +本应用同时依赖于src/protos/protogen.sh目录下文件来生成相关pb.h,pb.cc文件。 +_____ + +### 编译linux和Mac应用 +在目录下有build.sh脚本,在不同的平台上会判断系统版本,编译相应系统的应用。 +``` +./build.sh linux +./build.sh macx +``` + +### 编译wasm +``` +./build.sh wasm +``` + +### 开始编译 +本工具建议独立编译,通过部署第三方依赖库,emsdk,可编译出支持不同平台的应用。 +具体方法可参考[compile_trace_streamer](./doc/compile_trace_streamer.md)。 \ No newline at end of file diff --git a/trace_streamer/build.sh b/trace_streamer/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..96965a670d46f5a8e3fc812fb8aafccc4e3a19ac --- /dev/null +++ b/trace_streamer/build.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# 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. +set -e +PARAMS=$* +echo $PARAMS +echo "begin to check input" +./pare_third_party.sh +target_os="linux" +target_dir="linux" +gn_path="linux" +is_debug="false" +is_clean="false" +target="trace_streamer" +gn="gn" +ninja="ninja" +case "$OSTYPE" in + solaris*) echo "SOLARIS" ;; + darwin*) gn_path="macx" target_os="macx" ;; + linux*) gn_path="linux" target_os="linux" ;; + bsd*) echo "is bsd os" ;; + msys*) gn_path="windows" target_os="windows" gn="gn.exe" ninja="ninja.exe" ;; + *) echo "unknown: $OSTYPE" ;; +esac +usage="Usage: $basename $0 wasm/test/fuzz/protoc debug/release/clean" + +./dl_tools.sh $gn_path +if [ ! -f "out/$target_os/protoc" ] && [ "$1" != "protoc" ];then + ./build.sh protoc +fi +if [ ! -f "out/$target_os/protoreader_plugin" ] && [ "$1" != "spb" ] && [ -f "out/$target_os/protoc" ];then + ./build.sh spb +fi +if [ "$1" == "windows" ];then + echo "gn only support linux and wasm build currently" + if [ ! -d "out/windows" ];then + mkdir out/windows + fi + touch out/windows/trace_streamer.exe + exit +fi + +if [ "$#" -ne "0" ];then + if [ "$1" == "wasm" ];then + ./dl_emsdk.sh + target="wasm" + fi + if [ "$1" == "test" ];then + target="test" + fi + if [ "$1" == "testpb" ];then + target="testpb" + fi + if [ "$1" == "wasmpb" ];then + target="wasmpb" + fi + if [ "$1" == "fuzz" ];then + target="fuzz" + fi + if [ "$1" == "protoc" ];then + target="protoc" + fi + if [ "$1" == "sdkdemo" ];then + target="sdkdemo" + fi + if [ "$1" == "pbdecoder" ];then + target="pbdecoder" + fi + if [ "$1" == "dubaisdk" ];then + target="dubaisdk" + fi + if [ "$1" == "sdkdemotest" ];then + target="sdkdemotest" + fi + if [ "$1" == "spb" ];then + target="spb" + fi +fi +target_operator="$2" +if [ "$target" == "wasm" ] && [ "$target_os" == "windows" ];then + echo "!!!build wasm on winows will occur unknown error, strongly suggest you build wasm on linux(Ubuntu)" + exit +fi +./build_operator.sh $is_debug $target $target_os $is_clean $gn_path $gn $ninja $target_operator diff --git a/trace_streamer/build/ohos.gni b/trace_streamer/build/ohos.gni new file mode 100644 index 0000000000000000000000000000000000000000..dbad1dc962646897b1e346d924874212c88d22ab --- /dev/null +++ b/trace_streamer/build/ohos.gni @@ -0,0 +1,130 @@ +# 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. +template("ohos_source_set") { + source_set(target_name) { + part_name = invoker.part_name + subsystem_name = invoker.subsystem_name + print("part_name", part_name) + print("subsystem_name", subsystem_name) + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.configs)) { + configs = invoker.configs + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.ldflags)) { + ldflags = invoker.ldflags + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + } +} +template("ohos_shared_library") { + part_name = invoker.part_name + subsystem_name = invoker.subsystem_name + shared_library(target_name) { + sources = invoker.sources + if (defined(invoker.configs)) { + configs = invoker.configs + } + public_configs = invoker.public_configs + if (defined(invoker.defines)) { + defines = invoker.defines + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + } +} +template("ohos_static_library") { + part_name = invoker.part_name + subsystem_name = invoker.subsystem_name + static_library(target_name) { + sources = invoker.sources + if (defined(invoker.configs)) { + configs = invoker.configs + } + public_configs = invoker.public_configs + if (defined(invoker.defines)) { + defines = invoker.defines + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + } +} +template("ohos_executable") { + part_name = invoker.part_name + subsystem_name = invoker.subsystem_name + executable(target_name) { + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + sources = invoker.sources + if (defined(invoker.defines)) { + defines = invoker.defines + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.output_name)) { + output_name = invoker.output_name + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.ohos_test)) { + ohos_test = invoker.ohos_test + } + } +} diff --git a/trace_streamer/build/protoc.sh b/trace_streamer/build/protoc.sh new file mode 100644 index 0000000000000000000000000000000000000000..8012b221cce151b4a22d5f1e417d5dc1b4771799 --- /dev/null +++ b/trace_streamer/build/protoc.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# 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. + +set -e +#echo "begin to protoc--------------" +LIBCXX_X64_OUT="//out/linux" +PROTOC="//out/linux/protoc" +PARAMS=$* +PARAMS_FILTER="$1 $2" +#echo "EXEC: LD_LIBRARY_PATH=$LIBCXX_X64_OUT:$PROTOC ${PARAMS[@]:${#PARAMS_FILTER}}" +LD_LIBRARY_PATH=$LIBCXX_X64_OUT exec $PROTOC ${PARAMS[@]:${#PARAMS_FILTER}} diff --git a/trace_streamer/build/test.gni b/trace_streamer/build/test.gni new file mode 100644 index 0000000000000000000000000000000000000000..8bdf099d0885508f019e08b7d705a0acd5ea229e --- /dev/null +++ b/trace_streamer/build/test.gni @@ -0,0 +1,48 @@ +#!/bin/bash +# 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. +template("ohos_unittest") { + if (defined(invoker.ldflags)) { + print(invoker.ldflags) + } + executable(target_name) { + forward_variables_from(invoker, "*") + testonly = true + if (defined(invoker.ldflags)) { + print(invoker.ldflags) + } + if (defined(invoker.cflags)) { + print(invoker.cflags) + cflags += invoker.cflags + } + } +} + +template("ohos_fuzztest") { + executable(target_name) { + forward_variables_from(invoker, "*") + testonly = true + deps = [] + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.cflags)) { + cflags += invoker.cflags + } + ldflags += [ "-fsanitize=fuzzer" ] + cflags += [ + "-fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters", + "-fsanitize=fuzzer", + ] + } +} diff --git a/trace_streamer/build_operator.sh b/trace_streamer/build_operator.sh new file mode 100755 index 0000000000000000000000000000000000000000..d556c26c09e03d719309a2bc8f4dc7d5735963d9 --- /dev/null +++ b/trace_streamer/build_operator.sh @@ -0,0 +1,96 @@ +#!/bin/bash +set -e +# 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. +ext="" +target_dir="linux" +is_debug="$1" +target="$2" +target_os="$3" +is_clean="$4" +gn_path="$5" +gn="$6" +ninja="$7" +target_operator="$8" +if [ "$#" -ge "7" ];then + if [ $target != "trace" ] && [ $target != "pbdecoder" ] && [ $target != "linux" ] && [ $target != "windows" ] && + [ $target != "macx" ] && [ $target != "trace_streamer" ] && [ $target != "wasm" ] && [ $target != "wasmpb" ] && + [ $target != "test" ] && [ $target != "testpb" ] && [ $target != "spb" ] && [ $target != "fuzz" ] && + [ $target != "protoc" ] && [ $target != "sdkdemo" ] && [ $target != "dubaisdk" ] && [ $target != "sdkdemotest" ];then + echo "failed" + exit + fi + if [ "$target_operator" != "" ] && [ "$target_operator" != "debug" ] && [ "$target_operator" != "release" ] && [ "$target_operator" != "clean" ];then + if [ "$target_operator" == "protoc" ];then + target=$target_operator + else + echo "failed" + exit + fi + fi + if [ "$target_operator" == "debug" ];then + is_debug="true" + elif [ "$target_operator" == "clean" ];then + is_clean="true" + else + is_debug="false" + fi + echo "platform is $target_os" + echo "isdebug: $is_debug" + echo "isclean: $is_clean" +else + echo "$usage" + echo "It is not recommended to execute this file and use it by build.sh." + echo "use default input paramter" + echo "platform is $target_os" + echo "target is $target" + echo "is_debug:$is_debug" + exit +fi +if [ "$is_debug" != "false" ];then + ext="_debug" +fi +if [ ! -d "third_party/protogen" ] && [ "$target" != "spb" ] && [ "$target" != "protoc" ];then + ./src/protos/protogen.sh +fi + +if [ "$target" == "test" ] || [ "$target" == "fuzz" ] || [ "$target"="wasm" ] || [ "$target"="wasmpb" ] || [ "$target"="sdkdemo" ] || [ "$target"="sdkdemotest" ];then + target_dir=$target +else + target_dir=$target_os +fi +if [ "$target" == "trace_streamer" ] || [ "$target" == "trace" ] || [ "$target" == "spb" ]|| [ "$target" == "pbdecoder" ];then + target_dir=$target_os +fi +if [ "$target" == "testpb" ]; then + target_dir="test" +fi +echo "target_dir:" $target_dir +echo "target:" $target +# exit +if [ "$is_clean" == "true" ];then + prebuilts/$gn_path/$gn gen out/"$target_dir""$ext" --clean + prebuilts/$gn_path/$ninja -C out/"$target_dir""$ext" -t clean +else + prebuilts/$gn_path/$gn gen out/"$target_dir""$ext" --args='is_debug='"$is_debug"' target="'"$target"'" target_os="'"$target_os"'"' + echo "begin to build ..." + mkdir -p out/windows + touch out/windows/trace_streamer.exe + prebuilts/$gn_path/$ninja -C out/"$target_dir""$ext" + if [ "$target_dir" == "protoc" ];then + if [ ! -d "out/$target_os" ];then + mkdir -p "out/$target_os" + fi + mv out/"$target_dir""$ext"/$target_dir out/$target_os/ + fi +fi diff --git a/trace_streamer/commit.md b/trace_streamer/commit.md new file mode 100644 index 0000000000000000000000000000000000000000..7374972d3dbd3f62147e874b75ea7c711c7e11c7 --- /dev/null +++ b/trace_streamer/commit.md @@ -0,0 +1,19 @@ +## 关于提交代码的说明 +为了方便代码格式化的维护,提交代码前,请使用脚本对代码使用脚本格式化。 +format-code.sh文件会对如下的文件夹进行格式化: +``` +src +sdk/demo_sdk +test +``` +注意,该脚本不会对所有的#include格式化,因为#include涉及头文件字母表排序,请开发者自行排序。 +如果某一段代码不想被格式化,请在代码前后增加标识如下: +``` +// clang-format off +you code does not want to be formatted +// clang-format on +``` +上述标识会控制clang-format自动跳过标识内的代码块。 +目前使用的clang-format是: +```clang-format version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)``` +如果格式化代码后发现代码格式变化很大,请检查clang-format的版本。 diff --git a/trace_streamer/dl_emsdk.sh b/trace_streamer/dl_emsdk.sh new file mode 100755 index 0000000000000000000000000000000000000000..8ba47bab428a469c3152ac0ab41939dae3092e75 --- /dev/null +++ b/trace_streamer/dl_emsdk.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# 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. +set -e +if [ -d "prebuilts/emsdk" ] && [ ! -d "prebuilts/emsdk/emsdk/emscripten" ];then + rm -rf prebuilts/emsdk +fi +if [ ! -d "prebuilts/emsdk" ];then + echo "you need emsdk to compile wasm" + if [ ! -d "tools" ];then + mkdir tools + fi + if [ ! -d "tools/emsdk" ];then + cd tools + git clone https://gitee.com/su_ze1688/emsdk.git --depth=1 + cd emsdk + git pull + ./emsdk install 3.1.12 + ./emsdk activate 3.1.12 + cd ../../ + fi + if [ ! -d "prebuilts/emsdk" ];then + mkdir prebuilts/emsdk + fi + if [ ! -d "prebuilts/emsdk/emsdk" ];then + mkdir prebuilts/emsdk/emsdk + fi + if [ ! -d "prebuilts/emsdk/node" ];then + mkdir prebuilts/emsdk/node + fi + mv tools/emsdk/upstream/* prebuilts/emsdk/emsdk + mv tools/emsdk/node/* prebuilts/emsdk/node +fi diff --git a/trace_streamer/dl_tools.sh b/trace_streamer/dl_tools.sh new file mode 100755 index 0000000000000000000000000000000000000000..02e12b1699ce79508f64e4226b89bb94fa675c4c --- /dev/null +++ b/trace_streamer/dl_tools.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# 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. +set -e +gn_path="$1" +if [ ! -d "prebuilts/$gn_path" ];then + mkdir prebuilts/$gn_path +fi +if [ ! -f "prebuilts/$gn_path/gn" ];then + if [ ! -d "tools" ];then + mkdir tools + fi + if [ ! -d "tools/public_tools" ];then + cd tools + git clone git@gitee.com:su_ze1688/public_tools.git + cd .. + mv tools/public_tools/gn/$gn_path/gn prebuilts/$gn_path + mv tools/public_tools/gn/$gn_path/ninja prebuilts/$gn_path/ninja + fi +fi diff --git a/trace_streamer/doc/compile_trace_streamer.md b/trace_streamer/doc/compile_trace_streamer.md new file mode 100755 index 0000000000000000000000000000000000000000..90ddc6acc977dab4bac77cbbdc1fd069272a0698 --- /dev/null +++ b/trace_streamer/doc/compile_trace_streamer.md @@ -0,0 +1,314 @@ +# 如何编译TraceStreamer +TraceStreamer可以编译为命令行下的可执行程序,或者WebAssembly程序。 + +## 快速编译 + +可以按下面的方法快速编译TraceStreamer。 + +#### 准备工作 + +在码云上添加ssh公钥。 +本工具工程组织方式是gn。编译需要对应的编译器,编译前请自行配置本地编译器。 +所需编译器和版本如下表所示: +| 系统 | 工具 | 版本号| +| --- | --- | --- | +|linux |clang/clang++| (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0| +| macx |clang/clang++| 14.0.3 | +|windows |gcc.exe/g++.exe| (i686-posix-dwarf-rev0, Built by MinGW-W64 project) 8.1.0| +|wasm(linux下编译) |emcc/em++| 3.1.12| + +对于wasm环境,build.sh会自行配置,如果出现问题,可按本文档中后续命令自行检查修复。 +#### 快速编译命令行下的可执行程序 + +在linux/windows/macx平台进入代码根目录下执行: + +``` +./build.sh +``` +本脚本会下载和准备本地依赖的环境,并编译目标。 +在不同的平台上编译后的目标在不同的文件夹,如下所示: +| 系统 | release版本 | debug版本| +| --- | --- | --- | +|linux |out/linux| out/linux_debug| +| macx |out/macx| out/macx_debug | +|windows |out/windows| out/windows_debug| +|wasm(linux下编译) |out/wasm| + +#### 快速编译WebAssembly版本 + +如要编译WebAssembly版本,只需在代码根目录下执行: + +``` +./build.sh wasm +``` +emsdk请使用3.1.12版本。 + +如需要编译其他不同平台的版本,如windows,mac等,请查看***编译linux、mac、windows平台的TraceStreamer***章节获取更多信息。 + +WebAssembly版本目前只支持在linux平台下编译。 + +由于网络和权限不同,在编译过程中可能会造成一些问题,如使用以上方法无法正常编译,请按照本文档中后面的章节重新进行相关环境配置。 + +## 编译步骤 + +## 处理第三方库 + +处理第三方库,可以使用pare_third_party.sh文件来下载第三方库并做适当的处理,执行此脚本需要在码云上添加开发者的ssh公钥。 +如果pare_third_party.sh脚本出现问题,需要按如下的步骤做检查。 + +### sqlite + +1. 在第三方库中,找到并下载sqlite组件; +``` +ssh clone git@gitee.com:openharmony/third_party_sqlite.git) +``` +2. 把下载的文件解压后,文件夹命名为sqlite放入到third_party目录中; +3. 使用下面的命令,把sqlite的BUILD.gn修改为TraceStreamer适用的风格。 + +``` +patch -p0 third_party/sqlite/BUILD.gn prebuilts/patch_sqlite/sqlite3build.gn.patch +``` + +### protobuf + +1. 在第三方库中,找到并下载protobuf组件; + +``` +git clone git@gitee.com:openharmony/third_party_protobuf.git +``` + +2. 把下载的文件解压后,文件夹命名为protobuf,放入到third_party目录中; +3. 使用下面的命令,把protobuf的BUILD.gn修改为TraceStreamer适用的风格。 + +``` +patch -p0 third_party/protobuf/BUILD.gn prebuilts/patch_protobuf/protobufbuild.gn.patch +``` + +### googletest + +1. 在第三方库中,找到并下载googletest组件; + +``` +git clone git@gitee.com:openharmony/third_party_googletest.git +``` + +2. 把googletest文件夹放入third_party目录中; +3. 使用下面的命令,把googletest的BUILD.gn修改为TraceStreamer适用的风格。 + +``` +patch -p0 third_party/googletest/BUILD.gn prebuilts/patch_googletest/googletestbuild.gn.patch +``` + +4. 处理一系列public权限问题,处理原则是,但凡是有问题头文件的上下添加如下内容: + +``` +#undef private +#define private private +#include // 加入这里是编译有问题的头文件 +#undef private +#define private public +``` + +目前已知的需处理的地方有: + +``` +gtest-message.h文件 ++#undef private ++#define private private + #include +- ++#undef private ++#define private public + +gtest.h文件 +- ++#undef private ++#define private private + #include "gtest/internal/gtest-internal.h" ++#undef private ++#define private public + + gtest-tag.h文件 + 第13行注释即可 +### nlohmann_json +gtest-internal.h ++#undef private ++#define private private + #include ++#undef private ++#define private public + +gtest-port.h文件 ++#undef private ++#define private private +#include // NOLINT ++#undef private ++#define private public +``` + +### json库 + +1. 在第三方库中,找到并下载third_party_json库; +``` +git clone git@gitee.com:openharmony/third_party_json.git +``` +2. 把下载的文件解压后,文件夹命名为json-master,放入到third_party目录中。 + +### libunwind + +1. 在第三方库中,找到并下载libunwind组件; +``` +git clone git@gitee.com:openharmony/third_party_libunwind.git +``` +2. 把libunwind文件夹放入third_party目录中; +3. 使用下面的命令,把libunwind的BUILD.gn修改为TraceStreamer适用的风格。 + +``` +patch -p0 third_party/libunwind/BUILD.gn prebuilts/patch_libunwind/libunwindbuild.gn.patch +``` + +third_party/libunwind/src/x86_64/unwind_i.h第60行,注释。 + +``` +// #define setcontext UNW_ARCH_OBJ (setcontext) +``` +### hiperf +直接执行pare_third_party.sh即可自动完成hiperf相关配置。 + +### 其他文件 + +为了独立编译trace_streamer,还需要在third_party目录下有2个文件。 + +``` +third_party/perf_include/ +├── libbpf +│ └── linux +│ └── perf_event.h +└── musl + └── elf.h +``` + +perf_event.h文件获取方式: + +``` +wget https://gitee.com/openharmony/third_party_libbpf/raw/master/include/uapi/linux/perf_event.h +``` + +需打补丁: + +``` +patch -p0 perf_event.h prebuilts/patch_perf_event/perf_event.h.patch +``` + +elf.h文件获取方式: + +``` +wget https://gitee.com/openharmony/third_party_musl/raw/master/include/elf.h +``` + +## 开始编译 + +### 预置条件 + +1. 需要先获取一个可用的protoc可执行文件,或者在linux平台上执行: + +``` +./build.sh protoc +``` + +来生成可用的protoc可执行的程序。 + +2. 生成proto相关文件对应的pb.h或pb.cc文件。 + 可执行如下脚本来完成: + +``` +./src/protos/protogen.sh +``` + +### 编译linux、mac、windows平台的TraceStreamer + +编译不同平台的程序,需要在各自的PC环境编译,编译脚本会自行识别平台并编译程序。 +目前wasm版本仅支持在linux平台编译。 +编译不同版本:linux, windows, mac。 +注意,windows上目前支持Mingw编译,使用的mingw版本为 gcc version 8.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)。 + +``` +./build.sh +``` + +如果需要编译debug版本的应用,只需要输入debug标识即可,否则,默认是release版本的应用。 + +``` +./build.sh linux debug +``` + +生成的可执行文件分别位于如下路径: + +``` +out/linux_debug +``` +此命令对于windows和mac平台同样生效。 +___在不同的平台上,均需要gn和ninja的可执行文件来执行gn工程相关的操作,比如,windows上是gn.exe和ninja.exe。 +在 [https://gitee.com/su_ze1688/public_tools/tree/master/gn](https://gitee.com/su_ze1688/public_tools/tree/master/gn) 目录下,可以获取不同平台下可用的gn和ninja可执行文件,同时,为linux平台下提供了protoc可执行文件。可以下载并部署在本地的prebuilts目录下。也可以在linux平台下执行:___ + +``` +./build.sh protoc +``` + +___来生成out/linux/protoc可执行文件。___ + +### 编译WebAssembly版本 + +如果需要编译WebAssembly版本,需要在prebuilts/目录下安装emsdk。 +步骤如下: + +1. 在任何目录下载emsdk。 + +``` +git clone https://github.com/juj/emsdk.git --depth=1 +cd emsdk +git pull +./emsdk update # this may not work, ignore it +./emsdk install latest +./emsdk activate latest +``` + +2. 部署emsdk到编译工具目录 + 将刚刚下载和安装的emsdk目录下的 upstream/* 复制到prebuilts/emsdk/emsdk,node/* 复制到prebuilts/emsdk/node。 + 安装之后,目录结构当如下: + +``` +prebuilts/emsdk +├── prebuilts/emsdk/emsdk +│ ├── prebuilts/emsdk/emsdk/bin +│ ├── prebuilts/emsdk/emsdk/emscripten +│ │ ├── prebuilts/emsdk/emsdk/emscripten/cache +│ │ ├── prebuilts/emsdk/emsdk/emscripten/cmake +│ │ ├── prebuilts/emsdk/emsdk/emscripten/docs +│ │ ├── prebuilts/emsdk/emsdk/emscripten/media +│ │ ├── prebuilts/emsdk/emsdk/emscripten/node_modules +│ │ ├── prebuilts/emsdk/emsdk/emscripten/__pycache__ +│ │ ├── prebuilts/emsdk/emsdk/emscripten/src +│ │ ├── prebuilts/emsdk/emsdk/emscripten/system +│ │ ├── prebuilts/emsdk/emsdk/emscripten/tests +│ │ ├── prebuilts/emsdk/emsdk/emscripten/third_party +│ │ └── prebuilts/emsdk/emsdk/emscripten/tools +│ ├── prebuilts/emsdk/emsdk/include +│ │ └── prebuilts/emsdk/emsdk/include/c++ +│ └── prebuilts/emsdk/emsdk/lib +│ └── prebuilts/emsdk/emsdk/lib/clang +└── prebuilts/emsdk/node + └── prebuilts/emsdk/node/14.18.2_64bit + ├── prebuilts/emsdk/node/14.18.2_64bit/bin + ├── prebuilts/emsdk/node/14.18.2_64bit/include + ├── prebuilts/emsdk/node/14.18.2_64bit/lib + └── prebuilts/emsdk/node/14.18.2_64bit/share +``` + +之后,在TraceStream代码根目录,也就是这个文档的上级目录下执行: + +``` +./build.sh wasm +``` + +需要将sh脚本进行部分修改,因为这个脚本内置了一些库的下载和解析方式,也可以在编译环境对此脚本做定制修改。 diff --git a/trace_streamer/doc/compiler_ut.md b/trace_streamer/doc/compiler_ut.md new file mode 100644 index 0000000000000000000000000000000000000000..b971434b35677923e506e0ad03db7acbee0286f5 --- /dev/null +++ b/trace_streamer/doc/compiler_ut.md @@ -0,0 +1,31 @@ +# 编译UT +本文档给了编译trace_streamer的UT代码的方法。 +直接运行./build.sh test 即可编译代码,此代码不包含src/parser/htrace_parser目录下代码。如要编译src/parser/htrace_parser目录代码,直接运行./build.sh testpb即可。 +编译ut时,可能会遇到一些问题,需要将部分代码做如下处理: +v412.pb.h 大约第36行,添加如下内容: +``` +#ifdef major +#undef major +#endif +#ifdef minor +#undef minor +#endif +``` +js_heap_result.pb.cc文件中schemas替换成resultSchemas。 +js_heap_result.pb.cc文件中file_default_instances替换成result_file_default_instances。 +gtest-port.h 第286行。 +``` +#include +``` +修改为: +``` +#undef private +#define private private +#include +#undef private +#define private public +``` + +在ut代码编译完成之后,直接运行./test.sh,可以执行所有ut,显示正确与否。 +在ut执行之后,直接运行./lcov.sh,可以生成覆盖率报告。 +覆盖率报告位于out/test/html目录。 \ No newline at end of file diff --git a/trace_streamer/doc/des_binder.md b/trace_streamer/doc/des_binder.md new file mode 100644 index 0000000000000000000000000000000000000000..5d6301c3a3c0cf7e4d94f07a6985336f6144ce39 --- /dev/null +++ b/trace_streamer/doc/des_binder.md @@ -0,0 +1,58 @@ +# binder事件上下文如何关联 +binder事件相对复杂,这里是从ftrace事件中抽离出来的binder相关消息,用来作为开发者或用户追踪binder事件的参考。 +a binder event is identified by the sender and receive device, and a reply message only end +the last binder msg which reply the calling one. +the alloc_buf msg can always flow the binder_transaction, so we no need to identify the alloc msg with transactionID. + +## TAG TT need reply!!! needReply = !isReply && !(flags & 0x01) +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128108: binder_transaction: transaction=25155526 dest_node=25155471 dest_proc=506 dest_thread=0 reply=0 flags=0x10 code=0x9 +RenderThread-2267 ( 1592) [003] ...1 168766.128110: binder_transaction_alloc_buf: transaction=25155526 data_size=120 offsets_size=8 +``` +### received +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128154: binder_transaction_received: transaction=25155526 +``` +### binder is in DB, TAG A needReply +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128221: binder_transaction: transaction=25155529 dest_node=25155527 dest_proc=1592 dest_thread=2267 reply=0 flags=0x10 code=0x5f474854 +Binder:506_2-537 ( 506) [003] ...1 168766.128223: binder_transaction_alloc_buf: transaction=25155529 data_size=72 offsets_size=0 +``` +### the flowing is for TAG A, this is the reply for TAG A +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128262: binder_transaction: transaction=25155530 dest_node=0 dest_proc=506 dest_thread=537 reply=1 flags=0x8 code=0x0 + +RenderThread-2267 ( 1592) [003] ...1 168766.128264: binder_transaction_alloc_buf: transaction=25155530 data_size=4 offsets_size=0 +``` +### calc the dur of TAG A +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128288: binder_transaction_received: transaction=25155530 +``` +### binder last TAG A needReply, this is TAG B needReply!!! +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128328: binder_transaction: transaction=25155532 dest_node=25155527 dest_proc=1592 dest_thread=2267 reply=0 flags=0x10 code=0x2 +Binder:506_2-537 ( 506) [003] ...1 168766.128330: binder_transaction_alloc_buf: transaction=25155532 data_size=72 offsets_size=0 +``` +## in db +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128347: binder_transaction_received: transaction=25155532 +``` +## the reply message is not in db Session D, this is the reply for TAG B +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128361: binder_transaction: transaction=25155533 dest_node=0 dest_proc=506 dest_thread=537 reply=1 flags=0x0 code=0x0 +RenderThread-2267 ( 1592) [003] ...1 168766.128363: binder_transaction_alloc_buf: transaction=25155533 data_size=4 offsets_size=0 +``` +### no this message in db, calcate the dur of TAG B +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128385: binder_transaction_received: transaction=25155533 +``` +### no this message in db Session E, this is the reply for TAG TT +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128412: binder_transaction: transaction=25155534 dest_node=0 dest_proc=1592 dest_thread=2267 reply=1 flags=0x0 code=0x0 + +Binder:506_2-537 ( 506) [003] ...1 168766.128413: binder_transaction_alloc_buf: transaction=25155534 data_size=68 offsets_size=0 +``` +## the dur of TAG TT is calcated by the flowing msg +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128430: binder_transaction_received: transaction=25155534 +``` \ No newline at end of file diff --git a/trace_streamer/doc/des_native_hook_config.md b/trace_streamer/doc/des_native_hook_config.md new file mode 100644 index 0000000000000000000000000000000000000000..27454e400fba4ac3acee3e1882d9bfb9cc264f3a --- /dev/null +++ b/trace_streamer/doc/des_native_hook_config.md @@ -0,0 +1,14 @@ +# native_hook配置文件解析逻辑 +TS通过解析native_hook_config.proto中的配置识别native_hook数据模式。 +理解以下内容,请参考《native_hook_config.proto》和《native_hook_result.proto》 +1. 当statistics_interval有值时,代表抓到的native_hook数据为统计数据, 并且默认使用了调用栈压缩和字符串压缩。 + 包含数据: RecordStatisticsEvent, StackMap(离线符号化时ip生效, 非离线符号化时frame_map_id生效). + 非离线符号化包含: ThreadNameMap, FilePathMAp, FrameMap, Frame + 离线符号化包含:SymbolTalbe, MapsInfo。 + 不包含数据:AllocEvent, FreeEvent, MmapEvent, MunmapEvent,MemTagEvent. +2. 当offline_symbolization为true时, 代表抓到的数据需要离线符号化处理。并且默认使用了调用栈压缩和字符串压缩。 + 生效message包括: SymbolTalbe, MapsInfo +3. 当callframe_compressed为true时, 代表抓到的数据使用了调用栈压缩。 并且默认使用字符串压缩。 + 生效message包括: StackMap, FrameMap。 +4. 当string_compressed为true时,字符串压缩生效。 + 生效message包括:FilePathMap, SymbolMap, ThreadNameMap(非统计数据生效)。 \ No newline at end of file diff --git a/trace_streamer/doc/des_stat.md b/trace_streamer/doc/des_stat.md new file mode 100644 index 0000000000000000000000000000000000000000..f7c275f6cc20fff1380ceb864ed6c9145c3ba193 --- /dev/null +++ b/trace_streamer/doc/des_stat.md @@ -0,0 +1,31 @@ +# TraceStreamer 解析数据状态表 +TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件状态。通过stat表可以对trace数据源中各个类型事件的数据的数量,数据质量有一个基本了解。 +我们对不同类型的数据,统计了收到多少条,数据逻辑是否匹配,是否有不合法数据,是否有数据丢失情况,所有这些,是基于对数据格式本身和数据前后关系的主观认识。欢迎开发者提供更多的思路来帮我们完善数据本身的校验工作。 +## stat表支持统计的事件 +如[des_support_event.md](des_support_event.md)中所描述。 +## 事件对应解析状态 +每种事件解析数据都有5种状态,描述如下表: +|stat_type|description| +|---- |---- | +|received | 统计trace数据源中总共有多少该事件。| +|data_lost | 统计TraceStreamer解析过程中发现丢失数据条数。 | +|not_match | 统计有多少数据与上下文其他数据不匹配。 | +|not_supported | 统计有多少暂不支持解析该事件(一个事件可能包含多种类型的子事件, TraceStreamer可能支持该事件的一部分子事件)。| +|invalid_data | 统计收到多少条该事件的非法数据。| + +## 数据状态级别 +数据状态级别总共有4种,分别是:info, warn, error,fatal。由于数据的重要性不同,不同事件的同一种状态可能对应不同的级别。 +例如binder_transaction_received的 not_supported状态的数据为info级别,而binder_transaction_alloc_buf的not_supported状态数据为warn级别。 +可以在src/cfg/trace_streamer_config.cpp的InitSecurityMap方法中自行定义相关事件的优先级。 + +## 事件,状态与级别对应关系 +我们通过一张表,来记录所有事件的解析情况,拿下面这条数据举例: +| event_name | count| stat_type | serverity | +|---- |---|---- |---- | +| binder_transaction |12| received | info | +| binder_transaction |1| data_lost | error | +| binder_transaction |3| not_match | info | +| binder_transaction |0| not_supported | info | +| binder_transaction |5| invalid_data | error | +| - | - |-|- | +上面的图表表示:一共收到了12条binder_transaction的数据,其中有3条数据业务上不匹配,有5条数据格式非法。 \ No newline at end of file diff --git a/trace_streamer/doc/des_support_event.md b/trace_streamer/doc/des_support_event.md new file mode 100644 index 0000000000000000000000000000000000000000..54ce8679acc4163f9fbd6eb3b426ecdba2055959 --- /dev/null +++ b/trace_streamer/doc/des_support_event.md @@ -0,0 +1,269 @@ +# TraceStreamer支持识别事件列表 +trace事件是指系统在运行过程中输出的日志。trace事件有内核输出的,也有用户输出的,系统或用户在输出日志时,都可以添加特定的标识,以特定的格式输出。 +所谓事件,是指特定的标签,指定了其事件类型。 +## ftrace事件 +ftrace属于linux标准内核事件。 +ftrace相关事件属于系统内核事件,具体请参考linux内核相关技术网站(www.kernel.org)。 +``` +binder_transaction +binder_transaction_received +binder_transaction_alloc_buf +binder_transaction_lock +binder_transaction_locked +binder_transaction_unlock +sched_switch +task_rename +task_newtask +tracing_mark_write +print +sched_wakeup +sched_waking +cpu_idle +cpu_frequency +suspend_resume +workqueue_execute_start +workqueue_execute_end +clock_set_rate +clock_enable +clock_disable +clk_set_rate +clk_enable +clk_disable +sys_enter +sys_exit +irq_handler_entry +irq_handler_exit +softirq_raise +softirq_entry +softirq_exit +sched_wakeup_new +sched_process_exit +trace_event_clock_sync +// 下面的事件,属于ftrace,TraceStream可以识别并记录,但并不做业务解析。 +ipi_entry +ipi_exit +regulator_set_voltage +regulator_set_voltage_complete +regulator_disable +regulator_disable_complete +signal_generate +signal_deliver +trace_block_bio_backmerge +trace_block_bio_bounce +trace_block_bio_complete +trace_block_bio_frontmerge +trace_bblock_bio_queue +trace_block_bio_remap +trace_block_dirty_buffer +trace_block_getrq +trace_block_plug +trace_block_rq_complete +trace_block_rq_insert +trace_block_rq_remap +trace_block_rq_issue +``` +## 其他插件数据 +以下的数据,来自于htrace(序列化后的trace)的其他插件。 +注:如果是文本的trace的话,只支持ftrace。 +``` +memory +hilog +hidump_fps +native_hook_malloc +native_hook_free +native_hook_mmap +native_hook_munmap +sys_memory +sys_virtual_memory +trace_diskio +trace_process +trace_cpu_usage +trace_network +trace_perf +trace_ebpf +trace_ebpf_file_system +trace_ebpf_paged_memory +trace_ebpf_bio_latency +trace_hisys_event +trace_smaps +``` +## 进程的内存事件 +``` +mem.vm.size +mem.rss +mem.rss.anon +mem.rss.file +mem.rss.schem +mem.swap +mem.locked +mem.hwm +mem.oom_score_adj +``` +## 系统内存事件 +``` +sys.mem.unspecified +sys.mem.total +sys.mem.free +sys.mem.avaiable +sys.mem.buffers +sys.mem.cached +sys.mem.swap.chard +sys.mem.active +sys.mem.inactive +sys.mem.active.anon +sys.mem.inactive.anon +sys.mem.active_file +sys.mem.inactive_file +sys.mem.unevictable +sys.mem.mlocked +sys.mem.swap.total +sys.mem.swap.free +sys.mem.dirty +sys.mem.writeback +sys.mem.anon.pages +sys.mem.mapped +sys.mem.shmem +sys.mem.slab +sys.mem.slab.reclaimable +sys.mem.slab.unreclaimable +sys.mem.kernel.stack +sys.mem.page.tables +sys.mem.commit.limit +sys.mem.commited.as +sys.mem.vmalloc.total +sys.mem.vmalloc.used +sys.mem.vmalloc.chunk +sys.mem.cma.total +sys.mem.cma.free +``` +## 系统虚拟内存事件 +``` +sys.virtual.mem.unspecified +sys.virtual.mem.nr.free.pages +sys.virtual.mem.nr.alloc.batch +sys.virtual.mem.nr.inactive.anon +sys.virtual.mem.nr.active_anon +sys.virtual.mem.nr.inactive.file +sys.virtual.mem.nr.active_file +sys.virtual.mem.nr.unevictable +sys.virtual.mem.nr.mlock +sys.virtual.mem.anon.pages +sys.virtual.mem.nr.mapped +sys.virtual.mem.nr.file.pages +sys.virtual.mem.nr.dirty +sys.virtual.mem.nr.writeback +sys.virtual.mem.nr.slab.reclaimable +sys.virtual.mem.nr.slab.unreclaimable +sys.virtual.mem.nr.page_table.pages +sys.virtual.mem.nr_kernel.stack +sys.virtual.mem.nr.overhead +sys.virtual.mem.nr.unstable +sys.virtual.mem.nr.bounce +sys.virtual.mem.nr.vmscan.write +sys.virtual.mem.nr.vmscan.immediate.reclaim +sys.virtual.mem.nr.writeback_temp +sys.virtual.mem.nr.isolated_anon +sys.virtual.mem.nr.isolated_file +sys.virtual.mem.nr.shmem +sys.virtual.mem.nr.dirtied +sys.virtual.mem.nr.written +sys.virtual.mem.nr.pages.scanned +sys.virtual.mem.workingset.refault +sys.virtual.mem.workingset.activate +sys.virtual.mem.workingset_nodereclaim +sys.virtual.mem.nr_anon.transparent.hugepages +sys.virtual.mem.nr.free_cma +sys.virtual.mem.nr.swapcache +sys.virtual.mem.nr.dirty.threshold +sys.virtual.mem.nr.dirty.background.threshold +sys.virtual.mem.vmeminfo.pgpgin +sys.virtual.mem.pgpgout +sys.virtual.mem.pgpgoutclean +sys.virtual.mem.pswpin +sys.virtual.mem.pswpout +sys.virtual.mem.pgalloc.dma +sys.virtual.mem.pgalloc.normal +sys.virtual.mem.pgalloc.movable +sys.virtual.mem.pgfree +sys.virtual.mem.pgactivate +sys.virtual.mem.pgdeactivate +sys.virtual.mem.pgfault +sys.virtual.mem.pgmajfault +sys.virtual.mem.pgrefill.dma +sys.virtual.mem.pgrefill.normal +sys.virtual.mem.pgrefill.movable +sys.virtual.mem.pgsteal.kswapd.dma +sys.virtual.mem.pgsteal.kswapd.normal +sys.virtual.mem.pgsteal.kswapd.movable +sys.virtual.mem.pgsteal.direct.dma +sys.virtual.mem.pgsteal.direct.normal +sys.virtual.mem.pgsteal_direct.movable +sys.virtual.mem.pgscan.kswapd.dma +sys.virtual.mem.pgscan_kswapd.normal +sys.virtual.mem.pgscan.kswapd.movable +sys.virtual.mem.pgscan.direct.dma +sys.virtual.mem.pgscan.direct.normal +sys.virtual.mem.pgscan.direct.movable +sys.virtual.mem.pgscan.direct.throttle +sys.virtual.mem.pginodesteal +sys.virtual.mem.slabs_scanned +sys.virtual.mem.kswapd.inodesteal +sys.virtual.mem.kswapd.low.wmark.hit.quickly +sys.virtual.mem.high.wmark.hit.quickly +sys.virtual.mem.pageoutrun +sys.virtual.mem.allocstall +sys.virtual.mem.pgrotated +sys.virtual.mem.drop.pagecache +sys.virtual.mem.drop.slab +sys.virtual.mem.pgmigrate.success +sys.virtual.mem.pgmigrate.fail +sys.virtual.mem.compact.migrate.scanned +sys.virtual.mem.compact.free.scanned +sys.virtual.mem.compact.isolated +sys.virtual.mem.compact.stall +sys.virtual.mem.compact.fail +sys.virtual.mem.compact.success +sys.virtual.mem.compact.daemon.wake +sys.virtual.mem.unevictable.pgs.culled +sys.virtual.mem.unevictable.pgs.scanned +sys.virtual.mem.unevictable.pgs.rescued +sys.virtual.mem.unevictable.pgs.mlocked +sys.virtual.mem.unevictable.pgs.munlocked +sys.virtual.mem.unevictable.pgs.cleared +sys.virtual.mem.unevictable.pgs.stranded +sys.virtual.mem.nr.zspages +sys.virtual.mem.nr.ion.heap +sys.virtual.mem.nr.gpu.heap +sys.virtual.mem.allocstall.dma +sys.virtual.mem.allocstall.movable +sys.virtual.mem.allocstall.normal +sys.virtual.mem.compact_daemon.free.scanned +sys.virtual.mem.compact.daemon.migrate.scanned +sys.virtual.mem.nr.fastrpc +sys.virtual.mem.nr.indirectly.reclaimable +sys.virtual.mem.nr_ion_heap_pool +sys.virtual.mem.nr.kernel_misc.reclaimable +sys.virtual.mem.nr.shadow_call.stack_bytes +sys.virtual.mem.nr.shmem.hugepages +sys.virtual.mem.nr.shmem.pmdmapped +sys.virtual.mem.nr.unreclaimable.pages +sys.virtual.mem.nr.zone.active.anon +sys.virtual.mem.nr.zone.active.file +ys.virtual.mem.nr.zone.inactive_anon +sys.virtual.mem.nr.zone.inactive_file +sys.virtual.mem.nr.zone.unevictable +sys.virtual.mem.nr.zone.write_pending +sys.virtual.mem.oom.kill +sys.virtual.mem.pglazyfree +sys.virtual.mem.pglazyfreed +sys.virtual.mem.pgrefill +sys.virtual.mem.pgscan.direct +sys.virtual.mem.pgscan.kswapd +sys.virtual.mem.pgskip.dma +sys.virtual.mem.pgskip.movable +sys.virtual.mem.pgskip.normal +sys.virtual.mem.pgsteal.direct +sys.virtual.mem.pgsteal.kswapd +sys.virtual.mem.swap.ra +sys.virtual.mem.swap.ra.hit +``` \ No newline at end of file diff --git a/trace_streamer/doc/des_tables.md b/trace_streamer/doc/des_tables.md new file mode 100755 index 0000000000000000000000000000000000000000..15a489c2a13aa7f10135191671b3dc4d00430b03 --- /dev/null +++ b/trace_streamer/doc/des_tables.md @@ -0,0 +1,1433 @@ +# TraceStreamer数据表概述 +TraceStreamer可以将trace数据源转化为易于理解和使用的数据库。用户可以通过SmartPerf界面直观的研究系统跟踪数据,也可在理解TraceStreamer生成的数据库的基础上,在TraceStreamer的交互模式或者Smartperf的数据库查询模式下,使用SQL查询语句自由组装查看用户关心的数据。下文将对TraceStreamer生成的数据库进行详细描述,给用户使用SQL查询系统跟踪数据提供帮助。 + +## TraceStreamer输出的数据表分类 +* 常规泳道图数据表 +![GitHub Logo](../figures/db_common.png) +* native memory数据源相关表 +![GitHub Logo](../figures/db_native_memory.png) +* perf相关数据表 +![GitHub Logo](../figures/db_hiperf.png) +* hisysevent相关数据表 +![GitHub Logo](../figures/db_hisys_event.png) +## TraceStreamer输出数据库包含以下表格 +| 表名称 |作用| +| ---- |---- | +| app_name | 记录HiSysEvent事件的事件名与IDE部分事件的字段名为APPNAME中存放的相关信息的映射关系 | +| args | 记录方法参数集合| +| bio_latency_sample | 记录IO操作相关方法调用,及调用栈数据| +| callstack | 记录调用堆栈和异步调用信息,其中depth,stack_id和parent_stack_id仅在非异步调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号| +| clk_event_filter | 记录时钟相关的信息| +| clock_event_filter | 此结构用来维护时钟事件,cpu与唯一的ID做关联| +| cpu_measure_filter | cpu事件过滤器表| +| cpu_usage | 记录CPU使用率事件| +| data_dict | 记录常用的字符串,将字符串和索引关联,降低程序运行的内存占用,用作辅助数据| +| data_type | 记录数据类型和typeId的关联关系| +| diskio | 记录磁盘读写数据事件| +| ebpf_callstack | 记录了采样相关信息| +| file_system_samp | 记录了调用栈的相关信息| +| hidump | 记录FPS(Frame Per Second)数据| +| hisys_event_measure | 记录了HiSysEvent事件相关数据,目前HiSysEvent事件包括了异常事件,IDE事件,器件状态事件 | +| instant | 记录Sched_waking, sched_wakeup事件, 用作ThreadState表的上下文使用 | +| irq | 记录中断相关事件| +| js_heap_edges | 记录了js内存数据类对象对应的成员的信息| +| js_heap_files | 记录了js内存数据的名称和时间| +| js_heap_info | 记录了js内存数据类型,如nodes和edges的字段类型和数据总数| +| js_heap_location | 记录了js内存location节点相关数据| +| js_heap_nodes | 记录了js内存类对象和其成员的对应关系| +| js_heap_sample | 记录了timeline模式下的时间轴信息| +| js_heap_string | 记录了js内存数据中的字符串| +| js_heap_trace_function_info | 记录了timeline模式下的调用栈的每个函数信息| +| js_heap_trace_node | 记录了timeline模式下的调用栈信息| +| live_process | 记录了一些实时的进程中执行的一些数据| +| log | 记录hilog打印日志数据| +| measure_filter | 记录一个递增的filterid队列,所有其他的filter类型在获取过程中,均从此数据列表中获取下一个可用的filter_id并做记录| +| meta | 记录执行解析操作相关的基本信息| +| native_hook | 记录堆内存申请与释放相关的数据| +| native_hook_frame | 记录堆内存申请与释放相关的调用栈| +| network | 抓取网络信息传输时产生的一些相关信息| +| paged_memory_sample | 记录内存操作相关方法调用,及调用栈数据| +| perf_callchain | 记录Hiperf采样数据的调用栈信息| +| perf_files | 记录Hiperf工具采集到的函数符号表和文件名| +| perf_report | 记录Hiperf工具采集数据时的配置信息。包括|抓取的事件类型,抓取数据的命令, 抓数据时指定的进程名称| +| perf_sample | 记录Hiperf工具的采样信息| +| perf_thread | 记录Hiperf工具采集到的进程和线程数据| +| process | 记录所有的进程信息| +| process_filter | 过滤进程| +| process_measure | 保存进程的所有计量值| +| process_measure_filter | 将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id| +| raw | 此数据结构主要作为ThreadState的上下文使用,这张表是sched_waking,sched_wakup, cpu_idle事件的原始记录| +| sched_slice | 此数据结构主要作为ThreadState的上下文使用,这张表是sched_switch事件的原始记录| +| smaps | 记录进程的内存消耗的相关信息采样| +| stat | 此结果用来统计数据解析中各类数据的数据条数,数据和合法性,数据的匹配程度(begin-end),数据的损失等,查看此结构对应的表,可对数据源有基本的了解| +| symbols | 记录系统调用名称和其函数指针的对应关系,trace中用addr来映射function_name来节省存储空间| +| syscall | 记录用户空间函数与内核空间函数相互调用记录| +| sys_event_filter | 记录所有的filter| +| sys_mem_measure | 记录了所有的系统内存相关的测量信息| +| thread | 记录所有的线程信息| +| thread_filter | 过滤线程| +| thread_state | 记录线程状态信息| +| trace_range | 记录ftrace数据与其他类型数据的时间交集,供前端展示数据时使用| +| clock_snapshot | 时钟号和时间,时钟名的映射表| +| datasource_clockid | 数据源和时钟号的映射表| +## 表与事件来源 +| 表名称 | 事件源 | 插件名 | 备注 | +| ---- | ---- | ---- | ---- | +|app_name | - |hisysevent-plugin |JSON数据源 | +|args | - |ftrace-plugin |配合callstack使用 | +|callstack | - |ftrace-plugin |异步或非异步的调用 | +|cpu_measure_filter | - |ftrace-plugin |cpu跟踪器,cpu频率等 | +|cpu_usage | - |cpu-plugin |cpu使用率 | +|data_dict | 通用的 | - |所有字符串的记录 | +|data_type | 通用的 | - |辅助表 | +|file_system_callstack | - | - |ebpf文件系统 | +|file_system_sample | - | - |ebpf文件系统 | +|frame_maps | - |ftrace-plugin |帧渲染数据,app到RS的映射 | +|frame_slice | - |ftrace-plugin |帧渲染数据 | +|gpu_slice | - |ftrace-plugin |gpu渲染时长 | +|hidump | - |hidump-plugin |FPS数据 | +|hisys_event_measure | - |hisysevent-plugin |JSON数据源 | +|instant | - |ftrace-plugin |waking和wakeup事件 | +|irq | - |ftrace-plugin |记录中断事件 | +| js_heap_edges | - |js-memory | js内存数据 | +| js_heap_files | - |js-memory | js内存数据 | +| js_heap_info | - |js-memory | js内存数据 | +| js_heap_location | - |js-memory | js内存数据 | +| js_heap_nodes | - |js-memory | js内存数据 | +| js_heap_sample | - |js-memory | js内存数据 | +| js_heap_string | - |js-memory | js内存数据 | +| js_heap_trace_function_info | - |js-memory | js内存数据 | +| js_heap_trace_node | - |js-memory | js内存数据 | +|live_process | - |process-plugin |Monitor数据 | +|network | - |network-plugin |Monitor数据 | +|diskio | - |diskio-plugin |Monitor数据 | +|log | - |hilog-plugin |系统日志 | +|measure | 通用的 | - |系统中的计量值(数值型)| +|measure_filter | 通用的 | - |计量值的查询辅助表 | +|meta | 通用的 | - |记录解析现场数据(解析时间,数据类型,解析工具等)| +|native_hook | - |nativehook/hookdaemon |内存数据 | +|native_hook_frame | - |nativehook/hookdaemon |内存数据 | +|perf_callchain | - |perf-plugin |perf数据(非插件模式) | +|perf_files | - | - |perf数据(非插件模式) | +|perf_report | - | - |perf数据(非插件模式) | +|perf_sample | - | - |perf数据(非插件模式) | +|perf_thread | - | - |perf数据(非插件模式) | +|process | - |ftrace-plugin |进程信息 | +|process_filter | - |ftrace-plugin |进程计量表的辅助表 | +|process_measure | - |ftrace-plugin |进程内存 | +|process_measure_filter| - |ftrace-plugin |process_measure的辅助表| +|raw | - |ftrace-plugin |线程唤醒信息 | +|sched_slice | - |ftrace-plugin |配合现场状态表使用,dsched_switch的原始数据| +|smaps | - |memory-plugin |进程的内存消耗 | +|stat | 通用的 | - |记录不同种类数据的数据量| +|symbols | - |ftrace-plugin |符号表(地址到字符串的映射)| +|syscall | - |ftrace-plugin |系统调用 sys_enter/exit| +|sys_event_filter | - |ftrace-plugin | | +|sys_mem_measure | - |memory-plugin |系统内存 | +|thread | 通用的 | - |线程信息(常用) | +|thread_state | 通用的 |ftrace-plugin |线程调度图(常用) | +|trace_range | 通用的 | - |trace数据的时长 | +|thread_filter | 通用的 |ftrace-plugin |线程计量跟踪表(比较少用)| +|clock_snapshot | 通用的 |通用的 |时钟号和时间,时钟名的映射表| +|datasource_clockid | 通用的 |通用的 |数据源和时钟号的映射表| + +## ___表格关系图___ +--- +### 进程表与线程表关系 +当一个进程或者线程结束后,系统可能再次将该进程号或者线程号分配给其他进程或者线程,造成一个进程号或线程号代表多个进程或线程的情况。 +Process和Thread表中的id字段可以唯一标识进程和线程。process表中的id在其他表中用作ipid字段。thread表中的id在其他表中用作itid字段。 +thread表通过ipid字段关联process表的id字段,可以查询线程归属进程。 +![GitHub Logo](../figures/process_thread.png) +### 查询举例 +- 已知pid = 123,查看当前进程下的所有线程信息,可以使用如下SQL语句: +```select thread.* from thread, process where process.pid = 123 and thread.ipid = process.id``` + +### 线程表与线程运行状态表关系图 +thread_state表记录所有线程的运行状态信息,包含ts(状态起始时间),dur(状态持续时间),cpu, itid, state(线程状态)。 thread表的id字段与thread_state表的itid字段相关联。 +![GitHub Logo](../figures/thread_state.png) +### 查询举例 +- 已知tid = 123, 查看当前线程的所有运行状态信息,可以使用如下SQL语句: +```select thread_state.* from thread, thread_state where thread.tid = 123 and thread.id = thread_state.itid``` + +### 堆内存数据变化表关系图 +native_hook表记录堆内存申请(AllocEvent)和释放(FreeEvent)数据。native_hook表通过ipid和itid字段分别与process和thread表的id字段关联,通过callChainId与native_hook_frame表的callChainId字段相关联。 +native_hook表字段解释如下: +- callChainId:唯一标识一次堆内存申请或释放, 通过与native_hook_frame表关联可以拿到当前申请或释放的函数调用堆栈。 +- addr:堆内存申请/释放的地址。 +- native_hook_size:堆内存申请/释放的大小。 + +native_hook_frame表记录内存申请/释放的调用堆栈。通过callChainId区分一组调用堆栈,depth为堆栈深度,depth为0时,表示当前行为栈顶数据。 +![GitHub Logo](../figures/dump_and_mem.png) +### 查询举例 +- 已知tid = 123,查看当前线程的所有堆内存变化信息,可以使用如下SQL语句: +```select native_hook.* from thread, native_hook where thread.tid = 123 and thread.id = native_hook.itid``` +- 已知callchainid = 0, 查看当前内存变化调用堆栈 +```select * from native_hook_frame where callChainId = 0``` + +### 日志表与进程线程表关系图 +log表记录日志信息。可以根据seq字段的连续性,来判断是否存在日志丢失的情况。 +![GitHub Logo](../figures/log.png) +### 查询举例 +- 已知tid = 123,查看当前线程的所有error级别的日志,可以使用如下SQL语句: +```select * from log where tid = 123 and level = "error"``` + +### perf表之间关系图 +- perf_report:此表记录Hiperf工具采集数据时的配置信息。 +- perf_thread:此表记录hiperf采集到的进程和线程数据。 +- perf_sample:此表中记录Hiperf工具的采样信息。sample_id唯一表识一次采样记录,与perf_callchain表中的sample_id字段相关联。thread_id为线程号。与perf_thread表中的thread_id字段相关联。event_type_id为当前采样的事件类型id,与perf_report表中的id字段相关联。 +- perf_callchain:此表格记录的是调用栈信息。 +- Perf_files:此表格主要存放着获取到的函数符号表和文件信息。file_id唯一表识一个文件,与perf_callchain表中的file_id字段相关联。 + +![GitHub Logo](../figures/perf.png) +### 查询举例 +- 已知同步后的时间戳为28463134340470,查询采样数据 +```select * from perf_sample where timestamp_trace = 28463134340470``` + +- 已知同步后的时间戳为28463134340470,查询采样数据对应的的调用栈信息 +```select A.* from perf_callchain as A, perf_sample as B where B.timestamp_trace = 28463134340470 and A.sample_id = B.sample_id``` + +- 已知同步后的时间戳为28463134277762,查询采样数据的函数名及文件路径 +```select A.*, B.name, C.path from perf_sample as A, perf_callchain as B, perf_files as C where A.timestamp_trace = 28463134277762 and B.sample_id = A.sample_id and B.callchain_id = 0 and B.file_id = C.file_id and C.serial_id = 0``` + +- 已知线程号为6700,查询所有的采样记录 +```select * from perf_sample where thread_id = 6700``` + +- 已知进程号为7863,查询所有的采样记录 +```select A.* from perf_sample as A, perf_thread as B where B.process_id = 7863 and A.thread_id = B.thread_id``` + +- 查询所有采样对应的事件类型 +```select A.*, B.report_value from perf_sample as A, perf_report as B where A.event_type_id = B.id``` + +### 帧渲染表之间的关系图 +frame_slice: 记录RS(RenderService)和应用的帧渲染。 +gpu_slice: 记录RS的帧对应的gpu渲染时长。 +frame_maps:记录应用到RS的帧的映射关系。 +![GitHub Logo](../figures/frames.jpg) +### 查询示例 +- 已知进程,查询进程对应的实际渲染帧 +```select * from frame_slice where ipid = 1``` + +- 已知进程的实际渲染帧的dst为12,求其对应的RS进程的渲染帧 +```select * from frame_slice where id = 12 ``` + +- 已知RS的渲染帧在frame_slice中所在行是14,求其对应的GPU渲染时长 +```select * from gpu_slice where frame_row = 14``` + +### JS内存数据表关系图 + +js_heap_files:记录js内存数据的文件名和文件索引 + +![1683163158954](image/des_tables/1683163158954.png) + +js_heap_nodes:记录js内存类对象数据 +js_heap_edges:记录js内存类对象的成员数据 +js_heap_trace_node:记录timeline的调用栈信息 +js_heap_sample:记录timeline的时间轴信息 +![1683163373206](image/des_tables/1683163373206.png) +## TraceStreamer输出数据库表格详细介绍 +### app_name表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|flag |INT | +|app_name |INT | +|app_key |INT | +#### 表描述 +记录HiSysevent上报事件中的IDE相关事件中APPNAME的表关联信息。 +#### 字段详细描述 +- id:用于与表hisys_event_measure表中的key_id字段做对应 +- app_name:对应的事件的信息ID +- app_key:对应的事件的APPNAME字段的信息ID + +### args表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|key |INT | +|datatype |INT | +|value |INT | +|argset |INT | +#### 表描述 +记录方法的参数集合。 +#### 字段详细描述 +- key:键 +- datatype:数据类型 +- value:取值 +- argset:参数集合 + +### bio_latency_sample表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callchain_id |INT | +|datatype |INT | +|type |INT | +|ipid |INT | +|itid |INT | +|start_ts |INT | +|end_ts |INT | +|latency_dur |INT | +|tier |INT | +|size |INT | +|block_number |TEXT | +|path |TEXT | +|dur_per_4k |INT | +#### 表描述 +记录IO操作相关方法调用,及调用栈数据。 +#### 字段详细描述 +- callchain_id:调用栈的唯一标识。与ebpf_callstack表中Callchain_id字段关联 +- type:事件类型其取值为枚举类型(DATA_READ,DATA_WRITE,METADATA_READ,- METADATA_WRITE,PAGE_IN,PAGE_OUT) +- ipid:TS内部进程号 +- itid:TS内部线程号 +- start_ts:开始时间 +- end_ts:结束时间 +- latency_dur:总延迟 +- tier:优先级 +- size:文件大小 +- block_number:数据量大小(一般为4K) +- path:路径id +- dur_per_4k:每4k数据的平均延迟 + +### callstack表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|ts |INT | +|dur |INT | +|callid |INT | +|cat |TEXT | +|identify |INT | +|name |TEXT | +|depth |INT | +|cookie |INT | +|parent_id |INT | +|argsetid |INT | +|chainId |TEXT | +|spanId |TEXT | +|parentSpanId |TEXT | +|flag |TEXT | +|args |TEXT | +#### 表描述 +记录调用堆栈和异步调用信息,其中depth,stack_id和parent_stack_id仅在非异步的调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号。 +#### 字段详细描述 +- dur:调用时长 +- callid:调用者的ID,比如针对线程表里面的id +- identify:调用栈的名字,与表dataDict相关联能够取出其string值 +- name:调用名称 +- depth:调用深度 +- parent_id:父调用的id +- spanId:分布式调用关联关系 +- flag:C表示分布式调用发送方,S表示接受方 +- args:分布式调用函数参数 + +### clk_event_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|cpu |INT | +#### 表描述 +记录时钟信息。 +#### 字段详细描述 +- Type:时钟事件类型 +- Name:时钟事件名称 + +### clock_event_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|cpu |INT | +#### 表描述 +此结构用来维护时钟事件,cpu与唯一的ID做关联。 +#### 主要字段描述 +- Type:时钟事件类型 +- Name:时钟事件名称 + +### cpu_measure_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|cpu |INT | +#### 表描述 +将cpu号作为key1,cpu的频率,空闲等状态作为key2,唯一确定一个filter_id。 +#### 主要字段描述 +- Id(filterid), cpu:事件名称,cpu号 + +### cpu_usage表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|total_load |REAL | +|user_load |REAL | +|system_load |REAL | +|process_num |INT | +#### 表描述 +记录了与CPU使用率相关的数据。 +#### 主要字段描述 +- total_load:总负荷 +- user_load:用户负载 +- system_load:系统负载 +- process_num:线程数 + +### data_dict表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|data |TEXT | +#### 表描述 +此表记录了一个数据类型ID和字符串的映射。 +#### 主要字段描述 +- id:索引值 +- data:字符串 + +### data_type表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|typeId |INT | +|desc |TEXT | +#### 表描述 +此表记录了一个数据类型ID和数据描述的映射。 +#### 主要字段描述 +- typeId::数据类型id +- Desc:数据类型描述 + +### diskio表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|rd |INT | +|wr |INT | +|rd_speed |REAL | +|wr_speed |REAL | +|rd_count |INT | +|wr_count |INT | +|rd_count_speed |REAL | +|wr_count_speed |REAL | +#### 表描述 +记录了与磁盘读写相关的数据。 +#### 主要字段描述 +- rd_sectors_kb:读数据的速度 +- wr_sectors_kb:写入数据的速度 +- ts:时间戳 + +### ebpf_callstack表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callchain_id |INT | +|depth |TEXT | +|ip |TEXT | +|symbols_id |INT | +|file_path_id |INT | +#### 表描述 +记录了与磁盘读写相关的数据。 +#### 主要字段描述 +- callchain_id:调用栈的唯一标识。与ebpf_callstack表中Callchain_id字段关联 +- depth:调用栈深度。取值为零时表示栈顶 +- ip:调用栈ip +- symbols_id:调用栈函数名称, 与data_dict中的id字段关联 +- file_path_id:调用栈函数所属文件路径, 与data_dict中的id字段关联 + +### file_system_sample表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|callchain_id |INT | +|type |INT | +|ipid |INT | +|itid |INT | +|start_ts |INT | +|end_ts |INT | +|dur |INT | +|return_value |TEXT | +|error_code |TEXT | +|fd |INT | +|file_id |INT | +|size |INT | +|first_argument |TEXT | +|second_argument |TEXT | +|third_argument |TEXT | +|fourth_argument |TEXT | +#### 表描述 +记录了调用栈的相关信息。 +#### 主要字段描述 +- callchain_id:调用栈信息ID与file_system_callstack表中call_chain_id字段相关联 +- type:对应文件操作open,close,read,write +- ipid:线程所属的进程ID +- start_ts:开始时间 +- end_ts:结束时间 +- dur:耗时 +- return_value:文件操作的返回值 +- error_code:文件操作发生错误时的错误码 +- fd:文件描述符fd +- file_id:当type为open,close时为其操作的文件路径,当type为read,write时为固定字段(null) +- size:在type为read,write时对应的文件的读或者写的大小 +- first_argument:参数一 +- second_argument:参数二 +- third_argument:参数三 +- fourth_argument:参数四 + +### hidump表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|ts |INT | +|fps |INT | +#### 表描述 +此表记录了设备的帧率信息,fps。 +#### 相关字段描述 +- fps:帧率值 + +### hisys_event_measure表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|serial |INT | +|ts |INT | +|name_id |INT | +|key_id |INT | +|type |INT | +|int_value |REAL | +|string_value |TEXT | +#### 表描述 +记录所有的system event事件的相关数据,及其相关表的映射信息。 +#### 相关字段描述 +- serial:每条数据过来携带唯一一条id作为标识 +- name_id:存放事件对应的ID,与data_dict表相关联可以取出对应的字段 +- key_id:存放事件包含的字段的ID,与表app_name的id字段相关联,找到app_name表的 id字段对应行的app_key字段与表data_dict表相关联取出对应的字段 +- type:存放事件所包含的字段的值所属的类型为int型还是string(0为int,1为string) +- int_value:存放本事件所包含的字段的int型的值 +- string_value:存放本事件所包含的字段的string型的值 + +### instant表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|name |TEXT | +|ref |INT | +|wakeup_from |INT | +|ref_type |TEXT | +|value |REAL | +#### 表描述 +记录了系统中的waking和wakeup事件。 +#### 字段描述 +- ts:唤醒时间 +- name:唤醒事件的名称 +- ref:索引号 +- wakeup_from:唤醒当前线程的内部线程号(itid) +- ref_type:描述了value字段的类型(一般取值为itid) +- value:一般为当前线程的内部线程号取值 + +### irq表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|ts |INT | +|dur |INT | +|callid |INT | +|cat |TEXT | +|name |TEXT | +|depth |INT | +|cookie |INT | +|parent_id |INT | +|argsetid |INT | +|chainId |TEXT | +|spanId |TEXT | +|parentSpanId |TEXT | +|flag |TEXT | +|args |TEXT | +#### 表描述 +记录中断相关事件。 +#### 相关字段描述 +- dur:调用中断时长 +- callid:调用中断者的ID,比如针对线程表里面的id +- cat:调用栈数据类型(取值范围:irq,softirq...) +- name:调用中断的名称 +- depth:中断调用的深度 +- parent_id:父调用中断的id +- spanId:分布式调用中断关联关系 + +### js_heap_edges表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------- | -------- | +| file_id | INT | +| edge_index | INT | +| type | INT | +| name_or_index | INT | +| to_node | INT | +| from_node_id | INT | +| to_node_id | INT | +#### 表描述 +记录js内存数据类对象对应的成员的信息。 +#### 相关字段描述 +- file_id:文件ID +- edge_index:成员的索引号 +- type:成员的类型,取值范围为js_heap_info表中的edge_types +- name_or_index:数据名称,取值为js_heap_string表中的下标索引 +- to_node:此成员指向的类对象在nodes数组中的索引 +- from_node_id:类对象ID,该类对象指向此成员数据 +- to_node_id:此成员指向到的类对象nodes数组中的ID + +### js_heap_files表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------ | -------- | +| id | INT | +| file_name | TEXT | +| start_time | INT | +| end_time | INT | +| pid | INT | +#### 表描述 +记录了js内存数据的文件名称和时间。 +#### 相关字段描述 +- id:文件ID +- file_name:文件名称 +- start_time:数据抓取的起始时间 +- end_time:数据抓取的终止时间 +- pid:进程号 + +### js_heap_info表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------ | -------- | +| file_id | INT | +| key | TEXT | +| type | INT | +| int_value | INT | +| str_value | TEXT | +#### 表描述 +记录了js内存数据类型,如nodes和edges的字段类型和数据总数。 +#### 相关字段描述 +- file_id:文件ID +- key:类型名称 +- type:数据类型索引 +- int_value:int类型的数据值,如count类型数据 +- str_value:string类型的数据值,如typename + +### js_heap_location表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------ | -------- | +| file_id | INT | +| object_index | INT | +| script_id | INT | +| line | INT | +| column | INT | +#### 表描述 +记录了js内存location节点相关数据,此表目前无抓取到的数据。 +#### 相关字段描述 +- file_id:文件ID +- object_index:与location关联的类对象的索引,取值为js_heap_nodes的下标索引 +- script_id:关联到的类对象所在文件的绝对路径ID +- line:在类对象所在的文件中的行号 +- column:在类对象所在的文件中的列号 + +### js_heap_nodes表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------- | -------- | +| file_id | INT | +| node_index | TEXT | +| type | INT | +| name | INT | +| id | TEXT | +| self_size | INT | +| edge_count | INT | +| trace_node_id | INT | +| detachedness | INT | +#### 表描述 +记录了js内存数据中类对象的数据。 +#### 相关字段描述 +- file_id:文件ID +- node_index:类对象的索引 +- type:类对象的类型 +- name:类对象的名称 +- id:类对象的唯一ID +- self_size:该类对象所有成员的大小(以字节为单位) +- edge_count:该类对象指向的类成员的个数 +- trace_node_id:该类对象关联到js_heap_trace_node表中的调用栈ID +- detachedness:是否可以从window全局对象访问此节点,0表示是,1表示否 + +### js_heap_sample表 +#### 表结构 +| Columns Name | SQL TYPE | +| ---------------- | -------- | +| file_id | INT | +| timestamp_us | INT | +| last_assigned_id | INT | +#### 表描述 +记录了timeline模式下的时间轴信息。 +#### 相关字段描述 +- file_id:文件ID +- timestamp_us:时间信息 +- last_assigned_id:当前时间点的id + +### js_heap_string表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------ | -------- | +| file_id | INT | +| file_index | INT | +| string | TEXT | +#### 表描述 +记录了js内存数据中的字符串。 +#### 相关字段描述 +- file_id:文件ID +- file_index:索引 +- string:对应的字符串信息 + +### js_heap_trace_function_info表 +#### 表结构 +| Columns Name | SQL TYPE | +| -------------- | -------- | +| file_id | INT | +| function_index | INT | +| function_id | INT | +| name | INT | +| script_name | INT | +| script_id | INT | +| line | INT | +| column | INT | +#### 表描述 +记录了timeline模式下的调用栈的每个函数信息。 +#### 相关字段描述 +- file_id:文件ID +- function_index:函数索引 +- function_id:函数ID +- name:函数名称 +- script_name:关联到的类对象所在文件的绝对路径名称 +- script_id:关联到的类对象所在文件的绝对路径ID +- line:在类对象所在的文件中的行号 +- column:在类对象所在的文件中的列号 + +### js_heap_trace_node表 +#### 表结构 +| Columns Name | SQL TYPE | +| ------------------- | -------- | +| file_id | INT | +| id | INT | +| function_info_index | INT | +| count | INT | +| size | INT | +| parent_id | INT | +#### 表描述 +记录了timeline模式下的调用栈的信息。 +#### 相关字段描述 +- file_id:文件ID +- id:调用栈节点索引 +- function_info_index:函数信息索引 +- count:调用栈个数 +- size:调用栈大小 +- parent_id:调用栈父节点 + +### live_process表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|cpu_time |INT | +|process_id |INT | +|process_name |TEXT | +|parent_process_id |INT | +|uid |INT | +|user_name |TEXT | +|cpu_usage |REAL | +|pss_info |INT | +|thread_num |INT | +|disk_writes |INT | +|disk_reads |INT | +#### 表描述 +记录了一些实时的进程中执行的一些数据(Monitor)。 +#### 主要字段描述 +- process_id:进程id +- process_name:进程名 +- parent_process_id:父进程的id +- uid:用户id +- user_name:用户名 +- cpu_usage:cpu使用率 +- pss_info:进程信息 +- thread_num:线程数量 +- disk_writes:磁盘写量 +- disk_reads:磁盘读量 + +### log表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|seq |INT | +|ts |INT | +|pid |INT | +|tid |INT | +|level |TEXT | +|tag |TEXT | +|context |TEXT | +|origints |INT | +#### 表描述 +记录日志信息。 +#### 关键字段描述 +- Seq:日志序号,保证日志解析的准确性 +- Ts:打印日志时间 +- Pid:日志的进程号 +- Tid:日志的线程号 +- Level:日志级别 +- Tag:日志标签 +- Context:日志内容 + +### measure表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|type |TEXT | +|ts |INT | +|dur |INT | +|value |INT | +|filter_id |INT | +#### 表描述 +记录所有的计量值。 +#### 关键字段描述 +- type:固定字段(measure) +- ts:事件时间 +- dur:该值持续的时长 +- value:数值 +- filter_id:对应filter表中的ID + +### measure_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|source_arg_set_id |INT | +#### 表描述 +记录一个递增的filterid队列,所有其他的filter类型在获取过程中,均从此数据列表中获取下一个可用的filter_id并做记录。 +#### 字段详细描述 +过滤分类(type),过滤名称(key2),数据ID(key1)。 +数据ID在process_measure_filter, sys_event_filter中作为id。 + +### meta表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|name |TEXT | +|value |TEXT | +#### 表描述 +此表记录了数据解析或导出时的一些现场数据,比如使用的TraceStreamer版本, 工具的发布时间,数据解析的时间,数据的持续时长,以及原始数据的格式。 +#### 主要字段描述 +- Name:指定元数据的key +- Value:指定元数据的value + +### native_hook表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callChainId |INT | +|ipid |INT | +|itid |INT | +|event_type |TEXT | +|sub_type_id |NUM | +|start_ts |INT | +|end_ts |INT | +|dur |INT | +|addr |INT | +|heap_size |INT | +|all_heap_size |INT | +|current_size_dur |INT | +|last_lib_id |INT | +#### 表描述 +记录native_hook抓取的某个进程的堆内存,内存映射相关数据。 +#### 关键字段描述 +- callChainId:唯一标识一条native_hook数据 +- event_type:事件类型取值范围(AllocEvent,FreeEvent,MmapEvent, MunmapEvent) +- sub_type_id:子事件类型(只有sub_type字段为MmapEvent时,该字段才会有值) +- start_ts:申请内存开始时间 +- end_ts:释放内存时间 +- Dur:申请内存活跃时间 +- Addr:申请内存地址 +- mem_size:申请或释放内存大小 +- all_mem_size:从采集数据开始到当前时刻,申请并活跃的内存总量。 event_type为AllocEvent或者FreeEvent时,表示活跃的堆内存总量。当event_type为MmapEvent或者MunmapEvent时,表示活跃的映射内存总量 +- current_size_dur:表示当前活跃内存总量的持续时间 +- last_lib_id:函数调用栈他最后一个函数所属的文件路径,除了文件名中带musl和libc++ + +### native_hook_frame表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callchain_id |INT | +|depth |INT | +|symbol_id |INT | +|file_id |INT | +|offset |INT | +|symbol_offset |INT | +#### 表描述 +记录了内存的申请和释放的堆栈。 +#### 相关字段描述 +- callchain_id:标识一组调用堆栈 +- depth:调用栈深度 +- symbol_id:函数名 +- file_id:函数所属文件 + +### network表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|tx |INT | +|rx |INT | +|tx_speed |REAL | +|rx_speed |REAL | +|packet_in |INT | +|packet_in_sec |REAL | +|packet_out |INT | +|packet_out_sec |REAL | +|net_type |TEXT | +#### 表描述 +记录了网络数据传输相关的信息。 +#### 主要字段描述 +- tv_sec:时间,秒为单位 +- tv_nsec:时间,纳秒为单位 +- tx_bytes:网络数据的写入量 +- rx_bytes:网络数据的读取量 + +### paged_memory_sample表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callchain_id |INT | +|type |INT | +|ipid |INT | +|start_ts |INT | +|end_ts |INT | +|dur |INT | +|size |INT | +|addr |TEXT | +|itid |INT | +#### 表描述 +记录了网络数据传输相关的信息。 +#### 主要字段描述 +- callchain_id: 取值相同的一组数据,表示一个完整的调用栈 +- type:事件类型 +- ipid:TS内部进程号 +- start_ts:开始时间 +- end_ts:结束时间 +- dur:持续时间 +- size:操作页数 +- itid:TS内部线程号 + +### perf_callchain表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callchain_id |INT | +|depth |INT | +|vaddr_in_file |INT | +|file_id |INT | +|symbol_id |INT | +|name |TEXT | +#### 表描述 +记录了Hiperf采样数据的调用栈信息。 +#### 主要字段描述 +- callchain_id:标识一组调用堆栈 +- depth:调用栈深度 +- vaddr_in_file:函数在文件中的虚拟地址 +- file_id:与PerfFiles中的file_id字段相关联 +- symbol_id:与PerfFiles中的symbol_id相关联 +- name:函数名 + +### perf_files表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|file_id |INT | +|serial_id |INT | +|symbol |TEXT | +|path |TEXT | +#### 表描述 +记录Hiperf工具采集到的函数符号表和文件名。 +#### 主要字段描述 +- file_id:文件编号 +- serial_id:一个文件中可能有多个函数,serial_id表示函数的编号 +- symbol:函数名 +- path:文件路径 + +### perf_report表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|report_type |TEXT | +|report_value |TEXT | +#### 表描述 +记录Hiperf工具采集数据时的配置信息。包括:抓取的事件类型,抓取数据的命令, 抓数据时指定的进程名称。 +#### 主要字段描述 +- report_type:数据类型。取值只有三种类型:config_name(事件类型), workload(抓取的进程名), cmdline(抓取命令) +- report_value:对应类型的取值 + +### perf_sample表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|callchain_id |INT | +|timestamp |INT | +|thread_id |INT | +|event_count |INT | +|event_type_id |INT | +|timestamp_trace |INT | +|cpu_id |INT | +|thread_state |TEXT | +#### 表描述 +记录Hiperf工具的采样信息。 +#### 主要字段描述 +- timestamp:未进行时钟源同步的时间戳 +- thread_id:线程号 +- event_count:采样统计 +- event_type_id:事件类型编号。与PerfReport表的id字段相关联 +- timestamp_trace:时钟源同步后的时间戳 +- cpu_id:cpu核编号 +- thread_state:线程状态。采样对应Sched_Waking事件时,为Runing;对应Sched_Switch事件时,为Suspend。其余事件类型,为“-” + +### perf_thread表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|thread_id |INT | +|process_id |INT | +|thread_name |TEXT | +#### 表描述 +记录Hiperf工具采集到的进程和线程数据。 +#### 主要字段描述 +- thread_id:线程号 +- process_id:进程号 +- thread_name:线程名 + +### process表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|ipid |INT | +|type |TEXT | +|pid |INT | +|name |TEXT | +|start_ts |INT | +|switch_count |INT | +|thread_count |INT | +|slice_count |INT | +|mem_count |INT | +#### 表描述 +记录了进程相关数据。 +#### 关键字段描述 +- id:进程在数据库重新重新定义的id,从0开始序列增长 +- ipid:TS内部进程id +- type:固定取值:process +- pid:进程的真实id +- name:进程名字 +- start_ts:开始时间 +- switch_count:统计内部有多少个线程有切换 +- thread_count:统计其线程个数 +- slice_count:进程内有多个线程有slice数据 +- mem_count:进程是否有内存数据 + +### process_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|ipid |INT | +#### 表描述 +将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, filter_id同时被记录在filter表中。 +#### 主要字段描述 +- id:进程id +- type:固定取值:process_filter +- name:进程名 +- ipid:该进程表中的id与process表中的id相关联 + +### process_measure表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|type |TEXT | +|ts |INT | +|value |NUM | +|filter_id |INT | +#### 表描述 +保存进程的内存,堆栈值等所有计量值信息。 +#### 字段详细描述 +- ts:事件时间 +- value:数值 +- filter_id:对应process_measure_filter表中的ID + +### process_measure_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|ipid |INT | +#### 表描述 +将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, filter_id同时被记录在measure_filter表中。 +#### 字段详细描述 +- type:固定取值:process_measure_filter +- name:cpu状态名 +- ipid:进程内部编号 + +### raw表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|ts |INT | +|name |TEXT | +|cpu |INT | +|itid |INT | +#### 表描述 +记录了系统中的waking、wakup、cpu_idel、cpu_frequency数据。 +#### 相关字段描述 +- type:固定字段(raw) +- name:调度名称(取值:cpu_idle,sched_wakeup,sched_waking) +- cpu:事件发生在哪个CPU +- itid:时间对应哪个utid + +### sched_slice表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|ts |INT | +|dur |INT | +|ts_end |INT | +|cpu |INT | +|itid |INT | +|end_state |TEXT | +|priority |INT | +#### 表描述 +此数据结构主要作为ThreadState的上下文使用,这张表是sched_switch事件的原始记录。 +#### 主要字段描述 +- ts:事件发生事件 +- type:固定字段(sched_slice) +- dur:状态持续时长 +- ts_end:状态结束时长 +- cpu:事件发生在哪个cpu +- itid:事件对应哪个utid +- end_state:线程的终结状态 + +### smaps表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|timestamp |INT | +|start_addr |TEXT | +|end_addr |TEXT | +|dirty |INT | +|swapper |INT | +|resident_size |INT | +|pss |INT | +|virtaul_size |INT | +|reside |REAL | +|protection_id |INT | +|path_id |INT | +#### 表描述 +记录进程的内存消耗的相关信息采样。 +#### 主要字段描述 +- id:状态持续时长 +- timestamp:事件发生事件 +- start_addr:内存段地址的起始位置 +- end_addr:内存段地址的结束位置 +- dirty:其他进程共享的被写的页的大小 + 已被改写的私有页面的大小 +- swapper:存在于交换分区的数据大小 +- resident_size:实际分配的内存大小 +- pss:平摊计算后的实际物理使用内存 +- virtaul_size:虚拟内存空间的大小 +- reside:实际分配的内存大小与虚拟内存空间的大小的比 +- protection_id:内存段的权限id与表data_dict的id字段相关联 +- path_id:如果区域是从文件映射的,则这是文件的名称对应的id序号与表data_dict的id字段相关联 + +### stat表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|event_name |TEXT | +|stat_type |TEXT | +|count |INT | +|serverity |TEXT | +|source |TEXT | +#### 表描述 +此结果用来统计数据解析中各类数据的数据条数,数据和合法性,数据的匹配程度(begin-end),数据的损失等,查看此结构对应的表,可对数据源有基本的了解。 +#### 主要字段描述 +- event_name:数据类型 +- stat_type:数据状态 +- count:数据条数 +- severity:严重级别 +- source:数据来源 + +### symbols表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|funcname |TEXT | +|addr |INT | +#### 表描述 +此表记录了被调用函数与其地址的映射关系。 +#### 相关字段描述 +- funcname:系统调用名称 +- adr:系统调用地址 + +### syscall表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|syscall_num |INT | +|type |TEXT | +|ipid |INT | +|ts |INT | +|ret |INT | +#### 表描述 +记录用户空间函数与内核空间函数相互调用记录。 +#### 相关字段描述 +- syscall_num:系统调用的序号 +- type:固定取值:enter或者exit +- ipid:线程所属的进程ID +- ts:时间戳 +- ret:返回值,在type为exit时有效 + +### sys_event_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +#### 表描述 +记录所有的filter。 +#### 相关字段描述 +- type:文件类型 +- name:文件名 + +### sys_mem_measure表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|type |TEXT | +|ts |INT | +|value |INT | +|filter_id |INT | +#### 表描述 +记录系统内存与系统虚拟内存。 +#### 相关字段描述 +- ts:事件时间 +- value:数值 +- filter_id:对应filter表中的ID + +### thread表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|itid |INT | +|type |TEXT | +|tid |INT | +|name |TEXT | +|start_ts |INT | +|end_ts |INT | +|ipid |INT | +|is_main_thread|INT | +|switch_count |INT | +#### 表描述 +记录了线程相关数据。 +#### 字段详细描述 +- id:线程在数据库重新重新定义的id,从0开始序列增长 +- itid:TS内部线程id +- type:固定字段(thread) +- tid:线程号 +- name:线程名 +- start_ts:开始时间 +- end_ts:结束时间 +- ipid:线程所属的进程id, 关联process表中的ID +- is_main_thread:是否主线程,主线程即该线程实际就是进程本身 +- switch_count:当前线程的切换次数 + +### thread_filter表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|name |TEXT | +|itid |INT | +#### 表描述 +将线程ID作为key1,线程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, filter_id同时被记录在filter表中。 +#### 主要字段描述 +- id:线程id +- type:线程类型 +- name:线程名称 +- itid:该表中的tid与thread表中的tid相关联 + +### thread_state表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |TEXT | +|ts |INT | +|dur |INT | +|cpu |INT | +|itid |INT | +|tid |INT | +|pid |INT | +|state |TEXT | +#### 表描述 +记录了线程状态相关的数据。 +#### 字段详细描述 +- id:线程状态在数据库中的id,从0开始序列增长 +- ts:该线程状态的起始时间 +- dur:该线程状态的持续时间 +- cpu:该线程在哪个cpu上执行(针对running状态的线程) +- itid:该状态所属的线程id, 关联线程表中的id +- tid:线程号 +- pid:进程号 +- state:线程实际的的状态值 +``` +'R', Runnable状态 +'S', interruptible sleep +'D', uninterruptible sleep +'T', Stoped +'t', Traced +'X', ExitedDead +'Z', ExitZombie +'x', TaskDead +'I', TaskDead +'K', WakeKill +'P', Parked +'N', NoLoad +``` + +### clock_snapshot表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|clock_id |INT | +|ts |INT | +|clock_name |TEXT | +#### 表描述 +时钟号和时间,时钟名的映射表。 +#### 关键字段描述 +- clock_id:时钟号 +- ts:时钟快照报的时间 +- clock_name:时钟号对应的时钟名字 +时钟快照是用来对齐不同时钟号的时间 +比如,时钟号1的时间100,和时钟号2的时间200对齐 +则时钟号为2 的250,转换为时钟号1的时间后,为150 + +### datasource_clockid表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|data_source_name |TEXT | +|clock_id |INT | +#### 表描述 +数据源和时钟号的映射表。 +#### 关键字段描述 +- data_source_name:数据源的名称,和数据源的插件名保持一致 +- clock_id:时钟号,对应clock_snapshot中的时钟号 +这个表是用来告诉IDE,不同的事件源的事件,原始时钟号是多少,在数据库中保存的事件,通常是转换为boottime后的时间,但有些情况下,IDE仍然需要知道原始的时钟号是怎样的 +### frame_slice表 +### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|vsync |INT | +|ipid |INT | +|itid |INT | +|callstack_id |INT | +|dur |INT | +|src |TEXT | +|dst |INT | +|type |INT | +|flag |INT | +|depth |INT | +|frame_no |INT| +#### 表描述 +应用的实际渲染帧和期望渲染帧的开始时间,持续时长,以及RenderService和App之间的关联关系。 +#### 关键字段描述 +- callstack_id:该帧数据对应着callstack表的调用栈所在的行数 +- dur:该帧渲染时长(当数据不完整时,改行数据为空) +- src:该帧是被哪一帧(该表中对应的行数)触发的,有多个值时,用逗号分割 +- dst:该帧对应的渲染帧是哪一行 +- type: 0 说明该行数据是实际渲染帧, 1 说明该行数据是期望渲染帧 +- flag: 空时,为不完整的数据;0 表示实际渲染帧不卡帧, 1 表示实际渲染帧卡帧, 2 表示数据不需要绘制(没有frameNum信息) +- depth:预留 +- frame_no:预留 +### frame_maps表 +### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|src_row |INT | +|dst_row |INT | +#### 表描述 +该表记录了app到RenderService的帧的映射关系,同frame_slice表中的src映射到dst的关系。 +#### 关键字段描述 +- src_row:frame_slice表中app的帧所在的行 +- dst_row:frame_slice表中RenderService的帧所在的行 +### gpu_slice表 +### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|frame_row |INT | +|dur |INT | +#### 表描述 +该表记录了每一帧数据在GPU上的渲染时长。 +#### 关键字段描述 +- frame_row:frame_slice表中渲染帧所在的行 +- dur:帧渲染时长 +### trace_range表 +#### 表结构 +| Columns Name | SQL TYPE | +|---- |---- | +|start_ts |INT | +|end_ts |INT | +#### 表描述 +记录解析解析开始时间以及结束时间。 +#### 关键字段描述 +- start_ts:trace的开始时间,纳秒为单位 +- end_ts:trace的结束时间,纳秒为单位 \ No newline at end of file diff --git a/trace_streamer/doc/des_timestamp.md b/trace_streamer/doc/des_timestamp.md new file mode 100644 index 0000000000000000000000000000000000000000..c65897399ab763ff58cf421761e7b700a30b99eb --- /dev/null +++ b/trace_streamer/doc/des_timestamp.md @@ -0,0 +1,78 @@ + +## TS解析htrace数据时间戳的规则 +ProfilerPluginData是所有proto格式数据插件的最外层message。 +其中包含多个时间戳。根据name字段反序列化的data字段中包含一个时间戳,一般为具体事件发生的时刻;另外tv_sec, tv_nsec号数据域组成最外层的时间戳,一般为端侧使用该插件采集数据上报的时刻。 +在一些需要精确展示事件时间的业务中, 采用的是data中的时间; 在一些周期性采集统计数据的业务(如:进程的内存数据)中使用的是最外层tv_sec, tv_nsec. +message ProfilerPluginData { + string name = 1; + uint32 status = 2; + bytes data = 3; + enum ClockId { + CLOCKID_REALTIME = 0; + CLOCKID_REALTIME_ALARM = 1; // since Linux 3.0; Linux-specific + CLOCKID_REALTIME_COARSE = 2; // since Linux 2.6.32; Linux-specific + CLOCKID_TAI = 3; // since Linux 3.10; Linux-specific + CLOCKID_MONOTONIC = 4; + CLOCKID_MONOTONIC_COARSE = 5; // since Linux 2.6.32; Linux-specific + CLOCKID_MONOTONIC_RAW = 6; // since Linux 2.6.28; Linux-specific + CLOCKID_BOOTTIME = 7; // since Linux 2.6.39; Linux-specific + CLOCKID_BOOTTIME_ALARM = 8; // since Linux 3.0; Linux-specific + CLOCKID_PROCESS_CPUTIME_ID = 9; // since Linux 2.6.12 + CLOCKID_THREAD_CPUTIME_ID = 10; // since Linux 2.6.12 + }; + ClockId clock_id = 4; + uint64 tv_sec = 5; + uint64 tv_nsec = 6; + string version = 7; // "1.01" +} + +## 解析不同插件数据使用的时间戳对照表 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
对应的插件对应的业务说明
使用ProfilerPluginData.data中的时间戳ftrace-pluginftrace
hilog-pluginhilog日志
nativehooknative_memory(malloc, free, mmap,munmap, 统计事件)
hidump-pluginfps
使用ProfilerPluginData.tv_sec 和tv_nsec/td> + memory-plugin系统内存
network-plugin网络
cpu-plugincpu占用率
process-plugin进程内存
diskio-plugin磁盘读写速率
hisysevent-pluginhisysevent
\ No newline at end of file diff --git a/trace_streamer/doc/des_wakeup.md b/trace_streamer/doc/des_wakeup.md new file mode 100644 index 0000000000000000000000000000000000000000..170f7f4b0c3b627841735a97b343832f77ae26dc --- /dev/null +++ b/trace_streamer/doc/des_wakeup.md @@ -0,0 +1,4 @@ +# 关于wakeup事件和waking事件的处理说明 +对于trace事件的waking和wakeup处理,我们的策略如下: +waking是开始唤醒线程,wakeup是线程正式被唤醒,进入runnable(可运行状态); +我们的策略是:被唤醒才是真正进入runnable状态。 \ No newline at end of file diff --git a/trace_streamer/doc/frames.md b/trace_streamer/doc/frames.md new file mode 100644 index 0000000000000000000000000000000000000000..0909480dee62f4c2fa7397276cf1f1b725233f6d --- /dev/null +++ b/trace_streamer/doc/frames.md @@ -0,0 +1,31 @@ +# 帧渲染数据解析的逻辑 +帧的解析分为应用帧的解析和渲染帧的业务解析。 +## 应用帧 +应用帧解析主要是进行应用帧业务的开始和结束,并对其帧编号进行记录,以便在RS的业务中进行匹配(RenderService简称为RS)。 +应用帧会有下面一些调用栈: +H:ReceiveVsync +H:OnVsyncEvent +H:MarshRSTransactionData +后面两个调用栈嵌套在H:ReceiveVsync内。 +特别地,当一个栈没有H:MarshRSTransactionData事件时,是无效的帧。 +H:MarshRSTransactionData内会包含应用的帧标号,和线程号。 +## 渲染帧 +渲染帧会有下面一些调用栈: +H:ReceiveVsync +H:RSMainThread::OnVsync +H:RSMainThread::ProcessCommandUni +后面两个调用栈嵌套在H:ReceiveVsync内。 +特别地:当渲染帧不包含H:RSMainThread::ProcessCommandUni时,为无效的渲染帧。 +H:RSMainThread::ProcessCommandUni内包含被渲染的帧编号,所属的线程号。 +## GPU渲染时长 +和渲染帧同步并发的,是渲染线程的gpu信息,在事件中是H:M: Frame queued事件。 +只有当H:M: Frame queued事件的开始时间在渲染帧的H:ReceiveVsync时间的开始到结束的时间范围时,将该H:M: Frame queued事件和H:ReceiveVsync做关联,两者构成一个完整的渲染事件(也可能没有H:M: Frame queued事件)。 +而应用的渲染帧编号,和渲染线程中H:RSMainThread::ProcessCommandUni事件所携带的被渲染的帧编号,所属的线程号关联之后,形成应用帧的一个完整渲染事件。 +## 关于帧卡顿的定义 +关于帧卡顿的定义:帧的实际渲染时间晚于期望被渲染的时间,认为帧卡顿。数据库中标识为1,否则为0。 +期望帧不做任何标识,为默认的255(max u8),导出db时为空。 +特别地:以上事件发出的线程,必须是进程中的主线程,即线程号和进程号一致,否则,不做处理。 +## 关于无效帧的定义 +如果应用帧不包含FrameNum,则其为无效帧。 +无效帧的标识为2。 +当帧为无效帧时,会同时标识其实际帧和期望帧为无效帧。 \ No newline at end of file diff --git a/trace_streamer/doc/image/des_tables/1683163158954.png b/trace_streamer/doc/image/des_tables/1683163158954.png new file mode 100644 index 0000000000000000000000000000000000000000..8f50acb397072e022d1cbb4663dfbf33a8912a6a Binary files /dev/null and b/trace_streamer/doc/image/des_tables/1683163158954.png differ diff --git a/trace_streamer/doc/image/des_tables/1683163244217.png b/trace_streamer/doc/image/des_tables/1683163244217.png new file mode 100644 index 0000000000000000000000000000000000000000..7ab66d06a754c91dd3ddf8bac7a624b885590f20 Binary files /dev/null and b/trace_streamer/doc/image/des_tables/1683163244217.png differ diff --git a/trace_streamer/doc/image/des_tables/1683163373206.png b/trace_streamer/doc/image/des_tables/1683163373206.png new file mode 100644 index 0000000000000000000000000000000000000000..9111a357521303e2f6fa6cb3438c67a3dd839dd8 Binary files /dev/null and b/trace_streamer/doc/image/des_tables/1683163373206.png differ diff --git a/trace_streamer/doc/image/js_memory/1682579112175.png b/trace_streamer/doc/image/js_memory/1682579112175.png new file mode 100644 index 0000000000000000000000000000000000000000..8c132fb13206bb1f8ecff5a26f12830a8a8650cd Binary files /dev/null and b/trace_streamer/doc/image/js_memory/1682579112175.png differ diff --git a/trace_streamer/doc/image/js_memory/1682579160166.png b/trace_streamer/doc/image/js_memory/1682579160166.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5002721b3c82bb18d4f2c046a30f70e9e9b0b8 Binary files /dev/null and b/trace_streamer/doc/image/js_memory/1682579160166.png differ diff --git a/trace_streamer/doc/image/js_memory/1682579181701.png b/trace_streamer/doc/image/js_memory/1682579181701.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5002721b3c82bb18d4f2c046a30f70e9e9b0b8 Binary files /dev/null and b/trace_streamer/doc/image/js_memory/1682579181701.png differ diff --git a/trace_streamer/doc/image/js_memory/1682579300950.png b/trace_streamer/doc/image/js_memory/1682579300950.png new file mode 100644 index 0000000000000000000000000000000000000000..9348ca950eb4826e6075281f9304bc4a4c83411d Binary files /dev/null and b/trace_streamer/doc/image/js_memory/1682579300950.png differ diff --git a/trace_streamer/doc/image/js_memory/1682579350993.png b/trace_streamer/doc/image/js_memory/1682579350993.png new file mode 100644 index 0000000000000000000000000000000000000000..7ed701fdaad33fbe6781eb37d456bfed2073d312 Binary files /dev/null and b/trace_streamer/doc/image/js_memory/1682579350993.png differ diff --git a/trace_streamer/doc/image/js_memory/1683533864357.png b/trace_streamer/doc/image/js_memory/1683533864357.png new file mode 100644 index 0000000000000000000000000000000000000000..975e83438cf76a7b4637db898fd68028d8403fa2 Binary files /dev/null and b/trace_streamer/doc/image/js_memory/1683533864357.png differ diff --git a/trace_streamer/doc/js_memory.md b/trace_streamer/doc/js_memory.md new file mode 100644 index 0000000000000000000000000000000000000000..1580d43767015e7bc56c26a3963b9b17f7d54228 --- /dev/null +++ b/trace_streamer/doc/js_memory.md @@ -0,0 +1,80 @@ +# JS内存数据说明 + +TraceStreamer支持解析JS内存采集的二进制数据,数据分为Snapshot和Timeline两种类型,解析结果输出js_heap_edges, js_heap_files, js_heap_info, js_heap_location, js_heap_nodes, js_heap_sample, js_heap_string, js_heap_trace_function_info, js_heap_trace_node共计九张表分别记录边缘信息,文件信息,数据类型, location节点信息,node节点信息,Timeline模式下的时间轴信息,字符串信息,Timeline模式下的调用栈函数信息,Timeline模式下的调用栈信息。 + +## 数据格式说明 + +数据采集时,Snapshot和Timeline只能选择其中一种,其中Snapshot为堆内存数据,可设置数据采集间隔,上报的数据为多组,以{"id":1,"result":{}}做为一次数据的结束标识。 + +![1682579112175](image/js_memory/1682579112175.png) + +*Snapshot模式下在下发start命令后立马开始上报数据直到本次抓取结束,数据上报完成之前都属于数据抓取过程。* + +Timeline为时间轴数据,一个数据文件中只存在一组Timeline数据。以{"id":1,"result":{}}作为数据采集起始,{"id":2,"result":{}}作为数据采集结束。 + +![1682579181701](image/js_memory/1682579181701.png) + +*Timeline模式下发start命令后开始抓取,插件结束时下发stop命令停止抓取并开始上报数据。Start命令下发到stop命令下发之间属于数据抓取过程。* + +## proto文件说明 + +JS内存数据解析对应两个proto文件 + +![1682579300950](image/js_memory/1682579300950.png) + +![1682579350993](image/js_memory/1682579350993.png) + +其中数据类型和pid通过JsHeapConfig获取,JsHeapResult外层有时间戳可以获取。 + +## Snapshot + +一个Snapshot模式的文件包含有多组Snapshot数据,每一组以{"id":1,"result":{}}作为结束标识,Snapshot数据包含在json[params][ chunk]节点下,一条完整的Snapshot的数据会发送多次result,在收到结束标识之前,拼装所有的[chunk]节点下的result,即为一条完整的Snapshot数据。以此类推,解析至文件结束,可获取多条Snapshot数据。再用json库进行数据解析。 + +## Timeline + +一个Timeline模式的文件包含有一组Timeline数据,以{"id":1,"result":{}}作为起始标识,以{"id":2,"result":{}}作为结束标识。Timeline数据包含在json[params][chunk]节点下,一条完整的Timeline数据会发送多次result,从收到起始标识开始,拼装每一条json[params][chunk]下的数据,直到收到结束标识,即可获取一条完整的Timeline数据。 + +### 数据解析 + +--- + +js memory的数据包含在htrace文件中,由proto文件定义数据格式,解析规则如下: + +1.js-memory相关数据携带js-memory_config和js-memory插件头,先通过接口ParseJSMemoryConfig获取对应的type和pid,其中type=0为snapshot类型数据,type=1为timeline数据。js-memory数据为json格式,json包含以下节点:snapshot,nodes,edges,locations,strings,samples,trace_function_infos,trace_tree。使用第三方json库nlohmann::json进行解析。 + +2.json解析:snapshot和timeline两种数据类型json的解析规则是相同的。 + +snapshot:该节点包含js_heap_info表的信息,节点包括node、edge等节点对应的字段名称,数据类型和个数。 + +nodes:该节点包含了js_heap_nodes表的信息,每一行为7个int类型数字,分别表示type,name,id,self_size,edge_count,trace_node_id,detachedness。 + +edges:该节点包含了js_heap_edges表的信息,每一行为3个int类型数字,分别表示type,name_or_index,to_node。表中from_node_id是通过nodes节点的id和edgecount计算出的,nodes节点的每个edgecount对应的id即为edges节点的from_node_id。 + +![1683533864357](image/js_memory/1683533864357.png) + +例:"nodes" + +| type | name | id | self_size | edge_count | trace_node_id | datachedness | +| ---- | ---- | -- | --------- | ---------- | ------------- | ------------ | +| 9 | 1 | 1 | 0 | 3 | 0 | 0 | +| 9 | 2 | 3 | 0 | 2 | 0 | 0 | + +则edges每个节点对应的from_node_id应为: + +| from_node_id | +| ------------ | +| 1 | +| 1 | +| 1 | +| 3 | +| 3 | + +locations:该节点包含了js_heap_location表的信息,目前尚无数据,暂不关注。 + +samples:该节点包含了js_heap_sample表的信息,每一行为两个int类型数字,分别表示timestam_us,last_assigned_id。 + +strings:该节点包含了js_heap_string表的信息,每一行为一个string类型的字符串,是js内存中字符串的集合,对应表中的string字段。 + +trace_function_infos:该节点包含了js_heap_trace_function_info表的信息,每一行为6个int类型的字符串,分别表示function_id,name,script_name,script_id,line,column。 + +trace_tree:该节点包含了js_heap_trace_node表的信息,是一个多维数组,每个数组由5个元素组成,分别为id,function_info_index,count,size和对应的子节点数组信息。由于不知道trace_tree节点的嵌套层数,需用递归方式解析每一层嵌套的节点。 diff --git a/trace_streamer/doc/proto.md b/trace_streamer/doc/proto.md new file mode 100644 index 0000000000000000000000000000000000000000..a9c41d8ed552aa8503d73e016f7cca6f773cc0d3 --- /dev/null +++ b/trace_streamer/doc/proto.md @@ -0,0 +1,11 @@ +# proto文件的格式和protoReader解析的类型对应关系 +proto文件中数据类型的定义和其在ProtoReader解析中的类型对应关系如下表所示。 +| 基础数据类型 | proto数据类型 | 类型标识 | +| ------------- | ------------- | ----------- | +|double, fixed64 |kFixed64 | 1 | +|int32, int64, bool, enum |kVarInt |0 | +| string |kLengthDelimited | 2 | +|float, fixed32 |kFixed32 | 5 | + +关于repeated字段的说明 +除了string类型和自定义消息体(用户自定义的,非基本数据类型),其他基础数据类型在定义前加repeated会被识别为PackedRepeated包裹的类型。 diff --git a/trace_streamer/doc/symbol_file_import.md b/trace_streamer/doc/symbol_file_import.md new file mode 100644 index 0000000000000000000000000000000000000000..bd441cf964a0c7f49d0b24cf0314f976cbfaa1d1 --- /dev/null +++ b/trace_streamer/doc/symbol_file_import.md @@ -0,0 +1,19 @@ +# 关于符号文件导入的说明 +trace_streamer支持导入符号文件(so文件)来对各种调用栈中涉及的地址进行二次符号化。 +由于抓取的trace文件中初始会携带程序所依赖的符号文件的全路径,因此,在做符号文件导入时,需按如下规则进行符号文件的识别和导入: +- 1 一个函数地址是否被符号化,不仅取决于其地址范围是否和符号文件的符号地址相匹配,还取决于其符号所在的符号文件全路径,是否和被导入文件的全路径一致; +- 2 对于Perf数据而言,额外检查了被导入文件的buildId,而ebpf和nativehook由于原始数据未携带buildId,对buildId不做检查。 + +基于以上条件,在导入符号文件时,宜对被导入的文件还原其在设备中的原始目录结构,例如,文件目录结构可能如下所示: +``` +folder_to_import/system/lib64/libsec_shared.z.so +folder_to_import/system/lib64/libutils.z.so +folder_to_import/system/lib64/libhilog.so +folder_to_import/system/lib64/libskia_ohos.z.so +folder_to_import/system/lib64/libace.z.so +``` +请注意,在folder_to_import文件夹之下,其文件的路径和其在设备(开发板)上的路径是一致的。 +此规则对hiperf, ebpf, nativehook通用。 + +其他需要注意的: +关于perf文件的so导入操作,原始trace中的文件符号表(perf_files)只会包含调用栈中使用的符号,而导入so后,符号表中包含的是该文件全量的符号信息,会比原有的表更大,而且符号的serial_id也对应会发生变化,但这不影响最终调用栈的显示。 \ No newline at end of file diff --git a/trace_streamer/doc/times.md b/trace_streamer/doc/times.md new file mode 100644 index 0000000000000000000000000000000000000000..e0b51f448233c53f0e6154c671a59cc9fff3e799 --- /dev/null +++ b/trace_streamer/doc/times.md @@ -0,0 +1,14 @@ +# 关于时钟号的说明 +trace_streamer内部使用了和设备侧同步的时钟号,现将各个时钟号进行记录,并对个别时钟号进行特别说明 +``` +TS_CLOCK_UNKNOW = 0, +TS_CLOCK_BOOTTIME = 1, +TS_CLOCK_REALTIME = 2, +TS_CLOCK_REALTIME_COARSE = 3, +TS_MONOTONIC = 4, +TS_MONOTONIC_COARSE = 5, +TS_MONOTONIC_RAW = 6, +``` +- boot time  与monotonic时间相同,不过会累加上系统休眠的时间,它代表着系统上电后的总时间。 +- monotonic time  该时间自系统开机后就一直单调地增加,它不像xtime可以因用户的调整时间而产生跳变,不过该时间不计算系统休眠的时间,也就是说,系统休眠时,monotoic时间不会递增。 +- raw monotonic time  该时间与monotonic时间类似,也是单调递增的时间,唯一的不同是:raw monotonic time“更纯净”,他不会受到NTP时间调整的影响,它代表着系统独立时钟硬件对时间的统计。 diff --git a/trace_streamer/figures/cpu_frequency.png b/trace_streamer/figures/cpu_frequency.png new file mode 100644 index 0000000000000000000000000000000000000000..a18715fc696b3231b94425e4acd6aaf319bf399f Binary files /dev/null and b/trace_streamer/figures/cpu_frequency.png differ diff --git a/trace_streamer/figures/db_common.png b/trace_streamer/figures/db_common.png new file mode 100755 index 0000000000000000000000000000000000000000..29dbb080e1d213672b74d553610f6a24445663ad Binary files /dev/null and b/trace_streamer/figures/db_common.png differ diff --git a/trace_streamer/figures/db_hiperf.png b/trace_streamer/figures/db_hiperf.png new file mode 100755 index 0000000000000000000000000000000000000000..85cacf15a7153a0853c7aeee2fe34fba1f8983a8 Binary files /dev/null and b/trace_streamer/figures/db_hiperf.png differ diff --git a/trace_streamer/figures/db_hisys_event.png b/trace_streamer/figures/db_hisys_event.png new file mode 100755 index 0000000000000000000000000000000000000000..215265182de684f1b4a31fd7158309f8c7532053 Binary files /dev/null and b/trace_streamer/figures/db_hisys_event.png differ diff --git a/trace_streamer/figures/db_native_memory.png b/trace_streamer/figures/db_native_memory.png new file mode 100755 index 0000000000000000000000000000000000000000..0e1403e958fbf76f3d2c31fc6304426de6579afb Binary files /dev/null and b/trace_streamer/figures/db_native_memory.png differ diff --git a/trace_streamer/figures/dump_and_mem.png b/trace_streamer/figures/dump_and_mem.png new file mode 100755 index 0000000000000000000000000000000000000000..2c3f59eef7476de91cafb8f59832c93fe4117e51 Binary files /dev/null and b/trace_streamer/figures/dump_and_mem.png differ diff --git a/trace_streamer/figures/filters.png b/trace_streamer/figures/filters.png new file mode 100644 index 0000000000000000000000000000000000000000..a02d9416f08382ff7a03e176e37e6479f5922c08 Binary files /dev/null and b/trace_streamer/figures/filters.png differ diff --git a/trace_streamer/figures/frames.jpg b/trace_streamer/figures/frames.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b0cd54de43e8ca22de9e33fe19aaa0800bec3ef7 Binary files /dev/null and b/trace_streamer/figures/frames.jpg differ diff --git a/trace_streamer/figures/log.png b/trace_streamer/figures/log.png new file mode 100755 index 0000000000000000000000000000000000000000..0c9ac304183f2276454caeb2fea593a5e88bdc13 Binary files /dev/null and b/trace_streamer/figures/log.png differ diff --git a/trace_streamer/figures/mem_usage.png b/trace_streamer/figures/mem_usage.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ebd6e272c424d6861e2e8150c72c1f4de9802a Binary files /dev/null and b/trace_streamer/figures/mem_usage.png differ diff --git a/trace_streamer/figures/perf.png b/trace_streamer/figures/perf.png new file mode 100755 index 0000000000000000000000000000000000000000..9fc88ad255cece0040093392329e639e261c8bd9 Binary files /dev/null and b/trace_streamer/figures/perf.png differ diff --git a/trace_streamer/figures/process_thread.png b/trace_streamer/figures/process_thread.png new file mode 100755 index 0000000000000000000000000000000000000000..305a9bdb02d7776f086f8f13d5f6f72e72443226 Binary files /dev/null and b/trace_streamer/figures/process_thread.png differ diff --git a/trace_streamer/figures/thread_state.png b/trace_streamer/figures/thread_state.png new file mode 100755 index 0000000000000000000000000000000000000000..aa9f846fcc4b88c1b8e9df75e3aff7ada69537dc Binary files /dev/null and b/trace_streamer/figures/thread_state.png differ diff --git a/trace_streamer/figures/trace_streamer_stream.png b/trace_streamer/figures/trace_streamer_stream.png new file mode 100644 index 0000000000000000000000000000000000000000..d36687d164a32bcb07f8f8bd699f0fb0b37e63bd Binary files /dev/null and b/trace_streamer/figures/trace_streamer_stream.png differ diff --git a/trace_streamer/format-code.sh b/trace_streamer/format-code.sh new file mode 100755 index 0000000000000000000000000000000000000000..10701046d419f4888a956854f8b706994386d550 --- /dev/null +++ b/trace_streamer/format-code.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# 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. +set -e +target_os="linux" +gn="gn" +case "$OSTYPE" in + solaris*) echo "SOLARIS" ;; + darwin*) target_os="macx" ;; + linux*) target_os="linux" ;; + bsd*) echo "is bsd os" ;; + msys*) target_os="windows" gn="gn.exe" ;; + *) echo "unknown: $OSTYPE" ;; +esac +PRJ_ROOT_DIR=$(readlink -f -- "$(dirname $0)/") +cd ${PRJ_ROOT_DIR} +FORMAT_DIR_LIST=( + "${PRJ_ROOT_DIR}/src" + "${PRJ_ROOT_DIR}/sdk/demo_sdk" + "${PRJ_ROOT_DIR}/test" +) +echo "formatting code ..." +for d in ${FORMAT_DIR_LIST[@]}; do + echo $d + for f in $(find $d -type f -not -name '*sql.c' -regex '.*\.\(cpp\|hpp\|c\|h\)'); do + dos2unix $f + chmod -x $f + clang-format --verbose -i $f + done + for f in $(find $d -type f -not -name '*sql.c' -regex '.*\.\(gn\|gni\)'); do + echo $f + ./prebuilts/$target_os/gn format $f + done +done +echo "formatting code over" diff --git a/trace_streamer/gn/.emscripten b/trace_streamer/gn/.emscripten new file mode 100644 index 0000000000000000000000000000000000000000..0ed7e1dd1a0e50b80ac895e5911c4b1adc2b8da6 --- /dev/null +++ b/trace_streamer/gn/.emscripten @@ -0,0 +1,32 @@ +# 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. + +from platform import system +import os +import sys + +thisFile = os.getenv('EM_CONFIG') +if thisFile is None: + sys.stderr.write('No EM_CONFIG in .emscripten file\n') + sys.exit(-1) + +rootDir = os.path.dirname(os.path.dirname(thisFile)) +emsdkPath = os.path.join(rootDir, 'prebuilts/emsdk/emsdk') +nodePath = os.path.join(rootDir, 'prebuilts/emsdk/node/14.18.2_64bit') + +LLVM_ROOT = os.path.join(emsdkPath, 'bin') +NODE_JS = os.path.join(nodePath, 'bin/node') +EMSCRIPTEN_ROOT = os.path.join(emsdkPath, 'emscripten') +COMPILER_ENGINE = NODE_JS +JS_ENGINES = [NODE_JS] +BINARYEN_ROOT = emsdkPath diff --git a/trace_streamer/gn/BUILD.gn b/trace_streamer/gn/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..bb13e60c7989239035f1143fd7324f8d866560ba --- /dev/null +++ b/trace_streamer/gn/BUILD.gn @@ -0,0 +1,227 @@ +# 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. +print("target_os", target_os) +print("target_name", target) +group("default_deps") { + public_configs = [ ":default_config" ] + public_deps = [] +} +config("default_config") { + include_dirs = [ + "..", + "../include", + ] +} +config("trace_cfg") { + cflags_cc = [ + "-std=c++17", + "-fvisibility=hidden", + "-Wno-unused-variable", + ] + if (!is_test) { + cflags_cc += [ + "-fno-rtti", + "-fno-exceptions", + ] + } +} + +config("hiperf_trace_cfg") { + cflags_cc = [ + "-std=c++17", + "-fvisibility=hidden", + "-Wno-unused-variable", + ] +} + +config("visibility_hidden") { + cflags = [ "-fvisibility=hidden" ] +} + +config("default") { + cflags_c = [] + cflags_cc = [] + libs = [] + + cflags = [ + "-fstrict-aliasing", + "-g", + "-Wformat", + "-Wno-unused-variable", + ] + if (is_debug && is_win) { + ldflags = [ "-fstack-protector" ] + } + if (is_pbdecoder) { + cflags += [ "-D IS_PBDECODER" ] + } + if (target_os == "windows") { + cflags += ["-D target_cpu_x86_64"] + } else if (is_linux || is_macx) { + cflags += [ + "-Wa,--noexecstack", + "-fcolor-diagnostics", + "-fdiagnostics-show-template-tree", + "-ftrapv", + ] + if (!use_wasm) { + cflags += [ + "-fstack-protector-strong", + "-fstack-protector-all", + "-D_FORTIFY_SOURCE=2 -O2", + + # "-D SUPPORTTHREAD", # if support thread + + # "-D HAVE_ELF_H", + "-D target_cpu_x64", + "-D target_cpu_x86_64", + + # "-D HAVE_LINK_H", + # "-D_GNU_SOURCE", + "-DHAVE_CONFIG_H", + "-DCC_IS_CLANG", + ] + # with_libunwind = true + } + if (!use_wasm && !is_win && !is_macx && !is_test) { + cflags += [ "-D HAVE_LIBUNWIND" ] + } + + cflags += [ "-D USE_VTABLE" ] + if (use_wasm) { + cflags += [ + "-D IS_WASM", + "-D GOOGLE_PROTOBUF_NO_RDTSC", + + # "-D HAVE_LIBUNWIND", + "-D target_cpu_x64", + "-D target_cpu_x86_64", + "-DHAVE_CONFIG_H", + "-DNDEBUG", + "-DCC_IS_CLANG", + "-D__x86_64__", + ] + } + cflags += [ "-D BINDER_ASYNC" ] + libs += [ "pthread" ] + if (!is_macx) { + libs += [ "rt" ] + } + if (!is_win) { + cflags += [ + "-fPIE", + "-fPIC", + ] + } + } + if (use_wasm) { + cflags += [ "-D IS_WASM" ] + } + if (is_win) { + cflags += [ "-D is_mingw" ] + defines = [ "WIN32_LEAN_AND_MEAN" ] + libs += [ "wsock32" ] + libs += [ "Ws2_32" ] + cflags += [ + "-D SECUREC_IS_DLL_LIBRARY", + "-D __KERNEL__", + ] + } + if (with_perf) { + cflags += [ "-D WITH_PERF" ] + } + if (with_ebpf_help_table) { + cflags += [ "-D WITH_EBPF_HELP" ] + } +} + +config("symbols") { + cflags = [ "-O0" ] + if (is_linux || is_macx || !is_pbdecoder) { + cflags += [ "-funwind-tables" ] + } +} + +config("release") { + cflags = [ + "-fdata-sections", + "-ffunction-sections", + ] + + cflags += [ "-O3" ] + ldflags = [ "-fstack-protector" ] + if (!is_macx) { + ldflags += [ "-Wl,-O1" ] + if (!is_win) { + ldflags += [ + "-fuse-ld=gold", + "-Wl,--gc-sections", + ] + } + } + + if (!is_win && !is_macx) { + ldflags += [ + "-fPIC", + "-fpie", + "-pie", + ] + } + defines = [ "NDEBUG" ] +} + +config("shared_library") { + if (!is_win) { + ldflags = [ "-fPIC" ] + } +} + +config("executable") { + print("use_wasm", use_wasm) + ldflags = [] + + if (is_linux || ((is_macx && !use_wasm) || !is_pbdecoder)) { + ldflags += [] + } + if (!is_macx && !use_wasm && !is_win) { + ldflags = [ + "-Wl,--disable-new-dtags", + "-Wl,-z,noexecstack", + "-lrt", + "-fuse-ld=gold", + "-Wl,-z,now", + "-Wl,-z,relro", + ] + } + if (!is_macx && !use_wasm) { + ldflags += [ "-fpie" ] + } + if (!is_macx && !use_wasm && !is_win) { + ldflags += [ "-pie" ] + } + + if (is_macx) { + ldflags += [ + "-fdata-sections", + "-ffunction-sections", + ] + if (!use_wasm) { + ldflags += [ "-Wl,-U,__sanitizer_options_link_helper" ] + } + } + if (!is_debug && !is_macx) { + ldflags += [ "-s" ] + } else if (!is_debug && is_macx) { + ldflags += [ "-dead_strip" ] + } +} diff --git a/trace_streamer/gn/CONFIG.gn b/trace_streamer/gn/CONFIG.gn new file mode 100755 index 0000000000000000000000000000000000000000..848a7b4fe2733368c52c3f0f2e45685dbef07d3a --- /dev/null +++ b/trace_streamer/gn/CONFIG.gn @@ -0,0 +1,138 @@ +# 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. +is_win = false +is_linux = false +is_macx = false +is_protoc = false +with_perf = true +with_ebpf_help_table = false +is_mingw = false +with_libunwind = false +is_sdkdemo = false +is_dubai_sdk = false +is_sdkdemo_test = false +is_spb = false +is_pbdecoder = false +target_cpu = "x64" +declare_args() { + ar = "ar" + is_debug = true + use_wasm = false + use_wasmpb = false + is_test = false + is_sdkdemo = false + is_dubai_sdk = false + is_sdkdemo_test = false + testonly = false + is_fuzz = false + is_macx = false + is_spb = false + is_pbdecoder = false + target = "trace_streamer" +} +if (target_os == "linux") { + is_linux = true +} else if (target_os == "macx") { + is_macx = true +} else if (target_os == "windows") { + is_win = true + is_mingw = true +} else { + print("unknown platform " + target_os) + exit(-1) +} + +if (target == "wasm") { + use_wasm = true +} else if (target == "wasmpb") { + use_wasm = true + use_wasmpb = true + is_pbdecoder = true +} else if (target == "test") { + is_test = true + testonly = true +} else if (target == "testpb") { + is_test = true + testonly = true + is_pbdecoder = true +} else if (target == "fuzz") { + is_fuzz = true + testonly = true +} else if (target == "protoc") { + is_protoc = true +} else if (target == "sdkdemo") { + is_sdkdemo = true + use_wasm = true +} else if (target == "dubaisdk") { + is_dubai_sdk = true + use_wasm = true +} else if (target == "sdkdemotest") { + is_sdkdemo_test = true + testonly = true +} else if (target == "trace_streamer" || target == "streamer") { + print("build " + target) +} else if (target == "spb") { + is_linux = true + is_spb = true +} else if (target == "pbdecoder") { + is_pbdecoder = true +} else { + print("unknown target " + target_os) + exit(-1) +} + +print("platform " + target_os) +default_configs = [ + "//gn:symbols", + "//gn:default", + "//gn:trace_cfg", +] +hiperf_default_configs = [ + "//gn:symbols", + "//gn:default", + "//gn:hiperf_trace_cfg", +] + +set_defaults("static_library") { + configs = default_configs +} +if (!is_debug) { + default_configs -= [ "//gn:symbols" ] + default_configs += [ "//gn:release" ] + hiperf_default_configs -= [ "//gn:symbols" ] + hiperf_default_configs += [ "//gn:release" ] +} +if (is_debug) { + with_ebpf_help_table = true +} + +set_defaults("ohos_source_set") { + configs = default_configs +} + +# set_defaults("ohos_source_hiperf") { +# configs = hiperf_default_configs +# } +set_defaults("ohos_shared_library") { + configs = default_configs +} +set_defaults("executable") { + configs = default_configs + configs += [ "//gn:executable" ] +} +if (use_wasm || use_wasmpb) { + set_default_toolchain("//gn/toolchain:wasm") +} else { + print(use_wasm) + set_default_toolchain("//gn/toolchain:gcc_like") +} diff --git a/trace_streamer/gn/toolchain/BUILD.gn b/trace_streamer/gn/toolchain/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..3b31509464aa0660a9b73a9d08b4865bff5d292d --- /dev/null +++ b/trace_streamer/gn/toolchain/BUILD.gn @@ -0,0 +1,204 @@ +# 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("//gn/wasm.gni") +declare_args() { + if (target_os == "linux" || target_os == "macx") { + cc = "/usr/bin/clang" + cxx = "/usr/bin/clang++" + pic = "-fPIC" + rebuild_string = "" + extra_asmflags = "" + asm = "/usr/bin/clang" + } else if (target_os == "windows") { + cc = "gcc.exe" + cxx = "g++.exe" + rebuild_string = "" + extra_asmflags = "" + asm = "gcc.exe" + pic = "" + } + if (use_wasm == true) { + print("make_wasm") + } else if (use_wasm == false) { + print("no make_wasm") + } + cc_wrapper = "" +} +toolchain("wasm") { + # emsdk_dir and em_config are defined in wasm.gni. + print("use gcc_like_chain wasm") + if (!is_macx) { + ar = "$emsdk_dir/emscripten/emar --em-config $em_config" + } + cc = "$emsdk_dir/emscripten/emcc --em-config $em_config" + cxx = "$emsdk_dir/emscripten/em++ --em-config $em_config" + + lib_switch = "-l" + ld_arg = "" + lib_dir_switch = "-L" + external_cxxflags = "" + external_cflags = "" + external_ldflags = "" + if (defined(linker) && linker != "") { + ld_arg = "-fuse-ld=$_invoker_linker" + _invoker_linker = linker + } + if (defined(sysroot) && sysroot != "") { + _invoker_sysroot = sysroot + cxx = "$cxx --sysroot=$_invoker_sysroot" + cc = "$cc --sysroot=$_invoker_sysroot" + } + if (defined(gcc_toolchain) && gcc_toolchain != "") { + ld_arg = "$ld_arg --gcc-toolchain=$gcc_toolchain" + } + if (defined(external_cxxflags)) { + print("defined external_cxxflags") + external_cxxflags = external_cxxflags + } + if (defined(external_cflags)) { + external_cflags = external_cflags + } + + tool("cc") { + depfiles = "{{output}}.d" + command = "$cc_wrapper $cc -MMD -MF $depfiles {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} ${external_cflags} -c {{source}} -o {{output}}" + outputfiles = + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" + outputs = [ outputfiles ] + description = "step: compile {{source}}" + } + + tool("cxx") { + depfiles = "{{output}}.d" # must be defined + command = "$cc_wrapper $cxx -MMD -MF $depfiles {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} ${external_cflags} ${external_cxxflags} -c {{source}} -o {{output}}" + + outputfiles = + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" + outputs = [ outputfiles ] + description = "step: compile {{source}}" + } + tool("alink") { + rspfile = "{{output}}.rsp" # must be defined + rspfile_content = "{{inputs}}" + if (is_macx) { + command = "rm -f {{output}} && libtool -static {{arflags}} -o {{output}} -filelist $rspfile" + } else { + command = "rm -rf {{output}} && $ar rcsD {{output}} @$rspfile" + } + outputfiles = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" + outputs = [ outputfiles ] + output_prefix = "lib" + default_output_extension = ".a" + description = "step: link {{output}}" + } + tool("solink") { + sonames = "{{target_output_name}}{{output_extension}}" + outputfiles = "{{root_out_dir}}/$sonames" + unstripped_so = outputfiles + rpath = "" + outputs = [ outputfiles ] + command = "$cc_wrapper $cxx $ld_arg -shared {{ldflags}} ${external_ldflags} {{inputs}} {{solibs}} {{libs}} $rpath -o {{output}}" + output_prefix = "lib" + description = "step: link $unstripped_so" + default_output_extension = ".so" + } + + tool("link") { + outputfiles = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" + outputs = [ outputfiles ] + command = "$cc_wrapper $cxx $ld_arg {{ldflags}} ${external_ldflags} {{inputs}} {{solibs}} {{libs}} -o {{output}}" + description = "step:link {{output}}" + } + + tool("stamp") { + description = "step: stamp {{output}}" + command = "touch {{output}}" + } + + tool("copy") { + description = "step: COPY files from {{source}} to {{output}}" + command = "cp -arf {{source}} {{output}}" + } +} +toolchain("gcc_like") { + lib_switch = "-l" + lib_dir_switch = "-L" + + tool("cxx") { + depfile = "{{output}}.d" # must be defined + command = "$cxx -o {{output}} -MMD -MF $depfile {{defines}} $pic {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}}" + outputfiles = + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" + outputs = [ outputfiles ] + description = "step: compile {{source}}" + } + + tool("cc") { + depfile = "{{output}}.d" + command = "$cc -o {{output}} -MMD -MF $depfile {{defines}} $pic {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}}" + outputfiles = + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" + outputs = [ outputfiles ] + description = "step: compile {{source}}" + } + tool("asm") { + depfile = "{{output}}.d" + command = "$asm -o {{output}} -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}}" + depsformat = "gcc" + outputfiles = + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" + outputs = [ outputfiles ] + } + tool("alink") { + rspfile = "{{output}}.rsp" # this must be defined + if (is_macx) { + rspfile_content = "{{inputs_newline}}" + command = "rm -f {{output}} && libtool -static {{arflags}} -filelist $rspfile -o {{output}}" + } else { + rspfile_content = "{{inputs}}" # this must be defined + command = "rm -f {{output}} && $ar rcsD {{output}} @$rspfile" + } + outputsfiles = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" + outputs = [ outputsfiles ] + default_output_extension = ".a" + output_prefix = "lib" + description = "step: link {{output}}" + } + + tool("link") { + command = "$cxx -o {{output}} {{ldflags}} {{inputs}} {{solibs}} {{libs}}" + outputsfiles = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" + outputs = [ outputsfiles ] + description = "step: link {{output}}" + } + tool("solink") { + default_output_extension = ".so" + command = + "$cxx -o {{output}} {{ldflags}} {{inputs}} {{solibs}} {{libs}} -shared" + outputsfiles = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" + outputs = [ outputsfiles ] + description = "step: solink {{output}}" + } + + tool("stamp") { + print("need do nothing") + description = "step: touch {{output}}" + command = "touch {{output}}" + } + + tool("copy") { + description = "COPY files from {{source}} to {{output}}" + command = "cp -arf {{source}} {{output}}" + } +} diff --git a/trace_streamer/gn/wasm.gni b/trace_streamer/gn/wasm.gni new file mode 100644 index 0000000000000000000000000000000000000000..b4c986495cbb7afe176ebaa0972e22e932b6fa75 --- /dev/null +++ b/trace_streamer/gn/wasm.gni @@ -0,0 +1,79 @@ +# 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("./wasm_vars.gni") + +em_config = rebase_path(".emscripten", "") +emsdk_dir = rebase_path("//prebuilts/emsdk/emsdk", "") + +template("wasm_lib") { + _exports = "['ccall', 'callMain', 'addFunction', 'FS']" + print(invoker.name) + assert(defined(invoker.name)) + + # If the name is trace_sreamer the target_name must be trace_sreamer_wasm. + assert(invoker.name + "_wasm" == target_name) + _target_ldflags = [ + "-s", + "DISABLE_EXCEPTION_CATCHING=1", + "-s", + "WASM=1", + "-s", + "NO_DYNAMIC_EXECUTION=1", + "-s", + "ALLOW_MEMORY_GROWTH=1", + "-s", + "INITIAL_MEMORY=33554432", + "-s", + "ALLOW_TABLE_GROWTH=1", + "-s", + "MEMFS_APPEND_TO_TYPED_ARRAYS=1", + "-s", + "WASM_ASYNC_COMPILATION=0", + "-s", + "EXPORTED_RUNTIME_METHODS=" + _exports, + "-s", + "EXPORT_NAME=${target_name}", + "-s", + "MODULARIZE=1", + "-lworkerfs.js", # For FS.filesystems.WORKERFS + ] + _lib_name = invoker.name + if (is_debug) { + _target_ldflags += [ + "-s", + "ASSERTIONS=2", + "-s", + "STACK_OVERFLOW_CHECK=1", + "-s", + "SAFE_HEAP=1", + "-g4", + "-O0", + ] + } else { + _target_ldflags += [ + # "-g2", # Required for getting C++ symbol names. + "-O3", + # "-s", + # "ASSERTIONS=1", + ] + } + + _vars_to_forward = [ "deps" ] + + executable("${_lib_name}.js") { + ldflags = _target_ldflags + output_extension = "" + forward_variables_from(invoker, _vars_to_forward) + } +} diff --git a/trace_streamer/gn/wasm_vars.gni b/trace_streamer/gn/wasm_vars.gni new file mode 100644 index 0000000000000000000000000000000000000000..8b858fda7329eb8466b6975a0fefa7945532a5e4 --- /dev/null +++ b/trace_streamer/gn/wasm_vars.gni @@ -0,0 +1,15 @@ +# 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. + +wasm_toolchain = "//gn/toolchain:wasm" +is_wasm = current_toolchain == wasm_toolchain diff --git a/trace_streamer/huoyantu.sh b/trace_streamer/huoyantu.sh new file mode 100755 index 0000000000000000000000000000000000000000..e10830d261b51cfd73e5ddbe97638449e3dd22da --- /dev/null +++ b/trace_streamer/huoyantu.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# 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. +# 使用示例 ./perf.sh ~/SourceData/ftrace_small.txt ~/SourceData/3.svg +set -e +# 导出火焰图 +if [ "$#" -ne "2" ];then + echo "使用示例 ./huoyantu.sh ~/SourceData/ftrace_small.txt ~/SourceData/3.svg" + exit +fi +if [ ! -d "../FlameGraph" ];then + cd .. + git clone https://github.com/brendangregg/FlameGraph.git + cd - +fi +if [ ! -f "./out/linux_debug/trace_streamer" ];then + echo "need out/linux_debug/trace_streamer file" + exit +fi +source=$1 +dst=$2 +sudo perf record -g -F 99 -- ./out/linux_debug/trace_streamer $source -e /tmp/1.db +sudo perf script -i perf.data > out.perf +../FlameGraph/stackcollapse-perf.pl out.perf > out.floded +../FlameGraph/flamegraph.pl out.floded > $dst \ No newline at end of file diff --git a/trace_streamer/lcov_operator.sh b/trace_streamer/lcov_operator.sh new file mode 100755 index 0000000000000000000000000000000000000000..8bdc98d5916bbb78e58def75ce5d29d43194dc84 --- /dev/null +++ b/trace_streamer/lcov_operator.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# 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. +set -e +DIR=$(dirname $(realpath ${BASH_SOURCE[0]})) +TOP=$(realpath $DIR/) +HOST_OUT=$TOP/out/test +PREFIX=$TOP/ +# collect and convert all gcno and gcda to test.info +lcov -c -d $HOST_OUT -o test.info --gcov-tool $DIR/gcov.sh +if [ $? -ne 0 ]; then + echo "Install lcov: sudo apt install lcov" +fi + +# filter out system headers +lcov -r test.info \ + '/usr/include/*' \ + '*/out/*' \ + '*/src/base/*' \ + '*/third_party/*' \ + -o test.info + +# generate html report +genhtml -o out/test/html test.info --prefix $PREFIX diff --git a/trace_streamer/pare_third_party.sh b/trace_streamer/pare_third_party.sh new file mode 100755 index 0000000000000000000000000000000000000000..eb237cd6fedfa6a3eff87ef4e023287aeca22317 --- /dev/null +++ b/trace_streamer/pare_third_party.sh @@ -0,0 +1,138 @@ +#!/bin/bash +# 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. +set -e +patch='patch' +sed='sed' +cp='cp' +rm='rm' + +case "$OSTYPE" in + darwin*) sed="gsed" ;; +esac +if [ ! -d "third_party" ];then + mkdir third_party +fi +cd third_party + +if [ ! -f "sqlite/BUILD.gn" ];then + rm -rf sqlite + git clone git@gitee.com:openharmony/third_party_sqlite.git + if [ -d "third_party_sqlite" ];then + mv third_party_sqlite sqlite + $cp ../prebuilts/patch_sqlite/sqlite3build.gn ../third_party/sqlite/BUILD.gn + else + echo 'third_party_sqlite not exist' + fi +fi +if [ ! -f "protobuf/BUILD.gn" ];then + rm -rf protobuf + git clone git@gitee.com:openharmony/third_party_protobuf.git + if [ -d "third_party_protobuf" ];then + mv third_party_protobuf protobuf + $cp ../prebuilts/patch_protobuf/protobufbuild.gn ../third_party/protobuf/BUILD.gn + else + echo 'third_party_protobuf not exist' + fi +fi + +if [ ! -f "googletest/BUILD.gn" ];then + rm -rf googletest + git clone git@gitee.com:openharmony/third_party_googletest.git + if [ -d "third_party_googletest" ];then + mv third_party_googletest googletest + $cp ../prebuilts/patch_googletest/googletestbuild.gn ../third_party/googletest/BUILD.gn + $patch -p0 ../third_party/googletest/googletest/include/gtest/internal/gtest-internal.h ../prebuilts/patch_googletest/gtest_internal.h.patch + $patch -p0 ../third_party/googletest/googletest/include/gtest/internal/gtest-port.h ../prebuilts/patch_googletest/gtest_port.h.patch + $patch -p0 ../third_party/googletest/googletest/include/gtest/gtest-message.h ../prebuilts/patch_googletest/gtest-message.h.patch + $sed -i "/using ::std::string/s/^\(.*\)$/\/\/\1/g" ../third_party/googletest/googletest/include/gtest/hwext/gtest-tag.h + + else + echo 'third_party_googletest not exist' + fi +fi + +if [ ! -f "json-master/BUILD.gn" ];then + rm -rf json-master + git clone git@gitee.com:openharmony/third_party_json.git + if [ -d "third_party_json" ];then + mv third_party_json json-master + else + echo 'third_party_json not exist' + fi +fi + +if [ ! -f "libunwind/BUILD.gn" ];then + rm -rf libunwind + git clone git@gitee.com:openharmony/third_party_libunwind.git + if [ -d "third_party_libunwind" ];then + mv third_party_libunwind libunwind + $cp ../prebuilts/patch_libunwind/libunwindbuild.gn libunwind/BUILD.gn + else + echo 'third_party_libunwind not exist' + fi +fi + +if [ ! -f "perf_include/libbpf/linux/perf_event.h" ];then + mkdir -p perf_include/libbpf/linux + rm -rf perf_event.h + curl https://gitee.com/openharmony/third_party_libbpf/raw/20221117/github.com/libbpf/libbpf/refs/tags/v0.7.0/include/uapi/linux/perf_event.h > perf_event.h + mv perf_event.h perf_include/libbpf/linux/perf_event.h + $patch -p0 perf_include/libbpf/linux/perf_event.h ../prebuilts/patch_perf_event/perf_event.h.patch +fi + +if [ ! -f "perf_include/musl/elf.h" ];then + mkdir -p perf_include/musl + rm -rf elf.h + curl https://gitee.com/openharmony/third_party_musl/raw/master/include/elf.h > elf.h + mv elf.h perf_include/musl/elf.h +fi + +if [ ! -f "hiperf/BUILD.gn" ];then + rm -rf hiperf developtools_hiperf + git clone -b OpenHarmony-3.2-Release --depth=1 git@gitee.com:openharmony/developtools_hiperf.git + if [ -d "developtools_hiperf" ];then + mv developtools_hiperf hiperf + $cp ../prebuilts/patch_hiperf/BUILD.gn ../third_party/hiperf/BUILD.gn + # report.h + # remove #include "report_json_file.h" + $sed -i "/#include \"report_json_file.h\"/s/^\(.*\)$/\/\/\1/g" hiperf/include/report.h + $sed -i "/#include /s/^\(.*\)$/\/\/\1/g" hiperf/include/debug_logger.h + $sed -i "/#include /s/^\(.*\)$/\/\/\1/g" hiperf/include/utilities.h + $sed -i "/FRIEND_TEST/s/^\(.*\)$/\/\/\1/g" hiperf/include/virtual_thread.h + $sed -i "/FRIEND_TEST/s/^\(.*\)$/\/\/\1/g" hiperf/include/callstack.h + $sed -i "/FRIEND_TEST/s/^\(.*\)$/\/\/\1/g" hiperf/include/symbols_file.h + $sed -i "/FRIEND_TEST/s/^\(.*\)$/\/\/\1/g" hiperf/include/virtual_runtime.h + # elf_parser.h + $sed -i "/FRIEND_TEST/s/^\(.*\)$/\/\/\1/g" hiperf/include/report.h + #include <../musl/include/elf.h> + # 替换为 + #include + $sed -i "s/..\/musl\/include\/elf.h/elf.h/g" hiperf/include/elf_parser.h + # virtual_thread.h + # HIPERF_DEBUG 替换为 ALWAYSTRUE + $sed -i "s/HIPERF_DEBUG/ALWAYSTRUE/g" hiperf/include/virtual_thread.h + $cp ../prebuilts/patch_hiperf/file_ex.h hiperf/include/nonlinux/linux + $cp ../prebuilts/patch_hiperf/unique_fd.h hiperf/include/nonlinux/linux + $sed -i "/using __s8 = char;/a #define unw_word_t uint64_t" hiperf/include/nonlinux/linux/types.h + $sed -i "/#include /s/^\(.*\)$/\/\/\1/g" hiperf/src/utilities.cpp + $sed -i '/^bool CompressFile(/,/^}/ s/^.*$/\/\/&/; /^bool CompressFile(/,/return true;/ s/^[[:blank:]]*/ /' hiperf/src/utilities.cpp + $sed -i '/^bool UncompressFile(/,/^}/ s/^.*$/\/\/&/; /^bool UncompressFile(/,/return true;/ s/^[[:blank:]]*/ /' hiperf/src/utilities.cpp + $sed -i '/^void Report::PrepareConsole(/,/^}/ s/^.*$/\/\/&/; /^void Report::PrepareConsole(/,/return;/ s/^[[:blank:]]*/ /' hiperf/src/report.cpp + $sed -i '/namespace HiPerf {/abool UncompressFile(const std::string &gzipFile, const std::string &dataFile){return true;}' hiperf/src/utilities.cpp + $sed -i '/namespace HiPerf {/abool CompressFile(const std::string &dataFile, const std::string &destFile){return true;}' hiperf/src/utilities.cpp + $sed -i '/namespace HiPerf {/avoid Report::PrepareConsole(){ return;}' hiperf/src/report.cpp + else + echo 'hiperf not exist' + fi +fi diff --git a/trace_streamer/prebuilts/patch_googletest/googletestbuild.gn b/trace_streamer/prebuilts/patch_googletest/googletestbuild.gn new file mode 100755 index 0000000000000000000000000000000000000000..7ebdd491c830208cb6e0664ae6daaca30dd58e4a --- /dev/null +++ b/trace_streamer/prebuilts/patch_googletest/googletestbuild.gn @@ -0,0 +1,221 @@ +# 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. + +config("gtest_private_config") { + visibility = [ ":*" ] + include_dirs = [ "googletest" ] +} + +config("gtest_config") { + include_dirs = [ "googletest/include" ] +} + +static_library("gtest") { + testonly = true + public = [ + "googletest/include/gtest/gtest-spi.h", + "googletest/include/gtest/gtest.h", + ] + + cflags = [ + "-Wno-inconsistent-missing-override", + + # "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + "-Wno-exit-time-destructors", + "-Wno-missing-noreturn", + "-Wno-missing-noreturn", + ] + sources = [ + "googletest/include/gtest/gtest-death-test.h", + "googletest/include/gtest/gtest-message.h", + "googletest/include/gtest/gtest-param-test.h", + "googletest/include/gtest/gtest-printers.h", + "googletest/include/gtest/gtest-test-part.h", + "googletest/include/gtest/gtest-typed-test.h", + "googletest/include/gtest/gtest_pred_impl.h", + "googletest/include/gtest/gtest_prod.h", + "googletest/include/gtest/hwext/gtest-ext.h", + "googletest/include/gtest/hwext/gtest-filter.h", + "googletest/include/gtest/hwext/gtest-tag.h", + "googletest/include/gtest/hwext/utils.h", + "googletest/include/gtest/internal/custom/gtest-port.h", + "googletest/include/gtest/internal/custom/gtest-printers.h", + "googletest/include/gtest/internal/custom/gtest.h", + "googletest/include/gtest/internal/gtest-death-test-internal.h", + "googletest/include/gtest/internal/gtest-filepath.h", + "googletest/include/gtest/internal/gtest-internal.h", + "googletest/include/gtest/internal/gtest-linked_ptr.h", + "googletest/include/gtest/internal/gtest-param-util-generated.h", + "googletest/include/gtest/internal/gtest-param-util.h", + "googletest/include/gtest/internal/gtest-port-arch.h", + "googletest/include/gtest/internal/gtest-port.h", + "googletest/include/gtest/internal/gtest-string.h", + "googletest/include/gtest/internal/gtest-tuple.h", + "googletest/include/gtest/internal/gtest-type-util.h", + "googletest/src/gtest-all.cc", + "googletest/src/gtest-death-test.cc", + "googletest/src/gtest-filepath.cc", + "googletest/src/gtest-internal-inl.h", + "googletest/src/gtest-port.cc", + "googletest/src/gtest-printers.cc", + "googletest/src/gtest-test-part.cc", + "googletest/src/gtest-typed-test.cc", + "googletest/src/gtest.cc", + "googletest/src/hwext/gtest-ext.cc", + "googletest/src/hwext/gtest-filter.cc", + "googletest/src/hwext/gtest-tag.cc", + "googletest/src/hwext/gtest-utils.cc", + ] + sources -= [ "googletest/src/gtest-all.cc" ] + public_configs = [ ":gtest_config" ] + configs += [ ":gtest_private_config" ] + + # configs -= ["//build/config/coverage:default_coverage"] +} + +static_library("gtest_main") { + testonly = true + sources = [ "googletest/src/gtest_main.cc" ] + + cflags = [ + "-Wno-inconsistent-missing-override", + + # "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + "-Wno-exit-time-destructors", + "-Wno-missing-noreturn", + ] + public_deps = [ ":gtest" ] + + # configs -= ["//build/config/coverage:default_coverage"] +} + +config("gmock_private_config") { + visibility = [ ":*" ] + include_dirs = [ "googlemock" ] +} + +config("gmock_config") { + include_dirs = [ "googlemock/include" ] + + cflags_cc = [ + # The MOCK_METHODn() macros do not specify "override", which triggers this + # warning in users: "error: 'Method' overrides a member function but is not + # marked 'override' [-Werror,-Winconsistent-missing-override]". Suppress + # these warnings until https://github.com/google/googletest/issues/533 is + # fixed. + "-Wno-inconsistent-missing-override", + ] + cflags = [ + "-Wno-inconsistent-missing-override", + + # "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + "-Wno-exit-time-destructors", + "-Wno-missing-noreturn", + ] +} + +static_library("gmock") { + testonly = true + public = [ "googlemock/include/gmock/gmock.h" ] + cflags = [ + "-Wno-inconsistent-missing-override", + + # "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + "-Wno-exit-time-destructors", + "-Wno-missing-noreturn", + ] + sources = [ + "googlemock/include/gmock/gmock-actions.h", + "googlemock/include/gmock/gmock-cardinalities.h", + "googlemock/include/gmock/gmock-generated-actions.h", + "googlemock/include/gmock/gmock-generated-function-mockers.h", + "googlemock/include/gmock/gmock-generated-matchers.h", + "googlemock/include/gmock/gmock-generated-nice-strict.h", + "googlemock/include/gmock/gmock-matchers.h", + "googlemock/include/gmock/gmock-more-actions.h", + "googlemock/include/gmock/gmock-more-matchers.h", + "googlemock/include/gmock/gmock-spec-builders.h", + "googlemock/include/gmock/internal/custom/gmock-generated-actions.h", + "googlemock/include/gmock/internal/custom/gmock-matchers.h", + "googlemock/include/gmock/internal/custom/gmock-port.h", + "googlemock/include/gmock/internal/gmock-generated-internal-utils.h", + "googlemock/include/gmock/internal/gmock-internal-utils.h", + "googlemock/include/gmock/internal/gmock-port.h", + "googlemock/src/gmock-all.cc", + "googlemock/src/gmock-cardinalities.cc", + "googlemock/src/gmock-internal-utils.cc", + "googlemock/src/gmock-matchers.cc", + "googlemock/src/gmock-spec-builders.cc", + "googlemock/src/gmock.cc", + ] + sources -= [ "googlemock/src/gmock-all.cc" ] + public_configs = [ ":gmock_config" ] + configs += [ ":gmock_private_config" ] + + # configs -= ["//build/config/coverage:default_coverage"] + deps = [ ":gtest" ] +} + +static_library("gmock_main") { + testonly = true + + cflags = [ + "-Wno-inconsistent-missing-override", + + # "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + "-Wno-exit-time-destructors", + "-Wno-missing-noreturn", + ] + sources = [ "googlemock/src/gmock_main.cc" ] + public_deps = [ + ":gmock", + ":gtest", + ] + + # configs -= ["//build/config/coverage:default_coverage"] +} diff --git a/trace_streamer/prebuilts/patch_googletest/googletestbuild.gn.patch b/trace_streamer/prebuilts/patch_googletest/googletestbuild.gn.patch new file mode 100644 index 0000000000000000000000000000000000000000..7efd6627c4ec9f2ca379132b2141b72d1447d43c --- /dev/null +++ b/trace_streamer/prebuilts/patch_googletest/googletestbuild.gn.patch @@ -0,0 +1,191 @@ +--- googletest/BUILD.gn 2023-01-04 17:01:37.911633386 +0800 ++++ ../prebuilts/buildgoogletest/googletestbuild.gn 2022-11-29 14:31:52.355999207 +0800 +@@ -9,12 +9,6 @@ + + config("gtest_config") { + include_dirs = [ "googletest/include" ] +- if (is_mingw) { +- cflags_cc = [ +- "-Wno-unused-const-variable", +- "-Wno-unused-private-field", +- ] +- } + } + + static_library("gtest") { +@@ -23,9 +17,24 @@ + "googletest/include/gtest/gtest-spi.h", + "googletest/include/gtest/gtest.h", + ] ++ ++ cflags = [ ++ "-Wno-inconsistent-missing-override", ++ ++ # "-Dprivate=public", #allow test code access private members ++ "-fprofile-arcs", ++ "-ftest-coverage", ++ "-Wno-unused-command-line-argument", ++ "-Wno-format", ++ "-Wno-unused-const-variable", ++ "-Wno-unused-variable", ++ "-Wno-used-but-marked-unused", ++ "-Wno-exit-time-destructors", ++ "-Wno-missing-noreturn", ++ "-Wno-missing-noreturn", ++ ] + sources = [ + "googletest/include/gtest/gtest-death-test.h", +- "googletest/include/gtest/gtest-matchers.h", + "googletest/include/gtest/gtest-message.h", + "googletest/include/gtest/gtest-param-test.h", + "googletest/include/gtest/gtest-printers.h", +@@ -43,16 +52,18 @@ + "googletest/include/gtest/internal/gtest-death-test-internal.h", + "googletest/include/gtest/internal/gtest-filepath.h", + "googletest/include/gtest/internal/gtest-internal.h", ++ "googletest/include/gtest/internal/gtest-linked_ptr.h", ++ "googletest/include/gtest/internal/gtest-param-util-generated.h", + "googletest/include/gtest/internal/gtest-param-util.h", + "googletest/include/gtest/internal/gtest-port-arch.h", + "googletest/include/gtest/internal/gtest-port.h", + "googletest/include/gtest/internal/gtest-string.h", ++ "googletest/include/gtest/internal/gtest-tuple.h", + "googletest/include/gtest/internal/gtest-type-util.h", + "googletest/src/gtest-all.cc", + "googletest/src/gtest-death-test.cc", + "googletest/src/gtest-filepath.cc", + "googletest/src/gtest-internal-inl.h", +- "googletest/src/gtest-matchers.cc", + "googletest/src/gtest-port.cc", + "googletest/src/gtest-printers.cc", + "googletest/src/gtest-test-part.cc", +@@ -66,14 +77,31 @@ + sources -= [ "googletest/src/gtest-all.cc" ] + public_configs = [ ":gtest_config" ] + configs += [ ":gtest_private_config" ] +- configs -= [ "//build/config/coverage:default_coverage" ] ++ ++ # configs -= ["//build/config/coverage:default_coverage"] + } + + static_library("gtest_main") { + testonly = true + sources = [ "googletest/src/gtest_main.cc" ] ++ ++ cflags = [ ++ "-Wno-inconsistent-missing-override", ++ ++ # "-Dprivate=public", #allow test code access private members ++ "-fprofile-arcs", ++ "-ftest-coverage", ++ "-Wno-unused-command-line-argument", ++ "-Wno-format", ++ "-Wno-unused-const-variable", ++ "-Wno-unused-variable", ++ "-Wno-used-but-marked-unused", ++ "-Wno-exit-time-destructors", ++ "-Wno-missing-noreturn", ++ ] + public_deps = [ ":gtest" ] +- configs -= [ "//build/config/coverage:default_coverage" ] ++ ++ # configs -= ["//build/config/coverage:default_coverage"] + } + + config("gmock_private_config") { +@@ -92,26 +120,56 @@ + # fixed. + "-Wno-inconsistent-missing-override", + ] ++ cflags = [ ++ "-Wno-inconsistent-missing-override", ++ ++ # "-Dprivate=public", #allow test code access private members ++ "-fprofile-arcs", ++ "-ftest-coverage", ++ "-Wno-unused-command-line-argument", ++ "-Wno-format", ++ "-Wno-unused-const-variable", ++ "-Wno-unused-variable", ++ "-Wno-used-but-marked-unused", ++ "-Wno-exit-time-destructors", ++ "-Wno-missing-noreturn", ++ ] + } + + static_library("gmock") { + testonly = true + public = [ "googlemock/include/gmock/gmock.h" ] ++ cflags = [ ++ "-Wno-inconsistent-missing-override", ++ ++ # "-Dprivate=public", #allow test code access private members ++ "-fprofile-arcs", ++ "-ftest-coverage", ++ "-Wno-unused-command-line-argument", ++ "-Wno-format", ++ "-Wno-unused-const-variable", ++ "-Wno-unused-variable", ++ "-Wno-used-but-marked-unused", ++ "-Wno-exit-time-destructors", ++ "-Wno-missing-noreturn", ++ ] + sources = [ + "googlemock/include/gmock/gmock-actions.h", + "googlemock/include/gmock/gmock-cardinalities.h", +- "googlemock/include/gmock/gmock-function-mocker.h", ++ "googlemock/include/gmock/gmock-generated-actions.h", ++ "googlemock/include/gmock/gmock-generated-function-mockers.h", ++ "googlemock/include/gmock/gmock-generated-matchers.h", ++ "googlemock/include/gmock/gmock-generated-nice-strict.h", + "googlemock/include/gmock/gmock-matchers.h", + "googlemock/include/gmock/gmock-more-actions.h", + "googlemock/include/gmock/gmock-more-matchers.h", +- "googlemock/include/gmock/gmock-nice-strict.h", + "googlemock/include/gmock/gmock-spec-builders.h", + "googlemock/include/gmock/internal/custom/gmock-generated-actions.h", + "googlemock/include/gmock/internal/custom/gmock-matchers.h", + "googlemock/include/gmock/internal/custom/gmock-port.h", ++ "googlemock/include/gmock/internal/gmock-generated-internal-utils.h", + "googlemock/include/gmock/internal/gmock-internal-utils.h", + "googlemock/include/gmock/internal/gmock-port.h", +- "googlemock/include/gmock/internal/gmock-pp.h", + "googlemock/src/gmock-all.cc", + "googlemock/src/gmock-cardinalities.cc", + "googlemock/src/gmock-internal-utils.cc", +@@ -122,16 +180,33 @@ + sources -= [ "googlemock/src/gmock-all.cc" ] + public_configs = [ ":gmock_config" ] + configs += [ ":gmock_private_config" ] +- configs -= [ "//build/config/coverage:default_coverage" ] ++ ++ # configs -= ["//build/config/coverage:default_coverage"] + deps = [ ":gtest" ] + } + + static_library("gmock_main") { + testonly = true ++ ++ cflags = [ ++ "-Wno-inconsistent-missing-override", ++ ++ # "-Dprivate=public", #allow test code access private members ++ "-fprofile-arcs", ++ "-ftest-coverage", ++ "-Wno-unused-command-line-argument", ++ "-Wno-format", ++ "-Wno-unused-const-variable", ++ "-Wno-unused-variable", ++ "-Wno-used-but-marked-unused", ++ "-Wno-exit-time-destructors", ++ "-Wno-missing-noreturn", ++ ] + sources = [ "googlemock/src/gmock_main.cc" ] + public_deps = [ + ":gmock", + ":gtest", + ] +- configs -= [ "//build/config/coverage:default_coverage" ] ++ ++ # configs -= ["//build/config/coverage:default_coverage"] + } diff --git a/trace_streamer/prebuilts/patch_googletest/gtest-message.h.patch b/trace_streamer/prebuilts/patch_googletest/gtest-message.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..266103762b66274a49f8321cb336c2ccb017ab2d --- /dev/null +++ b/trace_streamer/prebuilts/patch_googletest/gtest-message.h.patch @@ -0,0 +1,15 @@ +--- third_party/googletest/googletest/include/gtest/gtest-message.h 2023-01-17 16:10:56.252360383 +0800 ++++ /home/suze/tp/code/ohos_devtools_trace_resolver/third_party/googletest/googletest/include/gtest/gtest-message.h 2023-01-06 17:58:25.830759482 +0800 +@@ -49,8 +49,11 @@ + + #include + #include ++#undef private ++#define private private + #include +- ++#undef private ++#define private public + #include "gtest/internal/gtest-port.h" + + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ diff --git a/trace_streamer/prebuilts/patch_googletest/gtest_internal.h.patch b/trace_streamer/prebuilts/patch_googletest/gtest_internal.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..e47ac4faa2343fc71ba90adae8cccb66b8cf0fa4 --- /dev/null +++ b/trace_streamer/prebuilts/patch_googletest/gtest_internal.h.patch @@ -0,0 +1,14 @@ +--- third_party/googletest/googletest/include/gtest/internal/gtest-internal.h 2023-01-17 16:10:56.252360383 +0800 ++++ /home/suze/tp/code/ohos_devtools_trace_resolver/third_party/googletest/googletest/include/gtest/internal/gtest-internal.h 2023-01-06 17:58:25.830759482 +0800 +@@ -54,7 +54,11 @@ + #include + #include + #include ++#undef private ++#define private private + #include ++#undef private ++#define private public + #include + #include + #include diff --git a/trace_streamer/prebuilts/patch_googletest/gtest_port.h.patch b/trace_streamer/prebuilts/patch_googletest/gtest_port.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..bb5d1e2d3d316b0fd53355268072c2a620c54022 --- /dev/null +++ b/trace_streamer/prebuilts/patch_googletest/gtest_port.h.patch @@ -0,0 +1,23 @@ +--- third_party/googletest/googletest/include/gtest/internal/gtest-port.h 2023-01-17 16:10:56.252360383 +0800 ++++ /home/suze/tp/code/ohos_devtools_trace_resolver/third_party/googletest/googletest/include/gtest/internal/gtest-port.h 2023-01-06 17:58:25.834759489 +0800 +@@ -276,7 +276,6 @@ + # include + # include + #endif +- + #include // NOLINT + #include + #include +@@ -2287,7 +2286,11 @@ using Any = ::absl::any; + // Otherwise for C++17 and higher use std::any for UniversalPrinter<> + // specializations. + #define GTEST_INTERNAL_HAS_ANY 1 +-#include ++#undef private ++#define private private ++#include // NOLINT ++#undef private ++#define private public + namespace testing { + namespace internal { + using Any = ::std::any; diff --git a/trace_streamer/prebuilts/patch_hiperf/BUILD.gn b/trace_streamer/prebuilts/patch_hiperf/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..496e27205fa62e4d81a7c1498c240438f767e789 --- /dev/null +++ b/trace_streamer/prebuilts/patch_hiperf/BUILD.gn @@ -0,0 +1,77 @@ +# 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("../../src/ts.gni") +ohos_source_set("hiperf_src") { + configs -= ["//gn:trace_cfg"] + configs += ["//gn:hiperf_trace_cfg"] + subsystem_name = "trace_streamer" + part_name = "hiperf_src" + cflags = [ "-D ALWAYSTRUE" ] + sources = [ + "./src/callstack.cpp", + "./src/callstack.h", + "./src/dwarf_encoding.cpp", + "./src/dwarf_encoding.h", + "./src/elf_file.cpp", + "./src/elf_header.cpp", + "./src/elf_symbol.cpp", + "./src/hashlist.h", + "./src/option.cpp", + "./src/perf_event_record.cpp", + "./src/perf_file_format.cpp", + "./src/perf_file_reader.cpp", + "./src/program_header.cpp", + "./src/register.cpp", + "./src/register.h", + "./src/report.cpp", + "./src/section_header.cpp", + "./src/subcommand.cpp", + "./src/symbols_file.cpp", + "./src/utilities.cpp", + "./src/virtual_runtime.cpp", + "./src/virtual_thread.cpp", + "include/symbols_file.h", + ] + include_dirs = [ + "linux", + "../", + "./", + "../../src/base", + "include", + "../../src/include", + "../../src/", + "../../src/trace_streamer", + "include/nonlinux", + "include/nonlinux/linux", + ] + include_dirs += [ + "//third_party/perf_include/libbpf", + "//third_party/perf_include/musl", + "//third_party/libunwind/include", + "//third_party/libunwind/src", + "//third_party/libunwind/include/tdep-x86_64", + ] +} + +group("hiperf") { + deps = [ + ":hiperf_src", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + if (target != "test" && !is_openharmony) { + deps += [ "//prebuilts/protos:ts_proto_data_cpp" ] + } +} diff --git a/trace_streamer/prebuilts/patch_hiperf/README.md b/trace_streamer/prebuilts/patch_hiperf/README.md new file mode 100644 index 0000000000000000000000000000000000000000..6acf3832549735569624f464e2a14ebd3d61d69e --- /dev/null +++ b/trace_streamer/prebuilts/patch_hiperf/README.md @@ -0,0 +1,55 @@ +# Hiperf目录文件说明 +TraceStreamer支持hiperf数据的解析,引用了openharmony原生的hiperf,但由于TraceStreamer是独立编译,需要使用独立的BUILD.gn,本目录下的BUILD.gn会用来替换下载的hiperf目录下的BUILD.gn。 +所有的操作,在代码的根目录下执行pare_third_party.sh会自动完成。 +TraceStreamer使用的perf文件列表如下: +``` +├── include +│   ├── callstack.h +│   ├── debug_logger.h +│   ├── dwarf_encoding.h +│   ├── elf_parser.h +│   ├── hashlist.h +│   ├── hashlist.hpp +│   ├── linux +│   │   ├── types.h +│   ├── mem_map_item.h +│   ├── noncopyable.h +│   ├── option.h +│   ├── perf_event_record.h +│   ├── perf_events.h +│   ├── perf_file_format.h +│   ├── perf_file_reader.h +│   ├── perf_record_format.h +│   ├── register.h +│   ├── report.h +│   ├── ring_buffer.h +│   ├── subcommand_dump.h +│   ├── subcommand.h +│   ├── subcommand_help.h +│   ├── symbols_file.h +│   ├── tracked_command.h +│   ├── utilities.h +│   ├── virtual_runtime.h +│   └── virtual_thread.h +└── src + ├── callstack.cpp + ├── debug_logger.cpp + ├── dwarf_encoding.cpp + ├── elf_file.cpp + ├── elf_header.cpp + ├── elf_symbol.cpp + ├── option.cpp + ├── perf_event_record.cpp + ├── perf_file_format.cpp + ├── perf_file_reader.cpp + ├── program_header.cpp + ├── register.cpp + ├── report.cpp + ├── section_header.cpp + ├── subcommand.cpp + ├── subcommand_help.cpp + ├── symbols_file.cpp + ├── utilities.cpp + ├── virtual_runtime.cpp + └── virtual_thread.cpp +``` \ No newline at end of file diff --git a/trace_streamer/prebuilts/patch_hiperf/file_ex.h b/trace_streamer/prebuilts/patch_hiperf/file_ex.h new file mode 100644 index 0000000000000000000000000000000000000000..09481777ef360eac52adc38e3ca5afe144b406f7 --- /dev/null +++ b/trace_streamer/prebuilts/patch_hiperf/file_ex.h @@ -0,0 +1,33 @@ +/* + * 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 UTILS_BASE_FILE_EX_H +#define UTILS_BASE_FILE_EX_H + +#include +#include +namespace OHOS { +bool LoadStringFromFile(const std::string& filePath, std::string& content); +bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated = true); +bool LoadStringFromFd(int fd, std::string& content); +bool SaveStringToFd(int fd, const std::string& content); +bool LoadBufferFromFile(const std::string& filePath, std::vector& content); +bool SaveBufferToFile(const std::string& filePath, const std::vector& content, bool truncated = true); +bool FileExists(const std::string& fileName); +bool StringExistsInFile(const std::string& fileName, const std::string& subStr, bool caseSensitive = true); +int CountStrInFile(const std::string& fileName, const std::string& subStr, bool caseSensitive = true); +} // namespace OHOS + +#endif diff --git a/trace_streamer/prebuilts/patch_hiperf/unique_fd.h b/trace_streamer/prebuilts/patch_hiperf/unique_fd.h new file mode 100644 index 0000000000000000000000000000000000000000..36ca3046e06ada2ae5399903ee0bb05372d63f1b --- /dev/null +++ b/trace_streamer/prebuilts/patch_hiperf/unique_fd.h @@ -0,0 +1,186 @@ +/* + * 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 UNIQUE_FD_H +#define UNIQUE_FD_H + +#include + +namespace OHOS { +class DefaultDeleter { +public: + static void Close(int fd) + { + if (fd >= 0) { + close(fd); + } + } +}; + +template +class UniqueFdAddDeletor; +template +bool operator==(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator!=(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator>=(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator>(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator<=(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator<(const int& lhs, const UniqueFdAddDeletor& rhs); + +template +class UniqueFdAddDeletor final { + + friend bool operator==(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator!=(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator>=(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator>(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator<=(const int& lhs, const UniqueFdAddDeletor& rhs); + // clang-format off + friend bool operator< (const int& lhs, const UniqueFdAddDeletor& rhs); + // clang-format on +public: + explicit UniqueFdAddDeletor(const int& value) : fd_(value) {} + UniqueFdAddDeletor() : fd_(-1) {} + ~UniqueFdAddDeletor() + { + Reset(-1); + } + + // get fd out + int Release() + { + int tmp = fd_; + fd_ = -1; + return tmp; + } + + // this is dangerous, when you use it , you should know it, donot operator on the ret + operator int() const + { + return Get(); + } // NOLINT + // this is dangerous, when you use it , you should know it, donot operator on the ret + int Get() const + { + return fd_; + } + + // we need move fd from one to another + UniqueFdAddDeletor(UniqueFdAddDeletor&& rhs) + { + int rhsfd = rhs.Release(); + fd_ = rhsfd; + } + + UniqueFdAddDeletor& operator=(UniqueFdAddDeletor&& rhs) + { + int rhsfd = rhs.Release(); + Reset(rhsfd); + return *this; + } + + bool operator==(const int& rhs) const + { + return fd_ == rhs; + } + + bool operator!=(const int& rhs) const + { + return !(fd_ == rhs); + } + bool operator>=(const int& rhs) const + { + return fd_ >= rhs; + } + + bool operator>(const int& rhs) const + { + return fd_ > rhs; + } + + bool operator<=(const int& rhs) const + { + return fd_ <= rhs; + } + + bool operator<(const int& rhs) const + { + return fd_ < rhs; + } + +private: + int fd_ = -1; + + void Reset(int newValue) + { + if (fd_ >= 0) { + Deleter::Close(fd_); + } + fd_ = newValue; + } + + // disallow copy ctor and copy assign + UniqueFdAddDeletor(const UniqueFdAddDeletor& rhs) = delete; + UniqueFdAddDeletor& operator=(const UniqueFdAddDeletor& rhs) = delete; +}; + +template +bool operator==(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs == uniqueFd.fd_; +} + +template +bool operator!=(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return !(lhs == uniqueFd.fd_); +} + +template +bool operator>=(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs >= uniqueFd.fd_; +} + +template +bool operator>(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs > uniqueFd.fd_; +} + +template +bool operator<=(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs <= uniqueFd.fd_; +} + +template +bool operator<(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs < uniqueFd.fd_; +} + +using UniqueFd = UniqueFdAddDeletor; +} // namespace OHOS +#endif diff --git a/trace_streamer/prebuilts/patch_libunwind/libunwindbuild.gn b/trace_streamer/prebuilts/patch_libunwind/libunwindbuild.gn new file mode 100644 index 0000000000000000000000000000000000000000..32b347a5d4506b8f2f1e84129844785be6c206f1 --- /dev/null +++ b/trace_streamer/prebuilts/patch_libunwind/libunwindbuild.gn @@ -0,0 +1,471 @@ +# 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") +common_source = [ + "src/dwarf/Gexpr.c", + "src/dwarf/Gfde.c", + "src/dwarf/Gfind_proc_info-lsb.c", + "src/dwarf/Gfind_unwind_table.c", + "src/dwarf/global.c", + "src/dwarf/Gparser.c", + "src/dwarf/Gpe.c", + "src/dwarf/Lexpr.c", + "src/dwarf/Lfde.c", + "src/dwarf/Lfind_proc_info-lsb.c", + "src/dwarf/Lfind_unwind_table.c", + "src/dwarf/Lparser.c", + "src/dwarf/Lpe.c", + "src/mi/backtrace.c", + "src/mi/dyn-cancel.c", + "src/mi/dyn-info-list.c", + "src/mi/dyn-register.c", + "src/mi/flush_cache.c", + "src/mi/Gdestroy_addr_space.c", + "src/mi/Gdyn-extract.c", + "src/mi/Gdyn-remote.c", + "src/mi/Gfind_dynamic_proc_info.c", + "src/mi/Gget_accessors.c", + "src/mi/Gget_fpreg.c", + "src/mi/Gget_proc_info_by_ip.c", + "src/mi/Gget_proc_name.c", + "src/mi/Gget_reg.c", + "src/mi/Gput_dynamic_unwind_info.c", + "src/mi/Gset_cache_size.c", + "src/mi/Gset_caching_policy.c", + "src/mi/Gset_fpreg.c", + "src/mi/Gset_reg.c", + "src/mi/init.c", + "src/mi/Ldestroy_addr_space.c", + "src/mi/Ldyn-extract.c", + "src/mi/Lfind_dynamic_proc_info.c", + "src/mi/Lget_fpreg.c", + "src/mi/Lget_proc_info_by_ip.c", + "src/mi/Lget_proc_name.c", + "src/mi/Lget_reg.c", + "src/mi/Lput_dynamic_unwind_info.c", + "src/mi/Lset_cache_size.c", + "src/mi/Lset_caching_policy.c", + "src/mi/Lset_fpreg.c", + "src/mi/Lset_reg.c", + "src/mi/mempool.c", + "src/mi/strerror.c", + "src/os-linux.c", + "src/ohos-config.c", + "src/ptrace/_UPT_access_fpreg.c", + "src/ptrace/_UPT_access_mem.c", + "src/ptrace/_UPT_access_reg.c", + "src/ptrace/_UPT_accessors.c", + "src/ptrace/_UPT_create.c", + "src/ptrace/_UPT_destroy.c", + "src/ptrace/_UPT_find_proc_info.c", + "src/ptrace/_UPT_get_dyn_info_list_addr.c", + "src/ptrace/_UPT_get_proc_name.c", + "src/ptrace/_UPT_put_unwind_info.c", + "src/ptrace/_UPT_reg_offset.c", + "src/ptrace/_UPT_resume.c", + "src/mi/maps.c", +] + +# as libc++ is static linked with libunwind.a +# we remove the Gstep.c for duplicated symbol violation +if (target_cpu == "arm") { + arm_source = [ + "src/arm/Gapply_reg_state.c", + "src/arm/Gcreate_addr_space.c", + "src/arm/Gex_tables.c", + "src/arm/Gget_proc_info.c", + "src/arm/Gget_save_loc.c", + "src/arm/Gglobal.c", + "src/arm/Ginit.c", + "src/arm/Ginit_local.c", + "src/arm/Ginit_remote.c", + "src/arm/Gos-linux.c", + "src/arm/Greg_states_iterate.c", + "src/arm/Gregs.c", + "src/arm/Gresume.c", + "src/arm/Gstash_frame.c", + "src/arm/Gstep.c", + "src/arm/Gtrace.c", + "src/arm/Lcreate_addr_space.c", + "src/arm/Lex_tables.c", + "src/arm/Lget_proc_info.c", + "src/arm/Lget_save_loc.c", + "src/arm/Lglobal.c", + "src/arm/Linit.c", + "src/arm/Linit_local.c", + "src/arm/Linit_remote.c", + "src/arm/Los-linux.c", + "src/arm/Lregs.c", + "src/arm/Lresume.c", + "src/arm/Lstash_frame.c", + "src/arm/Lstep.c", + "src/arm/Ltrace.c", + "src/arm/gen-offsets.c", + "src/arm/getcontext.S", + "src/arm/is_fpreg.c", + "src/arm/regname.c", + "src/arm/siglongjmp.S", + "src/elf32.c", + ] +} +if (target_cpu == "arm64") { + arm64_source = [ + "src/aarch64/Gcreate_addr_space.c", + "src/aarch64/Gget_proc_info.c", + "src/aarch64/Gget_save_loc.c", + "src/aarch64/Gglobal.c", + "src/aarch64/Ginit.c", + "src/aarch64/Ginit_local.c", + "src/aarch64/Ginit_remote.c", + "src/aarch64/Gis_signal_frame.c", + "src/aarch64/Gregs.c", + "src/aarch64/Gresume.c", + "src/aarch64/Gstash_frame.c", + "src/aarch64/Gstep.c", + "src/aarch64/Gtrace.c", + "src/aarch64/Lcreate_addr_space.c", + "src/aarch64/Lget_proc_info.c", + "src/aarch64/Lget_save_loc.c", + "src/aarch64/Lglobal.c", + "src/aarch64/Linit.c", + "src/aarch64/Linit_local.c", + "src/aarch64/Linit_remote.c", + "src/aarch64/Lis_signal_frame.c", + "src/aarch64/Lregs.c", + "src/aarch64/Lresume.c", + "src/aarch64/Lstash_frame.c", + "src/aarch64/Lstep.c", + "src/aarch64/Ltrace.c", + "src/aarch64/getcontext.S", + "src/aarch64/is_fpreg.c", + "src/aarch64/regname.c", + "src/elf64.c", + ] +} + +if (target_cpu == "x64") { + x64_source = [ + "src/elf64.c", + "src/x86_64/Gcreate_addr_space.c", + "src/x86_64/Gget_proc_info.c", + "src/x86_64/Gget_save_loc.c", + "src/x86_64/Gglobal.c", + "src/x86_64/Ginit.c", + "src/x86_64/Ginit_local.c", + "src/x86_64/Ginit_remote.c", + "src/x86_64/Gos-linux.c", + "src/x86_64/Gregs.c", + "src/x86_64/Gresume.c", + "src/x86_64/Gstash_frame.c", + "src/x86_64/Gstep.c", + "src/x86_64/Gtrace.c", + "src/x86_64/Lcreate_addr_space.c", + "src/x86_64/Lget_proc_info.c", + "src/x86_64/Lget_save_loc.c", + "src/x86_64/Lglobal.c", + "src/x86_64/Linit.c", + "src/x86_64/Linit_local.c", + "src/x86_64/Linit_remote.c", + "src/x86_64/Los-linux.c", + "src/x86_64/Lregs.c", + "src/x86_64/Lresume.c", + "src/x86_64/Lstash_frame.c", + "src/x86_64/Lstep.c", + "src/x86_64/Ltrace.c", + "src/x86_64/getcontext.S", + "src/x86_64/is_fpreg.c", + "src/x86_64/regname.c", + "src/x86_64/setcontext.S", + ] +} +remove_sources = [] + +ptrace_sources = [ + "src/ptrace/_UPT_access_fpreg.c", + "src/ptrace/_UPT_access_mem.c", + "src/ptrace/_UPT_access_reg.c", + "src/ptrace/_UPT_accessors.c", + "src/ptrace/_UPT_create.c", + "src/ptrace/_UPT_destroy.c", + "src/ptrace/_UPT_find_proc_info.c", + "src/ptrace/_UPT_get_dyn_info_list_addr.c", + "src/ptrace/_UPT_get_proc_name.c", + "src/ptrace/_UPT_put_unwind_info.c", + "src/ptrace/_UPT_reg_offset.c", + "src/ptrace/_UPT_resume.c", +] + +libunwind_la_SOURCES_local_nounwind = [ + "src/mi/backtrace.c", + "src/mi/dyn-cancel.c", + "src/mi/dyn-info-list.c", + "src/mi/dyn-register.c", + "src/mi/Ldyn-extract.c", + "src/mi/Lfind_dynamic_proc_info.c", + + # "src/mi/Lget_accessors.c", # miss + "src/mi/Lget_proc_info_by_ip.c", + "src/mi/Lget_proc_name.c", + "src/mi/Lput_dynamic_unwind_info.c", + "src/mi/Ldestroy_addr_space.c", + "src/mi/Lget_reg.c", + "src/mi/Lset_reg.c", + "src/mi/Lget_fpreg.c", + "src/mi/Lset_fpreg.c", + "src/mi/Lset_caching_policy.c", + "src/mi/Lset_cache_size.c", +] + +libunwind_dwarf_local_la_SOURCES = [ + "src/dwarf/Lexpr.c", + "src/dwarf/Lfde.c", + "src/dwarf/Lparser.c", + "src/dwarf/Lpe.c", + "src/dwarf/Lfind_proc_info-lsb.c", + "src/dwarf/Lfind_unwind_table.c", +] + +# remove local file +remove_sources += libunwind_la_SOURCES_local_nounwind +remove_sources += libunwind_dwarf_local_la_SOURCES +remove_sources += ptrace_sources + +if (is_mingw) { + common_source += [ "src/mingw/pal-single-threaded.c" ] +} + +config("unwind_config_public") { + include_dirs = [ + "src", + "include", + ] + + cflags = [ + "-D_GNU_SOURCE", + "-DHAVE_CONFIG_H", + + # "-DNDEBUG", + "-DCC_IS_CLANG", + "-fcommon", + "-Werror", + "-Wno-absolute-value", + "-Wno-header-guard", + "-Wno-unused-parameter", + "-Wno-unused-variable", + "-Wno-unused-result", + "-Wno-tautological-constant-out-of-range-compare", + ] + if (use_wasm) { + cflags += [ "-Wno-incompatible-pointer-types" ] + } + if (is_mingw) { + cflags += [ + "-Wno-attributes", + "-Wno-pointer-to-int-cast", + "-Wno-implicit-function-declaration", + + # "-Wno-absolute-value", + # "-Wno-header-guard", + # "-Wno-tautological-constant-out-of-range-compare", + # "-Wno-sometimes-uninitialized", + # "-Wno-int-to-void-pointer-cast", + ] + } + + if (use_wasm) { + cflags += [ + # "-D __mips__" + # "-D WASM", + ] + } + + if (defined(ohos_lite)) { + cflags += [ "-fPIC" ] + } + + if (target_cpu == "arm") { + include_dirs += [ "include/tdep-arm" ] + cflags += [ + "-Wno-inline-asm", + "-Wno-shift-count-overflow", + "-Wno-tautological-constant-out-of-range-compare", + "-Wno-unused-function", + ] + } else if (target_cpu == "arm64") { + include_dirs += [ "include/tdep-aarch64" ] + cflags += [ "-Wno-incompatible-pointer-types" ] + } else if (target_cpu == "x64") { + include_dirs += [ "include/tdep-x86_64" ] + } +} +config("unwind_config_remote") { + cflags = + [ "-Wno-format" ] # some debug feature will warning in host x64 build +} +config("unwind_config_remote_public") { + cflags = [] + include_dirs = [] + defines = [] + + # this is a host tools build + # what means host use remote mode to unwind + # with dwarf from stack or coredump or something not real target + # There is an exception, we can support local unwind for linux. + cflags += [ "-DUNW_REMOTE_ONLY" ] + + cflags += [ "-DBUILD_REMOTE" ] + + cflags += [ "-Wno-sometimes-uninitialized" ] # some value not initialized in + # host x64 build + cflags += [ "-Wno-int-to-void-pointer-cast" ] + + if (is_mingw) { + include_dirs += [ "include/mingw" ] + cflags += [ "-DMINGW" ] + } else if (is_linux) { + cflags += [ "-g" ] # we need debug info when it crash. + } + + defines += [ "build_remote=1" ] + defines += [ "target_cpu=${target_cpu}" ] + + # defines += [ "host_toolchain=${host_toolchain}" ] + # defines += [ "current_toolchain=${current_toolchain}" ] + # defines += [ "default_toolchain=${default_toolchain}" ] +} + +config("unwind_config_arm") { + defines = [ "UNW_TARGET_ARM" ] +} + +config("unwind_config_arm64") { + defines = [ "UNW_TARGET_ARM64" ] +} + +config("unwind_config_x64") { + defines = [ "UNW_TARGET_X86_64" ] + defines += [ "UNW_TARGET_X86_64_LINUX" ] +} +if (target_cpu == "arm") { + ohos_source_set("unwind_source_arm") { + subsystem_name = "trace_streamer" + part_name = "unwind_source_arm" + configs += [ ":unwind_config_remote" ] + public_configs = [ + ":unwind_config_public", + ":unwind_config_remote_public", + ":unwind_config_arm", + ] + sources = common_source + + # there is a main function in this file + # for a lib we dont need this + arm_source -= [ "src/arm/gen-offsets.c" ] + + # no jump lib + arm_source -= [ + "src/arm/getcontext.S", + "src/arm/siglongjmp.S", + ] + sources += arm_source + sources -= remove_sources + } +} +if (target_cpu == "arm64") { + ohos_source_set("unwind_source_arm64") { + subsystem_name = "trace_streamer" + part_name = "unwind_source_arm64" + configs += [ ":unwind_config_remote" ] + public_configs = [ + ":unwind_config_public", + ":unwind_config_remote_public", + ":unwind_config_arm64", + ] + sources = common_source + + arm64_source -= [ "src/aarch64/getcontext.S" ] + + sources += arm64_source + sources -= remove_sources + } +} +if (target_cpu == "x86") { + ohos_source_set("unwind_source_x64") { + subsystem_name = "trace_streamer" + part_name = "unwind_source_x64" + configs += [ ":unwind_config_remote" ] + public_configs = [ + ":unwind_config_public", + ":unwind_config_remote_public", + ":unwind_config_x64", + ] + sources = common_source + + # no jump lib + x64_source -= [ + "src/x86_64/getcontext.S", + "src/x86_64/setcontext.S", + ] + sources += x64_source + sources -= remove_sources + } +} +ohos_source_set("unwind_source") { + subsystem_name = "trace_streamer" + part_name = "unwind_source" + configs += [ ":unwind_config_public" ] + sources = common_source + if (target_cpu == "arm") { + # as libc++ is static linked with libunwind.a + # we remove the Gstep.c for duplicated symbol violation + sources += arm_source + public_configs = [ ":unwind_config_arm" ] + } else if (target_cpu == "arm64") { + sources += arm64_source + public_configs = [ ":unwind_config_arm64" ] + } else if (target_cpu == "x64") { + # deps = [ "unwind_source_x64" ] + sources += x64_source + public_configs = [ ":unwind_config_x64" ] + + # public_configs = [ + # ":unwind_config_public", + # ":unwind_config_remote_public", + # ":unwind_config_x64", + # ] + } + + sources += [ "src/os-ohos.c" ] +} + +if (defined(ohos_lite)) { + # shared_library("libunwind") { + source_set("libunwind") { + deps = [ ":unwind_source" ] + public_configs = [ ":unwind_config_public" ] + } +} else { + source_set("libunwind") { + deps = [ ":unwind_source" ] + + # install_images = [ + # "system", + # "updater", + # ] + public_configs = [ ":unwind_config_public" ] + + # part_name = "faultloggerd" + # subsystem_name = "hiviewdfx" + } +} diff --git a/trace_streamer/prebuilts/patch_libunwind/libunwindbuild.gn.patch b/trace_streamer/prebuilts/patch_libunwind/libunwindbuild.gn.patch new file mode 100644 index 0000000000000000000000000000000000000000..371e30bd8c7c9f292f6c58bca6788dceb3972cc8 --- /dev/null +++ b/trace_streamer/prebuilts/patch_libunwind/libunwindbuild.gn.patch @@ -0,0 +1,863 @@ +--- third_party/libunwind/BUILD.gn 2023-01-17 13:58:11.209820400 +0800 ++++ prebuilts/patch_libunwind/libunwindbuild.gn 2023-01-17 11:02:37.478105100 +0800 +@@ -11,13 +11,7 @@ + # See the License for the specific language governing permissions and + # limitations under the License. + +-if (defined(ohos_lite)) { +- import("//build/lite/config/component/lite_component.gni") +-} else { +- import("//build/ohos.gni") +- import("//third_party/libunwind/libunwind.gni") +-} +- ++import("//build/ohos.gni") + common_source = [ + "src/dwarf/Gexpr.c", + "src/dwarf/Gfde.c", +@@ -85,111 +79,116 @@ common_source = [ + + # as libc++ is static linked with libunwind.a + # we remove the Gstep.c for duplicated symbol violation +-arm_source = [ +- "src/arm/Gapply_reg_state.c", +- "src/arm/Gcreate_addr_space.c", +- "src/arm/Gex_tables.c", +- "src/arm/Gget_proc_info.c", +- "src/arm/Gget_save_loc.c", +- "src/arm/Gglobal.c", +- "src/arm/Ginit.c", +- "src/arm/Ginit_local.c", +- "src/arm/Ginit_remote.c", +- "src/arm/Gos-linux.c", +- "src/arm/Greg_states_iterate.c", +- "src/arm/Gregs.c", +- "src/arm/Gresume.c", +- "src/arm/Gstash_frame.c", +- "src/arm/Gstep.c", +- "src/arm/Gtrace.c", +- "src/arm/Lcreate_addr_space.c", +- "src/arm/Lex_tables.c", +- "src/arm/Lget_proc_info.c", +- "src/arm/Lget_save_loc.c", +- "src/arm/Lglobal.c", +- "src/arm/Linit.c", +- "src/arm/Linit_local.c", +- "src/arm/Linit_remote.c", +- "src/arm/Los-linux.c", +- "src/arm/Lregs.c", +- "src/arm/Lresume.c", +- "src/arm/Lstash_frame.c", +- "src/arm/Lstep.c", +- "src/arm/Ltrace.c", +- "src/arm/getcontext.S", +- "src/arm/is_fpreg.c", +- "src/arm/regname.c", +- "src/arm/siglongjmp.S", +- "src/elf32.c", +-] +- +-arm64_source = [ +- "src/aarch64/Gcreate_addr_space.c", +- "src/aarch64/Gget_proc_info.c", +- "src/aarch64/Gget_save_loc.c", +- "src/aarch64/Gglobal.c", +- "src/aarch64/Ginit.c", +- "src/aarch64/Ginit_local.c", +- "src/aarch64/Ginit_remote.c", +- "src/aarch64/Gis_signal_frame.c", +- "src/aarch64/Gregs.c", +- "src/aarch64/Gresume.c", +- "src/aarch64/Gstash_frame.c", +- "src/aarch64/Gstep.c", +- "src/aarch64/Gtrace.c", +- "src/aarch64/Lcreate_addr_space.c", +- "src/aarch64/Lget_proc_info.c", +- "src/aarch64/Lget_save_loc.c", +- "src/aarch64/Lglobal.c", +- "src/aarch64/Linit.c", +- "src/aarch64/Linit_local.c", +- "src/aarch64/Linit_remote.c", +- "src/aarch64/Lis_signal_frame.c", +- "src/aarch64/Lregs.c", +- "src/aarch64/Lresume.c", +- "src/aarch64/Lstash_frame.c", +- "src/aarch64/Lstep.c", +- "src/aarch64/Ltrace.c", +- "src/aarch64/getcontext.S", +- "src/aarch64/is_fpreg.c", +- "src/aarch64/regname.c", +- "src/elf64.c", +-] +- +-x64_source = [ +- "src/elf64.c", +- "src/x86_64/Gcreate_addr_space.c", +- "src/x86_64/Gget_proc_info.c", +- "src/x86_64/Gget_save_loc.c", +- "src/x86_64/Gglobal.c", +- "src/x86_64/Ginit.c", +- "src/x86_64/Ginit_local.c", +- "src/x86_64/Ginit_remote.c", +- "src/x86_64/Gos-linux.c", +- "src/x86_64/Gregs.c", +- "src/x86_64/Gresume.c", +- "src/x86_64/Gstash_frame.c", +- "src/x86_64/Gstep.c", +- "src/x86_64/Gtrace.c", +- "src/x86_64/Lcreate_addr_space.c", +- "src/x86_64/Lget_proc_info.c", +- "src/x86_64/Lget_save_loc.c", +- "src/x86_64/Lglobal.c", +- "src/x86_64/Linit.c", +- "src/x86_64/Linit_local.c", +- "src/x86_64/Linit_remote.c", +- "src/x86_64/Los-linux.c", +- "src/x86_64/Lregs.c", +- "src/x86_64/Lresume.c", +- "src/x86_64/Lstash_frame.c", +- "src/x86_64/Lstep.c", +- "src/x86_64/Ltrace.c", +- "src/x86_64/getcontext.S", +- "src/x86_64/is_fpreg.c", +- "src/x86_64/regname.c", +- "src/x86_64/setcontext.S", +-] ++if (target_cpu == "arm") { ++ arm_source = [ ++ "src/arm/Gapply_reg_state.c", ++ "src/arm/Gcreate_addr_space.c", ++ "src/arm/Gex_tables.c", ++ "src/arm/Gget_proc_info.c", ++ "src/arm/Gget_save_loc.c", ++ "src/arm/Gglobal.c", ++ "src/arm/Ginit.c", ++ "src/arm/Ginit_local.c", ++ "src/arm/Ginit_remote.c", ++ "src/arm/Gos-linux.c", ++ "src/arm/Greg_states_iterate.c", ++ "src/arm/Gregs.c", ++ "src/arm/Gresume.c", ++ "src/arm/Gstash_frame.c", ++ "src/arm/Gstep.c", ++ "src/arm/Gtrace.c", ++ "src/arm/Lcreate_addr_space.c", ++ "src/arm/Lex_tables.c", ++ "src/arm/Lget_proc_info.c", ++ "src/arm/Lget_save_loc.c", ++ "src/arm/Lglobal.c", ++ "src/arm/Linit.c", ++ "src/arm/Linit_local.c", ++ "src/arm/Linit_remote.c", ++ "src/arm/Los-linux.c", ++ "src/arm/Lregs.c", ++ "src/arm/Lresume.c", ++ "src/arm/Lstash_frame.c", ++ "src/arm/Lstep.c", ++ "src/arm/Ltrace.c", ++ "src/arm/gen-offsets.c", ++ "src/arm/getcontext.S", ++ "src/arm/is_fpreg.c", ++ "src/arm/regname.c", ++ "src/arm/siglongjmp.S", ++ "src/elf32.c", ++ ] ++} ++if (target_cpu == "arm64") { ++ arm64_source = [ ++ "src/aarch64/Gcreate_addr_space.c", ++ "src/aarch64/Gget_proc_info.c", ++ "src/aarch64/Gget_save_loc.c", ++ "src/aarch64/Gglobal.c", ++ "src/aarch64/Ginit.c", ++ "src/aarch64/Ginit_local.c", ++ "src/aarch64/Ginit_remote.c", ++ "src/aarch64/Gis_signal_frame.c", ++ "src/aarch64/Gregs.c", ++ "src/aarch64/Gresume.c", ++ "src/aarch64/Gstash_frame.c", ++ "src/aarch64/Gstep.c", ++ "src/aarch64/Gtrace.c", ++ "src/aarch64/Lcreate_addr_space.c", ++ "src/aarch64/Lget_proc_info.c", ++ "src/aarch64/Lget_save_loc.c", ++ "src/aarch64/Lglobal.c", ++ "src/aarch64/Linit.c", ++ "src/aarch64/Linit_local.c", ++ "src/aarch64/Linit_remote.c", ++ "src/aarch64/Lis_signal_frame.c", ++ "src/aarch64/Lregs.c", ++ "src/aarch64/Lresume.c", ++ "src/aarch64/Lstash_frame.c", ++ "src/aarch64/Lstep.c", ++ "src/aarch64/Ltrace.c", ++ "src/aarch64/getcontext.S", ++ "src/aarch64/is_fpreg.c", ++ "src/aarch64/regname.c", ++ "src/elf64.c", ++ ] ++} + ++if (target_cpu == "x64") { ++ x64_source = [ ++ "src/elf64.c", ++ "src/x86_64/Gcreate_addr_space.c", ++ "src/x86_64/Gget_proc_info.c", ++ "src/x86_64/Gget_save_loc.c", ++ "src/x86_64/Gglobal.c", ++ "src/x86_64/Ginit.c", ++ "src/x86_64/Ginit_local.c", ++ "src/x86_64/Ginit_remote.c", ++ "src/x86_64/Gos-linux.c", ++ "src/x86_64/Gregs.c", ++ "src/x86_64/Gresume.c", ++ "src/x86_64/Gstash_frame.c", ++ "src/x86_64/Gstep.c", ++ "src/x86_64/Gtrace.c", ++ "src/x86_64/Lcreate_addr_space.c", ++ "src/x86_64/Lget_proc_info.c", ++ "src/x86_64/Lget_save_loc.c", ++ "src/x86_64/Lglobal.c", ++ "src/x86_64/Linit.c", ++ "src/x86_64/Linit_local.c", ++ "src/x86_64/Linit_remote.c", ++ "src/x86_64/Los-linux.c", ++ "src/x86_64/Lregs.c", ++ "src/x86_64/Lresume.c", ++ "src/x86_64/Lstash_frame.c", ++ "src/x86_64/Lstep.c", ++ "src/x86_64/Ltrace.c", ++ "src/x86_64/getcontext.S", ++ "src/x86_64/is_fpreg.c", ++ "src/x86_64/regname.c", ++ "src/x86_64/setcontext.S", ++ ] ++} + remove_sources = [] + + ptrace_sources = [ +@@ -255,7 +254,8 @@ config("unwind_config_public") { + cflags = [ + "-D_GNU_SOURCE", + "-DHAVE_CONFIG_H", +- "-DNDEBUG", ++ ++ # "-DNDEBUG", + "-DCC_IS_CLANG", + "-fcommon", + "-Werror", +@@ -263,9 +263,32 @@ config("unwind_config_public") { + "-Wno-header-guard", + "-Wno-unused-parameter", + "-Wno-unused-variable", +- "-Wno-int-to-pointer-cast", +- "-Wno-pointer-to-int-cast", ++ "-Wno-unused-result", ++ "-Wno-tautological-constant-out-of-range-compare", + ] ++ if (use_wasm) { ++ cflags += [ "-Wno-incompatible-pointer-types" ] ++ } ++ if (is_mingw) { ++ cflags += [ ++ "-Wno-attributes", ++ "-Wno-pointer-to-int-cast", ++ "-Wno-implicit-function-declaration", ++ ++ # "-Wno-absolute-value", ++ # "-Wno-header-guard", ++ # "-Wno-tautological-constant-out-of-range-compare", ++ # "-Wno-sometimes-uninitialized", ++ # "-Wno-int-to-void-pointer-cast", ++ ] ++ } ++ ++ if (use_wasm) { ++ cflags += [ ++ # "-D __mips__" ++ # "-D WASM", ++ ] ++ } + + if (defined(ohos_lite)) { + cflags += [ "-fPIC" ] +@@ -282,18 +305,14 @@ config("unwind_config_public") { + } else if (target_cpu == "arm64") { + include_dirs += [ "include/tdep-aarch64" ] + cflags += [ "-Wno-incompatible-pointer-types" ] +- } else if (target_cpu == "x64" || target_cpu == "x86_64") { ++ } else if (target_cpu == "x64") { + include_dirs += [ "include/tdep-x86_64" ] +- } else if (target_cpu == "mipsel") { +- include_dirs += [ "include/tdep-mips" ] + } + } +- + config("unwind_config_remote") { + cflags = + [ "-Wno-format" ] # some debug feature will warning in host x64 build + } +- + config("unwind_config_remote_public") { + cflags = [] + include_dirs = [] +@@ -320,9 +339,10 @@ config("unwind_config_remote_public") { + + defines += [ "build_remote=1" ] + defines += [ "target_cpu=${target_cpu}" ] +- defines += [ "host_toolchain=${host_toolchain}" ] +- defines += [ "current_toolchain=${current_toolchain}" ] +- defines += [ "default_toolchain=${default_toolchain}" ] ++ ++ # defines += [ "host_toolchain=${host_toolchain}" ] ++ # defines += [ "current_toolchain=${current_toolchain}" ] ++ # defines += [ "default_toolchain=${default_toolchain}" ] + } + + config("unwind_config_arm") { +@@ -337,14 +357,8 @@ config("unwind_config_x64") { + defines = [ "UNW_TARGET_X86_64" ] + defines += [ "UNW_TARGET_X86_64_LINUX" ] + } +- +-config("unwind_config_x86_64") { +- defines = [ "UNW_TARGET_X86_64" ] +- defines += [ "UNW_TARGET_X86_64_LINUX" ] +-} +- +-if (defined(ohos_lite)) { +- source_set("unwind_source_arm") { ++if (target_cpu == "arm") { ++ ohos_source_set("unwind_source_arm") { + configs += [ ":unwind_config_remote" ] + public_configs = [ + ":unwind_config_public", +@@ -353,6 +367,10 @@ if (defined(ohos_lite)) { + ] + sources = common_source + ++ # there is a main function in this file ++ # for a lib we dont need this ++ arm_source -= [ "src/arm/gen-offsets.c" ] ++ + # no jump lib + arm_source -= [ + "src/arm/getcontext.S", +@@ -361,8 +379,9 @@ if (defined(ohos_lite)) { + sources += arm_source + sources -= remove_sources + } +- +- source_set("unwind_source_arm64") { ++} ++if (target_cpu == "arm64") { ++ ohos_source_set("unwind_source_arm64") { + configs += [ ":unwind_config_remote" ] + public_configs = [ + ":unwind_config_public", +@@ -376,8 +395,9 @@ if (defined(ohos_lite)) { + sources += arm64_source + sources -= remove_sources + } +- +- source_set("unwind_source_x64") { ++} ++if (target_cpu == "x86") { ++ ohos_source_set("unwind_source_x64") { + configs += [ ":unwind_config_remote" ] + public_configs = [ + ":unwind_config_public", +@@ -394,460 +414,51 @@ if (defined(ohos_lite)) { + sources += x64_source + sources -= remove_sources + } +- +- source_set("unwind_source") { +- configs += [ ":unwind_config_public" ] +- sources = common_source +- +- if (target_cpu == "arm") { +- # no jump lib +- arm_source -= [ +- "src/arm/getcontext.S", +- "src/arm/siglongjmp.S", +- ] +- +- # as libc++ is static linked with libunwind.a +- # we remove the Gstep.c for duplicated symbol violation +- sources += arm_source +- public_configs = [ ":unwind_config_arm" ] +- } else if (target_cpu == "arm64") { +- sources += arm64_source +- public_configs = [ ":unwind_config_arm64" ] +- } else if (target_cpu == "x64") { +- sources += x64_source +- public_configs = [ ":unwind_config_x64" ] +- } else if (target_cpu == "x86_64") { +- sources += x64_source +- public_configs = [ ":unwind_config_x86_64" ] +- } +- +- sources += [ "src/os-ohos.c" ] +- } +- +- shared_library("libunwind") { +- deps = [ ":unwind_source" ] +- public_configs = [ ":unwind_config_public" ] +- } +-} else { +- ohos_source_set("unwind_source_arm") { +- configs = [ ":unwind_config_remote" ] +- public_configs = [ +- ":unwind_config_public", +- ":unwind_config_remote_public", +- ":unwind_config_arm", +- ] +- sources = common_source +- +- # no jump lib +- arm_source -= [ +- "src/arm/getcontext.S", +- "src/arm/siglongjmp.S", +- ] ++} ++ohos_source_set("unwind_source") { ++ configs += [ ":unwind_config_public" ] ++ sources = common_source ++ if (target_cpu == "arm") { ++ # as libc++ is static linked with libunwind.a ++ # we remove the Gstep.c for duplicated symbol violation + sources += arm_source +- sources -= remove_sources +- } +- +- ohos_source_set("unwind_source_arm64") { +- configs = [ ":unwind_config_remote" ] +- public_configs = [ +- ":unwind_config_public", +- ":unwind_config_remote_public", +- ":unwind_config_arm64", +- ] +- sources = common_source +- +- arm64_source -= [ "src/aarch64/getcontext.S" ] +- ++ public_configs = [ ":unwind_config_arm" ] ++ } else if (target_cpu == "arm64") { + sources += arm64_source +- sources -= remove_sources +- } +- +- ohos_source_set("unwind_source_x64") { +- configs = [ ":unwind_config_remote" ] +- public_configs = [ +- ":unwind_config_public", +- ":unwind_config_remote_public", +- ":unwind_config_x64", +- ] +- sources = common_source +- +- # no jump lib +- x64_source -= [ +- "src/x86_64/getcontext.S", +- "src/x86_64/setcontext.S", +- ] ++ public_configs = [ ":unwind_config_arm64" ] ++ } else if (target_cpu == "x64") { ++ # deps = [ "unwind_source_x64" ] + sources += x64_source +- sources -= remove_sources +- } +- +- ohos_source_set("unwind_source_x86_64") { +- configs = [ ":unwind_config_remote" ] +- public_configs = [ +- ":unwind_config_public", +- ":unwind_config_remote_public", +- ":unwind_config_x86_64", +- ] +- sources = common_source ++ public_configs = [ ":unwind_config_x64" ] + +- # no jump lib +- x64_source -= [ +- "src/x86_64/getcontext.S", +- "src/x86_64/setcontext.S", +- ] +- sources += x64_source +- sources -= remove_sources ++ # public_configs = [ ++ # ":unwind_config_public", ++ # ":unwind_config_remote_public", ++ # ":unwind_config_x64", ++ # ] + } + +- ohos_source_set("unwind_source") { +- configs = [ ":unwind_config_public" ] +- sources = common_source +- +- if (target_cpu == "arm") { +- # as libc++ is static linked with libunwind.a +- # we remove the Gstep.c for duplicated symbol violation +- sources += arm_source +- public_configs = [ ":unwind_config_arm" ] +- } else if (target_cpu == "arm64") { +- sources += arm64_source +- public_configs = [ ":unwind_config_arm64" ] +- } else if (target_cpu == "x64") { +- sources += x64_source +- public_configs = [ ":unwind_config_x64" ] +- } else if (target_cpu == "x86_64") { +- sources += x64_source +- public_configs = [ ":unwind_config_x86_64" ] +- } +- +- sources += [ "src/os-ohos.c" ] +- cflags = [ +- "-DHAS_ARK_FRAME", +- "-DPARSE_BUILD_ID", +- "-DIS_VALIDATE_MEM", +- ] +- } ++ sources += [ "src/os-ohos.c" ] ++} + +- ohos_shared_library("libunwind") { ++if (defined(ohos_lite)) { ++ # shared_library("libunwind") { ++ source_set("libunwind") { + deps = [ ":unwind_source" ] +- install_images = [ +- "system", +- "updater", +- ] + public_configs = [ ":unwind_config_public" ] +- part_name = "faultloggerd" +- subsystem_name = "hiviewdfx" +- } +- +- config("unwind_config_local_only") { +- defines = [ "UNW_LOCAL_ONLY" ] + } ++} else { ++ # ohos_shared_library("libunwind") { ++ source_set("libunwind") { ++ deps = [ ":unwind_source" ] + +- ohos_static_library("libunwind_local") { +- sources = common_source ++ # install_images = [ ++ # "system", ++ # "updater", ++ # ] + public_configs = [ ":unwind_config_public" ] +- public_configs += [ ":unwind_config_local_only" ] +- +- if (target_cpu == "arm") { +- sources += arm_source +- sources -= arm_source_local +- public_configs += [ ":unwind_config_arm" ] +- } else if (target_cpu == "arm64") { +- sources += arm64_source +- sources -= arm64_source_local +- public_configs += [ ":unwind_config_arm64" ] +- } else if (target_cpu == "x64") { +- sources += x64_source +- sources -= x64_source_local +- public_configs += [ ":unwind_config_x64" ] +- } else if (target_cpu == "x86_64") { +- sources += x64_source +- sources -= x64_source_local +- public_configs += [ ":unwind_config_x86_64" ] +- } +- +- sources += [ "src/os-ohos.c" ] +- sources -= libunwind_dwarf_local_la_SOURCES +- sources -= libunwind_la_SOURCES_local +- sources -= ptrace_sources +- +- cflags = [ +- "-DHAS_ARK_FRAME", +- "-DPARSE_BUILD_ID", +- "-DIS_VALIDATE_MEM", +- "-DUNW_LOCAL_ONLY", +- "-DNO_RESERVE_CACHE", +- ] +- +- part_name = "faultloggerd" +- subsystem_name = "hiviewdfx" +- } +-} + +-if (!defined(ohos_lite)) { +- import("//build/test.gni") +- module_output_path = "hiviewdfx/faultloggerd" +- group("unittest") { +- testonly = true +- deps = [ +- ":Gtest_bt", +- ":Gtest_dyn1", +- ":Gtest_init", +- ":Gtest_trace", +- ":Ltest_bt", +- ":Ltest_cxx_exceptions", +- ":Ltest_dyn1", +- ":Ltest_init", +- ":Ltest_init_local_signal", +- ":Ltest_mem_validate", +- ":Ltest_nocalloc", +- ":Ltest_nomalloc", +- ":Ltest_trace", +- ":test_ptrace_misc", +- ":test_static_link", +- ] +- } +- config("unwind_test") { +- cflags = [ "-O0" ] +- } +- +- ohos_unittest("Gtest_init") { +- module_out_path = module_output_path +- sources = [ "tests/Gtest-init.cxx" ] +- include_dirs = [ +- "tests", +- "include", +- ] +- +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_init") { +- module_out_path = module_output_path +- sources = [ "tests/Ltest-init.cxx" ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_cxx_exceptions") { +- module_out_path = module_output_path +- sources = [ "tests/Ltest-cxx-exceptions.cxx" ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- cflags = [ "-fexceptions" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- remove_configs = [ "//build/config/compiler:no_exceptions" ] +- } +- +- ohos_unittest("Ltest_init_local_signal") { +- module_out_path = module_output_path +- sources = [ +- "tests/Ltest-init-local-signal-lib.c", +- "tests/Ltest-init-local-signal.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Gtest_dyn1") { +- module_out_path = module_output_path +- sources = [ +- "tests/Gtest-dyn1.c", +- "tests/flush-cache.h", +- ] +- if (target_cpu == "arm") { +- sources += [ "tests/flush-cache.S" ] +- } +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- cflags = [ "-DHAVE__BUILTIN___CLEAR_CACHE" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_dyn1") { +- module_out_path = module_output_path +- sources = [ +- "tests/Ltest-dyn1.c", +- "tests/flush-cache.h", +- ] +- if (target_cpu == "arm") { +- sources += [ "tests/flush-cache.S" ] +- } +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- cflags = [ "-DHAVE__BUILTIN___CLEAR_CACHE" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("test_static_link") { +- module_out_path = module_output_path +- sources = [ +- "tests/test-static-link-gen.c", +- "tests/test-static-link-loc.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Gtest_bt") { +- module_out_path = module_output_path +- sources = [ +- "tests/Gtest-bt.c", +- "tests/dummy_backtrace.c", +- "tests/ident.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_bt") { +- module_out_path = module_output_path +- sources = [ +- "tests/Ltest-bt.c", +- "tests/dummy_backtrace.c", +- "tests/ident.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("test_ptrace_misc") { +- module_out_path = module_output_path +- sources = [ +- "tests/ident.c", +- "tests/test-ptrace-misc.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_nomalloc") { +- module_out_path = module_output_path +- sources = [ "tests/Ltest-nomalloc.c" ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_nocalloc") { +- module_out_path = module_output_path +- sources = [ "tests/Ltest-nocalloc.c" ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Gtest_trace") { +- module_out_path = module_output_path +- sources = [ +- "tests/Gtest-trace.c", +- "tests/dummy_backtrace.c", +- "tests/ident.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_trace") { +- module_out_path = module_output_path +- sources = [ +- "tests/Ltest-trace.c", +- "tests/dummy_backtrace.c", +- "tests/ident.c", +- ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +- +- ohos_unittest("Ltest_mem_validate") { +- module_out_path = module_output_path +- sources = [ "tests/Ltest-mem-validate.c" ] +- include_dirs = [ +- "tests", +- "include", +- ] +- configs = [ ":unwind_test" ] +- deps = [ ":libunwind" ] +- subsystem_name = "hiviewdfx" +- part_name = "faultloggerd" +- } +-} else { +- group("unittest") { +- testonly = true +- deps = [] ++ # part_name = "faultloggerd" ++ # subsystem_name = "hiviewdfx" + } + } diff --git a/trace_streamer/prebuilts/patch_perf_event/perf_event.h.patch b/trace_streamer/prebuilts/patch_perf_event/perf_event.h.patch new file mode 100644 index 0000000000000000000000000000000000000000..657adda6d8d71c3dc9395fcc78e0e6012d2779ff --- /dev/null +++ b/trace_streamer/prebuilts/patch_perf_event/perf_event.h.patch @@ -0,0 +1,611 @@ +--- prebuilts/other/perf_event.h 2023-01-16 15:50:19.155934716 +0800 ++++ third_party/perf_include/linux/perf_event.h 2023-01-16 15:52:07.091731926 +0800 +@@ -1,4 +1,3 @@ +-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + /* + * Performance events: + * +@@ -12,12 +11,9 @@ + * + * For licencing details see kernel-base/COPYING + */ +-#ifndef _UAPI_LINUX_PERF_EVENT_H +-#define _UAPI_LINUX_PERF_EVENT_H +- +-#include +-#include +-#include ++#ifndef _TS_PERF_EVENT_H ++#define _TS_PERF_EVENT_H ++#include "types.h" + + /* + * User-space ABI bits: +@@ -38,21 +34,6 @@ enum perf_type_id { + }; + + /* +- * attr.config layout for type PERF_TYPE_HARDWARE and PERF_TYPE_HW_CACHE +- * PERF_TYPE_HARDWARE: 0xEEEEEEEE000000AA +- * AA: hardware event ID +- * EEEEEEEE: PMU type ID +- * PERF_TYPE_HW_CACHE: 0xEEEEEEEE00DDCCBB +- * BB: hardware cache ID +- * CC: hardware cache op ID +- * DD: hardware cache op result ID +- * EEEEEEEE: PMU type ID +- * If the PMU type ID is 0, the PERF_TYPE_RAW will be applied. +- */ +-#define PERF_PMU_TYPE_SHIFT 32 +-#define PERF_HW_EVENT_MASK 0xffffffff +- +-/* + * Generalized performance event event_id types, used by the + * attr.event_id parameter of the sys_perf_event_open() + * syscall: +@@ -127,7 +108,6 @@ enum perf_sw_ids { + PERF_COUNT_SW_EMULATION_FAULTS = 8, + PERF_COUNT_SW_DUMMY = 9, + PERF_COUNT_SW_BPF_OUTPUT = 10, +- PERF_COUNT_SW_CGROUP_SWITCHES = 11, + + PERF_COUNT_SW_MAX, /* non-ABI */ + }; +@@ -157,18 +137,10 @@ enum perf_event_sample_format { + PERF_SAMPLE_TRANSACTION = 1U << 17, + PERF_SAMPLE_REGS_INTR = 1U << 18, + PERF_SAMPLE_PHYS_ADDR = 1U << 19, +- PERF_SAMPLE_AUX = 1U << 20, +- PERF_SAMPLE_CGROUP = 1U << 21, +- PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22, +- PERF_SAMPLE_CODE_PAGE_SIZE = 1U << 23, +- PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24, + +- PERF_SAMPLE_MAX = 1U << 25, /* non-ABI */ +- +- __PERF_SAMPLE_CALLCHAIN_EARLY = 1ULL << 63, /* non-ABI; internal use */ ++ PERF_SAMPLE_MAX = 1U << 20, /* non-ABI */ + }; + +-#define PERF_SAMPLE_WEIGHT_TYPE (PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT) + /* + * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set + * +@@ -202,8 +174,6 @@ enum perf_branch_sample_type_shift { + + PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT = 16, /* save branch type */ + +- PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT = 17, /* save low level index of raw branch records */ +- + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ + }; + +@@ -231,8 +201,6 @@ enum perf_branch_sample_type { + PERF_SAMPLE_BRANCH_TYPE_SAVE = + 1U << PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT, + +- PERF_SAMPLE_BRANCH_HW_INDEX = 1U << PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT, +- + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, + }; + +@@ -326,8 +294,6 @@ enum perf_event_read_format { + /* add: sample_stack_user */ + #define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ + #define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */ +-#define PERF_ATTR_SIZE_VER6 120 /* add: aux_sample_size */ +-#define PERF_ATTR_SIZE_VER7 128 /* add: sig_data */ + + /* + * Hardware event_id to monitor via a performance monitoring event: +@@ -400,16 +366,7 @@ struct perf_event_attr { + context_switch : 1, /* context switch data */ + write_backward : 1, /* Write ring buffer from end to beginning */ + namespaces : 1, /* include namespaces data */ +- ksymbol : 1, /* include ksymbol events */ +- bpf_event : 1, /* include bpf events */ +- aux_output : 1, /* generate AUX records instead of events */ +- cgroup : 1, /* include cgroup events */ +- text_poke : 1, /* include text poke events */ +- build_id : 1, /* use build id in mmap2 events */ +- inherit_thread : 1, /* children only inherit if cloned with CLONE_THREAD */ +- remove_on_exec : 1, /* event is removed from task on exec */ +- sigtrap : 1, /* send synchronous SIGTRAP on event */ +- __reserved_1 : 26; ++ __reserved_1 : 35; + + union { + __u32 wakeup_events; /* wakeup every n events */ +@@ -419,14 +376,10 @@ struct perf_event_attr { + __u32 bp_type; + union { + __u64 bp_addr; +- __u64 kprobe_func; /* for perf_kprobe */ +- __u64 uprobe_path; /* for perf_uprobe */ + __u64 config1; /* extension of config */ + }; + union { + __u64 bp_len; +- __u64 kprobe_addr; /* when kprobe_func == NULL */ +- __u64 probe_offset; /* for perf_[k,u]probe */ + __u64 config2; /* extension of config1 */ + }; + __u64 branch_sample_type; /* enum perf_branch_sample_type */ +@@ -458,53 +411,24 @@ struct perf_event_attr { + */ + __u32 aux_watermark; + __u16 sample_max_stack; +- __u16 __reserved_2; +- __u32 aux_sample_size; +- __u32 __reserved_3; +- +- /* +- * User provided data if sigtrap=1, passed back to user via +- * siginfo_t::si_perf_data, e.g. to permit user to identify the event. +- */ +- __u64 sig_data; ++ __u16 __reserved_2; /* align to __u64 */ + }; + +-/* +- * Structure used by below PERF_EVENT_IOC_QUERY_BPF command +- * to query bpf programs attached to the same perf tracepoint +- * as the given perf event. +- */ +-struct perf_event_query_bpf { +- /* +- * The below ids array length +- */ +- __u32 ids_len; +- /* +- * Set by the kernel to indicate the number of +- * available programs +- */ +- __u32 prog_cnt; +- /* +- * User provided buffer to store program ids +- */ +- __u32 ids[0]; +-}; ++#define perf_flags(attr) (*(&(attr)->read_format + 1)) + + /* + * Ioctls that can be done on a perf event fd: + */ +-#define PERF_EVENT_IOC_ENABLE _IO ('$', 0) +-#define PERF_EVENT_IOC_DISABLE _IO ('$', 1) +-#define PERF_EVENT_IOC_REFRESH _IO ('$', 2) +-#define PERF_EVENT_IOC_RESET _IO ('$', 3) +-#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64) +-#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) +-#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) +-#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) +-#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) +-#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) +-#define PERF_EVENT_IOC_QUERY_BPF _IOWR('$', 10, struct perf_event_query_bpf *) +-#define PERF_EVENT_IOC_MODIFY_ATTRIBUTES _IOW('$', 11, struct perf_event_attr *) ++#define PERF_EVENT_IOC_ENABLE _IO ('$', 0) ++#define PERF_EVENT_IOC_DISABLE _IO ('$', 1) ++#define PERF_EVENT_IOC_REFRESH _IO ('$', 2) ++#define PERF_EVENT_IOC_RESET _IO ('$', 3) ++#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64) ++#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) ++#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) ++#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) ++#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) ++#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) + + enum perf_event_ioc_flags { + PERF_IOC_FLAG_GROUP = 1U << 0, +@@ -564,10 +488,9 @@ struct perf_event_mmap_page { + cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */ + + cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */ +- cap_user_time : 1, /* The time_{shift,mult,offset} fields are used */ ++ cap_user_time : 1, /* The time_* fields are used */ + cap_user_time_zero : 1, /* The time_zero field is used */ +- cap_user_time_short : 1, /* the time_{cycle,mask} fields are used */ +- cap_____res : 58; ++ cap_____res : 59; + }; + }; + +@@ -626,29 +549,13 @@ struct perf_event_mmap_page { + * ((rem * time_mult) >> time_shift); + */ + __u64 time_zero; +- + __u32 size; /* Header size up to __reserved[] fields. */ +- __u32 __reserved_1; +- +- /* +- * If cap_usr_time_short, the hardware clock is less than 64bit wide +- * and we must compute the 'cyc' value, as used by cap_usr_time, as: +- * +- * cyc = time_cycles + ((cyc - time_cycles) & time_mask) +- * +- * NOTE: this form is explicitly chosen such that cap_usr_time_short +- * is a correction on top of cap_usr_time, and code that doesn't +- * know about cap_usr_time_short still works under the assumption +- * the counter doesn't wrap. +- */ +- __u64 time_cycles; +- __u64 time_mask; + + /* + * Hole for extension of the self monitor capabilities + */ + +- __u8 __reserved[116*8]; /* align to 1k. */ ++ __u8 __reserved[118*8+4]; /* align to 1k. */ + + /* + * Control data for the mmap() data buffer. +@@ -688,22 +595,6 @@ struct perf_event_mmap_page { + __u64 aux_size; + }; + +-/* +- * The current state of perf_event_header::misc bits usage: +- * ('|' used bit, '-' unused bit) +- * +- * 012 CDEF +- * |||---------|||| +- * +- * Where: +- * 0-2 CPUMODE_MASK +- * +- * C PROC_MAP_PARSE_TIMEOUT +- * D MMAP_DATA / COMM_EXEC / FORK_EXEC / SWITCH_OUT +- * E MMAP_BUILD_ID / EXACT_IP / SCHED_OUT_PREEMPT +- * F (reserved) +- */ +- + #define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0) + #define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) + #define PERF_RECORD_MISC_KERNEL (1 << 0) +@@ -717,41 +608,19 @@ struct perf_event_mmap_page { + */ + #define PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT (1 << 12) + /* +- * Following PERF_RECORD_MISC_* are used on different +- * events, so can reuse the same bit position: +- * +- * PERF_RECORD_MISC_MMAP_DATA - PERF_RECORD_MMAP* events +- * PERF_RECORD_MISC_COMM_EXEC - PERF_RECORD_COMM event +- * PERF_RECORD_MISC_FORK_EXEC - PERF_RECORD_FORK event (perf internal) +- * PERF_RECORD_MISC_SWITCH_OUT - PERF_RECORD_SWITCH* events ++ * PERF_RECORD_MISC_MMAP_DATA and PERF_RECORD_MISC_COMM_EXEC are used on ++ * different events so can reuse the same bit position. ++ * Ditto PERF_RECORD_MISC_SWITCH_OUT. + */ + #define PERF_RECORD_MISC_MMAP_DATA (1 << 13) + #define PERF_RECORD_MISC_COMM_EXEC (1 << 13) +-#define PERF_RECORD_MISC_FORK_EXEC (1 << 13) + #define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) + /* +- * These PERF_RECORD_MISC_* flags below are safely reused +- * for the following events: +- * +- * PERF_RECORD_MISC_EXACT_IP - PERF_RECORD_SAMPLE of precise events +- * PERF_RECORD_MISC_SWITCH_OUT_PREEMPT - PERF_RECORD_SWITCH* events +- * PERF_RECORD_MISC_MMAP_BUILD_ID - PERF_RECORD_MMAP2 event +- * +- * +- * PERF_RECORD_MISC_EXACT_IP: +- * Indicates that the content of PERF_SAMPLE_IP points to +- * the actual instruction that triggered the event. See also +- * perf_event_attr::precise_ip. +- * +- * PERF_RECORD_MISC_SWITCH_OUT_PREEMPT: +- * Indicates that thread was preempted in TASK_RUNNING state. +- * +- * PERF_RECORD_MISC_MMAP_BUILD_ID: +- * Indicates that mmap2 event carries build id data. ++ * Indicates that the content of PERF_SAMPLE_IP points to ++ * the actual instruction that triggered the event. See also ++ * perf_event_attr::precise_ip. + */ + #define PERF_RECORD_MISC_EXACT_IP (1 << 14) +-#define PERF_RECORD_MISC_SWITCH_OUT_PREEMPT (1 << 14) +-#define PERF_RECORD_MISC_MMAP_BUILD_ID (1 << 14) + /* + * Reserve the last bit to indicate some extended misc field + */ +@@ -929,9 +798,7 @@ enum perf_event_type { + * char data[size];}&& PERF_SAMPLE_RAW + * + * { u64 nr; +- * { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX +- * { u64 from, to, flags } lbr[nr]; +- * } && PERF_SAMPLE_BRANCH_STACK ++ * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK + * + * { u64 abi; # enum perf_sample_regs_abi + * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER +@@ -940,33 +807,12 @@ enum perf_event_type { + * char data[size]; + * u64 dyn_size; } && PERF_SAMPLE_STACK_USER + * +- * { union perf_sample_weight +- * { +- * u64 full; && PERF_SAMPLE_WEIGHT +- * #if defined(__LITTLE_ENDIAN_BITFIELD) +- * struct { +- * u32 var1_dw; +- * u16 var2_w; +- * u16 var3_w; +- * } && PERF_SAMPLE_WEIGHT_STRUCT +- * #elif defined(__BIG_ENDIAN_BITFIELD) +- * struct { +- * u16 var3_w; +- * u16 var2_w; +- * u32 var1_dw; +- * } && PERF_SAMPLE_WEIGHT_STRUCT +- * #endif +- * } +- * } ++ * { u64 weight; } && PERF_SAMPLE_WEIGHT + * { u64 data_src; } && PERF_SAMPLE_DATA_SRC + * { u64 transaction; } && PERF_SAMPLE_TRANSACTION + * { u64 abi; # enum perf_sample_regs_abi + * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR + * { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR +- * { u64 size; +- * char data[size]; } && PERF_SAMPLE_AUX +- * { u64 data_page_size;} && PERF_SAMPLE_DATA_PAGE_SIZE +- * { u64 code_page_size;} && PERF_SAMPLE_CODE_PAGE_SIZE + * }; + */ + PERF_RECORD_SAMPLE = 9, +@@ -982,20 +828,10 @@ enum perf_event_type { + * u64 addr; + * u64 len; + * u64 pgoff; +- * union { +- * struct { +- * u32 maj; +- * u32 min; +- * u64 ino; +- * u64 ino_generation; +- * }; +- * struct { +- * u8 build_id_size; +- * u8 __reserved_1; +- * u16 __reserved_2; +- * u8 build_id[20]; +- * }; +- * }; ++ * u32 maj; ++ * u32 min; ++ * u64 ino; ++ * u64 ino_generation; + * u32 prot, flags; + * char filename[]; + * struct sample_id sample_id; +@@ -1024,7 +860,6 @@ enum perf_event_type { + * struct perf_event_header header; + * u32 pid; + * u32 tid; +- * struct sample_id sample_id; + * }; + */ + PERF_RECORD_ITRACE_START = 12, +@@ -1079,106 +914,9 @@ enum perf_event_type { + */ + PERF_RECORD_NAMESPACES = 16, + +- /* +- * Record ksymbol register/unregister events: +- * +- * struct { +- * struct perf_event_header header; +- * u64 addr; +- * u32 len; +- * u16 ksym_type; +- * u16 flags; +- * char name[]; +- * struct sample_id sample_id; +- * }; +- */ +- PERF_RECORD_KSYMBOL = 17, +- +- /* +- * Record bpf events: +- * enum perf_bpf_event_type { +- * PERF_BPF_EVENT_UNKNOWN = 0, +- * PERF_BPF_EVENT_PROG_LOAD = 1, +- * PERF_BPF_EVENT_PROG_UNLOAD = 2, +- * }; +- * +- * struct { +- * struct perf_event_header header; +- * u16 type; +- * u16 flags; +- * u32 id; +- * u8 tag[BPF_TAG_SIZE]; +- * struct sample_id sample_id; +- * }; +- */ +- PERF_RECORD_BPF_EVENT = 18, +- +- /* +- * struct { +- * struct perf_event_header header; +- * u64 id; +- * char path[]; +- * struct sample_id sample_id; +- * }; +- */ +- PERF_RECORD_CGROUP = 19, +- +- /* +- * Records changes to kernel text i.e. self-modified code. 'old_len' is +- * the number of old bytes, 'new_len' is the number of new bytes. Either +- * 'old_len' or 'new_len' may be zero to indicate, for example, the +- * addition or removal of a trampoline. 'bytes' contains the old bytes +- * followed immediately by the new bytes. +- * +- * struct { +- * struct perf_event_header header; +- * u64 addr; +- * u16 old_len; +- * u16 new_len; +- * u8 bytes[]; +- * struct sample_id sample_id; +- * }; +- */ +- PERF_RECORD_TEXT_POKE = 20, +- +- /* +- * Data written to the AUX area by hardware due to aux_output, may need +- * to be matched to the event by an architecture-specific hardware ID. +- * This records the hardware ID, but requires sample_id to provide the +- * event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT +- * records from multiple events. +- * +- * struct { +- * struct perf_event_header header; +- * u64 hw_id; +- * struct sample_id sample_id; +- * }; +- */ +- PERF_RECORD_AUX_OUTPUT_HW_ID = 21, +- + PERF_RECORD_MAX, /* non-ABI */ + }; + +-enum perf_record_ksymbol_type { +- PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0, +- PERF_RECORD_KSYMBOL_TYPE_BPF = 1, +- /* +- * Out of line code such as kprobe-replaced instructions or optimized +- * kprobes or ftrace trampolines. +- */ +- PERF_RECORD_KSYMBOL_TYPE_OOL = 2, +- PERF_RECORD_KSYMBOL_TYPE_MAX /* non-ABI */ +-}; +- +-#define PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER (1 << 0) +- +-enum perf_bpf_event_type { +- PERF_BPF_EVENT_UNKNOWN = 0, +- PERF_BPF_EVENT_PROG_LOAD = 1, +- PERF_BPF_EVENT_PROG_UNLOAD = 2, +- PERF_BPF_EVENT_MAX, /* non-ABI */ +-}; +- + #define PERF_MAX_STACK_DEPTH 127 + #define PERF_MAX_CONTEXTS_PER_STACK 8 + +@@ -1197,15 +935,10 @@ enum perf_callchain_context { + /** + * PERF_RECORD_AUX::flags bits + */ +-#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */ +-#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */ +-#define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */ +-#define PERF_AUX_FLAG_COLLISION 0x08 /* sample collided with another */ +-#define PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK 0xff00 /* PMU specific trace format type */ +- +-/* CoreSight PMU AUX buffer formats */ +-#define PERF_AUX_FLAG_CORESIGHT_FORMAT_CORESIGHT 0x0000 /* Default for backward compatibility */ +-#define PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW 0x0100 /* Raw format of the source */ ++#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */ ++#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */ ++#define PERF_AUX_FLAG_PARTIAL 0x04 /* record contains gaps */ ++#define PERF_AUX_FLAG_COLLISION 0x08 /* sample collided with another */ + + #define PERF_FLAG_FD_NO_GROUP (1UL << 0) + #define PERF_FLAG_FD_OUTPUT (1UL << 1) +@@ -1224,18 +957,14 @@ union perf_mem_data_src { + mem_lvl_num:4, /* memory hierarchy level number */ + mem_remote:1, /* remote */ + mem_snoopx:2, /* snoop mode, ext */ +- mem_blk:3, /* access blocked */ +- mem_hops:3, /* hop level */ +- mem_rsvd:18; ++ mem_rsvd:24; + }; + }; + #elif defined(__BIG_ENDIAN_BITFIELD) + union perf_mem_data_src { + __u64 val; + struct { +- __u64 mem_rsvd:18, +- mem_hops:3, /* hop level */ +- mem_blk:3, /* access blocked */ ++ __u64 mem_rsvd:24, + mem_snoopx:2, /* snoop mode, ext */ + mem_remote:1, /* remote */ + mem_lvl_num:4, /* memory hierarchy level number */ +@@ -1247,7 +976,7 @@ union perf_mem_data_src { + }; + }; + #else +-#error "Unknown endianness" ++// #error "Unknown endianness" + #endif + + /* type of opcode (load/store/prefetch,code) */ +@@ -1258,13 +987,7 @@ union perf_mem_data_src { + #define PERF_MEM_OP_EXEC 0x10 /* code (execution) */ + #define PERF_MEM_OP_SHIFT 0 + +-/* +- * PERF_MEM_LVL_* namespace being depricated to some extent in the +- * favour of newer composite PERF_MEM_{LVLNUM_,REMOTE_,SNOOPX_} fields. +- * Supporting this namespace inorder to not break defined ABIs. +- * +- * memory hierarchy (memory level, hit or miss) +- */ ++/* memory hierarchy (memory level, hit or miss) */ + #define PERF_MEM_LVL_NA 0x01 /* not available */ + #define PERF_MEM_LVL_HIT 0x02 /* hit level */ + #define PERF_MEM_LVL_MISS 0x04 /* miss level */ +@@ -1324,20 +1047,6 @@ union perf_mem_data_src { + #define PERF_MEM_TLB_OS 0x40 /* OS fault handler */ + #define PERF_MEM_TLB_SHIFT 26 + +-/* Access blocked */ +-#define PERF_MEM_BLK_NA 0x01 /* not available */ +-#define PERF_MEM_BLK_DATA 0x02 /* data could not be forwarded */ +-#define PERF_MEM_BLK_ADDR 0x04 /* address conflict */ +-#define PERF_MEM_BLK_SHIFT 40 +- +-/* hop level */ +-#define PERF_MEM_HOPS_0 0x01 /* remote core, same node */ +-#define PERF_MEM_HOPS_1 0x02 /* remote node, same socket */ +-#define PERF_MEM_HOPS_2 0x03 /* remote socket, same board */ +-#define PERF_MEM_HOPS_3 0x04 /* remote board */ +-/* 5-7 available */ +-#define PERF_MEM_HOPS_SHIFT 43 +- + #define PERF_MEM_S(a, s) \ + (((__u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT) + +@@ -1369,23 +1078,4 @@ struct perf_branch_entry { + reserved:40; + }; + +-union perf_sample_weight { +- __u64 full; +-#if defined(__LITTLE_ENDIAN_BITFIELD) +- struct { +- __u32 var1_dw; +- __u16 var2_w; +- __u16 var3_w; +- }; +-#elif defined(__BIG_ENDIAN_BITFIELD) +- struct { +- __u16 var3_w; +- __u16 var2_w; +- __u32 var1_dw; +- }; +-#else +-#error "Unknown endianness" +-#endif +-}; +- +-#endif /* _UAPI_LINUX_PERF_EVENT_H */ ++#endif /* _TS_PERF_EVENT_H */ diff --git a/trace_streamer/prebuilts/patch_protobuf/protobufbuild.gn b/trace_streamer/prebuilts/patch_protobuf/protobufbuild.gn new file mode 100755 index 0000000000000000000000000000000000000000..cbedb212d1133c4000f1efc8ec6d69f8d3e6f839 --- /dev/null +++ b/trace_streamer/prebuilts/patch_protobuf/protobufbuild.gn @@ -0,0 +1,354 @@ +# 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") + +config("protobuf_config") { + include_dirs = [ "src" ] +} +protobuf_dir = "src/google/protobuf" +protobuf_lite_src = [ + "$protobuf_dir/any_lite.cc", + "$protobuf_dir/arena.cc", + "$protobuf_dir/extension_set.cc", + "$protobuf_dir/generated_enum_util.cc", + "$protobuf_dir/generated_message_table_driven_lite.cc", + "$protobuf_dir/generated_message_util.cc", + "$protobuf_dir/implicit_weak_message.cc", + "$protobuf_dir/io/coded_stream.cc", + "$protobuf_dir/io/io_win32.cc", + "$protobuf_dir/io/strtod.cc", + "$protobuf_dir/io/zero_copy_stream.cc", + "$protobuf_dir/io/zero_copy_stream_impl.cc", + "$protobuf_dir/io/zero_copy_stream_impl_lite.cc", + "$protobuf_dir/message_lite.cc", + "$protobuf_dir/parse_context.cc", + "$protobuf_dir/repeated_field.cc", + "$protobuf_dir/stubs/bytestream.cc", + "$protobuf_dir/stubs/common.cc", + "$protobuf_dir/stubs/int128.cc", + "$protobuf_dir/stubs/status.cc", + "$protobuf_dir/stubs/statusor.cc", + "$protobuf_dir/stubs/stringpiece.cc", + "$protobuf_dir/stubs/stringprintf.cc", + "$protobuf_dir/stubs/structurally_valid.cc", + "$protobuf_dir/stubs/strutil.cc", + "$protobuf_dir/stubs/time.cc", + "$protobuf_dir/wire_format_lite.cc", +] + +protobuf_src = [ + "$protobuf_dir/any.cc", + "$protobuf_dir/any.pb.cc", + "$protobuf_dir/api.pb.cc", + "$protobuf_dir/compiler/importer.cc", + "$protobuf_dir/compiler/parser.cc", + "$protobuf_dir/descriptor.cc", + "$protobuf_dir/descriptor.pb.cc", + "$protobuf_dir/descriptor_database.cc", + "$protobuf_dir/duration.pb.cc", + "$protobuf_dir/dynamic_message.cc", + "$protobuf_dir/empty.pb.cc", + "$protobuf_dir/extension_set_heavy.cc", + "$protobuf_dir/field_mask.pb.cc", + "$protobuf_dir/generated_message_reflection.cc", + "$protobuf_dir/generated_message_table_driven.cc", + "$protobuf_dir/io/gzip_stream.cc", + "$protobuf_dir/io/printer.cc", + "$protobuf_dir/io/tokenizer.cc", + "$protobuf_dir/map_field.cc", + "$protobuf_dir/message.cc", + "$protobuf_dir/reflection_ops.cc", + "$protobuf_dir/service.cc", + "$protobuf_dir/source_context.pb.cc", + "$protobuf_dir/struct.pb.cc", + "$protobuf_dir/stubs/substitute.cc", + "$protobuf_dir/text_format.cc", + "$protobuf_dir/timestamp.pb.cc", + "$protobuf_dir/type.pb.cc", + "$protobuf_dir/unknown_field_set.cc", + "$protobuf_dir/util/delimited_message_util.cc", + "$protobuf_dir/util/field_comparator.cc", + "$protobuf_dir/util/field_mask_util.cc", + "$protobuf_dir/util/internal/datapiece.cc", + "$protobuf_dir/util/internal/default_value_objectwriter.cc", + "$protobuf_dir/util/internal/error_listener.cc", + "$protobuf_dir/util/internal/field_mask_utility.cc", + "$protobuf_dir/util/internal/json_escaping.cc", + "$protobuf_dir/util/internal/json_objectwriter.cc", + "$protobuf_dir/util/internal/json_stream_parser.cc", + "$protobuf_dir/util/internal/object_writer.cc", + "$protobuf_dir/util/internal/proto_writer.cc", + "$protobuf_dir/util/internal/protostream_objectsource.cc", + "$protobuf_dir/util/internal/protostream_objectwriter.cc", + "$protobuf_dir/util/internal/type_info.cc", + "$protobuf_dir/util/internal/type_info_test_helper.cc", + "$protobuf_dir/util/internal/utility.cc", + "$protobuf_dir/util/json_util.cc", + "$protobuf_dir/util/message_differencer.cc", + "$protobuf_dir/util/time_util.cc", + "$protobuf_dir/util/type_resolver_util.cc", + "$protobuf_dir/wire_format.cc", + "$protobuf_dir/wrappers.pb.cc", +] +if (use_wasm) { + source_set("protobuf_lite") { + sources = protobuf_lite_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + + #configs = default_configs + + public_configs = [ ":protobuf_config" ] + } +} else { + source_set("protobuf_lite") { + sources = protobuf_lite_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + + # configs = default_configs + + public_configs = [ ":protobuf_config" ] + } +} +if (use_wasm) { + source_set("protobuf") { + sources = protobuf_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + + deps = [ ":protobuf_lite" ] + + #configs = default_configs + + public_configs = [ ":protobuf_config" ] + } +} else { + source_set("protobuf") { + sources = protobuf_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + + #cflags_cc = [ + # "-Wno-sign-compare", + # "-ftrapv", + # "-fstack-protector-strong", + # "-fstack-protector-all", + # "-D_FORTIFY_SOURCE=2 -O2", + + #] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-ftrapv", + "-fstack-protector-strong", + "-fstack-protector-all", + "-D_FORTIFY_SOURCE=2 -O2", + "-std=c++17", + + # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + ] + + ldflags = [ "-fstack-protector" ] + if (!is_macx) { + ldflags += [ + "-fuse-ld=gold", + "-Wl,--gc-sections", + "-Wl,-O1", + "-fpie", + "-pie", + ] + } + + if (!is_win) { + cflags += [ + "-fPIE", + "-fPIC", + ] + } + + deps = [ ":protobuf_lite" ] + + public_configs = [ ":protobuf_config" ] + } + source_set("protoc_lib") { + sources = [ + "$protobuf_dir/compiler/code_generator.cc", + "$protobuf_dir/compiler/command_line_interface.cc", + "$protobuf_dir/compiler/cpp/cpp_enum.cc", + "$protobuf_dir/compiler/cpp/cpp_enum_field.cc", + "$protobuf_dir/compiler/cpp/cpp_extension.cc", + "$protobuf_dir/compiler/cpp/cpp_field.cc", + "$protobuf_dir/compiler/cpp/cpp_file.cc", + "$protobuf_dir/compiler/cpp/cpp_generator.cc", + "$protobuf_dir/compiler/cpp/cpp_helpers.cc", + "$protobuf_dir/compiler/cpp/cpp_map_field.cc", + "$protobuf_dir/compiler/cpp/cpp_message.cc", + "$protobuf_dir/compiler/cpp/cpp_message_field.cc", + "$protobuf_dir/compiler/cpp/cpp_padding_optimizer.cc", + "$protobuf_dir/compiler/cpp/cpp_primitive_field.cc", + "$protobuf_dir/compiler/cpp/cpp_service.cc", + "$protobuf_dir/compiler/cpp/cpp_string_field.cc", + "$protobuf_dir/compiler/csharp/csharp_doc_comment.cc", + "$protobuf_dir/compiler/csharp/csharp_enum.cc", + "$protobuf_dir/compiler/csharp/csharp_enum_field.cc", + "$protobuf_dir/compiler/csharp/csharp_field_base.cc", + "$protobuf_dir/compiler/csharp/csharp_generator.cc", + "$protobuf_dir/compiler/csharp/csharp_helpers.cc", + "$protobuf_dir/compiler/csharp/csharp_map_field.cc", + "$protobuf_dir/compiler/csharp/csharp_message.cc", + "$protobuf_dir/compiler/csharp/csharp_message_field.cc", + "$protobuf_dir/compiler/csharp/csharp_primitive_field.cc", + "$protobuf_dir/compiler/csharp/csharp_reflection_class.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_enum_field.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_message_field.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_primitive_field.cc", + "$protobuf_dir/compiler/csharp/csharp_source_generator_base.cc", + "$protobuf_dir/compiler/csharp/csharp_wrapper_field.cc", + "$protobuf_dir/compiler/java/java_context.cc", + "$protobuf_dir/compiler/java/java_doc_comment.cc", + "$protobuf_dir/compiler/java/java_enum.cc", + "$protobuf_dir/compiler/java/java_enum_field.cc", + "$protobuf_dir/compiler/java/java_enum_field_lite.cc", + "$protobuf_dir/compiler/java/java_enum_lite.cc", + "$protobuf_dir/compiler/java/java_extension.cc", + "$protobuf_dir/compiler/java/java_extension_lite.cc", + "$protobuf_dir/compiler/java/java_field.cc", + "$protobuf_dir/compiler/java/java_file.cc", + "$protobuf_dir/compiler/java/java_generator.cc", + "$protobuf_dir/compiler/java/java_generator_factory.cc", + "$protobuf_dir/compiler/java/java_helpers.cc", + "$protobuf_dir/compiler/java/java_map_field.cc", + "$protobuf_dir/compiler/java/java_map_field_lite.cc", + "$protobuf_dir/compiler/java/java_message.cc", + "$protobuf_dir/compiler/java/java_message_builder.cc", + "$protobuf_dir/compiler/java/java_message_builder_lite.cc", + "$protobuf_dir/compiler/java/java_message_field.cc", + "$protobuf_dir/compiler/java/java_message_field_lite.cc", + "$protobuf_dir/compiler/java/java_message_lite.cc", + "$protobuf_dir/compiler/java/java_name_resolver.cc", + "$protobuf_dir/compiler/java/java_primitive_field.cc", + "$protobuf_dir/compiler/java/java_primitive_field_lite.cc", + "$protobuf_dir/compiler/java/java_service.cc", + "$protobuf_dir/compiler/java/java_shared_code_generator.cc", + "$protobuf_dir/compiler/java/java_string_field.cc", + "$protobuf_dir/compiler/java/java_string_field_lite.cc", + "$protobuf_dir/compiler/js/js_generator.cc", + "$protobuf_dir/compiler/js/well_known_types_embed.cc", + "$protobuf_dir/compiler/objectivec/objectivec_enum.cc", + "$protobuf_dir/compiler/objectivec/objectivec_enum_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_extension.cc", + "$protobuf_dir/compiler/objectivec/objectivec_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_file.cc", + "$protobuf_dir/compiler/objectivec/objectivec_generator.cc", + "$protobuf_dir/compiler/objectivec/objectivec_helpers.cc", + "$protobuf_dir/compiler/objectivec/objectivec_map_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_message.cc", + "$protobuf_dir/compiler/objectivec/objectivec_message_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_oneof.cc", + "$protobuf_dir/compiler/objectivec/objectivec_primitive_field.cc", + "$protobuf_dir/compiler/php/php_generator.cc", + "$protobuf_dir/compiler/plugin.cc", + "$protobuf_dir/compiler/plugin.pb.cc", + "$protobuf_dir/compiler/python/python_generator.cc", + "$protobuf_dir/compiler/ruby/ruby_generator.cc", + "$protobuf_dir/compiler/subprocess.cc", + "$protobuf_dir/compiler/zip_writer.cc", + ] + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + + # "/opt/clang-mingw/i686-w64-mingw32/x86_64-linux-gnu", + # "/opt/clang-mingw/i686-w64-mingw32/x86_64-linux-gnu/c++/7", + # "/opt/clang-mingw/i686-w64-mingw32/include/c++/7", + # "/usr/include", + # "/usr/include/c++/7", + # "/usr/include/x86_64-linux-gnu/c++/7", + ] + if (!use_wasm) { + configs = default_configs + } + cflags_cc = [ + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-private-field", + + # "-std=gnu++17", + ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-Wno-unused-function", + "-std=c++17", + + # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + ] + + deps = [ + ":protobuf", + ":protobuf_lite", + ] + + public_configs = [ ":protobuf_config" ] + } + executable("protoc") { + sources = [ "$protobuf_dir/compiler/main.cc" ] + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + "/usr/include", + ] + deps = [ ":protoc_lib" ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + ] + } +} diff --git a/trace_streamer/prebuilts/patch_protobuf/protobufbuild.gn.patch b/trace_streamer/prebuilts/patch_protobuf/protobufbuild.gn.patch new file mode 100644 index 0000000000000000000000000000000000000000..2162831f399da363b0b695189853b04a89fcfb62 --- /dev/null +++ b/trace_streamer/prebuilts/patch_protobuf/protobufbuild.gn.patch @@ -0,0 +1,795 @@ +--- BUILD.gn 2023-02-07 11:25:55 ++++ /Users/suze/tp/code/ohos_devtools_trace_resolver/third_party/protobuf/BUILD.gn 2023-01-29 14:53:33 +@@ -12,510 +12,343 @@ import("//build/ohos.gni") + # limitations under the License. + + import("//build/ohos.gni") +-import("//developtools/profiler/build/config.gni") + + config("protobuf_config") { + include_dirs = [ "src" ] + } ++protobuf_dir = "src/google/protobuf" ++protobuf_lite_src = [ ++ "$protobuf_dir/any_lite.cc", ++ "$protobuf_dir/arena.cc", ++ "$protobuf_dir/extension_set.cc", ++ "$protobuf_dir/generated_enum_util.cc", ++ "$protobuf_dir/generated_message_table_driven_lite.cc", ++ "$protobuf_dir/generated_message_util.cc", ++ "$protobuf_dir/implicit_weak_message.cc", ++ "$protobuf_dir/io/coded_stream.cc", ++ "$protobuf_dir/io/io_win32.cc", ++ "$protobuf_dir/io/strtod.cc", ++ "$protobuf_dir/io/zero_copy_stream.cc", ++ "$protobuf_dir/io/zero_copy_stream_impl.cc", ++ "$protobuf_dir/io/zero_copy_stream_impl_lite.cc", ++ "$protobuf_dir/message_lite.cc", ++ "$protobuf_dir/parse_context.cc", ++ "$protobuf_dir/repeated_field.cc", ++ "$protobuf_dir/stubs/bytestream.cc", ++ "$protobuf_dir/stubs/common.cc", ++ "$protobuf_dir/stubs/int128.cc", ++ "$protobuf_dir/stubs/status.cc", ++ "$protobuf_dir/stubs/statusor.cc", ++ "$protobuf_dir/stubs/stringpiece.cc", ++ "$protobuf_dir/stubs/stringprintf.cc", ++ "$protobuf_dir/stubs/structurally_valid.cc", ++ "$protobuf_dir/stubs/strutil.cc", ++ "$protobuf_dir/stubs/time.cc", ++ "$protobuf_dir/wire_format_lite.cc", ++] + +-ohos_shared_library("protobuf_lite") { +- sources = [ +- "src/google/protobuf/any_lite.cc", +- "src/google/protobuf/arena.cc", +- "src/google/protobuf/extension_set.cc", +- "src/google/protobuf/generated_enum_util.cc", +- "src/google/protobuf/generated_message_table_driven_lite.cc", +- "src/google/protobuf/generated_message_util.cc", +- "src/google/protobuf/implicit_weak_message.cc", +- "src/google/protobuf/io/coded_stream.cc", +- "src/google/protobuf/io/io_win32.cc", +- "src/google/protobuf/io/strtod.cc", +- "src/google/protobuf/io/zero_copy_stream.cc", +- "src/google/protobuf/io/zero_copy_stream_impl.cc", +- "src/google/protobuf/io/zero_copy_stream_impl_lite.cc", +- "src/google/protobuf/message_lite.cc", +- "src/google/protobuf/parse_context.cc", +- "src/google/protobuf/repeated_field.cc", +- "src/google/protobuf/stubs/bytestream.cc", +- "src/google/protobuf/stubs/common.cc", +- "src/google/protobuf/stubs/int128.cc", +- "src/google/protobuf/stubs/status.cc", +- "src/google/protobuf/stubs/statusor.cc", +- "src/google/protobuf/stubs/stringpiece.cc", +- "src/google/protobuf/stubs/stringprintf.cc", +- "src/google/protobuf/stubs/structurally_valid.cc", +- "src/google/protobuf/stubs/strutil.cc", +- "src/google/protobuf/stubs/time.cc", +- "src/google/protobuf/wire_format_lite.cc", +- ] +- version_script = "libprotobuf_lite.map" +- include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", +- "src", +- ] +- if (!is_mingw) { +- if (current_toolchain != host_toolchain) { +- external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +- } +- } else { +- defines = [ "_FILE_OFFSET_BITS_SET_LSEEK" ] +- } ++protobuf_src = [ ++ "$protobuf_dir/any.cc", ++ "$protobuf_dir/any.pb.cc", ++ "$protobuf_dir/api.pb.cc", ++ "$protobuf_dir/compiler/importer.cc", ++ "$protobuf_dir/compiler/parser.cc", ++ "$protobuf_dir/descriptor.cc", ++ "$protobuf_dir/descriptor.pb.cc", ++ "$protobuf_dir/descriptor_database.cc", ++ "$protobuf_dir/duration.pb.cc", ++ "$protobuf_dir/dynamic_message.cc", ++ "$protobuf_dir/empty.pb.cc", ++ "$protobuf_dir/extension_set_heavy.cc", ++ "$protobuf_dir/field_mask.pb.cc", ++ "$protobuf_dir/generated_message_reflection.cc", ++ "$protobuf_dir/generated_message_table_driven.cc", ++ "$protobuf_dir/io/gzip_stream.cc", ++ "$protobuf_dir/io/printer.cc", ++ "$protobuf_dir/io/tokenizer.cc", ++ "$protobuf_dir/map_field.cc", ++ "$protobuf_dir/message.cc", ++ "$protobuf_dir/reflection_ops.cc", ++ "$protobuf_dir/service.cc", ++ "$protobuf_dir/source_context.pb.cc", ++ "$protobuf_dir/struct.pb.cc", ++ "$protobuf_dir/stubs/substitute.cc", ++ "$protobuf_dir/text_format.cc", ++ "$protobuf_dir/timestamp.pb.cc", ++ "$protobuf_dir/type.pb.cc", ++ "$protobuf_dir/unknown_field_set.cc", ++ "$protobuf_dir/util/delimited_message_util.cc", ++ "$protobuf_dir/util/field_comparator.cc", ++ "$protobuf_dir/util/field_mask_util.cc", ++ "$protobuf_dir/util/internal/datapiece.cc", ++ "$protobuf_dir/util/internal/default_value_objectwriter.cc", ++ "$protobuf_dir/util/internal/error_listener.cc", ++ "$protobuf_dir/util/internal/field_mask_utility.cc", ++ "$protobuf_dir/util/internal/json_escaping.cc", ++ "$protobuf_dir/util/internal/json_objectwriter.cc", ++ "$protobuf_dir/util/internal/json_stream_parser.cc", ++ "$protobuf_dir/util/internal/object_writer.cc", ++ "$protobuf_dir/util/internal/proto_writer.cc", ++ "$protobuf_dir/util/internal/protostream_objectsource.cc", ++ "$protobuf_dir/util/internal/protostream_objectwriter.cc", ++ "$protobuf_dir/util/internal/type_info.cc", ++ "$protobuf_dir/util/internal/type_info_test_helper.cc", ++ "$protobuf_dir/util/internal/utility.cc", ++ "$protobuf_dir/util/json_util.cc", ++ "$protobuf_dir/util/message_differencer.cc", ++ "$protobuf_dir/util/time_util.cc", ++ "$protobuf_dir/util/type_resolver_util.cc", ++ "$protobuf_dir/wire_format.cc", ++ "$protobuf_dir/wrappers.pb.cc", ++] ++if (use_wasm) { ++ source_set("protobuf_lite") { ++ sources = protobuf_lite_src ++ include_dirs = [ ++ "$protobuf_dir/**/*.h", ++ "$protobuf_dir/**/*.inc", ++ "src", ++ ] + +- cflags_cc = [ "-Wno-sign-compare" ] +- cflags = [ +- "-Wno-sign-compare", +- "-D HAVE_PTHREAD", +- ] ++ cflags_cc = [ "-Wno-sign-compare" ] ++ cflags = [ ++ "-Wno-sign-compare", ++ "-D HAVE_PTHREAD", ++ "-std=c++17", ++ ] + +- public_configs = [ ":protobuf_config" ] +- install_enable = true +- subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" +- part_name = "${OHOS_PROFILER_PART_NAME}" +-} ++ #configs = default_configs + +-ohos_static_library("protobuf_lite_static") { +- sources = [ +- "src/google/protobuf/any_lite.cc", +- "src/google/protobuf/arena.cc", +- "src/google/protobuf/extension_set.cc", +- "src/google/protobuf/generated_enum_util.cc", +- "src/google/protobuf/generated_message_table_driven_lite.cc", +- "src/google/protobuf/generated_message_util.cc", +- "src/google/protobuf/implicit_weak_message.cc", +- "src/google/protobuf/io/coded_stream.cc", +- "src/google/protobuf/io/io_win32.cc", +- "src/google/protobuf/io/strtod.cc", +- "src/google/protobuf/io/zero_copy_stream.cc", +- "src/google/protobuf/io/zero_copy_stream_impl.cc", +- "src/google/protobuf/io/zero_copy_stream_impl_lite.cc", +- "src/google/protobuf/message_lite.cc", +- "src/google/protobuf/parse_context.cc", +- "src/google/protobuf/repeated_field.cc", +- "src/google/protobuf/stubs/bytestream.cc", +- "src/google/protobuf/stubs/common.cc", +- "src/google/protobuf/stubs/int128.cc", +- "src/google/protobuf/stubs/status.cc", +- "src/google/protobuf/stubs/statusor.cc", +- "src/google/protobuf/stubs/stringpiece.cc", +- "src/google/protobuf/stubs/stringprintf.cc", +- "src/google/protobuf/stubs/structurally_valid.cc", +- "src/google/protobuf/stubs/strutil.cc", +- "src/google/protobuf/stubs/time.cc", +- "src/google/protobuf/wire_format_lite.cc", +- ] +- include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", +- "src", +- ] +- if (!is_mingw) { +- if (default_toolchain == current_toolchain) { +- # target build, not host build +- defines = [ "HAVE_HILOG" ] +- external_deps = [ "hiviewdfx_hilog_native:libhilog" ] +- } +- } else { +- defines = [ "_FILE_OFFSET_BITS_SET_LSEEK" ] ++ public_configs = [ ":protobuf_config" ] + } ++} else { ++ source_set("protobuf_lite") { ++ sources = protobuf_lite_src ++ include_dirs = [ ++ "$protobuf_dir/**/*.h", ++ "$protobuf_dir/**/*.inc", ++ "src", ++ ] + +- cflags_cc = [ "-Wno-sign-compare" ] +- cflags = [ +- "-Wno-sign-compare", +- "-D HAVE_PTHREAD", +- ] +- if (is_mingw) { +- # ../../third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.cc:60:9: error: 'lseek' macro redefined [-Werror,-Wmacro-redefined] +- cflags += [ "-Wno-macro-redefined" ] +- } +- public_configs = [ ":protobuf_config" ] +-} ++ cflags_cc = [ "-Wno-sign-compare" ] ++ cflags = [ ++ "-Wno-sign-compare", ++ "-D HAVE_PTHREAD", ++ "-std=c++17", ++ ] + +-ohos_shared_library("protobuf") { +- sources = [ +- "src/google/protobuf/any.cc", +- "src/google/protobuf/any.pb.cc", +- "src/google/protobuf/api.pb.cc", +- "src/google/protobuf/compiler/importer.cc", +- "src/google/protobuf/compiler/parser.cc", +- "src/google/protobuf/descriptor.cc", +- "src/google/protobuf/descriptor.pb.cc", +- "src/google/protobuf/descriptor_database.cc", +- "src/google/protobuf/duration.pb.cc", +- "src/google/protobuf/dynamic_message.cc", +- "src/google/protobuf/empty.pb.cc", +- "src/google/protobuf/extension_set_heavy.cc", +- "src/google/protobuf/field_mask.pb.cc", +- "src/google/protobuf/generated_message_reflection.cc", +- "src/google/protobuf/generated_message_table_driven.cc", +- "src/google/protobuf/io/gzip_stream.cc", +- "src/google/protobuf/io/printer.cc", +- "src/google/protobuf/io/tokenizer.cc", +- "src/google/protobuf/map_field.cc", +- "src/google/protobuf/message.cc", +- "src/google/protobuf/reflection_ops.cc", +- "src/google/protobuf/service.cc", +- "src/google/protobuf/source_context.pb.cc", +- "src/google/protobuf/struct.pb.cc", +- "src/google/protobuf/stubs/substitute.cc", +- "src/google/protobuf/text_format.cc", +- "src/google/protobuf/timestamp.pb.cc", +- "src/google/protobuf/type.pb.cc", +- "src/google/protobuf/unknown_field_set.cc", +- "src/google/protobuf/util/delimited_message_util.cc", +- "src/google/protobuf/util/field_comparator.cc", +- "src/google/protobuf/util/field_mask_util.cc", +- "src/google/protobuf/util/internal/datapiece.cc", +- "src/google/protobuf/util/internal/default_value_objectwriter.cc", +- "src/google/protobuf/util/internal/error_listener.cc", +- "src/google/protobuf/util/internal/field_mask_utility.cc", +- "src/google/protobuf/util/internal/json_escaping.cc", +- "src/google/protobuf/util/internal/json_objectwriter.cc", +- "src/google/protobuf/util/internal/json_stream_parser.cc", +- "src/google/protobuf/util/internal/object_writer.cc", +- "src/google/protobuf/util/internal/proto_writer.cc", +- "src/google/protobuf/util/internal/protostream_objectsource.cc", +- "src/google/protobuf/util/internal/protostream_objectwriter.cc", +- "src/google/protobuf/util/internal/type_info.cc", +- "src/google/protobuf/util/internal/type_info_test_helper.cc", +- "src/google/protobuf/util/internal/utility.cc", +- "src/google/protobuf/util/json_util.cc", +- "src/google/protobuf/util/message_differencer.cc", +- "src/google/protobuf/util/time_util.cc", +- "src/google/protobuf/util/type_resolver_util.cc", +- "src/google/protobuf/wire_format.cc", +- "src/google/protobuf/wrappers.pb.cc", +- ] +- include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", +- "src", +- ] +- cflags_cc = [ "-Wno-sign-compare" ] +- cflags = [ +- "-Wno-sign-compare", +- "-D HAVE_PTHREAD", +- ] ++ # configs = default_configs + +- deps = [ ":protobuf_lite" ] +- version_script = "libprotobuf.map" +- +- public_configs = [ ":protobuf_config" ] +- install_enable = true +- subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" +- part_name = "${OHOS_PROFILER_PART_NAME}" ++ public_configs = [ ":protobuf_config" ] ++ } + } ++if (use_wasm) { ++ source_set("protobuf") { ++ sources = protobuf_src ++ include_dirs = [ ++ "$protobuf_dir/**/*.h", ++ "$protobuf_dir/**/*.inc", ++ "src", ++ ] ++ cflags_cc = [ "-Wno-sign-compare" ] ++ cflags = [ ++ "-Wno-sign-compare", ++ "-D HAVE_PTHREAD", ++ "-std=c++17", ++ ] + +-ohos_static_library("protobuf_static") { +- sources = [ +- "src/google/protobuf/any.cc", +- "src/google/protobuf/any.pb.cc", +- "src/google/protobuf/api.pb.cc", +- "src/google/protobuf/compiler/importer.cc", +- "src/google/protobuf/compiler/parser.cc", +- "src/google/protobuf/descriptor.cc", +- "src/google/protobuf/descriptor.pb.cc", +- "src/google/protobuf/descriptor_database.cc", +- "src/google/protobuf/duration.pb.cc", +- "src/google/protobuf/dynamic_message.cc", +- "src/google/protobuf/empty.pb.cc", +- "src/google/protobuf/extension_set_heavy.cc", +- "src/google/protobuf/field_mask.pb.cc", +- "src/google/protobuf/generated_message_reflection.cc", +- "src/google/protobuf/generated_message_table_driven.cc", +- "src/google/protobuf/io/gzip_stream.cc", +- "src/google/protobuf/io/printer.cc", +- "src/google/protobuf/io/tokenizer.cc", +- "src/google/protobuf/map_field.cc", +- "src/google/protobuf/message.cc", +- "src/google/protobuf/reflection_ops.cc", +- "src/google/protobuf/service.cc", +- "src/google/protobuf/source_context.pb.cc", +- "src/google/protobuf/struct.pb.cc", +- "src/google/protobuf/stubs/substitute.cc", +- "src/google/protobuf/text_format.cc", +- "src/google/protobuf/timestamp.pb.cc", +- "src/google/protobuf/type.pb.cc", +- "src/google/protobuf/unknown_field_set.cc", +- "src/google/protobuf/util/delimited_message_util.cc", +- "src/google/protobuf/util/field_comparator.cc", +- "src/google/protobuf/util/field_mask_util.cc", +- "src/google/protobuf/util/internal/datapiece.cc", +- "src/google/protobuf/util/internal/default_value_objectwriter.cc", +- "src/google/protobuf/util/internal/error_listener.cc", +- "src/google/protobuf/util/internal/field_mask_utility.cc", +- "src/google/protobuf/util/internal/json_escaping.cc", +- "src/google/protobuf/util/internal/json_objectwriter.cc", +- "src/google/protobuf/util/internal/json_stream_parser.cc", +- "src/google/protobuf/util/internal/object_writer.cc", +- "src/google/protobuf/util/internal/proto_writer.cc", +- "src/google/protobuf/util/internal/protostream_objectsource.cc", +- "src/google/protobuf/util/internal/protostream_objectwriter.cc", +- "src/google/protobuf/util/internal/type_info.cc", +- "src/google/protobuf/util/internal/type_info_test_helper.cc", +- "src/google/protobuf/util/internal/utility.cc", +- "src/google/protobuf/util/json_util.cc", +- "src/google/protobuf/util/message_differencer.cc", +- "src/google/protobuf/util/time_util.cc", +- "src/google/protobuf/util/type_resolver_util.cc", +- "src/google/protobuf/wire_format.cc", +- "src/google/protobuf/wrappers.pb.cc", +- ] +- include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", +- "src", +- ] +- cflags_cc = [ "-Wno-sign-compare" ] +- cflags = [ +- "-Wno-sign-compare", +- "-D HAVE_PTHREAD", +- ] ++ deps = [ ":protobuf_lite" ] + +- deps = [ ":protobuf_lite_static" ] ++ #configs = default_configs + +- public_configs = [ ":protobuf_config" ] +-} +- +-if (current_toolchain == host_toolchain) { +- ohos_shared_library("protoc_lib") { +- sources = [ +- "src/google/protobuf/compiler/code_generator.cc", +- "src/google/protobuf/compiler/command_line_interface.cc", +- "src/google/protobuf/compiler/cpp/cpp_enum.cc", +- "src/google/protobuf/compiler/cpp/cpp_enum_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_extension.cc", +- "src/google/protobuf/compiler/cpp/cpp_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_file.cc", +- "src/google/protobuf/compiler/cpp/cpp_generator.cc", +- "src/google/protobuf/compiler/cpp/cpp_helpers.cc", +- "src/google/protobuf/compiler/cpp/cpp_map_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_message.cc", +- "src/google/protobuf/compiler/cpp/cpp_message_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc", +- "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_service.cc", +- "src/google/protobuf/compiler/cpp/cpp_string_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc", +- "src/google/protobuf/compiler/csharp/csharp_enum.cc", +- "src/google/protobuf/compiler/csharp/csharp_enum_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_field_base.cc", +- "src/google/protobuf/compiler/csharp/csharp_generator.cc", +- "src/google/protobuf/compiler/csharp/csharp_helpers.cc", +- "src/google/protobuf/compiler/csharp/csharp_map_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_message.cc", +- "src/google/protobuf/compiler/csharp/csharp_message_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_primitive_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_reflection_class.cc", +- "src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc", +- "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc", +- "src/google/protobuf/compiler/java/java_context.cc", +- "src/google/protobuf/compiler/java/java_doc_comment.cc", +- "src/google/protobuf/compiler/java/java_enum.cc", +- "src/google/protobuf/compiler/java/java_enum_field.cc", +- "src/google/protobuf/compiler/java/java_enum_field_lite.cc", +- "src/google/protobuf/compiler/java/java_enum_lite.cc", +- "src/google/protobuf/compiler/java/java_extension.cc", +- "src/google/protobuf/compiler/java/java_extension_lite.cc", +- "src/google/protobuf/compiler/java/java_field.cc", +- "src/google/protobuf/compiler/java/java_file.cc", +- "src/google/protobuf/compiler/java/java_generator.cc", +- "src/google/protobuf/compiler/java/java_generator_factory.cc", +- "src/google/protobuf/compiler/java/java_helpers.cc", +- "src/google/protobuf/compiler/java/java_map_field.cc", +- "src/google/protobuf/compiler/java/java_map_field_lite.cc", +- "src/google/protobuf/compiler/java/java_message.cc", +- "src/google/protobuf/compiler/java/java_message_builder.cc", +- "src/google/protobuf/compiler/java/java_message_builder_lite.cc", +- "src/google/protobuf/compiler/java/java_message_field.cc", +- "src/google/protobuf/compiler/java/java_message_field_lite.cc", +- "src/google/protobuf/compiler/java/java_message_lite.cc", +- "src/google/protobuf/compiler/java/java_name_resolver.cc", +- "src/google/protobuf/compiler/java/java_primitive_field.cc", +- "src/google/protobuf/compiler/java/java_primitive_field_lite.cc", +- "src/google/protobuf/compiler/java/java_service.cc", +- "src/google/protobuf/compiler/java/java_shared_code_generator.cc", +- "src/google/protobuf/compiler/java/java_string_field.cc", +- "src/google/protobuf/compiler/java/java_string_field_lite.cc", +- "src/google/protobuf/compiler/js/js_generator.cc", +- "src/google/protobuf/compiler/js/well_known_types_embed.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_enum.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_extension.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_file.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_generator.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_helpers.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_map_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_message.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_message_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_oneof.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc", +- "src/google/protobuf/compiler/php/php_generator.cc", +- "src/google/protobuf/compiler/plugin.cc", +- "src/google/protobuf/compiler/plugin.pb.cc", +- "src/google/protobuf/compiler/python/python_generator.cc", +- "src/google/protobuf/compiler/ruby/ruby_generator.cc", +- "src/google/protobuf/compiler/subprocess.cc", +- "src/google/protobuf/compiler/zip_writer.cc", +- ] ++ public_configs = [ ":protobuf_config" ] ++ } ++} else { ++ source_set("protobuf") { ++ sources = protobuf_src + include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", ++ "$protobuf_dir/**/*.h", ++ "$protobuf_dir/**/*.inc", + "src", + ] +- cflags_cc = [ +- "-Wno-sign-compare", +- "-Wno-unused-function", +- "-Wno-unused-private-field", +- ] ++ ++ #cflags_cc = [ ++ # "-Wno-sign-compare", ++ # "-ftrapv", ++ # "-fstack-protector-strong", ++ # "-fstack-protector-all", ++ # "-D_FORTIFY_SOURCE=2 -O2", ++ ++ #] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", +- "-Wno-unused-function", +- ] ++ "-ftrapv", ++ "-fstack-protector-strong", ++ "-fstack-protector-all", ++ "-D_FORTIFY_SOURCE=2 -O2", ++ "-std=c++17", + +- deps = [ +- ":protobuf", +- ":protobuf_lite", ++ # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + ] + ++ ldflags = [ "-fstack-protector" ] ++ if (!is_macx) { ++ ldflags += [ ++ "-fuse-ld=gold", ++ "-Wl,--gc-sections", ++ "-Wl,-O1", ++ "-fpie", ++ "-pie", ++ ] ++ } ++ ++ if (!is_win) { ++ cflags += [ ++ "-fPIE", ++ "-fPIC", ++ ] ++ } ++ ++ deps = [ ":protobuf_lite" ] ++ + public_configs = [ ":protobuf_config" ] +- subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" +- part_name = "${OHOS_PROFILER_PART_NAME}" + } +- +- ohos_static_library("protoc_static_lib") { ++ source_set("protoc_lib") { + sources = [ +- "src/google/protobuf/compiler/code_generator.cc", +- "src/google/protobuf/compiler/command_line_interface.cc", +- "src/google/protobuf/compiler/cpp/cpp_enum.cc", +- "src/google/protobuf/compiler/cpp/cpp_enum_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_extension.cc", +- "src/google/protobuf/compiler/cpp/cpp_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_file.cc", +- "src/google/protobuf/compiler/cpp/cpp_generator.cc", +- "src/google/protobuf/compiler/cpp/cpp_helpers.cc", +- "src/google/protobuf/compiler/cpp/cpp_map_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_message.cc", +- "src/google/protobuf/compiler/cpp/cpp_message_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc", +- "src/google/protobuf/compiler/cpp/cpp_primitive_field.cc", +- "src/google/protobuf/compiler/cpp/cpp_service.cc", +- "src/google/protobuf/compiler/cpp/cpp_string_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_doc_comment.cc", +- "src/google/protobuf/compiler/csharp/csharp_enum.cc", +- "src/google/protobuf/compiler/csharp/csharp_enum_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_field_base.cc", +- "src/google/protobuf/compiler/csharp/csharp_generator.cc", +- "src/google/protobuf/compiler/csharp/csharp_helpers.cc", +- "src/google/protobuf/compiler/csharp/csharp_map_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_message.cc", +- "src/google/protobuf/compiler/csharp/csharp_message_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_primitive_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_reflection_class.cc", +- "src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc", +- "src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc", +- "src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc", +- "src/google/protobuf/compiler/java/java_context.cc", +- "src/google/protobuf/compiler/java/java_doc_comment.cc", +- "src/google/protobuf/compiler/java/java_enum.cc", +- "src/google/protobuf/compiler/java/java_enum_field.cc", +- "src/google/protobuf/compiler/java/java_enum_field_lite.cc", +- "src/google/protobuf/compiler/java/java_enum_lite.cc", +- "src/google/protobuf/compiler/java/java_extension.cc", +- "src/google/protobuf/compiler/java/java_extension_lite.cc", +- "src/google/protobuf/compiler/java/java_field.cc", +- "src/google/protobuf/compiler/java/java_file.cc", +- "src/google/protobuf/compiler/java/java_generator.cc", +- "src/google/protobuf/compiler/java/java_generator_factory.cc", +- "src/google/protobuf/compiler/java/java_helpers.cc", +- "src/google/protobuf/compiler/java/java_map_field.cc", +- "src/google/protobuf/compiler/java/java_map_field_lite.cc", +- "src/google/protobuf/compiler/java/java_message.cc", +- "src/google/protobuf/compiler/java/java_message_builder.cc", +- "src/google/protobuf/compiler/java/java_message_builder_lite.cc", +- "src/google/protobuf/compiler/java/java_message_field.cc", +- "src/google/protobuf/compiler/java/java_message_field_lite.cc", +- "src/google/protobuf/compiler/java/java_message_lite.cc", +- "src/google/protobuf/compiler/java/java_name_resolver.cc", +- "src/google/protobuf/compiler/java/java_primitive_field.cc", +- "src/google/protobuf/compiler/java/java_primitive_field_lite.cc", +- "src/google/protobuf/compiler/java/java_service.cc", +- "src/google/protobuf/compiler/java/java_shared_code_generator.cc", +- "src/google/protobuf/compiler/java/java_string_field.cc", +- "src/google/protobuf/compiler/java/java_string_field_lite.cc", +- "src/google/protobuf/compiler/js/js_generator.cc", +- "src/google/protobuf/compiler/js/well_known_types_embed.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_enum.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_extension.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_file.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_generator.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_helpers.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_map_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_message.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_message_field.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_oneof.cc", +- "src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc", +- "src/google/protobuf/compiler/php/php_generator.cc", +- "src/google/protobuf/compiler/plugin.cc", +- "src/google/protobuf/compiler/plugin.pb.cc", +- "src/google/protobuf/compiler/python/python_generator.cc", +- "src/google/protobuf/compiler/ruby/ruby_generator.cc", +- "src/google/protobuf/compiler/subprocess.cc", +- "src/google/protobuf/compiler/zip_writer.cc", ++ "$protobuf_dir/compiler/code_generator.cc", ++ "$protobuf_dir/compiler/command_line_interface.cc", ++ "$protobuf_dir/compiler/cpp/cpp_enum.cc", ++ "$protobuf_dir/compiler/cpp/cpp_enum_field.cc", ++ "$protobuf_dir/compiler/cpp/cpp_extension.cc", ++ "$protobuf_dir/compiler/cpp/cpp_field.cc", ++ "$protobuf_dir/compiler/cpp/cpp_file.cc", ++ "$protobuf_dir/compiler/cpp/cpp_generator.cc", ++ "$protobuf_dir/compiler/cpp/cpp_helpers.cc", ++ "$protobuf_dir/compiler/cpp/cpp_map_field.cc", ++ "$protobuf_dir/compiler/cpp/cpp_message.cc", ++ "$protobuf_dir/compiler/cpp/cpp_message_field.cc", ++ "$protobuf_dir/compiler/cpp/cpp_padding_optimizer.cc", ++ "$protobuf_dir/compiler/cpp/cpp_primitive_field.cc", ++ "$protobuf_dir/compiler/cpp/cpp_service.cc", ++ "$protobuf_dir/compiler/cpp/cpp_string_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_doc_comment.cc", ++ "$protobuf_dir/compiler/csharp/csharp_enum.cc", ++ "$protobuf_dir/compiler/csharp/csharp_enum_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_field_base.cc", ++ "$protobuf_dir/compiler/csharp/csharp_generator.cc", ++ "$protobuf_dir/compiler/csharp/csharp_helpers.cc", ++ "$protobuf_dir/compiler/csharp/csharp_map_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_message.cc", ++ "$protobuf_dir/compiler/csharp/csharp_message_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_primitive_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_reflection_class.cc", ++ "$protobuf_dir/compiler/csharp/csharp_repeated_enum_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_repeated_message_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_repeated_primitive_field.cc", ++ "$protobuf_dir/compiler/csharp/csharp_source_generator_base.cc", ++ "$protobuf_dir/compiler/csharp/csharp_wrapper_field.cc", ++ "$protobuf_dir/compiler/java/java_context.cc", ++ "$protobuf_dir/compiler/java/java_doc_comment.cc", ++ "$protobuf_dir/compiler/java/java_enum.cc", ++ "$protobuf_dir/compiler/java/java_enum_field.cc", ++ "$protobuf_dir/compiler/java/java_enum_field_lite.cc", ++ "$protobuf_dir/compiler/java/java_enum_lite.cc", ++ "$protobuf_dir/compiler/java/java_extension.cc", ++ "$protobuf_dir/compiler/java/java_extension_lite.cc", ++ "$protobuf_dir/compiler/java/java_field.cc", ++ "$protobuf_dir/compiler/java/java_file.cc", ++ "$protobuf_dir/compiler/java/java_generator.cc", ++ "$protobuf_dir/compiler/java/java_generator_factory.cc", ++ "$protobuf_dir/compiler/java/java_helpers.cc", ++ "$protobuf_dir/compiler/java/java_map_field.cc", ++ "$protobuf_dir/compiler/java/java_map_field_lite.cc", ++ "$protobuf_dir/compiler/java/java_message.cc", ++ "$protobuf_dir/compiler/java/java_message_builder.cc", ++ "$protobuf_dir/compiler/java/java_message_builder_lite.cc", ++ "$protobuf_dir/compiler/java/java_message_field.cc", ++ "$protobuf_dir/compiler/java/java_message_field_lite.cc", ++ "$protobuf_dir/compiler/java/java_message_lite.cc", ++ "$protobuf_dir/compiler/java/java_name_resolver.cc", ++ "$protobuf_dir/compiler/java/java_primitive_field.cc", ++ "$protobuf_dir/compiler/java/java_primitive_field_lite.cc", ++ "$protobuf_dir/compiler/java/java_service.cc", ++ "$protobuf_dir/compiler/java/java_shared_code_generator.cc", ++ "$protobuf_dir/compiler/java/java_string_field.cc", ++ "$protobuf_dir/compiler/java/java_string_field_lite.cc", ++ "$protobuf_dir/compiler/js/js_generator.cc", ++ "$protobuf_dir/compiler/js/well_known_types_embed.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_enum.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_enum_field.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_extension.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_field.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_file.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_generator.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_helpers.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_map_field.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_message.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_message_field.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_oneof.cc", ++ "$protobuf_dir/compiler/objectivec/objectivec_primitive_field.cc", ++ "$protobuf_dir/compiler/php/php_generator.cc", ++ "$protobuf_dir/compiler/plugin.cc", ++ "$protobuf_dir/compiler/plugin.pb.cc", ++ "$protobuf_dir/compiler/python/python_generator.cc", ++ "$protobuf_dir/compiler/ruby/ruby_generator.cc", ++ "$protobuf_dir/compiler/subprocess.cc", ++ "$protobuf_dir/compiler/zip_writer.cc", + ] + include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", ++ "$protobuf_dir/**/*.h", ++ "$protobuf_dir/**/*.inc", + "src", ++ ++ # "/opt/clang-mingw/i686-w64-mingw32/x86_64-linux-gnu", ++ # "/opt/clang-mingw/i686-w64-mingw32/x86_64-linux-gnu/c++/7", ++ # "/opt/clang-mingw/i686-w64-mingw32/include/c++/7", ++ # "/usr/include", ++ # "/usr/include/c++/7", ++ # "/usr/include/x86_64-linux-gnu/c++/7", + ] ++ if (!use_wasm) { ++ configs = default_configs ++ } + cflags_cc = [ + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-private-field", ++ ++ # "-std=gnu++17", + ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-Wno-unused-function", ++ "-std=c++17", ++ ++ # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + ] + + deps = [ +- ":protobuf_lite_static", +- ":protobuf_static", ++ ":protobuf", ++ ":protobuf_lite", + ] + + public_configs = [ ":protobuf_config" ] +- subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" +- part_name = "${OHOS_PROFILER_PART_NAME}" + } +-} +- +-# Only compile the plugin for the host architecture. +-if (current_toolchain == host_toolchain) { +- ohos_executable("protoc") { +- sources = [ "src/google/protobuf/compiler/main.cc" ] ++ executable("protoc") { ++ sources = [ "$protobuf_dir/compiler/main.cc" ] + include_dirs = [ +- "src/google/protobuf/**/*.h", +- "src/google/protobuf/**/*.inc", ++ "$protobuf_dir/**/*.h", ++ "$protobuf_dir/**/*.inc", + "src", ++ "/usr/include", + ] +- deps = [ ":protoc_static_lib" ] ++ deps = [ ":protoc_lib" ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + ] +- +- subsystem_name = "${OHOS_PROFILER_SUBSYS_NAME}" +- part_name = "${OHOS_PROFILER_PART_NAME}" + } + } diff --git a/trace_streamer/prebuilts/patch_sqlite/sqlite3build.gn b/trace_streamer/prebuilts/patch_sqlite/sqlite3build.gn new file mode 100755 index 0000000000000000000000000000000000000000..cc5b9467bc17fcbbbd48bb68fb9cd90e6fbde1cc --- /dev/null +++ b/trace_streamer/prebuilts/patch_sqlite/sqlite3build.gn @@ -0,0 +1,50 @@ +# 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") +config("sqlite_config") { + include_dirs = [ "include" ] + cflags = [ + "-Wno-shorten-64-to-32", + "-Wno-double-promotion", + "-Wno-disabled-macro-expansion", + "-Wno-float-equal", + "-Wno-cast-qual", + "-Wno-conversion", + "-Wno-cast-align", + "-Wno-unused-macros", + "-Wno-comma", + "-Wno-unreachable-code-break", + "-Wno-unreachable-code", + "-Wno-unreachable-code-return", + "-DSQLITE_THREADSAFE=1", + "-DQLITE_DEFAULT_MEMSTATUS=0", + "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", + "-DSQLITE_OMIT_DEPRECATED", + "-DSQLITE_OMIT_SHARED_CACHE", + "-DHAVE_USLEEP", + "-DHAVE_UTIME", + "-DSQLITE_BYTEORDER=1234", + "-DSQLITE_DEFAULT_AUTOVACUUM=0", + "-DSQLITE_DEFAULT_MMAP_SIZE=0", + "-DSQLITE_CORE", + "-DSQLITE_TEMP_STORE=3", + "-DSQLITE_OMIT_LOAD_EXTENSION", + ] +} +ohos_source_set("sqlite") { + subsystem_name = "trace_streamer" + part_name = "sqlite" + sources = [ "src/sqlite3.c" ] + public_configs = [ ":sqlite_config" ] +} diff --git a/trace_streamer/prebuilts/patch_sqlite/sqlite3build.gn.patch b/trace_streamer/prebuilts/patch_sqlite/sqlite3build.gn.patch new file mode 100644 index 0000000000000000000000000000000000000000..b813a4389abab7577b9aba23effd7e1e51bf7e87 --- /dev/null +++ b/trace_streamer/prebuilts/patch_sqlite/sqlite3build.gn.patch @@ -0,0 +1,206 @@ +--- third_party/third_party_sqlite/BUILD.gn 2023-01-04 16:21:39.506997978 +0800 ++++ prebuilts/buildsqlite/sqlite3build.gn 2022-11-29 14:31:52.359999197 +0800 +@@ -1,4 +1,4 @@ +-# Copyright (C) 2022 Huawei Device Co., Ltd. ++# 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 +@@ -12,169 +12,37 @@ + # limitations under the License. + + import("//build/ohos.gni") +- +-# Lets callers do '#include ' + config("sqlite_config") { +- include_dirs = [ +- "include", +- "//commonlibrary/c_utils/base/include", +- ] +-} +- +-# This is the configuration used to build sqlite itself. +-# It should not be needed outside of this library. +-config("sqlite3_private_config") { +- visibility = [ ":*" ] +- include_dirs = [ "include" ] +-} +- +-group("libsqlite") { +- public_deps = [ ":sqlite" ] +-} +- +-ohos_shared_library("sqlite") { +- visibility = [ "//foundation/distributeddatamgr/*" ] +- visibility += [ "//foundation/multimodalinput/*" ] +- visibility += +- [ "//hit/fuzzing_test/projects/multimodal_InputService_fuzzer/*" ] +- visibility += [ "//foundation/communication/*" ] +- visibility += [ "//build/common/*" ] +- visibility += [ ":*" ] +- visibility += [ "//base/security/permission/*" ] +- visibility += [ "//third_party/libsoup/*" ] +- visibility += [ "//base/security/access_token/*" ] +- visibility += [ "//foundation/resourceschedule/resource_schedule_service/*" ] +- visibility += [ "//base/update/dupdate_engine/services/engine/*" ] +- +- sources = [ "src/sqlite3.c" ] +- +- defines = [ +- "NDEBUG=1", +- "HAVE_USLEEP=1", +- "SQLITE_HAVE_ISNAN", +- "SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576", +- "SQLITE_THREADSAFE=2", +- "SQLITE_TEMP_STORE=3", +- "SQLITE_POWERSAFE_OVERWRITE=1", +- "SQLITE_DEFAULT_FILE_FORMAT=4", +- "SQLITE_DEFAULT_AUTOVACUUM=1", +- "SQLITE_ENABLE_MEMORY_MANAGEMENT=1", +- "SQLITE_ENABLE_FTS3", +- "SQLITE_ENABLE_FTS4", +- "SQLITE_ENABLE_FTS5", +- "SQLITE_OMIT_COMPILEOPTION_DIAGS", +- "SQLITE_OMIT_LOAD_EXTENSION", +- "SQLITE_DEFAULT_FILE_PERMISSIONS=0660", +- "SQLITE_SECURE_DELETE", +- "SQLITE_ENABLE_BATCH_ATOMIC_WRITE", +- "USE_PREAD64", +- "fdatasync=fdatasync", +- "HAVE_MALLOC_H=1", +- "HAVE_MALLOC_USABLE_SIZE", +- "SQLITE_DIRECT_OVERFLOW_READ", +- "SQLITE_HAS_CODEC", +- "SQLITE_EXPORT_SYMBOLS", +- "SQLITE_SHARED_BLOCK_OPTIMIZATION", +- "SQLITE_CODEC_ATTACH_CHANGED", +- "SQLITE_ENABLE_DROPTABLE_CALLBACK", +- ] +- cflags_c = [ +- "-fvisibility=hidden", +- "-Wno-implicit-fallthrough", +- ] +- ldflags = [ "-Wl,--exclude-libs,ALL" ] +- deps = [ "//third_party/openssl:libcrypto_shared" ] +- public_configs = [ ":sqlite_config" ] +- configs = [ ":sqlite3_private_config" ] +- part_name = "common" +- install_images = [ system_base_dir ] +- relative_install_dir = "platformsdk" +- external_deps = [ "c_utils:utils" ] +-} +- +-ohos_executable("sqlite3") { + include_dirs = [ "include" ] +- sources = [ +- "src/shell.c", +- "src/sqlite3.c", +- ] +- +- defines = [ +- "NDEBUG=1", +- "HAVE_USLEEP=1", +- "SQLITE_HAVE_ISNAN", +- "SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576", +- "SQLITE_THREADSAFE=2", +- "SQLITE_TEMP_STORE=3", +- "SQLITE_POWERSAFE_OVERWRITE=1", +- "SQLITE_DEFAULT_FILE_FORMAT=4", +- "SQLITE_DEFAULT_AUTOVACUUM=1", +- "SQLITE_ENABLE_MEMORY_MANAGEMENT=1", +- "SQLITE_ENABLE_FTS3", +- "SQLITE_ENABLE_FTS4", +- "SQLITE_OMIT_COMPILEOPTION_DIAGS", +- "SQLITE_OMIT_LOAD_EXTENSION", +- "SQLITE_DEFAULT_FILE_PERMISSIONS=0600", +- "SQLITE_SECURE_DELETE", +- "SQLITE_ENABLE_BATCH_ATOMIC_WRITE", +- "USE_PREAD64", +- "fdatasync=fdatasync", +- "SQLITE_DIRECT_OVERFLOW_READ", +- "SQLITE_SHARED_BLOCK_OPTIMIZATION", +- ] +- + cflags = [ +- "-Wno-error=implicit-function-declaration", +- "-Wno-implicit-fallthrough", ++ "-Wno-shorten-64-to-32", ++ "-Wno-double-promotion", ++ "-Wno-disabled-macro-expansion", ++ "-Wno-float-equal", ++ "-Wno-cast-qual", ++ "-Wno-conversion", ++ "-Wno-cast-align", ++ "-Wno-unused-macros", ++ "-Wno-comma", ++ "-Wno-unreachable-code-break", ++ "-Wno-unreachable-code", ++ "-Wno-unreachable-code-return", ++ "-DSQLITE_THREADSAFE=1", ++ "-DQLITE_DEFAULT_MEMSTATUS=0", ++ "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", ++ "-DSQLITE_OMIT_DEPRECATED", ++ "-DSQLITE_OMIT_SHARED_CACHE", ++ "-DHAVE_USLEEP", ++ "-DHAVE_UTIME", ++ "-DSQLITE_BYTEORDER=1234", ++ "-DSQLITE_DEFAULT_AUTOVACUUM=0", ++ "-DSQLITE_DEFAULT_MMAP_SIZE=0", ++ "-DSQLITE_CORE", ++ "-DSQLITE_TEMP_STORE=3", ++ "-DSQLITE_OMIT_LOAD_EXTENSION", + ] + } +- +-if (is_mingw || is_mac) { +- ohos_shared_library("sqlite_sdk") { +- include_dirs = [ +- "include", +- "//third_party/bounds_checking_function/include", +- "//third_party/openssl/include", +- ] +- +- sources = [ "src/sqlite3.c" ] +- +- defines = [ +- "NDEBUG=1", +- "HAVE_USLEEP=1", +- "SQLITE_HAVE_ISNAN", +- "SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576", +- "SQLITE_THREADSAFE=2", +- "SQLITE_TEMP_STORE=3", +- "SQLITE_POWERSAFE_OVERWRITE=1", +- "SQLITE_DEFAULT_FILE_FORMAT=4", +- "SQLITE_DEFAULT_AUTOVACUUM=1", +- "SQLITE_ENABLE_MEMORY_MANAGEMENT=1", +- "SQLITE_ENABLE_FTS3", +- "SQLITE_ENABLE_FTS4", +- "SQLITE_OMIT_COMPILEOPTION_DIAGS", +- "SQLITE_OMIT_LOAD_EXTENSION", +- "SQLITE_DEFAULT_FILE_PERMISSIONS=0600", +- "SQLITE_SECURE_DELETE", +- "SQLITE_ENABLE_BATCH_ATOMIC_WRITE", +- "USE_PREAD64", +- "fdatasync=fdatasync", +- "SQLITE_DIRECT_OVERFLOW_READ", +- "SQLITE_HAS_CODEC", +- "SQLITE_EXPORT_SYMBOLS", +- "SQLITE_SHARED_BLOCK_OPTIMIZATION", +- ] +- remove_configs = [ "//build/config/compiler:chromium_code" ] +- deps = [ +- "//third_party/bounds_checking_function:libsec_shared", +- "//third_party/openssl:libcrypto_restool", +- ] +- if (is_mingw) { +- libs = [ "//prebuilts/mingw-w64/ohos/linux-x86_64/clang-mingw/x86_64-w64-mingw32/lib/libws2_32.a" ] +- } +- cflags = [ +- "-Wno-error=implicit-function-declaration", +- "-Wno-implicit-fallthrough", +- ] +- } ++ohos_source_set("sqlite") { ++ sources = [ "src/sqlite3.c" ] ++ public_configs = [ ":sqlite_config" ] + } diff --git a/trace_streamer/prebuilts/protos/BUILD.gn b/trace_streamer/prebuilts/protos/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..2f12454ebccce8aba84042edfd30c85fbd756fc7 --- /dev/null +++ b/trace_streamer/prebuilts/protos/BUILD.gn @@ -0,0 +1,173 @@ +# 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("../../src/ts.gni") +OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR = "//third_party/protobuf" +proto_dir = "//third_party/protogen" +services_dir = "$proto_dir/services" +ftrace_data_dir = "$proto_dir/types/plugins/ftrace_data/${kernel_version}" +memory_data_dir = "$proto_dir/types/plugins/memory_data" +hilog_data_dir = "$proto_dir/types/plugins/hilog_data" +native_hook_dir = "$proto_dir/types/plugins/native_hook" +hidump_data_dir = "$proto_dir/types/plugins/hidump_data" +network_data_dir = "$proto_dir/types/plugins/network_data" +cpu_data_dir = "$proto_dir/types/plugins/cpu_data" +diskio_data_dir = "$proto_dir/types/plugins/diskio_data" +process_data_dir = "$proto_dir/types/plugins/process_data" +hisysevent_data_dir = "$proto_dir/types/plugins/hisysevent_data" +config("ts_proto_include_config") { + include_dirs = [ + "$ftrace_data_dir", + "$memory_data_dir", + "$hilog_data_dir", + "$native_hook_dir", + "$hidump_data_dir", + "$hisysevent_data_dir", + ] +} +source_set("ts_proto_data_cpp") { + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + cflags = [ + "-ftrapv", + "-D_FORTIFY_SOURCE=2 -O2", + "-Wno-zero-length-array", + "-std=c++17", + ] + + if (!is_win) { + cflags += [ + "-fPIE", + "-fPIC", + ] + } + if (!use_wasm) { + cflags += [ + "-fstack-protector-strong", # + "-fstack-protector-all", + ] + } + + public_configs = [ ":ts_proto_include_config" ] + if (is_pbdecoder) { + sources = [ + "$ftrace_data_dir/binder.pb.cc", + "$ftrace_data_dir/block.pb.cc", + "$ftrace_data_dir/cgroup.pb.cc", + "$ftrace_data_dir/clk.pb.cc", + "$ftrace_data_dir/compaction.pb.cc", + "$ftrace_data_dir/cpuhp.pb.cc", + "$ftrace_data_dir/dma_fence.pb.cc", + "$ftrace_data_dir/ext4.pb.cc", + "$ftrace_data_dir/filelock.pb.cc", + "$ftrace_data_dir/filemap.pb.cc", + "$ftrace_data_dir/ftrace.pb.cc", + "$ftrace_data_dir/ftrace_event.pb.cc", + "$ftrace_data_dir/gpio.pb.cc", + "$ftrace_data_dir/i2c.pb.cc", + "$ftrace_data_dir/ipi.pb.cc", + "$ftrace_data_dir/irq.pb.cc", + "$ftrace_data_dir/kmem.pb.cc", + "$ftrace_data_dir/net.pb.cc", + + # "$ftrace_data_dir/mmc.pb.cc", + # "$ftrace_data_dir/f2fs.pb.cc", + # "$ftrace_data_dir/gpu_mem.pb.cc", + # "$ftrace_data_dir/regulator.pb.cc", + "$ftrace_data_dir/oom.pb.cc", + "$ftrace_data_dir/pagemap.pb.cc", + "$ftrace_data_dir/power.pb.cc", + "$ftrace_data_dir/printk.pb.cc", + "$ftrace_data_dir/raw_syscalls.pb.cc", + "$ftrace_data_dir/rcu.pb.cc", + "$ftrace_data_dir/sched.pb.cc", + "$ftrace_data_dir/signal.pb.cc", + "$ftrace_data_dir/sunrpc.pb.cc", + "$ftrace_data_dir/task.pb.cc", + "$ftrace_data_dir/timer.pb.cc", + "$ftrace_data_dir/trace_plugin_result.pb.cc", + "$ftrace_data_dir/v4l2.pb.cc", + "$ftrace_data_dir/vmscan.pb.cc", + "$ftrace_data_dir/workqueue.pb.cc", + "$ftrace_data_dir/writeback.pb.cc", + "$hidump_data_dir/hidump_plugin_result.pb.cc", + "$hilog_data_dir/hilog_plugin_result.pb.cc", + "$memory_data_dir/memory_plugin_common.pb.cc", + "$memory_data_dir/memory_plugin_config.pb.cc", + "$memory_data_dir/memory_plugin_result.pb.cc", + "$native_hook_dir/native_hook_config.pb.cc", + "$native_hook_dir/native_hook_result.pb.cc", + "${cpu_data_dir}/cpu_plugin_result.pb.cc", + "${diskio_data_dir}/diskio_plugin_result.pb.cc", + "${hisysevent_data_dir}/hisysevent_plugin_config.pb.cc", + "${hisysevent_data_dir}/hisysevent_plugin_result.pb.cc", + "${network_data_dir}/network_plugin_result.pb.cc", + "${process_data_dir}/process_plugin_result.pb.cc", + "${services_dir}/common_types.pb.cc", + ] + } else { + sources = [ + "$ftrace_data_dir/binder.pbreader.h", + "$ftrace_data_dir/block.pbreader.h", + "$ftrace_data_dir/cgroup.pbreader.h", + "$ftrace_data_dir/clk.pbreader.h", + "$ftrace_data_dir/compaction.pbreader.h", + "$ftrace_data_dir/cpuhp.pbreader.h", + "$ftrace_data_dir/dma_fence.pbreader.h", + "$ftrace_data_dir/ext4.pbreader.h", + "$ftrace_data_dir/filelock.pbreader.h", + "$ftrace_data_dir/filemap.pbreader.h", + "$ftrace_data_dir/ftrace.pbreader.h", + "$ftrace_data_dir/ftrace_event.pbreader.h", + "$ftrace_data_dir/gpio.pbreader.h", + "$ftrace_data_dir/i2c.pbreader.h", + "$ftrace_data_dir/ipi.pbreader.h", + "$ftrace_data_dir/irq.pbreader.h", + "$ftrace_data_dir/kmem.pbreader.h", + "$ftrace_data_dir/net.pbreader.h", + "$ftrace_data_dir/oom.pbreader.h", + "$ftrace_data_dir/pagemap.pbreader.h", + "$ftrace_data_dir/power.pbreader.h", + "$ftrace_data_dir/printk.pbreader.h", + "$ftrace_data_dir/raw_syscalls.pbreader.h", + "$ftrace_data_dir/rcu.pbreader.h", + "$ftrace_data_dir/sched.pbreader.h", + "$ftrace_data_dir/signal.pbreader.h", + "$ftrace_data_dir/sunrpc.pbreader.h", + "$ftrace_data_dir/task.pbreader.h", + "$ftrace_data_dir/timer.pbreader.h", + "$ftrace_data_dir/trace_plugin_result.pbreader.h", + "$ftrace_data_dir/v4l2.pbreader.h", + "$ftrace_data_dir/vmscan.pbreader.h", + "$ftrace_data_dir/workqueue.pbreader.h", + "$ftrace_data_dir/writeback.pbreader.h", + "$hidump_data_dir/hidump_plugin_result.pbreader.h", + "$hilog_data_dir/hilog_plugin_result.pbreader.h", + "$memory_data_dir/memory_plugin_common.pbreader.h", + "$memory_data_dir/memory_plugin_config.pbreader.h", + "$memory_data_dir/memory_plugin_result.pbreader.h", + "$native_hook_dir/native_hook_config.pbreader.h", + "$native_hook_dir/native_hook_result.pbreader.h", + "${cpu_data_dir}/cpu_plugin_result.pbreader.h", + "${diskio_data_dir}/diskio_plugin_result.pbreader.h", + "${hisysevent_data_dir}/hisysevent_plugin_config.pbreader.h", + "${hisysevent_data_dir}/hisysevent_plugin_result.pbreader.h", + "${network_data_dir}/network_plugin_result.pbreader.h", + "${process_data_dir}/process_plugin_result.pbreader.h", + "${services_dir}/common_types.pbreader.h", + ] + } +} diff --git a/trace_streamer/sdk/demo_sdk/BUILD.gn b/trace_streamer/sdk/demo_sdk/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..9100051f2184d2f5a0c642b4a911660a99f58b7b --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/BUILD.gn @@ -0,0 +1,181 @@ +# 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("ts.gni") +if (use_wasm) { + import("../../gn/wasm.gni") +} +if (use_wasm) { + ohos_source_set("trace_streamer_sdk_builtin") { + subsystem_name = "trace_streamer" + part_name = "trace_streamer_sdk_builtin" + sources = [] + include_dirs = [] + deps = [] + public_deps = [] + } +} +ohos_source_set("lib") { + subsystem_name = "trace_streamer" + part_name = "lib" + sources = [ "main.cpp" ] + deps = [ + ":trace_streamer_sdk", + "protos:ts_proto_data_cpp", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + include_dirs = [ + "base", + "..", + "trace_streamer", + "table", + "trace_data", + "include", + "plugin", + "filter", + "rpc", + "./", + "parser", + "cfg", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + ] + if (with_perf) { + include_dirs += [] + } + public_deps = [] +} +ohos_source_set("trace_streamer_sdk") { + subsystem_name = "trace_streamer" + part_name = "trace_streamer_sdk" + sources = [ + "filter/clock_filter.cpp", + "filter/clock_filter.h", + "parser/event_parser_base.cpp", + "parser/event_parser_base.h", + "parser/htrace_plugin_time_parser.cpp", + "rpc/http_socket.cpp", + "rpc/rpc_server.cpp", + "rpc/rpc_server.h", + "sdk/sdk_data_parser.cpp", + "sdk/sdk_data_parser.h", + "sdk/ts_sdk_api.cpp", + "sdk/ts_sdk_api.h", + "table/filter_constraints.cpp", + "table/gpu_counter_object_table.cpp", + "table/gpu_counter_object_table.h", + "table/gpu_counter_table.cpp", + "table/gpu_counter_table.h", + "table/index_map.cpp", + "table/index_map.h", + "table/meta_table.cpp", + "table/meta_table.h", + "table/slice_object_table.cpp", + "table/slice_object_table.h", + "table/slice_table.cpp", + "table/slice_table.h", + "table/table_base.cpp", + "trace_data/trace_data_cache.cpp", + "trace_data/trace_data_cache.h", + "trace_data/trace_data_cache_base.cpp", + "trace_data/trace_data_cache_base.h", + "trace_data/trace_data_cache_reader.cpp", + "trace_data/trace_data_cache_reader.h", + "trace_data/trace_data_cache_writer.cpp", + "trace_data/trace_data_cache_writer.h", + "trace_data/trace_data_db.cpp", + "trace_data/trace_data_db.h", + "trace_data/trace_stdtype.cpp", + "trace_data/trace_stdtype.h", + "trace_streamer/trace_streamer_selector.cpp", + "trace_streamer/trace_streamer_selector.h", + ] + include_dirs = [ + "base", + "..", + "trace_streamer", + "filter", + "table", + "trace_data", + "include", + "plugin", + "rpc", + "sdk", + "./", + "parser", + "cfg", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "//third_party/protobuf/src", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + ] + if (!use_wasm) { + include_dirs += [ + "//third_party/libunwind/include", + "//third_party/libunwind/src", + ] + } + if (with_perf) { + sources += [] + include_dirs += [] + } + deps = [ + "base:base", + "ext:sqliteext", + "include:ibase", + "plugin:sdk_plugin", + "protos:ts_proto_data_cpp", + "//third_party/sqlite:sqlite", + ] + if (with_perf) { + } + + if (use_wasm || enable_ts_utest) { + sources += [ + "sdk/wasm_func.cpp", + "sdk/wasm_func.h", + ] + } + cflags = [ "-std=c++17" ] + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "-std=c++17", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } + public_deps = [] +} +if (use_wasm) { + wasm_lib("trace_streamer_sdk_builtin_wasm") { + name = "trace_streamer_sdk_builtin" + deps = [ ":lib" ] + } +} else { + if (!is_test && !is_fuzz) { + executable("trace_streamer111") { + deps = [ ":lib" ] + } + } +} diff --git a/trace_streamer/sdk/demo_sdk/base/BUILD.gn b/trace_streamer/sdk/demo_sdk/base/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..684a0febf00bc557df27daf3045cd0927580c5be --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("../ts.gni") +ohos_source_set("base") { + subsystem_name = "trace_streamer" + part_name = "sdk_base" + deps = [] + public_deps = [ "../include:ibase" ] + include_dirs = [ "../include" ] + sources = [ + # "codec_cov.cpp", + # "file.cpp", + "log.cpp", + "meta.cpp", + + # "parting_string.cpp", + "string_help.cpp", + ] + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } +} diff --git a/trace_streamer/sdk/demo_sdk/base/args_set.h b/trace_streamer/sdk/demo_sdk/base/args_set.h new file mode 100644 index 0000000000000000000000000000000000000000..6148fd25be100805820643594e7a5a9bfc27174b --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/args_set.h @@ -0,0 +1,50 @@ +/* + * 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 SRC_TRACE_BASE_ARGS_SET_H +#define SRC_TRACE_BASE_ARGS_SET_H + +#include +#include +#include "ts_common.h" +namespace SysTuning { +namespace TraceStreamer { +class ArgsSet { +public: + ArgsSet() {} + ~ArgsSet() {} + ArgsSet& operator=(const ArgsSet& other) + { + this->valuesMap_ = other.valuesMap_; + this->argSetId_ = other.argSetId_; + this->sliceId_ = other.sliceId_; + this->inserted_ = other.inserted_; + return *this; + } + void AppendArg(DataIndex dataIndex, BaseDataType datatype, uint64_t value) + { + ArgsData data; + data.type = datatype; + data.value = value; + valuesMap_.emplace(dataIndex, data); + } + std::map valuesMap_; + uint32_t argSetId_ = 0; + uint32_t sliceId_ = 0; + bool inserted_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/base/log.cpp b/trace_streamer/sdk/demo_sdk/base/log.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d167a90cb4f5f1678b59e23518ddce9873b89d1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/log.cpp @@ -0,0 +1,17 @@ +/* + * 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 "log.h" +bool g_cleanMode = false; diff --git a/trace_streamer/sdk/demo_sdk/base/meta.cpp b/trace_streamer/sdk/demo_sdk/base/meta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..264905781ff1b9696cfbe51d25f8f0b6b4326787 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/meta.cpp @@ -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. + */ +#include "meta.h" +size_t g_loadSize = 0; +std::string SDK_VERSION = "1.0.2"; // version +std::string SDK_PUBLISHVERSION = "2023/3/13"; // publish datetime diff --git a/trace_streamer/sdk/demo_sdk/base/meta.h b/trace_streamer/sdk/demo_sdk/base/meta.h new file mode 100644 index 0000000000000000000000000000000000000000..41d0de858de99ebc1994063f118c23d2a03c89da --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/meta.h @@ -0,0 +1,23 @@ +/* + * 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 META_H +#define META_H +#include +#include +extern size_t g_loadSize; +extern std::string SDK_VERSION; // version +extern std::string SDK_PUBLISHVERSION; // publish datetime +#endif diff --git a/trace_streamer/sdk/demo_sdk/base/quatra_map.h b/trace_streamer/sdk/demo_sdk/base/quatra_map.h new file mode 100644 index 0000000000000000000000000000000000000000..daddea567edb85d34f79c369020cc4a7f114e26c --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/quatra_map.h @@ -0,0 +1,90 @@ +/* + * 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 SRC_TRACE_BASE_QUATRAMAP_H +#define SRC_TRACE_BASE_QUATRAMAP_H + +#include "triple_map.h" + +template +class QuatraMap { +public: + QuatraMap(T5 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T5 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Insert(t2, t3, t4, t5); + } else { + TripleMap mm(invalidValue_); + mm.Insert(t2, t3, t4, t5); + internalMap_.insert(std::make_pair(t1, mm)); + } + } + T5 Find(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return (*streamIdHookidMap).second.Find(t2, t3, t4); + } else { + return invalidValue_; + } + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2); + } + } + void Erase(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3); + } + } + void Erase(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3, t4); + } + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T5 invalidValue_; +}; + +#endif // SRC_TRACE_BASE_QUATRAMAP_H diff --git a/trace_streamer/sdk/demo_sdk/base/string_help.cpp b/trace_streamer/sdk/demo_sdk/base/string_help.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41a41329907e61d1920b130842edaf4c6a40d4f6 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/string_help.cpp @@ -0,0 +1,81 @@ +/* + * 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 "string_help.h" +#include +#include +#include +#include +namespace SysTuning { +namespace base { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +#if !is_mingw +int32_t memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize) +{ + if (srcSize > destSize || src == nullptr || dest == nullptr) { + return -1; + } else { + if (!memcpy(dest, src, srcSize)) { + printf("memcpy fail\n"); + return -1; + } + } + return 0; +} +int32_t sscanf_s(const char* buffer, const char* format, ...) +{ + va_list ap; + __builtin_va_start(ap, format); + int32_t ret = scanf(buffer, format, ap); + __builtin_va_end(ap); + return ret; +} + +int32_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count) +{ + return memcpy_s(strDest, destMax, strSrc, count); +} +#endif +void* memset_s(void* dest, size_t destSize, int32_t ch, size_t n) +{ + UNUSED(destSize); + UNUSED(ch); + return memset(dest, 0, n); +} + +int32_t snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...) +{ + UNUSED(count); + int32_t ret; + va_list ap; + __builtin_va_start(ap, format); + ret = vsnprintf(strDest, destMax, format, ap); + __builtin_va_end(ap); + return ret; +} + +int32_t sprintf_s(char* strDest, size_t destMax, const char* format, ...) +{ + UNUSED(destMax); + va_list ap; + __builtin_va_start(ap, format); + int32_t ret = sprintf(strDest, format, ap); + __builtin_va_end(ap); + return ret; +} +} // namespace base +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/base/string_help.h b/trace_streamer/sdk/demo_sdk/base/string_help.h new file mode 100644 index 0000000000000000000000000000000000000000..c2048609f18db7f4680f997f8710f3d6346b0a78 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/string_help.h @@ -0,0 +1,32 @@ +/* + * 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 SRC_TRACE_BASE_STRINGHELP_H +#define SRC_TRACE_BASE_STRINGHELP_H + +#include +#include +namespace SysTuning { +namespace base { +#if !is_mingw +int32_t memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize); +int32_t sscanf_s(const char* buffer, const char* format, ...); +int32_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count); +#endif +void* memset_s(void* dest, size_t destSize, int32_t ch, size_t n); +int32_t snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...); +int32_t sprintf_s(char* strDest, size_t destMax, const char* format, ...); +} // namespace base +} // namespace SysTuning +#endif // SRC_TRACE_BASE_STRINGHELP_H diff --git a/trace_streamer/sdk/demo_sdk/base/triple_map.h b/trace_streamer/sdk/demo_sdk/base/triple_map.h new file mode 100644 index 0000000000000000000000000000000000000000..ce3f75120bdebae6a0346141ef42c1ebdab631cc --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/triple_map.h @@ -0,0 +1,83 @@ +/* + * 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 SRC_TRACE_BASE_TRIPLEMAP_H +#define SRC_TRACE_BASE_TRIPLEMAP_H + +#include "double_map.h" + +template +class TripleMap { +public: + TripleMap(T4 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T4 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Insert(t2, t3, t4); + } else { + DoubleMap mm(invalidValue_); + mm.Insert(t2, t3, t4); + internalMap_.insert(std::make_pair(t1, mm)); + } + } + T4 Find(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return (*streamIdHookidMap).second.Find(t2, t3); + } else { + return invalidValue_; + } + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2); + } + } + void Erase(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3); + } + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T4 invalidValue_; +}; + +#endif // SRC_TRACE_BASE_TRIPLEMAP_H diff --git a/trace_streamer/sdk/demo_sdk/base/ts_common.h b/trace_streamer/sdk/demo_sdk/base/ts_common.h new file mode 100644 index 0000000000000000000000000000000000000000..d111412f181aee4054be54c414a3eb2974828e10 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/base/ts_common.h @@ -0,0 +1,120 @@ +/* + * 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 SRC_TRACE_BASE_TS_COMMON_H +#define SRC_TRACE_BASE_TS_COMMON_H + +#include +#include +#include +#include + +const uint64_t INVALID_UTID = std::numeric_limits::max(); +const uint64_t INVALID_UINT64 = std::numeric_limits::max(); +const uint64_t MAX_UINT32 = std::numeric_limits::max(); +const uint64_t MAX_UINT64 = std::numeric_limits::max(); +const uint32_t INVALID_UINT32 = std::numeric_limits::max(); +const uint32_t INVALID_INT32 = std::numeric_limits::max(); +const uint64_t INVALID_DATAINDEX = std::numeric_limits::max(); +const size_t MAX_SIZE_T = std::numeric_limits::max(); +const uint32_t INVALID_ID = std::numeric_limits::max(); +const uint64_t SEC_TO_NS = 1000 * 1000 * 1000; +const int32_t STR_DEFAULT_LEN = -1; +const auto INVALID_CPU = INVALID_UINT32; +const auto INVALID_TIME = INVALID_UINT64; +enum BuiltinClocks { + TS_CLOCK_UNKNOW = 0, + TS_CLOCK_BOOTTIME = 1, + TS_CLOCK_REALTIME = 2, + TS_CLOCK_REALTIME_COARSE = 3, + TS_MONOTONIC = 4, + TS_MONOTONIC_COARSE = 5, + TS_MONOTONIC_RAW = 6, +}; + +enum RefType { + K_REF_NO_REF = 0, + K_REF_ITID = 1, + K_REF_CPUID = 2, + K_REF_IRQ = 3, + K_REF_SOFT_IRQ = 4, + K_REF_IPID = 5, + K_REF_ITID_LOOKUP_IPID = 6, + K_REF_MAX +}; + +enum EndState { + // (R) ready state or running state, the process is ready to run, but not necessarily occupying the CPU + TASK_RUNNABLE = 0, + // (S) Indicates that the process is in light sleep, waiting for the resource state, and can respond to the signal. + // Generally, the process actively sleeps into 'S' state. + TASK_INTERRUPTIBLE = 1, + // (D) Indicates that the process is in deep sleep, waiting for resources, and does not respond to signals. + // Typical scenario: process acquisition semaphore blocking. + TASK_UNINTERRUPTIBLE = 2, + // (Running) Indicates that the thread is running + TASK_RUNNING = 3, + // (I) Thread in interrupt state + TASK_INTERRUPTED = 4, + // (T) Task being traced + TASK_TRACED = 8, + // (X) Exit status, the process is about to be destroyed. + TASK_EXIT_DEAD = 16, + // (Z) Zombie state + TASK_ZOMBIE = 32, + // (I) clone thread + TASK_CLONE = 64, + // (K) Process killed + TASK_KILLED = 128, + // (DK) + TASK_DK = 130, + // the process is being debug now + TASK_TRACED_KILL = 136, + // (W) The process is in a deep sleep state and will be killed directly after waking up + TASK_WAKEKILL = 256, + // (R+) Process groups in the foreground + TASK_FOREGROUND = 2048, + TASK_MAX = 4096, + TASK_INVALID = 9999 +}; +enum TSLogLevel { + TS_DEBUG = 68, // Debug + TS_ERROR = 69, // Error + TS_INFO = 73, // Info + TS_VERBOSE = 86, // Verbose + TS_WARN = 87 // Warn +}; +enum SchedWakeType { + SCHED_WAKING = 0, // sched_waking + SCHED_WAKEUP = 1, // sched_wakeup +}; +using DataIndex = uint64_t; +using TableRowId = uint32_t; +using InternalPid = uint32_t; +using InternalTid = uint32_t; +using InternalTime = uint64_t; +using FilterId = uint32_t; +using InternalCpu = uint32_t; // how many cpus? could change to int8_t? + +enum BaseDataType { BASE_DATA_TYPE_INT, BASE_DATA_TYPE_STRING, BASE_DATA_TYPE_DOUBLE, BASE_DATA_TYPE_BOOLEAN }; +namespace SysTuning { +namespace TraceStreamer { +struct ArgsData { + BaseDataType type; + int64_t value; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/doc/TraceStreamerSDK.md b/trace_streamer/sdk/demo_sdk/doc/TraceStreamerSDK.md new file mode 100644 index 0000000000000000000000000000000000000000..31575ffd7c84185b8dd4aba2de4eb8943550042d --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/doc/TraceStreamerSDK.md @@ -0,0 +1,325 @@ +# 1、SDK接口说明 + +### 1.1 SDK对开发者开放的接口(位于文件sdk/sdk/ts_sdk_api.h,示例代码位于plugin目录下) + +###### **设置对应的表名称** ,用户可选择调用。如不调用该接口,则默认的表名分别为counter_table, gpu_counter_object, slice_table, slice_object_table + +`counterObjectTableName: countObject表名` + +`counterTableName: counterTableName表名` + +`sliceObjectTableName: sliceObjectTableName表名` + +`sliceTableName: sliceTableName表名` + +``` +int SDK_SetTableName(std::string counterObjectTableName, std::string +counterTableName, std::string sliceObjectTableName, std::string +sliceTableName); +``` + +###### 添加counter业务ID和名称对应关系表。 + +`counterId: counter唯一标识。` + +`columnName: counter名称。` + +`return: 成功返回0,失败返回-1。` + +``` +int SDK_AppendCounterObject(int counterId, const char* columnName) +``` + +###### ******添加counter****业务表字段** + +`counterId: counter唯一标识` + +`ts: 时间戳` + +`value: counter值` + +`return: 成功返回0,失败返回-1` + +``` +int SDK_AppendCounter (int counterId, uint64_t ts, int value) +``` + +###### **添加slice业务ID和名称对应关系表** + +`sliceId: slice唯一标识` + +`columnName: slice名称` + +`return: 成功返回0,失败返回-1` + +``` +int SDK_AppendSliceObject(int sliceId, const char* columnName) +``` + +###### ******添加slice****业务表字段** + +`sliceId: slice唯一标识` + +`ts: 起始时间戳` + +`endTs: 结束时间戳` + +`value: slice值` + +`return: 成功返回0,失败返回-1` + +``` +int SDK_AppendSlice(int sliceId, uint64_t ts, uint64_t endTs, int value) +``` + +### 1.2 TraceStreamer SDK需用户实现的功能(plugin目录下) + +###### 使用TraceStreamerSDK,用户需要实现2个功能: + +`1. sdk_plugin_init_table_name:设置用来保存slice数据和counter数据的4张数据表;` + +`2. sdk_plugin_data_parser:实现数据解析,并在解析到对应的数据时,使用1.1中的api即可,之后,上层IDE使用目录2中的方法,即可实现TraceStreamer和第三方插件(基于SDK开发)的数据互通。` + +### 1.3 TraceStreamer SDK修改配置项 + +如需修改界面展示名称或其他配置项,可在目录sdk/sdk/sdk_data_parser.h中修改86行后settingConfig之后的配置。 + +![1678686879388](image/TraceStreamerSDK/1678686879388.png) + +### 1.4 不同名称的sdk编译方法 + +###### 1.4.1 新增proto文件后,如果文件格式和mockdata一致,则只需要修改wasm编译名称。 以下是需要修改的脚本文件: + +1. `最外层BUILD.gn文件中24行修改为需要生成的wasm名称。` + + ![1678687125370](image/TraceStreamerSDK/1678687125370.png) +2. `sdk/BUILD.gn文件20行名称修改为需要生成的wasm名称。` + + ![1678687179357](image/TraceStreamerSDK/1678687179357.png) +3. `sdk/BUILD.gn文件163行后wasm_lib和name对应的参数修改为需要生成的wasm名称。` + + ![1678687231618](image/TraceStreamerSDK/1678687231618.png) + +###### 1.4.2 新增proto文件后,如果proto文件格式和原有的mockdata格式不一致,则需要用户自己通过proto文件导出对应的pb.cc文件,并完成数据解析代码。以下是导出proto文件需要修改的脚本。 + +1. `sdk/BUILD.gn文件35行后include_dirs中新增对应的gpu_data目录。` + ![1678687426565](image/TraceStreamerSDK/1678687426565.png) +2. `sdk/BUILD.gn文件102行后include_dirs中新增对应的gpu_data目录。` + ![1678687469294](image/TraceStreamerSDK/1678687469294.png) +3. `sdk/plugin/BUILD.gn文件中21行include_dirs中新增对应的gpu_data目录` + ![1678687498819](image/TraceStreamerSDK/1678687498819.png) +4. `sdk/protos/BUILD.gn文件中17行下面增加gpu_data目录` + + ![1678687534793](image/TraceStreamerSDK/1678687534793.png) +5. `sdk/protos/BUILD.gn文件中49行sources内增加proto文件生成的pb.cc文件名称(该文件sdk/protos/protogen.sh生成,和proto文件只有后缀不同)` + + ![1678687580903](image/TraceStreamerSDK/1678687580903.png) +6. `sdk/protos/protogen.sh文件中23行后增加gpu_data路径定义,25行proto_array中增加proto文件路径` + + ![1678687619286](image/TraceStreamerSDK/1678687619286.png) +7. `sdk/protos/protogen.sh文件中35行新增gpu_data路径定义。` + + ![1678687656154](image/TraceStreamerSDK/1678687656154.png) + +修改完成后,执行./sdk/protos/protogen.sh,即可生成对应的gpu_plugin_result.pb.cc文件,路径为third_party/protogen/types/plugins/gpu_data。完成1.2的解析功能后,按照1.4.1修改编译的wasm名称,执行./build.sh sdkdemo,即可得到trace_streamer_sdk_gpu_builtin.js和trace_streamer_sdk_gpu_builtin_wasm文件。 + +# 2、 其他 + +### 2.1 TraceStreamer WebAssembly接口模式 + +通过封装相关数据解析接口,并且使用emsdk作为编译工具,本应用可以嵌入浏览器中运行。提供了如下接口: + +###### **初始化wasm,在JS中注册回调函数,并返回一段可复用的内存空间,由JS调用。** + +`replyFunction: 回调函数` + +`reqBufferSize: 返回的内存长度。` + +`return: 返回一段内存地址给JS。` + +``` +EMSCRIPTEN_KEEPALIVE uint8_t* Initialize(ReplyFunction replyFunction, uint32_t reqBufferSize) +``` + +###### 更新起始结束时间,由JS调用。 + +`len: 起始和结束时间组成的字符串长度` + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int UpdateTraceTime(int len) +``` + +###### **设置ts和第三方wasm通信的回调函数,并返回一段内存,由JS调用。** + +`sendDataCallBack:与第三方wasm通信的回调函数。` + +`reqBufferSize: 返回的内存长度。` + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE uint8_t* TraceStreamer_Set_ThirdParty_DataDealer(SendDataCallBack sendDataCallBack, uint32_t reqBufferSize) +``` + +###### **TS的数据解析接口,由JS调用。** + +`dataLen: 需要解析的数据源长度。` + +`return: 成功返回0,失败返回-1。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerParseDataEx(int dataLen) +``` + +###### **TS停止解析数据,由JS调用。** + +`return: 成功返回0,失败返回-1。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerParseDataOver() +``` + +###### **数据库操作接口,由JS调用。** + +`sqlLen: 需要执行的操作类sql语句长度。` + +`return: 成功返回0,失败返回-1。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlOperateEx(int sqlLen) +``` + +###### **清空wasm内存中的内容,由JS调用。** + +`return: 成功返回0,失败返回-1。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerReset() +``` + +###### **执行查询类sql语句,由JS调用。** + +`sqlLen: 需要执行的查询类sql语句长度。` + +`return: 成功返回0,失败返回-1。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlQueryEx(int sqlLen) +``` + +###### **取消sql查询,由JS调用。** + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerCancel() +``` + +###### **发送数据给第三方wasm解析,由TS调用。** + +`pluginData: 第三方插件的数据源。` + +`len: 数据源长度。` +`componentName: 第三方插件名称。` + +`return: 成功返回0。` + +``` +int TraceStreamer_Plugin_Out_SendData(const char* pluginData, int len, const std::string componentName) +``` + +###### **初始化配置接口,由JS调用。** + +`dataLen: 配置字符串的长度。` + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamer_Init_ThirdParty_Config(int dataLen) +``` + +WebAssembly通过非异步的通信方式和上层交互数据。 + +### 2.2 SDK对IDE开放的接口(位于sdk/sdk/wasm_func.h) + +###### **初始化SDK,在JS中注册回调函数,并返回一段可复用的内存空间,由JS调用。** + +`queryResultCallbackFunction: 回调函数` + +`reqBufferSize: 返回的内存长度。` + +`return: 返回一段内存地址给JS。` + +``` +EMSCRIPTEN_KEEPALIVE uint8_t* Init(QueryResultCallbackFunction queryResultCallbackFunction, uint32_t reqBufferSize) +``` + +###### **初始化一段内存空间,在JS中注册回调函数,用来传递SDK时间同步消息,由JS调用。** + +`traceRangeCallbackFunction: 回调函数` + +`reqBufferSize: 返回的内存长度。` + +`return: 返回一段内存地址给JS。` + +``` +EMSCRIPTEN_KEEPALIVE uint8_t* InitTraceRange(TraceRangeCallbackFunction traceRangeCallbackFunction, uint32_treqBufferSize) +``` + +###### **通知SDK数据解析完成。** + +`return: 返回一段内存地址给JS。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamer_In_ParseDataOver() +``` + +###### **获取SDK的json配置,由JS调用。** + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamer_In_JsonConfig() +``` + +###### **数据解析接口,由JS调用。** + +`len: 数据源长度` + +`componentId: 第三方wasm插件ID` + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int ParserData(int len, int componentId) +``` + +###### **查询类sql接口,由JS调用。** + +`sqlLen: 查询类sql长度` + +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlQueryEx(int sqlLen) +``` + +###### **初始化一段内存空间给JS,用来传递SDK的插件名称,由JS调用。** + +`reqBufferSize: 插件名称占用空间大小` +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int InitPluginName(uint32_t reqBufferSize) +``` + +###### **JS将插件名称写入初始化后的空间内,TS处理后即可获取插件名称,由JS调用。** + +`pluginLen: 传给JS的空间大小` +`return: 成功返回0。` + +``` +EMSCRIPTEN_KEEPALIVE int TraceStreamerGetPluginNameEx(int pluginLen) +``` diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678686879388.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678686879388.png new file mode 100644 index 0000000000000000000000000000000000000000..6deca243a0191b358a9896d8b7ea594b1b16feb7 Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678686879388.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687125370.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687125370.png new file mode 100644 index 0000000000000000000000000000000000000000..8f00717f7ae51af51dc44e4a5687c8d4d8167d32 Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687125370.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687167730.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687167730.png new file mode 100644 index 0000000000000000000000000000000000000000..ada97141d2d7ae0a6e8b304ed8cd460e5c71e86e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687167730.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687179357.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687179357.png new file mode 100644 index 0000000000000000000000000000000000000000..ada97141d2d7ae0a6e8b304ed8cd460e5c71e86e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687179357.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687218525.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687218525.png new file mode 100644 index 0000000000000000000000000000000000000000..797b239968f546be7a24b686e501845964b3886e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687218525.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687225709.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687225709.png new file mode 100644 index 0000000000000000000000000000000000000000..797b239968f546be7a24b686e501845964b3886e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687225709.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687231618.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687231618.png new file mode 100644 index 0000000000000000000000000000000000000000..797b239968f546be7a24b686e501845964b3886e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687231618.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687426565.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687426565.png new file mode 100644 index 0000000000000000000000000000000000000000..5414b9328c873c01f0c243a724aac0f439ce8cec Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687426565.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687469294.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687469294.png new file mode 100644 index 0000000000000000000000000000000000000000..ae5697926cc620e650afc31a6c347f1b81b18fbf Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687469294.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687498819.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687498819.png new file mode 100644 index 0000000000000000000000000000000000000000..c32af6f4aa2ba7ccd1517d884983eb3d50b88faa Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687498819.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687529966.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687529966.png new file mode 100644 index 0000000000000000000000000000000000000000..6db26f6e63461891110c28219b23c1e5f365a7bc Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687529966.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687534793.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687534793.png new file mode 100644 index 0000000000000000000000000000000000000000..6db26f6e63461891110c28219b23c1e5f365a7bc Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687534793.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687580903.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687580903.png new file mode 100644 index 0000000000000000000000000000000000000000..35bbc3921de2460a4ba5a7c94db2f7b33a3403a3 Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687580903.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687606212.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687606212.png new file mode 100644 index 0000000000000000000000000000000000000000..733de4624a63d40d3f2db166e3732d968d448ad8 Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687606212.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687611512.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687611512.png new file mode 100644 index 0000000000000000000000000000000000000000..733de4624a63d40d3f2db166e3732d968d448ad8 Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687611512.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687619286.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687619286.png new file mode 100644 index 0000000000000000000000000000000000000000..733de4624a63d40d3f2db166e3732d968d448ad8 Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687619286.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687652015.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687652015.png new file mode 100644 index 0000000000000000000000000000000000000000..7cfba37725735f342596382599e81f79e2f4294e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687652015.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687656154.png b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687656154.png new file mode 100644 index 0000000000000000000000000000000000000000..7cfba37725735f342596382599e81f79e2f4294e Binary files /dev/null and b/trace_streamer/sdk/demo_sdk/doc/image/TraceStreamerSDK/1678687656154.png differ diff --git a/trace_streamer/sdk/demo_sdk/doc/wasm.md b/trace_streamer/sdk/demo_sdk/doc/wasm.md new file mode 100644 index 0000000000000000000000000000000000000000..0c2876b9e1816899915b5c07234cf56743c6045e --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/doc/wasm.md @@ -0,0 +1,43 @@ +为了方便传输此sdk开发包,位于prebuilts目录下的emsdk目录已经被删除,可以通过下面的 +为了编译WebAssembly版本,需要在prebuilts/目录下安装emsdk +``` +git clone https://github.com/juj/emsdk.git --depth=1 +cd emsdk +git pull +./emsdk update # this may not work, ignore it +./emsdk install latest +./emsdk activate latest +安装之后,需要将upstream目录复制到prebuilts/emsdk/emsdk,node复制到prebuilts/emsdk/node +``` +安装之后,目录结构当如: +``` +prebuilts/emsdk +├── prebuilts/emsdk/emsdk +│ ├── prebuilts/emsdk/emsdk/bin +│ ├── prebuilts/emsdk/emsdk/emscripten +│ │ ├── prebuilts/emsdk/emsdk/emscripten/cache +│ │ ├── prebuilts/emsdk/emsdk/emscripten/cmake +│ │ ├── prebuilts/emsdk/emsdk/emscripten/docs +│ │ ├── prebuilts/emsdk/emsdk/emscripten/media +│ │ ├── prebuilts/emsdk/emsdk/emscripten/node_modules +│ │ ├── prebuilts/emsdk/emsdk/emscripten/__pycache__ +│ │ ├── prebuilts/emsdk/emsdk/emscripten/src +│ │ ├── prebuilts/emsdk/emsdk/emscripten/system +│ │ ├── prebuilts/emsdk/emsdk/emscripten/tests +│ │ ├── prebuilts/emsdk/emsdk/emscripten/third_party +│ │ └── prebuilts/emsdk/emsdk/emscripten/tools +│ ├── prebuilts/emsdk/emsdk/include +│ │ └── prebuilts/emsdk/emsdk/include/c++ +│ └── prebuilts/emsdk/emsdk/lib +│ └── prebuilts/emsdk/emsdk/lib/clang +└── prebuilts/emsdk/node + └── prebuilts/emsdk/node/14.18.2_64bit + ├── prebuilts/emsdk/node/14.18.2_64bit/bin + ├── prebuilts/emsdk/node/14.18.2_64bit/include + ├── prebuilts/emsdk/node/14.18.2_64bit/lib + └── prebuilts/emsdk/node/14.18.2_64bit/share +``` +之后调用 +``` +./build.sh sdkdemo 进行编译demo +``` \ No newline at end of file diff --git a/trace_streamer/sdk/demo_sdk/ext/BUILD.gn b/trace_streamer/sdk/demo_sdk/ext/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..a2212ebeb58dd199eb0c456701a8925f95e277c4 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/ext/BUILD.gn @@ -0,0 +1,25 @@ +# 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") +config("sqlite_config") { + include_dirs = [ + "//third_party/sqlite/include", + "../include", + ] + cflags = [ "-Wno-writable-strings" ] +} +source_set("sqliteext") { + sources = [ "sqlite_ext_funcs.cpp" ] + public_configs = [ ":sqlite_config" ] +} diff --git a/trace_streamer/sdk/demo_sdk/ext/sqlite_ext_funcs.cpp b/trace_streamer/sdk/demo_sdk/ext/sqlite_ext_funcs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d34064dc55a79f043dac99df3c1405803a945b96 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/ext/sqlite_ext_funcs.cpp @@ -0,0 +1,358 @@ +/* + * 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 "sqlite_ext_funcs.h" +#include +#include +#include "log.h" +#include "sqlite3.h" +namespace SysTuning { +namespace base { +/* +** Return a stdev value +*/ +static void sqliteExtStdevFinalize(sqlite3_context* context) +{ + StdevCtx* ptr = static_cast(sqlite3_aggregate_context(context, 0)); + if (ptr && ptr->cntValue > 1) { + sqlite3_result_double(context, sqrt(ptr->rSValue / (ptr->cntValue - 1))); + } else { + sqlite3_result_double(context, 0.0); + } +} +/* +** called each value received during a calculation of stdev or variance +*/ +static void sqliteExtStdevNextStep(sqlite3_context* context, int32_t argc, sqlite3_value** argv) +{ + TS_ASSERT(argc == 1); + StdevCtx* ptr = static_cast(sqlite3_aggregate_context(context, sizeof(StdevCtx))); + if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) { + ptr->cntValue++; + double x = sqlite3_value_double(argv[0]); + double deltaValue = (x - ptr->rMValue); + ptr->rMValue += deltaValue / ptr->cntValue; + ptr->rSValue += deltaValue * (x - ptr->rMValue); + } +} + +enum Type { + tsNull = 0, + tsLong, + tsDouble, + tsString, + tsBytes, +}; + +struct TSSqlValue { + TSSqlValue() = default; + + static TSSqlValue Long(int64_t v) + { + TSSqlValue value; + value.longValue = v; + value.type = Type::tsLong; + return value; + } + + static TSSqlValue Double(double v) + { + TSSqlValue value; + value.doubleValue = v; + value.type = Type::tsDouble; + return value; + } + + static TSSqlValue String(const char* v) + { + TSSqlValue value; + value.stringValue = v; + value.type = Type::tsString; + return value; + } + + static TSSqlValue Bytes(const void* v, size_t size) + { + TSSqlValue value; + value.bytesValue = v; + value.bytesCount = size; + value.type = Type::tsBytes; + return value; + } + + double GetDouble() const + { + return doubleValue; + } + int64_t GetLong() const + { + return longValue; + } + const char* GetString() const + { + return stringValue; + } + const void* GetBytes() const + { + return bytesValue; + } + + bool isNull() const + { + return type == Type::tsNull; + } + + union { + const char* stringValue; + int64_t longValue; + double doubleValue; + const void* bytesValue; + }; + size_t bytesCount = 0; + Type type = tsNull; +}; + +TSSqlValue SqliteValueToTSSqlValue(sqlite3_value* value) +{ + TSSqlValue sqlValue; + switch (sqlite3_value_type(value)) { + case SQLITE_INTEGER: + sqlValue.type = Type::tsLong; + sqlValue.longValue = sqlite3_value_int64(value); + break; + case SQLITE_FLOAT: + sqlValue.type = Type::tsDouble; + sqlValue.doubleValue = sqlite3_value_double(value); + break; + case SQLITE_TEXT: + sqlValue.type = Type::tsString; + sqlValue.stringValue = reinterpret_cast(sqlite3_value_text(value)); + break; + case SQLITE_BLOB: + sqlValue.type = Type::tsBytes; + sqlValue.bytesValue = sqlite3_value_blob(value); + sqlValue.bytesCount = static_cast(sqlite3_value_bytes(value)); + break; + } + return sqlValue; +} +class JsonBuild { +public: + JsonBuild() = default; + void AppendHead() + { + body_ += "{"; + } + void AppendTail() + { + body_ += "}"; + } + void AppendCommon() + { + body_ += ","; + } + bool AppendSqlValue(const std::string& field_name, const TSSqlValue& value) + { + body_ += "\"" + field_name + "\":"; + return AppendSqlValue(value); + } + bool AppendSqlValue(const TSSqlValue& value) + { + switch (value.type) { + case tsLong: + body_ += std::to_string(value.longValue) + ","; + break; + case tsDouble: + body_ += std::to_string(value.doubleValue) + ","; + break; + case tsString: + body_ += "\"" + std::string(value.stringValue) + "\"" + ","; + break; + case tsBytes: + body_ += "\"" + std::string(static_cast(value.bytesValue), value.bytesCount) + "\"" + ","; + break; + case tsNull: + body_ += std::to_string(0) + ","; + break; + } + return true; + } + std::string body_; + bool poped_ = false; + void PopLast() + { + body_.pop_back(); + } + const std::string& Body() const + { + return body_; + } +}; + +void BuildJson(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + const int32_t PAIR_ARGS_SIZE = 2; + if (argc % PAIR_ARGS_SIZE != 0) { + TS_LOGI("BuildJson arg number error"); + sqlite3_result_error(ctx, "BuildJson arg number error", -1); + return; + } + + JsonBuild builder; + builder.AppendHead(); + for (int32_t i = 0; i < argc; i += PAIR_ARGS_SIZE) { + if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) { + TS_LOGI("BuildJson: Invalid args argc:%d, %d", argc, sqlite3_value_type(argv[i])); + sqlite3_result_error(ctx, "BuildJson: Invalid args", -1); + return; + } + + auto* key = reinterpret_cast(sqlite3_value_text(argv[i])); + auto value = SqliteValueToTSSqlValue(argv[i + 1]); + auto status = builder.AppendSqlValue(key, value); + if (!status) { + TS_LOGI("AppendSqlValueError"); + sqlite3_result_error(ctx, "AppendSqlValueError", -1); + return; + } + } + builder.PopLast(); + builder.AppendTail(); + std::string raw = builder.Body(); + if (raw.empty()) { + sqlite3_result_blob(ctx, "", 0, nullptr); + return; + } + std::unique_ptr data = std::make_unique(raw.size()); + memcpy(data.get(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} + +void RepeatedJsonStep(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + const int32_t PAIR_ARGS_SIZE = 2; + auto** jsonBuild = static_cast(sqlite3_aggregate_context(ctx, sizeof(JsonBuild*))); + + if (*jsonBuild == nullptr) { + *jsonBuild = new JsonBuild(); + } + JsonBuild* builder = *jsonBuild; + builder->AppendHead(); + for (int32_t i = 0; i < argc; i += PAIR_ARGS_SIZE) { + if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) { + TS_LOGI("BuildJson: Invalid args argc:%d, %d", argc, sqlite3_value_type(argv[i])); + sqlite3_result_error(ctx, "BuildJson: Invalid args", -1); + return; + } + + auto* key = reinterpret_cast(sqlite3_value_text(argv[i])); + auto value = SqliteValueToTSSqlValue(argv[i + 1]); + auto status = builder->AppendSqlValue(key, value); + if (!status) { + TS_LOGI("AppendSqlValueError"); + sqlite3_result_error(ctx, "AppendSqlValueError", -1); + return; + } + } + builder->PopLast(); + builder->AppendTail(); + builder->AppendCommon(); +} +void RepeatedFieldStep(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + if (argc != 1) { + TS_LOGE( + "RepeatedField only support one arg, you can use BuildJson or BuildRepeatedJson function for multi args"); + return; + } + auto** jsonBuild = static_cast(sqlite3_aggregate_context(ctx, sizeof(JsonBuild*))); + + if (*jsonBuild == nullptr) { + *jsonBuild = new JsonBuild(); + } + JsonBuild* builder = *jsonBuild; + for (int32_t i = 0; i < argc; i++) { + auto value = SqliteValueToTSSqlValue(argv[i]); + auto status = builder->AppendSqlValue(value); + if (!status) { + sqlite3_result_error(ctx, "error", -1); + } + } +} + +void RepeatedFieldFinal(sqlite3_context* ctx) +{ + auto** jsonBuilder = static_cast(sqlite3_aggregate_context(ctx, 0)); + + if (jsonBuilder == nullptr) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr builder(*jsonBuilder); + std::string raw = builder->Body(); + raw.pop_back(); + if (raw.empty()) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr data = std::make_unique(raw.size()); + memcpy(data.get(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} + +void RepeatedJsonFinal(sqlite3_context* ctx) +{ + auto** jsonBuilder = static_cast(sqlite3_aggregate_context(ctx, 0)); + + if (jsonBuilder == nullptr) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr builder(*jsonBuilder); + builder->PopLast(); + std::string raw = builder->Body(); + if (raw.empty()) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr data = std::make_unique(raw.size()); + memcpy(data.get(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} +void ts_create_extend_function(sqlite3* db) +{ + sqlite3_create_function(db, "stdev", -1, SQLITE_UTF8, nullptr, 0, sqliteExtStdevNextStep, sqliteExtStdevFinalize); + auto ret = sqlite3_create_function_v2(db, "RepeatedField", 1, SQLITE_UTF8, nullptr, nullptr, RepeatedFieldStep, + RepeatedFieldFinal, nullptr); + if (ret) { + TS_LOGF("Error while initializing RepeatedField"); + } + ret = sqlite3_create_function_v2(db, "BuildRepeatedJson", -1, SQLITE_UTF8, nullptr, nullptr, RepeatedJsonStep, + RepeatedJsonFinal, nullptr); + if (ret) { + TS_LOGF("Error while initializing BuildRepeatedJson"); + } + std::unique_ptr ctx = std::make_unique(); + ret = sqlite3_create_function_v2(db, "BuildJson", -1, SQLITE_UTF8, ctx.release(), BuildJson, nullptr, nullptr, + [](void* ptr) { delete static_cast(ptr); }); + if (ret != SQLITE_OK) { + TS_LOGF("Error while initializing BuildJson"); + } +} +} // namespace base +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/sdk/demo_sdk/ext/sqlite_ext_funcs.h b/trace_streamer/sdk/demo_sdk/ext/sqlite_ext_funcs.h new file mode 100644 index 0000000000000000000000000000000000000000..e1ce74a727d69a10d177682f38f54ac943c0687c --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/ext/sqlite_ext_funcs.h @@ -0,0 +1,30 @@ +/* + * 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 SQLITE_EXT_FUNCS_H +#define SQLITE_EXT_FUNCS_H 1 +#include +#include "sqlite3.h" +namespace SysTuning { +namespace base { +typedef struct StdevCtx StdevCtx; +struct StdevCtx { + double rMValue; + double rSValue; + int64_t cntValue; +}; +void ts_create_extend_function(sqlite3* db); +} // namespace base +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/filter/clock_filter.cpp b/trace_streamer/sdk/demo_sdk/filter/clock_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5c721e58760d025992c05b9cfa300a0ab40d983 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/filter/clock_filter.cpp @@ -0,0 +1,147 @@ +/* + * 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 "clock_filter.h" +#include +#include +#include "string_help.h" + +namespace SysTuning { +namespace TraceStreamer { +ClockFilter::ClockFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) +{ + profilerSDKTraceFileHeader_ = std::make_unique().get(); +} +ClockFilter::~ClockFilter() {} + +std::string ClockFilter::GenClockKey(ClockId srcClockId, ClockId desClockId) +{ + std::string ret; + ret += std::to_string(srcClockId); + ret += ","; + ret += std::to_string(desClockId); + return ret; +} + +uint64_t ClockFilter::ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const +{ + if (srcClockId == primaryClock_) { + return srcTs; + } + return Convert(srcClockId, srcTs, primaryClock_); +} + +uint64_t ClockFilter::Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const +{ + std::string&& clockKey = GenClockKey(srcClockId, desClockId); + auto keyIt = clockMaps_.find(clockKey); + if (keyIt == clockMaps_.end()) { + return srcTs; + } + + auto tsIt = keyIt->second.upper_bound(srcTs); + if (tsIt != keyIt->second.begin()) { + tsIt--; + } + + if (tsIt->second >= 0) { + return srcTs + static_cast(tsIt->second); + } else { + return srcTs - static_cast(0 - tsIt->second); + } +} + +void ClockFilter::AddConvertClockMap(ClockId srcClockId, ClockId dstClockId, uint64_t srcTs, uint64_t dstTs) +{ + std::string&& clockKey = GenClockKey(srcClockId, dstClockId); + auto keyIt = clockMaps_.find(clockKey); + if (keyIt == clockMaps_.end()) { + ConvertClockMap newConvertMap = {{srcTs, dstTs - srcTs}}; + clockMaps_[clockKey] = newConvertMap; + } else { + clockMaps_[clockKey].insert(std::make_pair(srcTs, dstTs - srcTs)); + } +} +void ClockFilter::AddClockSnapshot(const std::vector& snapShot) +{ + ClockId srcId, desId; + for (srcId = 0; srcId < snapShot.size() - 1; srcId++) { + for (desId = srcId + 1; desId < snapShot.size(); desId++) { + ClockId srcClockId = snapShot[srcId].clockId; + ClockId desClockId = snapShot[desId].clockId; + uint64_t srcTs = snapShot[srcId].ts; + uint64_t desTs = snapShot[desId].ts; + + AddConvertClockMap(srcClockId, desClockId, srcTs, desTs); + AddConvertClockMap(desClockId, srcClockId, desTs, srcTs); + } + } + hasInitSnapShot_ = true; +} + +int32_t ClockFilter::InitSnapShotTimeRange(const uint8_t* data, int32_t len) +{ + std::unique_ptr buf = std::make_unique(len); + std::copy(data, data + len, buf.get()); + profilerSDKTraceFileHeader_ = reinterpret_cast(buf.get()); + + if (HasInitSnapShot()) { + TS_LOGE("SDK already has clock snapshot!!!"); + return -1; + } + if (!profilerSDKTraceFileHeader_->data.boottime) { + TS_LOGE("SDK Profiler header has no clock snapshot!!!"); + return -1; + } + + std::vector snapShot; + + TS_LOGE("SDK clockid: TS_CLOCK_BOOTTIME, ts:%llu", profilerSDKTraceFileHeader_->data.boottime); + if (profilerSDKTraceFileHeader_->data.boottime) { + snapShot.push_back(SnapShot{TS_CLOCK_BOOTTIME, profilerSDKTraceFileHeader_->data.boottime}); + } + + TS_LOGE("SDK clockid: TS_CLOCK_REALTIME, ts:%llu", profilerSDKTraceFileHeader_->data.realtime); + if (profilerSDKTraceFileHeader_->data.realtime) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME, profilerSDKTraceFileHeader_->data.realtime}); + } + + TS_LOGE("SDK clockid: TS_CLOCK_REALTIME_COARSE, ts:%llu", profilerSDKTraceFileHeader_->data.realtimeCoarse); + if (profilerSDKTraceFileHeader_->data.realtimeCoarse) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME_COARSE, profilerSDKTraceFileHeader_->data.realtimeCoarse}); + } + + TS_LOGE("SDK clockid: TS_MONOTONIC, ts:%llu", profilerSDKTraceFileHeader_->data.monotonic); + if (profilerSDKTraceFileHeader_->data.monotonic) { + snapShot.push_back(SnapShot{TS_MONOTONIC, profilerSDKTraceFileHeader_->data.monotonic}); + } + + TS_LOGE("SDK clockid: TS_MONOTONIC_COARSE, ts:%llu", profilerSDKTraceFileHeader_->data.monotonicCoarse); + if (profilerSDKTraceFileHeader_->data.monotonicCoarse) { + snapShot.push_back(SnapShot{TS_MONOTONIC_COARSE, profilerSDKTraceFileHeader_->data.monotonicCoarse}); + } + + TS_LOGE("SDK clockid: TS_MONOTONIC_RAW, ts:%llu", profilerSDKTraceFileHeader_->data.monotonicRaw); + if (profilerSDKTraceFileHeader_->data.monotonicRaw) { + snapShot.push_back(SnapShot{TS_MONOTONIC_RAW, profilerSDKTraceFileHeader_->data.monotonicRaw}); + } + + if (snapShot.size()) { + AddClockSnapshot(snapShot); + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/filter/clock_filter.h b/trace_streamer/sdk/demo_sdk/filter/clock_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..df2b0a5026430572a9dd4542faa403a4bf5f9482 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/filter/clock_filter.h @@ -0,0 +1,89 @@ +/* + * 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 CLOCK_FILTER_H +#define CLOCK_FILTER_H + +#include +#include +#include +#include +#include +#include "file.h" +#include "trace_data_cache.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +/* + * TS_REALTIME: A settable system-wide clock that measures real time. Its time represents seconds and nanoseconds + * since the Epoch. + * TS_REALTIME_COARSE: A faster but less precise version of TS_REALTIME. This clock is not settable. + * TS_MONOTONIC: The number of seconds that the system has been running since it was booted.The CLOCK_MONOTONIC + * clock is not affected by discontinuous jumps in the system time ,but is affected by the incremental adjustments + * performed by adjtime(3) and NTP. This clock does not count time that the system is suspended. + * TS_MONOTONIC_COARSE: A faster but less precise version of TS_MONOTONIC. + * TS_MONOTONIC_RAW: Similar to TS_MONOTONIC, but provides access to a raw hardware-based time that is not subject + * to NTP adjustments or the incremental adjustments performed by adjtime(3). This clock does not count time that the + * system is suspended. + * TS_BOOTTIME: A nonsettable system-wide clock that is identical to TS_MONOTONIC, except that it also includes + * any time that the system is suspended. + */ + +using ClockId = uint32_t; +struct SnapShot { + ClockId clockId; + uint64_t ts; +}; +class TraceStreamerFilters; +class ClockFilter { +public: + using ConvertClockMap = std::map; + ClockFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~ClockFilter(); + + void SetPrimaryClock(ClockId primary) + { + primaryClock_ = primary; + } + ClockId GetPrimaryClock() + { + return primaryClock_; + } + uint64_t ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const; + uint64_t Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const; + void UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp); + void AddClockSnapshot(const std::vector& snapShot); + int32_t InitSnapShotTimeRange(const uint8_t* data, int32_t len); + bool HasInitSnapShot() const + { + return hasInitSnapShot_; + } + +private: + static std::string GenClockKey(ClockId srcClockId, ClockId desClockId); + void AddConvertClockMap(ClockId srcClockId, ClockId dstClockId, uint64_t srcTs, uint64_t dstTs); + +private: + std::unordered_map clockMaps_ = {}; + base::ProfilerTraceFileHeader* profilerSDKTraceFileHeader_; + + ClockId primaryClock_ = BuiltinClocks::TS_CLOCK_BOOTTIME; + bool hasInitSnapShot_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // CLOCK_FILTER_H diff --git a/trace_streamer/sdk/demo_sdk/include/BUILD.gn b/trace_streamer/sdk/demo_sdk/include/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..5d175002dfa9f76334c078b3aa8362bd51c1b1bf --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/include/BUILD.gn @@ -0,0 +1,28 @@ +# 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") +ohos_source_set("ibase") { + subsystem_name = "trace_streamer" + part_name = "ibase" + sources = [ + "codec_cov.h", + "file.h", + "log.h", + "parting_string.h", + "string_to_numerical.h", + ] + include_dirs = [] + public_deps = [] + deps = [] + sources += [ "/usr/x86_64-w64-mingw32/include/windows.h" ] +} diff --git a/trace_streamer/sdk/demo_sdk/include/file.h b/trace_streamer/sdk/demo_sdk/include/file.h new file mode 100644 index 0000000000000000000000000000000000000000..91d6d6231a2de83d349d84cb51c6086f6fb620d9 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/include/file.h @@ -0,0 +1,80 @@ +/* + * 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 INCLUDE_TUNING_BASE_FILE_UTILS_H_ +#define INCLUDE_TUNING_BASE_FILE_UTILS_H_ + +#include + +namespace SysTuning { +namespace base { +#define TS_PERMISSION_RW 0600 +constexpr uint32_t kFileModeInvalid = 0xFFFFFFFF; +enum TraceParserStatus { + TRACE_PARSER_NORMAL = 0, + TRACE_PARSER_FILE_TYPE_ERROR = 1, + TRACE_PARSE_ERROR = 2, + TRACE_PARSER_ABNORMAL = 3 +}; +struct ProfilerTraceFileHeader { + // Some space is reserved to facilitate the subsequent addition of fields in the header + static constexpr uint32_t HEADER_SIZE = 1024; + static constexpr uint32_t SHA256_SIZE = 256 / 8; + static constexpr uint64_t HEADER_MAGIC = 0x464F5250534F484FuLL; + static constexpr uint32_t V_MAJOR = 0x0001; + static constexpr uint32_t V_MAJOR_BITS = 16; + static constexpr uint32_t V_MINOR = 0x0000; + static constexpr uint32_t TRACE_VERSION = (V_MAJOR << V_MAJOR_BITS) | V_MINOR; + enum DataType { + HIPROFILER_PROTOBUF_BIN = 0, + HIPERF_DATA, + UNKNOW_TYPE = 1024, + }; + struct HeaderData { + // Magic number, used to distinguish offline files + uint64_t magic = HEADER_MAGIC; + // Total length, which can be used to check whether the document is truncated; + uint64_t length = HEADER_SIZE; + uint32_t version = TRACE_VERSION; + // The number of segments in the load data. The number of segments is even. One describes the length L and the + // other describes the next data v + uint32_t segments = 0; + // Sha256 of load data is used to verify whether the load data is complete; + uint8_t sha256[SHA256_SIZE] = {}; + uint32_t dataType = UNKNOW_TYPE; + // clock + uint64_t boottime = 0; + uint64_t realtime = 0; + uint64_t realtimeCoarse = 0; + uint64_t monotonic = 0; + uint64_t monotonicCoarse = 0; + uint64_t monotonicRaw = 0; + } __attribute__((packed)); + HeaderData data = {}; + uint8_t padding_[HEADER_SIZE - sizeof(data)] = {}; +}; + +void SetAnalysisResult(TraceParserStatus stat); + +TraceParserStatus GetAnalysisResult(); + +ssize_t Read(int32_t fd, uint8_t* dst, size_t dstSize); + +int32_t OpenFile(const std::string& path, int32_t flags, uint32_t mode = kFileModeInvalid); + +std::string GetExecutionDirectoryPath(); +} // namespace base +} // namespace SysTuning +#endif // INCLUDE_TUNING_BASE_FILE_UTILS_H_ diff --git a/trace_streamer/sdk/demo_sdk/include/log.h b/trace_streamer/sdk/demo_sdk/include/log.h new file mode 100644 index 0000000000000000000000000000000000000000..394f678f9855e2ad16a03375a8216128bf3a75a0 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/include/log.h @@ -0,0 +1,65 @@ +/* + * 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 INCLUDE_TS_BASE_LOGGING_H_ +#define INCLUDE_TS_BASE_LOGGING_H_ + +#include +#include + +// namespace SysTuning { +// namespace base { +#define TS_CRASH \ + do { \ + __builtin_trap(); \ + __builtin_unreachable(); \ + } while (0) +enum LogLevel { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; +const enum LogLevel g_currentLogLevel = LOG_DEBUG; +extern bool g_cleanMode; +#define LOGWITHLEVEL(level, motify, fmt, ...) \ + do { \ + if (level >= g_currentLogLevel) { \ + if (!g_cleanMode) { \ + fprintf(stdout, "[-%c][%s][%d]: " fmt "\n", motify, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + } \ + if (level == LOG_FATAL) { \ + TS_CRASH; \ + } \ + } \ + } while (0) +#define TS_LOGE(fmt, ...) LOGWITHLEVEL(LOG_ERROR, 'E', fmt, ##__VA_ARGS__) +#define TS_LOGF(fmt, ...) LOGWITHLEVEL(LOG_FATAL, 'F', fmt, ##__VA_ARGS__) +#define TS_LOGI(fmt, ...) LOGWITHLEVEL(LOG_INFO, 'I', fmt, ##__VA_ARGS__) +#ifdef NDEBUG +#define TS_LOGD(format, ...) +#define TS_LOGW(format, ...) +#define TS_ASSERT(x) +#else +#define TS_LOGD(fmt, ...) LOGWITHLEVEL(LOG_DEBUG, 'D', fmt, ##__VA_ARGS__) +#define TS_LOGW(fmt, ...) LOGWITHLEVEL(LOG_WARN, 'W', fmt, ##__VA_ARGS__) + +#define TS_ASSERT(x) \ + do { \ + if (!(x)) { \ + TS_CRASH; \ + } \ + } while (0) + +#endif +// } // namespace base +// } // namespace SysTuning + +#endif // INCLUDE_TS_BASE_LOGGING_H_ diff --git a/trace_streamer/sdk/demo_sdk/include/string_to_numerical.h b/trace_streamer/sdk/demo_sdk/include/string_to_numerical.h new file mode 100644 index 0000000000000000000000000000000000000000..3a7fefa563fcab39b3b7b6ea255c8c3251f78393 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/include/string_to_numerical.h @@ -0,0 +1,110 @@ +/* + * 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 INCLUDE_BASE_STRING_TO_NUMERICAL_H_ +#define INCLUDE_BASE_STRING_TO_NUMERICAL_H_ + +#include +#include +#include + +namespace SysTuning { +namespace base { +enum IntegerRadixType { INTEGER_RADIX_TYPE_DEC = 10, INTEGER_RADIX_TYPE_HEX = 16 }; +inline uint16_t GetNameASCIISumNoNum(const std::string& str) +{ + uint32_t sum = 0; + int32_t len = str.length() - 1; + while (len >= 0) { + sum += std::isdigit(str.at(len)) ? 0 : str.at(len); + len--; + } + return sum % INTEGER_RADIX_TYPE_HEX; +} +inline std::optional StrToUInt32(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtoul(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::string number(uint64_t value, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + std::stringstream ss; + if (base == INTEGER_RADIX_TYPE_DEC) { + ss << std::dec << value; + } else if (base == INTEGER_RADIX_TYPE_HEX) { + ss << std::hex << value; + } + return ss.str(); +} + +inline std::optional StrToInt32(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtol(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::optional StrToUInt64(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtoull(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::optional StrToInt64(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + int64_t value = static_cast(std::strtoll(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + return std::nullopt; +} + +inline std::optional StrToDouble(const std::string& str) +{ + if (!str.empty()) { + double value = std::stod(str); + return std::make_optional(value); + } + + return std::nullopt; +} +} // namespace base +} // namespace SysTuning + +#endif // INCLUDE_TUNING_EXT_BASE_STRING_UTILS_H_ diff --git a/trace_streamer/sdk/demo_sdk/main.cpp b/trace_streamer/sdk/demo_sdk/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59b9cf5d546a6c53ad08f31ceeb0568d5b11d972 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/main.cpp @@ -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. + */ +int main(int argc, char** argv) +{ + return 0; +} diff --git a/trace_streamer/sdk/demo_sdk/parser/event_parser_base.cpp b/trace_streamer/sdk/demo_sdk/parser/event_parser_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4bdbf4f5e4e7ac919ecf6af18f1fe7b6e680f3d --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/parser/event_parser_base.cpp @@ -0,0 +1,24 @@ +/* + * 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 "event_parser_base.h" +namespace SysTuning { +namespace TraceStreamer { +EventParserBase::EventParserBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : streamFilters_(filter), traceDataCache_(dataCache) +{ +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/parser/event_parser_base.h b/trace_streamer/sdk/demo_sdk/parser/event_parser_base.h new file mode 100644 index 0000000000000000000000000000000000000000..1d9313edfcd0557c8351d705b2e82639ac2e296e --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/parser/event_parser_base.h @@ -0,0 +1,34 @@ +/* + * 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 SRC_EVENT_PARSER_BASE_H +#define SRC_EVENT_PARSER_BASE_H +#include "../trace_data/trace_data_cache.h" +#include "../trace_streamer/trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class EventParserBase { +public: + EventParserBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + virtual ~EventParserBase() = default; + +public: + const TraceStreamerFilters* streamFilters_; + TraceDataCache* traceDataCache_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_PARSER_BASE_H diff --git a/trace_streamer/sdk/demo_sdk/parser/htrace_plugin_time_parser.cpp b/trace_streamer/sdk/demo_sdk/parser/htrace_plugin_time_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40cb7f0053cfb28e05aa94fa4b9268977478f1a3 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/parser/htrace_plugin_time_parser.cpp @@ -0,0 +1,59 @@ +/* + * 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 "htrace_plugin_time_parser.h" +namespace SysTuning { +namespace TraceStreamer { +HtracePluginTimeParser::HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx) +{ +} +void HtracePluginTimeParser::UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp) +{ + minTs_ = std::min(minTs_, asyncTimestamp); + maxTs_ = std::max(maxTs_, asyncTimestamp); + if (clockId == streamFilters_->clockFilter_->GetPrimaryClock()) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + return; + } + if (syncTimestamp != asyncTimestamp) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + } else { + asyncHtracePluginStartTime_ = std::min(asyncHtracePluginStartTime_, syncTimestamp); + asyncHtracePluginEndTime_ = std::max(asyncHtracePluginEndTime_, syncTimestamp); + } +} +uint64_t HtracePluginTimeParser::GetPluginStartTime() +{ + if (syncHtracePluginStartTime_ != std::numeric_limits::max()) { + return syncHtracePluginStartTime_; + } else if (asyncHtracePluginStartTime_ != std::numeric_limits::max()) { + return asyncHtracePluginStartTime_; + } + return std::numeric_limits::max(); +} + +uint64_t HtracePluginTimeParser::GetPluginEndTime() +{ + if (syncHtracePluginEndTime_ != 0) { + return syncHtracePluginEndTime_; + } else if (asyncHtracePluginEndTime_ != 0) { + return asyncHtracePluginEndTime_; + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/parser/htrace_plugin_time_parser.h b/trace_streamer/sdk/demo_sdk/parser/htrace_plugin_time_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..6ac4d2f2d3668f301d6089a3952c90066524737a --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/parser/htrace_plugin_time_parser.h @@ -0,0 +1,52 @@ +/* + * 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 HTRACE_PLUGIN_TIME_PARSER_H +#define HTRACE_PLUGIN_TIME_PARSER_H +#include "clock_filter.h" +#include "event_parser_base.h" +#include "trace_data/trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtracePluginTimeParser : public EventParserBase { +public: + HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + HtracePluginTimeParser(const HtracePluginTimeParser&) = delete; + HtracePluginTimeParser& operator=(const HtracePluginTimeParser&) = delete; + ~HtracePluginTimeParser() = default; + void UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp); + uint64_t GetPluginStartTime(); + uint64_t GetPluginEndTime(); + uint64_t MinTs() const + { + return minTs_; + } + uint64_t MaxTs() const + { + return maxTs_; + } + +private: + uint64_t syncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t syncHtracePluginEndTime_ = 0; + uint64_t asyncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t asyncHtracePluginEndTime_ = 0; + uint64_t minTs_ = std::numeric_limits::max(); + uint64_t maxTs_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PLUGIN_TIME_PARSER_H diff --git a/trace_streamer/sdk/demo_sdk/plugin/BUILD.gn b/trace_streamer/sdk/demo_sdk/plugin/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..41e5b6834248509d711c75c0df0bb2de959ba532 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/plugin/BUILD.gn @@ -0,0 +1,36 @@ +# 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") +OHOS_PROTO_GEN = "//third_party/protogen" +ohos_source_set("sdk_plugin") { + subsystem_name = "trace_streamer" + part_name = "sdk_sdk_plugin" + sources = [ + "sdk_plugin_data_parser.cpp", + "sdk_plugin_data_parser.h", + ] + include_dirs = [ + "base", + "..", + "../include", + "../filter", + "../trace_data", + "../base", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "//third_party/protobuf/src", + ] + + public_deps = [] +} diff --git a/trace_streamer/sdk/demo_sdk/plugin/sdk_plugin_data_parser.cpp b/trace_streamer/sdk/demo_sdk/plugin/sdk_plugin_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6808b37f18990a38df8e72df72d37869a727e84d --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/plugin/sdk_plugin_data_parser.cpp @@ -0,0 +1,81 @@ +/* + * 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 "sdk_plugin_data_parser.h" +#include +#include "sdk/ts_sdk_api.h" + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +void sdk_plugin_init_table_name() +{ + SDK_SetTableName("counter_table", "gpu_counter_object", "slice_table", "slice_object_table"); +} +int32_t sdk_plugin_data_parser(const uint8_t* data, int32_t len) +{ + std::unique_ptr buf = std::make_unique(len); + std::copy(data, data + len, buf.get()); + MockDataArr mockDataArr; + mockDataArr.ParseFromArray(buf.get(), len); + int32_t size = mockDataArr.mockdata_size(); + if (size > 1) { + for (auto m = 0; m < size; m++) { + auto mockData = mockDataArr.mockdata().at(m); + sdk_plugin_parser(data, len, mockData); + } + } else { + MockData mockData; + mockData.ParseFromArray(buf.get(), len); + sdk_plugin_parser(data, len, mockData); + } + return 0; +} + +int32_t sdk_plugin_parser(const uint8_t* data, int32_t len, MockData mockData) +{ + // parser counterObject + for (auto i = 0; i < mockData.counterobj_size(); i++) { + int32_t counterId = mockData.counterobj(i).id(); + std::string counterName = mockData.counterobj(i).name(); + SDK_AppendCounterObject(counterId, counterName.c_str()); + } + + // parsercounterInfo + for (auto i = 0; i < mockData.counterinfo_size(); i++) { + CounterInfo counterInfo; + counterInfo = mockData.counterinfo(i); + SDK_AppendCounter(counterInfo.key(), counterInfo.ts(), counterInfo.value()); + } + + // parserSliceObj + for (auto i = 0; i < mockData.sliceobj_size(); i++) { + int32_t sliceId = mockData.sliceobj(i).id(); + std::string sliceName = mockData.sliceobj(i).name(); + SDK_AppendSliceObject(sliceId, sliceName.c_str()); + } + + // parserSliceInfo + for (auto i = 0; i < mockData.sliceinfo_size(); i++) { + int32_t sliceKey = mockData.sliceinfo(i).id(); + int32_t sliceValue = mockData.sliceinfo(i).value(); + uint64_t startTime = mockData.sliceinfo(i).start_time(); + uint64_t endTime = mockData.sliceinfo(i).end_time(); + SDK_AppendSlice(sliceKey, startTime, endTime, sliceValue); + } + return 0; +} +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/plugin/sdk_plugin_data_parser.h b/trace_streamer/sdk/demo_sdk/plugin/sdk_plugin_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..7acff69fc1eeaa92c3d74893cf75b4f41ad4fb8d --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/plugin/sdk_plugin_data_parser.h @@ -0,0 +1,31 @@ +/* + * 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 SDK_PLUGIN_DATA_PARSER_H +#define SDK_PLUGIN_DATA_PARSER_H + +#include +#include "mock_plugin_result.pb.h" + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +// set table name +void sdk_plugin_init_table_name(); +int32_t sdk_plugin_parser(const uint8_t* data, int32_t len, MockData mockData); +int32_t sdk_plugin_data_parser(const uint8_t* data, int32_t len); +} +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/protos/BUILD.gn b/trace_streamer/sdk/demo_sdk/protos/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0916cd9b338379bc7a3a56b1ce6e8164b66c958f --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/BUILD.gn @@ -0,0 +1,49 @@ +# 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") +OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR = "//third_party/protobuf" +proto_dir = "//third_party/protogen" +mock_dir = "$proto_dir/types/plugins/mock_data" +config("ts_proto_include_config") { + include_dirs = [] +} +source_set("ts_proto_data_cpp") { + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + cflags = [ + "-ftrapv", + "-D_FORTIFY_SOURCE=2 -O2", + "-Wno-zero-length-array", + "-std=c++17", + ] + + if (!is_win) { + print("xxx") + cflags += [ + "-fPIE", + "-fPIC", + ] + } + if (!use_wasm) { + cflags += [ + "-fstack-protector-strong", # + "-fstack-protector-all", + ] + } + + public_configs = [ ":ts_proto_include_config" ] + sources = [ "${mock_dir}/mock_plugin_result.pb.cc" ] +} diff --git a/trace_streamer/sdk/demo_sdk/protos/README_zh.md b/trace_streamer/sdk/demo_sdk/protos/README_zh.md new file mode 100755 index 0000000000000000000000000000000000000000..6e49694e23aafe5dcfd18c921519b3f5edda1911 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/README_zh.md @@ -0,0 +1,10 @@ +# protos 代码仓 + + + +`services` 目录下存放的是 服务接口定义, + +`types` 目录下存放的是 具体插件业务相关的类型定义,主要为配置类型和结果类型定义。 + +例如,`types/plugins/cpu_data/` 目录存放CPU数据插件的配置类型和结果类型。 + diff --git a/trace_streamer/sdk/demo_sdk/protos/protogen.sh b/trace_streamer/sdk/demo_sdk/protos/protogen.sh new file mode 100755 index 0000000000000000000000000000000000000000..1560e67f17fe6e8fe3b79fce6dfbb73170ad48cb --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/protogen.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# 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. +set -e +SOURCE="${BASH_SOURCE[0]}" +cd $(dirname ${SOURCE}) +echo "begin to generate proto based files" +SOURCE=$(dirname ${SOURCE}) +proto_dir="." +services_dir="$proto_dir/services" +# kernel_version="5.10.79_aarch64" +kernel_version="." +mock_data_dir="$proto_dir/types/plugins/mock_data" +proto_array=("$mock_data_dir/mock_plugin_result.proto") + +export LD_LIBRARY_PATH=../../out/linux +for ((i = 0; i < ${#proto_array[@]}; i ++)) +do + newpath=$(dirname ${proto_array[$i]}) + newpath=${newpath:2} + cppout=../../third_party/protogen/$newpath + mkdir -p $cppout + ../../../out/linux/protoc --proto_path=$mock_data_dir --cpp_out=$cppout ${proto_array[$i]} +done +echo "generate proto based files over" diff --git a/trace_streamer/sdk/demo_sdk/protos/protos.gni b/trace_streamer/sdk/demo_sdk/protos/protos.gni new file mode 100755 index 0000000000000000000000000000000000000000..f8582402a8b542f4435fdeda2e18278b1bd725e7 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/protos.gni @@ -0,0 +1,36 @@ +# 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/config.gni") + +subsys_name = OHOS_PROFILER_SUBSYS_NAME +part_name = OHOS_PROFILER_PART_NAME +subsys_x64_out = "clang_x64/$subsys_name/$part_name" +libc_dir_proto = rebase_path("$asdk_libs_dir", "//") +root_output_dir_proto = rebase_path("$root_out_dir", "//") + +#host:clang_x64 default:arm mingw:mingw_x86_64 +if (current_toolchain != host_toolchain) { + if (current_toolchain == default_toolchain) { + root_output_dir_proto = "$root_output_dir_proto/clang_x64" + } else { + root_output_dir_proto = + get_path_info("$root_output_dir_proto", "dir") + "/clang_x64" + } +} +protoc = root_output_dir_proto +print("default_toolchain = ", default_toolchain) +print("current_toolchain = ", current_toolchain) +print("host_toolchain = ", host_toolchain) +print("root_out_dir = ", root_out_dir) +print("root_output_dir_proto = ", root_output_dir_proto) diff --git a/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_config.proto b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..1f267cff59c12b1a2a37386930a546572eaeee22 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_config.proto @@ -0,0 +1,21 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message MockConfig { + uint32 version = 1; + string counters = 2; + bool stop_gator = 3; +} diff --git a/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_config_standard.proto b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_config_standard.proto new file mode 100755 index 0000000000000000000000000000000000000000..8e62d2e991387156dd257d7ef840ccc452cc0434 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_config_standard.proto @@ -0,0 +1,19 @@ +// 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. +syntax = "proto3"; +package ForStandard; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +message MockConfig { + string msg = 1; +} diff --git a/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_result.proto b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..780c39196cd9a7fb55e57eb04b3241fbd6d56069 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_result.proto @@ -0,0 +1,51 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message SliceObj { + int32 id = 1; + string name = 2; +} + +message SliceInfo { + int32 id = 1; + int32 value = 2; + uint64 start_time = 3; + uint64 end_time = 4; +} + +message CounterObj { + int32 id = 1; + string name = 2; +} + +message CounterInfo { + int32 key = 1; + int32 value = 2; + uint64 ts = 3; +} + +message MockData { + repeated CounterObj counterobj = 1; + repeated CounterInfo counterinfo = 2; + repeated SliceObj sliceobj = 3; + repeated SliceInfo sliceinfo = 4; +} + +message MockDataArr { + repeated MockData mockdata = 1; +} diff --git a/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_result_standard.proto b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_result_standard.proto new file mode 100755 index 0000000000000000000000000000000000000000..bebfd6b87f10d2616bc88ce5567dd838f3f8364e --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/protos/types/plugins/mock_data/mock_plugin_result_standard.proto @@ -0,0 +1,47 @@ +// 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. + +syntax = "proto3"; +package ForStandard; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +message SliceObj { + int32 id = 1; + string name = 2; +} + +message SliceInfo { + int32 id = 1; + int32 value = 2; + uint64 start_time = 3; + uint64 end_time = 4; +} + +message CounterObj { + int32 id = 1; + string name = 2; +} + +message CounterInfo { + int32 key = 1; + int32 value = 2; + uint64 ts = 3; +} + +message MockData { + repeated CounterObj counterobj = 1; + repeated CounterInfo counterinfo = 2; + repeated SliceObj sliceobj = 3; + repeated SliceInfo sliceinfo = 4; +} diff --git a/trace_streamer/sdk/demo_sdk/rpc/http_server.cpp b/trace_streamer/sdk/demo_sdk/rpc/http_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3694e873cd4c05df28616d6fe890980c598417f1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/rpc/http_server.cpp @@ -0,0 +1,387 @@ +/* + * 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 "http_server.h" +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include "log.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +void HttpServer::RegisterRpcFunction(RpcServer* rpc) +{ + rpcFunctions_.clear(); + + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + + auto parsedata = std::bind(&RpcServer::ParseData, rpc, _1, _2, _3); + rpcFunctions_["/parsedata"] = parsedata; + + auto parsedataover = std::bind(&RpcServer::ParseDataOver, rpc, _1, _2, _3); + rpcFunctions_["/parsedataover"] = parsedataover; + + auto sqlquery = std::bind(&RpcServer::SqlQuery, rpc, _1, _2, _3); + rpcFunctions_["/sqlquery"] = sqlquery; + + auto sqloperate = std::bind(&RpcServer::SqlOperate, rpc, _1, _2, _3); + rpcFunctions_["/sqloperate"] = sqloperate; + + auto reset = std::bind(&RpcServer::Reset, rpc, _1, _2, _3); + rpcFunctions_["/reset"] = reset; +} + +#ifdef _WIN32 +void HttpServer::Run(int32_t port) +{ + WSADATA ws{}; + if (WSAStartup(MAKEWORD(WS_VERSION_FIRST, WS_VERSION_SEC), &ws) != 0) { + return; + } + if (!CreateSocket(port)) { + return; + } + WSAEVENT events[COUNT_SOCKET]; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + if ((events[i] = WSACreateEvent()) == WSA_INVALID_EVENT) { + TS_LOGE("WSACreateEvent error %d", WSAGetLastError()); + return; + } + WSAEventSelect(sockets_[i].GetFd(), events[i], FD_ACCEPT | FD_CLOSE); + } + + while (!isExit_) { + ClearDeadClientThread(); + + int32_t index = WSAWaitForMultipleEvents(COUNT_SOCKET, events, false, pollTimeOut_, false); + if (index == WSA_WAIT_FAILED) { + TS_LOGE("WSAWaitForMultipleEvents error %d", WSAGetLastError()); + break; + } else if (index == WSA_WAIT_TIMEOUT) { + continue; + } + + index = index - WSA_WAIT_EVENT_0; + WSANETWORKEVENTS event; + WSAEnumNetworkEvents(sockets_[index].GetFd(), events[index], &event); + if (event.lNetworkEvents & FD_ACCEPT) { + if (event.iErrorCode[FD_ACCEPT_BIT] != 0) { + continue; + } + + std::unique_ptr client = std::make_unique(); + if (sockets_[index].Accept(client->sock_)) { + client->thread_ = std::thread(&HttpServer::ProcessClient, this, std::ref(client->sock_)); + clientThreads_.push_back(std::move(client)); + } else { + TS_LOGE("http socket accept error"); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + for (const auto& it : clientThreads_) { + if (it->thread_.joinable()) { + it->sock_.Close(); + it->thread_.join(); + } + } + clientThreads_.clear(); + + WSACleanup(); +} +#else +void HttpServer::Run(int32_t port) +{ + if (SIG_ERR == signal(SIGPIPE, SIG_IGN)) { + return; + } + + if (!CreateSocket(port)) { + return; + } + TS_LOGI("http server running"); + struct pollfd fds[COUNT_SOCKET]; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + fds[i] = {sockets_[i].GetFd(), POLLIN, 0}; + } + while (!isExit_) { + ClearDeadClientThread(); + if (poll(fds, sizeof(fds) / sizeof(pollfd), pollTimeOut_) <= 0) { + continue; // try again + } + + for (int32_t i = 0; i < 1; i++) { + if (fds[i].revents != POLLIN) { + continue; + } + std::unique_ptr client = std::make_unique(); + if (sockets_[i].Accept(client->sock_)) { + client->thread_ = std::thread(&HttpServer::ProcessClient, this, std::ref(client->sock_)); + clientThreads_.push_back(std::move(client)); + } else { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + for (const auto& it : clientThreads_) { + if (it->thread_.joinable()) { + it->sock_.Close(); + it->thread_.join(); + } + } + clientThreads_.clear(); + + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + sockets_[i].Close(); + } + TS_LOGI("http server exit"); +} +#endif + +void HttpServer::Exit() +{ + isExit_ = true; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + sockets_[i].Close(); + } +} + +bool HttpServer::CreateSocket(int32_t port) +{ + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + if (!sockets_[i].CreateSocket(i == 0 ? AF_INET : AF_INET6)) { + TS_LOGE("Create http socket error"); + return false; + } + if (!sockets_[i].Bind(port)) { + TS_LOGE("bind http socket error"); + return false; + } + if (!sockets_[i].Listen(SOMAXCONN)) { + TS_LOGE("listen http socket error"); + return false; + } + } + + return true; +} + +void HttpServer::ClearDeadClientThread() +{ + for (auto it = clientThreads_.begin(); it != clientThreads_.end();) { + if (it->get()->sock_.GetFd() != -1) { + it++; + continue; + } + if (it->get()->thread_.joinable()) { + it->get()->thread_.join(); + } + it = clientThreads_.erase(it); + } +} + +#ifdef _WIN32 +void HttpServer::ProcessClient(HttpSocket& client) +{ + std::vector recvBuf(MAXLEN_REQUEST); + size_t recvLen = recvBuf.size(); + size_t recvPos = 0; + RequestST reqST; + WSAEVENT recvEvent = WSACreateEvent(); + if (recvEvent == WSA_INVALID_EVENT) { + TS_LOGE("WSACreateEvent error %d", WSAGetLastError()); + return; + } + WSAEventSelect(client.GetFd(), recvEvent, FD_READ | FD_CLOSE); + while (!isExit_) { + int32_t index = WSAWaitForMultipleEvents(1, &recvEvent, false, pollTimeOut_, false); + if (index == WSA_WAIT_FAILED) { + TS_LOGE("WSAWaitForMultipleEvents error %d", WSAGetLastError()); + break; + } else if (index == WSA_WAIT_TIMEOUT) { + if (reqST.stat != RequstParseStat::INIT) { + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + recvPos = 0; + recvLen = recvBuf.size(); + } + continue; + } + + WSANETWORKEVENTS event; + WSAEnumNetworkEvents(client.GetFd(), recvEvent, &event); + if (event.lNetworkEvents & FD_READ) { + if (event.iErrorCode[FD_READ_BIT] != 0) { + continue; + } + if (!client.Recv(recvBuf.data() + recvPos, recvLen)) { + break; + } + recvPos += recvLen; + ParseRequest(recvBuf.data(), recvPos, reqST); + recvLen = recvBuf.size() - recvPos; + if (reqST.stat == RequstParseStat::RECVING) { + continue; + } + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + } else if (event.lNetworkEvents & FD_CLOSE) { + TS_LOGI("client close socket(%d)", client.GetFd()); + break; + } + } + TS_LOGI("recive client thread exit. socket(%d)", client.GetFd()); + + client.Close(); +} +#else +void HttpServer::ProcessClient(HttpSocket& client) +{ + std::vector recvBuf(MAXLEN_REQUEST); + size_t recvLen = recvBuf.size(); + size_t recvPos = 0; + RequestST reqST; + + struct pollfd fd = {client.GetFd(), POLLIN, 0}; + while (!isExit_) { + int32_t pollRet = poll(&fd, sizeof(fd) / sizeof(pollfd), pollTimeOut_); + if (pollRet < 0) { + TS_LOGE("poll client socket(%d) error: %d:%s", client.GetFd(), errno, strerror(errno)); + break; + } + if (pollRet == 0) { + if (reqST.stat != RequstParseStat::INIT) { + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + recvPos = 0; + recvLen = recvBuf.size(); + } + continue; + } + if (!client.Recv(recvBuf.data() + recvPos, recvLen)) { + TS_LOGI("client exit"); + break; + } + recvPos += recvLen; + ParseRequest(recvBuf.data(), recvPos, reqST); + recvLen = recvBuf.size() - recvPos; + if (reqST.stat == RequstParseStat::RECVING) { + continue; + } + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + } + TS_LOGI("recive client thread exit. socket(%d)", client.GetFd()); + + client.Close(); + TS_LOGI("thread exit"); +} +#endif + +void HttpServer::ProcessRequest(HttpSocket& client, RequestST& request) {} + +void HttpServer::ParseRequest(const uint8_t* requst, size_t& len, RequestST& httpReq) +{ + std::string_view reqStr(reinterpret_cast(requst), len); + size_t bodyPos = reqStr.find("\r\n\r\n"); + if (bodyPos == 0) { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } else if (bodyPos == std::string_view::npos) { + httpReq.stat = RequstParseStat::RECVING; + return; + } + std::string_view header = reqStr.substr(0, bodyPos); + bodyPos += strlen("\r\n\r\n"); + httpReq.bodyLen = reqStr.size() - bodyPos; + + std::vector headerlines = StringSplit(header, "\r\n"); + // at least 1 line in headerlines, such as "GET /parsedata HTTP/1.1" + std::vector requestItems = StringSplit(headerlines[0], " "); + const size_t indexHttpMethod = 0; + const size_t indexHttpUri = 1; + const size_t indexHttpVersion = 2; + const size_t countRequestItems = 3; + if (requestItems.size() != countRequestItems || requestItems[indexHttpVersion] != "HTTP/1.1") { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } + httpReq.method = requestItems[indexHttpMethod]; + httpReq.uri = requestItems[indexHttpUri]; + + for (size_t i = 1; i < headerlines.size(); i++) { + size_t tagPos = headerlines[i].find(":"); + if (tagPos == std::string_view::npos) { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } + std::string_view tag = headerlines[i].substr(0, tagPos); + if (strncasecmp(tag.data(), "Content-Length", tag.size()) == 0) { + std::string value(headerlines[i].data() + tagPos + strlen(":"), + headerlines[i].size() - tagPos - strlen(":")); + size_t conterntLen = atoi(value.c_str()); + if (conterntLen > httpReq.bodyLen) { + httpReq.stat = RequstParseStat::RECVING; + return; + } else if (conterntLen < httpReq.bodyLen) { + httpReq.bodyLen = conterntLen; + } + } + } + + if (httpReq.bodyLen > 0) { + httpReq.body = (requst + bodyPos); + } + httpReq.stat = RequstParseStat::OK; + len -= (bodyPos + httpReq.bodyLen); + return; +} + +std::vector HttpServer::StringSplit(std::string_view source, std::string_view split) +{ + std::vector result; + if (!split.empty()) { + size_t pos = 0; + while ((pos = source.find(split)) != std::string_view::npos) { + // split + std::string_view token = source.substr(0, pos); + if (!token.empty()) { + result.push_back(token); + } + source = source.substr(pos + split.size(), source.size() - token.size() - split.size()); + } + } + // add last token + if (!source.empty()) { + result.push_back(source); + } + return result; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/rpc/http_server.h b/trace_streamer/sdk/demo_sdk/rpc/http_server.h new file mode 100644 index 0000000000000000000000000000000000000000..6e47a50004186e90f014e7ed2bebdbea862f432f --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/rpc/http_server.h @@ -0,0 +1,74 @@ +/* + * 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 RPC_HTTPD_H +#define RPC_HTTPD_H + +#include +#include +#include +#include +#include +#include "http_socket.h" +#include "rpc_server.h" +namespace SysTuning { +namespace TraceStreamer { +class HttpServer { +public: + void RegisterRpcFunction(RpcServer* rpc); + void Run(int32_t port = 9001); + void Exit(); + + static constexpr size_t MAXLEN_REQUEST = 2 * 1024 + 1024 * 1024; // header 2K + body 1M + +private: + struct ClientThread { + HttpSocket sock_; + std::thread thread_; + }; + + enum RequstParseStat { INIT = 0, OK, BAD, RECVING }; + + struct RequestST { + int32_t stat = RequstParseStat::INIT; + std::string method; + std::string uri; + const uint8_t* body; + size_t bodyLen; + }; + + bool CreateSocket(int32_t port); + void ProcessClient(HttpSocket& client); + static void ProcessRequest(HttpSocket& client, RequestST& request); + static void ParseRequest(const uint8_t* requst, size_t& len, RequestST& httpReq); + void ClearDeadClientThread(); + static std::vector StringSplit(std::string_view source, std::string_view split); + + static const int32_t COUNT_SOCKET = 1; + HttpSocket sockets_[COUNT_SOCKET]; // ipv4 and ipv6 + std::atomic_bool isExit_ = {false}; + std::vector> clientThreads_; + using RpcFunction = std::function; + std::map rpcFunctions_; + const int32_t pollTimeOut_ = 1000; +#ifdef _WIN32 + const uint32_t WS_VERSION_FIRST = 2; + const uint32_t WS_VERSION_SEC = 2; +#endif +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // RPC_HTTPD_H diff --git a/trace_streamer/sdk/demo_sdk/rpc/http_socket.cpp b/trace_streamer/sdk/demo_sdk/rpc/http_socket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51c327ddbea5dbcf2179ee9063ba258c9296eb38 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/rpc/http_socket.cpp @@ -0,0 +1,173 @@ +/* + * 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 "http_socket.h" +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +HttpSocket::~HttpSocket() +{ + Close(); +} +bool HttpSocket::CreateSocket(int32_t domain) +{ + SOCKET sockId = socket(domain, SOCK_STREAM, 0); + if (sockId == INVALID_SOCKET) { + TS_LOGE("CreateSocket socket error, domain %d: %d:%s", domain, errno, strerror(errno)); + return false; + } + sockId_ = sockId; + if (domain == AF_INET || domain == AF_INET6) { + int32_t enable = 1; + if (setsockopt(sockId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), sizeof(enable)) == + SOCKET_ERROR) { + Close(); + return false; + } + if (domain == AF_INET6) { + if (setsockopt(sockId, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&enable), sizeof(enable)) == + SOCKET_ERROR) { + Close(); + return false; + } + } + } + domain_ = domain; + TS_LOGI("CreateSocket socket ok, socket %d domain %d", sockId_, domain); + return true; +} + +bool HttpSocket::Bind(int32_t port) +{ + if (sockId_ == INVALID_SOCKET) { + TS_LOGE("the socket not created"); + return false; + } + + if (domain_ == AF_INET) { + struct sockaddr_in addr; + std::fill(reinterpret_cast(&addr), reinterpret_cast(&addr) + sizeof(addr), 0); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htons(INADDR_ANY); + addr.sin_port = htons(static_cast(port)); + if (bind(sockId_, reinterpret_cast(&addr), sizeof(addr)) == -1) { + TS_LOGE("bind ipv4 socket error, port %d: %d:%s", port, errno, strerror(errno)); + return false; + } + } else if (domain_ == AF_INET6) { + struct sockaddr_in6 addr; + std::fill(reinterpret_cast(&addr), reinterpret_cast(&addr) + sizeof(addr), 0); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons(static_cast(port)); + if (bind(sockId_, reinterpret_cast(&addr), sizeof(addr)) == -1) { + TS_LOGE("bind ipv6 socket error, port %d: %d:%s", port, errno, strerror(errno)); + return false; + } + } else { + return false; + } + TS_LOGI("bind socket ok, port %d", port); + return true; +} + +bool HttpSocket::Listen(int32_t maxConn) +{ + if (listen(sockId_, maxConn) == SOCKET_ERROR) { + TS_LOGE("listen socket error: %d:%s", errno, strerror(errno)); + return false; + } + TS_LOGI("listen socket ok, maxConn %d", maxConn); + return true; +} + +bool HttpSocket::Accept(HttpSocket& client) +{ + int32_t clientId = accept(sockId_, nullptr, nullptr); + if (clientId == INVALID_SOCKET) { + TS_LOGE("accept socket error: %d:%s", errno, strerror(errno)); + return false; + } + + client.domain_ = domain_; + client.sockId_ = clientId; + TS_LOGI("accept client socket id %d domain %d", clientId, domain_); + return true; +} + +bool HttpSocket::Recv(void* data, size_t& len) +{ +#ifdef _WIN32 + ssize_t recvLen = recv(sockId_, static_cast(data), len, 0); +#else + ssize_t recvLen = recv(sockId_, data, len, 0); +#endif + if (recvLen == SOCKET_ERROR) { + if (errno == EAGAIN) { + recvLen = 0; + } else { + TS_LOGE("recv from socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + return false; + } + } else if (recvLen == 0) { + TS_LOGI("client socket(%d) closed", sockId_); + return false; + } + len = recvLen; + TS_LOGD("Recv from socket(%d) len %zu", sockId_, len); + return true; +} + +bool HttpSocket::Send(const void* data, size_t len) +{ +#ifdef _WIN32 + ssize_t sendLen = send(sockId_, static_cast(data), len, 0); +#else + ssize_t sendLen = send(sockId_, data, len, 0); +#endif + if (sendLen == SOCKET_ERROR) { + TS_LOGE("send to socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + return false; + } + TS_LOGI("send to socket(%d) len %zu", sockId_, len); + return true; +} + +void HttpSocket::Close() +{ + if (sockId_ == INVALID_SOCKET) { + return; + } + TS_LOGI("close socket(%d)", sockId_); +#ifdef _WIN32 + if (closesocket(sockId_) == SOCKET_ERROR) { +#else + if (close(sockId_) == SOCKET_ERROR) { +#endif + TS_LOGE("close socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + } + sockId_ = INVALID_SOCKET; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/rpc/http_socket.h b/trace_streamer/sdk/demo_sdk/rpc/http_socket.h new file mode 100644 index 0000000000000000000000000000000000000000..39bf9849c368309b90aec74919d83293acb416d0 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/rpc/http_socket.h @@ -0,0 +1,53 @@ +/* + * 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 RPC_HTTPSOCKET_H +#define RPC_HTTPSOCKET_H + +#include +namespace SysTuning { +namespace TraceStreamer { +class HttpSocket { +public: + HttpSocket() {} + HttpSocket(int32_t sockId, int32_t domain) : sockId_(sockId), domain_(domain) {} + ~HttpSocket(); + + bool CreateSocket(int32_t domain); + bool Bind(int32_t port); + bool Listen(int32_t maxConn); + bool Accept(HttpSocket& client); + bool Recv(void* data, size_t& len); + bool Send(const void* data, size_t len); + void Close(); + bool IsValid() const + { + return sockId_ != INVALID_SOCKET; + } + int32_t GetFd() const + { + return sockId_; + } + +private: + int32_t sockId_ = -1; + int32_t domain_ = 0; + using SOCKET = int32_t; + const int32_t SOCKET_ERROR = -1; + const SOCKET INVALID_SOCKET = -1; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RPC_HTTPSOCKET_H diff --git a/trace_streamer/sdk/demo_sdk/rpc/rpc_server.cpp b/trace_streamer/sdk/demo_sdk/rpc/rpc_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..928f10cb338ee10d89117590471fa1252fef1fa8 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/rpc/rpc_server.cpp @@ -0,0 +1,110 @@ +/* + * 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 "rpc_server.h" + +#include +#include +#include + +#include "log.h" +#include "meta.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +namespace SysTuning { +namespace TraceStreamer { + +bool RpcServer::SqlOperate(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("RPC SqlOperate(%s, %zu)", sql.c_str(), len); + + int32_t ret = ts_->OperateDatabase(sql); + if (resultCallBack) { + std::string response = "ok\r\n"; + if (ret != 0) { + response = "dberror\r\n"; + } + resultCallBack(response, SEND_FINISH, 0); + } + return (ret == 0); +} + +bool RpcServer::SqlQuery(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("RPC SqlQuery %zu:%s", len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, resultCallBack); + if (resultCallBack && ret != 0) { + resultCallBack("dberror\r\n", SEND_FINISH, 0); + } + ts_->SetCancel(false); + return (ret == 0); +} + +void RpcServer::CancelSqlQuery() +{ + ts_->SetCancel(true); +} + +bool RpcServer::Reset(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + UNUSED(data); + UNUSED(len); + TS_LOGI("RPC reset trace_streamer"); + ts_->WaitForParserEnd(); + ts_ = std::make_unique(); + if (resultCallBack) { + resultCallBack("ok\r\n", SEND_FINISH, 0); + } + return true; +} + +int32_t RpcServer::WasmSqlQuery(const uint8_t* data, size_t len, uint8_t* out, int32_t outLen) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("WASM RPC SqlQuery outlen(%d) sql(%zu:%s)", outLen, len, sql.c_str()); + int32_t ret = ts_->SearchDatabase(sql, out, outLen); + return ret; +} + +int32_t RpcServer::WasmGetPluginNameWithCallback(const uint8_t* data, size_t len) const +{ + std::string pluginName(reinterpret_cast(data), len); + TS_LOGI("WASM pluginName(%zu:%s)", len, pluginName.c_str()); + + int32_t ret = ts_->sdkDataParser_->GetPluginName(pluginName); + return ret; +} + +int32_t RpcServer::WasmSqlQueryWithCallback(const uint8_t* data, size_t len, ResultCallBack callback) const +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("WASM RPC SqlQuery sql(%zu:%s)", len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, callback); + return ret; +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/rpc/rpc_server.h b/trace_streamer/sdk/demo_sdk/rpc/rpc_server.h new file mode 100644 index 0000000000000000000000000000000000000000..191cbde2262dc0c6b52c510ea277f58a02aa6ab1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/rpc/rpc_server.h @@ -0,0 +1,45 @@ +/* + * 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 RPC_RPC_H +#define RPC_RPC_H + +#include +#include +#include "../trace_streamer/trace_streamer_selector.h" +#include "../sdk/sdk_data_parser.h" +namespace SysTuning { +namespace TraceStreamer { +class RpcServer { +public: + using ResultCallBack = std::function; + using TraceRangeCallbackFunction = std::function; + // In order to bind HTTP, maintain a unified interface, even if some parameters are useless + bool SqlOperate(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool SqlQuery(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool Reset(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + void CancelSqlQuery(); + + // only for wasm, no callback + int32_t WasmSqlQuery(const uint8_t* data, size_t len, uint8_t* out, int32_t outLen); + int32_t WasmSqlQueryWithCallback(const uint8_t* data, size_t len, ResultCallBack callback) const; + int32_t WasmGetPluginNameWithCallback(const uint8_t* data, size_t len) const; + +public: + std::unique_ptr ts_ = std::make_unique(); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RPC_RPC_H diff --git a/trace_streamer/sdk/demo_sdk/sdk/sdk_data_parser.cpp b/trace_streamer/sdk/demo_sdk/sdk/sdk_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c706c9cf0147e2ef5eed2df6f0d0fe64acb75a6 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/sdk_data_parser.cpp @@ -0,0 +1,204 @@ +/* + * 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 "sdk_data_parser.h" +#include +#include +#include +#include +#include "clock_filter.h" +#include "gpu_counter_object_table.h" +#include "gpu_counter_table.h" +#include "json.hpp" +#include "log.h" +#include "meta.h" +#include "meta_table.h" +#include "sdk_plugin_data_parser.h" +#include "slice_object_table.h" +#include "slice_table.h" +#include "ts_common.h" +#include "ts_sdk_api.h" + +namespace SysTuning { +namespace TraceStreamer { +SDKDataParser::SDKDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +int32_t SDKDataParser::GetPluginName(std::string pluginName) +{ + pluginName.replace(pluginName.find("-"), 1, "_"); + counterTableName_ = pluginName + "_" + "counter_table"; + counterObjectTableName_ = pluginName + "_" + "counterobj_table"; + sliceTableName_ = pluginName + "_" + "slice_table"; + sliceObjectName_ = pluginName + "_" + "sliceobj_table"; + return 0; +} +int32_t SDKDataParser::ParseDataOver(TraceRangeCallbackFunction traceRangeCallbackFunction) +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + std::string traceRangeStr = + std::to_string(traceDataCache_->traceStartTime_) + ";" + std::to_string(traceDataCache_->traceEndTime_) + ";"; + traceRangeCallbackFunction(traceRangeStr); + return 0; +} + +int32_t SDKDataParser::GetJsonConfig(QueryResultCallbackFunction queryResultCallbackFunction) +{ + queryResultCallbackFunction(jsonConfig_, 1, 1); + return 0; +} + +int32_t SDKDataParser::ParserData(const uint8_t* data, int32_t len, int32_t componentId) +{ + if (componentId == DATA_TYPE_CLOCK) { + ParserClock(data, len); + return 0; + } + sdk_plugin_data_parser(data, len); + return 0; +} + +int32_t SDKDataParser::ParserClock(const uint8_t* data, int32_t len) +{ + return streamFilters_->clockFilter_->InitSnapShotTimeRange(data, len); +} + +int32_t SDKDataParser::SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName) +{ + if (!g_isUseExternalModify) { + counterTableName_ = counterTableName; + counterObjectTableName_ = counterObjectTableName; + sliceTableName_ = sliceTableName; + sliceObjectName_ = sliceObjectName; + } + UpdateJson(); + return 0; +} + +int32_t SDKDataParser::UpdateJson() +{ + using json = nlohmann::json; + json jMessage = json::parse(jsonConfig_); + if (jMessage.is_discarded()) { + return -1; + } + + jMessage["tableConfig"]["showType"][0]["tableName"] = counterTableName_; + jMessage["tableConfig"]["showType"][0]["inner"]["tableName"] = counterObjectTableName_; + jMessage["tableConfig"]["showType"][1]["tableName"] = sliceTableName_; + jMessage["tableConfig"]["showType"][1]["inner"]["tableName"] = sliceObjectName_; + + jsonConfig_ = jMessage.dump(); + return 0; +} + +// 创建对应的表 +int32_t SDKDataParser::CreateTableByJson() +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "meta"); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_meta"); +#endif + // 创建对应的表 + CreateCounterObjectTable(counterObjectTableName_); + CreateCounterTable(counterTableName_); + CreateSliceObjectTable(sliceObjectName_); + CreateSliceTable(sliceTableName_); + return 0; +} + +// 根据Json配置创建couter object表 +int32_t SDKDataParser::CreateCounterObjectTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// 根据Json配置创建couter表 +int32_t SDKDataParser::CreateCounterTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// 根据Json配置创建slice object表 +int32_t SDKDataParser::CreateSliceObjectTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// 根据Json配置创建slice表 +int32_t SDKDataParser::CreateSliceTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// Counter业务 +int32_t SDKDataParser::AppendCounterObject(int32_t counterId, const char* columnName) +{ + traceDataCache_->GetGpuCounterObjectData()->AppendNewData(counterId, columnName); + return 0; +} + +int32_t SDKDataParser::AppendCounter(int32_t counterId, uint64_t ts, int32_t value) +{ + auto newTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, ts, newTs); + traceDataCache_->GetGpuCounterData()->AppendNewData(newTs, counterId, value); + return 0; +} + +// Slice业务 +int32_t SDKDataParser::AppendSliceObject(int32_t sliceId, const char* columnName) +{ + traceDataCache_->GetSliceObjectData()->AppendNewData(sliceId, columnName); + return 0; +} + +int32_t SDKDataParser::AppendSlice(int32_t sliceId, uint64_t ts, uint64_t endTs, int32_t value) +{ + auto newTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + auto newEndTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, endTs); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, ts, newTs); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, endTs, newEndTs); + traceDataCache_->GetSliceTableData()->AppendNewData(sliceId, newTs, newEndTs, value); + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/sdk/sdk_data_parser.h b/trace_streamer/sdk/demo_sdk/sdk/sdk_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..da082b2213696a01d2fd8259a1c2995261e40bb1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/sdk_data_parser.h @@ -0,0 +1,94 @@ +/* + * 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 SDK_DATA_PARSER_H +#define SDK_DATA_PARSER_H + +#include +#include +#include "file.h" +#include "../parser/htrace_plugin_time_parser.h" +#include "../table/table_base.h" +#include "../trace_streamer/trace_streamer_selector.h" + +namespace SysTuning { +namespace TraceStreamer { + +enum Third_Party_Wasm_Id { + DATA_TYPE_MOCK_PLUGIN = 0, + DATA_TYPE_CLOCK = 100, +}; +class SDKDataParser : public HtracePluginTimeParser { +public: + using TraceRangeCallbackFunction = std::function; + using QueryResultCallbackFunction = std::function; + SDKDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~SDKDataParser(){}; + + // third_party + int32_t CreateTableByJson(); + int32_t SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName); + int32_t GetJsonConfig(QueryResultCallbackFunction queryResultCallbackFunction); + int32_t GetPluginName(std::string pluginName); + int32_t ParseDataOver(TraceRangeCallbackFunction traceRangeCallbackFunction); + int32_t ParserData(const uint8_t* data, int32_t len, int32_t componentId); + int32_t AppendCounterObject(int32_t counterId, const char* columnName); + int32_t AppendCounter(int32_t counterId, uint64_t ts, int32_t value); + int32_t AppendSliceObject(int32_t sliceId, const char* columnName); + int32_t AppendSlice(int32_t sliceId, uint64_t ts, uint64_t endTs, int32_t value); + +private: + int32_t CreateCounterObjectTable(const std::string& tableName); + int32_t CreateCounterTable(const std::string& tableName); + int32_t CreateSliceObjectTable(const std::string& tableName); + int32_t CreateSliceTable(const std::string& tableName); + int32_t ParserClock(const uint8_t* data, int32_t len); + int32_t UpdateJson(); + +public: + std::string counterTableName_ = "counter_table"; + std::string counterObjectTableName_ = "gpu_counter_object"; + std::string sliceTableName_ = "slice_table"; + std::string sliceObjectName_ = "slice_object_table"; + std::string jsonConfig_ = + "{\"tableConfig\":{\"showType\":[{\"tableName\":\"counter_table\",\"inner\":{\"tableName\":\"gpu_counter_" + "object\"," + "\"columns\":[{\"column\":\"counter_name\",\"type\":\"STRING\",\"displayName\":\"\",\"showType\":[0]},{" + "\"column\":" + "\"counter_id\",\"type\":\"INTEGER\",\"displayName\":\"\",\"showType\":[0]}]},\"columns\":[{\"column\":\"ts\"," + "\"type\":\"INTEGER\",\"displayName\":\"TimeStamp\",\"showType\":[1,3]},{\"column\":\"counter_id\",\"type\":" + "\"INTEGER\",\"displayName\":\"MonitorValue\",\"showType\":[1,3]},{\"column\":\"value\",\"type\":\"INTEGER\"," + "\"displayName\":\"Value\",\"showType\":[1,3]}]},{\"tableName\":\"slice_table\",\"inner\":{\"tableName\":" + "\"slice_" + "object_table\",\"columns\":[{\"column\":\"slice_name\",\"type\":\"STRING\",\"displayName\":\"\",\"showType\":[" + "0]}," + "{\"column\":\"slice_id\",\"type\":\"INTEGER\",\"displayName\":\"\",\"showType\":[0]}]},\"columns\":[{" + "\"column\":" + "\"start_ts\",\"type\":\"INTEGER\",\"displayName\":\"startts\",\"showType\":[2,3]},{\"column\":\"end_ts\"," + "\"type\":" + "\"INTEGER\",\"displayName\":\"endts\",\"showType\":[2,3]},{\"column\":\"slice_id\",\"type\":\"INTEGER\"," + "\"displayName\":\"slice_id\",\"showType\":[2,3]},{\"column\":\"value\",\"type\":\"INTEGER\",\"displayName\":" + "\"Value\",\"showType\":[2,3]}]}]},\"settingConfig\":{\"name\":\"mailG77\",\"configuration\":{\"version\":{" + "\"type\":\"number\",\"default\":\"1\",\"description\":\"gatordversion\"},\"counters\":{\"type\":\"string\"," + "\"enum\":[\"ARM_Mali-TTRx_JS1_ACTIVE\",\"ARM_Mali-TTRx_JS0_ACTIVE\",\"ARM_Mali-TTRx_GPU_ACTIVE\",\"ARM_Mali-" + "TTRx_FRAG_ACTIVE\"]},\"stop_gator\":{\"type\":\"boolean\",\"default\":\"true\",\"description\":\"stop_gator\"}" + "}}}"; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SDK_DATA_PARSER_H diff --git a/trace_streamer/sdk/demo_sdk/sdk/ts.gni b/trace_streamer/sdk/demo_sdk/sdk/ts.gni new file mode 100755 index 0000000000000000000000000000000000000000..16279772850e6b180cc5c0b02a8945bfef54999b --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/ts.gni @@ -0,0 +1,61 @@ +# 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. +OHOS_PROTO_DIR = "" + +if (target_os == "linux" || target_os == "macx" || target_os == "windows") { + # OHOS_FTRACE_PROTO_DIR="//third_party/protogen" + OHOS_FTRACE_PROTO_DIR = "//src/multi_platform" + + # OHOS_MEMORY_PROTO_DIR="//third_party/protogen" + OHOS_MEMORY_PROTO_DIR = "//src/multi_platform" + + # OHOS_HILOG_PROTO_DIR="//third_party/protogen" + OHOS_HILOG_PROTO_DIR = "//src/multi_platform" + + # OHOS_NATIVE_HOOK_PROTO_DIR="//third_party/protogen" + OHOS_NATIVE_HOOK_PROTO_DIR = "//src/multi_platform" + + # OHOS_HIDUMP_PROTO_DIR="//third_party/protogen" + OHOS_HIDUMP_PROTO_DIR = "//src/multi_platform" + + # OHOS_SERVICE_PROTO_DIR = "//third_party/protogen" + OHOS_SERVICE_PROTO_DIR = "//src/multi_platform" + OHOS_PROTO_GEN = "//third_party/protogen" + + # kernel_version = "5.10.79_aarch64" + kernel_version = "." + if (target == "test") { + enable_ts_utest = true + } else { + enable_ts_utest = false + } + is_openharmony = false +} else { + enable_ts_utest = true + use_wasm = false + kernel_version = "." + is_fuzz = false + target = "trace_streamer" + is_openharmony = true + OHOS_FTRACE_PROTO_DIR = "//developtools/profiler/protos/types/plugins/ftrace_data/${kernel_version}" + OHOS_MEMORY_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/memory_data" + OHOS_HILOG_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hilog_data" + OHOS_NATIVE_HOOK_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/native_hook" + OHOS_HIDUMP_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hidump_data" + OHOS_SERVICE_PROTO_DIR = "//developtools/profiler/protos/services" + OHOS_PROTO_GEN = "//out/ohos-arm-release/gen/cpp/developtools/profiler/protos" +} diff --git a/trace_streamer/sdk/demo_sdk/sdk/ts_sdk_api.cpp b/trace_streamer/sdk/demo_sdk/sdk/ts_sdk_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2760f5fcd772a09146df6df77e50cce1b597ac8 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/ts_sdk_api.cpp @@ -0,0 +1,56 @@ +/* + * 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 "ts_sdk_api.h" +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +RpcServer* rpcServer_; +bool g_isUseExternalModify = true; +int32_t SDK_SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName) +{ + rpcServer_->ts_->sdkDataParser_->SetTableName(counterTableName, counterObjectTableName, sliceTableName, + sliceObjectName); + if (g_isUseExternalModify) { + TS_LOGE("If you want to use the SDK_SetTableName, please modify g_isUseExternalModify to false."); + } + return 0; +} + +int32_t SDK_AppendCounterObject(int32_t counterId, const char* columnName) +{ + return rpcServer_->ts_->sdkDataParser_->AppendCounterObject(counterId, columnName); +} +int32_t SDK_AppendCounter(int32_t counterId, uint64_t ts, int32_t value) +{ + return rpcServer_->ts_->sdkDataParser_->AppendCounter(counterId, ts, value); +} +int32_t SDK_AppendSliceObject(int32_t sliceId, const char* columnName) +{ + return rpcServer_->ts_->sdkDataParser_->AppendSliceObject(sliceId, columnName); +} +int32_t SDK_AppendSlice(int32_t sliceId, uint64_t ts, uint64_t endTs, int32_t value) +{ + return rpcServer_->ts_->sdkDataParser_->AppendSlice(sliceId, ts, endTs, value); +} +void SetRpcServer(RpcServer* rpcServer) +{ + rpcServer_ = std::move(rpcServer); +} +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/sdk/ts_sdk_api.h b/trace_streamer/sdk/demo_sdk/sdk/ts_sdk_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4193ecb0477f701680a8082e14f7fc5c2bea1708 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/ts_sdk_api.h @@ -0,0 +1,36 @@ +/* + * 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 TS_SDK_API_H +#define TS_SDK_API_H +#include "../rpc/rpc_server.h" + +#include +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +extern bool g_isUseExternalModify; +int32_t SDK_SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName); +int32_t SDK_AppendCounterObject(int32_t counterId, const char* columnName); +int32_t SDK_AppendCounter(int32_t counterId, uint64_t ts, int32_t value); +int32_t SDK_AppendSliceObject(int32_t sliceId, const char* columnName); +int32_t SDK_AppendSlice(int32_t sliceId, uint64_t ts, uint64_t endTs, int32_t value); +void SetRpcServer(RpcServer* rpcServer); +} +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/sdk/wasm_func.cpp b/trace_streamer/sdk/demo_sdk/sdk/wasm_func.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2daa8d6a54532f065858925371ff64bae106e4b1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/wasm_func.cpp @@ -0,0 +1,144 @@ +/* + * 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 "wasm_func.h" +#include +#include "meta.h" +#include "sdk_data_parser.h" +#include "sdk_plugin_data_parser.h" +#include "table_base.h" +#include "trace_stdtype.h" +#include "ts_sdk_api.h" + +namespace SysTuning { +namespace TraceStreamer { +RpcServer g_wasmTraceStreamer; + +extern "C" { +using QueryResultCallbackFunction = void (*)(const char* data, uint32_t len, int32_t finish, int32_t isConfig); +using TraceRangeCallbackFunction = void (*)(const char* data, uint32_t len); +QueryResultCallbackFunction g_reply; +TraceRangeCallbackFunction g_traceRange; +uint8_t* g_reqBuf; +uint32_t g_reqBufferSize; +uint8_t* g_traceRangeBuf; +uint32_t g_traceRangeSize; +uint8_t* g_PluginNameBuf; +uint32_t g_PluginNameSize; + +void QueryResultCallback(const std::string& jsonResult, int32_t finish, int32_t isConfig) +{ + g_reply(jsonResult.data(), jsonResult.size(), finish, isConfig); +} +void TraceRangeCallback(const std::string& jsonResult) +{ + g_traceRange(jsonResult.data(), jsonResult.size()); +} +EMSCRIPTEN_KEEPALIVE uint8_t* Init(QueryResultCallbackFunction queryResultCallbackFunction, uint32_t reqBufferSize) +{ + SetRpcServer(&g_wasmTraceStreamer); + sdk_plugin_init_table_name(); + g_wasmTraceStreamer.ts_->sdkDataParser_->CreateTableByJson(); + g_reply = queryResultCallbackFunction; + g_reqBuf = new uint8_t[reqBufferSize]; + g_reqBufferSize = reqBufferSize; + return g_reqBuf; +} + +// Get PluginName +EMSCRIPTEN_KEEPALIVE uint8_t* InitPluginName(uint32_t reqBufferSize) +{ + g_PluginNameBuf = new uint8_t[reqBufferSize]; + g_PluginNameSize = reqBufferSize; + return g_PluginNameBuf; +} + +// @deprecated recommand to use TraceStreamerGetPluginNameEx api +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_In_PluginName(const uint8_t* pluginName, int32_t len) +{ + std::string pluginNameStr(reinterpret_cast(pluginName), len); + g_wasmTraceStreamer.ts_->sdkDataParser_->GetPluginName(pluginNameStr); + return 0; +} + +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerGetPluginNameEx(int32_t pluginLen) +{ + return g_wasmTraceStreamer.WasmGetPluginNameWithCallback(g_PluginNameBuf, pluginLen); +} + +EMSCRIPTEN_KEEPALIVE uint8_t* InitTraceRange(TraceRangeCallbackFunction traceRangeCallbackFunction, + uint32_t reqBufferSize) +{ + g_traceRange = traceRangeCallbackFunction; + g_traceRangeBuf = new uint8_t[reqBufferSize]; + g_traceRangeSize = reqBufferSize; + return g_traceRangeBuf; +} + +// The whole file is parsed, and the third party is notified by JS +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_In_ParseDataOver() +{ + MetaData* metaData = g_wasmTraceStreamer.ts_->GetMetaData(); + metaData->InitMetaData(); + metaData->SetParserToolVersion(SDK_VERSION); + metaData->SetParserToolPublishDateTime(SDK_PUBLISHVERSION); + g_wasmTraceStreamer.ts_->sdkDataParser_->ParseDataOver(&TraceRangeCallback); + return 0; +} + +// Get Json configuration interface +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_In_JsonConfig() +{ + g_wasmTraceStreamer.ts_->sdkDataParser_->GetJsonConfig(&QueryResultCallback); + return 0; +} + +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlOperate(const uint8_t* sql, int32_t sqlLen) +{ + if (g_wasmTraceStreamer.SqlOperate(sql, sqlLen, nullptr)) { + return 0; + } + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlOperateEx(int32_t sqlLen) +{ + if (g_wasmTraceStreamer.SqlOperate(g_reqBuf, sqlLen, nullptr)) { + return 0; + } + return -1; +} + +// JS calls third-party parsing interface +EMSCRIPTEN_KEEPALIVE int32_t ParserData(int32_t len, int32_t componentId) +{ + TS_LOGI("wasm ParserData, len = %u", len); + g_wasmTraceStreamer.ts_->sdkDataParser_->ParserData(g_reqBuf, len, componentId); + return 0; +} + +// return the length of result, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlQuery(const uint8_t* sql, int32_t sqlLen, uint8_t* out, int32_t outLen) +{ + return g_wasmTraceStreamer.WasmSqlQuery(sql, sqlLen, out, outLen); +} +// return the length of result, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlQueryEx(int32_t sqlLen) +{ + return g_wasmTraceStreamer.WasmSqlQueryWithCallback(g_reqBuf, sqlLen, &QueryResultCallback); +} + +} // extern "C" +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/sdk/wasm_func.h b/trace_streamer/sdk/demo_sdk/sdk/wasm_func.h new file mode 100644 index 0000000000000000000000000000000000000000..2d634284241dfb078a452a82ceef1215d6bdbb26 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/sdk/wasm_func.h @@ -0,0 +1,34 @@ +/* + * 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 WASM_FUNC_H +#define WASM_FUNC_H + +#include +#include +#include +#include "rpc_server.h" +#include "../trace_streamer/trace_streamer_selector.h" + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +int32_t TraceStreamerSqlOperate(const uint8_t* sql, int32_t sqlLen); +} + +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // RPC_WASM_FUNC_H diff --git a/trace_streamer/sdk/demo_sdk/table/filter_constraints.cpp b/trace_streamer/sdk/demo_sdk/table/filter_constraints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd79bce8c5f922d97914e2549f6b37ff7400cfb8 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/filter_constraints.cpp @@ -0,0 +1,132 @@ +/* + * 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 "filter_constraints.h" + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +void FilterConstraints::AddConstraint(int32_t idx, int32_t col, unsigned char op, bool isSupport) +{ + Constraint& c = constraints_.emplace_back(); + c.idxInaConstraint = idx; + c.col = col; + c.op = op; + c.isSupport = isSupport; +} + +void FilterConstraints::UpdateConstraint(int32_t idx, bool isSupport) +{ + if (idx >= 0 && static_cast(idx) < constraints_.size()) { + constraints_[idx].isSupport = isSupport; + } +} + +void FilterConstraints::AddOrderBy(int32_t col, unsigned char desc) +{ + OrderBy& o = orderBys_.emplace_back(); + o.iColumn = col; + o.desc = desc; +} + +void FilterConstraints::Clear() +{ + constraints_.clear(); + orderBys_.clear(); +} + +void FilterConstraints::ToString(std::string& idxStr) const +{ + idxStr.clear(); + idxStr.reserve(idxStrSize_); + idxStr = "C" + std::to_string(constraints_.size()); + for (size_t i = 0; i < constraints_.size(); i++) { + idxStr += " " + std::to_string(constraints_[i].col); + idxStr += " " + std::to_string(constraints_[i].op); + } + idxStr += " O" + std::to_string(orderBys_.size()); + for (size_t i = 0; i < orderBys_.size(); i++) { + idxStr += " " + std::to_string(orderBys_[i].iColumn); + idxStr += " " + std::to_string(orderBys_[i].desc); + } +} + +void FilterConstraints::FromString(const std::string& idxStr) +{ + const char* p = static_cast(idxStr.c_str()); + char* pNext = nullptr; + TS_ASSERT(*p == 'C'); + errno = 0; + int32_t constraintCount = static_cast(strtol(p + 1, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + for (int32_t i = 0; i < constraintCount; i++) { + p = pNext; + errno = 0; + int32_t col = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + p = pNext; + errno = 0; + unsigned char op = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + + AddConstraint(i, col, op); + } + + pNext++; // jump the ' ' + p = pNext; + TS_ASSERT(*p == 'O'); + errno = 0; + int32_t orderbyCount = static_cast(strtol(p + 1, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + for (int32_t i = 0; i < orderbyCount; i++) { + p = pNext; + errno = 0; + int32_t col = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + p = pNext; + errno = 0; + unsigned char desc = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + + AddOrderBy(col, desc); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/filter_constraints.h b/trace_streamer/sdk/demo_sdk/table/filter_constraints.h new file mode 100644 index 0000000000000000000000000000000000000000..19cdd1372e1a084af3d680147bf7c426462f6bf6 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/filter_constraints.h @@ -0,0 +1,65 @@ +/* + * 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 TABLE_FILTER_CONSTRAINTS_H +#define TABLE_FILTER_CONSTRAINTS_H + +#include +#include +#include "sqlite3.h" + +namespace SysTuning { +namespace TraceStreamer { +class FilterConstraints { +public: + struct Constraint { + int32_t idxInaConstraint; // index in sqlite3_index_info.aConstraint[] + int32_t col; // Column this constraint refers to + unsigned char op; // SQLite op for the constraint + bool isSupport = false; + }; + using OrderBy = sqlite3_index_info::sqlite3_index_orderby; + + FilterConstraints() {} + ~FilterConstraints() {} + void AddConstraint(int32_t idx, int32_t col, unsigned char op, bool isSupport = false); + void UpdateConstraint(int32_t idx, bool isSupport); + void AddOrderBy(int32_t col, unsigned char desc); + void Clear(); + + const std::vector& GetOrderBys() const + { + return orderBys_; + } + + const std::vector& GetConstraints() const + { + return constraints_; + } + + // idxStr format: C col1 op1 ... colN opN O col1 desc1 ... colM descM + // like as "C2 0 2 1 4 O1 0 1" + void ToString(std::string& idxStr) const; + void FromString(const std::string& idxStr); + +private: + std::vector constraints_; + std::vector orderBys_; + const std::size_t idxStrSize_ = 512; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_FILTER_CONSTRAINTS_H diff --git a/trace_streamer/sdk/demo_sdk/table/gpu_counter_object_table.cpp b/trace_streamer/sdk/demo_sdk/table/gpu_counter_object_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e63c4df7916e1a057474145fdc9d52d1074107d --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/gpu_counter_object_table.cpp @@ -0,0 +1,63 @@ +/* + * 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 "gpu_counter_object_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { COUNTER_ID = 0, COUNTER_NAME = 1 }; +GpuCounterObjectTable::GpuCounterObjectTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("counter_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("counter_name", "REAL")); + tablePriKey_.push_back("counter_id"); +} + +GpuCounterObjectTable::~GpuCounterObjectTable() {} + +std::unique_ptr GpuCounterObjectTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +GpuCounterObjectTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstGpuCounterObjectData().Size())), + gpuCounterObjectDataObj_(dataCache->GetConstGpuCounterObjectData()) +{ +} + +GpuCounterObjectTable::Cursor::~Cursor() {} + +int32_t GpuCounterObjectTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case COUNTER_ID: { + sqlite3_result_int64(context_, static_cast(gpuCounterObjectDataObj_.CounterId()[CurrentRow()])); + break; + } + case COUNTER_NAME: { + sqlite3_result_text(context_, gpuCounterObjectDataObj_.CounterName()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/gpu_counter_object_table.h b/trace_streamer/sdk/demo_sdk/table/gpu_counter_object_table.h new file mode 100644 index 0000000000000000000000000000000000000000..d836d9a2d7a2696e4bc72b772bed7e8bd4ce68e9 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/gpu_counter_object_table.h @@ -0,0 +1,51 @@ +/* + * 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 GPU_COUNTER_OBJECT_TABLE_H +#define GPU_COUNTER_OBJECT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class GpuCounterObjectTable : public TableBase { +public: + explicit GpuCounterObjectTable(const TraceDataCache* dataCache); + ~GpuCounterObjectTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + }; + int32_t Column(int32_t column) const override; + + private: + const GpuCounterObject& gpuCounterObjectDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // GPU_COUNTER_OBJECT_TABLE_H diff --git a/trace_streamer/sdk/demo_sdk/table/gpu_counter_table.cpp b/trace_streamer/sdk/demo_sdk/table/gpu_counter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f44e99a0f08e99b2323a5441e083584653230bbd --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/gpu_counter_table.cpp @@ -0,0 +1,68 @@ +/* + * 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 "gpu_counter_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { TS = 0, COUNTER_ID = 1, VALUE = 2 }; +GpuCounterTable::GpuCounterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("counter_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "REAL")); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("counter_id"); +} + +GpuCounterTable::~GpuCounterTable() {} + +std::unique_ptr GpuCounterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +GpuCounterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstGpuCounterData().Size())), + gpuCounterDataObj_(dataCache->GetConstGpuCounterData()) +{ +} + +GpuCounterTable::Cursor::~Cursor() {} + +int32_t GpuCounterTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(gpuCounterDataObj_.TimeStamp()[CurrentRow()])); + break; + } + case COUNTER_ID: { + sqlite3_result_int64(context_, static_cast(gpuCounterDataObj_.CounterId()[CurrentRow()])); + break; + } + case VALUE: { + sqlite3_result_int64(context_, static_cast(gpuCounterDataObj_.Value()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/gpu_counter_table.h b/trace_streamer/sdk/demo_sdk/table/gpu_counter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..9d7e84cd9f100bc972f44198af8c291f35fd5a2e --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/gpu_counter_table.h @@ -0,0 +1,51 @@ +/* + * 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 GPU_COUNTER_TABLE_H +#define GPU_COUNTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class GpuCounterTable : public TableBase { +public: + explicit GpuCounterTable(const TraceDataCache* dataCache); + ~GpuCounterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + }; + int32_t Column(int32_t column) const override; + + private: + const GpuCounter& gpuCounterDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // GPU_COUNTER_TABLE_H diff --git a/trace_streamer/sdk/demo_sdk/table/index_map.cpp b/trace_streamer/sdk/demo_sdk/table/index_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c84d66a3e06d8cbb35c8e724be7bacd54f1f5e22 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/index_map.cpp @@ -0,0 +1,67 @@ +/* + * 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 "index_map.h" + +#include + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +IndexMap::IndexMap(TableRowId start, TableRowId end) : end_(end), current_(start), start_(start), type_(COMPACT) {} + +void IndexMap::CovertToIndexMap() +{ + if (converted_) { + indexType_ = INDEX_TYPE_OUTER_INDEX; + return; + } + converted_ = true; + if (indexType_ == INDEX_TYPE_ID && HasData()) { + for (auto i = start_; i < end_; i++) { + rowIndex_.push_back(i); + } + current_ = start_ = 0; + end_ = rowIndex_.size(); + empty_ = !rowIndex_.size(); + } + indexType_ = INDEX_TYPE_OUTER_INDEX; +} +bool IndexMap::HasData() const +{ + return (start_ != 0 || end_ != INVALID_UINT32) || !empty_; +} +void IndexMap::Intersect(TableRowId start, TableRowId end) +{ + if (indexType_ == INDEX_TYPE_OUTER_INDEX) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (*i >= start && *i < end) { + i++; + } else { + i = rowIndex_.erase(i); + } + } + start_ = current_ = 0; + end_ = rowIndex_.size(); + } else { + start_ = std::max(start_, start); + end_ = std::min(end_, end); + current_ = start_; + } + empty_ = false; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/index_map.h b/trace_streamer/sdk/demo_sdk/table/index_map.h new file mode 100644 index 0000000000000000000000000000000000000000..a6f363759b566efbeee24786a6adb1a3c7ead31b --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/index_map.h @@ -0,0 +1,416 @@ +/* + * 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 TABLE_INDEX_MAP_H +#define TABLE_INDEX_MAP_H + +#include +#include +#include +#include +#include "log.h" +#include "sqlite3.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +class IndexMap { +public: + IndexMap() {} + ~IndexMap() {} + + IndexMap(TableRowId start, TableRowId end); + void CovertToIndexMap(); + template + void MixRange(unsigned char op, T value, const std::deque& dataQueue) + { + auto invalidValue = std::numeric_limits::max(); + bool remove = false; + if (HasData()) { + CovertToIndexMap(); + remove = true; + } + auto size = dataQueue.size(); + rowIndexBak_.clear(); + bool changed = false; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] != value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] == value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_NE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] == value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] != value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNULL: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] != invalidValue) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] == invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] == invalidValue) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] != invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] <= value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] > value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] < value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] >= invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] > value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] < invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] >= value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] < invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + + default: + break; + } // end of switch (op) + empty_ = false; + } + void FixSize() + { + if (indexType_ == INDEX_TYPE_OUTER_INDEX) { + end_ = rowIndex_.size(); + } + } + void Remove(TableRowId row) + { + (void)std::remove(rowIndex_.begin(), rowIndex_.end(), row); + } + void Set(TableRowId start, TableRowId end) + { + if (indexType_ == INDEX_TYPE_ID) { + end_ = std::min(end_, end); + current_ = start_ = std::max(start_, start); + } + } + + size_t Size() const + { + return end_ - start_; + } + + void Next() + { + if (desc_) { + if (current_ > start_) { + current_--; + } + } else { + if (current_ < end_) { + current_++; + } + } + } + + bool Eof() const + { + if (desc_) { + return current_ <= start_; + } else { + return current_ >= end_; + } + } + + TableRowId CurrentRow() const + { + auto current = current_; + // if (desc_) { + // current--; + // } + if (indexType_ == INDEX_TYPE_ID) { + return current; + } else { + return rowIndex_[current]; + } + } + + void SortBy(bool desc) + { + if (desc) { + current_ = end_; + } else { + current_ = start_; + } + desc_ = desc; + } + + // void Insert(TableRowId index); + + // void Intersect(const IndexMap& other); + void Intersect(TableRowId start, TableRowId end); + // void Intersect(const std::vector& iv); + + // the follow functions require that thecolData is sotred + template + void IntersectabcEqual(const std::deque& rows, Val v, GetV getValue) + { + auto start = std::lower_bound(rows.begin() + start_, rows.begin() + end_, v); + auto end = std::upper_bound(start, rows.begin() + end_, v); + auto newStart = std::distance(rows.begin(), start); + auto newEnd = std::distance(rows.begin(), end); + Intersect(newStart, newEnd); + return; + } + + template + void IntersectGreaterEqual(const std::deque& rows, Val v, GetV getValue) + { + uint32_t index = rows.size() - 1; + for (; index != -1; index--) { + if (v >= getValue(rows[index])) { + break; + } + } + if (index == -1) { + index = 0; + } + Intersect(index, INVALID_UINT32); + return; + } + + template + void IntersectLessEqual(const std::deque& rows, Val v, GetV getValue) + { + uint32_t index = 0; + for (; index < rows.size(); index++) { + if (v <= getValue(rows[index])) { + break; + } + } + Intersect(0, index); + return; + } + template + void RemoveNullElements(const std::deque& rows, T v) + { + auto invalidValue = std::numeric_limits::max(); + bool remove = false; + if (HasData()) { + CovertToIndexMap(); + remove = true; + } + + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (rows[*i] == invalidValue) { + i = rowIndex_.erase(i); + } else { + i++; + } + } + } else { + auto size = rows.size(); + for (auto i = 0; i < size; i++) { + if (rows[i] != invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + return; + } + bool HasData() const; + std::vector rowIndex_; + std::vector rowIndexBak_; + +private: + TableRowId end_ = INVALID_UINT32; + TableRowId current_ = 0; + TableRowId start_ = 0; + enum FindIndexType { + INDEX_TYPE_ID, + INDEX_TYPE_OUTER_INDEX, + }; + FindIndexType indexType_ = INDEX_TYPE_ID; + uint32_t indexSize_ = 0; + uint32_t index_ = 0; + + enum IndexType { COMPACT, SPARSE }; + uint8_t type_ = COMPACT; + bool empty_ = true; + bool desc_ = false; + bool converted_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_INDEX_MAP_H diff --git a/trace_streamer/sdk/demo_sdk/table/meta_table.cpp b/trace_streamer/sdk/demo_sdk/table/meta_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0059d3e051f0f7076b37b444282b6409fc1e9819 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/meta_table.cpp @@ -0,0 +1,61 @@ +/* + * 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 "meta_table.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { NAMEINDEX = 0, VALUE }; +MetaTable::MetaTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "TEXT")); + tablePriKey_.push_back("name"); +} + +MetaTable::~MetaTable() {} + +std::unique_ptr MetaTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +MetaTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, MetaDataItem::METADATA_ITEM_MAX) +{ +} + +MetaTable::Cursor::~Cursor() {} + +int32_t MetaTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case NAMEINDEX: + sqlite3_result_text(context_, dataCache_->GetConstMetaData().Name(CurrentRow()).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + case VALUE: + sqlite3_result_text(context_, dataCache_->GetConstMetaData().Value(CurrentRow()).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/meta_table.h b/trace_streamer/sdk/demo_sdk/table/meta_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6269067d1742020d3e4fb82adbf5fdfc42c651c5 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/meta_table.h @@ -0,0 +1,49 @@ +/* + * 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 META_TABLE_H +#define META_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class MetaTable : public TableBase { +public: + explicit MetaTable(const TraceDataCache* dataCache); + ~MetaTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // META_TABLE_H diff --git a/trace_streamer/sdk/demo_sdk/table/slice_object_table.cpp b/trace_streamer/sdk/demo_sdk/table/slice_object_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f08418dff6179a37132e6185a53ce1e484d9d047 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/slice_object_table.cpp @@ -0,0 +1,63 @@ +/* + * 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 "slice_object_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { SLICE_ID = 0, SLICE_NAME = 1 }; +SliceObjectTable::SliceObjectTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("slice_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("slice_name", "REAL")); + tablePriKey_.push_back("slice_id"); +} + +SliceObjectTable::~SliceObjectTable() {} + +std::unique_ptr SliceObjectTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SliceObjectTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSliceObjectData().Size())), + sliceObjectDataObj_(dataCache->GetConstSliceObjectData()) +{ +} + +SliceObjectTable::Cursor::~Cursor() {} + +int32_t SliceObjectTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case SLICE_ID: { + sqlite3_result_int64(context_, static_cast(sliceObjectDataObj_.SliceId()[CurrentRow()])); + break; + } + case SLICE_NAME: { + sqlite3_result_text(context_, sliceObjectDataObj_.SliceName()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/slice_object_table.h b/trace_streamer/sdk/demo_sdk/table/slice_object_table.h new file mode 100644 index 0000000000000000000000000000000000000000..386161b1cb42f67fe51ee1aeb4bfcb8bbd22e8ef --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/slice_object_table.h @@ -0,0 +1,52 @@ +/* + * 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 SLICE_OBJECT_TABLE_H +#define SLICE_OBJECT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SliceObjectTable : public TableBase { +public: + explicit SliceObjectTable(const TraceDataCache* dataCache); + ~SliceObjectTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const SliceObject& sliceObjectDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SLICE_OBJECT_TABLE_H diff --git a/trace_streamer/sdk/demo_sdk/table/slice_table.cpp b/trace_streamer/sdk/demo_sdk/table/slice_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4eb7b200857424e215e69bec2ee23113d07c44b0 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/slice_table.cpp @@ -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. + */ + +#include "slice_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { TS = 0, ENDTS = 1, VALUE = 2, SLICE_ID = 3 }; +SliceTable::SliceTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("slice_id", "INTEGER")); + tablePriKey_.push_back("start_ts"); + tablePriKey_.push_back("slice_id"); +} + +SliceTable::~SliceTable() {} + +std::unique_ptr SliceTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SliceTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSliceData().Size())), + sliceDataObj_(dataCache->GetConstSliceData()) +{ +} + +SliceTable::Cursor::~Cursor() {} + +int32_t SliceTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.TimeStamp()[CurrentRow()])); + break; + } + case ENDTS: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.EndTs()[CurrentRow()])); + break; + } + case VALUE: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.Value()[CurrentRow()])); + break; + } + case SLICE_ID: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.SliceId()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/slice_table.h b/trace_streamer/sdk/demo_sdk/table/slice_table.h new file mode 100644 index 0000000000000000000000000000000000000000..284858143f585c0a1f1adbd106044baf5d41a399 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/slice_table.h @@ -0,0 +1,52 @@ +/* + * 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 SLICE_TABLE_H +#define SLICE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SliceTable : public TableBase { +public: + explicit SliceTable(const TraceDataCache* dataCache); + ~SliceTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const SliceData& sliceDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SLICE_TABLE_H diff --git a/trace_streamer/sdk/demo_sdk/table/table_base.cpp b/trace_streamer/sdk/demo_sdk/table/table_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f7e9832a18a7d0738aa6d969a523a0ccecce2778 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/table_base.cpp @@ -0,0 +1,286 @@ +/* + * 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 "table_base.h" + +#include +#include + +#include "log.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) + +namespace SysTuning { +namespace TraceStreamer { +struct TableContext { + TabTemplate tmplate; + TraceDataCache* dataCache; + sqlite3_module module; + std::string tableName; +}; + +TableBase::~TableBase() +{ + dataCache_ = nullptr; + cursor_ = nullptr; +} + +void TableBase::TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate) +{ + std::unique_ptr context(std::make_unique()); + context->dataCache = cache; + context->tmplate = tmplate; + context->tableName = tableName; + sqlite3_module& module = context->module; + module = {0}; + + auto createFn = [](sqlite3* xdb, void* pAux, int32_t argc, const char* const* argv, sqlite3_vtab** ppVTab, + char** pzErr) { + UNUSED(argc); + UNUSED(argv); + UNUSED(pzErr); + auto xdesc = static_cast(pAux); + auto table = xdesc->tmplate(xdesc->dataCache); + table->name_ = xdesc->tableName; + if (table->name_ == "process" || table->name_ == "thread") { + table->wdataCache_ = xdesc->dataCache; + } + + table->Init(argc, argv); + std::string createStmt = table->CreateTableSql(); + TS_LOGD("xCreate table %s, statement: %s", table->name_.c_str(), createStmt.c_str()); + int32_t ret = sqlite3_declare_vtab(xdb, createStmt.c_str()); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_declare_vtab %s faild: %s", table->name_.c_str(), createStmt.c_str()); + return ret; + } + *ppVTab = table.release(); + return SQLITE_OK; + }; + + auto destroyFn = [](sqlite3_vtab* t) { + TS_LOGD("xDestroy table %s", static_cast(t)->name_.c_str()); + delete static_cast(t); + return SQLITE_OK; + }; + module.xCreate = createFn; + module.xConnect = createFn; + module.xDisconnect = destroyFn; + module.xDestroy = destroyFn; + + module.xOpen = [](sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor) { + TS_LOGD("xOpen: %s", static_cast(pVTab)->name_.c_str()); + return static_cast(pVTab)->Open(ppCursor); + }; + + module.xClose = [](sqlite3_vtab_cursor* vc) { + TS_LOGD("xClose: %s", static_cast(vc)->table_->name_.c_str()); + delete static_cast(vc); + return SQLITE_OK; + }; + + module.xBestIndex = [](sqlite3_vtab* pVTab, sqlite3_index_info* idxInfo) { + TS_LOGD("xBestIndex: %s %d", static_cast(pVTab)->name_.c_str(), idxInfo->nConstraint); + return static_cast(pVTab)->BestIndex(idxInfo); + }; + + module.xFilter = [](sqlite3_vtab_cursor* vc, int32_t idxNum, const char* idxStr, int32_t argc, + sqlite3_value** argv) { + auto* c = static_cast(vc); + c->Reset(); + TS_LOGD("xFilter %s: [%d]%s", static_cast(vc)->table_->name_.c_str(), idxNum, idxStr); + if (c->table_->cacheIdxNum_ != idxNum) { + c->table_->cacheConstraint_.Clear(); + c->table_->cacheConstraint_.FromString(idxStr); + c->table_->cacheIdxNum_ = idxNum; + } + return c->Filter(c->table_->cacheConstraint_, argv); + }; + + module.xNext = [](sqlite3_vtab_cursor* vc) { return static_cast(vc)->Next(); }; + module.xEof = [](sqlite3_vtab_cursor* vc) { return static_cast(vc)->Eof(); }; + module.xColumn = [](sqlite3_vtab_cursor* vc, sqlite3_context* ctx, int32_t col) { + static_cast(vc)->context_ = ctx; + return static_cast(vc)->Column(col); + }; + if (tableName == "process" || tableName == "thread") { + module.xUpdate = [](sqlite3_vtab* pVTab, int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) { + TS_LOGD("xUpdate: %s", static_cast(pVTab)->name_.c_str()); + return static_cast(pVTab)->Update(argc, argv, pRowid); + }; + } + + sqlite3_create_module_v2(&db, tableName.c_str(), &module, context.release(), + [](void* arg) { delete static_cast(arg); }); +} + +std::string TableBase::CreateTableSql() const +{ + std::string stmt = "CREATE TABLE x("; + for (const auto& col : tableColumn_) { + stmt += " " + col.name_ + " " + col.type_; + stmt += ","; + } + stmt += " PRIMARY KEY("; + for (size_t i = 0; i < tablePriKey_.size(); i++) { + if (i != 0) + stmt += ", "; + stmt += tablePriKey_.at(i); + } + stmt += ")) WITHOUT ROWID;"; + return stmt; +} + +int32_t TableBase::BestIndex(sqlite3_index_info* idxInfo) +{ + FilterConstraints filterConstraints; + for (int32_t i = 0; i < idxInfo->nConstraint; i++) { + const auto& constraint = idxInfo->aConstraint[i]; + if (constraint.usable) { + filterConstraints.AddConstraint(i, constraint.iColumn, constraint.op); + } + } + for (int32_t i = 0; i < idxInfo->nOrderBy; i++) { + filterConstraints.AddOrderBy(idxInfo->aOrderBy[i].iColumn, idxInfo->aOrderBy[i].desc); + } + + EstimatedIndexInfo estimate = {idxInfo->estimatedRows, idxInfo->estimatedCost, false}; + EstimateFilterCost(filterConstraints, estimate); + idxInfo->orderByConsumed = estimate.isOrdered; + idxInfo->estimatedCost = estimate.estimatedCost; + idxInfo->estimatedRows = estimate.estimatedRows; + + auto cs = filterConstraints.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + auto& c = cs[i]; + idxInfo->aConstraintUsage[c.idxInaConstraint].argvIndex = static_cast(i + 1); + idxInfo->aConstraintUsage[c.idxInaConstraint].omit = c.isSupport; + } + + std::string str; + filterConstraints.ToString(str); + char* pIdxStr = static_cast(sqlite3_malloc(str.size() + 1)); + std::copy(str.begin(), str.end(), pIdxStr); + pIdxStr[str.size()] = '\0'; + idxInfo->idxStr = pIdxStr; + idxInfo->needToFreeIdxStr = true; + idxInfo->idxNum = ++bestIndexNum_; + + TS_LOGD("%s BestIndex return: %d: %s", name_.c_str(), idxInfo->idxNum, str.c_str()); + TS_LOGD("%s, aConstraintUsage[%d]", idxInfo->idxStr, idxInfo->nConstraint); + for (int32_t i = 0; i < idxInfo->nConstraint; i++) { + TS_LOGD("col: %d op: %d, argvindex: %d omit: %d", idxInfo->aConstraint[i].iColumn, idxInfo->aConstraint[i].op, + idxInfo->aConstraintUsage[i].argvIndex, idxInfo->aConstraintUsage[i].omit); + } + TS_LOGD("estimated: %lld cost:%.3f", idxInfo->estimatedRows, idxInfo->estimatedCost); + + return SQLITE_OK; +} + +int32_t TableBase::Open(sqlite3_vtab_cursor** ppCursor) +{ + *ppCursor = static_cast(CreateCursor().release()); + return SQLITE_OK; +} + +TableBase::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount) + : context_(nullptr), + table_(table), + dataCache_(dataCache), + indexMap_(std::make_unique(0, rowCount)), + rowCount_(rowCount) +{ +} + +TableBase::Cursor::~Cursor() +{ + context_ = nullptr; + dataCache_ = nullptr; +} +void TableBase::Cursor::FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times) +{ + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint64_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(times, v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: { + indexMap_->RemoveNullElements(times, v); + break; + } + default: + break; + } // end of switch (op) + } +} + +int32_t TableBase::Cursor::RowId(sqlite3_int64* id) +{ + if (dataCache_->Cancel() || indexMap_->Eof()) { + return SQLITE_ERROR; + } + *id = static_cast(indexMap_->CurrentRow()); + return SQLITE_OK; +} +void TableBase::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/table/table_base.h b/trace_streamer/sdk/demo_sdk/table/table_base.h new file mode 100644 index 0000000000000000000000000000000000000000..c66eaa0cbe4d1e3b356af55d38ddabfe10ce1af2 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/table/table_base.h @@ -0,0 +1,140 @@ +/* + * 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 TABLE_H +#define TABLE_H + +#include +#include +#include +#include + +#include "filter_constraints.h" +#include "index_map.h" +#include "sqlite3.h" +#include "trace_data_cache.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +namespace SysTuning { +namespace TraceStreamer { +class TableBase; +using TabTemplate = std::unique_ptr (*)(const TraceDataCache* dataCache); +class TableBase : public sqlite3_vtab { +public: + virtual ~TableBase(); + TableBase(const TableBase&) = delete; + TableBase& operator=(const TableBase&) = delete; + + template + static void TableDeclare(sqlite3& db, TraceDataCache* dataCache, const std::string& name) + { + TableRegister(db, dataCache, name, [](const TraceDataCache* cache) { + return std::unique_ptr(std::make_unique(cache)); + }); + dataCache->AppendNewTable(name); + } + std::string CreateTableSql() const; + + class Cursor : public sqlite3_vtab_cursor { + public: + Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount); + virtual ~Cursor(); + virtual void Reset() + { + indexMap_ = std::make_unique(0, rowCount_); + } + + virtual int32_t Next() + { + indexMap_->Next(); + return SQLITE_OK; + } + + virtual int32_t Eof() + { + return dataCache_->Cancel() || indexMap_->Eof(); + } + + virtual uint32_t CurrentRow() const + { + return indexMap_->CurrentRow(); + } + virtual void FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times); + + virtual int32_t RowId(sqlite3_int64* id); + virtual int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) = 0; + virtual int32_t Column(int32_t n) const = 0; + virtual void FilterId(unsigned char op, sqlite3_value* argv); + + public: + sqlite3_context* context_; + TableBase* table_ = nullptr; + + protected: + const TraceDataCache* dataCache_; + std::unique_ptr indexMap_; + uint32_t rowCount_; + }; + + struct ColumnInfo { + ColumnInfo(const std::string& name, const std::string& type) : name_(name), type_(type) {} + std::string name_; + std::string type_; + }; + +protected: + explicit TableBase(const TraceDataCache* dataCache) : dataCache_(dataCache), cursor_(nullptr) {} + + struct EstimatedIndexInfo { + int64_t estimatedRows = 0; + double estimatedCost = 0.0; + bool isOrdered = false; + }; + + static void TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate); + virtual int32_t Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) + { + return SQLITE_READONLY; + } + int32_t BestIndex(sqlite3_index_info* idxInfo); + // needs to correspond to Cursor::Filter() + virtual void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) = 0; + virtual std::unique_ptr CreateCursor() = 0; + int32_t Open(sqlite3_vtab_cursor** ppCursor); + virtual void Init(int32_t, const char* const*) + { + return; + }; + +protected: + std::vector tableColumn_ = {}; + std::vector tablePriKey_ = {}; + const TraceDataCache* dataCache_; + TraceDataCache* wdataCache_ = nullptr; + std::unique_ptr cursor_; + +private: + uint16_t bestIndexNum_ = 0; + int32_t cacheIdxNum_ = 0; + FilterConstraints cacheConstraint_; + std::string name_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_H diff --git a/trace_streamer/sdk/demo_sdk/test/BUILD.gn b/trace_streamer/sdk/demo_sdk/test/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..4b84cf161ea209c830e14d1f99ef5045859cfe0c --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/test/BUILD.gn @@ -0,0 +1,90 @@ +# 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("//build/test.gni") +import("../ts.gni") + +if (target == "sdkdemotest") { + ohos_unittest("trace_streamer_sdk_ut") { + sources = [ "unittest/sdk_api_test.cpp" ] + deps = [ + "../:trace_streamer_sdk", + "//prebuilts/protos:ts_proto_data_cpp", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + "//third_party/sqlite:sqlite", + ] + include_dirs = [ + "../base", + "../sdk", + "..", + "../trace_streamer", + "../filter", + "../table", + "../trace_data", + "../include", + "../plugin", + "../rpc", + "./", + "../parser", + "../cfg", + "//prebuilts/emsdk/emsdk/emscripten/system/include", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "//third_party/googletest/googletest/include/gtest", + "//third_party/protobuf/src", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + ] + cflags = [ + "-Wno-inconsistent-missing-override", + "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + cflags += [ + # clang coverage options: + "--coverage", + "-mllvm", + "-limited-coverage-experimental=true", + "-fno-use-cxa-atexit", + "-DIS_UT", + ] + if (is_macx) { + lib_dirs = [ "/usr/local/opt/llvm/lib" ] + } + libs = [ "LLVMCore" ] + } +} + +# this is the dest for ohos.build +if (target == "sdkdemotest") { + group("sdkunittest") { + testonly = true + deps = [ ":trace_streamer_sdk_ut" ] + } +} diff --git a/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp b/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..536259ceabeaa06746074dd5889a3361463b1a07 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/test/unittest/sdk_api_test.cpp @@ -0,0 +1,647 @@ +/* + * 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 +#include +#include "gpu_counter_object_table.h" +#include "gpu_counter_table.h" +#include "mock_plugin_result.pb.h" +#include "sdk_data_parser.h" +#include "slice_object_table.h" +#include "slice_table.h" +#include "ts_sdk_api.h" + +using namespace testing::ext; +namespace SysTuning ::TraceStreamer { +class SDKApiTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; + RpcServer* rpcServer = new RpcServer(); +}; + +std::string g_resultTest; +void res(const std::string result, int32_t finish, int32_t isConfig) +{ + TS_LOGI("%s", result.c_str()); + g_resultTest = result; +} + +std::string g_reply; +void QueryResultCallback(const std::string& jsonResult, int32_t finish, int32_t isConfig) +{ + g_reply = jsonResult; +} + +/** + * @tc.name: SetTableName + * @tc.desc: Set the table name manually + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, SetTableName, TestSize.Level1) +{ + TS_LOGI("test1-1"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", "second_table", "third_table", "fouth_table"); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_TRUE(ret); + EXPECT_EQ(g_resultTest.find("ok"), 0); + + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySlice("select * from third_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySliceObj("select * from fouth_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: DefaultTableName + * @tc.desc: Use the default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, DefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-2"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: NullTableName + * @tc.desc: Use the null table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, NullTableName, TestSize.Level1) +{ + TS_LOGI("test1-3"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", " "); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: NullAndManuallyCounterTableName + * @tc.desc: Use the null and manually counter table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, NullAndManuallyCounterTableName, TestSize.Level1) +{ + TS_LOGI("test1-4"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", "second_table", " ", " "); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: NullAndManuallySliceTableName + * @tc.desc: Use the null and manually slice table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, NullAndManuallySliceTableName, TestSize.Level1) +{ + TS_LOGI("test1-5"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", "first_table", "second_table"); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySlice("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySliceObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForCounterObjectWithDefaultTableName + * @tc.desc: Use CurrentData for CounterObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-6"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(1, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForCounterObjectWithManuallyTableName + * @tc.desc: Use CurrentData for CounterObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-7"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(1, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterObjectWithDefaultTableName + * @tc.desc: Use WrongData for CounterObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-8"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(INVALID_INT32, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterObjectWithManuallyTableName + * @tc.desc: Use WrongData for CounterObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-9"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(INVALID_INT32, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterObject + * @tc.desc: Use WrongData for CounterObject table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterObject, TestSize.Level1) +{ + TS_LOGI("test1-10"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(INVALID_INT32, " "); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: CurrentDataForCounterWithDefaultTableName + * @tc.desc: Use CurrentData for Counter table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-11"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(1, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForCounterWithManuallyTableName + * @tc.desc: Use CurrentData for Counter table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-12"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", " ", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(1, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterWithDefaultTableName + * @tc.desc: Use WrongData for Counter table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-13"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(INVALID_INT32, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterWithManuallyTableName + * @tc.desc: Use WrongData for Counter table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-14"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", " ", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(INVALID_INT32, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CounterWithWrongData + * @tc.desc: Use wrongData for counter table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CounterWithWrongData, TestSize.Level1) +{ + TS_LOGI("test1-15"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(INVALID_INT32, INVALID_UINT64, INVALID_INT32); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForSliceObjectWithDefaultTableName + * @tc.desc: Use CurrentData for SliceObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-16"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(1, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForSliceObjectWithManuallyTableName + * @tc.desc: Use CurrentData for SliceObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-17"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(1, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from fourth_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceObjectWithDefaultTableName + * @tc.desc: Use WrongData for SliceObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-18"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(1, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceObjectWithManuallyTableName + * @tc.desc: Use WrongData for SliceObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-19"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(INVALID_INT32, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: WrongDataForSliceObject + * @tc.desc: Use WrongData for SliceObject table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceObject, TestSize.Level1) +{ + TS_LOGI("test1-20"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(INVALID_INT32, " "); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: CurrentDataForSliceWithDefaultTableName + * @tc.desc: Use CurrentData for Slice table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-21"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(1, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from Slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForSliceWithManuallyTableName + * @tc.desc: Use CurrentData for Slice table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-22"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", "third_table", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(1, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from third_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceWithDefaultTableName + * @tc.desc: Use WrongData for Slice table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-23"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(INVALID_INT32, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from Slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceWithManuallyTableName + * @tc.desc: Use WrongData for Slice table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-24"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", "third_table", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(INVALID_INT32, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from third_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: SliceWithWrongData + * @tc.desc: Use wrongData for slice table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, SliceWithWrongData, TestSize.Level1) +{ + TS_LOGI("test1-25"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(INVALID_INT32, INVALID_UINT64, INVALID_UINT64, INVALID_INT32); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} +} // namespace SysTuning::TraceStreamer diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache.cpp b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a69df06f36af3b263f02162f25e0f46946053fa --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache.cpp @@ -0,0 +1,39 @@ +/* + * 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 "trace_data_cache.h" +#include "sqlite3.h" +#include "../table/gpu_counter_object_table.h" +#include "../table/gpu_counter_table.h" +#include "../table/slice_object_table.h" +#include "../table/slice_table.h" + +namespace SysTuning { +namespace TraceStreamer { +TraceDataCache::TraceDataCache() +{ + InitDB(); +} + +TraceDataCache::~TraceDataCache() {} + +void TraceDataCache::InitDB() +{ + if (dbInited) { + return; + } + dbInited = true; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache.h b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..28defa3a0e9dc2efd44ec857655caa4a1fb8ef05 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache.h @@ -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 TRACE_DATA_CACHE_H +#define TRACE_DATA_CACHE_H + +#include "trace_data_cache_reader.h" +#include "trace_data_cache_writer.h" +#include "trace_data_db.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCache : public TraceDataCacheReader, public TraceDataCacheWriter, public TraceDataDB { +public: + TraceDataCache(); + TraceDataCache(const TraceDataCache* dataCache) = delete; + TraceDataCache* operator=(const TraceDataCache* dataCache) = delete; + ~TraceDataCache() override; + void InitDB() override; + bool dbInited = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_DATA_CACHE_H diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_base.cpp b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d8dd22c63841c43d986bfbb83cb80ff8bfdcc9b --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_base.cpp @@ -0,0 +1,23 @@ +/* + * 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 "trace_data_cache_base.h" +#include + +namespace SysTuning { +namespace TraceStreamer { + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_base.h b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_base.h new file mode 100644 index 0000000000000000000000000000000000000000..db5460e7845496712c01cd85381a52b19d187a17 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_base.h @@ -0,0 +1,48 @@ +/* + * 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 TRACE_DATA_CACHE_BASE_H +#define TRACE_DATA_CACHE_BASE_H + +#include +#include +#include +#include +#include +#include +#include "trace_stdtype.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheBase { +public: + TraceDataCacheBase() = default; + TraceDataCacheBase(const TraceDataCacheBase&) = delete; + TraceDataCacheBase& operator=(const TraceDataCacheBase&) = delete; + virtual ~TraceDataCacheBase() = default; + +public: + GpuCounter gpuCounter_; + GpuCounterObject gpuCounterObject_; + SliceObject sliceObject_; + SliceData sliceData_; + MetaData metaData_; + uint64_t traceStartTime_ = std::numeric_limits::max(); + uint64_t traceEndTime_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_DATA_CACHE_BASE_H diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_reader.cpp b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee224b06364a5054acbe43f7320505895c7dcd88 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_reader.cpp @@ -0,0 +1,44 @@ +/* + * 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 "trace_data_cache_reader.h" +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +TraceDataCacheReader::~TraceDataCacheReader() {} + +const GpuCounter& TraceDataCacheReader::GetConstGpuCounterData() const +{ + return gpuCounter_; +} +const GpuCounterObject& TraceDataCacheReader::GetConstGpuCounterObjectData() const +{ + return gpuCounterObject_; +} +const SliceObject& TraceDataCacheReader::GetConstSliceObjectData() const +{ + return sliceObject_; +} +const SliceData& TraceDataCacheReader::GetConstSliceData() const +{ + return sliceData_; +} +const MetaData& TraceDataCacheReader::GetConstMetaData() const +{ + return metaData_; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_reader.h b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..916606ab21a49d01a6b848cc9d3e21c588c4a7e1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_reader.h @@ -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. + */ + +#ifndef TRACE_DATA_CACHE_READER_H +#define TRACE_DATA_CACHE_READER_H + +#include "log.h" +#include "trace_data_cache_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheReader : virtual public TraceDataCacheBase { +public: + TraceDataCacheReader() = default; + TraceDataCacheReader(const TraceDataCacheReader&) = delete; + TraceDataCacheReader& operator=(const TraceDataCacheReader&) = delete; + ~TraceDataCacheReader() override; + +public: + const GpuCounter& GetConstGpuCounterData() const; + const GpuCounterObject& GetConstGpuCounterObjectData() const; + const SliceObject& GetConstSliceObjectData() const; + const SliceData& GetConstSliceData() const; + const MetaData& GetConstMetaData() const; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_writer.cpp b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_writer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5a7920cfb2076c01e98308098d61c6cbb68297f --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_writer.cpp @@ -0,0 +1,67 @@ +/* + * 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 "trace_data_cache_writer.h" +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +TraceDataCacheWriter::~TraceDataCacheWriter() {} + +GpuCounter* TraceDataCacheWriter::GetGpuCounterData() +{ + return &gpuCounter_; +} +GpuCounterObject* TraceDataCacheWriter::GetGpuCounterObjectData() +{ + return &gpuCounterObject_; +} +SliceObject* TraceDataCacheWriter::GetSliceObjectData() +{ + return &sliceObject_; +} +SliceData* TraceDataCacheWriter::GetSliceTableData() +{ + return &sliceData_; +} +MetaData* TraceDataCacheWriter::GetMetaData() +{ + return &metaData_; +} +void TraceDataCacheWriter::MixTraceTime(uint64_t timestampMin, uint64_t timestampMax) +{ + if (timestampMin == std::numeric_limits::max() || timestampMax == 0) { + return; + } + if (traceStartTime_ != std::numeric_limits::max()) { + traceStartTime_ = std::max(traceStartTime_, timestampMin); + } else { + traceStartTime_ = timestampMin; + } + if (traceEndTime_) { + traceEndTime_ = std::min(traceEndTime_, timestampMax); + } else { + traceEndTime_ = timestampMax; + } +} +void TraceDataCacheWriter::Clear() +{ + gpuCounter_.Clear(); + gpuCounterObject_.Clear(); + sliceObject_.Clear(); + sliceData_.Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_writer.h b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..b97565b331520f414bb76a973a3ef1c7e4c26b60 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_cache_writer.h @@ -0,0 +1,43 @@ +/* + * 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 TRACE_DATA_CACHE_WRITER_H +#define TRACE_DATA_CACHE_WRITER_H + +#include "trace_data_cache_reader.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheWriter : virtual public TraceDataCacheBase { +public: + TraceDataCacheWriter() = default; + TraceDataCacheWriter(const TraceDataCacheWriter&) = delete; + TraceDataCacheWriter& operator=(const TraceDataCacheWriter&) = delete; + ~TraceDataCacheWriter() override; + void Clear(); + +public: + GpuCounter* GetGpuCounterData(); + GpuCounterObject* GetGpuCounterObjectData(); + SliceObject* GetSliceObjectData(); + SliceData* GetSliceTableData(); + MetaData* GetMetaData(); + void MixTraceTime(uint64_t timestampMin, uint64_t timestampMax); + // ThreadState* GetThreadStateData(); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_db.cpp b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_db.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f543a9c2eeefc709a247e8b4d83f15c8e17539a8 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_db.cpp @@ -0,0 +1,421 @@ +/* + * 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 "trace_data_db.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ext/sqlite_ext_funcs.h" +#include "file.h" +#include "log.h" +#include "sqlite3.h" +#include "string_help.h" + +const int32_t ONCE_MAX_MB = 1024 * 1024 * 4; +namespace SysTuning { +namespace TraceStreamer { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +using namespace SysTuning::base; +TraceDataDB::TraceDataDB() : db_(nullptr) +{ + if (sqlite3_threadsafe() > 0) { + int32_t retCode = sqlite3_config(SQLITE_CONFIG_SERIALIZED); + if (retCode == SQLITE_OK) { + TS_LOGI("Can now use sqlite on multiple threads, using the same connection"); + } else { + TS_LOGE("setting sqlite thread safe mode to serialized failed!!! return code: %d", retCode); + } + } else { + TS_LOGE("Your SQLite database is not compiled to be threadsafe."); + } + if (sqlite3_open(":memory:", &db_)) { + TS_LOGF("open :memory db failed"); + } + ts_create_extend_function(db_); +} + +TraceDataDB::~TraceDataDB() +{ + sqlite3_close(db_); +} + +void TraceDataDB::AppendNewTable(std::string tableName) +{ + internalTables_.push_back(tableName); +} +void TraceDataDB::EnableMetaTable(bool enabled) +{ + exportMetaTable_ = enabled; +} +int32_t TraceDataDB::ExportDatabase(const std::string& outputName) +{ + { + int32_t fd(base::OpenFile(outputName, O_CREAT | O_RDWR, TS_PERMISSION_RW)); + if (!fd) { + fprintf(stdout, "Failed to create file: %s", outputName.c_str()); + return 1; + } + auto ret = ftruncate(fd, 0); + UNUSED(ret); + close(fd); + } + + std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export"); +#ifdef _WIN32 + if (!base::GetCoding(reinterpret_cast(attachSql.c_str()), attachSql.length())) { + attachSql = base::GbkToUtf8(attachSql.c_str()); + } +#endif + ExecuteSql(attachSql); + + for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) { +#ifndef USE_VTABLE + if (*itor == "_meta" && !exportMetaTable_) { + continue; + } else { + std::string exportSql("CREATE TABLE systuning_export." + (*itor).substr(1, -1) + " AS SELECT * FROM " + + *itor); + ExecuteSql(exportSql); + } +#else + if (*itor == "meta" && !exportMetaTable_) { + continue; + } else { + std::string exportSql("CREATE TABLE systuning_export." + (*itor) + " AS SELECT * FROM " + *itor); + ExecuteSql(exportSql); + } +#endif + } + std::string createArgsView = + "create view systuning_export.args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when " + "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on (D.typeId " + "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key"; + ExecuteSql(createArgsView); + std::string updateProcessName = + "update process set name = (select name from thread t where t.ipid = process.id and t.name is not null and " + "is_main_thread = 1)"; + ExecuteSql(updateProcessName); + std::string detachSql("DETACH DATABASE systuning_export"); + ExecuteSql(detachSql); + return 0; +} +void TraceDataDB::Prepare() +{ + if (pared_) { + return; + } + pared_ = true; +#ifndef USE_VTABLE + for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) { + std::string exportSql("CREATE TABLE " + (*itor).substr(1, -1) + " AS SELECT * FROM " + *itor); + ExecuteSql(exportSql); + } +#endif + std::string createArgsView = + "create view args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when " + "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on " + "(D.typeId " + "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key"; + ExecuteSql(createArgsView); + + std::string updateProcessNewName = + "update process set name = (select name from thread t where t.ipid = process.id and t.name is not " + "null and " + "is_main_thread = 1)"; + ExecuteSql(updateProcessNewName); +} +void TraceDataDB::ExecuteSql(const std::string_view& sql) +{ + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.data(), static_cast(sql.size()), &stmt, nullptr); + + while (!ret) { + int32_t err = sqlite3_step(stmt); + if (err == SQLITE_ROW) { + continue; + } + if (err == SQLITE_DONE) { + break; + } + ret = err; + } + + sqlite3_finalize(stmt); +} +int32_t TraceDataDB::SearchData() +{ + Prepare(); + std::string line; + bool printResult = false; + for (;;) { + std::cout << "> "; + getline(std::cin, line); + if (line.empty()) { + std::cout << "If you want to quit either type -q or press CTRL-Z" << std::endl; + continue; + } + if (!line.compare("-q") || !line.compare("-quit")) { + break; + } else if (!line.compare("-e")) { + TS_LOGI("the db file will be at current folder, the name is default.db"); + return ExportDatabase("default.db"); + } else if (!line.compare("-help") || !line.compare("-h")) { + std::cout << "use info" << std::endl; + continue; + } else if (!line.compare("-p")) { + std::cout << "will print result of query" << std::endl; + printResult = true; + continue; + } else if (!line.compare("-up")) { + std::cout << "will not print result of query" << std::endl; + printResult = false; + continue; + } else if (line.find("-c:") != std::string::npos) { + line = line.substr(strlen("-c:")); + if (OperateDatabase(line) == SQLITE_OK) { + printf("operate SQL success\n"); + } + continue; + } + + using namespace std::chrono; + const auto start = steady_clock::now(); + int32_t rowCount = SearchDatabase(line, printResult); + std::chrono::nanoseconds searchDur = duration_cast(steady_clock::now() - start); + printf("\"%s\"\n\tused %.3fms row: %d\n", line.c_str(), searchDur.count() / 1E6, rowCount); + } + return 0; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, bool print) +{ + Prepare(); + int32_t rowCount = 0; + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return 0; + } + + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + TS_LOGI("sqlite3_column_count(%s) no column", sql.c_str()); + sqlite3_finalize(stmt); + return 0; + } + if (print) { + for (int32_t i = 0; i < colCount; i++) { + printf("%s\t", sqlite3_column_name(stmt, i)); + } + printf("\n"); + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + rowCount++; + for (int32_t i = 0; i < colCount; i++) { + const char* p = reinterpret_cast(sqlite3_column_text(stmt, i)); + int32_t type = sqlite3_column_type(stmt, i); + if (!print) { + continue; + } + if (p == nullptr) { + printf("null\t"); + continue; + } + if (type == SQLITE_TEXT) { + printf("\"%s\"\t", p); + } else { + printf("%s\t", p); + } + } + if (print) { + printf("\n"); + } + } + sqlite3_finalize(stmt); + return rowCount; +} +int32_t TraceDataDB::OperateDatabase(const std::string& sql) +{ + Prepare(); + char* errmsg = nullptr; + int32_t ret = sqlite3_exec(db_, sql.c_str(), NULL, NULL, &errmsg); + if (ret != SQLITE_OK && errmsg) { + TS_LOGE("sqlite3_exec(%s) failed: %d:%s", sql.c_str(), ret, errmsg); + sqlite3_free(errmsg); + } + return ret; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, ResultCallBack resultCallBack) +{ + Prepare(); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + resultCallBack("false\r\n", SEND_FINISH, 0); + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return ret; + } + if (!resultCallBack) { + return ret; + } + + std::string res = "ok\r\n"; + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + resultCallBack(res, SEND_FINISH, 0); + return ret; + } + res += "{\"columns\":["; + for (int32_t i = 0; i < colCount; i++) { + res += "\""; + res += sqlite3_column_name(stmt, i); + res += "\","; + } + res.pop_back(); // remove the last "," + res += "],\"values\":["; + bool hasRow = false; + constexpr int32_t defaultLenRowString = 1024; + std::string row; + row.reserve(defaultLenRowString); + while (sqlite3_step(stmt) == SQLITE_ROW) { + hasRow = true; + GetRowString(stmt, colCount, row); + res += row + ","; + if (res.size() >= ONCE_MAX_MB) { + resultCallBack(res, SEND_CONTINUE, 0); + res = ""; + } + } + if (hasRow) { + res.pop_back(); // remove the last ',' + } + res += "]}\r\n"; + resultCallBack(res, SEND_FINISH, 0); + + sqlite3_finalize(stmt); + return ret; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen) +{ + Prepare(); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return -1; + } + char* res = reinterpret_cast(out); + int32_t retSnprintf = snprintf_s(res, outLen, 1, "ok\r\n"); + if (retSnprintf < 0) { + return -1; + } + int32_t pos = retSnprintf; + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + return pos; + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s", "{\"columns\":["); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + for (int32_t i = 0; i < colCount; i++) { + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s%s%s", "\"", sqlite3_column_name(stmt, i), "\","); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + } + pos--; // rmove the last ',' + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "],\"values\":["); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + bool hasRow = false; + constexpr int32_t defaultLenRowString = 1024; + std::string row; + row.reserve(defaultLenRowString); + while (sqlite3_step(stmt) == SQLITE_ROW) { + hasRow = true; + GetRowString(stmt, colCount, row); + if (pos + row.size() + strlen(",]}\r\n") >= size_t(outLen)) { + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n"); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + sqlite3_finalize(stmt); + return pos; + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s%s", row.c_str(), ","); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + } + if (hasRow) { + pos--; // remove the last ',' + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n"); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + sqlite3_finalize(stmt); + return pos; +} +void TraceDataDB::SetCancel(bool cancel) +{ + cancelQuery_ = cancel; +} +void TraceDataDB::GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr) +{ + rowStr.clear(); + rowStr = "["; + for (int32_t i = 0; i < colCount; i++) { + const char* p = reinterpret_cast(sqlite3_column_text(stmt, i)); + if (p == nullptr) { + rowStr += "null,"; + continue; + } + int32_t type = sqlite3_column_type(stmt, i); + switch (type) { + case SQLITE_TEXT: + rowStr += "\""; + rowStr += p; + rowStr += "\""; + break; + default: + rowStr += p; + break; + } + rowStr += ","; + } + rowStr.pop_back(); // remove the last ',' + rowStr += "]"; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_data_db.h b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_db.h new file mode 100644 index 0000000000000000000000000000000000000000..75ddb7b2baa243016b91937a482e93208ce83857 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_data_db.h @@ -0,0 +1,66 @@ +/* + * 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 TRACE_DATA_DB_H +#define TRACE_DATA_DB_H + +#include +#include +#include +#include "sqlite3.h" + +namespace SysTuning { +namespace TraceStreamer { +const int32_t SEND_CONTINUE = 0; +const int32_t SEND_FINISH = 1; +class TraceDataDB { +public: + TraceDataDB(); + TraceDataDB(const TraceDataDB&) = delete; + TraceDataDB& operator=(const TraceDataDB&) = delete; + virtual ~TraceDataDB(); + virtual void InitDB() = 0; + void Prepare(); + +public: + int32_t ExportDatabase(const std::string& outputName); + int32_t SearchData(); + int32_t OperateDatabase(const std::string& sql); + using ResultCallBack = std::function; + int32_t SearchDatabase(const std::string& sql, ResultCallBack resultCallBack); + int32_t SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen); + void SetCancel(bool cancel); + void AppendNewTable(std::string tableName); + void EnableMetaTable(bool enabled); + bool Cancel() const + { + return cancelQuery_; + } + +public: + sqlite3* db_; + +private: + void ExecuteSql(const std::string_view& sql); + static void GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr); + int32_t SearchDatabase(const std::string& sql, bool print); + std::list internalTables_ = {}; + bool exportMetaTable_ = true; + bool pared_ = false; + bool cancelQuery_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_stdtype.cpp b/trace_streamer/sdk/demo_sdk/trace_data/trace_stdtype.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86dc8fcc9a56fadef29fddd22562ae01fe35afbf --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_stdtype.cpp @@ -0,0 +1,119 @@ +/* + * 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 "trace_stdtype.h" +#include +#include +namespace SysTuning { +namespace TraceStdtype { + +void GpuCounter::AppendNewData(uint64_t ts, int32_t counterId, int32_t value) +{ + ts_.emplace_back(ts); + counterId_.emplace_back(counterId); + value_.emplace_back(value); + ids_.push_back(counterId_.size() - 1); +} +const std::deque& GpuCounter::TimeStamp() const +{ + return ts_; +} +const std::deque& GpuCounter::CounterId() const +{ + return counterId_; +} +const std::deque& GpuCounter::Value() const +{ + return value_; +} + +void GpuCounterObject::AppendNewData(int32_t counterId, const std::string counterName) +{ + counterId_.emplace_back(counterId); + counterName_.emplace_back(counterName); + ids_.push_back(counterId_.size() - 1); +} +const std::deque& GpuCounterObject::CounterId() const +{ + return counterId_; +} +const std::deque& GpuCounterObject::CounterName() const +{ + return counterName_; +} +void SliceObject::AppendNewData(int32_t sliceId, std::string sliceName) +{ + sliceId_.emplace_back(sliceId); + sliceName_.emplace_back(sliceName); + ids_.push_back(sliceId_.size() - 1); +} +const std::deque& SliceObject::SliceId() const +{ + return sliceId_; +} +const std::deque& SliceObject::SliceName() const +{ + return sliceName_; +} +void SliceData::AppendNewData(int32_t sliceId, uint64_t startTs, uint64_t endTs, int32_t value) +{ + startTs_.emplace_back(startTs); + endTs_.emplace_back(endTs); + sliceId_.emplace_back(sliceId); + value_.emplace_back(value); + ids_.push_back(sliceId_.size() - 1); +} +const std::deque& SliceData::SliceId() const +{ + return sliceId_; +} +const std::deque& SliceData::TimeStamp() const +{ + return startTs_; +} +const std::deque& SliceData::EndTs() const +{ + return endTs_; +} +const std::deque& SliceData::Value() const +{ + return value_; +} +void MetaData::InitMetaData() +{ + columnNames_.resize(METADATA_ITEM_MAX); + values_.resize(METADATA_ITEM_MAX); + columnNames_[METADATA_ITEM_PARSERTOOL_VERSION] = METADATA_ITEM_PARSERTOOL_VERSION_COLNAME; + columnNames_[METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME] = METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME_COLNAME; +} +void MetaData::SetParserToolVersion(const std::string& version) +{ + values_[METADATA_ITEM_PARSERTOOL_VERSION] = version; +} +void MetaData::SetParserToolPublishDateTime(const std::string& datetime) +{ + values_[METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME] = datetime; +} +const std::string& MetaData::Value(uint64_t row) const +{ + return values_[row]; +} +const std::string& MetaData::Name(uint64_t row) const +{ + return columnNames_[row]; +} + +} // namespace TraceStdtype +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_data/trace_stdtype.h b/trace_streamer/sdk/demo_sdk/trace_data/trace_stdtype.h new file mode 100644 index 0000000000000000000000000000000000000000..e8984355713277ee22f4f56d7a83766d07b0ec45 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_data/trace_stdtype.h @@ -0,0 +1,148 @@ +/* + * 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 TRACE_STDTYPE_H +#define TRACE_STDTYPE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStdtype { +using namespace SysTuning::TraceStreamer; +// the supported metadata +enum MetaDataItem { METADATA_ITEM_PARSERTOOL_VERSION, METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME, METADATA_ITEM_MAX }; +class CacheBase { +public: + size_t Size() const + { + return std::max(timeStamps_.size(), ids_.size()); + } + const std::deque& IdsData() const + { + return ids_; + } + const std::deque& TimeStampData() const + { + return timeStamps_; + } + const std::deque& InternalTidsData() const + { + return internalTids_; + } + virtual void Clear() + { + internalTids_.clear(); + timeStamps_.clear(); + ids_.clear(); + } + +public: + std::deque internalTids_ = {}; + std::deque timeStamps_ = {}; + std::deque ids_ = {}; +}; + +class GpuCounterObject : public CacheBase { +public: + GpuCounterObject() = default; + ~GpuCounterObject() = default; + void AppendNewData(int32_t counterId, std::string counterName); + const std::deque& CounterId() const; + const std::deque& CounterName() const; + +private: + std::deque counterId_ = {}; + std::deque counterName_ = {}; +}; +class GpuCounter : public CacheBase { +public: + GpuCounter() = default; + ~GpuCounter() = default; + void AppendNewData(uint64_t ts, int32_t counterId, int32_t value); + const std::deque& TimeStamp() const; + const std::deque& CounterId() const; + const std::deque& Value() const; + +private: + std::deque ts_ = {}; + std::deque counterId_ = {}; + std::deque value_ = {}; +}; + +class SliceObject : public CacheBase { +public: + SliceObject() = default; + ~SliceObject() = default; + void AppendNewData(int32_t sliceId, std::string sliceName); + const std::deque& SliceId() const; + const std::deque& SliceName() const; + +private: + std::deque sliceId_ = {}; + std::deque sliceName_ = {}; +}; +class SliceData : public CacheBase { +public: + SliceData() = default; + ~SliceData() = default; + void AppendNewData(int32_t sliceId, uint64_t startTs, uint64_t endTs, int32_t value); + const std::deque& SliceId() const; + const std::deque& TimeStamp() const; + const std::deque& EndTs() const; + const std::deque& Value() const; + +private: + std::deque startTs_ = {}; + std::deque sliceId_ = {}; + std::deque endTs_ = {}; + std::deque value_ = {}; +}; +class MetaData : public CacheBase { +public: + MetaData() = default; + ~MetaData() = default; + void InitMetaData(); + void SetParserToolVersion(const std::string& version); + void SetParserToolPublishDateTime(const std::string& datetime); + const std::string& Value(uint64_t row) const; + const std::string& Name(uint64_t row) const; + void Clear() override + { + columnNames_.clear(); + values_.clear(); + } + +private: + const std::string METADATA_ITEM_PARSERTOOL_VERSION_COLNAME = "tool_version"; + const std::string METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME_COLNAME = "tool_publish_time"; + std::deque columnNames_ = {}; + std::deque values_ = {}; +}; +} // namespace TraceStdtype +} // namespace SysTuning + +#endif // TRACE_STDTYPE_H diff --git a/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_filters.cpp b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_filters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b831e4cea70d570902487a1267090ce0baf8a94 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_filters.cpp @@ -0,0 +1,21 @@ +/* + * 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 "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_filters.h b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_filters.h new file mode 100644 index 0000000000000000000000000000000000000000..506a69e6d76c504df468965bdadfad17387db5c6 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_filters.h @@ -0,0 +1,32 @@ +/* + * 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 TRACE_STREAMERTOKEN_H +#define TRACE_STREAMERTOKEN_H + +#include +#include "clock_filter.h" +namespace SysTuning { +namespace TraceStreamer { +class TraceStreamerFilters { +public: + TraceStreamerFilters(){}; + ~TraceStreamerFilters(){}; + std::unique_ptr clockFilter_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_STREAMERTOKEN_H diff --git a/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_selector.cpp b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_selector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e56161bb7cea65512ac69c16bd56631580dca8a1 --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_selector.cpp @@ -0,0 +1,98 @@ +/* + * 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 "trace_streamer_selector.h" +#include +#include +#include +#include +#include "clock_filter.h" +#include "string_help.h" + +using namespace SysTuning::base; +namespace SysTuning { +namespace TraceStreamer { +namespace { +TraceFileType GuessFileType(const uint8_t* data, size_t size) +{ + return TRACE_FILETYPE_UN_KNOW; +} +} // namespace + +TraceStreamerSelector::TraceStreamerSelector() +{ + InitFilter(); + sdkDataParser_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); +} +TraceStreamerSelector::~TraceStreamerSelector() {} + +void TraceStreamerSelector::InitFilter() +{ + streamFilters_ = std::make_unique(); + traceDataCache_ = std::make_unique(); + streamFilters_->clockFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); +} + +MetaData* TraceStreamerSelector::GetMetaData() +{ + return traceDataCache_->GetMetaData(); +} + +void TraceStreamerSelector::WaitForParserEnd() {} + +bool TraceStreamerSelector::ParseTraceDataSegment(std::unique_ptr data, size_t size) +{ + if (size == 0) { + return true; + } + return true; +} +void TraceStreamerSelector::EnableMetaTable(bool enabled) +{ + traceDataCache_->EnableMetaTable(enabled); +} + +void TraceStreamerSelector::SetCleanMode(bool cleanMode) {} +int32_t TraceStreamerSelector::ExportDatabase(const std::string& outputName) const +{ + return traceDataCache_->ExportDatabase(outputName); +} +void TraceStreamerSelector::Clear() +{ + traceDataCache_->Prepare(); + traceDataCache_->Clear(); +} +int32_t TraceStreamerSelector::SearchData() +{ + return traceDataCache_->SearchData(); +} +int32_t TraceStreamerSelector::OperateDatabase(const std::string& sql) +{ + return traceDataCache_->OperateDatabase(sql); +} +int32_t TraceStreamerSelector::SearchDatabase(const std::string& sql, TraceDataDB::ResultCallBack resultCallBack) +{ + return traceDataCache_->SearchDatabase(sql, resultCallBack); +} +int32_t TraceStreamerSelector::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen) +{ + return traceDataCache_->SearchDatabase(sql, out, outLen); +} +void TraceStreamerSelector::SetCancel(bool cancel) +{ + traceDataCache_->SetCancel(cancel); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_selector.h b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_selector.h new file mode 100644 index 0000000000000000000000000000000000000000..2c923f9402818b2e677719bd1d89baafb5497aae --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/trace_streamer/trace_streamer_selector.h @@ -0,0 +1,55 @@ +/* + * 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 TRACE_STREAMER_SELECTOR_H +#define TRACE_STREAMER_SELECTOR_H +#include +#include +#include "../sdk/sdk_data_parser.h" +#include "../trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class SDKDataParser; +enum TraceFileType { TRACE_FILETYPE_UN_KNOW }; +class TraceStreamerSelector { +public: + TraceStreamerSelector(); + ~TraceStreamerSelector(); + static bool ParseTraceDataSegment(std::unique_ptr data, size_t size); + void EnableMetaTable(bool enabled); + static void SetCleanMode(bool cleanMode); + int32_t ExportDatabase(const std::string& outputName) const; + int32_t SearchData(); + int32_t OperateDatabase(const std::string& sql); + int32_t SearchDatabase(const std::string& sql, TraceDataDB::ResultCallBack resultCallBack); + int32_t SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen); + MetaData* GetMetaData(); + static void WaitForParserEnd(); + void Clear(); + void SetDataType(TraceFileType type); + void SetCancel(bool cancel); + std::unique_ptr sdkDataParser_ = {}; + +private: + void InitFilter(); + std::unique_ptr streamFilters_ = {}; + std::unique_ptr traceDataCache_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_STREAMER_SELECTOR_H diff --git a/trace_streamer/sdk/demo_sdk/ts.gni b/trace_streamer/sdk/demo_sdk/ts.gni new file mode 100755 index 0000000000000000000000000000000000000000..16279772850e6b180cc5c0b02a8945bfef54999b --- /dev/null +++ b/trace_streamer/sdk/demo_sdk/ts.gni @@ -0,0 +1,61 @@ +# 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. +OHOS_PROTO_DIR = "" + +if (target_os == "linux" || target_os == "macx" || target_os == "windows") { + # OHOS_FTRACE_PROTO_DIR="//third_party/protogen" + OHOS_FTRACE_PROTO_DIR = "//src/multi_platform" + + # OHOS_MEMORY_PROTO_DIR="//third_party/protogen" + OHOS_MEMORY_PROTO_DIR = "//src/multi_platform" + + # OHOS_HILOG_PROTO_DIR="//third_party/protogen" + OHOS_HILOG_PROTO_DIR = "//src/multi_platform" + + # OHOS_NATIVE_HOOK_PROTO_DIR="//third_party/protogen" + OHOS_NATIVE_HOOK_PROTO_DIR = "//src/multi_platform" + + # OHOS_HIDUMP_PROTO_DIR="//third_party/protogen" + OHOS_HIDUMP_PROTO_DIR = "//src/multi_platform" + + # OHOS_SERVICE_PROTO_DIR = "//third_party/protogen" + OHOS_SERVICE_PROTO_DIR = "//src/multi_platform" + OHOS_PROTO_GEN = "//third_party/protogen" + + # kernel_version = "5.10.79_aarch64" + kernel_version = "." + if (target == "test") { + enable_ts_utest = true + } else { + enable_ts_utest = false + } + is_openharmony = false +} else { + enable_ts_utest = true + use_wasm = false + kernel_version = "." + is_fuzz = false + target = "trace_streamer" + is_openharmony = true + OHOS_FTRACE_PROTO_DIR = "//developtools/profiler/protos/types/plugins/ftrace_data/${kernel_version}" + OHOS_MEMORY_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/memory_data" + OHOS_HILOG_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hilog_data" + OHOS_NATIVE_HOOK_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/native_hook" + OHOS_HIDUMP_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hidump_data" + OHOS_SERVICE_PROTO_DIR = "//developtools/profiler/protos/services" + OHOS_PROTO_GEN = "//out/ohos-arm-release/gen/cpp/developtools/profiler/protos" +} diff --git a/trace_streamer/sdk/dubai_sdk/BUILD.gn b/trace_streamer/sdk/dubai_sdk/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..965ce97e682a472e9fea2903ef970b6635b7fa73 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/BUILD.gn @@ -0,0 +1,178 @@ +# 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("ts.gni") +if (use_wasm) { + import("../../gn/wasm.gni") +} +if (use_wasm) { + ohos_source_set("trace_streamer_dubai_builtin") { + subsystem_name = "trace_streamer" + part_name = "trace_streamer_dubai_builtin" + sources = [] + include_dirs = [] + deps = [] + public_deps = [] + } +} +ohos_source_set("lib") { + subsystem_name = "trace_streamer" + part_name = "lib" + sources = [ "main.cpp" ] + deps = [ + ":trace_streamer_sdk", + "protos:ts_proto_data_cpp", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + include_dirs = [ + "base", + "..", + "trace_streamer", + "table", + "trace_data", + "include", + "plugin", + "filter", + "rpc", + "./", + "parser", + "cfg", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + ] + if (with_perf) { + include_dirs += [] + } + public_deps = [] +} +source_set("trace_streamer_sdk") { + sources = [ + "filter/clock_filter.cpp", + "filter/clock_filter.h", + "parser/event_parser_base.cpp", + "parser/event_parser_base.h", + "parser/htrace_plugin_time_parser.cpp", + "rpc/http_socket.cpp", + "rpc/rpc_server.cpp", + "rpc/rpc_server.h", + "sdk/sdk_data_parser.cpp", + "sdk/sdk_data_parser.h", + "sdk/ts_sdk_api.cpp", + "sdk/ts_sdk_api.h", + "table/filter_constraints.cpp", + "table/gpu_counter_object_table.cpp", + "table/gpu_counter_object_table.h", + "table/gpu_counter_table.cpp", + "table/gpu_counter_table.h", + "table/index_map.cpp", + "table/index_map.h", + "table/meta_table.cpp", + "table/meta_table.h", + "table/slice_object_table.cpp", + "table/slice_object_table.h", + "table/slice_table.cpp", + "table/slice_table.h", + "table/table_base.cpp", + "trace_data/trace_data_cache.cpp", + "trace_data/trace_data_cache.h", + "trace_data/trace_data_cache_base.cpp", + "trace_data/trace_data_cache_base.h", + "trace_data/trace_data_cache_reader.cpp", + "trace_data/trace_data_cache_reader.h", + "trace_data/trace_data_cache_writer.cpp", + "trace_data/trace_data_cache_writer.h", + "trace_data/trace_data_db.cpp", + "trace_data/trace_data_db.h", + "trace_data/trace_stdtype.cpp", + "trace_data/trace_stdtype.h", + "trace_streamer/trace_streamer_selector.cpp", + "trace_streamer/trace_streamer_selector.h", + ] + include_dirs = [ + "base", + "..", + "trace_streamer", + "filter", + "table", + "trace_data", + "include", + "plugin", + "rpc", + "sdk", + "./", + "parser", + "cfg", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "//third_party/protobuf/src", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + ] + if (!use_wasm) { + include_dirs += [ + "//third_party/libunwind/include", + "//third_party/libunwind/src", + ] + } + if (with_perf) { + sources += [] + include_dirs += [] + } + deps = [ + "base:base", + "ext:sqliteext", + "include:ibase", + "plugin:sdk_plugin", + "protos:ts_proto_data_cpp", + "//third_party/sqlite:sqlite", + ] + if (with_perf) { + } + + if (use_wasm || enable_ts_utest) { + sources += [ + "sdk/wasm_func.cpp", + "sdk/wasm_func.h", + ] + } + cflags = [ "-std=c++17" ] + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } + public_deps = [] +} +if (use_wasm) { + wasm_lib("trace_streamer_dubai_builtin_wasm") { + name = "trace_streamer_dubai_builtin" + deps = [ ":lib" ] + } +} else { + if (!is_test && !is_fuzz) { + executable("trace_streamer111") { + deps = [ ":lib" ] + } + } +} diff --git a/trace_streamer/sdk/dubai_sdk/base/BUILD.gn b/trace_streamer/sdk/dubai_sdk/base/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..80c4437a97aefd5a4c6e461de2a73bb4b5a12b94 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("../ts.gni") +ohos_source_set("base") { + subsystem_name = "trace_streamer" + part_name = "sdk_dubai" + deps = [] + public_deps = [ "../include:ibase" ] + include_dirs = [ "../include" ] + sources = [ + # "codec_cov.cpp", + # "file.cpp", + "log.cpp", + "meta.cpp", + + # "parting_string.cpp", + "string_help.cpp", + ] + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } +} diff --git a/trace_streamer/sdk/dubai_sdk/base/args_set.h b/trace_streamer/sdk/dubai_sdk/base/args_set.h new file mode 100644 index 0000000000000000000000000000000000000000..6148fd25be100805820643594e7a5a9bfc27174b --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/args_set.h @@ -0,0 +1,50 @@ +/* + * 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 SRC_TRACE_BASE_ARGS_SET_H +#define SRC_TRACE_BASE_ARGS_SET_H + +#include +#include +#include "ts_common.h" +namespace SysTuning { +namespace TraceStreamer { +class ArgsSet { +public: + ArgsSet() {} + ~ArgsSet() {} + ArgsSet& operator=(const ArgsSet& other) + { + this->valuesMap_ = other.valuesMap_; + this->argSetId_ = other.argSetId_; + this->sliceId_ = other.sliceId_; + this->inserted_ = other.inserted_; + return *this; + } + void AppendArg(DataIndex dataIndex, BaseDataType datatype, uint64_t value) + { + ArgsData data; + data.type = datatype; + data.value = value; + valuesMap_.emplace(dataIndex, data); + } + std::map valuesMap_; + uint32_t argSetId_ = 0; + uint32_t sliceId_ = 0; + bool inserted_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/base/log.cpp b/trace_streamer/sdk/dubai_sdk/base/log.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d167a90cb4f5f1678b59e23518ddce9873b89d1 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/log.cpp @@ -0,0 +1,17 @@ +/* + * 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 "log.h" +bool g_cleanMode = false; diff --git a/trace_streamer/sdk/dubai_sdk/base/meta.cpp b/trace_streamer/sdk/dubai_sdk/base/meta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06a737262cfb31034b9f82615497e227c61baaca --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/meta.cpp @@ -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. + */ +#include "meta.h" +size_t g_loadSize = 0; +std::string SDK_VERSION = "1.0.2"; // version +std::string SDK_PUBLISHVERSION = "2023/3/13"; // publish datetime diff --git a/trace_streamer/sdk/dubai_sdk/base/meta.h b/trace_streamer/sdk/dubai_sdk/base/meta.h new file mode 100644 index 0000000000000000000000000000000000000000..99ca44232a458eabe8dc22561a22d92f126a2353 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/meta.h @@ -0,0 +1,23 @@ +/* + * 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 META_H +#define META_H +#include +#include +extern size_t g_loadSize; +extern std::string SDK_VERSION; // version +extern std::string SDK_PUBLISHVERSION; // publish datetime +#endif diff --git a/trace_streamer/sdk/dubai_sdk/base/quatra_map.h b/trace_streamer/sdk/dubai_sdk/base/quatra_map.h new file mode 100644 index 0000000000000000000000000000000000000000..df344bd08bf91b71c2d5be8f86921b0c058068a4 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/quatra_map.h @@ -0,0 +1,90 @@ +/* + * 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 SRC_TRACE_BASE_QUATRAMAP_H +#define SRC_TRACE_BASE_QUATRAMAP_H + +#include "triple_map.h" + +template +class QuatraMap { +public: + QuatraMap(T5 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T5 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Insert(t2, t3, t4, t5); + } else { + TripleMap mm(invalidValue_); + mm.Insert(t2, t3, t4, t5); + internalMap_.insert(std::make_pair(t1, mm)); + } + } + T5 Find(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return (*streamIdHookidMap).second.Find(t2, t3, t4); + } else { + return invalidValue_; + } + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2); + } + } + void Erase(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3); + } + } + void Erase(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3, t4); + } + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T5 invalidValue_; +}; + +#endif // SRC_TRACE_BASE_QUATRAMAP_H diff --git a/trace_streamer/sdk/dubai_sdk/base/string_help.cpp b/trace_streamer/sdk/dubai_sdk/base/string_help.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f308ac072f2dd05602834e706c312a84697bf88a --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/string_help.cpp @@ -0,0 +1,81 @@ +/* + * 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 "string_help.h" +#include +#include +#include +#include +namespace SysTuning { +namespace base { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +#if !is_mingw +int32_t memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize) +{ + if (srcSize > destSize || src == nullptr || dest == nullptr) { + return -1; + } else { + if (!memcpy(dest, src, srcSize)) { + printf("memcpy fail\n"); + return -1; + } + } + return 0; +} +int32_t sscanf_s(const char* buffer, const char* format, ...) +{ + va_list ap; + __builtin_va_start(ap, format); + int32_t ret = scanf(buffer, format, ap); + __builtin_va_end(ap); + return ret; +} + +int32_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count) +{ + return memcpy_s(strDest, destMax, strSrc, count); +} +#endif +void* memset_s(void* dest, size_t destSize, int32_t ch, size_t n) +{ + UNUSED(destSize); + UNUSED(ch); + return memset(dest, 0, n); +} + +int32_t snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...) +{ + UNUSED(count); + int32_t ret; + va_list ap; + __builtin_va_start(ap, format); + ret = vsnprintf(strDest, destMax, format, ap); + __builtin_va_end(ap); + return ret; +} + +int32_t sprintf_s(char* strDest, size_t destMax, const char* format, ...) +{ + UNUSED(destMax); + va_list ap; + __builtin_va_start(ap, format); + int32_t ret = sprintf(strDest, format, ap); + __builtin_va_end(ap); + return ret; +} +} // namespace base +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/base/string_help.h b/trace_streamer/sdk/dubai_sdk/base/string_help.h new file mode 100644 index 0000000000000000000000000000000000000000..c2048609f18db7f4680f997f8710f3d6346b0a78 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/string_help.h @@ -0,0 +1,32 @@ +/* + * 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 SRC_TRACE_BASE_STRINGHELP_H +#define SRC_TRACE_BASE_STRINGHELP_H + +#include +#include +namespace SysTuning { +namespace base { +#if !is_mingw +int32_t memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize); +int32_t sscanf_s(const char* buffer, const char* format, ...); +int32_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count); +#endif +void* memset_s(void* dest, size_t destSize, int32_t ch, size_t n); +int32_t snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...); +int32_t sprintf_s(char* strDest, size_t destMax, const char* format, ...); +} // namespace base +} // namespace SysTuning +#endif // SRC_TRACE_BASE_STRINGHELP_H diff --git a/trace_streamer/sdk/dubai_sdk/base/triple_map.h b/trace_streamer/sdk/dubai_sdk/base/triple_map.h new file mode 100644 index 0000000000000000000000000000000000000000..b9c30f8402fa067e3ae1f3bb9644c2f622a5ae06 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/triple_map.h @@ -0,0 +1,83 @@ +/* + * 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 SRC_TRACE_BASE_TRIPLEMAP_H +#define SRC_TRACE_BASE_TRIPLEMAP_H + +#include "double_map.h" + +template +class TripleMap { +public: + TripleMap(T4 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T4 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Insert(t2, t3, t4); + } else { + DoubleMap mm(invalidValue_); + mm.Insert(t2, t3, t4); + internalMap_.insert(std::make_pair(t1, mm)); + } + } + T4 Find(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return (*streamIdHookidMap).second.Find(t2, t3); + } else { + return invalidValue_; + } + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2); + } + } + void Erase(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3); + } + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T4 invalidValue_; +}; + +#endif // SRC_TRACE_BASE_TRIPLEMAP_H diff --git a/trace_streamer/sdk/dubai_sdk/base/ts_common.h b/trace_streamer/sdk/dubai_sdk/base/ts_common.h new file mode 100644 index 0000000000000000000000000000000000000000..2e99a653574ca55163629a85d9a6ad99990e5c00 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/base/ts_common.h @@ -0,0 +1,125 @@ +/* + * 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 SRC_TRACE_BASE_TS_COMMON_H +#define SRC_TRACE_BASE_TS_COMMON_H + +#include +#include +#include +#include + +const uint64_t INVALID_UTID = std::numeric_limits::max(); +const uint64_t INVALID_UINT64 = std::numeric_limits::max(); +const uint64_t MAX_UINT32 = std::numeric_limits::max(); +const uint64_t MAX_UINT64 = std::numeric_limits::max(); +const uint32_t INVALID_UINT32 = std::numeric_limits::max(); +const uint32_t INVALID_INT32 = std::numeric_limits::max(); +const uint64_t INVALID_DATAINDEX = std::numeric_limits::max(); +const size_t MAX_SIZE_T = std::numeric_limits::max(); +const uint32_t INVALID_ID = std::numeric_limits::max(); +const uint64_t SEC_TO_NS = 1000 * 1000 * 1000; +const int32_t STR_DEFAULT_LEN = -1; +const auto INVALID_CPU = INVALID_UINT32; +const auto INVALID_TIME = INVALID_UINT64; +enum BuiltinClocks { + TS_CLOCK_UNKNOW = 0, + TS_CLOCK_BOOTTIME = 1, + TS_CLOCK_REALTIME = 2, + TS_CLOCK_REALTIME_COARSE = 3, + TS_MONOTONIC = 4, + TS_MONOTONIC_COARSE = 5, + TS_MONOTONIC_RAW = 6, +}; + +enum RefType { + K_REF_NO_REF = 0, + K_REF_ITID = 1, + K_REF_CPUID = 2, + K_REF_IRQ = 3, + K_REF_SOFT_IRQ = 4, + K_REF_IPID = 5, + K_REF_ITID_LOOKUP_IPID = 6, + K_REF_MAX +}; + +enum EndState { + // (R) ready state or running state, the process is ready to run, but not necessarily occupying the CPU + TASK_RUNNABLE = 0, + // (S) Indicates that the process is in light sleep, waiting for the resource state, and can respond to the signal. + // Generally, the process actively sleeps into 'S' state. + TASK_INTERRUPTIBLE = 1, + // (D) Indicates that the process is in deep sleep, waiting for resources, and does not respond to signals. + // Typical scenario: process acquisition semaphore blocking. + TASK_UNINTERRUPTIBLE = 2, + // (Running) Indicates that the thread is running + TASK_RUNNING = 3, + // (I) Thread in interrupt state + TASK_INTERRUPTED = 4, + // (T) Task being traced + TASK_TRACED = 8, + // (X) Exit status, the process is about to be destroyed. + TASK_EXIT_DEAD = 16, + // (Z) Zombie state + TASK_ZOMBIE = 32, + // (I) clone thread + TASK_CLONE = 64, + // (K) Process killed + TASK_KILLED = 128, + // (DK) + TASK_DK = 130, + // the process is being debug now + TASK_TRACED_KILL = 136, + // (W) The process is in a deep sleep state and will be killed directly after waking up + TASK_WAKEKILL = 256, + // (R+) Process groups in the foreground + TASK_FOREGROUND = 2048, + TASK_MAX = 4096, + TASK_INVALID = 9999 +}; +enum TSLogLevel { + TS_DEBUG = 68, // Debug + TS_ERROR = 69, // Error + TS_INFO = 73, // Info + TS_VERBOSE = 86, // Verbose + TS_WARN = 87 // Warn +}; +enum SchedWakeType { + SCHED_WAKING = 0, // sched_waking + SCHED_WAKEUP = 1, // sched_wakeup +}; +using DataIndex = uint64_t; +using TableRowId = uint32_t; +using InternalPid = uint32_t; +using InternalTid = uint32_t; +using InternalTime = uint64_t; +using FilterId = uint32_t; +using InternalCpu = uint32_t; // how many cpus? could change to int8_t? + +enum BaseDataType { + BASE_DATA_TYPE_INT, + BASE_DATA_TYPE_STRING, + BASE_DATA_TYPE_DOUBLE, + BASE_DATA_TYPE_BOOLEAN +}; +namespace SysTuning { +namespace TraceStreamer { +struct ArgsData { + BaseDataType type; + int64_t value; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/doc/wasm.md b/trace_streamer/sdk/dubai_sdk/doc/wasm.md new file mode 100755 index 0000000000000000000000000000000000000000..0c2876b9e1816899915b5c07234cf56743c6045e --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/doc/wasm.md @@ -0,0 +1,43 @@ +为了方便传输此sdk开发包,位于prebuilts目录下的emsdk目录已经被删除,可以通过下面的 +为了编译WebAssembly版本,需要在prebuilts/目录下安装emsdk +``` +git clone https://github.com/juj/emsdk.git --depth=1 +cd emsdk +git pull +./emsdk update # this may not work, ignore it +./emsdk install latest +./emsdk activate latest +安装之后,需要将upstream目录复制到prebuilts/emsdk/emsdk,node复制到prebuilts/emsdk/node +``` +安装之后,目录结构当如: +``` +prebuilts/emsdk +├── prebuilts/emsdk/emsdk +│ ├── prebuilts/emsdk/emsdk/bin +│ ├── prebuilts/emsdk/emsdk/emscripten +│ │ ├── prebuilts/emsdk/emsdk/emscripten/cache +│ │ ├── prebuilts/emsdk/emsdk/emscripten/cmake +│ │ ├── prebuilts/emsdk/emsdk/emscripten/docs +│ │ ├── prebuilts/emsdk/emsdk/emscripten/media +│ │ ├── prebuilts/emsdk/emsdk/emscripten/node_modules +│ │ ├── prebuilts/emsdk/emsdk/emscripten/__pycache__ +│ │ ├── prebuilts/emsdk/emsdk/emscripten/src +│ │ ├── prebuilts/emsdk/emsdk/emscripten/system +│ │ ├── prebuilts/emsdk/emsdk/emscripten/tests +│ │ ├── prebuilts/emsdk/emsdk/emscripten/third_party +│ │ └── prebuilts/emsdk/emsdk/emscripten/tools +│ ├── prebuilts/emsdk/emsdk/include +│ │ └── prebuilts/emsdk/emsdk/include/c++ +│ └── prebuilts/emsdk/emsdk/lib +│ └── prebuilts/emsdk/emsdk/lib/clang +└── prebuilts/emsdk/node + └── prebuilts/emsdk/node/14.18.2_64bit + ├── prebuilts/emsdk/node/14.18.2_64bit/bin + ├── prebuilts/emsdk/node/14.18.2_64bit/include + ├── prebuilts/emsdk/node/14.18.2_64bit/lib + └── prebuilts/emsdk/node/14.18.2_64bit/share +``` +之后调用 +``` +./build.sh sdkdemo 进行编译demo +``` \ No newline at end of file diff --git a/trace_streamer/sdk/dubai_sdk/ext/BUILD.gn b/trace_streamer/sdk/dubai_sdk/ext/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..a2212ebeb58dd199eb0c456701a8925f95e277c4 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/ext/BUILD.gn @@ -0,0 +1,25 @@ +# 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") +config("sqlite_config") { + include_dirs = [ + "//third_party/sqlite/include", + "../include", + ] + cflags = [ "-Wno-writable-strings" ] +} +source_set("sqliteext") { + sources = [ "sqlite_ext_funcs.cpp" ] + public_configs = [ ":sqlite_config" ] +} diff --git a/trace_streamer/sdk/dubai_sdk/ext/sqlite_ext_funcs.cpp b/trace_streamer/sdk/dubai_sdk/ext/sqlite_ext_funcs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d34064dc55a79f043dac99df3c1405803a945b96 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/ext/sqlite_ext_funcs.cpp @@ -0,0 +1,358 @@ +/* + * 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 "sqlite_ext_funcs.h" +#include +#include +#include "log.h" +#include "sqlite3.h" +namespace SysTuning { +namespace base { +/* +** Return a stdev value +*/ +static void sqliteExtStdevFinalize(sqlite3_context* context) +{ + StdevCtx* ptr = static_cast(sqlite3_aggregate_context(context, 0)); + if (ptr && ptr->cntValue > 1) { + sqlite3_result_double(context, sqrt(ptr->rSValue / (ptr->cntValue - 1))); + } else { + sqlite3_result_double(context, 0.0); + } +} +/* +** called each value received during a calculation of stdev or variance +*/ +static void sqliteExtStdevNextStep(sqlite3_context* context, int32_t argc, sqlite3_value** argv) +{ + TS_ASSERT(argc == 1); + StdevCtx* ptr = static_cast(sqlite3_aggregate_context(context, sizeof(StdevCtx))); + if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) { + ptr->cntValue++; + double x = sqlite3_value_double(argv[0]); + double deltaValue = (x - ptr->rMValue); + ptr->rMValue += deltaValue / ptr->cntValue; + ptr->rSValue += deltaValue * (x - ptr->rMValue); + } +} + +enum Type { + tsNull = 0, + tsLong, + tsDouble, + tsString, + tsBytes, +}; + +struct TSSqlValue { + TSSqlValue() = default; + + static TSSqlValue Long(int64_t v) + { + TSSqlValue value; + value.longValue = v; + value.type = Type::tsLong; + return value; + } + + static TSSqlValue Double(double v) + { + TSSqlValue value; + value.doubleValue = v; + value.type = Type::tsDouble; + return value; + } + + static TSSqlValue String(const char* v) + { + TSSqlValue value; + value.stringValue = v; + value.type = Type::tsString; + return value; + } + + static TSSqlValue Bytes(const void* v, size_t size) + { + TSSqlValue value; + value.bytesValue = v; + value.bytesCount = size; + value.type = Type::tsBytes; + return value; + } + + double GetDouble() const + { + return doubleValue; + } + int64_t GetLong() const + { + return longValue; + } + const char* GetString() const + { + return stringValue; + } + const void* GetBytes() const + { + return bytesValue; + } + + bool isNull() const + { + return type == Type::tsNull; + } + + union { + const char* stringValue; + int64_t longValue; + double doubleValue; + const void* bytesValue; + }; + size_t bytesCount = 0; + Type type = tsNull; +}; + +TSSqlValue SqliteValueToTSSqlValue(sqlite3_value* value) +{ + TSSqlValue sqlValue; + switch (sqlite3_value_type(value)) { + case SQLITE_INTEGER: + sqlValue.type = Type::tsLong; + sqlValue.longValue = sqlite3_value_int64(value); + break; + case SQLITE_FLOAT: + sqlValue.type = Type::tsDouble; + sqlValue.doubleValue = sqlite3_value_double(value); + break; + case SQLITE_TEXT: + sqlValue.type = Type::tsString; + sqlValue.stringValue = reinterpret_cast(sqlite3_value_text(value)); + break; + case SQLITE_BLOB: + sqlValue.type = Type::tsBytes; + sqlValue.bytesValue = sqlite3_value_blob(value); + sqlValue.bytesCount = static_cast(sqlite3_value_bytes(value)); + break; + } + return sqlValue; +} +class JsonBuild { +public: + JsonBuild() = default; + void AppendHead() + { + body_ += "{"; + } + void AppendTail() + { + body_ += "}"; + } + void AppendCommon() + { + body_ += ","; + } + bool AppendSqlValue(const std::string& field_name, const TSSqlValue& value) + { + body_ += "\"" + field_name + "\":"; + return AppendSqlValue(value); + } + bool AppendSqlValue(const TSSqlValue& value) + { + switch (value.type) { + case tsLong: + body_ += std::to_string(value.longValue) + ","; + break; + case tsDouble: + body_ += std::to_string(value.doubleValue) + ","; + break; + case tsString: + body_ += "\"" + std::string(value.stringValue) + "\"" + ","; + break; + case tsBytes: + body_ += "\"" + std::string(static_cast(value.bytesValue), value.bytesCount) + "\"" + ","; + break; + case tsNull: + body_ += std::to_string(0) + ","; + break; + } + return true; + } + std::string body_; + bool poped_ = false; + void PopLast() + { + body_.pop_back(); + } + const std::string& Body() const + { + return body_; + } +}; + +void BuildJson(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + const int32_t PAIR_ARGS_SIZE = 2; + if (argc % PAIR_ARGS_SIZE != 0) { + TS_LOGI("BuildJson arg number error"); + sqlite3_result_error(ctx, "BuildJson arg number error", -1); + return; + } + + JsonBuild builder; + builder.AppendHead(); + for (int32_t i = 0; i < argc; i += PAIR_ARGS_SIZE) { + if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) { + TS_LOGI("BuildJson: Invalid args argc:%d, %d", argc, sqlite3_value_type(argv[i])); + sqlite3_result_error(ctx, "BuildJson: Invalid args", -1); + return; + } + + auto* key = reinterpret_cast(sqlite3_value_text(argv[i])); + auto value = SqliteValueToTSSqlValue(argv[i + 1]); + auto status = builder.AppendSqlValue(key, value); + if (!status) { + TS_LOGI("AppendSqlValueError"); + sqlite3_result_error(ctx, "AppendSqlValueError", -1); + return; + } + } + builder.PopLast(); + builder.AppendTail(); + std::string raw = builder.Body(); + if (raw.empty()) { + sqlite3_result_blob(ctx, "", 0, nullptr); + return; + } + std::unique_ptr data = std::make_unique(raw.size()); + memcpy(data.get(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} + +void RepeatedJsonStep(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + const int32_t PAIR_ARGS_SIZE = 2; + auto** jsonBuild = static_cast(sqlite3_aggregate_context(ctx, sizeof(JsonBuild*))); + + if (*jsonBuild == nullptr) { + *jsonBuild = new JsonBuild(); + } + JsonBuild* builder = *jsonBuild; + builder->AppendHead(); + for (int32_t i = 0; i < argc; i += PAIR_ARGS_SIZE) { + if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) { + TS_LOGI("BuildJson: Invalid args argc:%d, %d", argc, sqlite3_value_type(argv[i])); + sqlite3_result_error(ctx, "BuildJson: Invalid args", -1); + return; + } + + auto* key = reinterpret_cast(sqlite3_value_text(argv[i])); + auto value = SqliteValueToTSSqlValue(argv[i + 1]); + auto status = builder->AppendSqlValue(key, value); + if (!status) { + TS_LOGI("AppendSqlValueError"); + sqlite3_result_error(ctx, "AppendSqlValueError", -1); + return; + } + } + builder->PopLast(); + builder->AppendTail(); + builder->AppendCommon(); +} +void RepeatedFieldStep(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + if (argc != 1) { + TS_LOGE( + "RepeatedField only support one arg, you can use BuildJson or BuildRepeatedJson function for multi args"); + return; + } + auto** jsonBuild = static_cast(sqlite3_aggregate_context(ctx, sizeof(JsonBuild*))); + + if (*jsonBuild == nullptr) { + *jsonBuild = new JsonBuild(); + } + JsonBuild* builder = *jsonBuild; + for (int32_t i = 0; i < argc; i++) { + auto value = SqliteValueToTSSqlValue(argv[i]); + auto status = builder->AppendSqlValue(value); + if (!status) { + sqlite3_result_error(ctx, "error", -1); + } + } +} + +void RepeatedFieldFinal(sqlite3_context* ctx) +{ + auto** jsonBuilder = static_cast(sqlite3_aggregate_context(ctx, 0)); + + if (jsonBuilder == nullptr) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr builder(*jsonBuilder); + std::string raw = builder->Body(); + raw.pop_back(); + if (raw.empty()) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr data = std::make_unique(raw.size()); + memcpy(data.get(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} + +void RepeatedJsonFinal(sqlite3_context* ctx) +{ + auto** jsonBuilder = static_cast(sqlite3_aggregate_context(ctx, 0)); + + if (jsonBuilder == nullptr) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr builder(*jsonBuilder); + builder->PopLast(); + std::string raw = builder->Body(); + if (raw.empty()) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr data = std::make_unique(raw.size()); + memcpy(data.get(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} +void ts_create_extend_function(sqlite3* db) +{ + sqlite3_create_function(db, "stdev", -1, SQLITE_UTF8, nullptr, 0, sqliteExtStdevNextStep, sqliteExtStdevFinalize); + auto ret = sqlite3_create_function_v2(db, "RepeatedField", 1, SQLITE_UTF8, nullptr, nullptr, RepeatedFieldStep, + RepeatedFieldFinal, nullptr); + if (ret) { + TS_LOGF("Error while initializing RepeatedField"); + } + ret = sqlite3_create_function_v2(db, "BuildRepeatedJson", -1, SQLITE_UTF8, nullptr, nullptr, RepeatedJsonStep, + RepeatedJsonFinal, nullptr); + if (ret) { + TS_LOGF("Error while initializing BuildRepeatedJson"); + } + std::unique_ptr ctx = std::make_unique(); + ret = sqlite3_create_function_v2(db, "BuildJson", -1, SQLITE_UTF8, ctx.release(), BuildJson, nullptr, nullptr, + [](void* ptr) { delete static_cast(ptr); }); + if (ret != SQLITE_OK) { + TS_LOGF("Error while initializing BuildJson"); + } +} +} // namespace base +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/sdk/dubai_sdk/ext/sqlite_ext_funcs.h b/trace_streamer/sdk/dubai_sdk/ext/sqlite_ext_funcs.h new file mode 100644 index 0000000000000000000000000000000000000000..e1ce74a727d69a10d177682f38f54ac943c0687c --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/ext/sqlite_ext_funcs.h @@ -0,0 +1,30 @@ +/* + * 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 SQLITE_EXT_FUNCS_H +#define SQLITE_EXT_FUNCS_H 1 +#include +#include "sqlite3.h" +namespace SysTuning { +namespace base { +typedef struct StdevCtx StdevCtx; +struct StdevCtx { + double rMValue; + double rSValue; + int64_t cntValue; +}; +void ts_create_extend_function(sqlite3* db); +} // namespace base +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/filter/clock_filter.cpp b/trace_streamer/sdk/dubai_sdk/filter/clock_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..339fddffb0e8004d3adda29892b722d180d854a3 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/filter/clock_filter.cpp @@ -0,0 +1,147 @@ +/* + * 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 "clock_filter.h" +#include +#include +#include "string_help.h" + +namespace SysTuning { +namespace TraceStreamer { +ClockFilter::ClockFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) +{ + profilerSDKTraceFileHeader_ = std::make_unique().get(); +} +ClockFilter::~ClockFilter() {} + +std::string ClockFilter::GenClockKey(ClockId srcClockId, ClockId desClockId) +{ + std::string ret; + ret += std::to_string(srcClockId); + ret += ","; + ret += std::to_string(desClockId); + return ret; +} + +uint64_t ClockFilter::ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const +{ + if (srcClockId == primaryClock_) { + return srcTs; + } + return Convert(srcClockId, srcTs, primaryClock_); +} + +uint64_t ClockFilter::Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const +{ + std::string&& clockKey = GenClockKey(srcClockId, desClockId); + auto keyIt = clockMaps_.find(clockKey); + if (keyIt == clockMaps_.end()) { + return srcTs; + } + + auto tsIt = keyIt->second.upper_bound(srcTs); + if (tsIt != keyIt->second.begin()) { + tsIt--; + } + + if (tsIt->second >= 0) { + return srcTs + static_cast(tsIt->second); + } else { + return srcTs - static_cast(0 - tsIt->second); + } +} + +void ClockFilter::AddConvertClockMap(ClockId srcClockId, ClockId dstClockId, uint64_t srcTs, uint64_t dstTs) +{ + std::string&& clockKey = GenClockKey(srcClockId, dstClockId); + auto keyIt = clockMaps_.find(clockKey); + if (keyIt == clockMaps_.end()) { + ConvertClockMap newConvertMap = {{srcTs, dstTs - srcTs}}; + clockMaps_[clockKey] = newConvertMap; + } else { + clockMaps_[clockKey].insert(std::make_pair(srcTs, dstTs - srcTs)); + } +} +void ClockFilter::AddClockSnapshot(const std::vector& snapShot) +{ + ClockId srcId, desId; + for (srcId = 0; srcId < snapShot.size() - 1; ++srcId) { + for (desId = srcId + 1; desId < snapShot.size(); ++desId) { + ClockId srcClockId = snapShot[srcId].clockId; + ClockId desClockId = snapShot[desId].clockId; + uint64_t srcTs = snapShot[srcId].ts; + uint64_t desTs = snapShot[desId].ts; + + AddConvertClockMap(srcClockId, desClockId, srcTs, desTs); + AddConvertClockMap(desClockId, srcClockId, desTs, srcTs); + } + } + hasInitSnapShot_ = true; +} + +int32_t ClockFilter::InitSnapShotTimeRange(const uint8_t* data, int32_t len) +{ + std::unique_ptr buf = std::make_unique(len); + std::copy(data, data + len, buf.get()); + profilerSDKTraceFileHeader_ = reinterpret_cast(buf.get()); + + if (HasInitSnapShot()) { + TS_LOGE("SDK already has clock snapshot!!!"); + return -1; + } + if (!profilerSDKTraceFileHeader_->data.boottime) { + TS_LOGE("SDK Profiler header has no clock snapshot!!!"); + return -1; + } + + std::vector snapShot; + + TS_LOGE("SDK clockid: TS_CLOCK_BOOTTIME, ts:%llu", profilerSDKTraceFileHeader_->data.boottime); + if (profilerSDKTraceFileHeader_->data.boottime) { + snapShot.push_back(SnapShot{TS_CLOCK_BOOTTIME, profilerSDKTraceFileHeader_->data.boottime}); + } + + TS_LOGE("SDK clockid: TS_CLOCK_REALTIME, ts:%llu", profilerSDKTraceFileHeader_->data.realtime); + if (profilerSDKTraceFileHeader_->data.realtime) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME, profilerSDKTraceFileHeader_->data.realtime}); + } + + TS_LOGE("SDK clockid: TS_CLOCK_REALTIME_COARSE, ts:%llu", profilerSDKTraceFileHeader_->data.realtimeCoarse); + if (profilerSDKTraceFileHeader_->data.realtimeCoarse) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME_COARSE, profilerSDKTraceFileHeader_->data.realtimeCoarse}); + } + + TS_LOGE("SDK clockid: TS_MONOTONIC, ts:%llu", profilerSDKTraceFileHeader_->data.monotonic); + if (profilerSDKTraceFileHeader_->data.monotonic) { + snapShot.push_back(SnapShot{TS_MONOTONIC, profilerSDKTraceFileHeader_->data.monotonic}); + } + + TS_LOGE("SDK clockid: TS_MONOTONIC_COARSE, ts:%llu", profilerSDKTraceFileHeader_->data.monotonicCoarse); + if (profilerSDKTraceFileHeader_->data.monotonicCoarse) { + snapShot.push_back(SnapShot{TS_MONOTONIC_COARSE, profilerSDKTraceFileHeader_->data.monotonicCoarse}); + } + + TS_LOGE("SDK clockid: TS_MONOTONIC_RAW, ts:%llu", profilerSDKTraceFileHeader_->data.monotonicRaw); + if (profilerSDKTraceFileHeader_->data.monotonicRaw) { + snapShot.push_back(SnapShot{TS_MONOTONIC_RAW, profilerSDKTraceFileHeader_->data.monotonicRaw}); + } + + if (snapShot.size()) { + AddClockSnapshot(snapShot); + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/filter/clock_filter.h b/trace_streamer/sdk/dubai_sdk/filter/clock_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..73ea3f2fe3974565c4f4fc76fab10e8363e50808 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/filter/clock_filter.h @@ -0,0 +1,89 @@ +/* + * 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 CLOCK_FILTER_H +#define CLOCK_FILTER_H + +#include +#include +#include +#include +#include +#include "file.h" +#include "trace_data_cache.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +/* + * TS_REALTIME: A settable system-wide clock that measures real time. Its time represents seconds and nanoseconds + * since the Epoch. + * TS_REALTIME_COARSE: A faster but less precise version of TS_REALTIME. This clock is not settable. + * TS_MONOTONIC: The number of seconds that the system has been running since it was booted.The CLOCK_MONOTONIC + * clock is not affected by discontinuous jumps in the system time ,but is affected by the incremental adjustments + * performed by adjtime(3) and NTP. This clock does not count time that the system is suspended. + * TS_MONOTONIC_COARSE: A faster but less precise version of TS_MONOTONIC. + * TS_MONOTONIC_RAW: Similar to TS_MONOTONIC, but provides access to a raw hardware-based time that is not subject + * to NTP adjustments or the incremental adjustments performed by adjtime(3). This clock does not count time that the + * system is suspended. + * TS_BOOTTIME: A nonsettable system-wide clock that is identical to TS_MONOTONIC, except that it also includes + * any time that the system is suspended. + */ + +using ClockId = uint32_t; +struct SnapShot { + ClockId clockId; + uint64_t ts; +}; +class TraceStreamerFilters; +class ClockFilter { +public: + using ConvertClockMap = std::map; + ClockFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~ClockFilter(); + + void SetPrimaryClock(ClockId primary) + { + primaryClock_ = primary; + } + ClockId GetPrimaryClock() const + { + return primaryClock_; + } + uint64_t ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const; + uint64_t Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const; + void UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp); + void AddClockSnapshot(const std::vector& snapShot); + int32_t InitSnapShotTimeRange(const uint8_t* data, int32_t len); + bool HasInitSnapShot() const + { + return hasInitSnapShot_; + } + +private: + static std::string GenClockKey(ClockId srcClockId, ClockId desClockId); + void AddConvertClockMap(ClockId srcClockId, ClockId dstClockId, uint64_t srcTs, uint64_t dstTs); + +private: + std::unordered_map clockMaps_ = {}; + base::ProfilerTraceFileHeader* profilerSDKTraceFileHeader_; + + ClockId primaryClock_ = BuiltinClocks::TS_CLOCK_BOOTTIME; + bool hasInitSnapShot_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // CLOCK_FILTER_H diff --git a/trace_streamer/sdk/dubai_sdk/include/BUILD.gn b/trace_streamer/sdk/dubai_sdk/include/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..26c0ae9c99639118e7dff3df825541200332253b --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/include/BUILD.gn @@ -0,0 +1,28 @@ +# 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") +ohos_source_set("ibase") { + subsystem_name = "trace_streamer" + part_name = "dubai_ibase" + sources = [ + "codec_cov.h", + "file.h", + "log.h", + "parting_string.h", + "string_to_numerical.h", + ] + include_dirs = [] + public_deps = [] + deps = [] + sources += [ "/usr/x86_64-w64-mingw32/include/windows.h" ] +} diff --git a/trace_streamer/sdk/dubai_sdk/include/file.h b/trace_streamer/sdk/dubai_sdk/include/file.h new file mode 100644 index 0000000000000000000000000000000000000000..91d6d6231a2de83d349d84cb51c6086f6fb620d9 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/include/file.h @@ -0,0 +1,80 @@ +/* + * 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 INCLUDE_TUNING_BASE_FILE_UTILS_H_ +#define INCLUDE_TUNING_BASE_FILE_UTILS_H_ + +#include + +namespace SysTuning { +namespace base { +#define TS_PERMISSION_RW 0600 +constexpr uint32_t kFileModeInvalid = 0xFFFFFFFF; +enum TraceParserStatus { + TRACE_PARSER_NORMAL = 0, + TRACE_PARSER_FILE_TYPE_ERROR = 1, + TRACE_PARSE_ERROR = 2, + TRACE_PARSER_ABNORMAL = 3 +}; +struct ProfilerTraceFileHeader { + // Some space is reserved to facilitate the subsequent addition of fields in the header + static constexpr uint32_t HEADER_SIZE = 1024; + static constexpr uint32_t SHA256_SIZE = 256 / 8; + static constexpr uint64_t HEADER_MAGIC = 0x464F5250534F484FuLL; + static constexpr uint32_t V_MAJOR = 0x0001; + static constexpr uint32_t V_MAJOR_BITS = 16; + static constexpr uint32_t V_MINOR = 0x0000; + static constexpr uint32_t TRACE_VERSION = (V_MAJOR << V_MAJOR_BITS) | V_MINOR; + enum DataType { + HIPROFILER_PROTOBUF_BIN = 0, + HIPERF_DATA, + UNKNOW_TYPE = 1024, + }; + struct HeaderData { + // Magic number, used to distinguish offline files + uint64_t magic = HEADER_MAGIC; + // Total length, which can be used to check whether the document is truncated; + uint64_t length = HEADER_SIZE; + uint32_t version = TRACE_VERSION; + // The number of segments in the load data. The number of segments is even. One describes the length L and the + // other describes the next data v + uint32_t segments = 0; + // Sha256 of load data is used to verify whether the load data is complete; + uint8_t sha256[SHA256_SIZE] = {}; + uint32_t dataType = UNKNOW_TYPE; + // clock + uint64_t boottime = 0; + uint64_t realtime = 0; + uint64_t realtimeCoarse = 0; + uint64_t monotonic = 0; + uint64_t monotonicCoarse = 0; + uint64_t monotonicRaw = 0; + } __attribute__((packed)); + HeaderData data = {}; + uint8_t padding_[HEADER_SIZE - sizeof(data)] = {}; +}; + +void SetAnalysisResult(TraceParserStatus stat); + +TraceParserStatus GetAnalysisResult(); + +ssize_t Read(int32_t fd, uint8_t* dst, size_t dstSize); + +int32_t OpenFile(const std::string& path, int32_t flags, uint32_t mode = kFileModeInvalid); + +std::string GetExecutionDirectoryPath(); +} // namespace base +} // namespace SysTuning +#endif // INCLUDE_TUNING_BASE_FILE_UTILS_H_ diff --git a/trace_streamer/sdk/dubai_sdk/include/log.h b/trace_streamer/sdk/dubai_sdk/include/log.h new file mode 100644 index 0000000000000000000000000000000000000000..fef94e664b845cb7715e4c7df202da47efad1789 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/include/log.h @@ -0,0 +1,66 @@ +/* + * 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 INCLUDE_TS_BASE_LOGGING_H_ +#define INCLUDE_TS_BASE_LOGGING_H_ + +#include +#include + +// namespace SysTuning { +// namespace base { +#define TS_CRASH \ + do { \ + __builtin_trap(); \ + __builtin_unreachable(); \ + } while (0) +enum LogLevel {LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL}; +const enum LogLevel g_currentLogLevel = LOG_DEBUG; +extern bool g_cleanMode; +#define LOGWITHLEVEL(level, motify, fmt, ...) \ + do { \ + if (level >= g_currentLogLevel) { \ + if (!g_cleanMode) { \ + fprintf(stdout, "[-%c][%s][%d]: " fmt "\n", motify, __FUNCTION__, \ + __LINE__, ##__VA_ARGS__); \ + } \ + if (level == LOG_FATAL) { \ + TS_CRASH; \ + } \ + } \ + } while (0) +#define TS_LOGE(fmt, ...) LOGWITHLEVEL(LOG_ERROR, 'E', fmt, ##__VA_ARGS__) +#define TS_LOGF(fmt, ...) LOGWITHLEVEL(LOG_FATAL, 'F', fmt, ##__VA_ARGS__) +#define TS_LOGI(fmt, ...) LOGWITHLEVEL(LOG_INFO, 'I', fmt, ##__VA_ARGS__) +#ifdef NDEBUG +#define TS_LOGD(format, ...) +#define TS_LOGW(format, ...) +#define TS_ASSERT(x) +#else +#define TS_LOGD(fmt, ...) LOGWITHLEVEL(LOG_DEBUG, 'D', fmt, ##__VA_ARGS__) +#define TS_LOGW(fmt, ...) LOGWITHLEVEL(LOG_WARN, 'W', fmt, ##__VA_ARGS__) + +#define TS_ASSERT(x) \ + do { \ + if (!(x)) { \ + TS_CRASH; \ + } \ + } while (0) + +#endif +// } // namespace base +// } // namespace SysTuning + +#endif // INCLUDE_TS_BASE_LOGGING_H_ diff --git a/trace_streamer/sdk/dubai_sdk/include/string_to_numerical.h b/trace_streamer/sdk/dubai_sdk/include/string_to_numerical.h new file mode 100644 index 0000000000000000000000000000000000000000..c70bff6bf5e73c26f75c1a31867fd28139f1dc2c --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/include/string_to_numerical.h @@ -0,0 +1,113 @@ +/* + * 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 INCLUDE_BASE_STRING_TO_NUMERICAL_H_ +#define INCLUDE_BASE_STRING_TO_NUMERICAL_H_ + +#include +#include +#include + +namespace SysTuning { +namespace base { +enum IntegerRadixType { + INTEGER_RADIX_TYPE_DEC = 10, + INTEGER_RADIX_TYPE_HEX = 16 +}; +inline uint16_t GetNameASCIISumNoNum(const std::string& str) +{ + uint32_t sum = 0; + int32_t len = str.length() - 1; + while (len >= 0) { + sum += std::isdigit(str.at(len)) ? 0 : str.at(len); + len--; + } + return sum % INTEGER_RADIX_TYPE_HEX; +} +inline std::optional StrToUInt32(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtoul(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::string number(uint64_t value, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + std::stringstream ss; + if (base == INTEGER_RADIX_TYPE_DEC) { + ss << std::dec << value; + } else if (base == INTEGER_RADIX_TYPE_HEX) { + ss << std::hex << value; + } + return ss.str(); +} + +inline std::optional StrToInt32(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtol(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::optional StrToUInt64(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtoull(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::optional StrToInt64(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + int64_t value = static_cast(std::strtoll(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + return std::nullopt; +} + +inline std::optional StrToDouble(const std::string& str) +{ + if (!str.empty()) { + double value = std::stod(str); + return std::make_optional(value); + } + + return std::nullopt; +} +} // namespace base +} // namespace SysTuning + +#endif // INCLUDE_TUNING_EXT_BASE_STRING_UTILS_H_ diff --git a/trace_streamer/sdk/dubai_sdk/main.cpp b/trace_streamer/sdk/dubai_sdk/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59b9cf5d546a6c53ad08f31ceeb0568d5b11d972 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/main.cpp @@ -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. + */ +int main(int argc, char** argv) +{ + return 0; +} diff --git a/trace_streamer/sdk/dubai_sdk/parser/event_parser_base.cpp b/trace_streamer/sdk/dubai_sdk/parser/event_parser_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4bdbf4f5e4e7ac919ecf6af18f1fe7b6e680f3d --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/parser/event_parser_base.cpp @@ -0,0 +1,24 @@ +/* + * 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 "event_parser_base.h" +namespace SysTuning { +namespace TraceStreamer { +EventParserBase::EventParserBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : streamFilters_(filter), traceDataCache_(dataCache) +{ +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/parser/event_parser_base.h b/trace_streamer/sdk/dubai_sdk/parser/event_parser_base.h new file mode 100644 index 0000000000000000000000000000000000000000..1d9313edfcd0557c8351d705b2e82639ac2e296e --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/parser/event_parser_base.h @@ -0,0 +1,34 @@ +/* + * 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 SRC_EVENT_PARSER_BASE_H +#define SRC_EVENT_PARSER_BASE_H +#include "../trace_data/trace_data_cache.h" +#include "../trace_streamer/trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class EventParserBase { +public: + EventParserBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + virtual ~EventParserBase() = default; + +public: + const TraceStreamerFilters* streamFilters_; + TraceDataCache* traceDataCache_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_PARSER_BASE_H diff --git a/trace_streamer/sdk/dubai_sdk/parser/htrace_plugin_time_parser.cpp b/trace_streamer/sdk/dubai_sdk/parser/htrace_plugin_time_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..164c3b38aa631e7370ae926d3dc96d6227f1c261 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/parser/htrace_plugin_time_parser.cpp @@ -0,0 +1,58 @@ +/* + * 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 "htrace_plugin_time_parser.h" +namespace SysTuning { +namespace TraceStreamer { +HtracePluginTimeParser::HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx) +{} +void HtracePluginTimeParser::UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp) +{ + minTs_ = std::min(minTs_, asyncTimestamp); + maxTs_ = std::max(maxTs_, asyncTimestamp); + if (clockId == streamFilters_->clockFilter_->GetPrimaryClock()) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + return; + } + if (syncTimestamp != asyncTimestamp) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + } else { + asyncHtracePluginStartTime_ = std::min(asyncHtracePluginStartTime_, syncTimestamp); + asyncHtracePluginEndTime_ = std::max(asyncHtracePluginEndTime_, syncTimestamp); + } +} +uint64_t HtracePluginTimeParser::GetPluginStartTime() +{ + if (syncHtracePluginStartTime_ != std::numeric_limits::max()) { + return syncHtracePluginStartTime_; + } else if (asyncHtracePluginStartTime_ != std::numeric_limits::max()) { + return asyncHtracePluginStartTime_; + } + return std::numeric_limits::max(); +} + +uint64_t HtracePluginTimeParser::GetPluginEndTime() +{ + if (syncHtracePluginEndTime_ != 0) { + return syncHtracePluginEndTime_; + } else if (asyncHtracePluginEndTime_ != 0) { + return asyncHtracePluginEndTime_; + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/parser/htrace_plugin_time_parser.h b/trace_streamer/sdk/dubai_sdk/parser/htrace_plugin_time_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..6ac4d2f2d3668f301d6089a3952c90066524737a --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/parser/htrace_plugin_time_parser.h @@ -0,0 +1,52 @@ +/* + * 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 HTRACE_PLUGIN_TIME_PARSER_H +#define HTRACE_PLUGIN_TIME_PARSER_H +#include "clock_filter.h" +#include "event_parser_base.h" +#include "trace_data/trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtracePluginTimeParser : public EventParserBase { +public: + HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + HtracePluginTimeParser(const HtracePluginTimeParser&) = delete; + HtracePluginTimeParser& operator=(const HtracePluginTimeParser&) = delete; + ~HtracePluginTimeParser() = default; + void UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp); + uint64_t GetPluginStartTime(); + uint64_t GetPluginEndTime(); + uint64_t MinTs() const + { + return minTs_; + } + uint64_t MaxTs() const + { + return maxTs_; + } + +private: + uint64_t syncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t syncHtracePluginEndTime_ = 0; + uint64_t asyncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t asyncHtracePluginEndTime_ = 0; + uint64_t minTs_ = std::numeric_limits::max(); + uint64_t maxTs_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PLUGIN_TIME_PARSER_H diff --git a/trace_streamer/sdk/dubai_sdk/plugin/BUILD.gn b/trace_streamer/sdk/dubai_sdk/plugin/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..415be52063943441ddbd8bb38b4593cfecc4241c --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/plugin/BUILD.gn @@ -0,0 +1,36 @@ +# 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") +OHOS_PROTO_GEN = "//third_party/protogen" +ohos_source_set("sdk_plugin") { + subsystem_name = "trace_streamer" + part_name = "sdk_plugin" + sources = [ + "sdk_plugin_data_parser.cpp", + "sdk_plugin_data_parser.h", + ] + include_dirs = [ + "base", + "..", + "../include", + "../filter", + "../trace_data", + "../base", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "//third_party/protobuf/src", + ] + + public_deps = [] +} diff --git a/trace_streamer/sdk/dubai_sdk/plugin/sdk_plugin_data_parser.cpp b/trace_streamer/sdk/dubai_sdk/plugin/sdk_plugin_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d94d31c6dd781f757856e5a32e38d35c628b165 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/plugin/sdk_plugin_data_parser.cpp @@ -0,0 +1,88 @@ +/* + * 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 "sdk_plugin_data_parser.h" +#include +#include "sdk/ts_sdk_api.h" + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +void sdk_plugin_init_table_name() +{ + SDK_SetTableName("counter_table", + "gpu_counter_object", + "slice_table", + "slice_object_table"); +} +int32_t sdk_plugin_data_parser(const uint8_t* data, int32_t len) +{ + std::unique_ptr buf = std::make_unique(len); + std::copy(data, data + len, buf.get()); + MockDataArr mockDataArr; + mockDataArr.ParseFromArray(buf.get(), len); + int32_t size = mockDataArr.mockdata_size(); + if (size > 1) { + for (auto m = 0; m < size; m++) { + auto mockData = mockDataArr.mockdata().at(m); + sdk_plugin_parser(data, len, mockData); + } + } else { + MockData mockData; + mockData.ParseFromArray(buf.get(), len); + sdk_plugin_parser(data, len, mockData); + } + return 0; +} + +int32_t sdk_plugin_parser(const uint8_t* data, int32_t len, MockData mockData) +{ + // parsercounterObject + for (auto i = 0; i < mockData.counterobj_size(); i++) { + int32_t counterId = mockData.counterobj(i).id(); + std::string counterName = mockData.counterobj(i).name(); + SDK_AppendCounterObject(counterId, counterName.c_str()); + } + + // parsercounterInfo + for (auto i = 0; i < mockData.counterinfo_size(); i++) { + CounterInfo counterInfo; + counterInfo = mockData.counterinfo(i); + SDK_AppendCounter(counterInfo.key(), counterInfo.ts(), (double)counterInfo.value()); + } + + // parserSliceObj + for (auto i = 0; i < mockData.sliceobj_size(); i++) { + int32_t sliceId = mockData.sliceobj(i).id(); + std::string sliceName = mockData.sliceobj(i).name(); + SDK_AppendSliceObject(sliceId, sliceName.c_str()); + } + + // parserSliceInfo + for (auto i = 0; i < mockData.sliceinfo_size(); i++) { + int32_t sliceKey = mockData.sliceinfo(i).id(); + double sliceValue = mockData.sliceinfo(i).value(); + uint64_t startTime = mockData.sliceinfo(i).start_time(); + uint64_t endTime = mockData.sliceinfo(i).end_time(); + std::string start_time = mockData.sliceinfo(i).starting_time(); + TS_LOGI("start_time=%s", start_time.c_str()); + std::string end_time = mockData.sliceinfo(i).ending_time(); + TS_LOGI("end_time=%s", end_time.c_str()); + SDK_AppendSlice(sliceKey, startTime, endTime, start_time, end_time, sliceValue); + } + return 0; +} +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/plugin/sdk_plugin_data_parser.h b/trace_streamer/sdk/dubai_sdk/plugin/sdk_plugin_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..7acff69fc1eeaa92c3d74893cf75b4f41ad4fb8d --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/plugin/sdk_plugin_data_parser.h @@ -0,0 +1,31 @@ +/* + * 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 SDK_PLUGIN_DATA_PARSER_H +#define SDK_PLUGIN_DATA_PARSER_H + +#include +#include "mock_plugin_result.pb.h" + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +// set table name +void sdk_plugin_init_table_name(); +int32_t sdk_plugin_parser(const uint8_t* data, int32_t len, MockData mockData); +int32_t sdk_plugin_data_parser(const uint8_t* data, int32_t len); +} +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/protos/BUILD.gn b/trace_streamer/sdk/dubai_sdk/protos/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..0916cd9b338379bc7a3a56b1ce6e8164b66c958f --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/BUILD.gn @@ -0,0 +1,49 @@ +# 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") +OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR = "//third_party/protobuf" +proto_dir = "//third_party/protogen" +mock_dir = "$proto_dir/types/plugins/mock_data" +config("ts_proto_include_config") { + include_dirs = [] +} +source_set("ts_proto_data_cpp") { + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + cflags = [ + "-ftrapv", + "-D_FORTIFY_SOURCE=2 -O2", + "-Wno-zero-length-array", + "-std=c++17", + ] + + if (!is_win) { + print("xxx") + cflags += [ + "-fPIE", + "-fPIC", + ] + } + if (!use_wasm) { + cflags += [ + "-fstack-protector-strong", # + "-fstack-protector-all", + ] + } + + public_configs = [ ":ts_proto_include_config" ] + sources = [ "${mock_dir}/mock_plugin_result.pb.cc" ] +} diff --git a/trace_streamer/sdk/dubai_sdk/protos/README_zh.md b/trace_streamer/sdk/dubai_sdk/protos/README_zh.md new file mode 100755 index 0000000000000000000000000000000000000000..6e49694e23aafe5dcfd18c921519b3f5edda1911 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/README_zh.md @@ -0,0 +1,10 @@ +# protos 代码仓 + + + +`services` 目录下存放的是 服务接口定义, + +`types` 目录下存放的是 具体插件业务相关的类型定义,主要为配置类型和结果类型定义。 + +例如,`types/plugins/cpu_data/` 目录存放CPU数据插件的配置类型和结果类型。 + diff --git a/trace_streamer/sdk/dubai_sdk/protos/protogen.sh b/trace_streamer/sdk/dubai_sdk/protos/protogen.sh new file mode 100755 index 0000000000000000000000000000000000000000..501ed338c703b00308b1fd681c5745168ed05c02 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/protogen.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# 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. +set -e +SOURCE="${BASH_SOURCE[0]}" +cd $(dirname ${SOURCE}) +echo "begin to generate proto based files" +SOURCE=$(dirname ${SOURCE}) +proto_dir="." +services_dir="$proto_dir/services" +# kernel_version="5.10.79_aarch64" +kernel_version="." +mock_data_dir="$proto_dir/types/plugins/mock_data" +proto_array=("$mock_data_dir/mock_plugin_result.proto") + +export LD_LIBRARY_PATH=../../../out/linux +for ((i = 0; i < ${#proto_array[@]}; i ++)) +do + newpath=$(dirname ${proto_array[$i]}) + newpath=${newpath:2} + cppout=../../../third_party/protogen/$newpath + mkdir -p $cppout + ../../../out/linux/protoc --proto_path=$mock_data_dir --cpp_out=$cppout ${proto_array[$i]} +done +echo "generate proto based files over" diff --git a/trace_streamer/sdk/dubai_sdk/protos/protos.gni b/trace_streamer/sdk/dubai_sdk/protos/protos.gni new file mode 100755 index 0000000000000000000000000000000000000000..f8582402a8b542f4435fdeda2e18278b1bd725e7 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/protos.gni @@ -0,0 +1,36 @@ +# 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/config.gni") + +subsys_name = OHOS_PROFILER_SUBSYS_NAME +part_name = OHOS_PROFILER_PART_NAME +subsys_x64_out = "clang_x64/$subsys_name/$part_name" +libc_dir_proto = rebase_path("$asdk_libs_dir", "//") +root_output_dir_proto = rebase_path("$root_out_dir", "//") + +#host:clang_x64 default:arm mingw:mingw_x86_64 +if (current_toolchain != host_toolchain) { + if (current_toolchain == default_toolchain) { + root_output_dir_proto = "$root_output_dir_proto/clang_x64" + } else { + root_output_dir_proto = + get_path_info("$root_output_dir_proto", "dir") + "/clang_x64" + } +} +protoc = root_output_dir_proto +print("default_toolchain = ", default_toolchain) +print("current_toolchain = ", current_toolchain) +print("host_toolchain = ", host_toolchain) +print("root_out_dir = ", root_out_dir) +print("root_output_dir_proto = ", root_output_dir_proto) diff --git a/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_config.proto b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..fbe13025e00db2ec32b59aa30dc15f088ac922a4 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_config.proto @@ -0,0 +1,22 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message MockConfig { + uint32 version = 1; + string counters = 2; + bool stop_gator = 3; + uint32 duration = 1; +} diff --git a/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_config_standard.proto b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_config_standard.proto new file mode 100755 index 0000000000000000000000000000000000000000..8e62d2e991387156dd257d7ef840ccc452cc0434 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_config_standard.proto @@ -0,0 +1,19 @@ +// 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. +syntax = "proto3"; +package ForStandard; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +message MockConfig { + string msg = 1; +} diff --git a/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_result.proto b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..26f78b3bcc91603713789d7a41e9ad595abd36bb --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_result.proto @@ -0,0 +1,53 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message SliceObj { + int32 id = 1; + string name = 2; +} + +message SliceInfo { + int32 id = 1; + double value = 2; + uint64 start_time = 3; + uint64 end_time = 4; + string starting_time = 5; + string ending_time = 6; +} + +message CounterObj { + int32 id = 1; + string name = 2; +} + +message CounterInfo { + int32 key = 1; + int32 value = 2; + uint64 ts = 3; +} + +message MockData { + repeated CounterObj counterobj = 1; + repeated CounterInfo counterinfo = 2; + repeated SliceObj sliceobj = 3; + repeated SliceInfo sliceinfo = 4; +} + +message MockDataArr { + repeated MockData mockdata = 1; +} diff --git a/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_result_standard.proto b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_result_standard.proto new file mode 100755 index 0000000000000000000000000000000000000000..bebfd6b87f10d2616bc88ce5567dd838f3f8364e --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/protos/types/plugins/mock_data/mock_plugin_result_standard.proto @@ -0,0 +1,47 @@ +// 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. + +syntax = "proto3"; +package ForStandard; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +message SliceObj { + int32 id = 1; + string name = 2; +} + +message SliceInfo { + int32 id = 1; + int32 value = 2; + uint64 start_time = 3; + uint64 end_time = 4; +} + +message CounterObj { + int32 id = 1; + string name = 2; +} + +message CounterInfo { + int32 key = 1; + int32 value = 2; + uint64 ts = 3; +} + +message MockData { + repeated CounterObj counterobj = 1; + repeated CounterInfo counterinfo = 2; + repeated SliceObj sliceobj = 3; + repeated SliceInfo sliceinfo = 4; +} diff --git a/trace_streamer/sdk/dubai_sdk/rpc/http_server.cpp b/trace_streamer/sdk/dubai_sdk/rpc/http_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae4eca631b9153d4f9b39d2e1653d945b42e1534 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/rpc/http_server.cpp @@ -0,0 +1,381 @@ +/* + * 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 "http_server.h" +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include "log.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +void HttpServer::RegisterRpcFunction(RpcServer* rpc) +{ + rpcFunctions_.clear(); + + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + + auto parsedata = std::bind(&RpcServer::ParseData, rpc, _1, _2, _3); + rpcFunctions_["/parsedata"] = parsedata; + + auto parsedataover = std::bind(&RpcServer::ParseDataOver, rpc, _1, _2, _3); + rpcFunctions_["/parsedataover"] = parsedataover; + + auto sqlquery = std::bind(&RpcServer::SqlQuery, rpc, _1, _2, _3); + rpcFunctions_["/sqlquery"] = sqlquery; + + auto sqloperate = std::bind(&RpcServer::SqlOperate, rpc, _1, _2, _3); + rpcFunctions_["/sqloperate"] = sqloperate; + + auto reset = std::bind(&RpcServer::Reset, rpc, _1, _2, _3); + rpcFunctions_["/reset"] = reset; +} + +#ifdef _WIN32 +void HttpServer::Run(int32_t port) +{ + WSADATA ws{}; + if (WSAStartup(MAKEWORD(WS_VERSION_FIRST, WS_VERSION_SEC), &ws) != 0) { + return; + } + if (!CreateSocket(port)) { + return; + } + WSAEVENT events[COUNT_SOCKET]; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + if ((events[i] = WSACreateEvent()) == WSA_INVALID_EVENT) { + TS_LOGE("WSACreateEvent error %d", WSAGetLastError()); + return; + } + WSAEventSelect(sockets_[i].GetFd(), events[i], FD_ACCEPT | FD_CLOSE); + } + + while (!isExit_) { + ClearDeadClientThread(); + + int32_t index = WSAWaitForMultipleEvents(COUNT_SOCKET, events, false, pollTimeOut_, false); + if (index == WSA_WAIT_FAILED) { + TS_LOGE("WSAWaitForMultipleEvents error %d", WSAGetLastError()); + break; + } else if (index == WSA_WAIT_TIMEOUT) { + continue; + } + + index = index - WSA_WAIT_EVENT_0; + WSANETWORKEVENTS event; + WSAEnumNetworkEvents(sockets_[index].GetFd(), events[index], &event); + if (event.lNetworkEvents & FD_ACCEPT) { + if (event.iErrorCode[FD_ACCEPT_BIT] != 0) { + continue; + } + + std::unique_ptr client = std::make_unique(); + if (sockets_[index].Accept(client->sock_)) { + client->thread_ = std::thread(&HttpServer::ProcessClient, this, std::ref(client->sock_)); + clientThreads_.push_back(std::move(client)); + } else { + TS_LOGE("http socket accept error"); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + for (const auto& it : clientThreads_) { + if (it->thread_.joinable()) { + it->sock_.Close(); + it->thread_.join(); + } + } + clientThreads_.clear(); + + WSACleanup(); +} +#else +void HttpServer::Run(int32_t port) +{ + if (SIG_ERR == signal(SIGPIPE, SIG_IGN)) { + return; + } + + if (!CreateSocket(port)) { + return; + } + TS_LOGI("http server running"); + struct pollfd fds[COUNT_SOCKET]; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + fds[i] = {sockets_[i].GetFd(), POLLIN, 0}; + } + while (!isExit_) { + ClearDeadClientThread(); + if (poll(fds, sizeof(fds) / sizeof(pollfd), pollTimeOut_) <= 0) { + continue; // try again + } + + for (int32_t i = 0; i < 1; i++) { + if (fds[i].revents != POLLIN) { + continue; + } + std::unique_ptr client = std::make_unique(); + if (sockets_[i].Accept(client->sock_)) { + client->thread_ = std::thread(&HttpServer::ProcessClient, this, std::ref(client->sock_)); + clientThreads_.push_back(std::move(client)); + } else { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + for (const auto& it : clientThreads_) { + if (it->thread_.joinable()) { + it->sock_.Close(); + it->thread_.join(); + } + } + clientThreads_.clear(); + + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + sockets_[i].Close(); + } + TS_LOGI("http server exit"); +} +#endif + +void HttpServer::Exit() +{ + isExit_ = true; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + sockets_[i].Close(); + } +} + +bool HttpServer::CreateSocket(int32_t port) +{ + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + if (!sockets_[i].CreateSocket(i == 0 ? AF_INET : AF_INET6)) { + TS_LOGE("Create http socket error"); + return false; + } + if (!sockets_[i].Bind(port)) { + TS_LOGE("bind http socket error"); + return false; + } + if (!sockets_[i].Listen(SOMAXCONN)) { + TS_LOGE("listen http socket error"); + return false; + } + } + + return true; +} + +void HttpServer::ClearDeadClientThread() +{ + for (const auto it = clientThreads_.begin(); it != clientThreads_.end();) { + if (it->get()->sock_.GetFd() != -1) { + it++; + continue; + } + if (it->get()->thread_.joinable()) { + it->get()->thread_.join(); + } + it = clientThreads_.erase(it); + } +} + +#ifdef _WIN32 +void HttpServer::ProcessClient(HttpSocket& client) +{ + std::vector recvBuf(MAXLEN_REQUEST); + size_t recvLen = recvBuf.size(); + size_t recvPos = 0; + RequestST reqST; + WSAEVENT recvEvent = WSACreateEvent(); + if (recvEvent == WSA_INVALID_EVENT) { + TS_LOGE("WSACreateEvent error %d", WSAGetLastError()); + return; + } + WSAEventSelect(client.GetFd(), recvEvent, FD_READ | FD_CLOSE); + while (!isExit_) { + int32_t index = WSAWaitForMultipleEvents(1, &recvEvent, false, pollTimeOut_, false); + if (index == WSA_WAIT_FAILED) { + TS_LOGE("WSAWaitForMultipleEvents error %d", WSAGetLastError()); + break; + } else if (index == WSA_WAIT_TIMEOUT) { + if (reqST.stat != RequstParseStat::INIT) { + reqST.stat = RequstParseStat::INIT; + recvPos = 0; + recvLen = recvBuf.size(); + } + continue; + } + + WSANETWORKEVENTS event; + WSAEnumNetworkEvents(client.GetFd(), recvEvent, &event); + if (event.lNetworkEvents & FD_READ) { + if (event.iErrorCode[FD_READ_BIT] != 0) { + continue; + } + if (!client.Recv(recvBuf.data() + recvPos, recvLen)) { + break; + } + recvPos += recvLen; + ParseRequest(recvBuf.data(), recvPos, reqST); + recvLen = recvBuf.size() - recvPos; + if (reqST.stat == RequstParseStat::RECVING) { + continue; + } + reqST.stat = RequstParseStat::INIT; + } else if (event.lNetworkEvents & FD_CLOSE) { + TS_LOGI("client close socket(%d)", client.GetFd()); + break; + } + } + TS_LOGI("recive client thread exit. socket(%d)", client.GetFd()); + + client.Close(); +} +#else +void HttpServer::ProcessClient(HttpSocket& client) +{ + std::vector recvBuf(MAXLEN_REQUEST); + size_t recvLen = recvBuf.size(); + size_t recvPos = 0; + RequestST reqST; + + struct pollfd fd = {client.GetFd(), POLLIN, 0}; + while (!isExit_) { + int32_t pollRet = poll(&fd, sizeof(fd) / sizeof(pollfd), pollTimeOut_); + if (pollRet < 0) { + TS_LOGE("poll client socket(%d) error: %d:%s", client.GetFd(), errno, strerror(errno)); + break; + } + if (pollRet == 0) { + if (reqST.stat != RequstParseStat::INIT) { + reqST.stat = RequstParseStat::INIT; + recvPos = 0; + recvLen = recvBuf.size(); + } + continue; + } + if (!client.Recv(recvBuf.data() + recvPos, recvLen)) { + TS_LOGI("client exit"); + break; + } + recvPos += recvLen; + ParseRequest(recvBuf.data(), recvPos, reqST); + recvLen = recvBuf.size() - recvPos; + if (reqST.stat == RequstParseStat::RECVING) { + continue; + } + reqST.stat = RequstParseStat::INIT; + } + TS_LOGI("recive client thread exit. socket(%d)", client.GetFd()); + + client.Close(); + TS_LOGI("thread exit"); +} +#endif + +void HttpServer::ParseRequest(const uint8_t* requst, size_t& len, RequestST& httpReq) +{ + std::string_view reqStr(reinterpret_cast(requst), len); + size_t bodyPos = reqStr.find("\r\n\r\n"); + if (bodyPos == 0) { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } else if (bodyPos == std::string_view::npos) { + httpReq.stat = RequstParseStat::RECVING; + return; + } + std::string_view header = reqStr.substr(0, bodyPos); + bodyPos += strlen("\r\n\r\n"); + httpReq.bodyLen = reqStr.size() - bodyPos; + + std::vector headerlines = StringSplit(header, "\r\n"); + // at least 1 line in headerlines, such as "GET /parsedata HTTP/1.1" + std::vector requestItems = StringSplit(headerlines[0], " "); + const size_t indexHttpMethod = 0; + const size_t indexHttpUri = 1; + const size_t indexHttpVersion = 2; + const size_t countRequestItems = 3; + if (requestItems.size() != countRequestItems || requestItems[indexHttpVersion] != "HTTP/1.1") { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } + httpReq.method = requestItems[indexHttpMethod]; + httpReq.uri = requestItems[indexHttpUri]; + + for (size_t i = 1; i < headerlines.size(); i++) { + size_t tagPos = headerlines[i].find(":"); + if (tagPos == std::string_view::npos) { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } + std::string_view tag = headerlines[i].substr(0, tagPos); + if (strncasecmp(tag.data(), "Content-Length", tag.size()) == 0) { + std::string value(headerlines[i].data() + tagPos + strlen(":"), + headerlines[i].size() - tagPos - strlen(":")); + size_t conterntLen = atoi(value.c_str()); + if (conterntLen > httpReq.bodyLen) { + httpReq.stat = RequstParseStat::RECVING; + return; + } else if (conterntLen < httpReq.bodyLen) { + httpReq.bodyLen = conterntLen; + } + } + } + + if (httpReq.bodyLen > 0) { + httpReq.body = (requst + bodyPos); + } + httpReq.stat = RequstParseStat::OK; + len -= (bodyPos + httpReq.bodyLen); + return; +} + +std::vector HttpServer::StringSplit(std::string_view source, std::string_view split) +{ + std::vector result; + if (!split.empty()) { + size_t pos = 0; + while ((pos = source.find(split)) != std::string_view::npos) { + // split + std::string_view token = source.substr(0, pos); + if (!token.empty()) { + result.push_back(token); + } + source = source.substr(pos + split.size(), source.size() - token.size() - split.size()); + } + } + // add last token + if (!source.empty()) { + result.push_back(source); + } + return result; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/rpc/http_server.h b/trace_streamer/sdk/dubai_sdk/rpc/http_server.h new file mode 100644 index 0000000000000000000000000000000000000000..ae28977febd74eb4915a8fda7e3fa71e6e9167fa --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/rpc/http_server.h @@ -0,0 +1,79 @@ +/* + * 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 RPC_HTTPD_H +#define RPC_HTTPD_H + +#include +#include +#include +#include +#include +#include "http_socket.h" +#include "rpc_server.h" +namespace SysTuning { +namespace TraceStreamer { +class HttpServer { +public: + void RegisterRpcFunction(RpcServer* rpc); + void Run(int32_t port = 9001); + void Exit(); + + static constexpr size_t MAXLEN_REQUEST = 2 * 1024 + 1024 * 1024; // header 2K + body 1M + +private: + struct ClientThread { + HttpSocket sock_; + std::thread thread_; + }; + + enum RequstParseStat { + INIT = 0, + OK, + BAD, + RECVING + }; + + struct RequestST { + int32_t stat = RequstParseStat::INIT; + std::string method; + std::string uri; + const uint8_t* body; + size_t bodyLen; + }; + + bool CreateSocket(int32_t port); + void ProcessClient(HttpSocket& client); + static void ProcessRequest(HttpSocket& client, RequestST& request); + static void ParseRequest(const uint8_t* requst, size_t& len, RequestST& httpReq); + void ClearDeadClientThread(); + static std::vector StringSplit(std::string_view source, std::string_view split); + + static const int32_t COUNT_SOCKET = 1; + HttpSocket sockets_[COUNT_SOCKET]; // ipv4 and ipv6 + std::atomic_bool isExit_ = {false}; + std::vector> clientThreads_; + using RpcFunction = std::function; + std::map rpcFunctions_; + const int32_t pollTimeOut_ = 1000; +#ifdef _WIN32 + const uint32_t WS_VERSION_FIRST = 2; + const uint32_t WS_VERSION_SEC = 2; +#endif +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // RPC_HTTPD_H diff --git a/trace_streamer/sdk/dubai_sdk/rpc/http_socket.cpp b/trace_streamer/sdk/dubai_sdk/rpc/http_socket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5f5429151d40000a6cef48673235ae5d1a5a749 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/rpc/http_socket.cpp @@ -0,0 +1,173 @@ +/* + * 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 "http_socket.h" +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +HttpSocket::~HttpSocket() +{ + Close(); +} +bool HttpSocket::CreateSocket(int32_t domain) +{ + SOCKET sockId = socket(domain, SOCK_STREAM, 0); + if (sockId == INVALID_SOCKET) { + TS_LOGE("CreateSocket socket error, domain %d: %d:%s", domain, errno, strerror(errno)); + return false; + } + sockId_ = sockId; + if (domain == AF_INET || domain == AF_INET6) { + int32_t enable = 1; + if (setsockopt(sockId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), + sizeof(enable)) == SOCKET_ERROR) { + Close(); + return false; + } + if (domain == AF_INET6) { + if (setsockopt(sockId, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&enable), + sizeof(enable)) == SOCKET_ERROR) { + Close(); + return false; + } + } + } + domain_ = domain; + TS_LOGI("CreateSocket socket ok, socket %d domain %d", sockId_, domain); + return true; +} + +bool HttpSocket::Bind(int32_t port) +{ + if (sockId_ == INVALID_SOCKET) { + TS_LOGE("the socket not created"); + return false; + } + + if (domain_ == AF_INET) { + struct sockaddr_in addr; + std::fill(reinterpret_cast(&addr), reinterpret_cast(&addr) + sizeof(addr), 0); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htons(INADDR_ANY); + addr.sin_port = htons(static_cast(port)); + if (bind(sockId_, reinterpret_cast(&addr), sizeof(addr)) == -1) { + TS_LOGE("bind ipv4 socket error, port %d: %d:%s", port, errno, strerror(errno)); + return false; + } + } else if (domain_ == AF_INET6) { + struct sockaddr_in6 addr; + std::fill(reinterpret_cast(&addr), reinterpret_cast(&addr) + sizeof(addr), 0); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons(static_cast(port)); + if (bind(sockId_, reinterpret_cast(&addr), sizeof(addr)) == -1) { + TS_LOGE("bind ipv6 socket error, port %d: %d:%s", port, errno, strerror(errno)); + return false; + } + } else { + return false; + } + TS_LOGI("bind socket ok, port %d", port); + return true; +} + +bool HttpSocket::Listen(int32_t maxConn) +{ + if (listen(sockId_, maxConn) == SOCKET_ERROR) { + TS_LOGE("listen socket error: %d:%s", errno, strerror(errno)); + return false; + } + TS_LOGI("listen socket ok, maxConn %d", maxConn); + return true; +} + +bool HttpSocket::Accept(HttpSocket& client) +{ + int32_t clientId = accept(sockId_, nullptr, nullptr); + if (clientId == INVALID_SOCKET) { + TS_LOGE("accept socket error: %d:%s", errno, strerror(errno)); + return false; + } + + client.domain_ = domain_; + client.sockId_ = clientId; + TS_LOGI("accept client socket id %d domain %d", clientId, domain_); + return true; +} + +bool HttpSocket::Recv(void* data, size_t& len) +{ +#ifdef _WIN32 + ssize_t recvLen = recv(sockId_, static_cast(data), len, 0); +#else + ssize_t recvLen = recv(sockId_, data, len, 0); +#endif + if (recvLen == SOCKET_ERROR) { + if (errno == EAGAIN) { + recvLen = 0; + } else { + TS_LOGE("recv from socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + return false; + } + } else if (recvLen == 0) { + TS_LOGI("client socket(%d) closed", sockId_); + return false; + } + len = recvLen; + TS_LOGD("Recv from socket(%d) len %zu", sockId_, len); + return true; +} + +bool HttpSocket::Send(const void* data, size_t len) +{ +#ifdef _WIN32 + ssize_t sendLen = send(sockId_, static_cast(data), len, 0); +#else + ssize_t sendLen = send(sockId_, data, len, 0); +#endif + if (sendLen == SOCKET_ERROR) { + TS_LOGE("send to socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + return false; + } + TS_LOGI("send to socket(%d) len %zu", sockId_, len); + return true; +} + +void HttpSocket::Close() +{ + if (sockId_ == INVALID_SOCKET) { + return; + } + TS_LOGI("close socket(%d)", sockId_); +#ifdef _WIN32 + if (closesocket(sockId_) == SOCKET_ERROR) { +#else + if (close(sockId_) == SOCKET_ERROR) { +#endif + TS_LOGE("close socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + } + sockId_ = INVALID_SOCKET; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/rpc/http_socket.h b/trace_streamer/sdk/dubai_sdk/rpc/http_socket.h new file mode 100644 index 0000000000000000000000000000000000000000..39bf9849c368309b90aec74919d83293acb416d0 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/rpc/http_socket.h @@ -0,0 +1,53 @@ +/* + * 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 RPC_HTTPSOCKET_H +#define RPC_HTTPSOCKET_H + +#include +namespace SysTuning { +namespace TraceStreamer { +class HttpSocket { +public: + HttpSocket() {} + HttpSocket(int32_t sockId, int32_t domain) : sockId_(sockId), domain_(domain) {} + ~HttpSocket(); + + bool CreateSocket(int32_t domain); + bool Bind(int32_t port); + bool Listen(int32_t maxConn); + bool Accept(HttpSocket& client); + bool Recv(void* data, size_t& len); + bool Send(const void* data, size_t len); + void Close(); + bool IsValid() const + { + return sockId_ != INVALID_SOCKET; + } + int32_t GetFd() const + { + return sockId_; + } + +private: + int32_t sockId_ = -1; + int32_t domain_ = 0; + using SOCKET = int32_t; + const int32_t SOCKET_ERROR = -1; + const SOCKET INVALID_SOCKET = -1; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RPC_HTTPSOCKET_H diff --git a/trace_streamer/sdk/dubai_sdk/rpc/rpc_server.cpp b/trace_streamer/sdk/dubai_sdk/rpc/rpc_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..672d36bd5c3d131d26f134e9a8eb9bd02bdebd1f --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/rpc/rpc_server.cpp @@ -0,0 +1,111 @@ +/* + * 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 "rpc_server.h" + +#include +#include +#include + +#include "log.h" +#include "meta.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +namespace SysTuning { +namespace TraceStreamer { + +bool RpcServer::SqlOperate(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("RPC SqlOperate(%s, %zu)", sql.c_str(), len); + + int32_t ret = ts_->OperateDatabase(sql); + if (resultCallBack) { + std::string response = "ok\r\n"; + if (ret != 0) { + response = "dberror\r\n"; + } + resultCallBack(response, SEND_FINISH, 0); + } + return (ret == 0); +} + +bool RpcServer::SqlQuery(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("RPC SqlQuery %zu:%s", len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, resultCallBack); + if (resultCallBack && ret != 0) { + resultCallBack("dberror\r\n", SEND_FINISH, 0); + } + ts_->SetCancel(false); + return (ret == 0); +} + +void RpcServer::CancelSqlQuery() +{ + ts_->SetCancel(true); +} + +bool RpcServer::Reset(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + UNUSED(data); + UNUSED(len); + TS_LOGI("RPC reset trace_streamer"); + + ts_->WaitForParserEnd(); + ts_ = std::make_unique(); + if (resultCallBack) { + resultCallBack("ok\r\n", SEND_FINISH, 0); + } + return true; +} + +int32_t RpcServer::WasmSqlQuery(const uint8_t* data, size_t len, uint8_t* out, int32_t outLen) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("WASM RPC SqlQuery outlen(%d) sql(%zu:%s)", outLen, len, sql.c_str()); + int32_t ret = ts_->SearchDatabase(sql, out, outLen); + return ret; +} + +int32_t RpcServer::WasmGetPluginNameWithCallback(const uint8_t* data, size_t len) const +{ + std::string pluginName(reinterpret_cast(data), len); + TS_LOGI("WASM pluginName(%zu:%s)", len, pluginName.c_str()); + + int32_t ret = ts_->sdkDataParser_->GetPluginName(pluginName); + return ret; +} + +int32_t RpcServer::WasmSqlQueryWithCallback(const uint8_t* data, size_t len, ResultCallBack callback) const +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("WASM RPC SqlQuery sql(%zu:%s)", len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, callback); + return ret; +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/rpc/rpc_server.h b/trace_streamer/sdk/dubai_sdk/rpc/rpc_server.h new file mode 100644 index 0000000000000000000000000000000000000000..191cbde2262dc0c6b52c510ea277f58a02aa6ab1 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/rpc/rpc_server.h @@ -0,0 +1,45 @@ +/* + * 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 RPC_RPC_H +#define RPC_RPC_H + +#include +#include +#include "../trace_streamer/trace_streamer_selector.h" +#include "../sdk/sdk_data_parser.h" +namespace SysTuning { +namespace TraceStreamer { +class RpcServer { +public: + using ResultCallBack = std::function; + using TraceRangeCallbackFunction = std::function; + // In order to bind HTTP, maintain a unified interface, even if some parameters are useless + bool SqlOperate(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool SqlQuery(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool Reset(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + void CancelSqlQuery(); + + // only for wasm, no callback + int32_t WasmSqlQuery(const uint8_t* data, size_t len, uint8_t* out, int32_t outLen); + int32_t WasmSqlQueryWithCallback(const uint8_t* data, size_t len, ResultCallBack callback) const; + int32_t WasmGetPluginNameWithCallback(const uint8_t* data, size_t len) const; + +public: + std::unique_ptr ts_ = std::make_unique(); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RPC_RPC_H diff --git a/trace_streamer/sdk/dubai_sdk/sdk/sdk_data_parser.cpp b/trace_streamer/sdk/dubai_sdk/sdk/sdk_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5a3b1ae65224ded231687e0cee722a5bbf99e9f --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/sdk_data_parser.cpp @@ -0,0 +1,210 @@ +/* + * 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 "sdk_data_parser.h" +#include +#include +#include +#include +#include "clock_filter.h" +#include "gpu_counter_object_table.h" +#include "gpu_counter_table.h" +#include "json.hpp" +#include "log.h" +#include "meta.h" +#include "meta_table.h" +#include "sdk_plugin_data_parser.h" +#include "slice_object_table.h" +#include "slice_table.h" +#include "ts_common.h" +#include "ts_sdk_api.h" + + +namespace SysTuning { +namespace TraceStreamer { +SDKDataParser::SDKDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +int32_t SDKDataParser::GetPluginName(std::string pluginName) +{ + pluginName.replace(pluginName.find("-"), 1, "_"); + counterTableName_ = pluginName + "_" + "counter_table"; + counterObjectTableName_ = pluginName + "_" + "counterobj_table"; + sliceTableName_ = pluginName + "_" + "slice_table"; + sliceObjectName_ = pluginName + "_" + "sliceobj_table"; + return 0; +} +int32_t SDKDataParser::ParseDataOver(TraceRangeCallbackFunction traceRangeCallbackFunction) +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + std::string traceRangeStr = + std::to_string(traceDataCache_->traceStartTime_) + ";" + std::to_string(traceDataCache_->traceEndTime_) + ";"; + traceRangeCallbackFunction(traceRangeStr); + return 0; +} + +int32_t SDKDataParser::GetJsonConfig(QueryResultCallbackFunction queryResultCallbackFunction) +{ + queryResultCallbackFunction(jsonConfig_, 1, 1); + return 0; +} + +int32_t SDKDataParser::ParserData(const uint8_t* data, int32_t len, int32_t componentId) +{ + if (componentId == DATA_TYPE_CLOCK) { + ParserClock(data, len); + return 0; + } + sdk_plugin_data_parser(data, len); + return 0; +} + +int32_t SDKDataParser::ParserClock(const uint8_t* data, int32_t len) +{ + return streamFilters_->clockFilter_->InitSnapShotTimeRange(data, len); +} + +int32_t SDKDataParser::SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName) +{ + if (!g_isUseExternalModify) { + counterTableName_ = counterTableName; + counterObjectTableName_ = counterObjectTableName; + sliceTableName_ = sliceTableName; + sliceObjectName_ = sliceObjectName; + } + UpdateJson(); + return 0; +} + +int32_t SDKDataParser::UpdateJson() +{ + using json = nlohmann::json; + json jMessage = json::parse(jsonConfig_); + if (jMessage.is_discarded()) { + return -1; + } + + jMessage["tableConfig"]["showType"][0]["tableName"] = counterTableName_; + jMessage["tableConfig"]["showType"][0]["inner"]["tableName"] = counterObjectTableName_; + jMessage["tableConfig"]["showType"][1]["tableName"] = sliceTableName_; + jMessage["tableConfig"]["showType"][1]["inner"]["tableName"] = sliceObjectName_; + + jsonConfig_ = jMessage.dump(); + return 0; +} + +// create a corresponding table +int32_t SDKDataParser::CreateTableByJson() +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "meta"); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_meta"); +#endif + // create a corresponding table + CreateCounterObjectTable(counterObjectTableName_); + CreateCounterTable(counterTableName_); + CreateSliceObjectTable(sliceObjectName_); + CreateSliceTable(sliceTableName_); + return 0; +} + +// create a couter object table based on the JSON configuration +int32_t SDKDataParser::CreateCounterObjectTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// Create a couter table based on the JSON configuration +int32_t SDKDataParser::CreateCounterTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// Create a slice object table based on the JSON configuration +int32_t SDKDataParser::CreateSliceObjectTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// Create a slice table based on the JSON configuration +int32_t SDKDataParser::CreateSliceTable(const std::string& tableName) +{ +#ifdef USE_VTABLE + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, tableName); +#else + TableBase::TableDeclare(*(traceDataCache_->db_), traceDataCache_, "_" + tableName); +#endif + return 0; +} + +// Counter business +int32_t SDKDataParser::AppendCounterObject(int32_t counterId, const char* columnName) +{ + traceDataCache_->GetGpuCounterObjectData()->AppendNewData(counterId, columnName); + return 0; +} + +int32_t SDKDataParser::AppendCounter(int32_t counterId, uint64_t ts, double value) +{ + auto newTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, ts, newTs); + traceDataCache_->GetGpuCounterData()->AppendNewData(newTs, counterId, value); + return 0; +} + +// Slice business +int32_t SDKDataParser::AppendSliceObject(int32_t sliceId, const char* columnName) +{ + traceDataCache_->GetSliceObjectData()->AppendNewData(sliceId, columnName); + return 0; +} + +int32_t SDKDataParser::AppendSlice(int32_t sliceId, + uint64_t ts, + uint64_t endTs, + std::string start_time, + std::string end_time, + double value) +{ + auto newTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + auto newEndTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, endTs); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, ts, newTs); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, endTs, newEndTs); + traceDataCache_->GetSliceTableData()->AppendNewData(sliceId, newTs, newEndTs, start_time, end_time, value); + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/sdk/sdk_data_parser.h b/trace_streamer/sdk/dubai_sdk/sdk/sdk_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..56c5b63f58225c911725662a6c94af3d54626853 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/sdk_data_parser.h @@ -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. + */ + +#ifndef SDK_DATA_PARSER_H +#define SDK_DATA_PARSER_H + +#include +#include +#include "file.h" +#include "../parser/htrace_plugin_time_parser.h" +#include "../table/table_base.h" +#include "../trace_streamer/trace_streamer_selector.h" + +namespace SysTuning { +namespace TraceStreamer { + +enum Third_Party_Wasm_Id { + DATA_TYPE_MOCK_PLUGIN = 0, + DATA_TYPE_CLOCK = 100, +}; +class SDKDataParser : public HtracePluginTimeParser { +public: + using TraceRangeCallbackFunction = std::function; + using QueryResultCallbackFunction = std::function; + SDKDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~SDKDataParser(){}; + + // third_party + int32_t CreateTableByJson(); + int32_t SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName); + int32_t GetJsonConfig(QueryResultCallbackFunction queryResultCallbackFunction); + int32_t GetPluginName(std::string pluginName); + int32_t GetPluginName(const uint8_t* data, int32_t len); + int32_t ParseDataOver(TraceRangeCallbackFunction traceRangeCallbackFunction); + int32_t ParserData(const uint8_t* data, int32_t len, int32_t componentId); + int32_t AppendCounterObject(int32_t counterId, const char* columnName); + int32_t AppendCounter(int32_t counterId, uint64_t ts, double value); + int32_t AppendSliceObject(int32_t sliceId, const char* columnName); + int32_t AppendSlice(int32_t sliceId, + uint64_t ts, + uint64_t endTs, + std::string start_time, + std::string end_time, + double value); + +private: + int32_t CreateCounterObjectTable(const std::string& tableName); + int32_t CreateCounterTable(const std::string& tableName); + int32_t CreateSliceObjectTable(const std::string& tableName); + int32_t CreateSliceTable(const std::string& tableName); + int32_t ParserClock(const uint8_t* data, int32_t len); + int32_t UpdateJson(); + +public: + std::string counterTableName_ = "counter_table"; + std::string counterObjectTableName_ = "gpu_counter_object"; + std::string sliceTableName_ = "slice_table"; + std::string sliceObjectName_ = "slice_object_table"; + std::string jsonConfig_ = + "{\"tableConfig\":{\"showType\":[{\"tableName\":\"counter_table\",\"inner\":{\"tableName\":\"gpu_counter_" + "object\"," + "\"columns\":[{\"column\":\"counter_name\",\"type\":\"STRING\",\"displayName\":\"\",\"showType\":[0]},{" + "\"column\":" + "\"counter_id\",\"type\":\"INTEGER\",\"displayName\":\"\",\"showType\":[0]}]},\"columns\":[{\"column\":\"ts\"," + "\"type\":\"INTEGER\",\"displayName\":\"TimeStamp\",\"showType\":[1,3]},{\"column\":\"counter_id\",\"type\":" + "\"INTEGER\",\"displayName\":\"MonitorValue\",\"showType\":[1,3]},{\"column\":\"value\",\"type\":\"INTEGER\"," + "\"displayName\":\"Value\",\"showType\":[1,3]}]},{\"tableName\":\"slice_table\",\"inner\":{\"tableName\":" + "\"slice_" + "object_table\",\"columns\":[{\"column\":\"slice_name\",\"type\":\"STRING\",\"displayName\":\"\",\"showType\":[" + "0]}," + "{\"column\":\"slice_id\",\"type\":\"INTEGER\",\"displayName\":\"\",\"showType\":[0]}]},\"columns\":[{" + "\"column\":" + "\"start_ts\",\"type\":\"INTEGER\",\"displayName\":\"startts\",\"showType\":[2,3]},{\"column\":\"end_ts\"," + "\"type\":" + "\"INTEGER\",\"displayName\":\"endts\",\"showType\":[2,3]},{\"column\":\"start\",\"type\":\"STRING\"," + "\"displayName\":\"start_time\",\"showType\":[2,3]},{\"column\":\"end\",\"type\":\"STRING\"," + "\"displayName\":\"end_time\",\"showType\":[2,3]},{\"column\":\"slice_id\",\"type\":\"INTEGER\"," + "\"displayName\":\"slice_id\",\"showType\":[2,3]},{\"column\":\"value\",\"type\":\"INTEGER\",\"displayName\":" + "\"Value\",\"showType\":[2,3]}]}]},\"settingConfig\":{\"name\":\"mailG77\",\"configuration\":{\"version\":{" + "\"type\":\"number\",\"default\":\"1\",\"description\":\"gatordversion\"},\"counters\":{\"type\":\"string\"," + "\"enum\":[\"ARM_Mali-TTRx_JS1_ACTIVE\",\"ARM_Mali-TTRx_JS0_ACTIVE\",\"ARM_Mali-TTRx_GPU_ACTIVE\",\"ARM_Mali-" + "TTRx_FRAG_ACTIVE\"]},\"stop_gator\":{\"type\":\"boolean\",\"default\":\"true\",\"description\":\"stop_gator\"}" + "}}}"; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SDK_DATA_PARSER_H diff --git a/trace_streamer/sdk/dubai_sdk/sdk/ts.gni b/trace_streamer/sdk/dubai_sdk/sdk/ts.gni new file mode 100755 index 0000000000000000000000000000000000000000..16279772850e6b180cc5c0b02a8945bfef54999b --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/ts.gni @@ -0,0 +1,61 @@ +# 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. +OHOS_PROTO_DIR = "" + +if (target_os == "linux" || target_os == "macx" || target_os == "windows") { + # OHOS_FTRACE_PROTO_DIR="//third_party/protogen" + OHOS_FTRACE_PROTO_DIR = "//src/multi_platform" + + # OHOS_MEMORY_PROTO_DIR="//third_party/protogen" + OHOS_MEMORY_PROTO_DIR = "//src/multi_platform" + + # OHOS_HILOG_PROTO_DIR="//third_party/protogen" + OHOS_HILOG_PROTO_DIR = "//src/multi_platform" + + # OHOS_NATIVE_HOOK_PROTO_DIR="//third_party/protogen" + OHOS_NATIVE_HOOK_PROTO_DIR = "//src/multi_platform" + + # OHOS_HIDUMP_PROTO_DIR="//third_party/protogen" + OHOS_HIDUMP_PROTO_DIR = "//src/multi_platform" + + # OHOS_SERVICE_PROTO_DIR = "//third_party/protogen" + OHOS_SERVICE_PROTO_DIR = "//src/multi_platform" + OHOS_PROTO_GEN = "//third_party/protogen" + + # kernel_version = "5.10.79_aarch64" + kernel_version = "." + if (target == "test") { + enable_ts_utest = true + } else { + enable_ts_utest = false + } + is_openharmony = false +} else { + enable_ts_utest = true + use_wasm = false + kernel_version = "." + is_fuzz = false + target = "trace_streamer" + is_openharmony = true + OHOS_FTRACE_PROTO_DIR = "//developtools/profiler/protos/types/plugins/ftrace_data/${kernel_version}" + OHOS_MEMORY_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/memory_data" + OHOS_HILOG_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hilog_data" + OHOS_NATIVE_HOOK_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/native_hook" + OHOS_HIDUMP_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hidump_data" + OHOS_SERVICE_PROTO_DIR = "//developtools/profiler/protos/services" + OHOS_PROTO_GEN = "//out/ohos-arm-release/gen/cpp/developtools/profiler/protos" +} diff --git a/trace_streamer/sdk/dubai_sdk/sdk/ts_sdk_api.cpp b/trace_streamer/sdk/dubai_sdk/sdk/ts_sdk_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..936632821d16bb52b5103da98f23370cf0ff0605 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/ts_sdk_api.cpp @@ -0,0 +1,61 @@ +/* + * 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 "ts_sdk_api.h" +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +RpcServer* rpcServer_; +bool g_isUseExternalModify = true; +int32_t SDK_SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName) +{ + rpcServer_->ts_->sdkDataParser_->SetTableName(counterTableName, counterObjectTableName, sliceTableName, + sliceObjectName); + if (g_isUseExternalModify) { + TS_LOGE("If you want to use the SDK_SetTableName, please modify g_isUseExternalModify to false."); + } + return 0; +} + +int32_t SDK_AppendCounterObject(int32_t counterId, const char* columnName) +{ + return rpcServer_->ts_->sdkDataParser_->AppendCounterObject(counterId, columnName); +} +int32_t SDK_AppendCounter(int32_t counterId, uint64_t ts, double value) +{ + return rpcServer_->ts_->sdkDataParser_->AppendCounter(counterId, ts, value); +} +int32_t SDK_AppendSliceObject(int32_t sliceId, const char* columnName) +{ + return rpcServer_->ts_->sdkDataParser_->AppendSliceObject(sliceId, columnName); +} +int32_t SDK_AppendSlice(int32_t sliceId, + uint64_t ts, + uint64_t endTs, + std::string start_time, + std::string end_time, + double value) +{ + return rpcServer_->ts_->sdkDataParser_->AppendSlice(sliceId, ts, endTs, start_time, end_time, value); +} +void SetRpcServer(RpcServer* rpcServer) +{ + rpcServer_ = std::move(rpcServer); +} +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/sdk/ts_sdk_api.h b/trace_streamer/sdk/dubai_sdk/sdk/ts_sdk_api.h new file mode 100644 index 0000000000000000000000000000000000000000..23f1734bae4f983f17cae0c655da17f00d2359c1 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/ts_sdk_api.h @@ -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. + */ +#ifndef TS_SDK_API_H +#define TS_SDK_API_H +#include "../rpc/rpc_server.h" + +#include +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +extern bool g_isUseExternalModify; +int32_t SDK_SetTableName(const char* counterTableName, + const char* counterObjectTableName, + const char* sliceTableName, + const char* sliceObjectName); +int32_t SDK_AppendCounterObject(int32_t counterId, const char* columnName); +int32_t SDK_AppendCounter(int32_t counterId, uint64_t ts, double value); +int32_t SDK_AppendSliceObject(int32_t sliceId, const char* columnName); +int32_t SDK_AppendSlice(int32_t sliceId, + uint64_t ts, + uint64_t endTs, + std::string start_time, + std::string end_time, + double value); +void SetRpcServer(RpcServer* rpcServer); +} +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/sdk/wasm_func.cpp b/trace_streamer/sdk/dubai_sdk/sdk/wasm_func.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5071455544a4cd7d47e2815e38b06ffad8a0b195 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/wasm_func.cpp @@ -0,0 +1,145 @@ +/* + * 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 "wasm_func.h" +#include +#include "meta.h" +#include "sdk_data_parser.h" +#include "sdk_plugin_data_parser.h" +#include "table_base.h" +#include "trace_stdtype.h" +#include "ts_sdk_api.h" + +namespace SysTuning { +namespace TraceStreamer { +RpcServer g_wasmTraceStreamer; + +extern "C" { +using QueryResultCallbackFunction = void (*)(const char* data, uint32_t len, int32_t finish, int32_t isConfig); +using TraceRangeCallbackFunction = void (*)(const char* data, uint32_t len); +QueryResultCallbackFunction g_reply; +TraceRangeCallbackFunction g_traceRange; +uint8_t* g_reqBuf; +uint32_t g_reqBufferSize; +uint8_t* g_traceRangeBuf; +uint32_t g_traceRangeSize; +uint8_t* g_PluginNameBuf; +uint32_t g_PluginNameSize; + +void QueryResultCallback(const std::string& jsonResult, int32_t finish, int32_t isConfig) +{ + g_reply(jsonResult.data(), jsonResult.size(), finish, isConfig); +} +void TraceRangeCallback(const std::string& jsonResult) +{ + g_traceRange(jsonResult.data(), jsonResult.size()); +} +EMSCRIPTEN_KEEPALIVE uint8_t* Init(QueryResultCallbackFunction queryResultCallbackFunction, uint32_t reqBufferSize) +{ + SetRpcServer(&g_wasmTraceStreamer); + sdk_plugin_init_table_name(); + g_wasmTraceStreamer.ts_->sdkDataParser_->CreateTableByJson(); + g_reply = queryResultCallbackFunction; + g_reqBuf = new uint8_t[reqBufferSize]; + g_reqBufferSize = reqBufferSize; + return g_reqBuf; +} + +// Get PluginName +EMSCRIPTEN_KEEPALIVE uint8_t* InitPluginName(uint32_t reqBufferSize) +{ + g_PluginNameBuf = new uint8_t[reqBufferSize]; + g_PluginNameSize = reqBufferSize; + return g_PluginNameBuf; +} + +// @deprecated recommand to use TraceStreamerGetPluginNameEx api +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_In_PluginName(const uint8_t* pluginName, int32_t len) +{ + std::string pluginNameStr(reinterpret_cast(pluginName), len); + g_wasmTraceStreamer.ts_->sdkDataParser_->GetPluginName(pluginNameStr); + return 0; +} + +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerGetPluginNameEx(int32_t pluginLen) +{ + return g_wasmTraceStreamer.WasmGetPluginNameWithCallback(g_PluginNameBuf, pluginLen); +} + + +EMSCRIPTEN_KEEPALIVE uint8_t* InitTraceRange(TraceRangeCallbackFunction traceRangeCallbackFunction, + uint32_t reqBufferSize) +{ + g_traceRange = traceRangeCallbackFunction; + g_traceRangeBuf = new uint8_t[reqBufferSize]; + g_traceRangeSize = reqBufferSize; + return g_traceRangeBuf; +} + +// The whole file is parsed, and the third party is notified by JS +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_In_ParseDataOver() +{ + MetaData* metaData = g_wasmTraceStreamer.ts_->GetMetaData(); + metaData->InitMetaData(); + metaData->SetParserToolVersion(SDK_VERSION); + metaData->SetParserToolPublishDateTime(SDK_PUBLISHVERSION); + g_wasmTraceStreamer.ts_->sdkDataParser_->ParseDataOver(&TraceRangeCallback); + return 0; +} + +// Get Json configuration interface +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_In_JsonConfig() +{ + g_wasmTraceStreamer.ts_->sdkDataParser_->GetJsonConfig(&QueryResultCallback); + return 0; +} + +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlOperate(const uint8_t* sql, int32_t sqlLen) +{ + if (g_wasmTraceStreamer.SqlOperate(sql, sqlLen, nullptr)) { + return 0; + } + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlOperateEx(int32_t sqlLen) +{ + if (g_wasmTraceStreamer.SqlOperate(g_reqBuf, sqlLen, nullptr)) { + return 0; + } + return -1; +} + +// JS calls third-party parsing interface +EMSCRIPTEN_KEEPALIVE int32_t ParserData(int32_t len, int32_t componentId) +{ + TS_LOGI("wasm ParserData, len = %u", len); + g_wasmTraceStreamer.ts_->sdkDataParser_->ParserData(g_reqBuf, len, componentId); + return 0; +} + +// return the length of result, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlQuery(const uint8_t* sql, int32_t sqlLen, uint8_t* out, int32_t outLen) +{ + return g_wasmTraceStreamer.WasmSqlQuery(sql, sqlLen, out, outLen); +} +// return the length of result, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlQueryEx(int32_t sqlLen) +{ + return g_wasmTraceStreamer.WasmSqlQueryWithCallback(g_reqBuf, sqlLen, &QueryResultCallback); +} + +} // extern "C" +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/sdk/wasm_func.h b/trace_streamer/sdk/dubai_sdk/sdk/wasm_func.h new file mode 100644 index 0000000000000000000000000000000000000000..109b12b3a72701b3efec6a708dc5425e0c8c0c73 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/sdk/wasm_func.h @@ -0,0 +1,35 @@ +/* + * 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 WASM_FUNC_H +#define WASM_FUNC_H + +#include +#include +#include +#include "rpc_server.h" +#include "../trace_streamer/trace_streamer_selector.h" + + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +int32_t TraceStreamerSqlOperate(const uint8_t* sql, int32_t sqlLen); +} + +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // RPC_WASM_FUNC_H diff --git a/trace_streamer/sdk/dubai_sdk/table/filter_constraints.cpp b/trace_streamer/sdk/dubai_sdk/table/filter_constraints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd79bce8c5f922d97914e2549f6b37ff7400cfb8 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/filter_constraints.cpp @@ -0,0 +1,132 @@ +/* + * 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 "filter_constraints.h" + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +void FilterConstraints::AddConstraint(int32_t idx, int32_t col, unsigned char op, bool isSupport) +{ + Constraint& c = constraints_.emplace_back(); + c.idxInaConstraint = idx; + c.col = col; + c.op = op; + c.isSupport = isSupport; +} + +void FilterConstraints::UpdateConstraint(int32_t idx, bool isSupport) +{ + if (idx >= 0 && static_cast(idx) < constraints_.size()) { + constraints_[idx].isSupport = isSupport; + } +} + +void FilterConstraints::AddOrderBy(int32_t col, unsigned char desc) +{ + OrderBy& o = orderBys_.emplace_back(); + o.iColumn = col; + o.desc = desc; +} + +void FilterConstraints::Clear() +{ + constraints_.clear(); + orderBys_.clear(); +} + +void FilterConstraints::ToString(std::string& idxStr) const +{ + idxStr.clear(); + idxStr.reserve(idxStrSize_); + idxStr = "C" + std::to_string(constraints_.size()); + for (size_t i = 0; i < constraints_.size(); i++) { + idxStr += " " + std::to_string(constraints_[i].col); + idxStr += " " + std::to_string(constraints_[i].op); + } + idxStr += " O" + std::to_string(orderBys_.size()); + for (size_t i = 0; i < orderBys_.size(); i++) { + idxStr += " " + std::to_string(orderBys_[i].iColumn); + idxStr += " " + std::to_string(orderBys_[i].desc); + } +} + +void FilterConstraints::FromString(const std::string& idxStr) +{ + const char* p = static_cast(idxStr.c_str()); + char* pNext = nullptr; + TS_ASSERT(*p == 'C'); + errno = 0; + int32_t constraintCount = static_cast(strtol(p + 1, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + for (int32_t i = 0; i < constraintCount; i++) { + p = pNext; + errno = 0; + int32_t col = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + p = pNext; + errno = 0; + unsigned char op = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + + AddConstraint(i, col, op); + } + + pNext++; // jump the ' ' + p = pNext; + TS_ASSERT(*p == 'O'); + errno = 0; + int32_t orderbyCount = static_cast(strtol(p + 1, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + for (int32_t i = 0; i < orderbyCount; i++) { + p = pNext; + errno = 0; + int32_t col = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + p = pNext; + errno = 0; + unsigned char desc = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + + AddOrderBy(col, desc); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/filter_constraints.h b/trace_streamer/sdk/dubai_sdk/table/filter_constraints.h new file mode 100644 index 0000000000000000000000000000000000000000..192dba271fdd73d2d3983f1d75192fd7b10942ef --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/filter_constraints.h @@ -0,0 +1,65 @@ +/* + * 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 TABLE_FILTER_CONSTRAINTS_H +#define TABLE_FILTER_CONSTRAINTS_H + +#include +#include +#include "sqlite3.h" + +namespace SysTuning { +namespace TraceStreamer { +class FilterConstraints { +public: + struct Constraint { + int32_t idxInaConstraint; // index in sqlite3_index_info.aConstraint[] + int32_t col; // Column this constraint refers to + unsigned char op; // SQLite op for the constraint + bool isSupport = false; + }; + using OrderBy = sqlite3_index_info::sqlite3_index_orderby; + + FilterConstraints() {} + ~FilterConstraints() {} + void AddConstraint(int32_t idx, int32_t col, unsigned char op, bool isSupport = false); + void UpdateConstraint(int32_t idx, bool isSupport); + void AddOrderBy(int32_t col, unsigned char desc); + void Clear(); + + const std::vector& GetOrderBys() const + { + return orderBys_; + } + + const std::vector& GetConstraints() const + { + return constraints_; + } + + // idxStr format: C col1 op1 ... colN opN O col1 desc1 ... colM descM + // like as "C2 0 2 1 4 O1 0 1" + void ToString(std::string& idxStr) const; + void FromString(const std::string& idxStr); + +private: + std::vector constraints_; + std::vector orderBys_; + const std::size_t idxStrSize_ = 512; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_FILTER_CONSTRAINTS_H diff --git a/trace_streamer/sdk/dubai_sdk/table/gpu_counter_object_table.cpp b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_object_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d1a577b75b87b45a97a890ae513bf8c85abd241 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_object_table.cpp @@ -0,0 +1,65 @@ +/* + * 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 "gpu_counter_object_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +namespace { +enum Index { COUNTER_ID = 0, COUNTER_NAME = 1 }; +} +GpuCounterObjectTable::GpuCounterObjectTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("counter_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("counter_name", "REAL")); + tablePriKey_.push_back("counter_id"); +} + +GpuCounterObjectTable::~GpuCounterObjectTable() {} + +std::unique_ptr GpuCounterObjectTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +GpuCounterObjectTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstGpuCounterObjectData().Size())), + gpuCounterObjectDataObj_(dataCache->GetConstGpuCounterObjectData()) +{ +} + +GpuCounterObjectTable::Cursor::~Cursor() {} + +int32_t GpuCounterObjectTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case COUNTER_ID: { + sqlite3_result_int64(context_, static_cast(gpuCounterObjectDataObj_.CounterId()[CurrentRow()])); + break; + } + case COUNTER_NAME: { + sqlite3_result_text(context_, gpuCounterObjectDataObj_.CounterName()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/gpu_counter_object_table.h b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_object_table.h new file mode 100644 index 0000000000000000000000000000000000000000..91909f78b9597b01dfc36a721787774f351911bb --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_object_table.h @@ -0,0 +1,51 @@ +/* + * 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 GPU_COUNTER_OBJECT_TABLE_H +#define GPU_COUNTER_OBJECT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class GpuCounterObjectTable : public TableBase { +public: + explicit GpuCounterObjectTable(const TraceDataCache* dataCache); + ~GpuCounterObjectTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + }; + int32_t Column(int32_t column) const override; + + private: + const GpuCounterObject& gpuCounterObjectDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // GPU_COUNTER_OBJECT_TABLE_H diff --git a/trace_streamer/sdk/dubai_sdk/table/gpu_counter_table.cpp b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4aed65a53e754c98bbcd0f26bbb840e2a0b9366b --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_table.cpp @@ -0,0 +1,70 @@ +/* + * 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 "gpu_counter_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +namespace { +enum Index { TS = 0, COUNTER_ID = 1, VALUE = 2 }; +} +GpuCounterTable::GpuCounterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("counter_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "REAL")); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("counter_id"); +} + +GpuCounterTable::~GpuCounterTable() {} + +std::unique_ptr GpuCounterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +GpuCounterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstGpuCounterData().Size())), + gpuCounterDataObj_(dataCache->GetConstGpuCounterData()) +{ +} + +GpuCounterTable::Cursor::~Cursor() {} + +int32_t GpuCounterTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(gpuCounterDataObj_.TimeStamp()[CurrentRow()])); + break; + } + case COUNTER_ID: { + sqlite3_result_int64(context_, static_cast(gpuCounterDataObj_.CounterId()[CurrentRow()])); + break; + } + case VALUE: { + sqlite3_result_int64(context_, static_cast(gpuCounterDataObj_.Value()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/gpu_counter_table.h b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..9d7e84cd9f100bc972f44198af8c291f35fd5a2e --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/gpu_counter_table.h @@ -0,0 +1,51 @@ +/* + * 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 GPU_COUNTER_TABLE_H +#define GPU_COUNTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class GpuCounterTable : public TableBase { +public: + explicit GpuCounterTable(const TraceDataCache* dataCache); + ~GpuCounterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + }; + int32_t Column(int32_t column) const override; + + private: + const GpuCounter& gpuCounterDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // GPU_COUNTER_TABLE_H diff --git a/trace_streamer/sdk/dubai_sdk/table/index_map.cpp b/trace_streamer/sdk/dubai_sdk/table/index_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c0ec2ffd6ac8082926e1e818585ef3307f97712 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/index_map.cpp @@ -0,0 +1,67 @@ +/* + * 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 "index_map.h" + +#include + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +IndexMap::IndexMap(TableRowId start, TableRowId end) + : end_(end), current_(start), start_(start), type_(COMPACT) {} + +void IndexMap::CovertToIndexMap() +{ + if (converted_) { + indexType_ = INDEX_TYPE_OUTER_INDEX; + return; + } + converted_ = true; + if (indexType_ == INDEX_TYPE_ID && HasData()) { + for (auto i = start_; i < end_; i++) { + rowIndex_.push_back(i); + } + current_ = start_ = 0; + end_ = rowIndex_.size(); + empty_ = !rowIndex_.size(); + } + indexType_ = INDEX_TYPE_OUTER_INDEX; +} +bool IndexMap::HasData() const { + return (start_ != 0 || end_ != INVALID_UINT32) || !empty_; +} +void IndexMap::Intersect(TableRowId start, TableRowId end) +{ + if (indexType_ == INDEX_TYPE_OUTER_INDEX) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (*i >= start && *i < end) { + i++; + } else { + i = rowIndex_.erase(i); + } + } + start_ = current_ = 0; + end_ = rowIndex_.size(); + } else { + start_ = std::max(start_, start); + end_ = std::min(end_, end); + current_ = start_; + } + empty_ = false; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/index_map.h b/trace_streamer/sdk/dubai_sdk/table/index_map.h new file mode 100644 index 0000000000000000000000000000000000000000..419aa1a7596b68bd5d3280055789b52bdfb44a4e --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/index_map.h @@ -0,0 +1,420 @@ +/* + * 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 TABLE_INDEX_MAP_H +#define TABLE_INDEX_MAP_H + +#include +#include +#include +#include +#include "log.h" +#include "sqlite3.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +class IndexMap { +public: + IndexMap() {} + ~IndexMap() {} + + IndexMap(TableRowId start, TableRowId end); + void CovertToIndexMap(); + template + void MixRange(unsigned char op, T value, const std::deque& dataQueue) + { + auto invalidValue = std::numeric_limits::max(); + bool remove = false; + if (HasData()) { + CovertToIndexMap(); + remove = true; + } + auto size = dataQueue.size(); + rowIndexBak_.clear(); + bool changed = false; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] != value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] == value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_NE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] == value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] != value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNULL: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] != invalidValue) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] == invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] == invalidValue) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] != invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] <= value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] > value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] < value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] >= invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] > value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] < invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] >= value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] < invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + + + default: + break; + } // end of switch (op) + empty_ = false; + } + void FixSize() + { + if (indexType_ == INDEX_TYPE_OUTER_INDEX) + { + end_ = rowIndex_.size(); + } + } + void Remove(TableRowId row) + { + rowIndex_.erase(std::remove(rowIndex_.begin(), rowIndex_.end(), row), rowIndex_.end()); + } + void Set(TableRowId start, TableRowId end) + { + if (indexType_ == INDEX_TYPE_ID) { + end_ = std::min(end_, end); + current_ = start_ = std::max(start_, start); + } + } + + size_t Size() const + { + return end_ - start_; + } + + void Next() + { + if (desc_) { + if (current_ > start_) { + current_--; + } + } else { + if (current_ < end_) { + current_++; + } + } + } + + bool Eof() const + { + if (desc_) { + return current_ <= start_; + } else { + return current_ >= end_; + } + } + + TableRowId CurrentRow() const + { + auto current = current_; + // if (desc_) { + // current--; + // } + if (indexType_ == INDEX_TYPE_ID) { + return current; + } else { + return rowIndex_[current]; + } + } + + void SortBy(bool desc) + { + if (desc) { + current_ = end_; + } else { + current_ = start_; + } + desc_ = desc; + } + + // void Insert(TableRowId index); + + // void Intersect(const IndexMap& other); + void Intersect(TableRowId start, TableRowId end); + // void Intersect(const std::vector& iv); + + // the follow functions require that thecolData is sotred + template + void IntersectabcEqual(const std::deque& rows, Val v, GetV getValue) + { + auto start = std::lower_bound(rows.begin() + start_, rows.begin() + end_, v); + auto end = std::upper_bound(start, rows.begin() + end_, v); + auto newStart = std::distance(rows.begin(), start); + auto newEnd = std::distance(rows.begin(), end); + Intersect(newStart, newEnd); + return; + } + + template + void IntersectGreaterEqual(const std::deque& rows, Val v, GetV getValue) + { + uint32_t index = rows.size() - 1; + for (; index != -1; index--) { + if (v >= getValue(rows[index])) { + break; + } + } + if (index == -1) { + index = 0; + } + Intersect(index, INVALID_UINT32); + return; + } + + template + void IntersectLessEqual(const std::deque& rows, Val v, GetV getValue) + { + uint32_t index = 0; + for (; index < rows.size(); index++) { + if (v <= getValue(rows[index])) { + break; + } + } + Intersect(0, index); + return; + } + template + void RemoveNullElements(const std::deque& rows, T v) + { + auto invalidValue = std::numeric_limits::max(); + bool remove = false; + if (HasData()) { + CovertToIndexMap(); + remove = true; + } + + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (rows[*i] == invalidValue) { + i = rowIndex_.erase(i); + } else { + i++; + } + } + } else { + auto size = rows.size(); + for (auto i = 0; i < size; i++) { + if (rows[i] != invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + return; + } + bool HasData() const; + std::vector rowIndex_; + std::vector rowIndexBak_; +private: + TableRowId end_ = INVALID_UINT32; + TableRowId current_ = 0; + TableRowId start_ = 0; + enum FindIndexType { + INDEX_TYPE_ID, + INDEX_TYPE_OUTER_INDEX, + }; + FindIndexType indexType_ = INDEX_TYPE_ID; + uint32_t indexSize_ = 0; + uint32_t index_ = 0; + + enum IndexType { + COMPACT, + SPARSE + }; + uint8_t type_ = COMPACT; + bool empty_ = true; + bool desc_ = false; + bool converted_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_INDEX_MAP_H diff --git a/trace_streamer/sdk/dubai_sdk/table/meta_table.cpp b/trace_streamer/sdk/dubai_sdk/table/meta_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93e0a6ab6c0e29678d30fdeebe604ba97f1aa931 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/meta_table.cpp @@ -0,0 +1,63 @@ +/* + * 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 "meta_table.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +namespace { +enum Index { NAMEINDEX = 0, VALUE }; +} +MetaTable::MetaTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "TEXT")); + tablePriKey_.push_back("name"); +} + +MetaTable::~MetaTable() {} + +std::unique_ptr MetaTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +MetaTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, MetaDataItem::METADATA_ITEM_MAX) +{ +} + +MetaTable::Cursor::~Cursor() {} + +int32_t MetaTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case NAMEINDEX: + sqlite3_result_text(context_, dataCache_->GetConstMetaData().Name(CurrentRow()).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + case VALUE: + sqlite3_result_text(context_, dataCache_->GetConstMetaData().Value(CurrentRow()).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/meta_table.h b/trace_streamer/sdk/dubai_sdk/table/meta_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6269067d1742020d3e4fb82adbf5fdfc42c651c5 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/meta_table.h @@ -0,0 +1,49 @@ +/* + * 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 META_TABLE_H +#define META_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class MetaTable : public TableBase { +public: + explicit MetaTable(const TraceDataCache* dataCache); + ~MetaTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // META_TABLE_H diff --git a/trace_streamer/sdk/dubai_sdk/table/slice_object_table.cpp b/trace_streamer/sdk/dubai_sdk/table/slice_object_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e212152cb20820c686915007624647d89008707 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/slice_object_table.cpp @@ -0,0 +1,65 @@ +/* + * 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 "slice_object_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +namespace { +enum Index { SLICE_ID = 0, SLICE_NAME = 1 }; +} +SliceObjectTable::SliceObjectTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("slice_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("slice_name", "REAL")); + tablePriKey_.push_back("slice_id"); +} + +SliceObjectTable::~SliceObjectTable() {} + +std::unique_ptr SliceObjectTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SliceObjectTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSliceObjectData().Size())), + sliceObjectDataObj_(dataCache->GetConstSliceObjectData()) +{ +} + +SliceObjectTable::Cursor::~Cursor() {} + +int32_t SliceObjectTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case SLICE_ID: { + sqlite3_result_int64(context_, static_cast(sliceObjectDataObj_.SliceId()[CurrentRow()])); + break; + } + case SLICE_NAME: { + sqlite3_result_text(context_, sliceObjectDataObj_.SliceName()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/slice_object_table.h b/trace_streamer/sdk/dubai_sdk/table/slice_object_table.h new file mode 100644 index 0000000000000000000000000000000000000000..386161b1cb42f67fe51ee1aeb4bfcb8bbd22e8ef --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/slice_object_table.h @@ -0,0 +1,52 @@ +/* + * 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 SLICE_OBJECT_TABLE_H +#define SLICE_OBJECT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SliceObjectTable : public TableBase { +public: + explicit SliceObjectTable(const TraceDataCache* dataCache); + ~SliceObjectTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const SliceObject& sliceObjectDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SLICE_OBJECT_TABLE_H diff --git a/trace_streamer/sdk/dubai_sdk/table/slice_table.cpp b/trace_streamer/sdk/dubai_sdk/table/slice_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..911d3741873daca2ab81910af6c53b5d661da72d --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/slice_table.cpp @@ -0,0 +1,85 @@ +/* + * 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 "slice_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +namespace { +enum Index { TS = 0, ENDTS = 1, ST=2, ET=3, VALUE = 4, SLICE_ID = 5}; +} +SliceTable::SliceTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("end", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "DOUBLE")); + tableColumn_.push_back(TableBase::ColumnInfo("slice_id", "INTEGER")); + tablePriKey_.push_back("start_ts"); + tablePriKey_.push_back("slice_id"); +} + +SliceTable::~SliceTable() {} + +std::unique_ptr SliceTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SliceTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSliceData().Size())), + sliceDataObj_(dataCache->GetConstSliceData()) +{ +} + +SliceTable::Cursor::~Cursor() {} + +int32_t SliceTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.TimeStamp()[CurrentRow()])); + break; + } + case ENDTS: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.EndTs()[CurrentRow()])); + break; + } + case ST: { + sqlite3_result_text(context_, sliceDataObj_.StartTime()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case ET: { + sqlite3_result_text(context_, sliceDataObj_.EndTime()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case VALUE: { + sqlite3_result_double(context_, static_cast(sliceDataObj_.Value()[CurrentRow()])); + break; + } + case SLICE_ID: { + sqlite3_result_int64(context_, static_cast(sliceDataObj_.SliceId()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/slice_table.h b/trace_streamer/sdk/dubai_sdk/table/slice_table.h new file mode 100644 index 0000000000000000000000000000000000000000..284858143f585c0a1f1adbd106044baf5d41a399 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/slice_table.h @@ -0,0 +1,52 @@ +/* + * 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 SLICE_TABLE_H +#define SLICE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SliceTable : public TableBase { +public: + explicit SliceTable(const TraceDataCache* dataCache); + ~SliceTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const SliceData& sliceDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SLICE_TABLE_H diff --git a/trace_streamer/sdk/dubai_sdk/table/table_base.cpp b/trace_streamer/sdk/dubai_sdk/table/table_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c524e15b612d8d949aa7c78e413244ba55a71fcd --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/table_base.cpp @@ -0,0 +1,288 @@ +/* + * 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 "table_base.h" + +#include +#include + +#include "log.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) + +namespace SysTuning { +namespace TraceStreamer { +namespace { +struct TableContext { + TabTemplate tmplate; + TraceDataCache* dataCache; + sqlite3_module module; + std::string tableName; +}; +} // namespace + +TableBase::~TableBase() +{ + dataCache_ = nullptr; + cursor_ = nullptr; +} + +void TableBase::TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate) +{ + std::unique_ptr context(std::make_unique()); + context->dataCache = cache; + context->tmplate = tmplate; + context->tableName = tableName; + sqlite3_module& module = context->module; + module = {0}; + + auto createFn = [](sqlite3* xdb, void* pAux, int32_t argc, const char* const* argv, sqlite3_vtab** ppVTab, + char** pzErr) { + UNUSED(argc); + UNUSED(argv); + UNUSED(pzErr); + auto xdesc = static_cast(pAux); + auto table = xdesc->tmplate(xdesc->dataCache); + table->name_ = xdesc->tableName; + if (table->name_ == "process" || table->name_ == "thread") { + table->wdataCache_ = xdesc->dataCache; + } + + table->Init(argc, argv); + std::string createStmt = table->CreateTableSql(); + TS_LOGD("xCreate table %s, statement: %s", table->name_.c_str(), createStmt.c_str()); + int32_t ret = sqlite3_declare_vtab(xdb, createStmt.c_str()); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_declare_vtab %s faild: %s", table->name_.c_str(), createStmt.c_str()); + return ret; + } + *ppVTab = table.release(); + return SQLITE_OK; + }; + + auto destroyFn = [](sqlite3_vtab* t) { + TS_LOGD("xDestroy table %s", static_cast(t)->name_.c_str()); + delete static_cast(t); + return SQLITE_OK; + }; + module.xCreate = createFn; + module.xConnect = createFn; + module.xDisconnect = destroyFn; + module.xDestroy = destroyFn; + + module.xOpen = [](sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor) { + TS_LOGD("xOpen: %s", static_cast(pVTab)->name_.c_str()); + return static_cast(pVTab)->Open(ppCursor); + }; + + module.xClose = [](sqlite3_vtab_cursor* vc) { + TS_LOGD("xClose: %s", static_cast(vc)->table_->name_.c_str()); + delete static_cast(vc); + return SQLITE_OK; + }; + + module.xBestIndex = [](sqlite3_vtab* pVTab, sqlite3_index_info* idxInfo) { + TS_LOGD("xBestIndex: %s %d", static_cast(pVTab)->name_.c_str(), idxInfo->nConstraint); + return static_cast(pVTab)->BestIndex(idxInfo); + }; + + module.xFilter = [](sqlite3_vtab_cursor* vc, int32_t idxNum, const char* idxStr, int32_t argc, + sqlite3_value** argv) { + auto* c = static_cast(vc); + c->Reset(); + TS_LOGD("xFilter %s: [%d]%s", static_cast(vc)->table_->name_.c_str(), idxNum, idxStr); + if (c->table_->cacheIdxNum_ != idxNum) { + c->table_->cacheConstraint_.Clear(); + c->table_->cacheConstraint_.FromString(idxStr); + c->table_->cacheIdxNum_ = idxNum; + } + return c->Filter(c->table_->cacheConstraint_, argv); + }; + + module.xNext = [](sqlite3_vtab_cursor* vc) { return static_cast(vc)->Next(); }; + module.xEof = [](sqlite3_vtab_cursor* vc) { return static_cast(vc)->Eof(); }; + module.xColumn = [](sqlite3_vtab_cursor* vc, sqlite3_context* ctx, int32_t col) { + static_cast(vc)->context_ = ctx; + return static_cast(vc)->Column(col); + }; + if (tableName == "process" || tableName == "thread") { + module.xUpdate = [](sqlite3_vtab* pVTab, int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) { + TS_LOGD("xUpdate: %s", static_cast(pVTab)->name_.c_str()); + return static_cast(pVTab)->Update(argc, argv, pRowid); + }; + } + + sqlite3_create_module_v2(&db, tableName.c_str(), &module, context.release(), + [](void* arg) { delete static_cast(arg); }); +} + +std::string TableBase::CreateTableSql() const +{ + std::string stmt = "CREATE TABLE x("; + for (const auto& col : tableColumn_) { + stmt += " " + col.name_ + " " + col.type_; + stmt += ","; + } + stmt += " PRIMARY KEY("; + for (size_t i = 0; i < tablePriKey_.size(); i++) { + if (i != 0) + stmt += ", "; + stmt += tablePriKey_.at(i); + } + stmt += ")) WITHOUT ROWID;"; + return stmt; +} + +int32_t TableBase::BestIndex(sqlite3_index_info* idxInfo) +{ + FilterConstraints filterConstraints; + for (int32_t i = 0; i < idxInfo->nConstraint; i++) { + const auto& constraint = idxInfo->aConstraint[i]; + if (constraint.usable) { + filterConstraints.AddConstraint(i, constraint.iColumn, constraint.op); + } + } + for (int32_t i = 0; i < idxInfo->nOrderBy; i++) { + filterConstraints.AddOrderBy(idxInfo->aOrderBy[i].iColumn, idxInfo->aOrderBy[i].desc); + } + + EstimatedIndexInfo estimate = {idxInfo->estimatedRows, idxInfo->estimatedCost, false}; + EstimateFilterCost(filterConstraints, estimate); + idxInfo->orderByConsumed = estimate.isOrdered; + idxInfo->estimatedCost = estimate.estimatedCost; + idxInfo->estimatedRows = estimate.estimatedRows; + + auto cs = filterConstraints.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + auto& c = cs[i]; + idxInfo->aConstraintUsage[c.idxInaConstraint].argvIndex = static_cast(i + 1); + idxInfo->aConstraintUsage[c.idxInaConstraint].omit = c.isSupport; + } + + std::string str; + filterConstraints.ToString(str); + char* pIdxStr = static_cast(sqlite3_malloc(str.size() + 1)); + std::copy(str.begin(), str.end(), pIdxStr); + pIdxStr[str.size()] = '\0'; + idxInfo->idxStr = pIdxStr; + idxInfo->needToFreeIdxStr = true; + idxInfo->idxNum = ++bestIndexNum_; + + TS_LOGD("%s BestIndex return: %d: %s", name_.c_str(), idxInfo->idxNum, str.c_str()); + TS_LOGD("%s, aConstraintUsage[%d]", idxInfo->idxStr, idxInfo->nConstraint); + for (int32_t i = 0; i < idxInfo->nConstraint; i++) { + TS_LOGD("col: %d op: %d, argvindex: %d omit: %d", idxInfo->aConstraint[i].iColumn, idxInfo->aConstraint[i].op, + idxInfo->aConstraintUsage[i].argvIndex, idxInfo->aConstraintUsage[i].omit); + } + TS_LOGD("estimated: %lld cost:%.3f", idxInfo->estimatedRows, idxInfo->estimatedCost); + + return SQLITE_OK; +} + +int32_t TableBase::Open(sqlite3_vtab_cursor** ppCursor) +{ + *ppCursor = static_cast(CreateCursor().release()); + return SQLITE_OK; +} + +TableBase::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount) + : context_(nullptr), + table_(table), + dataCache_(dataCache), + indexMap_(std::make_unique(0, rowCount)), + rowCount_(rowCount) +{ +} + +TableBase::Cursor::~Cursor() +{ + context_ = nullptr; + dataCache_ = nullptr; +} +void TableBase::Cursor::FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times) +{ + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint64_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(times, v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: { + indexMap_->RemoveNullElements(times, v); + break; + } + default: + break; + } // end of switch (op) + } +} + +int32_t TableBase::Cursor::RowId(sqlite3_int64* id) +{ + if (dataCache_->Cancel() || indexMap_->Eof()) { + return SQLITE_ERROR; + } + *id = static_cast(indexMap_->CurrentRow()); + return SQLITE_OK; +} +void TableBase::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/table/table_base.h b/trace_streamer/sdk/dubai_sdk/table/table_base.h new file mode 100644 index 0000000000000000000000000000000000000000..9d6161e351e1542570f243a52d346f1c8bb246bd --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/table/table_base.h @@ -0,0 +1,140 @@ +/* + * 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 TABLE_H +#define TABLE_H + +#include +#include +#include +#include + +#include "filter_constraints.h" +#include "index_map.h" +#include "sqlite3.h" +#include "trace_data_cache.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +namespace SysTuning { +namespace TraceStreamer { +class TableBase; +using TabTemplate = std::unique_ptr (*)(const TraceDataCache* dataCache); +class TableBase : public sqlite3_vtab { +public: + virtual ~TableBase(); + TableBase(const TableBase&) = delete; + TableBase& operator=(const TableBase&) = delete; + + template + static void TableDeclare(sqlite3& db, TraceDataCache* dataCache, const std::string& name) + { + TableRegister(db, dataCache, name, + [](const TraceDataCache* cache) { + return std::unique_ptr(std::make_unique(cache)); + }); + dataCache->AppendNewTable(name); + } + std::string CreateTableSql() const; + + class Cursor : public sqlite3_vtab_cursor { + public: + Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount); + virtual ~Cursor(); + virtual void Reset() + { + indexMap_ = std::make_unique(0, rowCount_); + } + + virtual int32_t Next() + { + indexMap_->Next(); + return SQLITE_OK; + } + + virtual int32_t Eof() + { + return dataCache_->Cancel() || indexMap_->Eof(); + } + + virtual uint32_t CurrentRow() const + { + return indexMap_->CurrentRow(); + } + virtual void FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times); + + virtual int32_t RowId(sqlite3_int64* id); + virtual int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) = 0; + virtual int32_t Column(int32_t n) const = 0; + virtual void FilterId(unsigned char op, sqlite3_value* argv); + public: + sqlite3_context* context_; + TableBase* table_ = nullptr; + + protected: + const TraceDataCache* dataCache_; + std::unique_ptr indexMap_; + uint32_t rowCount_; + }; + + struct ColumnInfo { + ColumnInfo(const std::string& name, const std::string& type) : name_(name), type_(type) {} + std::string name_; + std::string type_; + }; + +protected: + explicit TableBase(const TraceDataCache* dataCache) : dataCache_(dataCache), cursor_(nullptr) {} + + struct EstimatedIndexInfo { + int64_t estimatedRows = 0; + double estimatedCost = 0.0; + bool isOrdered = false; + }; + + static void TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate); + virtual int32_t Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) + { + return SQLITE_READONLY; + } + int32_t BestIndex(sqlite3_index_info* idxInfo); + // needs to correspond to Cursor::Filter() + virtual void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) = 0; + virtual std::unique_ptr CreateCursor() = 0; + int32_t Open(sqlite3_vtab_cursor** ppCursor); + virtual void Init(int32_t, const char* const*) + { + return; + }; + +protected: + std::vector tableColumn_ = {}; + std::vector tablePriKey_ = {}; + const TraceDataCache* dataCache_; + TraceDataCache* wdataCache_ = nullptr; + std::unique_ptr cursor_; + +private: + uint16_t bestIndexNum_ = 0; + int32_t cacheIdxNum_ = 0; + FilterConstraints cacheConstraint_; + std::string name_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_H diff --git a/trace_streamer/sdk/dubai_sdk/test/BUILD.gn b/trace_streamer/sdk/dubai_sdk/test/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..cdf2e8732ec8aa61d1e58f3df8735d621c3487f5 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/test/BUILD.gn @@ -0,0 +1,90 @@ +# 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("//build/test.gni") +import("../ts.gni") + +if (target == "sdkdemotest") { + ohos_unittest("trace_streamer_sdk_ut") { + sources = [ "unittest/sdk_api_test.cpp" ] + deps = [ + "../:trace_streamer_sdk", + "//prebuilts/protos:ts_proto_data_cpp", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + "//third_party/sqlite:sqlite", + ] + include_dirs = [ + "../base", + "../sdk", + "..", + "../trace_streamer", + "../filter", + "../table", + "../trace_data", + "../include", + "../plugin", + "../rpc", + "./", + "../parser", + "../cfg", + "//prebuilts/emsdk/emsdk/emscripten/system/include", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/mock_data", + "//third_party/googletest/googletest/include/gtest", + "//third_party/protobuf/src", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + ] + cflags = [ + "-Wno-inconsistent-missing-override", + "-Dprivate=public", #allow test code access private members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + cflags += [ + # clang coverage options: + "--coverage", + "-mllvm", + "-limited-coverage-experimental=true", + "-fno-use-cxa-atexit", + "-DUT_MAC", + ] + if (is_macx) { + lib_dirs = [ "/usr/local/opt/llvm/lib" ] + } + libs = [ "LLVMCore" ] + } +} + +# this is the dest for ohos.build +if (target == "sdkdemotest") { + group("sdkunittest") { + testonly = true + deps = [ ":trace_streamer_sdk_ut" ] + } +} diff --git a/trace_streamer/sdk/dubai_sdk/test/unittest/sdk_api_test.cpp b/trace_streamer/sdk/dubai_sdk/test/unittest/sdk_api_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..536259ceabeaa06746074dd5889a3361463b1a07 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/test/unittest/sdk_api_test.cpp @@ -0,0 +1,647 @@ +/* + * 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 +#include +#include "gpu_counter_object_table.h" +#include "gpu_counter_table.h" +#include "mock_plugin_result.pb.h" +#include "sdk_data_parser.h" +#include "slice_object_table.h" +#include "slice_table.h" +#include "ts_sdk_api.h" + +using namespace testing::ext; +namespace SysTuning ::TraceStreamer { +class SDKApiTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; + RpcServer* rpcServer = new RpcServer(); +}; + +std::string g_resultTest; +void res(const std::string result, int32_t finish, int32_t isConfig) +{ + TS_LOGI("%s", result.c_str()); + g_resultTest = result; +} + +std::string g_reply; +void QueryResultCallback(const std::string& jsonResult, int32_t finish, int32_t isConfig) +{ + g_reply = jsonResult; +} + +/** + * @tc.name: SetTableName + * @tc.desc: Set the table name manually + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, SetTableName, TestSize.Level1) +{ + TS_LOGI("test1-1"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", "second_table", "third_table", "fouth_table"); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_TRUE(ret); + EXPECT_EQ(g_resultTest.find("ok"), 0); + + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySlice("select * from third_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySliceObj("select * from fouth_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: DefaultTableName + * @tc.desc: Use the default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, DefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-2"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: NullTableName + * @tc.desc: Use the null table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, NullTableName, TestSize.Level1) +{ + TS_LOGI("test1-3"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", " "); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: NullAndManuallyCounterTableName + * @tc.desc: Use the null and manually counter table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, NullAndManuallyCounterTableName, TestSize.Level1) +{ + TS_LOGI("test1-4"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", "second_table", " ", " "); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: NullAndManuallySliceTableName + * @tc.desc: Use the null and manually slice table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, NullAndManuallySliceTableName, TestSize.Level1) +{ + TS_LOGI("test1-5"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", "first_table", "second_table"); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); + std::string sqlQuerySlice("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); + std::string sqlQuerySliceObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForCounterObjectWithDefaultTableName + * @tc.desc: Use CurrentData for CounterObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-6"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(1, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForCounterObjectWithManuallyTableName + * @tc.desc: Use CurrentData for CounterObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-7"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(1, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterObjectWithDefaultTableName + * @tc.desc: Use WrongData for CounterObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-8"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(INVALID_INT32, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterObjectWithManuallyTableName + * @tc.desc: Use WrongData for CounterObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-9"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(INVALID_INT32, "counter_1"); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from second_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterObject + * @tc.desc: Use WrongData for CounterObject table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterObject, TestSize.Level1) +{ + TS_LOGI("test1-10"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", "second_table", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounterObject(INVALID_INT32, " "); + EXPECT_EQ(0, ret); + std::string sqlQueryCounterObj("select * from gpu_counter_object;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounterObj.c_str(), sqlQueryCounterObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: CurrentDataForCounterWithDefaultTableName + * @tc.desc: Use CurrentData for Counter table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-11"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(1, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForCounterWithManuallyTableName + * @tc.desc: Use CurrentData for Counter table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForCounterWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-12"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", " ", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(1, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterWithDefaultTableName + * @tc.desc: Use WrongData for Counter table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-13"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(INVALID_INT32, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForCounterWithManuallyTableName + * @tc.desc: Use WrongData for Counter table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForCounterWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-14"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName("first_table", " ", " ", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(INVALID_INT32, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from first_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CounterWithWrongData + * @tc.desc: Use wrongData for counter table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CounterWithWrongData, TestSize.Level1) +{ + TS_LOGI("test1-15"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendCounter(INVALID_INT32, INVALID_UINT64, INVALID_INT32); + EXPECT_EQ(0, ret); + std::string sqlQueryCounter("select * from counter_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQueryCounter.c_str(), sqlQueryCounter.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForSliceObjectWithDefaultTableName + * @tc.desc: Use CurrentData for SliceObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-16"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(1, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForSliceObjectWithManuallyTableName + * @tc.desc: Use CurrentData for SliceObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-17"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(1, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from fourth_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceObjectWithDefaultTableName + * @tc.desc: Use WrongData for SliceObject table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceObjectWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-18"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(1, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceObjectWithManuallyTableName + * @tc.desc: Use WrongData for SliceObject table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceObjectWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-19"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(INVALID_INT32, "slice_1"); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: WrongDataForSliceObject + * @tc.desc: Use WrongData for SliceObject table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceObject, TestSize.Level1) +{ + TS_LOGI("test1-20"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", " ", "fourth_table"); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSliceObject(INVALID_INT32, " "); + EXPECT_EQ(0, ret); + std::string sqlQuerySliceObj("select * from slice_object_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySliceObj.c_str(), sqlQuerySliceObj.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), string::npos); + EXPECT_FALSE(ret); +} + +/** + * @tc.name: CurrentDataForSliceWithDefaultTableName + * @tc.desc: Use CurrentData for Slice table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-21"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(1, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from Slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: CurrentDataForSliceWithManuallyTableName + * @tc.desc: Use CurrentData for Slice table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, CurrentDataForSliceWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-22"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", "third_table", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(1, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from third_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceWithDefaultTableName + * @tc.desc: Use WrongData for Slice table with default table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceWithDefaultTableName, TestSize.Level1) +{ + TS_LOGI("test1-23"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(INVALID_INT32, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from Slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongDataForSliceWithManuallyTableName + * @tc.desc: Use WrongData for Slice table with manually table name + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, WrongDataForSliceWithManuallyTableName, TestSize.Level1) +{ + TS_LOGI("test1-24"); + SetRpcServer(rpcServer); + auto ret = SDK_SetTableName(" ", " ", "third_table", " "); + ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(INVALID_INT32, 100, 100, 100); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from third_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: SliceWithWrongData + * @tc.desc: Use wrongData for slice table + * @tc.type: FUNC + */ +HWTEST_F(SDKApiTest, SliceWithWrongData, TestSize.Level1) +{ + TS_LOGI("test1-25"); + SetRpcServer(rpcServer); + auto ret = rpcServer->ts_->sdkDataParser_->GetJsonConfig(QueryResultCallback); + EXPECT_EQ(0, ret); + ret = rpcServer->ts_->sdkDataParser_->CreateTableByJson(); + EXPECT_EQ(0, ret); + ret = SDK_AppendSlice(INVALID_INT32, INVALID_UINT64, INVALID_UINT64, INVALID_INT32); + EXPECT_EQ(0, ret); + std::string sqlQuerySlice("select * from slice_table;"); + ret = rpcServer->SqlQuery((const uint8_t*)sqlQuerySlice.c_str(), sqlQuerySlice.length(), res); + EXPECT_EQ(g_resultTest.find("ok"), 0); + EXPECT_TRUE(ret); +} +} // namespace SysTuning::TraceStreamer diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache.cpp b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a69df06f36af3b263f02162f25e0f46946053fa --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache.cpp @@ -0,0 +1,39 @@ +/* + * 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 "trace_data_cache.h" +#include "sqlite3.h" +#include "../table/gpu_counter_object_table.h" +#include "../table/gpu_counter_table.h" +#include "../table/slice_object_table.h" +#include "../table/slice_table.h" + +namespace SysTuning { +namespace TraceStreamer { +TraceDataCache::TraceDataCache() +{ + InitDB(); +} + +TraceDataCache::~TraceDataCache() {} + +void TraceDataCache::InitDB() +{ + if (dbInited) { + return; + } + dbInited = true; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache.h b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..28defa3a0e9dc2efd44ec857655caa4a1fb8ef05 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache.h @@ -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 TRACE_DATA_CACHE_H +#define TRACE_DATA_CACHE_H + +#include "trace_data_cache_reader.h" +#include "trace_data_cache_writer.h" +#include "trace_data_db.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCache : public TraceDataCacheReader, public TraceDataCacheWriter, public TraceDataDB { +public: + TraceDataCache(); + TraceDataCache(const TraceDataCache* dataCache) = delete; + TraceDataCache* operator=(const TraceDataCache* dataCache) = delete; + ~TraceDataCache() override; + void InitDB() override; + bool dbInited = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_DATA_CACHE_H diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_base.cpp b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9da698ee3afe99fed20c4d3c75a075b78e9724bd --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_base.cpp @@ -0,0 +1,24 @@ +/* + * 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 "trace_data_cache_base.h" +#include + +namespace SysTuning { +namespace TraceStreamer { + + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_base.h b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_base.h new file mode 100644 index 0000000000000000000000000000000000000000..da9156269218b388dc1cb0b53cb9b87a075a64d6 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_base.h @@ -0,0 +1,50 @@ +/* + * 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 TRACE_DATA_CACHE_BASE_H +#define TRACE_DATA_CACHE_BASE_H + + +#include +#include +#include +#include +#include +#include +#include "trace_stdtype.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheBase { +public: + TraceDataCacheBase() = default; + TraceDataCacheBase(const TraceDataCacheBase&) = delete; + TraceDataCacheBase& operator=(const TraceDataCacheBase&) = delete; + virtual ~TraceDataCacheBase() = default; + +public: + GpuCounter gpuCounter_; + GpuCounterObject gpuCounterObject_; + SliceObject sliceObject_; + SliceData sliceData_; + MetaData metaData_; + uint64_t traceStartTime_ = std::numeric_limits::max(); + uint64_t traceEndTime_ = 0; + +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_DATA_CACHE_BASE_H diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_reader.cpp b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee224b06364a5054acbe43f7320505895c7dcd88 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_reader.cpp @@ -0,0 +1,44 @@ +/* + * 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 "trace_data_cache_reader.h" +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +TraceDataCacheReader::~TraceDataCacheReader() {} + +const GpuCounter& TraceDataCacheReader::GetConstGpuCounterData() const +{ + return gpuCounter_; +} +const GpuCounterObject& TraceDataCacheReader::GetConstGpuCounterObjectData() const +{ + return gpuCounterObject_; +} +const SliceObject& TraceDataCacheReader::GetConstSliceObjectData() const +{ + return sliceObject_; +} +const SliceData& TraceDataCacheReader::GetConstSliceData() const +{ + return sliceData_; +} +const MetaData& TraceDataCacheReader::GetConstMetaData() const +{ + return metaData_; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_reader.h b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..916606ab21a49d01a6b848cc9d3e21c588c4a7e1 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_reader.h @@ -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. + */ + +#ifndef TRACE_DATA_CACHE_READER_H +#define TRACE_DATA_CACHE_READER_H + +#include "log.h" +#include "trace_data_cache_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheReader : virtual public TraceDataCacheBase { +public: + TraceDataCacheReader() = default; + TraceDataCacheReader(const TraceDataCacheReader&) = delete; + TraceDataCacheReader& operator=(const TraceDataCacheReader&) = delete; + ~TraceDataCacheReader() override; + +public: + const GpuCounter& GetConstGpuCounterData() const; + const GpuCounterObject& GetConstGpuCounterObjectData() const; + const SliceObject& GetConstSliceObjectData() const; + const SliceData& GetConstSliceData() const; + const MetaData& GetConstMetaData() const; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_writer.cpp b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_writer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5a7920cfb2076c01e98308098d61c6cbb68297f --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_writer.cpp @@ -0,0 +1,67 @@ +/* + * 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 "trace_data_cache_writer.h" +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +TraceDataCacheWriter::~TraceDataCacheWriter() {} + +GpuCounter* TraceDataCacheWriter::GetGpuCounterData() +{ + return &gpuCounter_; +} +GpuCounterObject* TraceDataCacheWriter::GetGpuCounterObjectData() +{ + return &gpuCounterObject_; +} +SliceObject* TraceDataCacheWriter::GetSliceObjectData() +{ + return &sliceObject_; +} +SliceData* TraceDataCacheWriter::GetSliceTableData() +{ + return &sliceData_; +} +MetaData* TraceDataCacheWriter::GetMetaData() +{ + return &metaData_; +} +void TraceDataCacheWriter::MixTraceTime(uint64_t timestampMin, uint64_t timestampMax) +{ + if (timestampMin == std::numeric_limits::max() || timestampMax == 0) { + return; + } + if (traceStartTime_ != std::numeric_limits::max()) { + traceStartTime_ = std::max(traceStartTime_, timestampMin); + } else { + traceStartTime_ = timestampMin; + } + if (traceEndTime_) { + traceEndTime_ = std::min(traceEndTime_, timestampMax); + } else { + traceEndTime_ = timestampMax; + } +} +void TraceDataCacheWriter::Clear() +{ + gpuCounter_.Clear(); + gpuCounterObject_.Clear(); + sliceObject_.Clear(); + sliceData_.Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_writer.h b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..b97565b331520f414bb76a973a3ef1c7e4c26b60 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_cache_writer.h @@ -0,0 +1,43 @@ +/* + * 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 TRACE_DATA_CACHE_WRITER_H +#define TRACE_DATA_CACHE_WRITER_H + +#include "trace_data_cache_reader.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheWriter : virtual public TraceDataCacheBase { +public: + TraceDataCacheWriter() = default; + TraceDataCacheWriter(const TraceDataCacheWriter&) = delete; + TraceDataCacheWriter& operator=(const TraceDataCacheWriter&) = delete; + ~TraceDataCacheWriter() override; + void Clear(); + +public: + GpuCounter* GetGpuCounterData(); + GpuCounterObject* GetGpuCounterObjectData(); + SliceObject* GetSliceObjectData(); + SliceData* GetSliceTableData(); + MetaData* GetMetaData(); + void MixTraceTime(uint64_t timestampMin, uint64_t timestampMax); + // ThreadState* GetThreadStateData(); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_db.cpp b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_db.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e14e6c7846e8de61e8b91ee924532279a26dad62 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_db.cpp @@ -0,0 +1,421 @@ +/* + * 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 "trace_data_db.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ext/sqlite_ext_funcs.h" +#include "file.h" +#include "log.h" +#include "sqlite3.h" +#include "string_help.h" + +const int32_t ONCE_MAX_MB = 1024 * 1024 * 4; +namespace SysTuning { +namespace TraceStreamer { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +using namespace SysTuning::base; +TraceDataDB::TraceDataDB() : db_(nullptr) +{ + if (sqlite3_threadsafe() > 0) { + int32_t retCode = sqlite3_config(SQLITE_CONFIG_SERIALIZED); + if (retCode == SQLITE_OK) { + TS_LOGI("Can now use sqlite on multiple threads, using the same connection"); + } else { + TS_LOGE("setting sqlite thread safe mode to serialized failed!!! return code: %d", retCode); + } + } else { + TS_LOGE("Your SQLite database is not compiled to be threadsafe."); + } + if (sqlite3_open(":memory:", &db_)) { + TS_LOGF("open :memory db failed"); + } + ts_create_extend_function(db_); +} + +TraceDataDB::~TraceDataDB() +{ + sqlite3_close(db_); +} + +void TraceDataDB::AppendNewTable(std::string tableName) +{ + internalTables_.push_back(tableName); +} +void TraceDataDB::EnableMetaTable(bool enabled) +{ + exportMetaTable_ = enabled; +} +int32_t TraceDataDB::ExportDatabase(const std::string& outputName) +{ + { + int32_t fd(base::OpenFile(outputName, O_CREAT | O_RDWR, TS_PERMISSION_RW)); + if (!fd) { + fprintf(stdout, "Failed to create file: %s", outputName.c_str()); + return 1; + } + auto ret = ftruncate(fd, 0); + UNUSED(ret); + close(fd); + } + + std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export"); +#ifdef _WIN32 + if (!base::GetCoding(reinterpret_cast(attachSql.c_str()), attachSql.length())) { + attachSql = base::GbkToUtf8(attachSql.c_str()); + } +#endif + ExecuteSql(attachSql); + + for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) { +#ifndef USE_VTABLE + if (*itor == "_meta" && !exportMetaTable_) { + continue; + } else { + std::string exportSql("CREATE TABLE systuning_export." + (*itor).substr(1, -1) + " AS SELECT * FROM " + + *itor); + ExecuteSql(exportSql); + } +#else + if (*itor == "meta" && !exportMetaTable_) { + continue; + } else { + std::string exportSql("CREATE TABLE systuning_export." + (*itor) + " AS SELECT * FROM " + *itor); + ExecuteSql(exportSql); + } +#endif + } + std::string createArgsView = + "create view systuning_export.args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when " + "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on (D.typeId " + "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key"; + ExecuteSql(createArgsView); + std::string updateProcessName = + "update process set name = (select name from thread t where t.ipid = process.id and t.name is not null and " + "is_main_thread = 1)"; + ExecuteSql(updateProcessName); + std::string detachSql("DETACH DATABASE systuning_export"); + ExecuteSql(detachSql); + return 0; +} +void TraceDataDB::Prepare() +{ + if (pared_) { + return; + } + pared_ = true; +#ifndef USE_VTABLE + for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) { + std::string exportSql("CREATE TABLE " + (*itor).substr(1, -1) + " AS SELECT * FROM " + *itor); + ExecuteSql(exportSql); + } +#endif + std::string createArgsView = + "create view args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when " + "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on " + "(D.typeId " + "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key"; + ExecuteSql(createArgsView); + + std::string updateProcessNewName = + "update process set name = (select name from thread t where t.ipid = process.id and t.name is not " + "null and " + "is_main_thread = 1)"; + ExecuteSql(updateProcessNewName); +} +void TraceDataDB::ExecuteSql(const std::string_view& sql) +{ + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.data(), static_cast(sql.size()), &stmt, nullptr); + + while (!ret) { + int32_t err = sqlite3_step(stmt); + if (err == SQLITE_ROW) { + continue; + } + if (err == SQLITE_DONE) { + break; + } + ret = err; + } + + sqlite3_finalize(stmt); +} +int32_t TraceDataDB::SearchData() +{ + Prepare(); + std::string line; + bool printResult = false; + for (;;) { + std::cout << "> "; + getline(std::cin, line); + if (line.empty()) { + std::cout << "If you want to quit either type -q or press CTRL-Z" << std::endl; + continue; + } + if (!line.compare("-q") || !line.compare("-quit")) { + break; + } else if (!line.compare("-e")) { + TS_LOGI("the db file will be at current folder, the name is default.db"); + return ExportDatabase("default.db"); + } else if (!line.compare("-help") || !line.compare("-h")) { + std::cout << "use info" << std::endl; + continue; + } else if (!line.compare("-p")) { + std::cout << "will print result of query" << std::endl; + printResult = true; + continue; + } else if (!line.compare("-up")) { + std::cout << "will not print result of query" << std::endl; + printResult = false; + continue; + } else if (line.find("-c:") != std::string::npos) { + line = line.substr(strlen("-c:")); + if (OperateDatabase(line) == SQLITE_OK) { + printf("operate SQL success\n"); + } + continue; + } + + using namespace std::chrono; + const auto start = steady_clock::now(); + int32_t rowCount = SearchDatabase(line, printResult); + std::chrono::nanoseconds searchDur = duration_cast(steady_clock::now() - start); + printf("\"%s\"\n\tused %.3fms row: %d\n", line.c_str(), searchDur.count() / 1E6, rowCount); + } + return 0; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, bool print) +{ + Prepare(); + int32_t rowCount = 0; + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return 0; + } + + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + TS_LOGI("sqlite3_column_count(%s) no column", sql.c_str()); + sqlite3_finalize(stmt); + return 0; + } + if (print) { + for (int32_t i = 0; i < colCount; i++) { + printf("%s\t", sqlite3_column_name(stmt, i)); + } + printf("\n"); + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + rowCount++; + for (int32_t i = 0; i < colCount; i++) { + const char* p = reinterpret_cast(sqlite3_column_text(stmt, i)); + int32_t type = sqlite3_column_type(stmt, i); + if (!print) { + continue; + } + if (p == nullptr) { + printf("null\t"); + continue; + } + if (type == SQLITE_TEXT) { + printf("\"%s\"\t", p); + } else { + printf("%s\t", p); + } + } + if (print) { + printf("\n"); + } + } + sqlite3_finalize(stmt); + return rowCount; +} +int32_t TraceDataDB::OperateDatabase(const std::string& sql) +{ + Prepare(); + char* errmsg = nullptr; + int32_t ret = sqlite3_exec(db_, sql.c_str(), NULL, NULL, &errmsg); + if (ret != SQLITE_OK && errmsg) { + TS_LOGE("sqlite3_exec(%s) failed: %d:%s", sql.c_str(), ret, errmsg); + sqlite3_free(errmsg); + } + return ret; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, ResultCallBack resultCallBack) +{ + Prepare(); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + resultCallBack("false\r\n", SEND_FINISH, 0); + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return ret; + } + if (!resultCallBack) { + return ret; + } + + std::string res = "ok\r\n"; + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + resultCallBack(res, SEND_FINISH, 0); + return ret; + } + res += "{\"columns\":["; + for (int32_t i = 0; i < colCount; i++) { + res += "\""; + res += sqlite3_column_name(stmt, i); + res += "\","; + } + res.pop_back(); // remove the last "," + res += "],\"values\":["; + bool hasRow = false; + constexpr int32_t defaultLenRowString = 1024; + std::string row; + row.reserve(defaultLenRowString); + while (sqlite3_step(stmt) == SQLITE_ROW) { + hasRow = true; + GetRowString(stmt, colCount, row); + res += row + ","; + if (res.size() >= ONCE_MAX_MB) { + resultCallBack(res, SEND_CONTINUE, 0); + res = ""; + } + } + if (hasRow) { + res.pop_back(); // remove the last ',' + } + res += "]}\r\n"; + resultCallBack(res, SEND_FINISH, 0); + + sqlite3_finalize(stmt); + return ret; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen) +{ + Prepare(); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return -1; + } + char* res = reinterpret_cast(out); + int32_t retSnprintf = snprintf_s(res, outLen, 1, "ok\r\n"); + if (retSnprintf < 0) { + return -1; + } + int32_t pos = retSnprintf; + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + return pos; + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s", "{\"columns\":["); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + for (int32_t i = 0; i < colCount; i++) { + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s%s%s", "\"", sqlite3_column_name(stmt, i), "\","); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + } + pos--; // rmove the last ',' + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "],\"values\":["); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + bool hasRow = false; + constexpr int32_t defaultLenRowString = 1024; + std::string row; + row.reserve(defaultLenRowString); + while (sqlite3_step(stmt) == SQLITE_ROW) { + hasRow = true; + GetRowString(stmt, colCount, row); + if (pos + row.size() + strlen(",]}\r\n") >= size_t(outLen)) { + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n"); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + sqlite3_finalize(stmt); + return pos; + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s%s", row.c_str(), ","); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + } + if (hasRow) { + pos--; // remove the last ',' + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n"); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + sqlite3_finalize(stmt); + return pos; +} +void TraceDataDB::SetCancel(bool cancel) +{ + cancelQuery_ = cancel; +} +void TraceDataDB::GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr) +{ + rowStr.clear(); + rowStr = "["; + for (int32_t i = 0; i < colCount; i++) { + const char* p = reinterpret_cast(sqlite3_column_text(stmt, i)); + if (p == nullptr) { + rowStr += "null,"; + continue; + } + int32_t type = sqlite3_column_type(stmt, i); + switch (type) { + case SQLITE_TEXT: + rowStr += "\""; + rowStr += p; + rowStr += "\""; + break; + default: + rowStr += p; + break; + } + rowStr += ","; + } + rowStr.pop_back(); // remove the last ',' + rowStr += "]"; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_db.h b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_db.h new file mode 100644 index 0000000000000000000000000000000000000000..75ddb7b2baa243016b91937a482e93208ce83857 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_data_db.h @@ -0,0 +1,66 @@ +/* + * 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 TRACE_DATA_DB_H +#define TRACE_DATA_DB_H + +#include +#include +#include +#include "sqlite3.h" + +namespace SysTuning { +namespace TraceStreamer { +const int32_t SEND_CONTINUE = 0; +const int32_t SEND_FINISH = 1; +class TraceDataDB { +public: + TraceDataDB(); + TraceDataDB(const TraceDataDB&) = delete; + TraceDataDB& operator=(const TraceDataDB&) = delete; + virtual ~TraceDataDB(); + virtual void InitDB() = 0; + void Prepare(); + +public: + int32_t ExportDatabase(const std::string& outputName); + int32_t SearchData(); + int32_t OperateDatabase(const std::string& sql); + using ResultCallBack = std::function; + int32_t SearchDatabase(const std::string& sql, ResultCallBack resultCallBack); + int32_t SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen); + void SetCancel(bool cancel); + void AppendNewTable(std::string tableName); + void EnableMetaTable(bool enabled); + bool Cancel() const + { + return cancelQuery_; + } + +public: + sqlite3* db_; + +private: + void ExecuteSql(const std::string_view& sql); + static void GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr); + int32_t SearchDatabase(const std::string& sql, bool print); + std::list internalTables_ = {}; + bool exportMetaTable_ = true; + bool pared_ = false; + bool cancelQuery_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_stdtype.cpp b/trace_streamer/sdk/dubai_sdk/trace_data/trace_stdtype.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06f09984425506e046bd66a631fc7bdc9287d7f0 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_stdtype.cpp @@ -0,0 +1,135 @@ +/* + * 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 "trace_stdtype.h" +#include +#include +namespace SysTuning { +namespace TraceStdtype { + +void GpuCounter::AppendNewData(uint64_t ts, int32_t counterId, double value) +{ + ts_.emplace_back(ts); + counterId_.emplace_back(counterId); + value_.emplace_back(value); + ids_.push_back(counterId_.size() - 1); +} +const std::deque& GpuCounter::TimeStamp() const +{ + return ts_; +} +const std::deque& GpuCounter::CounterId() const +{ + return counterId_; +} +const std::deque& GpuCounter::Value() const +{ + return value_; +} + +void GpuCounterObject::AppendNewData(int32_t counterId, const std::string counterName) +{ + counterId_.emplace_back(counterId); + counterName_.emplace_back(counterName); + ids_.push_back(counterId_.size() - 1); +} +const std::deque& GpuCounterObject::CounterId() const +{ + return counterId_; +} +const std::deque& GpuCounterObject::CounterName() const +{ + return counterName_; +} +void SliceObject::AppendNewData(int32_t sliceId, std::string sliceName) +{ + sliceId_.emplace_back(sliceId); + sliceName_.emplace_back(sliceName); + ids_.push_back(sliceId_.size() - 1); +} +const std::deque& SliceObject::SliceId() const +{ + return sliceId_; +} +const std::deque& SliceObject::SliceName() const +{ + return sliceName_; +} +void SliceData::AppendNewData(int32_t sliceId, + uint64_t startTs, + uint64_t endTs, + std::string start_time, + std::string end_time, + double value) +{ + startTs_.emplace_back(startTs); + endTs_.emplace_back(endTs); + sliceId_.emplace_back(sliceId); + value_.emplace_back(value); + starttime_.emplace_back(start_time); + endtime_.emplace_back(end_time); + ids_.push_back(sliceId_.size() - 1); +} +const std::deque& SliceData::SliceId() const +{ + return sliceId_; +} +const std::deque& SliceData::TimeStamp() const +{ + return startTs_; +} +const std::deque& SliceData::EndTs() const +{ + return endTs_; +} +const std::deque& SliceData::StartTime() const +{ + return starttime_; +} +const std::deque& SliceData::EndTime() const +{ + return endtime_; +} +const std::deque& SliceData::Value() const +{ + return value_; +} +void MetaData::InitMetaData() +{ + columnNames_.resize(METADATA_ITEM_MAX); + values_.resize(METADATA_ITEM_MAX); + columnNames_[METADATA_ITEM_PARSERTOOL_VERSION] = METADATA_ITEM_PARSERTOOL_VERSION_COLNAME; + columnNames_[METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME] = METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME_COLNAME; +} +void MetaData::SetParserToolVersion(const std::string& version) +{ + values_[METADATA_ITEM_PARSERTOOL_VERSION] = version; + +} +void MetaData::SetParserToolPublishDateTime(const std::string& datetime) +{ + values_[METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME] = datetime; +} +const std::string& MetaData::Value(uint64_t row) const +{ + return values_[row]; +} +const std::string& MetaData::Name(uint64_t row) const +{ + return columnNames_[row]; +} + +} // namespace TraceStdtype +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_data/trace_stdtype.h b/trace_streamer/sdk/dubai_sdk/trace_data/trace_stdtype.h new file mode 100644 index 0000000000000000000000000000000000000000..86fb1bbf25d786aa5a4fb704989b33e6af0dc55f --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_data/trace_stdtype.h @@ -0,0 +1,152 @@ +/* + * 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 TRACE_STDTYPE_H +#define TRACE_STDTYPE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStdtype { +using namespace SysTuning::TraceStreamer; +// the supported metadata +enum MetaDataItem { METADATA_ITEM_PARSERTOOL_VERSION, METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME, METADATA_ITEM_MAX }; +class CacheBase { +public: + size_t Size() const + { + return std::max(timeStamps_.size(), ids_.size()); + } + const std::deque& IdsData() const + { + return ids_; + } + const std::deque& TimeStampData() const + { + return timeStamps_; + } + const std::deque& InternalTidsData() const + { + return internalTids_; + } + virtual void Clear() + { + internalTids_.clear(); + timeStamps_.clear(); + ids_.clear(); + } + +public: + std::deque internalTids_ = {}; + std::deque timeStamps_ = {}; + std::deque ids_ = {}; +}; + +class GpuCounterObject : public CacheBase { +public: + GpuCounterObject() = default; + ~GpuCounterObject() = default; + void AppendNewData(int32_t counterId, const std::string counterName); + const std::deque& CounterId() const; + const std::deque& CounterName() const; + +private: + std::deque counterId_ = {}; + std::deque counterName_ = {}; +}; +class GpuCounter : public CacheBase { +public: + GpuCounter() = default; + ~GpuCounter() = default; + void AppendNewData(uint64_t ts, int32_t counterId, double value); + const std::deque& TimeStamp() const; + const std::deque& CounterId() const; + const std::deque& Value() const; + +private: + std::deque ts_ = {}; + std::deque counterId_ = {}; + std::deque value_ = {}; +}; + +class SliceObject : public CacheBase { +public: + SliceObject() = default; + ~SliceObject() = default; + void AppendNewData(int32_t sliceId, std::string sliceName); + const std::deque& SliceId() const; + const std::deque& SliceName() const; + +private: + std::deque sliceId_ = {}; + std::deque sliceName_ = {}; +}; +class SliceData : public CacheBase { +public: + SliceData() = default; + ~SliceData() = default; + void AppendNewData(int32_t sliceId, uint64_t startTs, uint64_t endTs, std::string start_time, std::string end_time, double value); + const std::deque& SliceId() const; + const std::deque& TimeStamp() const; + const std::deque& EndTs() const; + const std::deque& Value() const; + const std::deque& StartTime() const; + const std::deque& EndTime() const; + +private: + std::deque startTs_ = {}; + std::deque sliceId_ = {}; + std::deque endTs_ = {}; + std::deque value_ = {}; + std::deque starttime_ = {}; + std::deque endtime_ = {}; +}; +class MetaData : public CacheBase { +public: + MetaData() = default; + ~MetaData() = default; + void InitMetaData(); + void SetParserToolVersion(const std::string& version); + void SetParserToolPublishDateTime(const std::string& datetime); + const std::string& Value(uint64_t row) const; + const std::string& Name(uint64_t row) const; + virtual void Clear() override + { + columnNames_.clear(); + values_.clear(); + } + +private: + const std::string METADATA_ITEM_PARSERTOOL_VERSION_COLNAME = "tool_version"; + const std::string METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME_COLNAME = "tool_publish_time"; + std::deque columnNames_ = {}; + std::deque values_ = {}; +}; +} // namespace TraceStdtype +} // namespace SysTuning + +#endif // TRACE_STDTYPE_H diff --git a/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_filters.cpp b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_filters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b831e4cea70d570902487a1267090ce0baf8a94 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_filters.cpp @@ -0,0 +1,21 @@ +/* + * 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 "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_filters.h b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_filters.h new file mode 100644 index 0000000000000000000000000000000000000000..506a69e6d76c504df468965bdadfad17387db5c6 --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_filters.h @@ -0,0 +1,32 @@ +/* + * 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 TRACE_STREAMERTOKEN_H +#define TRACE_STREAMERTOKEN_H + +#include +#include "clock_filter.h" +namespace SysTuning { +namespace TraceStreamer { +class TraceStreamerFilters { +public: + TraceStreamerFilters(){}; + ~TraceStreamerFilters(){}; + std::unique_ptr clockFilter_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_STREAMERTOKEN_H diff --git a/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_selector.cpp b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_selector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..190338f2dc6c2cda6a3568f80069029d1287a96c --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_selector.cpp @@ -0,0 +1,101 @@ +/* + * 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 "trace_streamer_selector.h" +#include +#include +#include +#include +#include "clock_filter.h" +#include "string_help.h" + +using namespace SysTuning::base; +namespace SysTuning { +namespace TraceStreamer { +namespace { +TraceFileType GuessFileType(const uint8_t* data, size_t size) +{ + return TRACE_FILETYPE_UN_KNOW; +} +} // namespace + +TraceStreamerSelector::TraceStreamerSelector() +{ + InitFilter(); + sdkDataParser_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); +} +TraceStreamerSelector::~TraceStreamerSelector() {} + +void TraceStreamerSelector::InitFilter() +{ + streamFilters_ = std::make_unique(); + traceDataCache_ = std::make_unique(); + streamFilters_->clockFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); +} + +MetaData* TraceStreamerSelector::GetMetaData() +{ + return traceDataCache_->GetMetaData(); +} + +void TraceStreamerSelector::WaitForParserEnd() +{ +} + +bool TraceStreamerSelector::ParseTraceDataSegment(std::unique_ptr data, size_t size) +{ + if (size == 0) { + return true; + } + return true; +} +void TraceStreamerSelector::EnableMetaTable(bool enabled) +{ + traceDataCache_->EnableMetaTable(enabled); +} + +void TraceStreamerSelector::SetCleanMode(bool cleanMode) {} +int32_t TraceStreamerSelector::ExportDatabase(const std::string& outputName) const +{ + return traceDataCache_->ExportDatabase(outputName); +} +void TraceStreamerSelector::Clear() +{ + traceDataCache_->Prepare(); + traceDataCache_->Clear(); +} +int32_t TraceStreamerSelector::SearchData() +{ + return traceDataCache_->SearchData(); +} +int32_t TraceStreamerSelector::OperateDatabase(const std::string& sql) +{ + return traceDataCache_->OperateDatabase(sql); +} +int32_t TraceStreamerSelector::SearchDatabase(const std::string& sql, + TraceDataDB::ResultCallBack resultCallBack) +{ + return traceDataCache_->SearchDatabase(sql, resultCallBack); +} +int32_t TraceStreamerSelector::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen) +{ + return traceDataCache_->SearchDatabase(sql, out, outLen); +} +void TraceStreamerSelector::SetCancel(bool cancel) +{ + traceDataCache_->SetCancel(cancel); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_selector.h b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_selector.h new file mode 100644 index 0000000000000000000000000000000000000000..2c923f9402818b2e677719bd1d89baafb5497aae --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/trace_streamer/trace_streamer_selector.h @@ -0,0 +1,55 @@ +/* + * 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 TRACE_STREAMER_SELECTOR_H +#define TRACE_STREAMER_SELECTOR_H +#include +#include +#include "../sdk/sdk_data_parser.h" +#include "../trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class SDKDataParser; +enum TraceFileType { TRACE_FILETYPE_UN_KNOW }; +class TraceStreamerSelector { +public: + TraceStreamerSelector(); + ~TraceStreamerSelector(); + static bool ParseTraceDataSegment(std::unique_ptr data, size_t size); + void EnableMetaTable(bool enabled); + static void SetCleanMode(bool cleanMode); + int32_t ExportDatabase(const std::string& outputName) const; + int32_t SearchData(); + int32_t OperateDatabase(const std::string& sql); + int32_t SearchDatabase(const std::string& sql, TraceDataDB::ResultCallBack resultCallBack); + int32_t SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen); + MetaData* GetMetaData(); + static void WaitForParserEnd(); + void Clear(); + void SetDataType(TraceFileType type); + void SetCancel(bool cancel); + std::unique_ptr sdkDataParser_ = {}; + +private: + void InitFilter(); + std::unique_ptr streamFilters_ = {}; + std::unique_ptr traceDataCache_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_STREAMER_SELECTOR_H diff --git a/trace_streamer/sdk/dubai_sdk/ts.gni b/trace_streamer/sdk/dubai_sdk/ts.gni new file mode 100755 index 0000000000000000000000000000000000000000..16279772850e6b180cc5c0b02a8945bfef54999b --- /dev/null +++ b/trace_streamer/sdk/dubai_sdk/ts.gni @@ -0,0 +1,61 @@ +# 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. +OHOS_PROTO_DIR = "" + +if (target_os == "linux" || target_os == "macx" || target_os == "windows") { + # OHOS_FTRACE_PROTO_DIR="//third_party/protogen" + OHOS_FTRACE_PROTO_DIR = "//src/multi_platform" + + # OHOS_MEMORY_PROTO_DIR="//third_party/protogen" + OHOS_MEMORY_PROTO_DIR = "//src/multi_platform" + + # OHOS_HILOG_PROTO_DIR="//third_party/protogen" + OHOS_HILOG_PROTO_DIR = "//src/multi_platform" + + # OHOS_NATIVE_HOOK_PROTO_DIR="//third_party/protogen" + OHOS_NATIVE_HOOK_PROTO_DIR = "//src/multi_platform" + + # OHOS_HIDUMP_PROTO_DIR="//third_party/protogen" + OHOS_HIDUMP_PROTO_DIR = "//src/multi_platform" + + # OHOS_SERVICE_PROTO_DIR = "//third_party/protogen" + OHOS_SERVICE_PROTO_DIR = "//src/multi_platform" + OHOS_PROTO_GEN = "//third_party/protogen" + + # kernel_version = "5.10.79_aarch64" + kernel_version = "." + if (target == "test") { + enable_ts_utest = true + } else { + enable_ts_utest = false + } + is_openharmony = false +} else { + enable_ts_utest = true + use_wasm = false + kernel_version = "." + is_fuzz = false + target = "trace_streamer" + is_openharmony = true + OHOS_FTRACE_PROTO_DIR = "//developtools/profiler/protos/types/plugins/ftrace_data/${kernel_version}" + OHOS_MEMORY_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/memory_data" + OHOS_HILOG_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hilog_data" + OHOS_NATIVE_HOOK_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/native_hook" + OHOS_HIDUMP_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hidump_data" + OHOS_SERVICE_PROTO_DIR = "//developtools/profiler/protos/services" + OHOS_PROTO_GEN = "//out/ohos-arm-release/gen/cpp/developtools/profiler/protos" +} diff --git a/trace_streamer/sdktest.sh b/trace_streamer/sdktest.sh new file mode 100755 index 0000000000000000000000000000000000000000..c485bd0aa1729fca043c1d44d1f5c6ef4c7b00f7 --- /dev/null +++ b/trace_streamer/sdktest.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# 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. +set -e +./build.sh sdkdemotest +rm -rf out/sdkdemotest/*.xml +find out/sdkdemotest -name "*.gcda" -print0 | xargs -0 rm +mkdir -p out/sdkdemotest/data/resource +cp sdkdemotest/resource/* out/sdkdemotest/data/resource/ +cd out/sdkdemotest +./trace_streamer_sdk_ut diff --git a/trace_streamer/src/BUILD.gn b/trace_streamer/src/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..1549f1abcf81e7c20b615b63884f3108bbf3d7f1 --- /dev/null +++ b/trace_streamer/src/BUILD.gn @@ -0,0 +1,222 @@ +# 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("ts.gni") +if (use_wasm) { + import("//gn/wasm.gni") +} +if (use_wasm) { + ohos_source_set("trace_streamer_builtin") { + subsystem_name = "trace_streamer" + part_name = "src" + sources = [] + include_dirs = [] + deps = [] + public_deps = [] + } +} +ohos_source_set("lib") { + subsystem_name = "trace_streamer" + part_name = "lib" + sources = [ "main.cpp" ] + deps = [ + ":trace_streamer_source", + "proto_reader:proto_reader", + ] + include_dirs = [ + "base", + "..", + "trace_streamer", + "filter", + "table", + "trace_data", + "include", + "rpc", + "./", + "parser", + "cfg", + "proto_reader/include", + "//third_party/sqlite/include", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + "//third_party/hiperf/include", + ] + if (!is_pbdecoder) { + include_dirs += [ + "parser/htrace_pbreader_parser", + "parser/htrace_pbreader_parser/htrace_event_parser", + "parser/htrace_pbreader_parser/htrace_cpu_parser", + ] + } else { + include_dirs += [ + "parser/htrace_parser", + "parser/htrace_parser/htrace_event_parser", + "parser/htrace_parser/htrace_cpu_parser", + ] + } + if (with_perf) { + include_dirs += [ + "parser/hiperf_parser", + "//third_party/hiperf/include", + "//third_party/hiperf/include/nonlinux", + "//third_party/hiperf/include/nonlinux/linux", + "//third_party/perf_include/musl", + ] + } + public_deps = [] +} +ohos_source_set("trace_streamer_source") { + subsystem_name = "trace_streamer" + part_name = "trace_streamer_source" + sources = [ + "cfg/trace_streamer_config.cpp", + "cfg/trace_streamer_config.h", + "rpc/http_server.cpp", + "rpc/http_socket.cpp", + "rpc/rpc_server.cpp", + "trace_streamer/trace_streamer_filters.cpp", + "trace_streamer/trace_streamer_filters.h", + "trace_streamer/trace_streamer_selector.cpp", + "trace_streamer/trace_streamer_selector.h", + ] + include_dirs = [ + "base", + "..", + "trace_streamer", + "filter", + "table", + "trace_data", + "include", + "rpc", + "./", + "parser", + "cfg", + "proto_reader/include", + "parser/ebpf_parser", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + ] + if (use_wasm) { + include_dirs += + [ "../prebuilts/emsdk/emsdk/emscripten/cache/sysroot/include" ] + } + if (is_macx && !is_test) { + cflags = [ "-D_XOPEN_SOURCE=600" ] + } + if (is_test) { + include_dirs += [ "../prebuilts/emsdk/emsdk/emscripten/system/include" ] + } + if (!is_pbdecoder) { + include_dirs += [ + "parser/htrace_pbreader_parser", + "parser/htrace_pbreader_parser/htrace_event_parser", + "parser/htrace_pbreader_parser/htrace_cpu_parser", + ] + } else { + include_dirs += [ + "parser/htrace_parser", + "parser/htrace_parser/htrace_event_parser", + "parser/htrace_parser/htrace_cpu_parser", + ] + } + include_dirs += [ + "//third_party/libunwind/include", + "//third_party/libunwind/src", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + ] + + if (with_perf) { + include_dirs += [ + "parser/hiperf_parser", + "//third_party/hiperf/include", + "//third_party/hiperf/include/nonlinux", + "//third_party/hiperf/include/nonlinux/linux", + "//third_party/perf_include/libbpf", + "//third_party/perf_include/musl", + ] + } + deps = [ + "base:base", + "ext:sqliteext", + "filter:filter", + "include:ibase", + "parser:parser", + "table:table", + "trace_data:trace_data", + "//third_party/sqlite:sqlite", + ] + if (with_perf) { + deps += [ "parser/hiperf_parser:hiperf_parser" ] + } + + if (use_wasm) { + sources += [ + "rpc/wasm_func.cpp", + "rpc/wasm_func.h", + ] + } + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } + public_deps = [] +} +if (use_wasm) { + wasm_lib("trace_streamer_builtin_wasm") { + name = "trace_streamer_builtin" + deps = [ ":lib" ] + } +} else { + if (!is_test && !is_fuzz) { + executable("trace_streamer") { + deps = [ ":lib" ] + } + } +} diff --git a/trace_streamer/src/base/BUILD.gn b/trace_streamer/src/base/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..70b8c78329352ba116bfecd8a9a55445c93c2faa --- /dev/null +++ b/trace_streamer/src/base/BUILD.gn @@ -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/ohos.gni") +import("../ts.gni") +ohos_source_set("base") { + subsystem_name = "trace_streamer" + part_name = "trace_streamer_source_base" + deps = [] + public_deps = [ "../include:ibase" ] + include_dirs = [ "../include" ] + sources = [ + "codec_cov.cpp", + "file.cpp", + "log.cpp", + "meta.cpp", + "parting_string.cpp", + "string_help.cpp", + ] + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } +} diff --git a/trace_streamer/src/base/args_set.h b/trace_streamer/src/base/args_set.h new file mode 100644 index 0000000000000000000000000000000000000000..579c2e41ae91aadb99e1717e28ca7949c0ec2bb2 --- /dev/null +++ b/trace_streamer/src/base/args_set.h @@ -0,0 +1,50 @@ +/* + * 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 SRC_TRACE_BASE_ARGS_SET_H +#define SRC_TRACE_BASE_ARGS_SET_H + +#include "ts_common.h" +#include +#include +namespace SysTuning { +namespace TraceStreamer { +class ArgsSet { +public: + ArgsSet() {} + ~ArgsSet() {} + ArgsSet& operator=(const ArgsSet& other) + { + this->valuesMap_ = other.valuesMap_; + this->argSetId_ = other.argSetId_; + this->sliceId_ = other.sliceId_; + this->inserted_ = other.inserted_; + return *this; + } + void AppendArg(DataIndex dataIndex, BaseDataType datatype, uint64_t value) + { + ArgsData data; + data.type = datatype; + data.value = value; + valuesMap_.emplace(dataIndex, data); + } + std::map valuesMap_; + uint32_t argSetId_ = 0; + uint32_t sliceId_ = 0; + bool inserted_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/base/codec_cov.cpp b/trace_streamer/src/base/codec_cov.cpp new file mode 100644 index 0000000000000000000000000000000000000000..342c22e4e4668befde1d061cea655510c19af113 --- /dev/null +++ b/trace_streamer/src/base/codec_cov.cpp @@ -0,0 +1,120 @@ +/* + * 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 "codec_cov.h" + +#include +#ifdef _WIN32 +#include +#endif + +namespace SysTuning { +namespace base { +int32_t PreNum(unsigned char byte) +{ + constexpr uint32_t BITS = 8; + unsigned char mask = 0x80; + int32_t num = 0; + for (uint32_t i = 0; i < BITS; i++) { + if ((byte & mask) == mask) { + mask = mask >> 1; + num++; + } else { + break; + } + } + return num; +} + +bool IsUTF8(const uint8_t* data, int32_t len) +{ + constexpr uint8_t MASK = 0x80; + constexpr uint8_t FIRST_BYTE = 0xc0; + constexpr int32_t TARGET = 2; + int32_t num = 0; + int32_t i = 0; + while (i < len) { + if ((data[i] & MASK) == 0x00) { + i++; + continue; + } + if ((num = PreNum(data[i])) <= TARGET) { + return false; + } + i++; + for (int32_t j = 0; j < num - 1; j++) { + if ((data[i] & FIRST_BYTE) != MASK) { + return false; + } + i++; + } + } + return true; +} + +bool IsGBK(const uint8_t* data, int32_t len) +{ + constexpr int32_t STEP = 2; + constexpr uint8_t ASCII_END = 0x7f; + constexpr uint8_t FIRST_BYTE = 0x81; + constexpr uint8_t FIRST_BYTE_END = 0xfe; + constexpr uint8_t SECOND_BYTE_ONE = 0x40; + constexpr uint8_t SECOND_BYTE_TWO_END = 0xfe; + constexpr uint8_t GBK_MASK = 0xf7; + int32_t i = 0; + while (i < len) { + if (data[i] <= ASCII_END) { + i++; + continue; + } else { + if (data[i] >= FIRST_BYTE && data[i] <= FIRST_BYTE_END && data[i + 1] >= SECOND_BYTE_ONE && + data[i + 1] <= SECOND_BYTE_TWO_END && data[i + 1] != GBK_MASK) { + i += STEP; + continue; + } else { + return false; + } + } + } + return true; +} + +CODING GetCoding(const uint8_t* data, int32_t len) +{ + CODING coding; + if (IsUTF8(data, len)) { + coding = UTF8; + } else if (IsGBK(data, len)) { + coding = GBK; + } else { + coding = UNKOWN; + } + return coding; +} + +#ifdef _WIN32 +std::string GbkToUtf8(const char* srcStr) +{ + int32_t len = MultiByteToWideChar(CP_ACP, 0, srcStr, -1, NULL, 0); + std::unique_ptr wstr = std::make_unique(len + 1); + MultiByteToWideChar(CP_ACP, 0, srcStr, -1, wstr.get(), len); + len = WideCharToMultiByte(CP_UTF8, 0, wstr.get(), -1, NULL, 0, NULL, NULL); + std::unique_ptr str = std::make_unique(len + 1); + WideCharToMultiByte(CP_UTF8, 0, wstr.get(), -1, str.get(), len, NULL, NULL); + return std::string(str.get()); +} +#endif +} // namespace base +} // namespace SysTuning diff --git a/trace_streamer/src/base/double_map.h b/trace_streamer/src/base/double_map.h new file mode 100644 index 0000000000000000000000000000000000000000..7422a92df3976a880fb744752d0bacb2810b838a --- /dev/null +++ b/trace_streamer/src/base/double_map.h @@ -0,0 +1,100 @@ +/* + * 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 SRC_TRACE_BASE_DOUBLEMAP_H +#define SRC_TRACE_BASE_DOUBLEMAP_H + +#include + +template +class DoubleMap { +public: + DoubleMap(T3 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T3 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + auto hookId = (*streamIdHookidMap).second.find(t2); + if (hookId == (*streamIdHookidMap).second.end()) { + (*streamIdHookidMap).second.emplace(std::make_pair(t2, t3)); + } else { + (*streamIdHookidMap).second.at(t2) = t3; + } + } else { + std::map mm = {{t2, t3}}; + internalMap_.emplace(std::make_pair(t1, mm)); + } + } + T3 Find(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + auto hookId = (*streamIdHookidMap).second.find(t2); + if (hookId == (*streamIdHookidMap).second.end()) { + return invalidValue_; + } else { + return hookId->second; + } + } else { + return invalidValue_; + } + } + const std::map* Find(T1 t1) const + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return &streamIdHookidMap->second; + } + return nullptr; + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + auto hookId = (*streamIdHookidMap).second.find(t2); + if (hookId != (*streamIdHookidMap).second.end()) { + (*streamIdHookidMap).second.erase(hookId); + } + } + } + bool Empty() + { + return internalMap_.size() == 0 ? true : false; + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T3 invalidValue_; +}; + +#endif // DOUBLEMAP_H diff --git a/trace_streamer/src/base/file.cpp b/trace_streamer/src/base/file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13e1e967bce4dd9c9884b5c069fa3cd2f385f796 --- /dev/null +++ b/trace_streamer/src/base/file.cpp @@ -0,0 +1,79 @@ +/* + * 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 "file.h" +#include +#include +#include +#include +#include + +#include "log.h" +#if defined(_WIN32) +#include +#include +#include +#endif + +namespace SysTuning { +namespace base { +static TraceParserStatus g_status = TRACE_PARSER_ABNORMAL; + +void SetAnalysisResult(TraceParserStatus stat) +{ + g_status = stat; +} +TraceParserStatus GetAnalysisResult() +{ + return g_status; +} + +ssize_t Read(int32_t fd, uint8_t* dst, size_t dstSize) +{ +#if defined(_WIN32) + return _read(fd, dst, static_cast(dstSize)); +#else + ssize_t ret = -1; + do { + ret = read(fd, dst, dstSize); + } while (ret == -1 && errno == EINTR); + return ret; +#endif +} +int32_t OpenFile(const std::string& path, int32_t flags, uint32_t mode) +{ + TS_ASSERT((flags & O_CREAT) == 0 || mode != kFileModeInvalid); +#if defined(_WIN32) + int32_t fd(_open(path.c_str(), flags | O_BINARY, mode)); +#else + int32_t fd(open(path.c_str(), flags | O_CLOEXEC, mode)); +#endif + return fd; +} + +std::string GetExecutionDirectoryPath() +{ + char currPath[1024] = {0}; +#if defined(_WIN32) + ::GetModuleFileNameA(NULL, currPath, MAX_PATH); + (strrchr(currPath, '\\'))[1] = 0; +#else + readlink("/proc/self/exe", currPath, sizeof(currPath) - 1); +#endif + std::string str(currPath); + return str.substr(0, str.find_last_of('/')); +} +} // namespace base +} // namespace SysTuning diff --git a/trace_streamer/src/base/log.cpp b/trace_streamer/src/base/log.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d167a90cb4f5f1678b59e23518ddce9873b89d1 --- /dev/null +++ b/trace_streamer/src/base/log.cpp @@ -0,0 +1,17 @@ +/* + * 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 "log.h" +bool g_cleanMode = false; diff --git a/trace_streamer/src/base/meta.cpp b/trace_streamer/src/base/meta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b2e26b731ad80022532790863e410d6c2cf73ff --- /dev/null +++ b/trace_streamer/src/base/meta.cpp @@ -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. + */ +#include "meta.h" +size_t g_loadSize = 0; +std::string TRACE_STREAM_VERSION = "3.2.2"; // version +std::string TRACE_STREAM_PUBLISHVERSION = "2023/5/7"; // publish datetime diff --git a/trace_streamer/src/base/meta.h b/trace_streamer/src/base/meta.h new file mode 100644 index 0000000000000000000000000000000000000000..d36b0469b04c1d5f22369f37a8ce89598b377840 --- /dev/null +++ b/trace_streamer/src/base/meta.h @@ -0,0 +1,23 @@ +/* + * 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 META_H +#define META_H +#include +#include +extern size_t g_loadSize; +extern std::string TRACE_STREAM_VERSION; // version +extern std::string TRACE_STREAM_PUBLISHVERSION; // publish datetime +#endif diff --git a/trace_streamer/src/base/optimize.h b/trace_streamer/src/base/optimize.h new file mode 100644 index 0000000000000000000000000000000000000000..e44a6bdf4e3f42443f27cc966ccb7fdcb87db0b6 --- /dev/null +++ b/trace_streamer/src/base/optimize.h @@ -0,0 +1,33 @@ +/* + * 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 SRC_TRACE_BASE_OPTIMIZE_H +#define SRC_TRACE_BASE_OPTIMIZE_H + +#if defined(__GNUC__) || defined(__clang__) +#define TS_LIKELY(_x) __builtin_expect(!!(_x), 1) +#define TS_UNLIKELY(_x) __builtin_expect(!!(_x), 0) +#else +#define TS_LIKELY(_x) (_x) +#define TS_UNLIKELY(_x) (_x) +#endif +#if defined(__clang__) +#define TS_INLINE __attribute__((__always_inline__)) +#define TS_NO_INLINE __attribute__((__noinline__)) +#else +#define TS_INLINE +#define TS_NO_INLINE +#endif +#endif diff --git a/trace_streamer/src/base/parting_string.cpp b/trace_streamer/src/base/parting_string.cpp new file mode 100644 index 0000000000000000000000000000000000000000..adff0f934288b77422809453d176a5906ff3cff2 --- /dev/null +++ b/trace_streamer/src/base/parting_string.cpp @@ -0,0 +1,57 @@ +/* + * 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 "parting_string.h" +namespace SysTuning { +namespace base { +PartingString::PartingString(std::string str, char delimiter) : str_(std::move(str)), delimiter_(delimiter) +{ + begin_ = str_.begin(); + end_ = str_.end(); + cur_ = nullptr; +} + +bool PartingString::Next() +{ + while (begin_ != end_) { + if (*begin_ == delimiter_) { + begin_++; + continue; + } + + cur_ = begin_.base(); + do { + if (*begin_ == delimiter_) { + *(begin_++) = '\0'; + break; + } + if (*begin_ == '\0') { + begin_ = end_; + break; + } + } while (begin_++ != end_); + + if (*cur_) { + return true; + } + + begin_++; + } + + cur_ = nullptr; + return false; +} +} // namespace base +} // namespace SysTuning diff --git a/trace_streamer/src/base/quatra_map.h b/trace_streamer/src/base/quatra_map.h new file mode 100644 index 0000000000000000000000000000000000000000..cefafcb95d3e56b3f3b9a9edae528540c134e84c --- /dev/null +++ b/trace_streamer/src/base/quatra_map.h @@ -0,0 +1,90 @@ +/* + * 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 SRC_TRACE_BASE_QUATRAMAP_H +#define SRC_TRACE_BASE_QUATRAMAP_H + +#include "triple_map.h" + +template +class QuatraMap { +public: + QuatraMap(T5 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T5 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Insert(t2, t3, t4, t5); + } else { + TripleMap mm(invalidValue_); + mm.Insert(t2, t3, t4, t5); + internalMap_.emplace(std::make_pair(t1, mm)); + } + } + T5 Find(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return (*streamIdHookidMap).second.Find(t2, t3, t4); + } else { + return invalidValue_; + } + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2); + } + } + void Erase(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3); + } + } + void Erase(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3, t4); + } + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T5 invalidValue_; +}; + +#endif // SRC_TRACE_BASE_QUATRAMAP_H diff --git a/trace_streamer/src/base/securec.h b/trace_streamer/src/base/securec.h new file mode 100644 index 0000000000000000000000000000000000000000..6a7687067cd782d6687e33f0f4541e58db671f2b --- /dev/null +++ b/trace_streamer/src/base/securec.h @@ -0,0 +1,22 @@ +/* + * 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 SRC_TRACE_BASE_SECUREC_H +#define SRC_TRACE_BASE_SECUREC_H + +#include +#include +#define EOK 0 +#include "string_help.h" +#endif // SRC_TRACE_BASE_SECUREC_H diff --git a/trace_streamer/src/base/string_help.cpp b/trace_streamer/src/base/string_help.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07f83c3e425ac9b92a9b7af86cd6747439b7c46d --- /dev/null +++ b/trace_streamer/src/base/string_help.cpp @@ -0,0 +1,111 @@ +/* + * 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 "string_help.h" +#include +#include +#include +#include +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +#if !is_mingw +int32_t memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize) +{ + if (srcSize > destSize || src == nullptr || dest == nullptr) { + return -1; + } else { + if (!memcpy(dest, src, srcSize)) { + printf("memcpy fail\n"); + return -1; + } + } + return 0; +} +int32_t sscanf_s(const char* buffer, const char* format, ...) +{ + va_list ap; + __builtin_va_start(ap, format); + int32_t ret = scanf(buffer, format, ap); + __builtin_va_end(ap); + return ret; +} + +int32_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count) +{ + (void*)strncpy(strDest, strSrc, destMax); + return destMax; +} +#endif +void* memset_s(void* dest, size_t destSize, int32_t ch, size_t n) +{ + UNUSED(destSize); + UNUSED(ch); + return memset(dest, 0, n); +} + +int32_t snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...) +{ + UNUSED(count); + int32_t ret; + va_list ap; + __builtin_va_start(ap, format); + ret = vsnprintf(strDest, destMax, format, ap); + __builtin_va_end(ap); + return ret; +} + +int32_t sprintf_s(char* strDest, size_t destMax, const char* format, ...) +{ + va_list ap; + __builtin_va_start(ap, format); + int32_t ret = vsnprintf(strDest, destMax, format, ap); + __builtin_va_end(ap); + return ret; +} + +const char* GetDemangleSymbolIndex(const char* mangled) +{ + int status = 0; + auto demangle = abi::__cxa_demangle(mangled, nullptr, nullptr, &status); + if (status) { // status != 0 failed + return mangled; + } else { + return demangle; + } +} +int GetProcessorNumFromString(char *str) +{ + int processorNum = 0; + int lastNum = -1; + char *s = str; + while (*s != '\0') { + if (isdigit(*s)) { + int currentNum = strtol(s, &s, 10); + if (lastNum == -1) { + processorNum++; + } else { + processorNum += currentNum - lastNum; + } + lastNum = currentNum; + } else { + if (*s == ',') { + lastNum = -1; + } + s++; + } + } + return processorNum; +} diff --git a/trace_streamer/src/base/string_help.h b/trace_streamer/src/base/string_help.h new file mode 100644 index 0000000000000000000000000000000000000000..75ac88638858ef7ee8bdd553e442597ab8189954 --- /dev/null +++ b/trace_streamer/src/base/string_help.h @@ -0,0 +1,31 @@ +/* + * 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 SRC_TRACE_BASE_STRINGHELP_H +#define SRC_TRACE_BASE_STRINGHELP_H + +#include +#include +#include +#if !is_mingw +int32_t memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize); +int32_t sscanf_s(const char* buffer, const char* format, ...); +int32_t strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count); +int32_t sprintf_s(char* strDest, size_t destMax, const char* format, ...); +#endif +void* memset_s(void* dest, size_t destSize, int32_t ch, size_t n); +int32_t snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...); +const char* GetDemangleSymbolIndex(const char* mangled); +int GetProcessorNumFromString(char *str); +#endif // SRC_TRACE_BASE_STRINGHELP_H diff --git a/trace_streamer/src/base/triple_map.h b/trace_streamer/src/base/triple_map.h new file mode 100644 index 0000000000000000000000000000000000000000..b815d4a4074e86f776a5eca0399021496459b992 --- /dev/null +++ b/trace_streamer/src/base/triple_map.h @@ -0,0 +1,83 @@ +/* + * 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 SRC_TRACE_BASE_TRIPLEMAP_H +#define SRC_TRACE_BASE_TRIPLEMAP_H + +#include "double_map.h" + +template +class TripleMap { +public: + TripleMap(T4 invalidValue) + { + invalidValue_ = invalidValue; + } + void SetInvalidRet(T4 invalidValue) + { + invalidValue_ = invalidValue; + } + void Insert(T1 t1, T2 t2, T3 t3, T4 t4) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Insert(t2, t3, t4); + } else { + DoubleMap mm(invalidValue_); + mm.Insert(t2, t3, t4); + internalMap_.emplace(std::make_pair(t1, mm)); + } + } + T4 Find(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + return (*streamIdHookidMap).second.Find(t2, t3); + } else { + return invalidValue_; + } + } + void Erase(T1 t1) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + internalMap_.erase(streamIdHookidMap); + } + } + void Erase(T1 t1, T2 t2) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2); + } + } + void Erase(T1 t1, T2 t2, T3 t3) + { + auto streamIdHookidMap = internalMap_.find(t1); + if (streamIdHookidMap != internalMap_.end()) { + (*streamIdHookidMap).second.Erase(t2, t3); + } + } + void Clear() + { + internalMap_.clear(); + } + +private: + std::map> internalMap_; + T4 invalidValue_; +}; + +#endif // SRC_TRACE_BASE_TRIPLEMAP_H diff --git a/trace_streamer/src/base/ts_common.h b/trace_streamer/src/base/ts_common.h new file mode 100644 index 0000000000000000000000000000000000000000..856f4376b58863aa55460089ff3c42026976eb52 --- /dev/null +++ b/trace_streamer/src/base/ts_common.h @@ -0,0 +1,163 @@ +/* + * 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 SRC_TRACE_BASE_TS_COMMON_H +#define SRC_TRACE_BASE_TS_COMMON_H + +#include +#include +#include +#include + +const uint64_t INVALID_UTID = std::numeric_limits::max(); +const uint64_t INVALID_UINT64 = std::numeric_limits::max(); +const uint64_t MAX_UINT32 = std::numeric_limits::max(); +const uint64_t MAX_UINT64 = std::numeric_limits::max(); +const uint32_t INVALID_UINT8 = std::numeric_limits::max(); +const uint32_t INVALID_UINT16 = std::numeric_limits::max(); +const uint32_t INVALID_UINT32 = std::numeric_limits::max(); +const uint32_t INVALID_INT32 = std::numeric_limits::max(); +const int64_t INVALID_INT64 = std::numeric_limits::max(); +const uint64_t INVALID_DATAINDEX = std::numeric_limits::max(); +const uint64_t INVALID_CALL_CHAIN_ID = std::numeric_limits::max(); +const size_t MAX_SIZE_T = std::numeric_limits::max(); +const uint32_t INVALID_ID = std::numeric_limits::max(); +const uint64_t SEC_TO_NS = 1000 * 1000 * 1000; +const int32_t STR_DEFAULT_LEN = -1; +const auto INVALID_CPU = INVALID_UINT32; +const auto INVALID_TIME = INVALID_UINT64; +enum BuiltinClocks { + TS_CLOCK_UNKNOW = 0, + TS_CLOCK_BOOTTIME = 1, + TS_CLOCK_REALTIME = 2, + TS_CLOCK_REALTIME_COARSE = 3, + TS_MONOTONIC = 4, + TS_MONOTONIC_COARSE = 5, + TS_MONOTONIC_RAW = 6, +}; + +enum RefType { + K_REF_NO_REF = 0, + K_REF_ITID = 1, + K_REF_CPUID = 2, + K_REF_IRQ = 3, + K_REF_SOFT_IRQ = 4, + K_REF_IPID = 5, + K_REF_ITID_LOOKUP_IPID = 6, + K_REF_MAX +}; + +enum TraceFileType { TRACE_FILETYPE_BY_TRACE, TRACE_FILETYPE_H_TRACE, TRACE_FILETYPE_SYSEVENT, TRACE_FILETYPE_UN_KNOW }; + +enum EndState { + // (R) ready state or running state, the process is ready to run, but not necessarily occupying the CPU + TASK_RUNNABLE = 0, + // (S) Indicates that the process is in light sleep, waiting for the resource state, and can respond to the signal. + // Generally, the process actively sleeps into 'S' state. + TASK_INTERRUPTIBLE = 1, + // (D) Indicates that the process is in deep sleep, waiting for resources, and does not respond to signals. + // Typical scenario: process acquisition semaphore blocking. + TASK_UNINTERRUPTIBLE = 2, + TASK_UNINTERRUPTIBLE_IO = 21, + TASK_UNINTERRUPTIBLE_NIO = 22, + // (Running) Indicates that the thread is running + TASK_RUNNING = 3, + // (I) Thread in interrupt state + TASK_INTERRUPTED = 4, + // (T) Task being traced + TASK_TRACED = 8, + // (X) Exit status, the process is about to be destroyed. + TASK_EXIT_DEAD = 16, + // (Z) Zombie state + TASK_ZOMBIE = 32, + // (I) clone thread + TASK_CLONE = 64, + // (K) Process killed + TASK_KILLED = 128, + // (DK) + TASK_DK = 130, + TASK_DK_IO = 131, + TASK_DK_NIO = 132, + // the process is being debug now + TASK_TRACED_KILL = 136, + // (W) The process is in a deep sleep state and will be killed directly after waking up + TASK_WAKEKILL = 256, + TASK_PARKED = 512, + // (R+) Process groups in the foreground + TASK_FOREGROUND = 2048, + TASK_MAX = 4096, + TASK_INVALID = 9999 +}; +enum TSLogLevel { + TS_DEBUG = 68, // Debug + TS_ERROR = 69, // Error + TS_INFO = 73, // Info + TS_VERBOSE = 86, // Verbose + TS_WARN = 87 // Warn +}; +enum SchedWakeType { + SCHED_WAKING = 0, // sched_waking + SCHED_WAKEUP = 1, // sched_wakeup +}; +#ifndef IS_PBDECODER +enum DataSourceType { + DATA_SOURCE_TYPE_TRACE, + DATA_SOURCE_TYPE_MEM, + DATA_SOURCE_TYPE_HILOG, + DATA_SOURCE_TYPE_NATIVEHOOK, + DATA_SOURCE_TYPE_NATIVEHOOK_CONFIG, + DATA_SOURCE_TYPE_FPS, + DATA_SOURCE_TYPE_NETWORK, + DATA_SOURCE_TYPE_DISKIO, + DATA_SOURCE_TYPE_CPU, + DATA_SOURCE_TYPE_PROCESS, + DATA_SOURCE_TYPE_HISYSEVENT, + DATA_SOURCE_TYPE_HISYSEVENT_CONFIG, + DATA_SOURCE_TYPE_JSMEMORY, + DATA_SOURCE_TYPE_JSMEMORY_CONFIG +}; +#else +enum DataSourceType { + DATA_SOURCE_TYPE_TRACE, + DATA_SOURCE_TYPE_MEM, + DATA_SOURCE_TYPE_HILOG, + DATA_SOURCE_TYPE_ALLOCATION, + DATA_SOURCE_TYPE_FPS, + DATA_SOURCE_TYPE_NETWORK, + DATA_SOURCE_TYPE_DISKIO, + DATA_SOURCE_TYPE_CPU, + DATA_SOURCE_TYPE_PROCESS, + DATA_SOURCE_TYPE_HISYSEVENT, + DATA_SOURCE_TYPE_HISYSEVENT_CONFIG +}; +#endif +using DataIndex = uint64_t; +using TableRowId = int32_t; +using InternalPid = uint32_t; +using InternalTid = uint32_t; +using InternalTime = uint64_t; +using FilterId = uint32_t; +using InternalCpu = uint32_t; // how many cpus? could change to int8_t? + +enum BaseDataType { BASE_DATA_TYPE_INT, BASE_DATA_TYPE_STRING, BASE_DATA_TYPE_DOUBLE, BASE_DATA_TYPE_BOOLEAN }; +namespace SysTuning { +namespace TraceStreamer { +struct ArgsData { + BaseDataType type; + int64_t value; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/cfg/trace_streamer_config.cpp b/trace_streamer/src/cfg/trace_streamer_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9931296ad6555691898056c8062bec52ffe78e7f --- /dev/null +++ b/trace_streamer/src/cfg/trace_streamer_config.cpp @@ -0,0 +1,1214 @@ +/* + * 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 "trace_streamer_config.h" +#include "log.h" +namespace SysTuning { +namespace TraceCfg { +TraceStreamerConfig::TraceStreamerConfig() +{ + InitEventNameMap(); + eventErrorDescMap_ = { + {STAT_EVENT_RECEIVED, TRACE_STAT_TYPE_RECEIVED_DESC}, + {STAT_EVENT_DATA_LOST, TRACE_STAT_TYPE_LOST_DESC}, + {STAT_EVENT_NOTMATCH, TRACE_STAT_TYPE_NOTMATCH_DESC}, + {STAT_EVENT_NOTSUPPORTED, TRACE_STAT_TYPE_NOTSUPPORTED_DESC}, + {STAT_EVENT_DATA_INVALID, TRACE_STAT_TYPE_DATA_INVALID_DESC}, + }; + serverityLevelDescMap_ = { + {STAT_SEVERITY_LEVEL_INFO, STAT_SEVERITY_LEVEL_INFO_DESC}, + {STAT_SEVERITY_LEVEL_WARN, STAT_SEVERITY_LEVEL_WARN_DESC}, + {STAT_SEVERITY_LEVEL_ERROR, STAT_SEVERITY_LEVEL_ERROR_DESC}, + {STAT_SEVERITY_LEVEL_FATAL, STAT_SEVERITY_LEVEL_FATAL_DESC}, + }; + memNameMap_ = { + {MEM_VM_SIZE, MEM_INFO_VM_SIZE_DESC}, {MEM_VM_LOCKED, MEM_INFO_LOCKED_DESC}, + {MEM_VM_RSS, MEM_INFO_RSS_DESC}, {MEM_VM_ANON, MEM_INFO_RSS_ANON_DESC}, + {MEM_RSS_FILE, MEM_INFO_RSS_FILE_DESC}, {MEM_RSS_SHMEM, MEM_INFO_RSS_SCHEM_DESC}, + {MEM_VM_SWAP, MEM_INFO_SWAP_DESC}, {MEM_VM_LOCKED, MEM_INFO_VIRT_DESC}, + {MEM_VM_HWM, MEM_INFO_HWM_DESC}, {MEM_OOM_SCORE_ADJ, MEM_INFO_SCORE_ADJ_DESC}, + }; + + InitSysMemMap(); + InitSysVmemMap(); + InitSecurityMap(); + if (eventNameMap_.size() != TRACE_EVENT_MAX) { + TS_LOGF("eventNameMap_.size() max be %d, logic error", TRACE_EVENT_MAX); + } + if (eventErrorDescMap_.size() != STAT_EVENT_MAX) { + TS_LOGF("eventErrorDescMap_.size() max be %d, logic error", STAT_EVENT_MAX); + } + if (serverityLevelDescMap_.size() != STAT_SEVERITY_LEVEL_MAX) { + TS_LOGF("serverityLevelDescMap_.size() max be %d, logic error", STAT_SEVERITY_LEVEL_MAX); + } + if (eventParserStatSeverityDescMap_.size() != TRACE_EVENT_MAX) { + TS_LOGF("eventParserStatSeverityDescMap_.size() max be %d, logic error", TRACE_EVENT_MAX); + } + if (memNameMap_.size() != MEM_MAX) { + TS_LOGF("memNameMap_.size() max be %d, logic error", MEM_MAX); + } + for (int32_t i = TRACE_EVENT_START; i < TRACE_EVENT_MAX; i++) { + if (eventParserStatSeverityDescMap_.at(static_cast(i)).size() != STAT_EVENT_MAX) { + TS_LOGF("every item in eventParserStatSeverityDescMap_ max be %d, logic error", STAT_EVENT_MAX); + } + } +} + +void TraceStreamerConfig::PrintInfo() const +{ + printf("---all kind of trace event info---\n"); + for (auto itor = eventNameMap_.begin(); itor != eventNameMap_.end(); itor++) { + printf("%s\n", itor->second.c_str()); + } + printf("\n"); + printf("---subdir of process mem info---\n"); + for (auto itor = memNameMap_.begin(); itor != memNameMap_.end(); itor++) { + printf("%s\n", itor->second.c_str()); + } + printf("\n"); + printf("---subdir of sys mem info---\n"); + for (auto itor = sysMemNameMap_.begin(); itor != sysMemNameMap_.end(); itor++) { + printf("%s\n", itor->second.c_str()); + } + printf("\n"); + printf("---subdir of sys vmem info---\n"); + for (auto itor = sysVirtualMemNameMap_.begin(); itor != sysVirtualMemNameMap_.end(); itor++) { + printf("%s\n", itor->second.c_str()); + } + printf("\n"); +} + +uint32_t TraceStreamerConfig::GetStateValue(uint32_t state) const +{ + return (state > CPU_IDEL_INVALID_VALUE ? 0 : (state + 1)); +} + +void TraceStreamerConfig::InitEventNameMap() +{ + eventNameMap_ = {{TRACE_EVENT_BINDER_TRANSACTION, TRACE_ACTION_BINDER_TRANSACTION}, + {TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, TRACE_ACTION_BINDER_TRANSACTION_RECEIVED}, + {TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, TRACE_ACTION_BINDER_TRANSACTION_ALLOC_BUF}, + {TRACE_EVENT_BINDER_TRANSACTION_LOCK, TRACE_ACTION_BINDER_TRANSACTION_LOCK}, + {TRACE_EVENT_BINDER_TRANSACTION_LOCKED, TRACE_ACTION_BINDER_TRANSACTION_LOCKED}, + {TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, TRACE_ACTION_BINDER_TRANSACTION_UNLOCK}, + {TRACE_EVENT_SCHED_SWITCH, TRACE_ACTION_SCHED_SWITCH}, + {TRACE_EVENT_SCHED_BLOCKED_REASON, TRACE_ACTION_SCHED_BLOCKED_REASON}, + {TRACE_EVENT_TASK_RENAME, TRACE_ACTION_TASK_RENAME}, + {TRACE_EVENT_TASK_NEWTASK, TRACE_ACTION_TASK_NEWTASK}, + {TRACE_EVENT_TRACING_MARK_WRITE, TRACE_ACTION_TRACING_MARK_WRITE}, + {TRACE_EVENT_PRINT, TRACE_ACTION_PRINT}, + {TRACE_EVENT_SCHED_WAKEUP, TRACE_ACTION_SCHED_WAKEUP}, + {TRACE_EVENT_SCHED_WAKING, TRACE_ACTION_SCHED_WAKING}, + {TRACE_EVENT_CPU_IDLE, TRACE_ACTION_CPU_IDLE}, + {TRACE_EVENT_CPU_FREQUENCY, TRACE_ACTION_CPU_FREQUENCY}, + {TRACE_EVENT_CPU_FREQUENCY_LIMITS, TRACE_ACTION_CPU_FREQUENCY_LIMITS}, + {TRACE_EVENT_SUSPEND_RESUME, TRACE_ACTION_SUSPEND_RESUME}, + {TRACE_EVENT_WORKQUEUE_EXECUTE_START, TRACE_ACTION_WORKQUEUE_EXECUTE_START}, + {TRACE_EVENT_WORKQUEUE_EXECUTE_END, TRACE_ACTION_WORKQUEUE_EXECUTE_END}, + {TRACE_EVENT_CLOCK_SET_RATE, TRACE_ACTION_CLOCK_SET_RATE}, + {TRACE_EVENT_CLOCK_ENABLE, TRACE_ACTION_CLOCK_ENABLE}, + {TRACE_EVENT_CLOCK_DISABLE, TRACE_ACTION_CLOCK_DISABLE}, + {TRACE_EVENT_CLK_SET_RATE, TRACE_ACTION_CLK_SET_RATE}, + {TRACE_EVENT_CLK_ENABLE, TRACE_ACTION_CLK_ENABLE}, + {TRACE_EVENT_CLK_DISABLE, TRACE_ACTION_CLK_DISABLE}, + {TRACE_EVENT_SYS_ENTRY, TRACE_ACTION_SYS_ENTRY}, + {TRACE_EVENT_SYS_EXIT, TRACE_ACTION_SYS_EXIT}, + {TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, TRACE_ACTION_OOM_SCORE_ADJ_UPDATE}, + {TRACE_EVENT_REGULATOR_SET_VOLTAGE, TRACE_ACTION_REGULATOR_SET_VOLTAGE}, + {TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE, TRACE_ACTION_REGULATOR_SET_VOLTAGE_COMPLETE}, + {TRACE_EVENT_REGULATOR_DISABLE, TRACE_ACTION_REGULATOR_DISABLE}, + {TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, TRACE_ACTION_REGULATOR_DISABLE_COMPLETE}, + {TRACE_EVENT_IPI_ENTRY, TRACE_ACTION_IPI_ENTRY}, + {TRACE_EVENT_IPI_EXIT, TRACE_ACTION_IPI_EXIT}, + {TRACE_EVENT_IRQ_HANDLER_ENTRY, TRACE_ACTION_IRQ_HANDLER_ENTRY}, + {TRACE_EVENT_IRQ_HANDLER_EXIT, TRACE_ACTION_IRQ_HANDLER_EXIT}, + {TRACE_EVENT_SOFTIRQ_RAISE, TRACE_ACTION_SOFTIRQ_RAISE}, + {TRACE_EVENT_SOFTIRQ_ENTRY, TRACE_ACTION_SOFTIRQ_ENTRY}, + {TRACE_EVENT_SOFTIRQ_EXIT, TRACE_ACTION_SOFTIRQ_EXIT}, + {TRACE_EVENT_SCHED_WAKEUP_NEW, TRACE_ACTION_SCHED_WAKEUP_NEW}, + {TRACE_EVENT_PROCESS_EXIT, TRACE_ACTION_PROCESS_EXIT}, + {TRACE_EVENT_PROCESS_FREE, TRACE_ACTION_PROCESS_FREE}, + {TRACE_EVENT_CLOCK_SYNC, TRACE_ACTION_CLOCK_SYNC}, + {TRACE_EVENT_SIGNAL_GENERATE, TRACE_ACTION_SIGNAL_GENERATE}, + {TRACE_EVENT_SIGNAL_DELIVER, TRACE_ACTION_SIGNAL_DELIVER}, + {TRACE_EVENT_BLOCK_BIO_BACKMERGE, TRACE_ACTION_BLOCK_BIO_BACKMERGE}, + {TRACE_EVENT_BLOCK_BIO_BOUNCE, TRACE_ACTION_BLOCK_BIO_BOUNCE}, + {TRACE_EVENT_BLOCK_BIO_COMPLETE, TRACE_ACTION_BLOCK_BIO_COMPLETE}, + {TRACE_EVENT_BLOCK_BIO_FRONTMERGE, TRACE_ACTION_BLOCK_BIO_FRONTMERGE}, + {TRACE_EVENT_BLOCK_BIO_QUEUE, TRACE_ACTION_BLOCK_BIO_QUEUE}, + {TRACE_EVENT_BLOCK_BIO_REMAP, TRACE_ACTION_BLOCK_BIO_REMAP}, + {TRACE_EVENT_BLOCK_DIRTY_BUFFER, TRACE_ACTION_BLOCK_DIRTY_BUFFER}, + {TRACE_EVENT_BLOCK_GETRQ, TRACE_ACTION_BLOCK_GETRQ}, + {TRACE_EVENT_BLOCK_PLUG, TRACE_ACTION_BLOCK_PLUG}, + {TRACE_EVENT_BLOCK_RQ_COMPLETE, TRACE_ACTION_BLOCK_RQ_COMPLETE}, + {TRACE_EVENT_BLOCK_RQ_INSERT, TRACE_ACTION_BLOCK_RQ_INSERT}, + {TRACE_EVENT_BLOCK_RQ_REMAP, TRACE_ACTION_BLOCK_RQ_REMAP}, + {TRACE_EVENT_BLOCK_RQ_ISSUE, TRACE_ACTION_BLOCK_RQ_ISSUE}, + {TRACE_EVENT_OTHER, TRACE_ACTION_OTHER}, + {TRACE_MEMORY, TRACE_ACTION_MEMORY}, + {TRACE_SYS_MEMORY, TRACE_ACTION_SYS_MEMORY}, + {TRACE_SYS_VIRTUAL_MEMORY, TRACE_ACTION_SYS_VIRTUAL_MEMORY}, + {TRACE_DISKIO, TRACE_ACTION_DISKIO}, + {TRACE_PROCESS, TRACE_ACTION_PROCESS}, + {TRACE_CPU_USAGE, TRACE_ACTION_CPU_USAGE}, + {TRACE_NETWORK, TRACE_ACTION_NETWORK}, + {TRACE_JS_MEMORY, TRACE_ACTION_JS_MEMORY}, + {TRACE_PERF, TRACE_ACTION_PERF}, + {TRACE_HILOG, TRACE_ACTION_HILOG}, + {TRACE_HIDUMP_FPS, TRACE_ACTION_HIDUMP_FPS}, + {TRACE_NATIVE_HOOK_MALLOC, TRACE_ACTION_NATIVE_HOOK_MALLOC}, + {TRACE_NATIVE_HOOK_FREE, TRACE_ACTION_NATIVE_HOOK_FREE}, + {TRACE_NATIVE_HOOK_MMAP, TRACE_ACTION_NATIVE_HOOK_MMAP}, + {TRACE_NATIVE_HOOK_MUNMAP, TRACE_ACTION_NATIVE_HOOK_MUNMAP}, + {TRACE_NATIVE_HOOK_RECORD_STATISTICS, TRACE_ACTION_NATIVE_HOOK_RECORD_STATISTICS}, + {TRACE_HISYSEVENT, TRACE_ACTION_HISYS_EVENT}, + {TRACE_SMAPS, TRACE_ACTION_SMAPS}, + {TRACE_VSYNC, TRACE_ACTION_VSYNC}, + {TRACE_ONVSYNC, TRACE_ACTION_ONVSYNC}, + {TRACE_FRAMEQUEUE, TRACE_ACTION_FRAMEQUEUE}, + {TRACE_EVENT_EBPF, TRACE_ACTION_EBPF}, + {TRACE_EVENT_EBPF_FILE_SYSTEM, TRACE_ACTION_EBPF_FILE_SYSTEM}, + {TRACE_EVENT_EBPF_PAGED_MEMORY, TRACE_ACTION_EBPF_PAGED_MEMORY}, + {TRACE_EVENT_EBPF_BIO_LATENCY, TRACE_ACTION_EBPF_BIO_LATENCY}}; +} +void TraceStreamerConfig::InitSysMemMap() +{ + sysMemNameMap_ = {{SysMeminfoType::PMEM_UNSPECIFIED, SYS_MEMINFO_UNSPECIFIED_DESC}, + {SysMeminfoType::PMEM_MEM_TOTAL, SYS_MEMINFO_MEM_TOTAL_DESC}, + {SysMeminfoType::PMEM_MEM_FREE, SYS_MEMINFO_MEM_FREE_DESC}, + {SysMeminfoType::PMEM_MEM_AVAILABLE, SYS_MEMINFO_MEM_AVAILABLE_DESC}, + {SysMeminfoType::PMEM_BUFFERS, SYS_MEMINFO_BUFFERS_DESC}, + {SysMeminfoType::PMEM_CACHED, SYS_MEMINFO_CACHED_DESC}, + {SysMeminfoType::PMEM_SWAP_CACHED, SYS_MEMINFO_SWAP_CACHED_DESC}, + {SysMeminfoType::PMEM_ACTIVE, SYS_MEMINFO_ACTIVE_DESC}, + {SysMeminfoType::PMEM_INACTIVE, SYS_MEMINFO_INACTIVE_DESC}, + {SysMeminfoType::PMEM_ACTIVE_ANON, SYS_MEMINFO_ACTIVE_ANON_DESC}, + {SysMeminfoType::PMEM_INACTIVE_ANON, SYS_MEMINFO_INACTIVE_ANON_DESC}, + {SysMeminfoType::PMEM_ACTIVE_FILE, SYS_MEMINFO_ACTIVE_FILE_DESC}, + {SysMeminfoType::PMEM_INACTIVE_FILE, SYS_MEMINFO_INACTIVE_FILE_DESC}, + {SysMeminfoType::PMEM_UNEVICTABLE, SYS_MEMINFO_UNEVICTABLE_DESC}, + {SysMeminfoType::PMEM_MLOCKED, SYS_MEMINFO_MLOCKED_DESC}, + {SysMeminfoType::PMEM_SWAP_TOTAL, SYS_MEMINFO_SWAP_TOTAL_DESC}, + {SysMeminfoType::PMEM_SWAP_FREE, SYS_MEMINFO_SWAP_FREE_DESC}, + {SysMeminfoType::PMEM_DIRTY, SYS_MEMINFO_DIRTY_DESC}, + {SysMeminfoType::PMEM_WRITEBACK, SYS_MEMINFO_WRITEBACK_DESC}, + {SysMeminfoType::PMEM_ANON_PAGES, SYS_MEMINFO_ANON_PAGES_DESC}, + {SysMeminfoType::PMEM_MAPPED, SYS_MEMINFO_MAPPED_DESC}, + {SysMeminfoType::PMEM_SHMEM, SYS_MEMINFO_SHMEM_DESC}, + {SysMeminfoType::PMEM_SLAB, SYS_MEMINFO_SLAB_DESC}, + {SysMeminfoType::PMEM_SLAB_RECLAIMABLE, SYS_MEMINFO_SLAB_RECLAIMABLE_DESC}, + {SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE, SYS_MEMINFO_SLAB_UNRECLAIMABLE_DESC}, + {SysMeminfoType::PMEM_KERNEL_STACK, SYS_MEMINFO_KERNEL_STACK_DESC}, + {SysMeminfoType::PMEM_PAGE_TABLES, SYS_MEMINFO_PAGE_TABLES_DESC}, + {SysMeminfoType::PMEM_COMMIT_LIMIT, SYS_MEMINFO_COMMIT_LIMIT_DESC}, + {SysMeminfoType::PMEM_COMMITED_AS, SYS_MEMINFO_COMMITED_AS_DESC}, + {SysMeminfoType::PMEM_VMALLOC_TOTAL, SYS_MEMINFO_VMALLOC_TOTAL_DESC}, + {SysMeminfoType::PMEM_VMALLOC_USED, SYS_MEMINFO_VMALLOC_USED_DESC}, + {SysMeminfoType::PMEM_VMALLOC_CHUNK, SYS_MEMINFO_VMALLOC_CHUNK_DESC}, + {SysMeminfoType::PMEM_CMA_TOTAL, SYS_MEMINFO_CMA_TOTAL_DESC}, + {SysMeminfoType::PMEM_CMA_FREE, SYS_MEMINFO_CMA_FREE_DESC}, + {SysMeminfoType::PMEM_KERNEL_RECLAIMABLE, SYS_MEMINFO_KERNEL_RECLAIMABLE_DESC}}; +} + +void TraceStreamerConfig::InitSysVmemMap() +{ + sysVirtualMemNameMap_ = { + {SysVMeminfoType::VMEMINFO_UNSPECIFIED, SYS_VMEMINFO_UNSPECIFIED_DESC}, + {SysVMeminfoType::VMEMINFO_NR_FREE_PAGES, SYS_VMEMINFO_NR_FREE_PAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ALLOC_BATCH, SYS_VMEMINFO_NR_ALLOC_BATCH_DESC}, + {SysVMeminfoType::VMEMINFO_NR_INACTIVE_ANON, SYS_VMEMINFO_NR_INACTIVE_ANON_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ACTIVE_ANON, SYS_VMEMINFO_NR_ACTIVE_ANON_DESC}, + {SysVMeminfoType::VMEMINFO_NR_INACTIVE_FILE, SYS_VMEMINFO_NR_INACTIVE_FILE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ACTIVE_FILE, SYS_VMEMINFO_NR_ACTIVE_FILE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_UNEVICTABLE, SYS_VMEMINFO_NR_UNEVICTABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_MLOCK, SYS_VMEMINFO_NR_MLOCK_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ANON_PAGES, SYS_VMEMINFO_NR_ANON_PAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_MAPPED, SYS_VMEMINFO_NR_MAPPED_DESC}, + {SysVMeminfoType::VMEMINFO_NR_FILE_PAGES, SYS_VMEMINFO_NR_FILE_PAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_DIRTY, SYS_VMEMINFO_NR_DIRTY_DESC}, + {SysVMeminfoType::VMEMINFO_NR_WRITEBACK, SYS_VMEMINFO_NR_WRITEBACK_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SLAB_RECLAIMABLE, SYS_VMEMINFO_NR_SLAB_RECLAIMABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SLAB_UNRECLAIMABLE, SYS_VMEMINFO_NR_SLAB_UNRECLAIMABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_PAGE_TABLE_PAGES, SYS_VMEMINFO_NR_PAGE_TABLE_PAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_KERNEL_STACK, SYS_VMEMINFO_NR_KERNEL_STACK_DESC}, + {SysVMeminfoType::VMEMINFO_NR_OVERHEAD, SYS_VMEMINFO_NR_OVERHEAD_DESC}, + {SysVMeminfoType::VMEMINFO_NR_UNSTABLE, SYS_VMEMINFO_NR_UNSTABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_BOUNCE, SYS_VMEMINFO_NR_BOUNCE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_VMSCAN_WRITE, SYS_VMEMINFO_NR_VMSCAN_WRITE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM, SYS_VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM_DESC}, + {SysVMeminfoType::VMEMINFO_NR_WRITEBACK_TEMP, SYS_VMEMINFO_NR_WRITEBACK_TEMP_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ISOLATED_ANON, SYS_VMEMINFO_NR_ISOLATED_ANON_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ISOLATED_FILE, SYS_VMEMINFO_NR_ISOLATED_FILE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SHMEM, SYS_VMEMINFO_NR_SHMEM_DESC}, + {SysVMeminfoType::VMEMINFO_NR_DIRTIED, SYS_VMEMINFO_NR_DIRTIED_DESC}, + {SysVMeminfoType::VMEMINFO_NR_WRITTEN, SYS_VMEMINFO_NR_WRITTEN_DESC}, + {SysVMeminfoType::VMEMINFO_NR_PAGES_SCANNED, SYS_VMEMINFO_NR_PAGES_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_WORKINGSET_REFAULT, SYS_VMEMINFO_WORKINGSET_REFAULT_DESC}, + {SysVMeminfoType::VMEMINFO_WORKINGSET_ACTIVATE, SYS_VMEMINFO_WORKINGSET_ACTIVATE_DESC}, + {SysVMeminfoType::VMEMINFO_WORKINGSET_NODERECLAIM, SYS_VMEMINFO_WORKINGSET_NODERECLAIM_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES, SYS_VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_FREE_CMA, SYS_VMEMINFO_NR_FREE_CMA_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SWAPCACHE, SYS_VMEMINFO_NR_SWAPCACHE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_DIRTY_THRESHOLD, SYS_VMEMINFO_NR_DIRTY_THRESHOLD_DESC}, + {SysVMeminfoType::VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD, SYS_VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD_DESC}, + {SysVMeminfoType::VMEMINFO_PGPGIN, SYS_VMEMINFO_PGPGIN_DESC}, + {SysVMeminfoType::VMEMINFO_PGPGOUT, SYS_VMEMINFO_PGPGOUT_DESC}, + {SysVMeminfoType::VMEMINFO_PGPGOUTCLEAN, SYS_VMEMINFO_PGPGOUTCLEAN_DESC}, + {SysVMeminfoType::VMEMINFO_PSWPIN, SYS_VMEMINFO_PSWPIN_DESC}, + {SysVMeminfoType::VMEMINFO_PSWPOUT, SYS_VMEMINFO_PSWPOUT_DESC}, + {SysVMeminfoType::VMEMINFO_PGALLOC_DMA, SYS_VMEMINFO_PGALLOC_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGALLOC_NORMAL, SYS_VMEMINFO_PGALLOC_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGALLOC_MOVABLE, SYS_VMEMINFO_PGALLOC_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGFREE, SYS_VMEMINFO_PGFREE_DESC}, + {SysVMeminfoType::VMEMINFO_PGACTIVATE, SYS_VMEMINFO_PGACTIVATE_DESC}, + {SysVMeminfoType::VMEMINFO_PGDEACTIVATE, SYS_VMEMINFO_PGDEACTIVATE_DESC}, + {SysVMeminfoType::VMEMINFO_PGFAULT, SYS_VMEMINFO_PGFAULT_DESC}, + {SysVMeminfoType::VMEMINFO_PGMAJFAULT, SYS_VMEMINFO_PGMAJFAULT_DESC}, + {SysVMeminfoType::VMEMINFO_PGREFILL_DMA, SYS_VMEMINFO_PGREFILL_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGREFILL_NORMAL, SYS_VMEMINFO_PGREFILL_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGREFILL_MOVABLE, SYS_VMEMINFO_PGREFILL_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_DMA, SYS_VMEMINFO_PGSTEAL_KSWAPD_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_NORMAL, SYS_VMEMINFO_PGSTEAL_KSWAPD_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_MOVABLE, SYS_VMEMINFO_PGSTEAL_KSWAPD_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_DMA, SYS_VMEMINFO_PGSTEAL_DIRECT_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_NORMAL, SYS_VMEMINFO_PGSTEAL_DIRECT_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_MOVABLE, SYS_VMEMINFO_PGSTEAL_DIRECT_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_DMA, SYS_VMEMINFO_PGSCAN_KSWAPD_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_NORMAL, SYS_VMEMINFO_PGSCAN_KSWAPD_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_MOVABLE, SYS_VMEMINFO_PGSCAN_KSWAPD_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_DMA, SYS_VMEMINFO_PGSCAN_DIRECT_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_NORMAL, SYS_VMEMINFO_PGSCAN_DIRECT_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_MOVABLE, SYS_VMEMINFO_PGSCAN_DIRECT_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_THROTTLE, SYS_VMEMINFO_PGSCAN_DIRECT_THROTTLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGINODESTEAL, SYS_VMEMINFO_PGINODESTEAL_DESC}, + {SysVMeminfoType::VMEMINFO_SLABS_SCANNED, SYS_VMEMINFO_SLABS_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_KSWAPD_INODESTEAL, SYS_VMEMINFO_KSWAPD_INODESTEAL_DESC}, + {SysVMeminfoType::VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY, SYS_VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY_DESC}, + {SysVMeminfoType::VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY, SYS_VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY_DESC}, + {SysVMeminfoType::VMEMINFO_PAGEOUTRUN, SYS_VMEMINFO_PAGEOUTRUN_DESC}, + {SysVMeminfoType::VMEMINFO_ALLOCSTALL, SYS_VMEMINFO_ALLOCSTALL_DESC}, + {SysVMeminfoType::VMEMINFO_PGROTATED, SYS_VMEMINFO_PGROTATED_DESC}, + {SysVMeminfoType::VMEMINFO_DROP_PAGECACHE, SYS_VMEMINFO_DROP_PAGECACHE_DESC}, + {SysVMeminfoType::VMEMINFO_DROP_SLAB, SYS_VMEMINFO_DROP_SLAB_DESC}, + {SysVMeminfoType::VMEMINFO_PGMIGRATE_SUCCESS, SYS_VMEMINFO_PGMIGRATE_SUCCESS_DESC}, + {SysVMeminfoType::VMEMINFO_PGMIGRATE_FAIL, SYS_VMEMINFO_PGMIGRATE_FAIL_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_MIGRATE_SCANNED, SYS_VMEMINFO_COMPACT_MIGRATE_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_FREE_SCANNED, SYS_VMEMINFO_COMPACT_FREE_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_ISOLATED, SYS_VMEMINFO_COMPACT_ISOLATED_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_STALL, SYS_VMEMINFO_COMPACT_STALL_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_FAIL, SYS_VMEMINFO_COMPACT_FAIL_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_SUCCESS, SYS_VMEMINFO_COMPACT_SUCCESS_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_WAKE, SYS_VMEMINFO_COMPACT_DAEMON_WAKE_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CULLED, SYS_VMEMINFO_UNEVICTABLE_PGS_CULLED_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_SCANNED, SYS_VMEMINFO_UNEVICTABLE_PGS_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_RESCUED, SYS_VMEMINFO_UNEVICTABLE_PGS_RESCUED_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MLOCKED, SYS_VMEMINFO_UNEVICTABLE_PGS_MLOCKED_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED, SYS_VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CLEARED, SYS_VMEMINFO_UNEVICTABLE_PGS_CLEARED_DESC}, + {SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_STRANDED, SYS_VMEMINFO_UNEVICTABLE_PGS_STRANDED_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZSPAGES, SYS_VMEMINFO_NR_ZSPAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ION_HEAP, SYS_VMEMINFO_NR_ION_HEAP_DESC}, + {SysVMeminfoType::VMEMINFO_NR_GPU_HEAP, SYS_VMEMINFO_NR_GPU_HEAP_DESC}, + {SysVMeminfoType::VMEMINFO_ALLOCSTALL_DMA, SYS_VMEMINFO_ALLOCSTALL_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_ALLOCSTALL_MOVABLE, SYS_VMEMINFO_ALLOCSTALL_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_ALLOCSTALL_NORMAL, SYS_VMEMINFO_ALLOCSTALL_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_FREE_SCANNED, SYS_VMEMINFO_COMPACT_DAEMON_FREE_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED, SYS_VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED_DESC}, + {SysVMeminfoType::VMEMINFO_NR_FASTRPC, SYS_VMEMINFO_NR_FASTRPC_DESC}, + {SysVMeminfoType::VMEMINFO_NR_INDIRECTLY_RECLAIMABLE, SYS_VMEMINFO_NR_INDIRECTLY_RECLAIMABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ION_HEAP_POOL, SYS_VMEMINFO_NR_ION_HEAP_POOL_DESC}, + {SysVMeminfoType::VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE, SYS_VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SHADOW_CALL_STACK_BYTES, SYS_VMEMINFO_NR_SHADOW_CALL_STACK_BYTES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SHMEM_HUGEPAGES, SYS_VMEMINFO_NR_SHMEM_HUGEPAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_SHMEM_PMDMAPPED, SYS_VMEMINFO_NR_SHMEM_PMDMAPPED_DESC}, + {SysVMeminfoType::VMEMINFO_NR_UNRECLAIMABLE_PAGES, SYS_VMEMINFO_NR_UNRECLAIMABLE_PAGES_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_ANON, SYS_VMEMINFO_NR_ZONE_ACTIVE_ANON_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_FILE, SYS_VMEMINFO_NR_ZONE_ACTIVE_FILE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_ANON, SYS_VMEMINFO_NR_ZONE_INACTIVE_ANON_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_FILE, SYS_VMEMINFO_NR_ZONE_INACTIVE_FILE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZONE_UNEVICTABLE, SYS_VMEMINFO_NR_ZONE_UNEVICTABLE_DESC}, + {SysVMeminfoType::VMEMINFO_NR_ZONE_WRITE_PENDING, SYS_VMEMINFO_NR_ZONE_WRITE_PENDING_DESC}, + {SysVMeminfoType::VMEMINFO_OOM_KILL, SYS_VMEMINFO_OOM_KILL_DESC}, + {SysVMeminfoType::VMEMINFO_PGLAZYFREE, SYS_VMEMINFO_PGLAZYFREE_DESC}, + {SysVMeminfoType::VMEMINFO_PGLAZYFREED, SYS_VMEMINFO_PGLAZYFREED_DESC}, + {SysVMeminfoType::VMEMINFO_PGREFILL, SYS_VMEMINFO_PGREFILL_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT, SYS_VMEMINFO_PGSCAN_DIRECT_DESC}, + {SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD, SYS_VMEMINFO_PGSCAN_KSWAPD_DESC}, + {SysVMeminfoType::VMEMINFO_PGSKIP_DMA, SYS_VMEMINFO_PGSKIP_DMA_DESC}, + {SysVMeminfoType::VMEMINFO_PGSKIP_MOVABLE, SYS_VMEMINFO_PGSKIP_MOVABLE_DESC}, + {SysVMeminfoType::VMEMINFO_PGSKIP_NORMAL, SYS_VMEMINFO_PGSKIP_NORMAL_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT, SYS_VMEMINFO_PGSTEAL_DIRECT_DESC}, + {SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD, SYS_VMEMINFO_PGSTEAL_KSWAPD_DESC}, + {SysVMeminfoType::VMEMINFO_SWAP_RA, SYS_VMEMINFO_SWAP_RA_DESC}, + {SysVMeminfoType::VMEMINFO_SWAP_RA_HIT, SYS_VMEMINFO_SWAP_RA_HIT_DESC}, + {SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE, SYS_VMEMINFO_WORKINGSET_RESTORE_DESC}}; +} +void TraceStreamerConfig::InitSecurityMap() +{ + eventParserStatSeverityDescMap_ = { + { + TRACE_EVENT_BINDER_TRANSACTION, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BINDER_TRANSACTION_LOCK, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BINDER_TRANSACTION_LOCKED, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SCHED_SWITCH, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SCHED_BLOCKED_REASON, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_TASK_RENAME, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_TASK_NEWTASK, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_TRACING_MARK_WRITE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_PRINT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SCHED_WAKEUP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SCHED_WAKING, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CPU_IDLE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CPU_FREQUENCY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CPU_FREQUENCY_LIMITS, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SUSPEND_RESUME, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_WORKQUEUE_EXECUTE_START, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_WORKQUEUE_EXECUTE_END, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLOCK_SET_RATE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLOCK_ENABLE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLOCK_DISABLE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLK_SET_RATE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLK_ENABLE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLK_DISABLE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_REGULATOR_SET_VOLTAGE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_REGULATOR_DISABLE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_IPI_ENTRY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_IPI_EXIT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_IRQ_HANDLER_ENTRY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_IRQ_HANDLER_EXIT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SOFTIRQ_RAISE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SOFTIRQ_ENTRY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SOFTIRQ_EXIT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SCHED_WAKEUP_NEW, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_PROCESS_EXIT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_PROCESS_FREE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_CLOCK_SYNC, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SYS_ENTRY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SYS_EXIT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_MEMORY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_HILOG, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_HIDUMP_FPS, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NATIVE_HOOK_MALLOC, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NATIVE_HOOK_FREE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NATIVE_HOOK_MMAP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NATIVE_HOOK_MUNMAP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NATIVE_HOOK_RECORD_STATISTICS, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_SYS_MEMORY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_SYS_VIRTUAL_MEMORY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_DISKIO, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_PROCESS, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_CPU_USAGE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NETWORK, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_JS_MEMORY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_PERF, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SIGNAL_GENERATE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_SIGNAL_DELIVER, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_BIO_BACKMERGE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_BIO_BOUNCE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_BIO_COMPLETE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_BIO_FRONTMERGE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_BIO_QUEUE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_BIO_REMAP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_DIRTY_BUFFER, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_GETRQ, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_PLUG, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_RQ_COMPLETE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_RQ_INSERT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_RQ_REMAP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_BLOCK_RQ_ISSUE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_EBPF, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_EBPF_FILE_SYSTEM, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_EBPF_PAGED_MEMORY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_EBPF_BIO_LATENCY, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_HISYSEVENT, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_SMAPS, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_VSYNC, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_ONVSYNC, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_FRAMEQUEUE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_EVENT_OTHER, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + }; +} +} // namespace TraceCfg +} // namespace SysTuning diff --git a/trace_streamer/src/cfg/trace_streamer_config.h b/trace_streamer/src/cfg/trace_streamer_config.h new file mode 100644 index 0000000000000000000000000000000000000000..f9bca25a4d186a7bf77368023b1d11d2e5bcde8d --- /dev/null +++ b/trace_streamer/src/cfg/trace_streamer_config.h @@ -0,0 +1,468 @@ +/* + * 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 TRACE_STREAMER_CONFIG_H +#define TRACE_STREAMER_CONFIG_H +#include +#include +#include "memory_plugin_common.pb.h" +#include "ts_common.h" +namespace SysTuning { +namespace TraceCfg { +// all supported events should be defined here +#define CPU_IDEL_INVALID_KEY 4294967295 +#define CPU_IDEL_INVALID_VALUE 4 +enum SupportedTraceEventType { + TRACE_EVENT_START = 0, + TRACE_EVENT_BINDER_TRANSACTION = TRACE_EVENT_START, + TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, + TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, + TRACE_EVENT_BINDER_TRANSACTION_LOCK, + TRACE_EVENT_BINDER_TRANSACTION_LOCKED, + TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, + TRACE_EVENT_SCHED_SWITCH, + TRACE_EVENT_SCHED_BLOCKED_REASON, + TRACE_EVENT_TASK_RENAME, + TRACE_EVENT_TASK_NEWTASK, + TRACE_EVENT_TRACING_MARK_WRITE, + TRACE_EVENT_PRINT, + TRACE_EVENT_SCHED_WAKEUP, + TRACE_EVENT_SCHED_WAKING, + TRACE_EVENT_CPU_IDLE, + TRACE_EVENT_CPU_FREQUENCY, + TRACE_EVENT_CPU_FREQUENCY_LIMITS, + TRACE_EVENT_SUSPEND_RESUME, + TRACE_EVENT_WORKQUEUE_EXECUTE_START, + TRACE_EVENT_WORKQUEUE_EXECUTE_END, + TRACE_EVENT_CLOCK_SET_RATE, + TRACE_EVENT_CLOCK_ENABLE, + TRACE_EVENT_CLOCK_DISABLE, + TRACE_EVENT_CLK_SET_RATE, + TRACE_EVENT_CLK_ENABLE, + TRACE_EVENT_CLK_DISABLE, + TRACE_EVENT_SYS_ENTRY, + TRACE_EVENT_SYS_EXIT, + TRACE_EVENT_REGULATOR_SET_VOLTAGE, + TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE, + TRACE_EVENT_REGULATOR_DISABLE, + TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, + TRACE_EVENT_IPI_ENTRY, + TRACE_EVENT_IPI_EXIT, + TRACE_EVENT_IRQ_HANDLER_ENTRY, + TRACE_EVENT_IRQ_HANDLER_EXIT, + TRACE_EVENT_SOFTIRQ_RAISE, + TRACE_EVENT_SOFTIRQ_ENTRY, + TRACE_EVENT_SOFTIRQ_EXIT, + TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, + TRACE_EVENT_SCHED_WAKEUP_NEW, + TRACE_EVENT_PROCESS_EXIT, + TRACE_EVENT_PROCESS_FREE, + TRACE_EVENT_CLOCK_SYNC, + TRACE_EVENT_SIGNAL_GENERATE, + TRACE_EVENT_SIGNAL_DELIVER, + TRACE_EVENT_BLOCK_BIO_BACKMERGE, + TRACE_EVENT_BLOCK_BIO_BOUNCE, + TRACE_EVENT_BLOCK_BIO_COMPLETE, + TRACE_EVENT_BLOCK_BIO_FRONTMERGE, + TRACE_EVENT_BLOCK_BIO_QUEUE, + TRACE_EVENT_BLOCK_BIO_REMAP, + TRACE_EVENT_BLOCK_DIRTY_BUFFER, + TRACE_EVENT_BLOCK_GETRQ, + TRACE_EVENT_BLOCK_PLUG, + TRACE_EVENT_BLOCK_RQ_COMPLETE, + TRACE_EVENT_BLOCK_RQ_INSERT, + TRACE_EVENT_BLOCK_RQ_REMAP, + TRACE_EVENT_BLOCK_RQ_ISSUE, + TRACE_MEMORY, + TRACE_HILOG, + TRACE_HIDUMP_FPS, + TRACE_NATIVE_HOOK_MALLOC, + TRACE_NATIVE_HOOK_FREE, + TRACE_NATIVE_HOOK_MMAP, + TRACE_NATIVE_HOOK_MUNMAP, + TRACE_NATIVE_HOOK_RECORD_STATISTICS, + TRACE_SYS_MEMORY, + TRACE_SYS_VIRTUAL_MEMORY, + TRACE_DISKIO, + TRACE_PROCESS, + TRACE_CPU_USAGE, + TRACE_NETWORK, + TRACE_JS_MEMORY, + TRACE_PERF, + TRACE_EVENT_EBPF, + TRACE_EVENT_EBPF_FILE_SYSTEM, + TRACE_EVENT_EBPF_PAGED_MEMORY, + TRACE_EVENT_EBPF_BIO_LATENCY, + TRACE_HISYSEVENT, + TRACE_SMAPS, + TRACE_VSYNC, + TRACE_ONVSYNC, + TRACE_FRAMEQUEUE, + TRACE_EVENT_OTHER, + TRACE_EVENT_MAX +}; +enum MemInfoType { + MEM_VM_SIZE, + MEM_VM_RSS, + MEM_VM_ANON, + MEM_RSS_FILE, + MEM_RSS_SHMEM, + MEM_VM_SWAP, + MEM_VM_LOCKED, + MEM_VM_HWM, + MEM_OOM_SCORE_ADJ, + MEM_MAX +}; +enum StatType { + STAT_EVENT_START = 0, + STAT_EVENT_RECEIVED = STAT_EVENT_START, + STAT_EVENT_DATA_LOST, + STAT_EVENT_NOTMATCH, + STAT_EVENT_NOTSUPPORTED, + STAT_EVENT_DATA_INVALID, + STAT_EVENT_MAX +}; + +// there maybe some error while parser trace msgs, here defined the error levels +enum StatSeverityLevel { + STAT_SEVERITY_LEVEL_START = 0, + STAT_SEVERITY_LEVEL_INFO = STAT_SEVERITY_LEVEL_START, + STAT_SEVERITY_LEVEL_WARN, + STAT_SEVERITY_LEVEL_ERROR, + STAT_SEVERITY_LEVEL_FATAL, + STAT_SEVERITY_LEVEL_MAX +}; + +// the supported metadata +enum MetaDataItem { + METADATA_ITEM_START = 0, + METADATA_ITEM_DATASIZE = METADATA_ITEM_START, + METADATA_ITEM_PARSETOOL_NAME, + METADATA_ITEM_PARSERTOOL_VERSION, + METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME, + METADATA_ITEM_SOURCE_FILENAME, + METADATA_ITEM_OUTPUT_FILENAME, + METADATA_ITEM_PARSERTIME, // the data time while the data parsed + METADATA_ITEM_TRACE_DURATION, + METADATA_ITEM_SOURCE_DATETYPE, // proto-based-trace or txt-based-trace + METADATA_ITEM_MAX +}; + +class TraceStreamerConfig { +public: + TraceStreamerConfig(); + ~TraceStreamerConfig() = default; + void PrintInfo() const; + uint32_t GetStateValue(uint32_t state) const; + +public: + std::map eventNameMap_ = {}; + std::map eventErrorDescMap_ = {}; + std::map serverityLevelDescMap_ = {}; + // different msg may have STAT_EVENT_MAX types of exception when parse, and they have different error level + // if you think some error level should be improve or depress, you can edit this map + std::map> eventParserStatSeverityDescMap_ = {}; + // process mem info desc + std::map memNameMap_ = {}; + // sys memorty info desc + std::map sysMemNameMap_ = {}; + // sys virtual memorty info desc + std::map sysVirtualMemNameMap_ = {}; + +private: + void InitEventNameMap(); + void InitSysMemMap(); + void InitSysVmemMap(); + void InitSecurityMap(); + // all supported events should be defined here, these str can be find in text-based trace + const std::string TRACE_ACTION_BINDER_TRANSACTION = "binder_transaction"; + const std::string TRACE_ACTION_BINDER_TRANSACTION_RECEIVED = "binder_transaction_received"; + const std::string TRACE_ACTION_SCHED_SWITCH = "sched_switch"; + const std::string TRACE_ACTION_SCHED_BLOCKED_REASON = "sched_blocked_reason"; + const std::string TRACE_ACTION_TASK_RENAME = "task_rename"; + const std::string TRACE_ACTION_TASK_NEWTASK = "task_newtask"; + const std::string TRACE_ACTION_TRACING_MARK_WRITE = "tracing_mark_write"; + const std::string TRACE_ACTION_PRINT = "print"; + const std::string TRACE_ACTION_SCHED_WAKEUP = "sched_wakeup"; + const std::string TRACE_ACTION_SCHED_WAKING = "sched_waking"; + const std::string TRACE_ACTION_CPU_IDLE = "cpu_idle"; + const std::string TRACE_ACTION_CPU_FREQUENCY = "cpu_frequency"; + const std::string TRACE_ACTION_CPU_FREQUENCY_LIMITS = "cpu_frequency_limits"; + const std::string TRACE_ACTION_SUSPEND_RESUME = "suspend_resume"; + const std::string TRACE_ACTION_WORKQUEUE_EXECUTE_START = "workqueue_execute_start"; + const std::string TRACE_ACTION_WORKQUEUE_EXECUTE_END = "workqueue_execute_end"; + + const std::string TRACE_ACTION_CLOCK_SET_RATE = "clock_set_rate"; + const std::string TRACE_ACTION_CLOCK_ENABLE = "clock_enable"; + const std::string TRACE_ACTION_CLOCK_DISABLE = "clock_disable"; + const std::string TRACE_ACTION_CLK_SET_RATE = "clk_set_rate"; + const std::string TRACE_ACTION_CLK_ENABLE = "clk_enable"; + const std::string TRACE_ACTION_CLK_DISABLE = "clk_disable"; + const std::string TRACE_ACTION_SYS_ENTRY = "sys_enter"; + const std::string TRACE_ACTION_SYS_EXIT = "sys_exit"; + const std::string TRACE_ACTION_OOM_SCORE_ADJ_UPDATE = "oom_score_adj_update"; + const std::string TRACE_ACTION_REGULATOR_SET_VOLTAGE = "regulator_set_voltage"; + const std::string TRACE_ACTION_REGULATOR_SET_VOLTAGE_COMPLETE = "regulator_set_voltage_complete"; + const std::string TRACE_ACTION_REGULATOR_DISABLE = "regulator_disable"; + const std::string TRACE_ACTION_REGULATOR_DISABLE_COMPLETE = "regulator_disable_complete"; + const std::string TRACE_ACTION_IPI_ENTRY = "ipi_entry"; + const std::string TRACE_ACTION_IPI_EXIT = "ipi_exit"; + const std::string TRACE_ACTION_IRQ_HANDLER_ENTRY = "irq_handler_entry"; + const std::string TRACE_ACTION_IRQ_HANDLER_EXIT = "irq_handler_exit"; + const std::string TRACE_ACTION_SOFTIRQ_RAISE = "softirq_raise"; + const std::string TRACE_ACTION_SOFTIRQ_ENTRY = "softirq_entry"; + const std::string TRACE_ACTION_SOFTIRQ_EXIT = "softirq_exit"; + const std::string TRACE_ACTION_BINDER_TRANSACTION_ALLOC_BUF = "binder_transaction_alloc_buf"; + const std::string TRACE_ACTION_BINDER_TRANSACTION_LOCK = "binder_transaction_lock"; + const std::string TRACE_ACTION_BINDER_TRANSACTION_LOCKED = "binder_transaction_locked"; + const std::string TRACE_ACTION_BINDER_TRANSACTION_UNLOCK = "binder_transaction_unlock"; + const std::string TRACE_ACTION_SCHED_WAKEUP_NEW = "sched_wakeup_new"; + const std::string TRACE_ACTION_PROCESS_EXIT = "sched_process_exit"; + const std::string TRACE_ACTION_PROCESS_FREE = "sched_process_free"; + const std::string TRACE_ACTION_CLOCK_SYNC = "trace_event_clock_sync"; + const std::string TRACE_ACTION_MEMORY = "memory"; + const std::string TRACE_ACTION_HILOG = "hilog"; + const std::string TRACE_ACTION_HIDUMP_FPS = "hidump_fps"; + const std::string TRACE_ACTION_NATIVE_HOOK_MALLOC = "native_hook_malloc"; + const std::string TRACE_ACTION_NATIVE_HOOK_FREE = "native_hook_free"; + const std::string TRACE_ACTION_NATIVE_HOOK_MMAP = "native_hook_mmap"; + const std::string TRACE_ACTION_NATIVE_HOOK_MUNMAP = "native_hook_munmap"; + const std::string TRACE_ACTION_NATIVE_HOOK_RECORD_STATISTICS = "native_hook_record_statistics"; + const std::string TRACE_ACTION_SIGNAL_GENERATE = "signal_generate"; + const std::string TRACE_ACTION_SIGNAL_DELIVER = "signal_deliver"; + const std::string TRACE_ACTION_BLOCK_BIO_BACKMERGE = "trace_block_bio_backmerge"; + const std::string TRACE_ACTION_BLOCK_BIO_BOUNCE = "trace_block_bio_bounce"; + const std::string TRACE_ACTION_BLOCK_BIO_COMPLETE = "trace_block_bio_complete"; + const std::string TRACE_ACTION_BLOCK_BIO_FRONTMERGE = "trace_block_bio_frontmerge"; + const std::string TRACE_ACTION_BLOCK_BIO_QUEUE = "trace_bblock_bio_queue"; + const std::string TRACE_ACTION_BLOCK_BIO_REMAP = "trace_block_bio_remap"; + const std::string TRACE_ACTION_BLOCK_DIRTY_BUFFER = "trace_block_dirty_buffer"; + const std::string TRACE_ACTION_BLOCK_GETRQ = "trace_block_getrq"; + const std::string TRACE_ACTION_BLOCK_PLUG = "trace_block_plug"; + const std::string TRACE_ACTION_BLOCK_RQ_COMPLETE = "trace_block_rq_complete"; + const std::string TRACE_ACTION_BLOCK_RQ_INSERT = "trace_block_rq_insert"; + const std::string TRACE_ACTION_BLOCK_RQ_REMAP = "trace_block_rq_remap"; + const std::string TRACE_ACTION_BLOCK_RQ_ISSUE = "trace_block_rq_issue"; + + const std::string TRACE_ACTION_SYS_MEMORY = "sys_memory"; + const std::string TRACE_ACTION_SYS_VIRTUAL_MEMORY = "sys_virtual_memory"; + const std::string TRACE_ACTION_DISKIO = "trace_diskio"; + const std::string TRACE_ACTION_PROCESS = "trace_process"; + const std::string TRACE_ACTION_CPU_USAGE = "trace_cpu_usage"; + const std::string TRACE_ACTION_NETWORK = "trace_network"; + const std::string TRACE_ACTION_JS_MEMORY = "trace_js_memory"; + const std::string TRACE_ACTION_PERF = "trace_perf"; + const std::string TRACE_ACTION_EBPF = "trace_ebpf"; + const std::string TRACE_ACTION_EBPF_FILE_SYSTEM = "trace_ebpf_file_system"; + const std::string TRACE_ACTION_EBPF_PAGED_MEMORY = "trace_ebpf_paged_memory"; + const std::string TRACE_ACTION_EBPF_BIO_LATENCY = "trace_ebpf_bio_latency"; + const std::string TRACE_ACTION_HISYS_EVENT = "trace_hisys_event"; + const std::string TRACE_ACTION_SMAPS = "trace_smaps"; + const std::string TRACE_ACTION_VSYNC = "trace_vsync"; + const std::string TRACE_ACTION_ONVSYNC = "trace_on_vsync"; + const std::string TRACE_ACTION_FRAMEQUEUE = "trace_frame_queue"; + const std::string TRACE_ACTION_OTHER = "other"; + + const std::string MEM_INFO_VM_SIZE_DESC = "mem.vm.size"; + const std::string MEM_INFO_LOCKED_DESC = "mem.locked"; + const std::string MEM_INFO_RSS_DESC = "mem.rss"; + const std::string MEM_INFO_RSS_ANON_DESC = "mem.rss.anon"; + const std::string MEM_INFO_RSS_FILE_DESC = "mem.rss.file"; + const std::string MEM_INFO_RSS_SCHEM_DESC = "mem.rss.schem"; + const std::string MEM_INFO_SWAP_DESC = "mem.swap"; + const std::string MEM_INFO_VIRT_DESC = "mem.virt"; + const std::string MEM_INFO_HWM_DESC = "mem.hwm"; + const std::string MEM_INFO_SCORE_ADJ_DESC = "mm.oom_score_adj"; + + const std::string SYS_MEMINFO_UNSPECIFIED_DESC = "sys.mem.unspecified"; + const std::string SYS_MEMINFO_MEM_TOTAL_DESC = "sys.mem.total"; + const std::string SYS_MEMINFO_MEM_FREE_DESC = "sys.mem.free"; + const std::string SYS_MEMINFO_MEM_AVAILABLE_DESC = "sys.mem.avaiable"; + const std::string SYS_MEMINFO_BUFFERS_DESC = "sys.mem.buffers"; + const std::string SYS_MEMINFO_CACHED_DESC = "sys.mem.cached"; + const std::string SYS_MEMINFO_SWAP_CACHED_DESC = "sys.mem.swap.chard"; + const std::string SYS_MEMINFO_ACTIVE_DESC = "sys.mem.active"; + const std::string SYS_MEMINFO_INACTIVE_DESC = "sys.mem.inactive"; + const std::string SYS_MEMINFO_ACTIVE_ANON_DESC = "sys.mem.active.anon"; + const std::string SYS_MEMINFO_INACTIVE_ANON_DESC = "sys.mem.inactive.anon"; + const std::string SYS_MEMINFO_ACTIVE_FILE_DESC = "sys.mem.active_file"; + const std::string SYS_MEMINFO_INACTIVE_FILE_DESC = "sys.mem.inactive_file"; + const std::string SYS_MEMINFO_UNEVICTABLE_DESC = "sys.mem.unevictable"; + const std::string SYS_MEMINFO_MLOCKED_DESC = "sys.mem.mlocked"; + const std::string SYS_MEMINFO_SWAP_TOTAL_DESC = "sys.mem.swap.total"; + const std::string SYS_MEMINFO_SWAP_FREE_DESC = "sys.mem.swap.free"; + const std::string SYS_MEMINFO_DIRTY_DESC = "sys.mem.dirty"; + const std::string SYS_MEMINFO_WRITEBACK_DESC = "sys.mem.writeback"; + const std::string SYS_MEMINFO_ANON_PAGES_DESC = "sys.mem.anon.pages"; + const std::string SYS_MEMINFO_MAPPED_DESC = "sys.mem.mapped"; + const std::string SYS_MEMINFO_SHMEM_DESC = "sys.mem.shmem"; + const std::string SYS_MEMINFO_SLAB_DESC = "sys.mem.slab"; + const std::string SYS_MEMINFO_SLAB_RECLAIMABLE_DESC = "sys.mem.slab.reclaimable"; + const std::string SYS_MEMINFO_SLAB_UNRECLAIMABLE_DESC = "sys.mem.slab.unreclaimable"; + const std::string SYS_MEMINFO_KERNEL_STACK_DESC = "sys.mem.kernel.stack"; + const std::string SYS_MEMINFO_PAGE_TABLES_DESC = "sys.mem.page.tables"; + const std::string SYS_MEMINFO_COMMIT_LIMIT_DESC = "sys.mem.commit.limit"; + const std::string SYS_MEMINFO_COMMITED_AS_DESC = "sys.mem.commited.as"; + const std::string SYS_MEMINFO_VMALLOC_TOTAL_DESC = "sys.mem.vmalloc.total"; + const std::string SYS_MEMINFO_VMALLOC_USED_DESC = "sys.mem.vmalloc.used"; + const std::string SYS_MEMINFO_VMALLOC_CHUNK_DESC = "sys.mem.vmalloc.chunk"; + const std::string SYS_MEMINFO_CMA_TOTAL_DESC = "sys.mem.cma.total"; + const std::string SYS_MEMINFO_CMA_FREE_DESC = "sys.mem.cma.free"; + const std::string SYS_MEMINFO_KERNEL_RECLAIMABLE_DESC = "sys.mem.kernel.reclaimable"; + const std::string SYS_VMEMINFO_UNSPECIFIED_DESC = "sys.virtual.mem.unspecified"; + const std::string SYS_VMEMINFO_NR_FREE_PAGES_DESC = "sys.virtual.mem.nr.free.pages"; + const std::string SYS_VMEMINFO_NR_ALLOC_BATCH_DESC = "sys.virtual.mem.nr.alloc.batch"; + const std::string SYS_VMEMINFO_NR_INACTIVE_ANON_DESC = "sys.virtual.mem.nr.inactive.anon"; + const std::string SYS_VMEMINFO_NR_ACTIVE_ANON_DESC = "sys.virtual.mem.nr.active_anon"; + const std::string SYS_VMEMINFO_NR_INACTIVE_FILE_DESC = "sys.virtual.mem.nr.inactive.file"; + const std::string SYS_VMEMINFO_NR_ACTIVE_FILE_DESC = "sys.virtual.mem.nr.active_file"; + const std::string SYS_VMEMINFO_NR_UNEVICTABLE_DESC = "sys.virtual.mem.nr.unevictable"; + const std::string SYS_VMEMINFO_NR_MLOCK_DESC = "sys.virtual.mem.nr.mlock"; + const std::string SYS_VMEMINFO_NR_ANON_PAGES_DESC = "sys.virtual.mem.anon.pages"; + const std::string SYS_VMEMINFO_NR_MAPPED_DESC = "sys.virtual.mem.nr.mapped"; + const std::string SYS_VMEMINFO_NR_FILE_PAGES_DESC = "sys.virtual.mem.nr.file.pages"; + const std::string SYS_VMEMINFO_NR_DIRTY_DESC = "sys.virtual.mem.nr.dirty"; + const std::string SYS_VMEMINFO_NR_WRITEBACK_DESC = "sys.virtual.mem.nr.writeback"; + const std::string SYS_VMEMINFO_NR_SLAB_RECLAIMABLE_DESC = "sys.virtual.mem.nr.slab.reclaimable"; + const std::string SYS_VMEMINFO_NR_SLAB_UNRECLAIMABLE_DESC = "sys.virtual.mem.nr.slab.unreclaimable"; + const std::string SYS_VMEMINFO_NR_PAGE_TABLE_PAGES_DESC = "sys.virtual.mem.nr.page_table.pages"; + const std::string SYS_VMEMINFO_NR_KERNEL_STACK_DESC = "sys.virtual.mem.nr_kernel.stack"; + const std::string SYS_VMEMINFO_NR_OVERHEAD_DESC = "sys.virtual.mem.nr.overhead"; + const std::string SYS_VMEMINFO_NR_UNSTABLE_DESC = "sys.virtual.mem.nr.unstable"; + const std::string SYS_VMEMINFO_NR_BOUNCE_DESC = "sys.virtual.mem.nr.bounce"; + const std::string SYS_VMEMINFO_NR_VMSCAN_WRITE_DESC = "sys.virtual.mem.nr.vmscan.write"; + const std::string SYS_VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM_DESC = "sys.virtual.mem.nr.vmscan.immediate.reclaim"; + const std::string SYS_VMEMINFO_NR_WRITEBACK_TEMP_DESC = "sys.virtual.mem.nr.writeback_temp"; + const std::string SYS_VMEMINFO_NR_ISOLATED_ANON_DESC = "sys.virtual.mem.nr.isolated_anon"; + const std::string SYS_VMEMINFO_NR_ISOLATED_FILE_DESC = "sys.virtual.mem.nr.isolated_file"; + const std::string SYS_VMEMINFO_NR_SHMEM_DESC = "sys.virtual.mem.nr.shmem"; + const std::string SYS_VMEMINFO_NR_DIRTIED_DESC = "sys.virtual.mem.nr.dirtied"; + const std::string SYS_VMEMINFO_NR_WRITTEN_DESC = "sys.virtual.mem.nr.written"; + const std::string SYS_VMEMINFO_NR_PAGES_SCANNED_DESC = "sys.virtual.mem.nr.pages.scanned"; + const std::string SYS_VMEMINFO_WORKINGSET_REFAULT_DESC = "sys.virtual.mem.workingset.refault"; + const std::string SYS_VMEMINFO_WORKINGSET_ACTIVATE_DESC = "sys.virtual.mem.workingset.activate"; + const std::string SYS_VMEMINFO_WORKINGSET_NODERECLAIM_DESC = "sys.virtual.mem.workingset_nodereclaim"; + const std::string SYS_VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES_DESC = "sys.virtual.mem.nr_anon.transparent.hugepages"; + const std::string SYS_VMEMINFO_NR_FREE_CMA_DESC = "sys.virtual.mem.nr.free_cma"; + const std::string SYS_VMEMINFO_NR_SWAPCACHE_DESC = "sys.virtual.mem.nr.swapcache"; + const std::string SYS_VMEMINFO_NR_DIRTY_THRESHOLD_DESC = "sys.virtual.mem.nr.dirty.threshold"; + const std::string SYS_VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD_DESC = "sys.virtual.mem.nr.dirty.background.threshold"; + const std::string SYS_VMEMINFO_PGPGIN_DESC = "sys.virtual.mem.vmeminfo.pgpgin"; + const std::string SYS_VMEMINFO_PGPGOUT_DESC = "sys.virtual.mem.pgpgout"; + const std::string SYS_VMEMINFO_PGPGOUTCLEAN_DESC = "sys.virtual.mem.pgpgoutclean"; + const std::string SYS_VMEMINFO_PSWPIN_DESC = "sys.virtual.mem.pswpin"; + const std::string SYS_VMEMINFO_PSWPOUT_DESC = "sys.virtual.mem.pswpout"; + const std::string SYS_VMEMINFO_PGALLOC_DMA_DESC = "sys.virtual.mem.pgalloc.dma"; + const std::string SYS_VMEMINFO_PGALLOC_NORMAL_DESC = "sys.virtual.mem.pgalloc.normal"; + const std::string SYS_VMEMINFO_PGALLOC_MOVABLE_DESC = "sys.virtual.mem.pgalloc.movable"; + const std::string SYS_VMEMINFO_PGFREE_DESC = "sys.virtual.mem.pgfree"; + const std::string SYS_VMEMINFO_PGACTIVATE_DESC = "sys.virtual.mem.pgactivate"; + const std::string SYS_VMEMINFO_PGDEACTIVATE_DESC = "sys.virtual.mem.pgdeactivate"; + const std::string SYS_VMEMINFO_PGFAULT_DESC = "sys.virtual.mem.pgfault"; + const std::string SYS_VMEMINFO_PGMAJFAULT_DESC = "sys.virtual.mem.pgmajfault"; + const std::string SYS_VMEMINFO_PGREFILL_DMA_DESC = "sys.virtual.mem.pgrefill.dma"; + const std::string SYS_VMEMINFO_PGREFILL_NORMAL_DESC = "sys.virtual.mem.pgrefill.normal"; + const std::string SYS_VMEMINFO_PGREFILL_MOVABLE_DESC = "sys.virtual.mem.pgrefill.movable"; + const std::string SYS_VMEMINFO_PGSTEAL_KSWAPD_DMA_DESC = "sys.virtual.mem.pgsteal.kswapd.dma"; + const std::string SYS_VMEMINFO_PGSTEAL_KSWAPD_NORMAL_DESC = "sys.virtual.mem.pgsteal.kswapd.normal"; + const std::string SYS_VMEMINFO_PGSTEAL_KSWAPD_MOVABLE_DESC = "sys.virtual.mem.pgsteal.kswapd.movable"; + const std::string SYS_VMEMINFO_PGSTEAL_DIRECT_DMA_DESC = "sys.virtual.mem.pgsteal.direct.dma"; + const std::string SYS_VMEMINFO_PGSTEAL_DIRECT_NORMAL_DESC = "sys.virtual.mem.pgsteal.direct.normal"; + const std::string SYS_VMEMINFO_PGSTEAL_DIRECT_MOVABLE_DESC = "sys.virtual.mem.pgsteal_direct.movable"; + const std::string SYS_VMEMINFO_PGSCAN_KSWAPD_DMA_DESC = "sys.virtual.mem.pgscan.kswapd.dma"; + const std::string SYS_VMEMINFO_PGSCAN_KSWAPD_NORMAL_DESC = "sys.virtual.mem.pgscan_kswapd.normal"; + const std::string SYS_VMEMINFO_PGSCAN_KSWAPD_MOVABLE_DESC = "sys.virtual.mem.pgscan.kswapd.movable"; + const std::string SYS_VMEMINFO_PGSCAN_DIRECT_DMA_DESC = "sys.virtual.mem.pgscan.direct.dma"; + const std::string SYS_VMEMINFO_PGSCAN_DIRECT_NORMAL_DESC = "sys.virtual.mem.pgscan.direct.normal"; + const std::string SYS_VMEMINFO_PGSCAN_DIRECT_MOVABLE_DESC = "sys.virtual.mem.pgscan.direct.movable"; + const std::string SYS_VMEMINFO_PGSCAN_DIRECT_THROTTLE_DESC = "sys.virtual.mem.pgscan.direct.throttle"; + const std::string SYS_VMEMINFO_PGINODESTEAL_DESC = "sys.virtual.mem.pginodesteal"; + const std::string SYS_VMEMINFO_SLABS_SCANNED_DESC = "sys.virtual.mem.slabs_scanned"; + const std::string SYS_VMEMINFO_KSWAPD_INODESTEAL_DESC = "sys.virtual.mem.kswapd.inodesteal"; + const std::string SYS_VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY_DESC = "sys.virtual.mem.kswapd.low.wmark.hit.quickly"; + const std::string SYS_VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY_DESC = "sys.virtual.mem.high.wmark.hit.quickly"; + const std::string SYS_VMEMINFO_PAGEOUTRUN_DESC = "sys.virtual.mem.pageoutrun"; + const std::string SYS_VMEMINFO_ALLOCSTALL_DESC = "sys.virtual.mem.allocstall"; + const std::string SYS_VMEMINFO_PGROTATED_DESC = "sys.virtual.mem.pgrotated"; + const std::string SYS_VMEMINFO_DROP_PAGECACHE_DESC = "sys.virtual.mem.drop.pagecache"; + const std::string SYS_VMEMINFO_DROP_SLAB_DESC = "sys.virtual.mem.drop.slab"; + const std::string SYS_VMEMINFO_PGMIGRATE_SUCCESS_DESC = "sys.virtual.mem.pgmigrate.success"; + const std::string SYS_VMEMINFO_PGMIGRATE_FAIL_DESC = "sys.virtual.mem.pgmigrate.fail"; + const std::string SYS_VMEMINFO_COMPACT_MIGRATE_SCANNED_DESC = "sys.virtual.mem.compact.migrate.scanned"; + const std::string SYS_VMEMINFO_COMPACT_FREE_SCANNED_DESC = "sys.virtual.mem.compact.free.scanned"; + const std::string SYS_VMEMINFO_COMPACT_ISOLATED_DESC = "sys.virtual.mem.compact.isolated"; + const std::string SYS_VMEMINFO_COMPACT_STALL_DESC = "sys.virtual.mem.compact.stall"; + const std::string SYS_VMEMINFO_COMPACT_FAIL_DESC = "sys.virtual.mem.compact.fail"; + const std::string SYS_VMEMINFO_COMPACT_SUCCESS_DESC = "sys.virtual.mem.compact.success"; + const std::string SYS_VMEMINFO_COMPACT_DAEMON_WAKE_DESC = "sys.virtual.mem.compact.daemon.wake"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_CULLED_DESC = "sys.virtual.mem.unevictable.pgs.culled"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_SCANNED_DESC = "sys.virtual.mem.unevictable.pgs.scanned"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_RESCUED_DESC = "sys.virtual.mem.unevictable.pgs.rescued"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_MLOCKED_DESC = "sys.virtual.mem.unevictable.pgs.mlocked"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED_DESC = "sys.virtual.mem.unevictable.pgs.munlocked"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_CLEARED_DESC = "sys.virtual.mem.unevictable.pgs.cleared"; + const std::string SYS_VMEMINFO_UNEVICTABLE_PGS_STRANDED_DESC = "sys.virtual.mem.unevictable.pgs.stranded"; + const std::string SYS_VMEMINFO_NR_ZSPAGES_DESC = "sys.virtual.mem.nr.zspages"; + const std::string SYS_VMEMINFO_NR_ION_HEAP_DESC = "sys.virtual.mem.nr.ion.heap"; + const std::string SYS_VMEMINFO_NR_GPU_HEAP_DESC = "sys.virtual.mem.nr.gpu.heap"; + const std::string SYS_VMEMINFO_ALLOCSTALL_DMA_DESC = "sys.virtual.mem.allocstall.dma"; + const std::string SYS_VMEMINFO_ALLOCSTALL_MOVABLE_DESC = "sys.virtual.mem.allocstall.movable"; + const std::string SYS_VMEMINFO_ALLOCSTALL_NORMAL_DESC = "sys.virtual.mem.allocstall.normal"; + const std::string SYS_VMEMINFO_COMPACT_DAEMON_FREE_SCANNED_DESC = "sys.virtual.mem.compact_daemon.free.scanned"; + const std::string SYS_VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED_DESC = + "sys.virtual.mem.compact.daemon.migrate.scanned"; + const std::string SYS_VMEMINFO_NR_FASTRPC_DESC = "sys.virtual.mem.nr.fastrpc"; + const std::string SYS_VMEMINFO_NR_INDIRECTLY_RECLAIMABLE_DESC = "sys.virtual.mem.nr.indirectly.reclaimable"; + const std::string SYS_VMEMINFO_NR_ION_HEAP_POOL_DESC = "sys.virtual.mem.nr_ion_heap_pool"; + const std::string SYS_VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE_DESC = "sys.virtual.mem.nr.kernel_misc.reclaimable"; + const std::string SYS_VMEMINFO_NR_SHADOW_CALL_STACK_BYTES_DESC = "sys.virtual.mem.nr.shadow_call.stack_bytes"; + const std::string SYS_VMEMINFO_NR_SHMEM_HUGEPAGES_DESC = "sys.virtual.mem.nr.shmem.hugepages"; + const std::string SYS_VMEMINFO_NR_SHMEM_PMDMAPPED_DESC = "sys.virtual.mem.nr.shmem.pmdmapped"; + const std::string SYS_VMEMINFO_NR_UNRECLAIMABLE_PAGES_DESC = "sys.virtual.mem.nr.unreclaimable.pages"; + const std::string SYS_VMEMINFO_NR_ZONE_ACTIVE_ANON_DESC = "sys.virtual.mem.nr.zone.active.anon"; + const std::string SYS_VMEMINFO_NR_ZONE_ACTIVE_FILE_DESC = "sys.virtual.mem.nr.zone.active.file"; + const std::string SYS_VMEMINFO_NR_ZONE_INACTIVE_ANON_DESC = "sys.virtual.mem.nr.zone.inactive_anon"; + const std::string SYS_VMEMINFO_NR_ZONE_INACTIVE_FILE_DESC = "sys.virtual.mem.nr.zone.inactive_file"; + const std::string SYS_VMEMINFO_NR_ZONE_UNEVICTABLE_DESC = "sys.virtual.mem.nr.zone.unevictable"; + const std::string SYS_VMEMINFO_NR_ZONE_WRITE_PENDING_DESC = "sys.virtual.mem.nr.zone.write_pending"; + const std::string SYS_VMEMINFO_OOM_KILL_DESC = "sys.virtual.mem.oom.kill"; + const std::string SYS_VMEMINFO_PGLAZYFREE_DESC = "sys.virtual.mem.pglazyfree"; + const std::string SYS_VMEMINFO_PGLAZYFREED_DESC = "sys.virtual.mem.pglazyfreed"; + const std::string SYS_VMEMINFO_PGREFILL_DESC = "sys.virtual.mem.pgrefill"; + const std::string SYS_VMEMINFO_PGSCAN_DIRECT_DESC = "sys.virtual.mem.pgscan.direct"; + const std::string SYS_VMEMINFO_PGSCAN_KSWAPD_DESC = "sys.virtual.mem.pgscan.kswapd"; + const std::string SYS_VMEMINFO_PGSKIP_DMA_DESC = "sys.virtual.mem.pgskip.dma"; + const std::string SYS_VMEMINFO_PGSKIP_MOVABLE_DESC = "sys.virtual.mem.pgskip.movable"; + const std::string SYS_VMEMINFO_PGSKIP_NORMAL_DESC = "sys.virtual.mem.pgskip.normal"; + const std::string SYS_VMEMINFO_PGSTEAL_DIRECT_DESC = "sys.virtual.mem.pgsteal.direct"; + const std::string SYS_VMEMINFO_PGSTEAL_KSWAPD_DESC = "sys.virtual.mem.pgsteal.kswapd"; + const std::string SYS_VMEMINFO_SWAP_RA_DESC = "sys.virtual.mem.swap.ra"; + const std::string SYS_VMEMINFO_SWAP_RA_HIT_DESC = "sys.virtual.mem.swap.ra.hit"; + const std::string SYS_VMEMINFO_WORKINGSET_RESTORE_DESC = "sys.virtual.mem.workingset.restore"; + + const std::string TRACE_STAT_TYPE_RECEIVED_DESC = "received"; + const std::string TRACE_STAT_TYPE_LOST_DESC = "data_lost"; + const std::string TRACE_STAT_TYPE_NOTMATCH_DESC = "not_match"; + const std::string TRACE_STAT_TYPE_NOTSUPPORTED_DESC = "not_supported"; + const std::string TRACE_STAT_TYPE_DATA_INVALID_DESC = "invalid_data"; + + const std::string STAT_SEVERITY_LEVEL_INFO_DESC = "info"; + const std::string STAT_SEVERITY_LEVEL_WARN_DESC = "warn"; + const std::string STAT_SEVERITY_LEVEL_ERROR_DESC = "error"; + const std::string STAT_SEVERITY_LEVEL_FATAL_DESC = "fatal"; +}; +} // namespace TraceCfg +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/ext/BUILD.gn b/trace_streamer/src/ext/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0099b5d862f83ed29c1503173721c389b019af94 --- /dev/null +++ b/trace_streamer/src/ext/BUILD.gn @@ -0,0 +1,28 @@ +# 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") +config("sqlite_config") { + include_dirs = [ + "../../third_party/sqlite/include", + "../include", + ] + cflags = [ + "-Wno-writable-strings", + "-std=c++17", + ] +} +source_set("sqliteext") { + sources = [ "sqlite_ext_funcs.cpp" ] + public_configs = [ ":sqlite_config" ] +} diff --git a/trace_streamer/src/ext/sqlite_ext_funcs.cpp b/trace_streamer/src/ext/sqlite_ext_funcs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c35955063fa48b30ce0dfd026887a0660e7b3b8 --- /dev/null +++ b/trace_streamer/src/ext/sqlite_ext_funcs.cpp @@ -0,0 +1,363 @@ +/* + * 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 "sqlite_ext_funcs.h" +#include +#include +#include +#include "log.h" +#include "sqlite3.h" +#include "../base/string_help.h" +namespace SysTuning { +namespace base { +/* +** Return a stdev value +*/ +static void sqliteExtStdevFinalize(sqlite3_context* context) +{ + StdevCtx* ptr = static_cast(sqlite3_aggregate_context(context, 0)); + if (ptr && ptr->cntValue > 1) { + sqlite3_result_double(context, sqrt(ptr->rSValue / (ptr->cntValue - 1))); + } else { + sqlite3_result_double(context, 0.0); + } +} +/* +** called each value received during a calculation of stdev or variance +*/ +static void sqliteExtStdevNextStep(sqlite3_context* context, int32_t argc, sqlite3_value** argv) +{ + double deltaValue; + double x; + + TS_ASSERT(argc == 1); + StdevCtx* ptr = static_cast(sqlite3_aggregate_context(context, sizeof(StdevCtx))); + if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) { + ptr->cntValue++; + x = sqlite3_value_double(argv[0]); + deltaValue = (x - ptr->rMValue); + ptr->rMValue += deltaValue / ptr->cntValue; + ptr->rSValue += deltaValue * (x - ptr->rMValue); + } +} + +enum Type { + TS_NULL = 0, + TS_LONG, + TS_DOUBLE, + TS_STRING, + TS_BYTES, +}; + +struct TSSqlValue { + TSSqlValue() = default; + + static TSSqlValue Long(int64_t v) + { + TSSqlValue value; + value.longValue = v; + value.type = Type::TS_LONG; + return value; + } + + static TSSqlValue Double(double v) + { + TSSqlValue value; + value.doubleValue = v; + value.type = Type::TS_DOUBLE; + return value; + } + + static TSSqlValue String(const char* v) + { + TSSqlValue value; + value.stringValue = v; + value.type = Type::TS_STRING; + return value; + } + + static TSSqlValue Bytes(const char* v, size_t size) + { + TSSqlValue value; + value.bytesValue = v; + value.bytesCount = size; + value.type = Type::TS_BYTES; + return value; + } + + double GetDouble() const + { + return doubleValue; + } + int64_t GetLong() const + { + return longValue; + } + const char* GetString() const + { + return stringValue; + } + const void* GetBytes() const + { + return bytesValue; + } + + bool IsNull() const + { + return type == Type::TS_NULL; + } + + union { + const char* stringValue; + int64_t longValue; + double doubleValue; + const void* bytesValue; + }; + size_t bytesCount = 0; + Type type = TS_NULL; +}; + +TSSqlValue SqliteValueToTSSqlValue(sqlite3_value* value) +{ + TSSqlValue sqlValue; + switch (sqlite3_value_type(value)) { + case SQLITE_INTEGER: + sqlValue.type = Type::TS_LONG; + sqlValue.longValue = sqlite3_value_int64(value); + break; + case SQLITE_FLOAT: + sqlValue.type = Type::TS_DOUBLE; + sqlValue.doubleValue = sqlite3_value_double(value); + break; + case SQLITE_TEXT: + sqlValue.type = Type::TS_STRING; + sqlValue.stringValue = reinterpret_cast(sqlite3_value_text(value)); + break; + case SQLITE_BLOB: + sqlValue.type = Type::TS_BYTES; + sqlValue.bytesValue = sqlite3_value_blob(value); + sqlValue.bytesCount = static_cast(sqlite3_value_bytes(value)); + break; + } + return sqlValue; +} +class JsonBuild { +public: + JsonBuild() = default; + void AppendHead() + { + body_ += "{"; + } + void AppendTail() + { + body_ += "}"; + } + void AppendCommon() + { + body_ += ","; + } + bool AppendSqlValue(const std::string& field_name, const TSSqlValue& value) + { + body_ += "\"" + field_name + "\":"; + return AppendSqlValue(value); + } + bool AppendSqlValue(const TSSqlValue& value) + { + switch (value.type) { + case TS_LONG: + body_ += std::to_string(value.longValue) + ","; + break; + case TS_DOUBLE: + body_ += std::to_string(value.doubleValue) + ","; + break; + case TS_STRING: + body_ += "\"" + std::string(value.stringValue) + "\"" + ","; + break; + case TS_BYTES: + body_ += "\"" + std::string(static_cast(value.bytesValue), value.bytesCount) + "\"" + ","; + break; + case TS_NULL: + body_ += std::to_string(0) + ","; + break; + } + return true; + } + std::string body_; + bool poped_ = false; + void PopLast() + { + body_.pop_back(); + } + const std::string& Body() + { + return body_; + } +}; + +void BuildJson(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + const int32_t PAIR_ARGS_SIZE = 2; + if (argc % PAIR_ARGS_SIZE != 0) { + TS_LOGI("BuildJson arg number error"); + sqlite3_result_error(ctx, "BuildJson arg number error", -1); + return; + } + + JsonBuild builder; + builder.AppendHead(); + for (int32_t i = 0; i < argc; i += PAIR_ARGS_SIZE) { + if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) { + TS_LOGI("BuildJson: Invalid args argc:%d, %d", argc, sqlite3_value_type(argv[i])); + sqlite3_result_error(ctx, "BuildJson: Invalid args", -1); + return; + } + + auto* key = reinterpret_cast(sqlite3_value_text(argv[i])); + auto value = SqliteValueToTSSqlValue(argv[i + 1]); + auto status = builder.AppendSqlValue(key, value); + if (!status) { + TS_LOGI("AppendSqlValueError"); + sqlite3_result_error(ctx, "AppendSqlValueError", -1); + return; + } + } + builder.PopLast(); + builder.AppendTail(); + std::string raw = builder.Body(); + if (raw.empty()) { + sqlite3_result_blob(ctx, "", 0, nullptr); + return; + } + std::unique_ptr data = std::make_unique(raw.size()); + memcpy_s(data.get(), raw.size(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} + +void RepeatedJsonStep(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + const int32_t PAIR_ARGS_SIZE = 2; + auto** jsonBuild = static_cast(sqlite3_aggregate_context(ctx, sizeof(JsonBuild*))); + + if (*jsonBuild == nullptr) { + *jsonBuild = new JsonBuild(); + } + JsonBuild* builder = *jsonBuild; + builder->AppendHead(); + for (int32_t i = 0; i < argc; i += PAIR_ARGS_SIZE) { + if (sqlite3_value_type(argv[i]) != SQLITE_TEXT) { + TS_LOGI("BuildJson: Invalid args argc:%d, %d", argc, sqlite3_value_type(argv[i])); + sqlite3_result_error(ctx, "BuildJson: Invalid args", -1); + return; + } + + auto* key = reinterpret_cast(sqlite3_value_text(argv[i])); + auto value = SqliteValueToTSSqlValue(argv[i + 1]); + auto status = builder->AppendSqlValue(key, value); + if (!status) { + TS_LOGI("AppendSqlValueError"); + sqlite3_result_error(ctx, "AppendSqlValueError", -1); + return; + } + } + builder->PopLast(); + builder->AppendTail(); + builder->AppendCommon(); +} +void RepeatedFieldStep(sqlite3_context* ctx, int32_t argc, sqlite3_value** argv) +{ + if (argc != 1) { + TS_LOGE( + "RepeatedField only support one arg, you can use BuildJson or BuildRepeatedJson function for multi args"); + return; + } + auto** jsonBuild = static_cast(sqlite3_aggregate_context(ctx, sizeof(JsonBuild*))); + + if (*jsonBuild == nullptr) { + *jsonBuild = new JsonBuild(); + } + JsonBuild* builder = *jsonBuild; + for (int32_t i = 0; i < argc; i++) { + auto value = SqliteValueToTSSqlValue(argv[i]); + auto status = builder->AppendSqlValue(value); + if (!status) { + sqlite3_result_error(ctx, "error", -1); + } + } +} + +void RepeatedFieldFinal(sqlite3_context* ctx) +{ + auto** jsonBuilder = static_cast(sqlite3_aggregate_context(ctx, 0)); + + if (jsonBuilder == nullptr) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr builder(*jsonBuilder); + std::string raw = builder->Body(); + raw.pop_back(); + if (raw.empty()) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr data = std::make_unique(raw.size()); + memcpy_s(data.get(), raw.size(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} + +void RepeatedJsonFinal(sqlite3_context* ctx) +{ + auto** jsonBuilder = static_cast(sqlite3_aggregate_context(ctx, 0)); + + if (jsonBuilder == nullptr) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr builder(*jsonBuilder); + builder->PopLast(); + std::string raw = builder->Body(); + if (raw.empty()) { + sqlite3_result_null(ctx); + return; + } + + std::unique_ptr data = std::make_unique(raw.size()); + memcpy_s(data.get(), raw.size(), raw.data(), raw.size()); + sqlite3_result_blob(ctx, data.release(), static_cast(raw.size()), free); +} +void ts_create_extend_function(sqlite3* db) +{ + sqlite3_create_function(db, "stdev", -1, SQLITE_UTF8, nullptr, 0, sqliteExtStdevNextStep, sqliteExtStdevFinalize); + auto ret = sqlite3_create_function_v2(db, "RepeatedField", 1, SQLITE_UTF8, nullptr, nullptr, RepeatedFieldStep, + RepeatedFieldFinal, nullptr); + if (ret) { + TS_LOGF("Error while initializing RepeatedField"); + } + ret = sqlite3_create_function_v2(db, "BuildRepeatedJson", -1, SQLITE_UTF8, nullptr, nullptr, RepeatedJsonStep, + RepeatedJsonFinal, nullptr); + if (ret) { + TS_LOGF("Error while initializing BuildRepeatedJson"); + } + std::unique_ptr ctx = std::make_unique(); + ret = sqlite3_create_function_v2(db, "BuildJson", -1, SQLITE_UTF8, ctx.release(), BuildJson, nullptr, nullptr, + [](void* ptr) { delete static_cast(ptr); }); + if (ret != SQLITE_OK) { + TS_LOGF("Error while initializing BuildJson"); + } +} +} // namespace base +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/src/ext/sqlite_ext_funcs.h b/trace_streamer/src/ext/sqlite_ext_funcs.h new file mode 100644 index 0000000000000000000000000000000000000000..e1ce74a727d69a10d177682f38f54ac943c0687c --- /dev/null +++ b/trace_streamer/src/ext/sqlite_ext_funcs.h @@ -0,0 +1,30 @@ +/* + * 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 SQLITE_EXT_FUNCS_H +#define SQLITE_EXT_FUNCS_H 1 +#include +#include "sqlite3.h" +namespace SysTuning { +namespace base { +typedef struct StdevCtx StdevCtx; +struct StdevCtx { + double rMValue; + double rSValue; + int64_t cntValue; +}; +void ts_create_extend_function(sqlite3* db); +} // namespace base +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/filter/BUILD.gn b/trace_streamer/src/filter/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..63a7177b8bf594f1ccd56a2655ccd22fd57a82dc --- /dev/null +++ b/trace_streamer/src/filter/BUILD.gn @@ -0,0 +1,100 @@ +# 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("//src/ts.gni") + +ohos_source_set("filter") { + subsystem_name = "trace_streamer" + part_name = "trace_streamer_filter" + sources = [ + "args_filter.cpp", + "args_filter.h", + "binder_filter.cpp", + "binder_filter.h", + "clock_filter.cpp", + "clock_filter.h", + "cpu_filter.cpp", + "filter_base.cpp", + "filter_base.h", + "filter_filter.cpp", + "filter_filter.h", + "frame_filter.cpp", + "frame_filter.h", + "hi_sysevent_measure_filter.cpp", + "hi_sysevent_measure_filter.h", + "irq_filter.cpp", + "irq_filter.h", + "measure_filter.cpp", + "measure_filter.h", + "process_filter.cpp", + "process_filter.h", + "slice_filter.cpp", + "slice_filter.h", + "stat_filter.cpp", + "stat_filter.h", + "symbols_filter.cpp", + "symbols_filter.h", + "system_event_measure_filter.cpp", + "system_event_measure_filter.h", + ] + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } + deps = [] + include_dirs = [ + "//src/base", + "//src/trace_streamer", + "//src/trace_data", + "//src/include", + "//src/filter", + "//src/cfg", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//src", + "//third_party/protobuf/src", + "//third_party/sqlite/include", + ".", + ] + + if (!is_pbdecoder) { + sources += [ + "native_hook_filter.cpp", + "native_hook_filter.h", + "offline_symbolization_filter.cpp", + "offline_symbolization_filter.h", + ] + include_dirs += [ + "../proto_reader/include", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "//third_party/perf_include/musl", + ] + } + + if (with_perf) { + sources += [ + "perf_data_filter.cpp", + "perf_data_filter.h", + ] + } +} diff --git a/trace_streamer/src/filter/args_filter.cpp b/trace_streamer/src/filter/args_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9cb68bfbf5e752d5ce56d134c646a0e3977839f3 --- /dev/null +++ b/trace_streamer/src/filter/args_filter.cpp @@ -0,0 +1,55 @@ +/* + * 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 "args_filter.h" +#include "filter_filter.h" +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +ArgsFilter::ArgsFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) : FilterBase(dataCache, filter) +{ + (void)traceDataCache_->GetDataTypeData()->AppendNewDataType(BASE_DATA_TYPE_INT, + traceDataCache_->GetDataIndex("int32_t")); + (void)traceDataCache_->GetDataTypeData()->AppendNewDataType(BASE_DATA_TYPE_STRING, + traceDataCache_->GetDataIndex("string")); + (void)traceDataCache_->GetDataTypeData()->AppendNewDataType(BASE_DATA_TYPE_DOUBLE, + traceDataCache_->GetDataIndex("double")); + (void)traceDataCache_->GetDataTypeData()->AppendNewDataType(BASE_DATA_TYPE_BOOLEAN, + traceDataCache_->GetDataIndex("boolean")); +} + +ArgsFilter::~ArgsFilter() {} + +uint32_t ArgsFilter::NewArgs(const ArgsSet& args) +{ + auto argSet = traceDataCache_->GetArgSetData(); + for (auto it = args.valuesMap_.begin(); it != args.valuesMap_.end(); it++) { + (void)argSet->AppendNewArg(it->first, it->second.type, it->second.value, count_); + } + count_++; + return count_ - 1; +} +uint32_t ArgsFilter::AppendArgs(const ArgsSet& args, const size_t argSetId) +{ + auto argSet = traceDataCache_->GetArgSetData(); + for (auto it = args.valuesMap_.begin(); it != args.valuesMap_.end(); it++) { + (void)argSet->AppendNewArg(it->first, it->second.type, it->second.value, argSetId); + } + return count_ - 1; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/args_filter.h b/trace_streamer/src/filter/args_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..2f187d193d3f3bd367a3ec5601da3a20e973a38d --- /dev/null +++ b/trace_streamer/src/filter/args_filter.h @@ -0,0 +1,43 @@ +/* + * 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 ARGS_FILTER_H +#define ARGS_FILTER_H + +#include +#include +#include + +#include "args_set.h" +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class ArgsFilter : private FilterBase { +public: + ArgsFilter(TraceDataCache*, const TraceStreamerFilters*); + ArgsFilter(const ArgsFilter&) = delete; + ArgsFilter& operator=(const ArgsFilter&) = delete; + ~ArgsFilter() override; + uint32_t NewArgs(const ArgsSet& args); + uint32_t AppendArgs(const ArgsSet& args, const size_t argSetId); + int32_t count_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // ARGS_FILTER_H diff --git a/trace_streamer/src/filter/binder_filter.cpp b/trace_streamer/src/filter/binder_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a961fd4e22a187b5cd64bf43a84cdfb44b97c74 --- /dev/null +++ b/trace_streamer/src/filter/binder_filter.cpp @@ -0,0 +1,202 @@ +/* + * 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 "binder_filter.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +BinderFilter::BinderFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter) +{ + binderFlagDescs_ = {{noReturnMsgFlag_, " this is a one-way call: async, no return; "}, + {rootObjectMsgFlag_, " contents are the components root object; "}, + {statusCodeMsgFlag_, " contents are a 32-bit status code; "}, + {acceptFdsMsgFlag_, " allow replies with file descriptors; "}, + {noFlagsMsgFlag_, " No Flags Set"}}; +} +BinderFilter::~BinderFilter() = default; + +std::string BinderFilter::GetBinderFlagsDesc(uint32_t flag) +{ + std::string str; + if (flag & noReturnMsgFlag_) { + str += binderFlagDescs_.at(noReturnMsgFlag_); + } + if (flag & rootObjectMsgFlag_) { + str += binderFlagDescs_.at(rootObjectMsgFlag_); + } + if (flag & statusCodeMsgFlag_) { + str += binderFlagDescs_.at(statusCodeMsgFlag_); + } + if (flag & acceptFdsMsgFlag_) { + str += binderFlagDescs_.at(acceptFdsMsgFlag_); + } + if (flag == noFlagsMsgFlag_) { + str += binderFlagDescs_.at(noFlagsMsgFlag_); + } + return str; +} +void BinderFilter::SendTraction(int64_t ts, + uint32_t tid, + uint64_t transactionId, + int32_t destNode, + int32_t destTgid, + int32_t destTid, + bool isReply, + int32_t flags, + int32_t code) +{ + auto flagsStr = traceDataCache_->GetDataIndex("0x" + base::number(flags, base::INTEGER_RADIX_TYPE_HEX) + + GetBinderFlagsDesc(flags)); + DataIndex codeStr = traceDataCache_->GetDataIndex("0x" + base::number(code, base::INTEGER_RADIX_TYPE_HEX) + + " Java Layer Dependent"); + ArgsSet argsSend; + argsSend.AppendArg(transId_, BASE_DATA_TYPE_INT, transactionId); + argsSend.AppendArg(destNodeId_, BASE_DATA_TYPE_INT, destNode); + argsSend.AppendArg(destProcessId_, BASE_DATA_TYPE_INT, destTgid); + argsSend.AppendArg(isReplayId_, BASE_DATA_TYPE_BOOLEAN, isReply); + argsSend.AppendArg(flagsId_, BASE_DATA_TYPE_STRING, flagsStr); + argsSend.AppendArg(codeId_, BASE_DATA_TYPE_STRING, codeStr); + argsSend.AppendArg(callingTid_, BASE_DATA_TYPE_INT, tid); + + if (isReply) { + // sometime a reply-binder from a tid appear repeated to different dest, we only chose the right one + if (transReplyFilter_.count(tid) && transReplyFilter_[tid] == destTid) { + // Add dest information to Reply slices, the Begin msg is from TAG-2 + InternalTid dstItid = streamFilters_->processFilter_->UpdateOrCreateThread(ts, destTid); + const auto destThreadName = traceDataCache_->GetConstThreadData(dstItid).nameIndex_; + ArgsSet destArgs; + destArgs.AppendArg(destThreadId_, BASE_DATA_TYPE_INT, destTid); + destArgs.AppendArg(destThreadNameId_, BASE_DATA_TYPE_STRING, destThreadName); + (void)streamFilters_->sliceFilter_->AddArgs(tid, binderCatalogId_, replyId_, destArgs); + transReplyFilter_.erase(tid); + } + // the flowing code should be under the ubove conditions, but this will bring a big impact to the UI-SHOW + (void)streamFilters_->sliceFilter_->EndBinder(ts, tid, INVALID_UINT64, INVALID_UINT64, argsSend); + transReplyWaitingReply_.insert(transactionId); + return; + } else { + bool needReply = !isReply && !(flags & noReturnMsgFlag_); + if (needReply) { + // transaction needs reply TAG-1 + (void)streamFilters_->sliceFilter_->BeginBinder(ts, tid, binderCatalogId_, transSliceId_, argsSend); + transNeedReply_[transactionId] = tid; + } else { + // transaction do not need reply + // tid calling id + // a binder event only care the transactionId and the callint tid + (void)streamFilters_->sliceFilter_->AsyncBinder(ts, tid, binderCatalogId_, transAsyncId_, argsSend); + asyncBinderEvents_[transactionId] = argsSend; + } + } +} +void BinderFilter::ReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId) +{ + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(ts, pid); + const auto threadName = traceDataCache_->GetConstThreadData(internalTid).nameIndex_; + if (transReplyWaitingReply_.count(transactionId)) { + (void)streamFilters_->sliceFilter_->EndBinder(ts, pid); + transReplyWaitingReply_.erase(transactionId); + return; + } + + if (transNeedReply_.count(transactionId)) { + // First, begin the reply, the reply will be end in "SendTraction" func, and the isReply will be true, TAG-2 + auto replySliceid = streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, replyId_); + transReplyFilter_[pid] = transNeedReply_[transactionId]; + // Add dest info to the reply + ArgsSet args; + args.AppendArg(destThreadId_, BASE_DATA_TYPE_INT, pid); + args.AppendArg(destThreadNameId_, BASE_DATA_TYPE_STRING, threadName); + if (IsValidUint32(static_cast(replySliceid))) { + args.AppendArg(destSliceId_, BASE_DATA_TYPE_INT, replySliceid); + } + // Add dest args + uint64_t transSliceId = INVALID_UINT64; + uint32_t argSetId = INVALID_UINT32; + std::tie(transSliceId, argSetId) = streamFilters_->sliceFilter_->AddArgs(transNeedReply_[transactionId], + binderCatalogId_, transSliceId_, args); + + // remeber dest slice-id to the argset from "SendTraction" TAG-1 + ArgsSet replyDestInserter; + if (IsValidUint32(transSliceId)) { + replyDestInserter.AppendArg(destSliceId_, BASE_DATA_TYPE_INT, transSliceId); + } + std::tie(transSliceId, argSetId) = + streamFilters_->sliceFilter_->AddArgs(pid, binderCatalogId_, replyId_, replyDestInserter); + traceDataCache_->GetInternalSlicesData()->SetArgSetId(transSliceId, argSetId); + transNeedReply_.erase(transactionId); + return; + } + // the code below can be hard to understand, may be a EndBinder will be better + // this problem can be test after the IDE is finished + if (asyncBinderEvents_.count(transactionId)) { + auto args = asyncBinderEvents_[transactionId]; + (void)streamFilters_->sliceFilter_->AsyncBinder(ts, pid, binderCatalogId_, asyncRcvId_, args); + // maybe you can use the flowing code: streamFilters_->sliceFilter_->EndBinder(ts, pid); + asyncBinderEvents_.erase(transactionId); + return; + } +} +void BinderFilter::TransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize) +{ + ArgsSet args; + args.AppendArg(dataSizeId_, BASE_DATA_TYPE_INT, dataSize); + args.AppendArg(dataOffsetSizeId_, BASE_DATA_TYPE_INT, offsetsSize); + (void)streamFilters_->sliceFilter_->AddArgs(pid, binderCatalogId_, transSliceId_, args); + UNUSED(ts); +} +void BinderFilter::TractionLock(int64_t ts, uint32_t pid, const std::string& tag) +{ + UNUSED(tag); + lastEventTs_[pid] = ts; + (void)streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, lockTryId_); +} +void BinderFilter::TractionLocked(int64_t ts, uint32_t pid, const std::string& tag) +{ + UNUSED(tag); + if (!lastEventTs_.count(pid)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, STAT_EVENT_NOTMATCH); + return; + } + (void)streamFilters_->sliceFilter_->EndBinder(ts, pid); + (void)streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, lockHoldId_); + lastEventTs_.erase(pid); + lastEventTs_[pid] = ts; +} +void BinderFilter::TractionUnlock(int64_t ts, uint32_t pid, const std::string& tag) +{ + UNUSED(tag); + if (!lastEventTs_.count(pid)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, STAT_EVENT_NOTMATCH); + return; + } + (void)streamFilters_->sliceFilter_->EndBinder(ts, pid, binderCatalogId_, lockHoldId_); + lastEventTs_.erase(pid); + lastEventTs_[pid] = ts; +} +void BinderFilter::Clear() +{ + lastEventTs_.clear(); + transReplyWaitingReply_.clear(); + transNeedReply_.clear(); + asyncBinderEvents_.clear(); + binderFlagDescs_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/binder_filter.h b/trace_streamer/src/filter/binder_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..e475cc78f5c6288b3fcd89b9d0d8f831e76dae24 --- /dev/null +++ b/trace_streamer/src/filter/binder_filter.h @@ -0,0 +1,91 @@ +/* + * 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 BINDER_FILTER_H +#define BINDER_FILTER_H + +#include +#include "args_set.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class BinderFilter : private FilterBase { +public: + BinderFilter(TraceDataCache*, const TraceStreamerFilters*); + BinderFilter(const BinderFilter&) = delete; + BinderFilter& operator=(const BinderFilter&) = delete; + ~BinderFilter() override; + +public: + void SendTraction(int64_t ts, + uint32_t tid, + uint64_t transactionId, + int32_t destNode, + int32_t destTgid, + int32_t destTid, + bool isReply, + int32_t flags, + int32_t code); + void ReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId); + void TransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize); + void TractionLock(int64_t ts, uint32_t pid, const std::string& tag); + void TractionLocked(int64_t ts, uint32_t pid, const std::string& tag); + void TractionUnlock(int64_t ts, uint32_t pid, const std::string& tag); + void Clear(); + +private: + std::string GetBinderFlagsDesc(uint32_t flag); + bool IsValidUint32(uint32_t value) const + { + return (value != INVALID_UINT32); + } + uint32_t noReturnMsgFlag_ = 0x01; + uint32_t rootObjectMsgFlag_ = 0x04; + uint32_t statusCodeMsgFlag_ = 0x08; + uint32_t acceptFdsMsgFlag_ = 0x10; + uint32_t noFlagsMsgFlag_ = 0; + const DataIndex binderCatalogId_ = traceDataCache_->GetDataIndex("binder"); + const DataIndex replyId_ = traceDataCache_->GetDataIndex("binder reply"); + const DataIndex isReplayId_ = traceDataCache_->GetDataIndex("reply transaction?"); + const DataIndex flagsId_ = traceDataCache_->GetDataIndex("flags"); + const DataIndex transSliceId_ = traceDataCache_->GetDataIndex("binder transaction"); + const DataIndex transId_ = traceDataCache_->GetDataIndex("transaction id"); + const DataIndex asyncRcvId_ = traceDataCache_->GetDataIndex("binder async rcv"); + const DataIndex codeId_ = traceDataCache_->GetDataIndex("code"); + const DataIndex callingTid_ = traceDataCache_->GetDataIndex("calling tid"); + const DataIndex destNodeId_ = traceDataCache_->GetDataIndex("destination node"); + const DataIndex destThreadId_ = traceDataCache_->GetDataIndex("destination thread"); + const DataIndex destThreadNameId_ = traceDataCache_->GetDataIndex("destination name"); + const DataIndex destSliceId_ = traceDataCache_->GetDataIndex("destination slice id"); + const DataIndex destProcessId_ = traceDataCache_->GetDataIndex("destination process"); + const DataIndex transAsyncId_ = traceDataCache_->GetDataIndex("binder transaction async"); + const DataIndex lockTryId_ = traceDataCache_->GetDataIndex("binder lock waiting"); + const DataIndex lockHoldId_ = traceDataCache_->GetDataIndex("binder lock held"); + const DataIndex dataSizeId_ = traceDataCache_->GetDataIndex("data size"); + const DataIndex dataOffsetSizeId_ = traceDataCache_->GetDataIndex("offsets size"); + const DataIndex nullStringId_ = traceDataCache_->GetDataIndex("null"); + std::unordered_map lastEventTs_ = {}; + std::unordered_set transReplyWaitingReply_ = {}; + std::unordered_map transNeedReply_ = {}; + std::unordered_map transReplyFilter_ = {}; + std::unordered_map asyncBinderEvents_ = {}; + std::unordered_map binderFlagDescs_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // BINDER_FILTER_H diff --git a/trace_streamer/src/filter/clock_filter.cpp b/trace_streamer/src/filter/clock_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdc880c76f55b6d5cc530863108f1d07a4f39fca --- /dev/null +++ b/trace_streamer/src/filter/clock_filter.cpp @@ -0,0 +1,103 @@ +/* + * 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 "clock_filter.h" +#include +#include + +namespace SysTuning { +namespace TraceStreamer { +ClockFilter::ClockFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter), primaryClock_(BuiltinClocks::TS_CLOCK_BOOTTIME), dataCache_(dataCache) +{ +} + +ClockFilter::~ClockFilter() {} + +std::string ClockFilter::GenClockKey(ClockId srcClockId, ClockId desClockId) +{ + std::string ret; + ret += std::to_string(srcClockId); + ret += ","; + ret += std::to_string(desClockId); + return ret; +} + +uint64_t ClockFilter::ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const +{ + if (srcClockId == primaryClock_) { + return srcTs; + } + return Convert(srcClockId, srcTs, primaryClock_); +} + +uint64_t ClockFilter::Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const +{ + std::string&& clockKey = GenClockKey(srcClockId, desClockId); + auto keyIt = clockMaps_.find(clockKey); + if (keyIt == clockMaps_.end()) { + return srcTs; + } + + auto tsIt = keyIt->second.upper_bound(srcTs); + if (tsIt != keyIt->second.begin()) { + tsIt--; + } + + if (tsIt->second >= 0) { + return srcTs + static_cast(tsIt->second); + } else { + return srcTs - static_cast(0 - tsIt->second); + } +} + +void ClockFilter::AddConvertClockMap(ClockId srcClockId, ClockId dstClockId, uint64_t srcTs, uint64_t dstTs) +{ + std::string&& clockKey = GenClockKey(srcClockId, dstClockId); + auto keyIt = clockMaps_.find(clockKey); + if (keyIt == clockMaps_.end()) { + ConvertClockMap newConvertMap = {{srcTs, dstTs - srcTs}}; + clockMaps_[clockKey] = newConvertMap; + } else { + clockMaps_[clockKey].insert(std::make_pair(srcTs, dstTs - srcTs)); + } +} + +void ClockFilter::AddClockSnapshot(const std::vector& snapShot) +{ + ClockId srcId, desId; + const int32_t theDataBeforeLast = 2; + for (srcId = 0; srcId < snapShot.size() - 1; ++srcId) { + ClockId srcClockId = snapShot[srcId].clockId; + uint64_t srcTs = snapShot[srcId].ts; + (void)traceDataCache_->GetClockSnapshotData()->AppendNewSnapshot( + srcClockId, srcTs, + dataCache_->GetConstStatAndInfo().clockid2ClockNameMap_.at(static_cast(srcClockId))); + for (desId = srcId + 1; desId < snapShot.size(); ++desId) { + ClockId desClockId = snapShot[desId].clockId; + uint64_t desTs = snapShot[desId].ts; + if ((srcId == snapShot.size() - theDataBeforeLast) and (desId == snapShot.size() - 1)) { + traceDataCache_->GetClockSnapshotData()->AppendNewSnapshot( + desClockId, desTs, + dataCache_->GetConstStatAndInfo().clockid2ClockNameMap_.at(static_cast(desClockId))); + } + AddConvertClockMap(srcClockId, desClockId, srcTs, desTs); + AddConvertClockMap(desClockId, srcClockId, desTs, srcTs); + } + } + hasInitSnapShot_ = true; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/clock_filter.h b/trace_streamer/src/filter/clock_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..69a743afc0a7c7dec537bf624f2fa919f1bf87e9 --- /dev/null +++ b/trace_streamer/src/filter/clock_filter.h @@ -0,0 +1,87 @@ +/* + * 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 CLOCK_FILTER_H +#define CLOCK_FILTER_H + +#include +#include +#include +#include +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +/* + * TS_REALTIME: A settable system-wide clock that measures real time. Its time represents seconds and nanoseconds + * since the Epoch. + * TS_REALTIME_COARSE: A faster but less precise version of TS_REALTIME. This clock is not settable. + * TS_MONOTONIC: The number of seconds that the system has been running since it was booted.The CLOCK_MONOTONIC + * clock is not affected by discontinuous jumps in the system time ,but is affected by the incremental adjustments + * performed by adjtime(3) and NTP. This clock does not count time that the system is suspended. + * TS_MONOTONIC_COARSE: A faster but less precise version of TS_MONOTONIC. + * TS_MONOTONIC_RAW: Similar to TS_MONOTONIC, but provides access to a raw hardware-based time that is not subject + * to NTP adjustments or the incremental adjustments performed by adjtime(3). This clock does not count time that the + * system is suspended. + * TS_BOOTTIME: A nonsettable system-wide clock that is identical to TS_MONOTONIC, except that it also includes + * any time that the system is suspended. + */ + +using ClockId = uint32_t; +struct SnapShot { + ClockId clockId; + uint64_t ts; +}; +class ClockFilter : private FilterBase { +public: + using ConvertClockMap = std::map; + + ClockFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~ClockFilter() override; + + void SetPrimaryClock(ClockId primary) + { + primaryClock_ = primary; + } + ClockId GetPrimaryClock() const + { + return primaryClock_; + } + uint64_t ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const; + uint64_t Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const; + void AddClockSnapshot(const std::vector& snapShot); + bool HasInitSnapShot() const + { + return hasInitSnapShot_; + } + +private: + static std::string GenClockKey(ClockId srcClockId, ClockId desClockId); + void AddConvertClockMap(ClockId srcClockId, ClockId dstClockId, uint64_t srcTs, uint64_t dstTs); + +private: + std::unordered_map clockMaps_ = {}; + + ClockId primaryClock_; + bool hasInitSnapShot_ = false; + TraceDataCache* dataCache_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // CLOCK_FILTER_H diff --git a/trace_streamer/src/filter/cpu_filter.cpp b/trace_streamer/src/filter/cpu_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fce9980181da5b104df3509e6202f27caed38b0a --- /dev/null +++ b/trace_streamer/src/filter/cpu_filter.cpp @@ -0,0 +1,262 @@ +/* + * 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 "cpu_filter.h" +#include "args_filter.h" +#include "process_filter.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +CpuFilter::CpuFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) : FilterBase(dataCache, filter) {} +CpuFilter::~CpuFilter() = default; +void CpuFilter::InsertSwitchEvent(uint64_t ts, + uint64_t cpu, + uint32_t prevPid, + uint64_t prevPior, + uint64_t prevState, + uint32_t nextPid, + uint64_t nextPior, + DataIndex nextInfo) +{ + auto index = traceDataCache_->GetSchedSliceData()->AppendSchedSlice(ts, 0, cpu, nextPid, 0, nextPior); + auto prevTidOnCpu = cpuToRowSched_.find(cpu); + if (prevTidOnCpu != cpuToRowSched_.end()) { + traceDataCache_->GetSchedSliceData()->Update(prevTidOnCpu->second.row, ts, prevState); + cpuToRowSched_.at(cpu).row = index; + } else { + cpuToRowSched_.insert(std::make_pair(cpu, RowPos{nextPid, index})); + } + if (nextPid) { + CheckWakeupEvent(nextPid); + auto lastRow = RowOfInternalTidInStateTable(nextPid); + if (lastRow != INVALID_UINT64) { + // check if there are wakeup or waking events before + lastRow = RowOfInternalTidInStateTable(nextPid); + traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast(lastRow), ts); + } + auto index = + traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, cpu, nextPid, TASK_RUNNING); + if (nextInfo != INVALID_DATAINDEX) { + ArgsSet args; + args.AppendArg(nextInfo_, BASE_DATA_TYPE_STRING, nextInfo); + auto argSetId = streamFilters_->argsFilter_->NewArgs(args); + traceDataCache_->GetThreadStateData()->SetArgSetId(index, argSetId); + } + (void)RemberInternalTidInStateTable(nextPid, index, TASK_RUNNING); + if (cpuToRowThreadState_.find(cpu) == cpuToRowThreadState_.end()) { + cpuToRowThreadState_.insert(std::make_pair(cpu, index)); + } else { + // only one thread on run on a cpu at a certain time + if (traceDataCache_->GetThreadStateData()->ItidsData()[cpuToRowThreadState_.at(cpu)] != prevPid) { + if (!traceDataCache_->GetThreadStateData()->End(static_cast(cpuToRowThreadState_.at(cpu)), + ts)) { + ClearInternalTidInStateTable( + traceDataCache_->GetThreadStateData()->ItidsData()[cpuToRowThreadState_.at(cpu)]); + } + } + cpuToRowThreadState_.at(cpu) = index; + } + } + + if (prevPid) { + auto lastRow = RowOfInternalTidInStateTable(prevPid); + if (lastRow != INVALID_UINT64) { + CheckWakeupEvent(prevPid); + lastRow = RowOfInternalTidInStateTable(prevPid); + traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast(lastRow), ts); + streamFilters_->processFilter_->AddCpuStateCount(prevPid); + auto thread = traceDataCache_->GetThreadData(prevPid); + if (thread && !thread->switchCount_) { + thread->switchCount_ = 1; + } + } + auto threadStateRow = + traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, INVALID_CPU, prevPid, prevState); + if (prevState == TASK_UNINTERRUPTIBLE || prevState == TASK_DK) { + if (!pidToThreadSliceRow.count(prevPid)) { + pidToThreadSliceRow.emplace(std::make_pair(prevPid, threadStateRow)); + } else { + pidToThreadSliceRow.at(prevPid) = threadStateRow; + } + } + (void)RemberInternalTidInStateTable(prevPid, threadStateRow, prevState); + } +} + +bool CpuFilter::InsertBlockedReasonEvent(uint64_t ts, + uint64_t cpu, + uint32_t iTid, + bool iowait, + DataIndex caller, + uint32_t delay) +{ + if (pidToThreadSliceRow.count(iTid)) { + // ArgSet + ArgsSet args; + args.AppendArg(ioWait_, BASE_DATA_TYPE_INT, iowait); + args.AppendArg(caller_, BASE_DATA_TYPE_STRING, caller); + if (delay != INVALID_UINT32) { + args.AppendArg(delay_, BASE_DATA_TYPE_INT, delay); + } + auto argSetId = streamFilters_->argsFilter_->NewArgs(args); + auto row = pidToThreadSliceRow.at(iTid); + traceDataCache_->GetThreadStateData()->SetArgSetId(row, argSetId); + if (iowait) { + auto state = traceDataCache_->GetThreadStateData()->StatesData()[row]; + if (state == TASK_UNINTERRUPTIBLE) { + traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_IO); + } else if (state == TASK_DK) { // state == TASK_DK + traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_IO); + } + } else { + auto state = traceDataCache_->GetThreadStateData()->StatesData()[row]; + if (state == TASK_UNINTERRUPTIBLE) { + traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_UNINTERRUPTIBLE_NIO); + } else if (state == TASK_DK) { // state == TASK_DK + traceDataCache_->GetThreadStateData()->UpdateState(row, TASK_DK_NIO); + } + } + pidToThreadSliceRow.erase(iTid); + } + return true; +} +bool CpuFilter::InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint32_t pid) +{ + UNUSED(cpu); + auto thread = traceDataCache_->GetThreadData(static_cast(pid)); + if (thread) { + thread->endT_ = ts; + return true; + } + return false; +} + +bool CpuFilter::InsertProcessFreeEvent(uint64_t ts, uint32_t pid) +{ + auto thread = traceDataCache_->GetThreadData(static_cast(pid)); + if (thread) { + thread->endT_ = ts; + return true; + } + return false; +} + +void CpuFilter::Finish() const +{ + auto size = traceDataCache_->ThreadSize(); + for (auto i = 0; i < size; i++) { + auto thread = traceDataCache_->GetThreadData(i); + if (thread->internalPid_ != INVALID_UINT32) { + traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++; + traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_; + traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_; + traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_; + continue; + } + auto ipid = traceDataCache_->AppendNewProcessData( + thread->tid_, traceDataCache_->GetDataFromDict(thread->nameIndex_), thread->startT_); + thread->internalPid_ = ipid; + traceDataCache_->GetProcessData(thread->internalPid_)->threadCount_++; + traceDataCache_->GetProcessData(thread->internalPid_)->cpuStatesCount_ += thread->cpuStatesCount_; + traceDataCache_->GetProcessData(thread->internalPid_)->sliceSize_ += thread->sliceSize_; + traceDataCache_->GetProcessData(thread->internalPid_)->switchCount_ += thread->switchCount_; + } + auto threadState = traceDataCache_->GetConstThreadStateData(); + size = threadState.Size(); + auto rowData = threadState.ItidsData(); + for (auto i = 0; i < size; i++) { + auto thread = traceDataCache_->GetThreadData(rowData[i]); + if (thread->internalPid_ == INVALID_UINT32) { + continue; + } + auto process = traceDataCache_->GetProcessData(thread->internalPid_); + traceDataCache_->GetThreadStateData()->UpdateTidAndPid(i, thread->tid_, process->pid_); + } + auto slice = traceDataCache_->GetConstSchedSliceData(); + size = slice.Size(); + for (auto i = 0; i < size; i++) { + traceDataCache_->GetSchedSliceData()->AppendInternalPid( + traceDataCache_->GetThreadData(slice.InternalTidsData()[i])->internalPid_); + } +} +void CpuFilter::Clear() +{ + cpuToRowThreadState_.clear(); + cpuToRowSched_.clear(); + lastWakeUpMsg_.clear(); + internalTidToRowThreadState_.clear(); +} +void CpuFilter::InsertWakeupEvent(uint64_t ts, uint32_t internalTid, bool isWaking) +{ + if (!isWaking && !toRunnableTid_.count(internalTid)) { + toRunnableTid_[internalTid] = ts; + } +} +uint64_t CpuFilter::RemberInternalTidInStateTable(uint32_t uid, uint64_t row, uint64_t state) +{ + if (internalTidToRowThreadState_.find(uid) != internalTidToRowThreadState_.end()) { + internalTidToRowThreadState_.at(uid) = TPthread{row, state}; + } else { + internalTidToRowThreadState_.insert(std::make_pair(uid, TPthread{row, state})); + } + return 0; +} +uint64_t CpuFilter::RowOfInternalTidInStateTable(uint32_t uid) const +{ + auto row = internalTidToRowThreadState_.find(uid); + if (row != internalTidToRowThreadState_.end()) { + return (*row).second.row_; + } + return INVALID_UINT64; +} +void CpuFilter::ClearInternalTidInStateTable(uint32_t uid) +{ + auto row = internalTidToRowThreadState_.find(uid); + if (row != internalTidToRowThreadState_.end()) { + internalTidToRowThreadState_.erase(row); + } +} +uint64_t CpuFilter::StateOfInternalTidInStateTable(uint32_t uid) const +{ + auto row = internalTidToRowThreadState_.find(uid); + if (row != internalTidToRowThreadState_.end()) { + return (*row).second.state_; + } + return TASK_INVALID; +} + +void CpuFilter::CheckWakeupEvent(uint32_t internalTid) +{ + if (toRunnableTid_.count(internalTid)) { + uint64_t lastrow = RowOfInternalTidInStateTable(internalTid); + auto lastState = StateOfInternalTidInStateTable(internalTid); + if (lastState == TASK_RUNNING) { + toRunnableTid_.erase(internalTid); + return; + } + if (lastrow != INVALID_UINT64) { + traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast(lastrow), + toRunnableTid_.at(internalTid)); + } + auto index = traceDataCache_->GetThreadStateData()->AppendThreadState( + toRunnableTid_.at(internalTid), INVALID_TIME, INVALID_CPU, internalTid, TASK_RUNNABLE); + (void)RemberInternalTidInStateTable(internalTid, index, TASK_RUNNABLE); + toRunnableTid_.erase(internalTid); + } + return; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/cpu_filter.h b/trace_streamer/src/filter/cpu_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..0c46d93c609f5829369fc090c59219ab7c35ad3c --- /dev/null +++ b/trace_streamer/src/filter/cpu_filter.h @@ -0,0 +1,89 @@ +/* + * 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 CPU_FILTER_H +#define CPU_FILTER_H + +#include +#include +#include +#include +#include + +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +class TraceStreamerFilters; +class CpuFilter : private FilterBase { +public: + CpuFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + CpuFilter(const CpuFilter&) = delete; + CpuFilter& operator=(const CpuFilter&) = delete; + ~CpuFilter() override; + +public: + void InsertSwitchEvent(uint64_t ts, + uint64_t cpu, + uint32_t prevPid, + uint64_t prevPior, + uint64_t prevState, + uint32_t nextPid, + uint64_t nextPior, + DataIndex nextInfo); + bool InsertBlockedReasonEvent(uint64_t ts, + uint64_t cpu, + uint32_t iTid, + bool iowait, + DataIndex caller, + uint32_t delay); + void InsertWakeupEvent(uint64_t ts, uint32_t internalTid, bool isWaking = false); + bool InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint32_t pid); + bool InsertProcessFreeEvent(uint64_t ts, uint32_t pid); + void Finish() const; + void Clear(); + +private: + void CheckWakeupEvent(uint32_t internalTid); + uint64_t RemberInternalTidInStateTable(uint32_t uid, uint64_t row, uint64_t state = TASK_INVALID); + uint64_t RowOfInternalTidInStateTable(uint32_t uid) const; + void ClearInternalTidInStateTable(uint32_t uid); + uint64_t StateOfInternalTidInStateTable(uint32_t uid) const; + std::map cpuToRowThreadState_ = {}; + typedef struct { + uint32_t iTid; + uint64_t row; + } RowPos; + std::map cpuToRowSched_ = {}; + + std::map lastWakeUpMsg_ = {}; + std::map pidToThreadSliceRow = {}; + struct TPthread { + uint64_t row_; + uint64_t state_; + }; + std::map internalTidToRowThreadState_ = {}; + const DataIndex ioWait_ = traceDataCache_->GetDataIndex("iowait"); + const DataIndex nextInfo_ = traceDataCache_->GetDataIndex("next_info"); + const DataIndex caller_ = traceDataCache_->GetDataIndex("caller"); + const DataIndex delay_ = traceDataCache_->GetDataIndex("delay"); + std::map toRunnableTid_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // CPU_FILTER_H diff --git a/trace_streamer/src/filter/filter_base.cpp b/trace_streamer/src/filter/filter_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3bbcd5b42879f975af15193fce3d312721a2724 --- /dev/null +++ b/trace_streamer/src/filter/filter_base.cpp @@ -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. + */ + +#include "filter_base.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +FilterBase::FilterBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : streamFilters_(filter), traceDataCache_(dataCache) +{ +} +FilterBase::~FilterBase() = default; +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/filter_base.h b/trace_streamer/src/filter/filter_base.h new file mode 100644 index 0000000000000000000000000000000000000000..16e6238ccc86c36a8813764c42e317de64230849 --- /dev/null +++ b/trace_streamer/src/filter/filter_base.h @@ -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. + */ + +#ifndef FILTER_BASE_H +#define FILTER_BASE_H +#include +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) + +namespace SysTuning { +namespace TraceStreamer { +class FilterBase { +public: + FilterBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + FilterBase(const FilterBase&) = delete; + FilterBase& operator=(const FilterBase&) = delete; + virtual ~FilterBase(); + +public: + const TraceStreamerFilters* streamFilters_ = {}; + TraceDataCache* traceDataCache_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // FILTER_BASE_H diff --git a/trace_streamer/src/filter/filter_filter.cpp b/trace_streamer/src/filter/filter_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ed67817f6586a843e6212e2a06da8cd43dd1c73 --- /dev/null +++ b/trace_streamer/src/filter/filter_filter.cpp @@ -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. + */ + +#include "filter_filter.h" + +#include "process_filter.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +FilterFilter::FilterFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter) +{ +} + +FilterFilter::~FilterFilter() = default; + +uint32_t FilterFilter::AddFilter(std::string type, std::string name, uint64_t arg) +{ + auto filter = traceDataCache_->GetFilterData(); + size_t id = filter->AppendNewFilterData(type, name, arg); + return static_cast(id); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/filter_filter.h b/trace_streamer/src/filter/filter_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..cef929bb0a378faa79f4a97cc828ee68e7d56299 --- /dev/null +++ b/trace_streamer/src/filter/filter_filter.h @@ -0,0 +1,36 @@ +/* + * 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 FILTER_FILTER_H +#define FILTER_FILTER_H + +#include "filter_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class TraceStreamerFilters; +class FilterFilter : private FilterBase { +public: + FilterFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + FilterFilter(const FilterFilter&) = delete; + FilterFilter& operator=(const FilterFilter&) = delete; + ~FilterFilter() override; + + uint32_t AddFilter(std::string type, std::string name, uint64_t arg); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // FILTER_FILTER_H diff --git a/trace_streamer/src/filter/frame_filter.cpp b/trace_streamer/src/filter/frame_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..237f147b8be587ec4c48af545cf271d8bc046c62 --- /dev/null +++ b/trace_streamer/src/filter/frame_filter.cpp @@ -0,0 +1,265 @@ +/* + * 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 "frame_filter.h" +#include +#include "log.h" +#define ISINVALIDU32(value) (value == INVALID_UINT32) +namespace SysTuning { +namespace TraceStreamer { +FrameFilter::FrameFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) : FilterBase(dataCache, filter) +{ +} +FrameFilter::~FrameFilter() = default; + +void FrameFilter::BeginVsyncEvent(uint64_t ts, + uint32_t ipid, + uint32_t itid, + uint64_t expectStart, + uint64_t expectEnd, + uint32_t vsyncId, + uint32_t callStackSliceId) +{ + auto frame = std::make_shared(); + frame->startTs_ = ts; + frame->callStackSliceId_ = callStackSliceId; + frame->expectedStartTs_ = expectStart; + frame->expectedEndTs_ = expectEnd; + frame->expectedDur_ = expectEnd - expectStart; + frame->vsyncId_ = vsyncId; + frame->frameSliceRow_ = + traceDataCache_->GetFrameSliceData()->AppendFrame(ts, ipid, itid, vsyncId, callStackSliceId); + frame->frameExpectedSliceRow_ = traceDataCache_->GetFrameSliceData()->AppendFrame( + expectStart, ipid, itid, vsyncId, callStackSliceId, expectEnd, (uint8_t)EXPECT_SLICE); + if (vsyncRenderSlice_.count(itid)) { + vsyncRenderSlice_[itid].push_back(frame); + } else { + std::vector> frameVec; + frameVec.push_back(frame); + vsyncRenderSlice_[itid] = frameVec; + } +} + +bool FrameFilter::MarkRSOnvsyncEvent(uint64_t ts, uint32_t itid) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("BeginOnvsyncEvent find for itid:%u failed, ts:%llu", itid, ts); + return false; + } + if (!frame->second.size()) { + TS_LOGW("BeginOnvsyncEvent find for itid:%u failed", itid); + return false; + } + auto pos = frame->second.begin(); + if (frame->second.size() > 1) { + pos++; + } + pos->get()->isRsMainThread_ = true; + return true; +} +bool FrameFilter::EndOnVsyncEvent(uint64_t ts, uint32_t itid) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("BeginOnvsyncEvent find for itid:%u failed", itid); + return false; + } + if (!frame->second.size()) { + TS_LOGW("BeginOnvsyncEvent find for itid:%u failed", itid); + return false; + } + auto pos = frame->second.begin(); + if (frame->second.size() > 1) { + pos++; + } + if (!pos->get()->isRsMainThread_ && ISINVALIDU32(pos->get()->frameNum_)) { + // if app's frame num not received + traceDataCache_->GetFrameSliceData()->Erase(pos->get()->frameSliceRow_); + traceDataCache_->GetFrameSliceData()->Erase(pos->get()->frameExpectedSliceRow_); + frame->second.erase(pos); + return false; + } + return true; +} +// for app +bool FrameFilter::BeginRSTransactionData(uint64_t ts, uint32_t itid, uint32_t franeNum) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("BeginRSTransactionData find for itid:%u failed", itid); + return false; + } + if (!frame->second.size()) { + TS_LOGW("BeginRSTransactionData find for itid:%u failed", itid); + return false; + } + frame->second.begin()->get()->frameNum_ = franeNum; + if (!dstRenderSlice_.count(itid)) { + std::unordered_map> frameMap; + dstRenderSlice_.emplace(std::make_pair(itid, std::move(frameMap))); + } + // dstRenderSlice_.at(itid).insert(std::make_pair(franeNum, frame->second.begin())); + dstRenderSlice_[itid][franeNum] = frame->second[0]; + return true; +} +// for RS +bool FrameFilter::BeginProcessCommandUni(uint64_t ts, + uint32_t itid, + const std::vector& frames, + uint32_t sliceIndex) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("BeginProcessCommandUni find for itid:%u failed", itid); + return false; + } + if (!frame->second.size()) { + TS_LOGW("BeginProcessCommandUni find for itid:%u failed", itid); + return false; + } + auto pos = frame->second.begin(); + if (frame->second.size() > 1) { + if (frame->second.begin()->get()->vsyncEnd_) { + pos++; + } + } + std::vector fromSlices = {}; + std::vector fromExpectedSlices = {}; + for (auto& it : frames) { + auto sourceFrameMap = dstRenderSlice_.find(it.sourceItid); + if (sourceFrameMap == dstRenderSlice_.end()) { + // error + TS_LOGE("BeginProcessCommandUni find for itid:%u framenum:%u failed", it.sourceItid, it.frameNum); + continue; + } + auto srcFrame = sourceFrameMap->second.find(it.frameNum); + if (srcFrame == sourceFrameMap->second.end()) { + // error + TS_LOGE("BeginProcessCommandUni find for itid:%u framenum:%u failed", it.sourceItid, it.frameNum); + continue; + } + fromSlices.push_back(srcFrame->second.get()->frameSliceRow_); + fromExpectedSlices.push_back(srcFrame->second.get()->frameExpectedSliceRow_); + srcFrame->second.get()->dstFrameSliceId_ = pos->get()->frameSliceRow_; + srcFrame->second.get()->dstExpectedFrameSliceId_ = pos->get()->frameExpectedSliceRow_; + (void)traceDataCache_->GetFrameMapsData()->AppendNew(srcFrame->second.get()->frameSliceRow_, + srcFrame->second.get()->dstFrameSliceId_); + (void)traceDataCache_->GetFrameMapsData()->AppendNew(srcFrame->second.get()->frameExpectedSliceRow_, + srcFrame->second.get()->dstExpectedFrameSliceId_); + traceDataCache_->GetFrameSliceData()->SetDst(srcFrame->second.get()->frameSliceRow_, + srcFrame->second.get()->dstFrameSliceId_); + traceDataCache_->GetFrameSliceData()->SetDst(srcFrame->second.get()->frameExpectedSliceRow_, + srcFrame->second.get()->dstExpectedFrameSliceId_); + if (srcFrame->second.get()->endTs_ != INVALID_UINT64) { + // erase Source + sourceFrameMap->second.erase(it.frameNum); + } + } + if (!fromSlices.size()) { + return false; + } + pos->get()->sourceSlice_ = fromSlices; + pos->get()->sourceExpectedSlice_ = fromExpectedSlices; + traceDataCache_->GetFrameSliceData()->SetSrcs(pos->get()->frameSliceRow_, fromSlices); + traceDataCache_->GetFrameSliceData()->SetSrcs(pos->get()->frameExpectedSliceRow_, fromExpectedSlices); + return true; +} +bool FrameFilter::EndVsyncEvent(uint64_t ts, uint32_t itid) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("EndVsyncEvent find for itid:%u ts:%llu failed", itid, ts); + return false; + } + if (!frame->second.size()) { + TS_LOGW("EndVsyncEvent find for itid:%u ts:%llu failed", itid, ts); + return false; + } + auto pos = frame->second.begin(); + if (frame->second.size() > 1) { + pos++; + } + pos->get()->vsyncEnd_ = true; + if (pos->get()->isRsMainThread_) { + if (pos->get()->gpuEnd_) { + traceDataCache_->GetFrameSliceData()->SetEndTimeAndFlag( + pos->get()->frameSliceRow_, ts, pos->get()->expectedDur_, pos->get()->expectedEndTs_); + pos->get()->endTs_ = ts; + // for Render serivce + frame->second.erase(pos); + } + } else { // for app + traceDataCache_->GetFrameSliceData()->SetEndTimeAndFlag(pos->get()->frameSliceRow_, ts, + pos->get()->expectedDur_, pos->get()->expectedEndTs_); + if (ISINVALIDU32(pos->get()->frameNum_)) { + // if app's frame num not received + traceDataCache_->GetFrameSliceData()->Erase(pos->get()->frameSliceRow_); + traceDataCache_->GetFrameSliceData()->Erase(pos->get()->frameExpectedSliceRow_); + frame->second.erase(pos); + return false; + } + pos->get()->endTs_ = ts; + frame->second.erase(pos); + } + return true; +} +// only for renderservice +bool FrameFilter::StartFrameQueue(uint64_t ts, uint32_t itid) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("StartFrameQueue find for itid:%u failed", itid); + return false; + } + if (!frame->second.size()) { + TS_LOGW("StartFrameQueue find for itid:%u failed", itid); + return false; + } + auto pos = frame->second.begin(); + pos->get()->gpuEnd_ = false; + pos->get()->frameQueueStartTs_ = ts; + return true; +} +bool FrameFilter::EndFrameQueue(uint64_t ts, uint32_t itid) +{ + auto frame = vsyncRenderSlice_.find(itid); + if (frame == vsyncRenderSlice_.end()) { + TS_LOGW("EndFrameQueue find for itid:%u ts:%llu failed", itid, ts); + return false; + } + if (!frame->second.size()) { + TS_LOGW("EndFrameQueue find for itid:%u ts:%llu failed", itid, ts); + return false; + } + auto pos = frame->second.begin(); + (void)traceDataCache_->GetGPUSliceData()->AppendNew(pos->get()->frameSliceRow_, + ts - pos->get()->frameQueueStartTs_); + pos->get()->gpuEnd_ = true; + if (pos->get()->vsyncEnd_) { + pos->get()->endTs_ = ts; + traceDataCache_->GetFrameSliceData()->SetEndTimeAndFlag(pos->get()->frameSliceRow_, ts, + pos->get()->expectedDur_, pos->get()->expectedEndTs_); + // if vsync ended + frame->second.erase(pos); + } + return true; +} +void FrameFilter::Finish() +{ + vsyncRenderSlice_.clear(); + dstRenderSlice_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/frame_filter.h b/trace_streamer/src/filter/frame_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..fac3d0f9dca6052b0bc66d73ef5ff2a210f6fdcd --- /dev/null +++ b/trace_streamer/src/filter/frame_filter.h @@ -0,0 +1,85 @@ +/* + * 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 FRAME_FILTER_H +#define FRAME_FILTER_H +#include +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class FrameFilter : private FilterBase { +public: + FrameFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~FrameFilter() override; + void BeginVsyncEvent(uint64_t ts, + uint32_t ipid, + uint32_t itid, + uint64_t expectStart, + uint64_t expectEnd, + uint32_t vsyncId, + uint32_t callStackSliceId); + bool MarkRSOnvsyncEvent(uint64_t ts, uint32_t itid); + bool EndOnVsyncEvent(uint64_t ts, uint32_t itid); + bool BeginRSTransactionData(uint64_t ts, uint32_t itid, uint32_t franeNum); + typedef struct { + uint32_t sourceItid; + uint32_t frameNum; + } FrameMap; + bool BeginProcessCommandUni(uint64_t ts, uint32_t itid, const std::vector& frame, uint32_t sliceIndex); + bool EndVsyncEvent(uint64_t ts, uint32_t itid); + bool StartFrameQueue(uint64_t ts, uint32_t itid); + bool EndFrameQueue(uint64_t ts, uint32_t itid); + void Finish(); + +private: + typedef enum FrameSliceType { ACTURAL_SLICE, EXPECT_SLICE } FrameSliceType; + class FrameSlice { + public: + FrameSlice() {} + uint64_t startTs_ = INVALID_UINT64; + // @deprecated it will be deleted later + uint64_t expectedStartTs_ = INVALID_UINT64; + // if a frame experience video lag, is depend on if the real end ts is later then the expected ts, rather then + // the dur. noted at 2023/4/6 + uint64_t expectedEndTs_ = INVALID_UINT64; + // @deprecated it will be deleted later + uint64_t expectedDur_ = INVALID_UINT64; + uint64_t endTs_ = INVALID_UINT64; + bool gpuEnd_ = true; + FrameSliceType frameType_ = ACTURAL_SLICE; + uint32_t vsyncId_ = INVALID_UINT32; + uint64_t frameQueueStartTs_ = INVALID_UINT64; + bool vsyncEnd_ = false; + bool isRsMainThread_ = false; + uint32_t frameNum_ = INVALID_UINT32; + uint64_t callStackSliceId_ = INVALID_UINT64; + uint64_t frameSliceRow_ = INVALID_UINT64; + uint64_t frameExpectedSliceRow_ = INVALID_UINT64; + std::vector sourceSlice_ = {}; + std::vector sourceExpectedSlice_ = {}; + uint64_t dstFrameSliceId_ = INVALID_UINT64; + uint64_t dstExpectedFrameSliceId_ = INVALID_UINT64; + }; + std::unordered_map>> vsyncRenderSlice_ = {}; + std::unordered_map>> + dstRenderSlice_ = {}; + bool checkFrameAlwasy_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/filter/hi_sysevent_measure_filter.cpp b/trace_streamer/src/filter/hi_sysevent_measure_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dca6d0e797b196ad127528397fc83fbfe9fa7103 --- /dev/null +++ b/trace_streamer/src/filter/hi_sysevent_measure_filter.cpp @@ -0,0 +1,146 @@ +/* + * 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 "hi_sysevent_measure_filter.h" +#include "filter_filter.h" +#include "log.h" +#include "system_event_measure_filter.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +HiSysEventMeasureFilter::HiSysEventMeasureFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter), appKey_(INVALID_UINT64), appName_(INVALID_UINT64) +{ +} + +HiSysEventMeasureFilter::~HiSysEventMeasureFilter() {} + +DataIndex HiSysEventMeasureFilter::AppendNewValue(uint64_t serial, + uint64_t timeStamp, + DataIndex appNameId, + DataIndex key, + int32_t type, + double numericValue, + DataIndex strValue) +{ + uint64_t appKeyId = GetOrCreateFilterIdInternal(appNameId, key); + traceDataCache_->GetSyseventMeasureData()->AppendData(serial, timeStamp, appNameId, appKeyId, type, numericValue, + strValue); + return appNameId; +} +void HiSysEventMeasureFilter::AppendNewValue(std::string msg, std::string processName) +{ + traceDataCache_->GetTraceConfigData()->AppendNewData("hisys_event", msg, processName); + return; +} +void HiSysEventMeasureFilter::AppendNewValue(int32_t brightnessState, + int32_t btState, + int32_t locationState, + int32_t wifiState, + int32_t streamDefault, + int32_t voiceCall, + int32_t music, + int32_t streamRing, + int32_t media, + int32_t voiceAssistant, + int32_t system, + int32_t alarm, + int32_t notification, + int32_t bluetoolthSco, + int32_t enforcedAudible, + int32_t streamDtmf, + int32_t streamTts, + int32_t accessibility, + int32_t recording, + int32_t streamAll) +{ + traceDataCache_->GetDeviceStateData()->AppendNewData( + brightnessState, btState, locationState, wifiState, streamDefault, voiceCall, music, streamRing, media, + voiceAssistant, system, alarm, notification, bluetoolthSco, enforcedAudible, streamDtmf, streamTts, + accessibility, recording, streamAll); + return; +} +DataIndex HiSysEventMeasureFilter::GetOrCreateFilterIdInternal(DataIndex appNameId, DataIndex key) +{ + uint64_t appKeyId = appKey_.Find(appNameId, key); + if (appKeyId == INVALID_DATAINDEX) { + appKeyId = traceDataCache_->GetAppNamesData()->AppendAppName(1, appNameId, key); + appKey_.Insert(appNameId, key, appKeyId); + } + return appKeyId; +} + +DataIndex HiSysEventMeasureFilter::GetOrCreateFilterId(DataIndex eventSource) +{ + DataIndex eventSourceFilterId = INVALID_DATAINDEX; + if (eventSource_.find(eventSource) == eventSource_.end()) { + eventSourceFilterId = streamFilters_->sysEventSourceFilter_->AppendNewMeasureFilter(eventSource); + eventSource_.insert(std::make_pair(eventSource, eventSourceFilterId)); + } else { + eventSourceFilterId = eventSource_.at(eventSource); + } + return eventSourceFilterId; +} +DataIndex HiSysEventMeasureFilter::GetOrCreateFilterId(DataIndex eventSource, DataIndex appName) +{ + DataIndex eventSourceFilterId = INVALID_DATAINDEX; + DataIndex appNameId = INVALID_DATAINDEX; + if (eventSource_.find(eventSource) == eventSource_.end()) { + eventSourceFilterId = streamFilters_->sysEventSourceFilter_->AppendNewMeasureFilter(eventSource); + eventSource_.insert(std::make_pair(eventSource, eventSourceFilterId)); + } else { + eventSourceFilterId = eventSource_.at(eventSource); + } + appNameId = appName_.Find(eventSourceFilterId, appName); + if (appNameId == INVALID_DATAINDEX) { + appNameId = traceDataCache_->GetAppNamesData()->AppendAppName(0, eventSourceFilterId, appName); + appName_.Insert(eventSourceFilterId, appName, appNameId); + } + return appNameId; +} +std::tuple HiSysEventMeasureFilter::GetOrCreateFilterId(DataIndex eventSource, + DataIndex appName, + DataIndex key) +{ + DataIndex eventSourceFilterId = INVALID_DATAINDEX; + DataIndex appNameId = INVALID_DATAINDEX; + if (eventSource_.find(eventSource) == eventSource_.end()) { + eventSourceFilterId = streamFilters_->sysEventSourceFilter_->AppendNewMeasureFilter(eventSource); + eventSource_.insert(std::make_pair(eventSource, eventSourceFilterId)); + } else { + eventSourceFilterId = eventSource_.at(eventSource); + } + appNameId = appName_.Find(eventSourceFilterId, appName); + if (appNameId == INVALID_DATAINDEX) { + appNameId = traceDataCache_->GetAppNamesData()->AppendAppName(0, eventSourceFilterId, appName); + appName_.Insert(eventSourceFilterId, appName, appNameId); + } + uint64_t appKeyId = appKey_.Find(appNameId, key); + if (appKeyId == INVALID_DATAINDEX) { + appKeyId = traceDataCache_->GetAppNamesData()->AppendAppName(1, appNameId, key); + appKey_.Insert(appNameId, key, appKeyId); + } + return std::make_tuple(appNameId, appKeyId); +} + +void HiSysEventMeasureFilter::Clear() +{ + appKey_.Clear(); + appName_.Clear(); + eventSource_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/hi_sysevent_measure_filter.h b/trace_streamer/src/filter/hi_sysevent_measure_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..4f75ba9a67a9b3fff3ab63b90855154ec902cdfa --- /dev/null +++ b/trace_streamer/src/filter/hi_sysevent_measure_filter.h @@ -0,0 +1,78 @@ +/* + * 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 HI_SYS_EVENT_MEASURE_FILTER_H +#define HI_SYS_EVENT_MEASURE_FILTER_H + +#include +#include +#include + +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "triple_map.h" + +namespace SysTuning { +namespace TraceStreamer { +class HiSysEventMeasureFilter : private FilterBase { +public: + HiSysEventMeasureFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + HiSysEventMeasureFilter(const HiSysEventMeasureFilter&) = delete; + HiSysEventMeasureFilter& operator=(const HiSysEventMeasureFilter&) = delete; + ~HiSysEventMeasureFilter() override; + DataIndex GetOrCreateFilterId(DataIndex eventSource); + DataIndex GetOrCreateFilterId(DataIndex eventSource, DataIndex appName); + std::tuple GetOrCreateFilterId(DataIndex eventSource, DataIndex appName, DataIndex key); + DataIndex AppendNewValue(uint64_t serial, + uint64_t timeStamp, + DataIndex appNameId, + DataIndex key, + int32_t type, + double numericValue, + DataIndex strValue); + void AppendNewValue(std::string msg, std::string processName); + void AppendNewValue(int32_t brightnessState, + int32_t btState, + int32_t locationState, + int32_t wifiState, + int32_t streamDefault, + int32_t voiceCall, + int32_t music, + int32_t streamRing, + int32_t media, + int32_t voiceAssistant, + int32_t system, + int32_t alarm, + int32_t notification, + int32_t bluetoolthSco, + int32_t enforcedAudible, + int32_t streamDtmf, + int32_t streamTts, + int32_t accessibility, + int32_t recording, + int32_t streamAll); + void Clear(); + +private: + DataIndex GetOrCreateFilterIdInternal(DataIndex appNameId, DataIndex key); + DoubleMap appKey_; + DoubleMap appName_; + std::map eventSource_; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HI_SYS_EVENT_MEASURE_FILTER_H diff --git a/trace_streamer/src/filter/irq_filter.cpp b/trace_streamer/src/filter/irq_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c2e95043aa76d2d6a1e0784f2df9897e17ed901 --- /dev/null +++ b/trace_streamer/src/filter/irq_filter.cpp @@ -0,0 +1,84 @@ +/* + * 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 "irq_filter.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +IrqFilter::IrqFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) : FilterBase(dataCache, filter) +{ + for (size_t i = 0; i < irqActionNames_.size(); i++) { + irqActionNameIds_.push_back(traceDataCache_->GetDataIndex(irqActionNames_[i])); + } +} +IrqFilter::~IrqFilter() = default; + +void IrqFilter::IrqHandlerEntry(int64_t ts, uint32_t cpu, DataIndex nameId) +{ + streamFilters_->sliceFilter_->IrqHandlerEntry(ts, cpu, irqCatalog_, nameId); +} +void IrqFilter::IrqHandlerExit(int64_t ts, uint32_t cpu, uint32_t irq, uint32_t ret) +{ + DataIndex irqRet = INVALID_DATAINDEX; + if (ret == 1) { + irqRet = irqHandled_; + } else { + irqRet = irqUnHandled_; + } + ArgsSet args; + args.AppendArg(irqRet_, BASE_DATA_TYPE_STRING, irqRet); + args.AppendArg(irq_, BASE_DATA_TYPE_INT, irq); + streamFilters_->sliceFilter_->IrqHandlerExit(ts, cpu, args); +} + +void IrqFilter::IpiHandlerEntry(int64_t ts, uint32_t cpu, DataIndex nameId) +{ + streamFilters_->sliceFilter_->IpiHandlerEntry(ts, cpu, ipiCatalog_, nameId); +} +void IrqFilter::IpiHandlerExit(int64_t ts, uint32_t cpu) +{ + streamFilters_->sliceFilter_->IpiHandlerExit(ts, cpu); +} +void IrqFilter::SoftIrqEntry(int64_t ts, uint32_t cpu, uint32_t vec) +{ + if (vec >= irqActionNames_.size()) { + return; + } + streamFilters_->sliceFilter_->SoftIrqEntry(ts, cpu, softIrqCatalog_, irqActionNameIds_[vec]); +} +void IrqFilter::SoftIrqExit(int64_t ts, uint32_t cpu, uint32_t vec) +{ + if (vec >= irqActionNames_.size()) { + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_NOTMATCH); + return; + } + ArgsSet args; + args.AppendArg(irqRet_, BASE_DATA_TYPE_STRING, irqActionNameIds_[vec]); + args.AppendArg(irqVec_, BASE_DATA_TYPE_INT, vec); + streamFilters_->sliceFilter_->SoftIrqExit(ts, cpu, args); + return; +} +void IrqFilter::Clear() +{ + lastEventTs_.clear(); + transReplyWaitingReply_.clear(); + transWaitingRcv_.clear(); + transNoNeedReply_.clear(); + binderFlagDescs_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/irq_filter.h b/trace_streamer/src/filter/irq_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..8d26c7ce4cf6da88428b27df5b2188a52c981721 --- /dev/null +++ b/trace_streamer/src/filter/irq_filter.h @@ -0,0 +1,64 @@ +/* + * 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 IRQ_FILTER_H +#define IRQ_FILTER_H + +#include +#include "args_set.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class IrqFilter : private FilterBase { +public: + IrqFilter(TraceDataCache*, const TraceStreamerFilters*); + IrqFilter(const IrqFilter&) = delete; + IrqFilter& operator=(const IrqFilter&) = delete; + ~IrqFilter() override; + +public: + void IrqHandlerEntry(int64_t ts, uint32_t cpu, DataIndex nameId); + void IrqHandlerExit(int64_t ts, uint32_t cpu, uint32_t irq, uint32_t ret); + void IpiHandlerEntry(int64_t ts, uint32_t cpu, DataIndex nameId); + void IpiHandlerExit(int64_t ts, uint32_t cpu); + void SoftIrqEntry(int64_t ts, uint32_t cpu, uint32_t vec); + void SoftIrqExit(int64_t ts, uint32_t cpu, uint32_t vec); + void Clear(); + +private: + const DataIndex irqId_ = traceDataCache_->GetDataIndex("irq_id"); + const DataIndex irqRet_ = traceDataCache_->GetDataIndex("irq_ret"); + const DataIndex irq_ = traceDataCache_->GetDataIndex("irq"); + const DataIndex irqVec_ = traceDataCache_->GetDataIndex("vec"); + const DataIndex irqHandled_ = traceDataCache_->GetDataIndex("handled"); + const DataIndex irqUnHandled_ = traceDataCache_->GetDataIndex("unhandled"); + const DataIndex irqCatalog_ = traceDataCache_->GetDataIndex("irq"); + const DataIndex ipiCatalog_ = traceDataCache_->GetDataIndex("ipi"); + const DataIndex softIrqCatalog_ = traceDataCache_->GetDataIndex("softirq"); + std::unordered_map lastEventTs_ = {}; + std::unordered_set transReplyWaitingReply_ = {}; + std::unordered_map transWaitingRcv_ = {}; + std::unordered_map transNoNeedReply_ = {}; + std::unordered_map binderFlagDescs_ = {}; + std::vector irqActionNames_ = {"HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", + "BLOCK_IOPOLL", "TASKLET", "SCHED", "HRTIMER", "RCU"}; + std::vector irqActionNameIds_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // IRQ_FILTER_H diff --git a/trace_streamer/src/filter/measure_filter.cpp b/trace_streamer/src/filter/measure_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd382112b81dfe965186be9844e31192b876c7c1 --- /dev/null +++ b/trace_streamer/src/filter/measure_filter.cpp @@ -0,0 +1,103 @@ +/* + * 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 "measure_filter.h" +#include "filter_filter.h" +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +MeasureFilter::MeasureFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter, FilterType e) + : FilterBase(dataCache, filter), tidStreamIdFilterIdMap_(INVALID_UINT64), filterType_(e) +{ +} + +MeasureFilter::~MeasureFilter() {} + +bool MeasureFilter::AppendNewMeasureData(uint64_t internalTid, DataIndex nameIndex, uint64_t timeStamp, int64_t value) +{ + auto filterId = GetOrCreateFilterId(internalTid, nameIndex); + if (filterType_ == E_PROCESS_MEASURE_FILTER) { + traceDataCache_->GetProcessMeasureData()->AppendMeasureData(0, timeStamp, value, filterId); + } else { + auto row = traceDataCache_->GetMeasureData()->AppendMeasureData(0, timeStamp, value, filterId); + // if the filterId ever exists + if (filterIdToRow_.count(filterId)) { + traceDataCache_->GetMeasureData()->SetDur(filterIdToRow_.at(filterId), timeStamp); + filterIdToRow_.at(filterId) = row; + } else { + filterIdToRow_.insert(std::make_pair(filterId, row)); + } + } + return value != 0; +} +uint32_t MeasureFilter::GetOrCreateFilterId(uint64_t internalTid, DataIndex nameIndex) +{ + auto filterId = tidStreamIdFilterIdMap_.Find(internalTid, nameIndex); + if (filterId != INVALID_UINT64) { + return static_cast(filterId); + } + + uint32_t newFilterId = streamFilters_->filterFilter_->AddFilter( + filterTypeValue.at(filterType_), traceDataCache_->GetDataFromDict(nameIndex), internalTid); + AddCertainFilterId(internalTid, nameIndex, newFilterId); + return newFilterId; +} + +void MeasureFilter::AddCertainFilterId(uint64_t internalTid, DataIndex nameIndex, uint64_t filterId) +{ + tidStreamIdFilterIdMap_.Insert(internalTid, nameIndex, filterId); + + if (filterType_ == E_THREADMEASURE_FILTER) { + traceDataCache_->GetThreadMeasureFilterData()->AppendNewFilter(filterId, static_cast(nameIndex), + internalTid); + } else if (filterType_ == E_THREAD_FILTER) { + traceDataCache_->GetThreadFilterData()->AppendNewFilter(filterId, static_cast(nameIndex), + internalTid); + } else if (filterType_ == E_PROCESS_MEASURE_FILTER) { + traceDataCache_->GetProcessMeasureFilterData()->AppendNewFilter( + static_cast(filterId), static_cast(nameIndex), static_cast(internalTid)); + } else if (filterType_ == E_PROCESS_FILTER_FILTER) { + traceDataCache_->GetProcessFilterData()->AppendNewFilter( + static_cast(filterId), static_cast(nameIndex), static_cast(internalTid)); + } else if (filterType_ == E_CPU_MEASURE_FILTER) { + traceDataCache_->GetCpuMeasuresData()->AppendNewFilter(filterId, static_cast(nameIndex), internalTid); + } else if (filterType_ == E_CLOCK_RATE_FILTER) { + traceDataCache_->GetClockEventFilterData()->AppendNewFilter(filterId, clockSetRateDataIndex_, + static_cast(nameIndex), internalTid); + } else if (filterType_ == E_CLOCK_ENABLE_FILTER) { + traceDataCache_->GetClockEventFilterData()->AppendNewFilter(filterId, clockEnableDataIndex_, + static_cast(nameIndex), internalTid); + } else if (filterType_ == E_CLOCK_DISABLE_FILTER) { + traceDataCache_->GetClockEventFilterData()->AppendNewFilter(filterId, clockDisableDataIndex_, + static_cast(nameIndex), internalTid); + } else if (filterType_ == E_CLK_RATE_FILTER) { + traceDataCache_->GetClkEventFilterData()->AppendNewFilter(filterId, clkSetRateDataIndex_, + static_cast(nameIndex), internalTid); + } else if (filterType_ == E_CLK_ENABLE_FILTER) { + traceDataCache_->GetClkEventFilterData()->AppendNewFilter(filterId, clkEnableDataIndex_, + static_cast(nameIndex), internalTid); + } else if (filterType_ == E_CLK_DISABLE_FILTER) { + traceDataCache_->GetClkEventFilterData()->AppendNewFilter(filterId, clkDisableDataIndex_, + static_cast(nameIndex), internalTid); + } +} +void MeasureFilter::Clear() +{ + tidStreamIdFilterIdMap_.Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/measure_filter.h b/trace_streamer/src/filter/measure_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..c8df03d61f284b19ddc7ef9471cccedfddae519f --- /dev/null +++ b/trace_streamer/src/filter/measure_filter.h @@ -0,0 +1,80 @@ +/* + * 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 THREAD_MEASURE_FILTER_H +#define THREAD_MEASURE_FILTER_H + +#include +#include +#include + +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +enum FilterType { + E_THREADMEASURE_FILTER, + E_THREAD_FILTER, + E_PROCESS_MEASURE_FILTER, + E_PROCESS_FILTER_FILTER, + E_CPU_MEASURE_FILTER, + E_CLOCK_RATE_FILTER, + E_CLOCK_ENABLE_FILTER, + E_CLOCK_DISABLE_FILTER, + E_CLK_RATE_FILTER, + E_CLK_ENABLE_FILTER, + E_CLK_DISABLE_FILTER +}; + +class MeasureFilter : private FilterBase { +public: + MeasureFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter, FilterType); + MeasureFilter(const MeasureFilter&) = delete; + MeasureFilter& operator=(const MeasureFilter&) = delete; + ~MeasureFilter() override; + bool AppendNewMeasureData(uint64_t internalTid, DataIndex nameIndex, uint64_t timeStamp, int64_t value); + uint32_t GetOrCreateFilterId(uint64_t internalTid, DataIndex nameIndex); + void Clear(); + +private: + void AddCertainFilterId(uint64_t internalTid, DataIndex nameIndex, uint64_t filterId); + DoubleMap tidStreamIdFilterIdMap_; + FilterType filterType_; + + const std::map filterTypeValue = {{E_THREADMEASURE_FILTER, "thread_measure_filter"}, + {E_THREAD_FILTER, "thread_measure"}, + {E_PROCESS_MEASURE_FILTER, "process_measure_filter"}, + {E_PROCESS_FILTER_FILTER, "process_filter"}, + {E_CPU_MEASURE_FILTER, "cpu_measure_filter"}, + {E_CLOCK_RATE_FILTER, "clock_rate_filter"}, + {E_CLOCK_ENABLE_FILTER, "clock_enable_filter"}, + {E_CLOCK_DISABLE_FILTER, "clock_disable_filter"}, + {E_CLK_RATE_FILTER, "clk_rate_filter"}, + {E_CLK_ENABLE_FILTER, "clk_enable_filter"}, + {E_CLK_DISABLE_FILTER, "clk_disable_filter"}}; + const DataIndex clockSetRateDataIndex_ = traceDataCache_->GetDataIndex("clock_set_rate"); + const DataIndex clockEnableDataIndex_ = traceDataCache_->GetDataIndex("clock_enable"); + const DataIndex clockDisableDataIndex_ = traceDataCache_->GetDataIndex("clock_disable"); + const DataIndex clkSetRateDataIndex_ = traceDataCache_->GetDataIndex("clk_set_rate"); + const DataIndex clkEnableDataIndex_ = traceDataCache_->GetDataIndex("clk_enable"); + const DataIndex clkDisableDataIndex_ = traceDataCache_->GetDataIndex("clk_disable"); + std::map filterIdToRow_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // THREAD_MEASURE_FILTER_H diff --git a/trace_streamer/src/filter/native_hook_filter.cpp b/trace_streamer/src/filter/native_hook_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68e0ff6f716bd836adeaea1d32a255007388e7b7 --- /dev/null +++ b/trace_streamer/src/filter/native_hook_filter.cpp @@ -0,0 +1,941 @@ +/* + * 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 "native_hook_filter.h" +namespace SysTuning { +namespace TraceStreamer { +NativeHookFilter::NativeHookFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : OfflineSymbolizationFilter(dataCache, filter) +{ + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/libc++.so")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib64/libc++.so")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-aarch64.so.1")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-arm.so.1")); +} + +void NativeHookFilter::ParseConfigInfo(ProtoReader::BytesView& protoData) +{ + auto configReader = ProtoReader::NativeHookConfig_Reader(protoData); + if (configReader.has_statistics_interval()) { + isStatisticMode_ = true; + isCallStackCompressedMode_ = true; + isStringCompressedMode_ = true; + } + if (configReader.has_offline_symbolization()) { + isOfflineSymbolizationMode_ = true; + isCallStackCompressedMode_ = true; + isStringCompressedMode_ = true; + return; + } + if (configReader.has_callframe_compressed()) { + isCallStackCompressedMode_ = true; + isStringCompressedMode_ = true; + return; + } + if (configReader.has_string_compressed()) { + isStringCompressedMode_ = true; + return; + } + return; +} +void NativeHookFilter::AppendStackMaps(uint32_t stackid, std::vector& frames) +{ + auto framesSharedPtr = std::make_shared>(frames); + stackIdToFramesMap_.emplace(std::make_pair(stackid, framesSharedPtr)); + // allStackIdToFramesMap_ save all offline symbolic call stack + if (isOfflineSymbolizationMode_) { + allStackIdToFramesMap_.emplace(std::make_pair(stackid, framesSharedPtr)); + } +} +void NativeHookFilter::AppendFrameMaps(uint32_t id, const ProtoReader::BytesView& bytesView) +{ + auto frames = std::make_shared(bytesView); + frameIdToFrameBytes_.emplace(std::make_pair(id, frames)); +} +void NativeHookFilter::AppendFilePathMaps(uint32_t id, uint64_t fileIndex) +{ + filePathIdToFileIndex_.emplace(id, fileIndex); + fileIndexToFilePathId_.emplace(fileIndex, id); +} +void NativeHookFilter::AppendSymbolMap(uint32_t id, uint64_t symbolIndex) +{ + symbolIdToSymbolIndex_.emplace(id, symbolIndex); +} +void NativeHookFilter::AppendThreadNameMap(uint32_t id, uint64_t threadNameIndex) +{ + threadNameIdToThreadNameIndex_.emplace(id, threadNameIndex); +} + +template +void NativeHookFilter::UpdateMap(std::unordered_map& sourceMap, T1 key, T2 value) +{ + auto itor = sourceMap.find(key); + if (itor != sourceMap.end()) { + itor->second = value; + } else { + sourceMap.insert(std::make_pair(key, value)); + } +} +std::unique_ptr NativeHookFilter::ParseFrame(const ProtoReader::DataArea& frame) +{ + ProtoReader::Frame_Reader reader(frame.Data(), frame.Size()); + uint64_t symbolIndex = INVALID_UINT64; + uint64_t filePathIndex = INVALID_UINT64; + if (isStringCompressedMode_) { + if (!symbolIdToSymbolIndex_.count(reader.symbol_name_id())) { + TS_LOGE("Native hook ParseFrame find symbol id failed!!!"); + return nullptr; + } + symbolIndex = symbolIdToSymbolIndex_.at(reader.symbol_name_id()); + + if (!filePathIdToFileIndex_.count(reader.file_path_id())) { + TS_LOGE("Native hook ParseFrame find file path id failed!!!"); + return nullptr; + } + filePathIndex = filePathIdToFileIndex_.at(reader.file_path_id()); + } else { + symbolIndex = traceDataCache_->dataDict_.GetStringIndex(reader.symbol_name().ToStdString()); + filePathIndex = traceDataCache_->dataDict_.GetStringIndex(reader.file_path().ToStdString()); + } + auto frameInfo = std::make_unique(reader.ip(), reader.sp(), symbolIndex, filePathIndex, + reader.offset(), reader.symbol_offset()); + return std::move(frameInfo); +} + +void NativeHookFilter::CompressStackAndFrames(ProtoReader::RepeatedDataAreaIterator frames) +{ + std::vector framesHash; + uint64_t frameHash = INVALID_UINT64; + std::string framesHashStr = ""; + for (auto itor = frames; itor; itor++) { + std::string_view frameStr(reinterpret_cast(itor->Data()), itor->Size()); + auto frameHash = hashFun_(frameStr); + if (!frameHashToFrameInfoMap_.count(frameHash)) { + // the frame compression is completed and the frame is parsed. + auto frameInfo = ParseFrame(itor.GetDataArea()); + frameHashToFrameInfoMap_.emplace(std::make_pair(frameHash, std::move(frameInfo))); + } + framesHash.emplace_back(frameHash); + framesHashStr.append("+"); + framesHashStr.append(std::to_string(frameHash)); + } + auto stackHashValue = hashFun_(framesHashStr); + uint32_t callChainId = INVALID_UINT32; + if (!stackHashValueToCallChainIdMap_.count(stackHashValue)) { + callChainId = callChainIdToStackHashValueMap_.size() + 1; + callChainIdToStackHashValueMap_.emplace(std::make_pair(callChainId, stackHashValue)); + stackHashValueToCallChainIdMap_.emplace(std::make_pair(stackHashValue, callChainId)); + stackHashValueToFramesHashMap_.emplace(std::make_pair(stackHashValue, std::move(framesHash))); + } else { + callChainId = stackHashValueToCallChainIdMap_[stackHashValue]; + } + // When compressing the call stack, update the callChainId of the nativeHook table + auto row = traceDataCache_->GetNativeHookData()->Size() - 1; + traceDataCache_->GetNativeHookData()->UpdateCallChainId(row, callChainId); +} +void NativeHookFilter::ParseStatisticEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView) +{ + ProtoReader::RecordStatisticsEvent_Reader reader(bytesView); + if (ipid_ == INVALID_UINT32) { + ipid_ = streamFilters_->processFilter_->GetOrCreateInternalPid(timeStamp, reader.pid()); + } + uint32_t callChainId = INVALID_UINT32; + // When the stack id is zero, there is no matching call stack + if (isOfflineSymbolizationMode_ && reader.callstack_id()) { + // The same call stack may have different symbolic results due to changes in the symbol table + if (stackIdToCallChainIdMap_.count(reader.callstack_id())) { + callChainId = stackIdToCallChainIdMap_.at(reader.callstack_id()); + } else { + TS_LOGE("invalid callChainId, can not find stack id : %u in stackIdToCallChainIdMap_!", + reader.callstack_id()); + } + } else if (reader.callstack_id()) { // when isStatisticMode_ is true, isCallStackCompressedMode_ must be true. + // when isOfflineSymblolizationMode_ is false, the stack id is unique + callChainId = reader.callstack_id(); + } + + traceDataCache_->GetNativeHookStatisticsData()->AppendNewNativeHookStatistic( + ipid_, timeStamp, callChainId, reader.type(), reader.apply_count(), reader.release_count(), reader.apply_size(), + reader.release_size()); +} +void NativeHookFilter::ParseAllocEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView) +{ + ProtoReader::AllocEvent_Reader allocEventReader(bytesView); + uint32_t callChainId = INVALID_UINT32; + // When the stack id is zero, there is no matching call stack + if (isOfflineSymbolizationMode_ && allocEventReader.stack_id()) { + // The same call stack may have different symbolic results due to changes in the symbol table + if (stackIdToCallChainIdMap_.count(allocEventReader.stack_id())) { + callChainId = stackIdToCallChainIdMap_.at(allocEventReader.stack_id()); + } else { + TS_LOGE("invalid callChainId, can not find stack id : %u in stackIdToCallChainIdMap_!", + allocEventReader.stack_id()); + } + } else if (isCallStackCompressedMode_ && allocEventReader.stack_id()) { + // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique + callChainId = allocEventReader.stack_id(); + } + + auto itid = + streamFilters_->processFilter_->GetOrCreateThreadWithPid(allocEventReader.tid(), allocEventReader.pid()); + if (ipid_ == INVALID_UINT32) { + ipid_ = streamFilters_->processFilter_->GetOrCreateInternalPid(timeStamp, allocEventReader.pid()); + } + if (allocEventReader.has_thread_name_id()) { + UpdateMap(itidToThreadNameId_, itid, allocEventReader.thread_name_id()); + } + auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid_, itid, "AllocEvent", INVALID_UINT64, timeStamp, 0, 0, allocEventReader.addr(), + allocEventReader.size()); + addrToAllocEventRow_.insert(std::make_pair(allocEventReader.addr(), static_cast(row))); + if (allocEventReader.size() != 0) { + MaybeUpdateCurrentSizeDur(row, timeStamp, true); + } + // Uncompressed call stack + if (allocEventReader.has_frame_info()) { + CompressStackAndFrames(allocEventReader.frame_info()); + } +} + +void NativeHookFilter::ParseFreeEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView) +{ + ProtoReader::FreeEvent_Reader freeEventReader(bytesView); + uint32_t callChainId = INVALID_UINT32; + // When the stack id is zero, there is no matching call stack + if (isOfflineSymbolizationMode_ && freeEventReader.stack_id()) { + // The same call stack may have different symbolic results due to changes in the symbol table + if (stackIdToCallChainIdMap_.count(freeEventReader.stack_id())) { + callChainId = stackIdToCallChainIdMap_.at(freeEventReader.stack_id()); + } else { + TS_LOGE("invalid callChainId, can not find stack id : %u in stackIdToCallChainIdMap_!", + freeEventReader.stack_id()); + } + } else if (isCallStackCompressedMode_ && freeEventReader.stack_id()) { + // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique + callChainId = freeEventReader.stack_id(); + } + auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(freeEventReader.tid(), freeEventReader.pid()); + if (ipid_ == INVALID_UINT32) { + ipid_ = streamFilters_->processFilter_->GetOrCreateInternalPid(timeStamp, freeEventReader.pid()); + } + if (freeEventReader.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, freeEventReader.thread_name_id()); + } + int64_t freeHeapSize = 0; + // Find a matching malloc event, and if the matching fails, do not write to the database + uint64_t row = INVALID_UINT64; + if (addrToAllocEventRow_.count(freeEventReader.addr())) { + row = addrToAllocEventRow_.at(freeEventReader.addr()); + } + if (row != INVALID_UINT64 && timeStamp > traceDataCache_->GetNativeHookData()->TimeStampData()[row]) { + addrToAllocEventRow_.erase(freeEventReader.addr()); + traceDataCache_->GetNativeHookData()->UpdateEndTimeStampAndDuration(row, timeStamp); + freeHeapSize = traceDataCache_->GetNativeHookData()->MemSizes()[row]; + } else { + TS_LOGD("func addr:%lu is empty", freeEventReader.addr()); + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_DATA_INVALID); + return; + } + + row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid_, itid, "FreeEvent", INVALID_UINT64, timeStamp, 0, 0, freeEventReader.addr(), freeHeapSize); + if (freeHeapSize != 0) { + MaybeUpdateCurrentSizeDur(row, timeStamp, true); + } + // Uncompressed call stack + if (freeEventReader.has_frame_info()) { + CompressStackAndFrames(freeEventReader.frame_info()); + } +} + +void NativeHookFilter::ParseMmapEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView) +{ + ProtoReader::MmapEvent_Reader mMapEventReader(bytesView); + uint32_t callChainId = INVALID_UINT32; + // When the stack id is zero, there is no matching call stack + if (isOfflineSymbolizationMode_ && mMapEventReader.stack_id()) { + // The same call stack may have different symbolic results due to changes in the symbol table + if (stackIdToCallChainIdMap_.count(mMapEventReader.stack_id())) { + callChainId = stackIdToCallChainIdMap_.at(mMapEventReader.stack_id()); + } else { + TS_LOGE("invalid callChainId, can not find stack id : %u in stackIdToCallChainIdMap_!", + mMapEventReader.stack_id()); + } + } else if (isCallStackCompressedMode_ && mMapEventReader.stack_id()) { + // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique + callChainId = mMapEventReader.stack_id(); + } + auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(mMapEventReader.tid(), mMapEventReader.pid()); + if (ipid_ == INVALID_UINT32) { + ipid_ = streamFilters_->processFilter_->GetOrCreateInternalPid(timeStamp, mMapEventReader.pid()); + } + // Update the mapping of tid to thread name id. + if (mMapEventReader.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, mMapEventReader.thread_name_id()); + } + // Gets the index of the mmap event's label in the data dictionary + DataIndex subType = INVALID_UINT64; + if (mMapEventReader.has_type()) { + subType = traceDataCache_->dataDict_.GetStringIndex(mMapEventReader.type().ToStdString()); + // Establish a mapping of addr and size to the mmap tag index. + traceDataCache_->GetNativeHookData()->UpdateAddrToMemMapSubType(mMapEventReader.addr(), subType); + } + auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid_, itid, "MmapEvent", subType, timeStamp, 0, 0, mMapEventReader.addr(), + mMapEventReader.size()); + addrToMmapEventRow_.insert(std::make_pair(mMapEventReader.addr(), static_cast(row))); + // update currentSizeDur. + if (mMapEventReader.size()) { + MaybeUpdateCurrentSizeDur(row, timeStamp, false); + } + // Uncompressed call stack + if (mMapEventReader.has_frame_info()) { + CompressStackAndFrames(mMapEventReader.frame_info()); + } +} + +void NativeHookFilter::ParseMunmapEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView) +{ + ProtoReader::MunmapEvent_Reader mUnmapEventReader(bytesView); + uint32_t callChainId = INVALID_UINT32; + // When the stack id is zero, there is no matching call stack + if (isOfflineSymbolizationMode_ && mUnmapEventReader.stack_id()) { + // The same call stack may have different symbolic results due to changes in the symbol table + if (stackIdToCallChainIdMap_.count(mUnmapEventReader.stack_id())) { + callChainId = stackIdToCallChainIdMap_.at(mUnmapEventReader.stack_id()); + } else { + TS_LOGE("invalid callChainId, can not find stack id : %u in stackIdToCallChainIdMap_!", + mUnmapEventReader.stack_id()); + } + } else if (isCallStackCompressedMode_ && mUnmapEventReader.stack_id()) { + // when isOfflineSymblolizationMode_ is false && isCallStackCompressedMode is true, the stack id is unique + callChainId = mUnmapEventReader.stack_id(); + } + auto itid = + streamFilters_->processFilter_->GetOrCreateThreadWithPid(mUnmapEventReader.tid(), mUnmapEventReader.pid()); + if (ipid_ == INVALID_UINT32) { + ipid_ = streamFilters_->processFilter_->GetOrCreateInternalPid(timeStamp, mUnmapEventReader.pid()); + } + if (mUnmapEventReader.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, mUnmapEventReader.thread_name_id()); + } + // Query for MMAP events that match the current data. If there are no matching MMAP events, the current data is not + // written to the database. + uint64_t row = INVALID_UINT64; + if (addrToMmapEventRow_.count(mUnmapEventReader.addr())) { + row = addrToMmapEventRow_.at(mUnmapEventReader.addr()); + } + if (row != INVALID_UINT64 && timeStamp > traceDataCache_->GetNativeHookData()->TimeStampData()[row]) { + addrToMmapEventRow_.erase(mUnmapEventReader.addr()); + traceDataCache_->GetNativeHookData()->UpdateEndTimeStampAndDuration(row, timeStamp); + } else { + TS_LOGD("func addr:%lu is empty", mUnmapEventReader.addr()); + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_DATA_INVALID); + return; + } + row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid_, itid, "MunmapEvent", INVALID_UINT64, timeStamp, 0, 0, mUnmapEventReader.addr(), + mUnmapEventReader.size()); + if (mUnmapEventReader.size() != 0) { + MaybeUpdateCurrentSizeDur(row, timeStamp, false); + } + // Uncompressed call stack + if (mUnmapEventReader.has_frame_info()) { + CompressStackAndFrames(mUnmapEventReader.frame_info()); + } +} +void NativeHookFilter::FilterNativeHookMainEvent(size_t num) +{ + auto itor = tsToMainEventsMap_.begin(); + for (; itor != tsToMainEventsMap_.end() && num; num--, itor++) { + auto nativeHookDataReader = itor->second->reader_.get(); + auto timeStamp = itor->first; + if (nativeHookDataReader->has_alloc_event()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + ParseAllocEvent(timeStamp, nativeHookDataReader->alloc_event()); + } else if (nativeHookDataReader->has_free_event()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + ParseFreeEvent(timeStamp, nativeHookDataReader->free_event()); + } else if (nativeHookDataReader->has_mmap_event()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + ParseMmapEvent(timeStamp, nativeHookDataReader->mmap_event()); + } else if (nativeHookDataReader->has_munmap_event()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + ParseMunmapEvent(timeStamp, nativeHookDataReader->munmap_event()); + } else if (nativeHookDataReader->has_statistics_event()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_RECORD_STATISTICS, STAT_EVENT_RECEIVED); + ParseStatisticEvent(timeStamp, nativeHookDataReader->statistics_event()); + } + } + tsToMainEventsMap_.erase(tsToMainEventsMap_.begin(), itor); +} + +void NativeHookFilter::MaybeParseNativeHookMainEvent(uint64_t timeStamp, + std::unique_ptr nativeHookMetaData) +{ + tsToMainEventsMap_.insert(std::make_pair(timeStamp, std::move(nativeHookMetaData))); + if (tsToMainEventsMap_.size() > MAX_CACHE_SIZE) { + if (isOfflineSymbolizationMode_) { + ParseFramesInOfflineSymbolizationMode(); + ReparseStacksWithDifferentMeans(); + } + FilterNativeHookMainEvent(tsToMainEventsMap_.size() - MAX_CACHE_SIZE); + } +} + +// Returns the address range of memMaps that conflict with start Addr and endAddr, as [start, end). +std::tuple NativeHookFilter::GetNeedUpdateProcessMapsAddrRange(uint64_t startAddr, uint64_t endAddr) +{ + uint64_t start = INVALID_UINT64; + uint64_t end = INVALID_UINT64; + if (startAddr >= endAddr) { + return std::make_tuple(start, end); + } + // Find first item in startAddrToMapsInfoMap_, + // that startItor->second()->start <= startAddr && startItor->second()->end > startAddr. + auto startItor = startAddrToMapsInfoMap_.upper_bound(startAddr); + if (startAddrToMapsInfoMap_.begin() != startItor) { + startItor--; + // Follow the rules of front closing and rear opening, [start, end) + if (startAddr >= startItor->second->end()) { + startItor++; + } + } + // Forward query for the last item with filePathId == startItor ->filePathId() + if (startItor != startAddrToMapsInfoMap_.end()) { + auto startFilePathId = startItor->second->file_path_id(); + while (startAddrToMapsInfoMap_.begin() != startItor) { + startItor--; + if (startFilePathId != startItor->second->file_path_id()) { + startItor++; + break; + } + } + start = startItor->first; + } + + // Find first item in startAddrToMapsInfoMap_, that endItor->second()->start > endAddr + auto endItor = startAddrToMapsInfoMap_.upper_bound(endAddr); + if (endItor == startAddrToMapsInfoMap_.end() || endItor == startAddrToMapsInfoMap_.begin()) { + return std::make_tuple(start, end); + } + // Backward query for the last item with filePathId == endItor ->filePathId() + --endItor; + auto endFilePathId = endItor->second->file_path_id(); + ++endItor; + while (endItor != startAddrToMapsInfoMap_.end()) { + if (endFilePathId != endItor->second->file_path_id()) { + end = endItor->second->start(); + break; + } + endItor++; + } + return std::make_tuple(start, end); +} +void NativeHookFilter::ReparseStacksWithDifferentMeans() +{ + for (auto itor = reparseStackIdToFramesMap_.begin(); itor != reparseStackIdToFramesMap_.end(); itor++) { + // Items with key equal to stack id should not be retained in stackIdToCallChainIdMap_ + if (stackIdToCallChainIdMap_.count(itor->first)) { + TS_LOGE("error! The mapping of ambiguous call stack id and callChainId has not been deleted!"); + } + stackIdToCallChainIdMap_.insert(std::make_pair(itor->first, ++callChainId_)); + auto framesInfo = OfflineSymbolization(itor->second); + uint64_t depth = 0; + uint64_t filePathIndex = INVALID_UINT64; + for (auto itor = framesInfo->rbegin(); itor != framesInfo->rend(); itor++) { + // Note that the filePathId here is provided for the end side. Not a true TS internal index dictionary. + auto frameInfo = itor->get(); + if (filePathIdToFileIndex_.count(frameInfo->filePathId_)) { + filePathIndex = filePathIdToFileIndex_.at(frameInfo->filePathId_); + } else { + filePathIndex = INVALID_UINT64; + } + std::string vaddr = base::Uint64ToHexText(frameInfo->symVaddr_); + + traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame( + callChainId_, depth, frameInfo->ip_, INVALID_UINT64, frameInfo->symbolIndex_, filePathIndex, + frameInfo->offset_, frameInfo->symbolOffset_, vaddr); + depth++; + } + } + reparseStackIdToFramesMap_.clear(); +} +// Only called in offline symbolization mode. +void NativeHookFilter::ParseMapsEvent(std::unique_ptr& nativeHookMetaData) +{ + segs_.emplace_back(nativeHookMetaData->seg_); + auto reader = std::make_shared(nativeHookMetaData->reader_->maps_info()); + // The temporary variable startAddr here is to solve the problem of parsing errors under the window platform + auto startAddr = reader->start(); + auto endAddr = reader->end(); + uint64_t start = INVALID_UINT64; + uint64_t end = INVALID_UINT64; + // Get [start, end) of ips addr range which need to update + std::tie(start, end) = GetNeedUpdateProcessMapsAddrRange(startAddr, endAddr); + if (start != INVALID_UINT64) { // Conflicting + /* First parse the updated call stacks, then parse the main events, and finally update Maps or SymbolTable + Note that when tsToMainEventsMap_.size() > MAX_CACHE_SIZE and main events need to be resolved, this logic + should also be followed. */ + ParseFramesInOfflineSymbolizationMode(); + // When a main event is updated, the call stack that needs to be parsed again is parsed. + if (tsToMainEventsMap_.size()) { + ReparseStacksWithDifferentMeans(); + FilterNativeHookMainEvent(tsToMainEventsMap_.size()); + } + + // Delete IP symbolization results within the conflict range. + auto ipToFrameInfoItor = ipToFrameInfo_.lower_bound(start); + while (ipToFrameInfoItor != ipToFrameInfo_.end() && ipToFrameInfoItor->first < end) { + auto key = ipToFrameInfoItor->first; + ipToFrameInfoItor++; + ipToFrameInfo_.erase(key); + } + // Delete MapsInfo within the conflict range + auto startAddrToMapsInfoItor = startAddrToMapsInfoMap_.lower_bound(start); + while (startAddrToMapsInfoItor != startAddrToMapsInfoMap_.end() && startAddrToMapsInfoItor->first < end) { + auto key = startAddrToMapsInfoItor->first; + startAddrToMapsInfoItor++; + startAddrToMapsInfoMap_.erase(key); + } + // Get the list of call stack ids that should be parsed again + for (auto itor = allStackIdToFramesMap_.begin(); itor != allStackIdToFramesMap_.end(); itor++) { + auto ips = itor->second; + for (auto ipsItor = ips->begin(); ipsItor != ips->end(); ipsItor++) { + if (*ipsItor >= start && *ipsItor < end) { + // delete the stack ids whitch should be parsed again + if (stackIdToCallChainIdMap_.count(itor->first)) { + stackIdToCallChainIdMap_.erase(itor->first); + } + /* update reparseStackIdToFramesMap_. The reparseStackIdToFramesMap_ cannot be parsed immediately. + Wait until the relevant memmaps and symbolTable updates are completed. After the main event is + updated and before the main event is about to be parsed, parse reparseStackIdToFramesMap_ first. */ + if (!stackIdToFramesMap_.count(itor->first)) { + reparseStackIdToFramesMap_.emplace(std::make_pair(itor->first, itor->second)); + } + break; + } + } + } + } + startAddrToMapsInfoMap_.insert(std::make_pair(startAddr, std::move(reader))); +} +template +void NativeHookFilter::UpdateSymbolTablePtrAndStValueToSymAddrMap( + T* firstSymbolAddr, + const int size, + std::shared_ptr reader) +{ + for (auto i = 0; i < size; i++) { + auto symAddr = firstSymbolAddr + i; + if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) { + symbolTablePtrAndStValueToSymAddr_.Insert(reader, symAddr->st_value, + reinterpret_cast(symAddr)); + } + } +} +// Only called in offline symbolization mode. +void NativeHookFilter::ParseSymbolTableEvent(std::unique_ptr& nativeHookMetaData) +{ + segs_.emplace_back(nativeHookMetaData->seg_); + + auto reader = std::make_shared(nativeHookMetaData->reader_->symbol_tab()); + auto filePathId = reader->file_path_id(); + if (filePathIdToSymbolTableMap_.count(filePathId)) { // SymbolTable already exists. + /* First parse the updated call stacks, then parse the main events, and finally update Maps or SymbolTable + Note that when tsToMainEventsMap_.size() > MAX_CACHE_SIZE and main events need to be resolved, this logic + should also be followed. */ + ParseFramesInOfflineSymbolizationMode(); + // When a main event is updated, the call stack that needs to be parsed again is parsed. + if (tsToMainEventsMap_.size()) { + ReparseStacksWithDifferentMeans(); + FilterNativeHookMainEvent(tsToMainEventsMap_.size()); + } + // Delete symbolic results with the same filePathId + for (auto itor = ipToFrameInfo_.begin(); itor != ipToFrameInfo_.end(); itor++) { + if (itor->second->filePathId_ == filePathId) { + ipToFrameInfo_.erase(itor->first); + } + } + uint64_t start = INVALID_UINT32; + uint64_t end = 0; + for (auto itor = startAddrToMapsInfoMap_.begin(); itor != startAddrToMapsInfoMap_.end(); itor++) { + if (itor->second->file_path_id() == filePathId) { + start = std::min(itor->first, start); + end = std::max(itor->second->end(), end); + } else if (start != INVALID_UINT32) { + break; + } + } + // Get the list of call stack ids that should be parsed again + for (auto itor = allStackIdToFramesMap_.begin(); itor != allStackIdToFramesMap_.end(); itor++) { + auto ips = itor->second; + for (auto ipsItor = ips->begin(); ipsItor != ips->end(); ipsItor++) { + if (*ipsItor >= start && *ipsItor < end) { + // delete the stack ids whitch should be parsed again + if (stackIdToCallChainIdMap_.count(itor->first)) { + stackIdToCallChainIdMap_.erase(itor->first); + } + /* update reparseStackIdToFramesMap_. The reparseStackIdToFramesMap_ cannot be parsed immediately. + Wait until the relevant memmaps and symbolTable updates are completed. After the main event is + updated and before the main event is about to be parsed, parse reparseStackIdToFramesMap_ first. */ + if (!stackIdToFramesMap_.count(itor->first)) { + reparseStackIdToFramesMap_.emplace(std::make_pair(itor->first, itor->second)); + } + break; + } + } + } + + filePathIdToSymbolTableMap_.at(filePathId) = reader; + } else { + filePathIdToSymbolTableMap_.insert(std::make_pair(filePathId, reader)); + } + + auto symEntrySize = reader->sym_entry_size(); + auto symTable = reader->sym_table(); + auto size = symTable.Size() / symEntrySize; + if (symEntrySize == ELF32_SYM) { + UpdateSymbolTablePtrAndStValueToSymAddrMap(reinterpret_cast(symTable.Data()), size, reader); + } else { + UpdateSymbolTablePtrAndStValueToSymAddrMap(reinterpret_cast(symTable.Data()), size, reader); + } +} + +void NativeHookFilter::MaybeUpdateCurrentSizeDur(uint64_t row, uint64_t timeStamp, bool isMalloc) +{ + auto& lastAnyEventRaw = isMalloc ? lastMallocEventRaw_ : lastMmapEventRaw_; + if (lastAnyEventRaw != INVALID_UINT64) { + traceDataCache_->GetNativeHookData()->UpdateCurrentSizeDur(lastAnyEventRaw, timeStamp); + } + lastAnyEventRaw = row; +} +// when symbolization failed, use filePath + vaddr as symbol name +void NativeHookFilter::UpdateSymbolIdsForSymbolizationFailed() +{ + auto size = traceDataCache_->GetNativeHookFrameData()->Size(); + for (auto i = 0; i < size; ++i) { + if (traceDataCache_->GetNativeHookFrameData()->SymbolNames()[i] == INVALID_UINT64) { + auto filePathIndex = traceDataCache_->GetNativeHookFrameData()->FilePaths()[i]; + auto filePathStr = traceDataCache_->dataDict_.GetDataFromDict(filePathIndex); + auto vaddrStr = traceDataCache_->GetNativeHookFrameData()->Vaddrs()[i]; + traceDataCache_->GetNativeHookFrameData()->UpdateSymbolId( + i, traceDataCache_->dataDict_.GetStringIndex(filePathStr + "+" + vaddrStr)); + } + } +} +void NativeHookFilter::ParseFramesInOfflineSymbolizationMode() +{ + for (auto stackIdToFramesItor = stackIdToFramesMap_.begin(); stackIdToFramesItor != stackIdToFramesMap_.end(); + stackIdToFramesItor++) { + auto framesInfo = OfflineSymbolization(stackIdToFramesItor->second); + uint64_t depth = 0; + uint64_t filePathIndex = INVALID_UINT64; + ++callChainId_; + // In offline mode, parsing the main event depends on the updated stackIdToCallChainIdMap_ here. + stackIdToCallChainIdMap_.emplace(std::make_pair(stackIdToFramesItor->first, callChainId_)); + for (auto itor = framesInfo->rbegin(); itor != framesInfo->rend(); itor++) { + // Note that the filePathId here is provided for the end side. Not a true TS internal index dictionary. + auto frameInfo = itor->get(); + if (filePathIdToFileIndex_.count(frameInfo->filePathId_)) { + filePathIndex = filePathIdToFileIndex_.at(frameInfo->filePathId_); + } else { + filePathIndex = INVALID_UINT64; + } + std::string vaddr = base::Uint64ToHexText(frameInfo->symVaddr_); + + traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame( + callChainId_, depth, frameInfo->ip_, INVALID_UINT64, frameInfo->symbolIndex_, filePathIndex, + frameInfo->offset_, frameInfo->symbolOffset_, vaddr); + depth++; + } + } + // In offline symbolization scenarios, The updated call stack information is saved in stackIdToFramesMap_. + // After each parsing is completed, it needs to be cleared to avoid repeated parsing. + stackIdToFramesMap_.clear(); +} + +void NativeHookFilter::GetNativeHookFrameVaddrs() +{ + vaddrs_.clear(); + auto size = traceDataCache_->GetNativeHookFrameData()->Size(); + // Traverse every piece of native_hook frame data + for (auto i = 0; i < size; i++) { + auto symbolOffset = traceDataCache_->GetNativeHookFrameData()->SymbolOffsets()[i]; + // When the symbol offset is not 0, vaddr=offset+symbol offset + if (symbolOffset) { + auto fileOffset = traceDataCache_->GetNativeHookFrameData()->Offsets()[i]; + auto vaddr = base::Uint64ToHexText(fileOffset + symbolOffset); + vaddrs_.emplace_back(vaddr); + continue; + } + // When the symbol offset is 0, vaddr takes the string after the plus sign in the function name + auto functionNameIndex = traceDataCache_->GetNativeHookFrameData()->SymbolNames()[i]; + std::string vaddr = ""; + auto itor = functionNameIndexToVaddr_.find(functionNameIndex); + if (itor == functionNameIndexToVaddr_.end()) { + auto functionName = traceDataCache_->dataDict_.GetDataFromDict(functionNameIndex); + auto pos = functionName.rfind("+"); + if (pos != functionName.npos && pos != functionName.length() - 1) { + vaddr = functionName.substr(++pos); + } + // Vaddr keeps "" when lookup failed + functionNameIndexToVaddr_.emplace(std::make_pair(functionNameIndex, vaddr)); + } else { + vaddr = itor->second; + } + vaddrs_.emplace_back(vaddr); + } +} +// Called When isCallStackCompressedMode_ is true && isOfflineSymbolizationMode_ is false. +void NativeHookFilter::ParseFramesInCallStackCompressedMode() +{ + for (auto stackIdToFramesItor = stackIdToFramesMap_.begin(); stackIdToFramesItor != stackIdToFramesMap_.end(); + stackIdToFramesItor++) { + auto frameIds = stackIdToFramesItor->second; + uint64_t depth = 0; + for (auto frameIdsItor = frameIds->crbegin(); frameIdsItor != frameIds->crend(); frameIdsItor++) { + if (!frameIdToFrameBytes_.count(*frameIdsItor)) { + TS_LOGE("Can not find Frame by frame_map_id!!!"); + continue; + } + ProtoReader::Frame_Reader reader(*(frameIdToFrameBytes_.at(*frameIdsItor))); + + if (!reader.has_file_path_id() or !reader.has_symbol_name_id()) { + TS_LOGE("Data exception, frames should has fil_path_id and symbol_name_id"); + continue; + } + if (!filePathIdToFileIndex_.count(reader.file_path_id())) { + TS_LOGE("Data exception, can not find fil_path_id!!!"); + continue; + } + auto& filePathIndex = filePathIdToFileIndex_.at(reader.file_path_id()); + if (!symbolIdToSymbolIndex_.count(reader.symbol_name_id())) { + TS_LOGE("Data exception, can not find symbol_name_id!!!"); + continue; + } + auto& symbolIndex = symbolIdToSymbolIndex_.at(reader.symbol_name_id()); + traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame( + stackIdToFramesItor->first, depth, reader.ip(), reader.sp(), symbolIndex, filePathIndex, + reader.offset(), reader.symbol_offset()); + depth++; + } + } +} +// Called When isCallStackCompressedMode_ is false. +void NativeHookFilter::ParseFramesWithOutCallStackCompressedMode() +{ + for (auto itor = callChainIdToStackHashValueMap_.begin(); itor != callChainIdToStackHashValueMap_.end(); itor++) { + auto callChainId = itor->first; + if (!stackHashValueToFramesHashMap_.count(itor->second)) { + continue; + } + auto& framesHash = stackHashValueToFramesHashMap_.at(itor->second); + uint64_t depth = 0; + for (auto frameHashValueVectorItor = framesHash.crbegin(); frameHashValueVectorItor != framesHash.crend(); + frameHashValueVectorItor++) { + if (!frameHashToFrameInfoMap_.count(*frameHashValueVectorItor)) { + TS_LOGE("find matching frameInfo failed!!!!"); + return; + } + auto& frameInfo = frameHashToFrameInfoMap_.at(*frameHashValueVectorItor); + traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame( + callChainId, depth, frameInfo->ip_, frameInfo->sp_, frameInfo->symbolIndex_, frameInfo->filePathIndex_, + frameInfo->offset_, frameInfo->symbolOffset_); + depth++; + } + } +} +void NativeHookFilter::ParseSymbolizedNativeHookFrame() +{ + // isOfflineSymbolizationMode is false, but isCallStackCompressedMode is true. + if (isCallStackCompressedMode_) { + ParseFramesInCallStackCompressedMode(); + } else { + ParseFramesWithOutCallStackCompressedMode(); + } + GetNativeHookFrameVaddrs(); + traceDataCache_->GetNativeHookFrameData()->UpdateVaddrs(vaddrs_); + return; +} +void NativeHookFilter::UpdateThreadNameWithNativeHookData() const +{ + if (itidToThreadNameId_.empty() || threadNameIdToThreadNameIndex_.empty()) { + return; + } + for (auto itor = itidToThreadNameId_.begin(); itor != itidToThreadNameId_.end(); ++itor) { + auto thread = traceDataCache_->GetThreadData(itor->first); + if (!thread->nameIndex_) { + auto threadNameMapItor = threadNameIdToThreadNameIndex_.find(itor->second); + if (threadNameMapItor != threadNameIdToThreadNameIndex_.end()) { + thread->nameIndex_ = threadNameMapItor->second; + } + } + } +} +void NativeHookFilter::FinishParseNativeHookData() +{ + // In offline symbolization mode Parse all NativeHook main events depends on updated stackIdToCallChainIdMap_ during + // execute ParseSymbolizedNativeHookFrame or ReparseStacksWithDifferentMeans , So first parse the call stack data + // and then parse the main event. + if (isOfflineSymbolizationMode_) { + ParseFramesInOfflineSymbolizationMode(); + ReparseStacksWithDifferentMeans(); + UpdateSymbolIdsForSymbolizationFailed(); + } + FilterNativeHookMainEvent(tsToMainEventsMap_.size()); + // In online symbolization mode and callstack is not compressed mode parse stack should after parse main event + // In online symbolization mode and callstack is compressed mode, there is no need worry about the order + if (!isOfflineSymbolizationMode_) { + ParseSymbolizedNativeHookFrame(); + } + + traceDataCache_->GetNativeHookData()->UpdateMemMapSubType(); + // update last lib id + GetCallIdToLastLibId(); + if (callIdToLastCallerPathIndex_.size()) { + traceDataCache_->GetNativeHookData()->UpdateLastCallerPathIndexs(callIdToLastCallerPathIndex_); + } + UpdateThreadNameWithNativeHookData(); +} +void NativeHookFilter::GetCallIdToLastLibId() +{ + auto size = static_cast(traceDataCache_->GetNativeHookFrameData()->Size()); + uint32_t lastCallChainId = INVALID_UINT32; + bool foundLast = false; + for (auto i = size - 1; i > -1; i--) { + auto callChainId = traceDataCache_->GetNativeHookFrameData()->CallChainIds()[i]; + if (callChainId == lastCallChainId) { + if (foundLast) { + continue; + } + } + if (callChainId != lastCallChainId) { + lastCallChainId = callChainId; + foundLast = false; + } + auto filePathIndex = traceDataCache_->GetNativeHookFrameData()->FilePaths()[i]; + if (!traceDataCache_->GetNativeHookFrameData()->Depths()[i]) { + callIdToLastCallerPathIndex_.insert(std::make_pair(callChainId, filePathIndex)); + foundLast = true; + continue; + } + + auto lower = std::lower_bound(invalidLibPathIndexs_.begin(), invalidLibPathIndexs_.end(), filePathIndex); + if (lower == invalidLibPathIndexs_.end() || *lower != filePathIndex) { // found + auto filePath = traceDataCache_->dataDict_.GetDataFromDict(filePathIndex); + auto ret = filePath.find("libc++_shared.so"); + if (ret == filePath.npos) { + callIdToLastCallerPathIndex_.insert(std::make_pair(callChainId, filePathIndex)); + foundLast = true; + } + } + } +} +bool NativeHookFilter::GetIpsWitchNeedResymbolization(DataIndex filePathId, std::set& ips) +{ + bool value = false; + for (auto itor = ipToFrameInfo_.begin(); itor != ipToFrameInfo_.end(); itor++) { + if (!itor->second) { + TS_LOGI("ip :%lu can not symbolization! FrameInfo is nullptr", itor->first); + continue; + } + if (itor->second->filePathId_ == filePathId) { + ips.insert(itor->first); + value = true; + } + } + return value; +} + +template +void NativeHookFilter::UpdateFilePathIdAndStValueToSymAddrMap(T* firstSymbolAddr, const int size, uint32_t filePathId) +{ + for (auto i = 0; i < size; i++) { + auto symAddr = firstSymbolAddr + i; + if ((symAddr->st_info & STT_FUNC) && (symAddr->st_value)) { + filePathIdAndStValueToSymAddr_.Insert(filePathId, symAddr->st_value, + reinterpret_cast(symAddr)); + } + } +} +bool NativeHookFilter::NativeHookReloadElfSymbolTable( + std::shared_ptr>> elfSymbolTables) +{ + std::set resymbolizationIps; + for (auto elfSymbolTable : *elfSymbolTables) { + auto filePathIndex = traceDataCache_->dataDict_.GetStringIndex(elfSymbolTable->filePath); + if (!fileIndexToFilePathId_.count(filePathIndex)) { + TS_LOGD("native_hook maps does not support using %s resymbolization!", elfSymbolTable->filePath.c_str()); + continue; + } + auto filePathId = fileIndexToFilePathId_.at(filePathIndex); + // record ips whitch needs resymbolization + auto ret = GetIpsWitchNeedResymbolization(filePathId, resymbolizationIps); + if (!ret) { + continue; + } + auto symEntrySize = elfSymbolTable->symEntSize; + auto size = elfSymbolTable->symTable.size() / symEntrySize; + if (symEntrySize == ELF32_SYM) { + UpdateFilePathIdAndStValueToSymAddrMap(reinterpret_cast(elfSymbolTable->symTable.data()), + size, filePathId); + } else { + UpdateFilePathIdAndStValueToSymAddrMap(reinterpret_cast(elfSymbolTable->symTable.data()), + size, filePathId); + } + if (filePathIdToImportSymbolTableMap_.count(filePathId)) { + filePathIdToImportSymbolTableMap_.at(filePathId) = elfSymbolTable; + } else { + filePathIdToImportSymbolTableMap_.emplace(std::make_pair(filePathId, elfSymbolTable)); + } + } + // Delete symbolization results with the same filePath + for (auto ip : resymbolizationIps) { + ipToFrameInfo_.erase(ip); + } + OfflineSymbolization(resymbolizationIps); + UpdateResymbolizationResult(resymbolizationIps); + return true; +} +void NativeHookFilter::UpdateResymbolizationResult(const std::set& ips) +{ + auto nativeHookFrame = traceDataCache_->GetNativeHookFrameData(); + for (auto i = 0; i < nativeHookFrame->Size(); i++) { + auto ip = nativeHookFrame->Ips()[i]; + auto itor = ips.lower_bound(ip); + if (itor == ips.end() || *itor != ip) { + continue; + } + if (!ipToFrameInfo_.count(ip)) { + continue; + } + auto frameInfo = ipToFrameInfo_.at(ip); + DataIndex filePathIndex = INVALID_DATAINDEX; + if (!filePathIdToFileIndex_.count(frameInfo->filePathId_)) { + TS_LOGE("filePathId_%u not found", frameInfo->filePathId_); + continue; + } + filePathIndex = filePathIdToFileIndex_.at(frameInfo->filePathId_); + nativeHookFrame->UpdateFrameInfo(i, frameInfo->symbolIndex_, filePathIndex, frameInfo->offset_, + frameInfo->symbolOffset_); + } + UpdateSymbolIdsForSymbolizationFailed(); + // update vaddrs + GetNativeHookFrameVaddrs(); + nativeHookFrame->UpdateVaddrs(vaddrs_); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/native_hook_filter.h b/trace_streamer/src/filter/native_hook_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..c6648e8a8b31cd7a1f60b798c9470e7939787603 --- /dev/null +++ b/trace_streamer/src/filter/native_hook_filter.h @@ -0,0 +1,149 @@ +/* + * 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 NATIVE_HOOK_FILTER_H +#define NATIVE_HOOK_FILTER_H +#include "native_hook_config.pbreader.h" +#include "numerical_to_string.h" +#include "offline_symbolization_filter.h" +#include "stat_filter.h" +#include "string_help.h" + +namespace SysTuning { +namespace TraceStreamer { +class NativeHookFrameInfo { +public: + NativeHookFrameInfo() + : ip_(INVALID_UINT64), + sp_(INVALID_UINT64), + symbolIndex_(INVALID_UINT64), + filePathIndex_(INVALID_UINT64), + offset_(INVALID_UINT64), + symbolOffset_(INVALID_UINT64) + { + } + NativeHookFrameInfo(uint64_t ip, + uint64_t sp, + uint64_t symbolIndex, + uint64_t filePathIndex, + uint64_t offset, + uint64_t symbolOffset) + : ip_(ip), + sp_(sp), + symbolIndex_(symbolIndex), + filePathIndex_(filePathIndex), + offset_(offset), + symbolOffset_(symbolOffset) + { + } + ~NativeHookFrameInfo() {} + uint64_t ip_; + uint64_t sp_; + uint64_t symbolIndex_; + uint64_t filePathIndex_; + uint64_t offset_; + uint64_t symbolOffset_; +}; + +class NativeHookFilter : public OfflineSymbolizationFilter { +public: + NativeHookFilter(TraceDataCache*, const TraceStreamerFilters*); + NativeHookFilter(const NativeHookFilter&) = delete; + NativeHookFilter& operator=(const NativeHookFilter&) = delete; + ~NativeHookFilter() = default; + +public: + void MaybeParseNativeHookMainEvent(uint64_t timeStamp, std::unique_ptr nativeHookMetaData); + void ParseConfigInfo(ProtoReader::BytesView& protoData); + void AppendStackMaps(uint32_t stackid, std::vector& frames); + void AppendFrameMaps(uint32_t id, const ProtoReader::BytesView& bytesView); + void AppendFilePathMaps(uint32_t id, uint64_t fileIndex); + void AppendSymbolMap(uint32_t id, uint64_t symbolIndex); + void AppendThreadNameMap(uint32_t id, uint64_t threadNameIndex); + void ParseMapsEvent(std::unique_ptr& nativeHookMetaData); + void ParseSymbolTableEvent(std::unique_ptr& nativeHookMetaData); + void FinishParseNativeHookData(); + bool NativeHookReloadElfSymbolTable(std::shared_ptr>> elfSymbolTables); + bool SupportImportSymbolTable() + { + return isOfflineSymbolizationMode_; + } + +private: + void FilterNativeHookMainEvent(size_t num); + void ParseStatisticEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView); + template + void UpdateMap(std::unordered_map& sourceMap, T1 key, T2 value); + void ParseAllocEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView); + void ParseFreeEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView); + void ParseMmapEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView); + void ParseMunmapEvent(uint64_t timeStamp, const ProtoReader::BytesView& bytesView); + void MaybeUpdateCurrentSizeDur(uint64_t row, uint64_t timeStamp, bool isMalloc); + void UpdateThreadNameWithNativeHookData() const; + void GetCallIdToLastLibId(); + void GetNativeHookFrameVaddrs(); + void UpdateSymbolIdsForSymbolizationFailed(); + void ParseFramesInOfflineSymbolizationMode(); + void ParseFramesInCallStackCompressedMode(); + void ParseFramesWithOutCallStackCompressedMode(); + void ParseSymbolizedNativeHookFrame(); + bool GetIpsWitchNeedResymbolization(DataIndex filePathId, std::set& ips); + template + void UpdateSymbolTablePtrAndStValueToSymAddrMap(T* firstSymbolAddr, + const int size, + std::shared_ptr reader); + void ReparseStacksWithDifferentMeans(); + void CompressStackAndFrames(ProtoReader::RepeatedDataAreaIterator frames); + std::tuple GetNeedUpdateProcessMapsAddrRange(uint64_t startAddr, uint64_t endAddr); + std::unique_ptr ParseFrame(const ProtoReader::DataArea& frame); + template + void UpdateFilePathIdAndStValueToSymAddrMap(T* firstSymbolAddr, const int size, uint32_t filePathId); + void UpdateResymbolizationResult(const std::set& ips); + +private: + std::multimap> tsToMainEventsMap_ = {}; + std::map>> reparseStackIdToFramesMap_ = {}; + std::map>> allStackIdToFramesMap_ = {}; + std::map>> stackIdToFramesMap_ = {}; + std::map callChainIdToStackHashValueMap_ = {}; + std::unordered_map> frameIdToFrameBytes_ = {}; + std::unordered_map> stackHashValueToFramesHashMap_ = {}; + std::unordered_map> frameHashToFrameInfoMap_ = {}; + std::unordered_map threadNameIdToThreadNameIndex_ = {}; + std::unordered_map callIdToLastCallerPathIndex_ = {}; + std::unordered_map functionNameIndexToVaddr_ = {}; + std::unordered_map symbolIdToSymbolIndex_ = {}; + std::unordered_map stackHashValueToCallChainIdMap_ = {}; + std::unordered_map itidToThreadNameId_ = {}; + std::unordered_map filePathIdToFileIndex_ = {}; + std::unordered_map fileIndexToFilePathId_ = {}; + std::unordered_map stackIdToCallChainIdMap_ = {}; + std::unordered_map addrToAllocEventRow_; + std::unordered_map addrToMmapEventRow_; + std::set invalidLibPathIndexs_ = {}; + std::deque vaddrs_ = {}; + std::hash hashFun_; + uint64_t lastMallocEventRaw_ = INVALID_UINT64; + uint64_t lastMmapEventRaw_ = INVALID_UINT64; + bool isOfflineSymbolizationMode_ = false; + bool isCallStackCompressedMode_ = false; + bool isStringCompressedMode_ = false; + bool isStatisticMode_ = false; + const size_t MAX_CACHE_SIZE = 200000; + uint32_t ipid_ = INVALID_UINT32; + uint32_t callChainId_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // NATIVE_HOOK_FILTER_H diff --git a/trace_streamer/src/filter/offline_symbolization_filter.cpp b/trace_streamer/src/filter/offline_symbolization_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a3988c3683e476da4adc3c811c8de229211fe3d --- /dev/null +++ b/trace_streamer/src/filter/offline_symbolization_filter.cpp @@ -0,0 +1,203 @@ +/* + * 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 "offline_symbolization_filter.h" +namespace SysTuning { +namespace TraceStreamer { +OfflineSymbolizationFilter::OfflineSymbolizationFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter), + symbolTablePtrAndStValueToSymAddr_(nullptr), + filePathIdAndStValueToSymAddr_(nullptr) +{ +} +std::shared_ptr>> OfflineSymbolizationFilter::OfflineSymbolization( + const std::shared_ptr> ips) +{ + auto result = std::make_shared>>(); + for (auto itor = ips->begin(); itor != ips->end(); itor++) { + auto frameInfo = OfflineSymbolization(*itor); + // If the IP in the middle of the call stack cannot be symbolized, the remaining IP is discarded + if (!frameInfo) { + break; + } + result->emplace_back(frameInfo); + } + return result; +} +template +void OfflineSymbolizationFilter::UpdateFrameInfo(T* elfSym, + uint32_t& symbolStart, + uint64_t symVaddr, + uint64_t ip, + FrameInfo* frameInfo) +{ + if (elfSym->st_value + elfSym->st_size >= symVaddr) { + symbolStart = elfSym->st_name; + frameInfo->offset_ = elfSym->st_value != 0 ? elfSym->st_value : ip; + frameInfo->symbolOffset_ = symVaddr - elfSym->st_value; + } +} +std::shared_ptr OfflineSymbolizationFilter::OfflineSymbolization(uint64_t ip) +{ + if (ipToFrameInfo_.count(ip)) { + return ipToFrameInfo_.at(ip); + } + // start symbolization + std::shared_ptr frameInfo = std::make_shared(); + frameInfo->ip_ = ip; + uint64_t vmStart = INVALID_UINT64; + uint64_t vmOffset = INVALID_UINT64; + auto endItor = startAddrToMapsInfoMap_.upper_bound(ip); + auto length = std::distance(startAddrToMapsInfoMap_.begin(), endItor); + if (length > 0) { + endItor--; + // Follow the rules of front closing and rear opening, [start, end) + if (ip < endItor->second->end()) { + vmStart = endItor->second->start(); + vmOffset = endItor->second->offset(); + frameInfo->filePathId_ = endItor->second->file_path_id(); + } + } + if (frameInfo->filePathId_ == INVALID_UINT32) { + // find matching MapsInfo failed!!! + TS_LOGD("find matching Maps Info failed, ip = %lu", ip); + return nullptr; + } + // find SymbolTable by filePathId + auto itor = filePathIdToSymbolTableMap_.find(frameInfo->filePathId_); + if (itor == filePathIdToSymbolTableMap_.end()) { + // find matching SymbolTable failed, but filePathId is availiable + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + TS_LOGD("find matching filePathId failed, ip = %lu, filePathId = %u", ip, frameInfo->filePathId_); + return frameInfo; + } + auto symbolTable = itor->second; + // calculate symVaddr = ip - vmStart + vmOffset + phdrVaddr - phdrOffset + uint64_t symVaddr = + ip - vmStart + vmOffset + symbolTable->text_exec_vaddr() - symbolTable->text_exec_vaddr_file_offset(); + frameInfo->symVaddr_ = symVaddr; + + // pase sym_table to Elf32_Sym or Elf64_Sym array decided by sym_entry_size. + auto symEntLen = symbolTable->sym_entry_size(); + auto startValueToSymAddrMap = symbolTablePtrAndStValueToSymAddr_.Find(symbolTable); + if (!startValueToSymAddrMap) { + // find matching SymbolTable failed, but symVaddr is availiable + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + // find symbolTable failed!!! + TS_LOGD("find symbolTalbe failed!!!"); + return frameInfo; + } + // Traverse array, st_value <= symVaddr and symVaddr <= st_value + st_size. then you can get st_name + auto end = startValueToSymAddrMap->upper_bound(symVaddr); + length = std::distance(startValueToSymAddrMap->begin(), end); + uint32_t symbolStart = INVALID_UINT32; + if (length > 0) { + end--; + if (symEntLen == ELF32_SYM) { + UpdateFrameInfo(reinterpret_cast(end->second), symbolStart, symVaddr, ip, + frameInfo.get()); + } else { + UpdateFrameInfo(reinterpret_cast(end->second), symbolStart, symVaddr, ip, + frameInfo.get()); + } + } + + if (symbolStart == INVALID_UINT32 || symbolStart >= symbolTable->str_table().Size()) { + // find symbolStart failed, but some data is availiable. + frameInfo->offset_ = ip; + frameInfo->symbolOffset_ = 0; + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + TS_LOGD("symbolStart is %lu invaliable!!!", symbolStart); + return frameInfo; + } + + auto mangle = reinterpret_cast(symbolTable->str_table().Data() + symbolStart); + auto demangle = GetDemangleSymbolIndex(mangle); + frameInfo->symbolIndex_ = traceDataCache_->GetDataIndex(demangle); + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + return frameInfo; +} + +void OfflineSymbolizationFilter::OfflineSymbolization(const std::set& ips) +{ + for (auto ip : ips) { + // start symbolization + std::shared_ptr frameInfo = std::make_shared(); + frameInfo->ip_ = ip; + uint64_t vmStart = INVALID_UINT64; + uint64_t vmOffset = INVALID_UINT64; + auto endItor = startAddrToMapsInfoMap_.upper_bound(ip); + auto length = std::distance(startAddrToMapsInfoMap_.begin(), endItor); + if (length > 0) { + endItor--; + // Follow the rules of front closing and rear opening, [start, end) + if (ip < endItor->second->end()) { + vmStart = endItor->second->start(); + vmOffset = endItor->second->offset(); + frameInfo->filePathId_ = endItor->second->file_path_id(); + } + } + if (frameInfo->filePathId_ == INVALID_UINT32) { + // find matching MapsInfo failed!!! + TS_LOGD("find matching Maps Info failed, ip = %lu", ip); + continue; + } + if (!filePathIdToImportSymbolTableMap_.count(frameInfo->filePathId_)) { + TS_LOGD("can not find matching symbol table!"); + continue; + } + auto& symbolTable = filePathIdToImportSymbolTableMap_.at(frameInfo->filePathId_); + // Calculate virtual address + uint64_t symVaddr = ip - vmStart + vmOffset + symbolTable->textVaddr - symbolTable->textOffset; + // pase sym_table to Elf32_Sym or Elf64_Sym array decided by sym_entry_size. + auto symEntLen = symbolTable->symEntSize; + auto startValueToSymAddrMap = filePathIdAndStValueToSymAddr_.Find(frameInfo->filePathId_); + if (!startValueToSymAddrMap) { + // find matching SymbolTable failed, but symVaddr is availiable + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + // find symbolTable failed!!! + TS_LOGD("find symbolTalbe failed!!!"); + continue; + } + // Traverse array, st_value <= symVaddr and symVaddr <= st_value + st_size. then you can get st_name + auto end = startValueToSymAddrMap->upper_bound(symVaddr); + length = std::distance(startValueToSymAddrMap->begin(), end); + uint32_t symbolStart = INVALID_UINT32; + if (length > 0) { + end--; + if (symEntLen == ELF32_SYM) { + UpdateFrameInfo(reinterpret_cast(end->second), symbolStart, symVaddr, ip, + frameInfo.get()); + } else { + UpdateFrameInfo(reinterpret_cast(end->second), symbolStart, symVaddr, ip, + frameInfo.get()); + } + } + if (symbolStart == INVALID_UINT32 || symbolStart >= symbolTable->strTable.size()) { + // find symbolStart failed, but some data is availiable. + frameInfo->offset_ = ip; + frameInfo->symbolOffset_ = 0; + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + TS_LOGD("symbolStart is : %u invaliable!!!", symbolStart); + continue; + } + auto mangle = symbolTable->strTable.c_str() + symbolStart; + auto demangle = GetDemangleSymbolIndex(mangle); + frameInfo->symbolIndex_ = traceDataCache_->GetDataIndex(demangle); + ipToFrameInfo_.insert(std::make_pair(ip, frameInfo)); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/offline_symbolization_filter.h b/trace_streamer/src/filter/offline_symbolization_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..60ee00e9a55dc46f9e6835f28589d8c27830487c --- /dev/null +++ b/trace_streamer/src/filter/offline_symbolization_filter.h @@ -0,0 +1,81 @@ +/* + * 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 OFFLINE_SYMBOLIZATION_FILTER_H +#define OFFLINE_SYMBOLIZATION_FILTER_H +#include +#include +#include "native_hook_result.pbreader.h" +#include "process_filter.h" +#include "proto_reader.h" +#include "string_help.h" +#include "ts_common.h" +namespace SysTuning { +namespace TraceStreamer { +class FrameInfo { +public: + FrameInfo() + { + filePathId_ = INVALID_UINT32; + ip_ = INVALID_UINT64; + symbolIndex_ = INVALID_UINT64; + offset_ = INVALID_UINT64; + symbolOffset_ = INVALID_UINT64; + symVaddr_ = INVALID_UINT64; + } + uint32_t filePathId_; + uint64_t ip_; + uint64_t symbolIndex_; + uint64_t offset_; + uint64_t symbolOffset_; + uint64_t symVaddr_; +}; +struct NativeHookMetaData { + NativeHookMetaData(const std::shared_ptr& seg, + std::unique_ptr reader) + : seg_(seg), reader_(std::move(reader)) + { + } + std::shared_ptr seg_; + std::unique_ptr reader_; +}; +class OfflineSymbolizationFilter : public FilterBase { +public: + OfflineSymbolizationFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~OfflineSymbolizationFilter() = default; + std::shared_ptr OfflineSymbolization(uint64_t ip); + std::shared_ptr>> OfflineSymbolization( + const std::shared_ptr> ips); + void OfflineSymbolization(const std::set& ips); + +protected: + enum SYSTEM_ENTRY_VALUE { ELF32_SYM = 16, ELF64_SYM = 24 }; + std::map> startAddrToMapsInfoMap_ = {}; + std::unordered_map> filePathIdToSymbolTableMap_ = {}; + std::unordered_map> filePathIdToImportSymbolTableMap_ = {}; + DoubleMap filePathIdAndStValueToSymAddr_; + DoubleMap, uint64_t, const uint8_t*> + symbolTablePtrAndStValueToSymAddr_; + std::map> ipToFrameInfo_ = {}; + std::vector> segs_ = {}; + +private: + template + void UpdateFrameInfo(T* elfSym, uint32_t& symbolStart, uint64_t symVaddr, uint64_t ip, FrameInfo* frameInfo); +}; + +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/filter/perf_data_filter.cpp b/trace_streamer/src/filter/perf_data_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c9d1f24bc4b3c84a521f4c769d940295726ba873 --- /dev/null +++ b/trace_streamer/src/filter/perf_data_filter.cpp @@ -0,0 +1,105 @@ +/* + * 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 "perf_data_filter.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +PerfDataFilter::PerfDataFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter), fileIdToRowInFileTable_(INVALID_UINT64), fileIdToRowInChainTable_(INVALID_UINT64) +{ +} +PerfDataFilter::~PerfDataFilter() = default; + +size_t PerfDataFilter::AppendPerfFiles(uint64_t fileId, uint32_t serial, DataIndex symbols, DataIndex filePath) +{ + fileIds_.emplace(fileId); + auto size = traceDataCache_->GetPerfFilesData()->AppendNewPerfFiles(fileId, serial, symbols, filePath); + fileIdToRowInFileTable_.Insert(fileId, serial, size); + if (!serial) { + fileIdToRow_.insert(std::make_pair(fileId, size)); + } + return size; +} + +size_t PerfDataFilter::AppendPerfCallChain(uint64_t sampleId, + uint32_t callChainId, + uint64_t vaddrInFile, + uint64_t fileId, + uint64_t symbolId) +{ + auto size = traceDataCache_->GetPerfCallChainData()->AppendNewPerfCallChain(sampleId, callChainId, vaddrInFile, + fileId, symbolId); + fileIdToRowInChainTable_.Insert(fileId, symbolId, size); + return size; +} +void PerfDataFilter::BeforeReload() +{ + traceDataCache_->GetPerfCallChainData()->Clear(); + traceDataCache_->GetPerfFilesData()->Clear(); + fileIdToRowInFileTable_.Clear(); + fileIdToRowInChainTable_.Clear(); + fileIds_.clear(); + fileIdToRow_.clear(); +} +void PerfDataFilter::Finish() +{ + auto fileIds = traceDataCache_->GetPerfCallChainData()->FileIds(); + auto symbolsIds = traceDataCache_->GetPerfCallChainData()->SymbolIds(); + auto size = traceDataCache_->GetPerfCallChainData()->Size(); + auto filePath = traceDataCache_->GetPerfFilesData()->FilePaths(); + auto sambols = traceDataCache_->GetPerfFilesData()->Symbols(); + uint64_t flag = 1; + flag = ~(flag << 63); + for (auto i = 0; i < size; i++) { + if (fileIds_.find(fileIds[i]) == fileIds_.end()) { + // When the function name is empty and there is no file information to which the function belongs, + // set the function name to the virtual address of the function in the file + traceDataCache_->GetPerfCallChainData()->SetName( + i, "+0x" + base::number(traceDataCache_->GetPerfCallChainData()->VaddrInFiles()[i] & flag)); + continue; + } + if (symbolsIds[i] == -1) { + // When the function name is empty, if there has the file Id to which the function belongs,but the symboleid + // is -1. Set the function name as "the file name of the function at the top of the callstack + the virtual + // address of this function" + auto pathIndex = filePath[fileIdToRow_.at(fileIds[i])]; + auto fullPath = traceDataCache_->GetDataFromDict(pathIndex); + auto iPos = fullPath.find_last_of('/'); + fullPath = fullPath.substr(iPos + 1, -1); + traceDataCache_->GetPerfCallChainData()->SetName( + i, fullPath + "+0x" + base::number(traceDataCache_->GetPerfCallChainData()->VaddrInFiles()[i] & flag)); + continue; + } + // When the function name is empty, if there has the file Id to which the function belongs,and the symboleid + // is not -1. Set the function name as the virtual address of this function + auto value = fileIdToRowInFileTable_.Find(fileIds[i], symbolsIds[i]); + if (value == INVALID_UINT64) { + traceDataCache_->GetPerfCallChainData()->SetName( + i, "+0x" + base::number(traceDataCache_->GetPerfCallChainData()->VaddrInFiles()[i] & flag)); + continue; + } + // The function name is not empty + traceDataCache_->GetPerfCallChainData()->SetName(i, traceDataCache_->GetDataFromDict(sambols[value])); + } + fileIdToRowInFileTable_.Clear(); + fileIdToRowInChainTable_.Clear(); + fileIds_.clear(); + fileIdToRow_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/perf_data_filter.h b/trace_streamer/src/filter/perf_data_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..d4b0e21df32aacd2d09a2f4078330636441b3180 --- /dev/null +++ b/trace_streamer/src/filter/perf_data_filter.h @@ -0,0 +1,53 @@ +/* + * 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 PERF_DATA_FILTER_H +#define PERF_DATA_FILTER_H +#include +#include +#include +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class PerfDataFilter : private FilterBase { +public: + PerfDataFilter(TraceDataCache*, const TraceStreamerFilters*); + PerfDataFilter(const PerfDataFilter&) = delete; + PerfDataFilter& operator=(const PerfDataFilter&) = delete; + ~PerfDataFilter() override; + +public: + size_t AppendPerfFiles(uint64_t fileId, uint32_t serial, DataIndex symbols, DataIndex filePath); + size_t AppendPerfCallChain(uint64_t sampleId, + uint32_t callChainId, + uint64_t vaddrInFile, + uint64_t fileId, + uint64_t symbolId); + void Finish(); + void BeforeReload(); + +private: + DoubleMap fileIdToRowInFileTable_; + DoubleMap fileIdToRowInChainTable_; + std::set fileIds_; + std::map fileIdToRow_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // PERF_DATA_FILTER_H diff --git a/trace_streamer/src/filter/process_filter.cpp b/trace_streamer/src/filter/process_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33ce2cf2bd148c60a749c9fee021ff6467f9463f --- /dev/null +++ b/trace_streamer/src/filter/process_filter.cpp @@ -0,0 +1,250 @@ +/* + * 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 "process_filter.h" +#include +#include +#include +#include + +using CustomPair = std::pair; +namespace SysTuning { +namespace TraceStreamer { +namespace { +const uint32_t INVALID_ID = std::numeric_limits::max(); +} +ProcessFilter::ProcessFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter) +{ + tidMappingSet_.insert(CustomPair(0, 0)); + pidToInternalPidMap_.insert(CustomPair(0, 0)); +} + +ProcessFilter::~ProcessFilter() {} + +uint32_t ProcessFilter::UpdateOrCreateThreadWithName(uint64_t timeStamp, uint32_t tid, std::string_view name) +{ + DataIndex nameIndex = traceDataCache_->GetDataIndex(name); + return UpdateOrCreateThreadWithNameIndex(timeStamp, tid, nameIndex); +} + +void ProcessFilter::AddProcessMemory(uint32_t ipid) +{ + traceDataCache_->GetProcessData(ipid)->memSize_ = 1; +} + +void ProcessFilter::AddThreadSliceNum(uint32_t itid) +{ + traceDataCache_->GetThreadData(itid)->sliceSize_ = 1; +} +void ProcessFilter::AddProcessSliceNum(uint32_t ipid) +{ + traceDataCache_->GetProcessData(ipid)->sliceSize_ = 1; +} + +void ProcessFilter::AddCpuStateCount(uint32_t itid) +{ + auto thread = traceDataCache_->GetThreadData(itid); + if (thread) { + thread->cpuStatesCount_++; + } +} +uint32_t ProcessFilter::UpdateOrCreateThread(uint64_t timeStamp, uint32_t tid) +{ + return UpdateOrCreateThreadWithNameIndex(timeStamp, tid, 0); +} +uint32_t ProcessFilter::UpdateOrCreateThreadWithPidAndName(uint32_t tid, uint32_t pid, std::string_view name) +{ + uint32_t internalTid = GetOrCreateThreadWithPid(tid, pid); + auto thread = traceDataCache_->GetThreadData(internalTid); + auto nameIndex = traceDataCache_->GetDataIndex(name); + thread->nameIndex_ = nameIndex; + // When the process ID is equal to the thread ID, the process name is also equal to the thread name + if (tid == pid) { + UpdateOrCreateProcessWithName(pid, name); + } + return internalTid; +} + +uint32_t ProcessFilter::GetOrCreateThreadWithPid(uint32_t tid, uint32_t pid) +{ + TraceStdtype::Thread* thread = nullptr; + uint32_t internalTid = INVALID_ID; + if (pid == 0) { + internalTid = GetInternalTid(tid); + } else { + internalTid = GetInternalTid(tid, pid); + } + if (internalTid != INVALID_ID) { + thread = traceDataCache_->GetThreadData(internalTid); + } else { + std::tie(internalTid, thread) = NewThread(tid); + } + + if (thread->internalPid_ == INVALID_UINT32 && pid != 0) { + std::tie(thread->internalPid_, std::ignore) = CreateProcessMaybe(pid, thread->startT_); + } + + return internalTid; +} + +uint32_t ProcessFilter::UpdateOrCreateProcessWithName(uint32_t pid, std::string_view name) +{ + uint32_t internalPid = 0; + TraceStdtype::Process* process = nullptr; + std::tie(internalPid, process) = CreateProcessMaybe(pid, 0); + if (process && process->cmdLine_ != name) { + process->cmdLine_ = std::string(name); + } + // update main thread name + auto internalTid = GetInternalTid(pid, pid); + if (internalTid != INVALID_ID) { + auto thread = traceDataCache_->GetThreadData(internalTid); + thread->nameIndex_ = traceDataCache_->GetDataIndex(name); + } + return internalPid; +} + +uint32_t ProcessFilter::UpdateOrCreateThreadWithNameIndex(uint64_t timeStamp, uint32_t tid, DataIndex threadNameIndex) +{ + TraceStdtype::Thread* thread = nullptr; + uint32_t internalTid = GetInternalTid(tid); + if (internalTid != INVALID_ID) { + if (threadNameIndex) { + thread = traceDataCache_->GetThreadData(internalTid); + if (threadNameIndex != thread->nameIndex_) { + thread->nameIndex_ = threadNameIndex; + } + } + } else { + std::tie(internalTid, thread) = NewThread(tid); + if (threadNameIndex != thread->nameIndex_) { + thread->nameIndex_ = threadNameIndex; + } + if (timeStamp < thread->startT_) { + thread->startT_ = timeStamp; + } + } + return internalTid; +} +uint32_t ProcessFilter::GetInternalTid(uint32_t tid, uint32_t pid) const +{ + uint32_t internalTid = INVALID_ID; + auto tidsPair = tidMappingSet_.equal_range(tid); + for (auto it = tidsPair.first; it != tidsPair.second; it++) { + uint32_t iterItid = it->second; + auto iterThread = traceDataCache_->GetThreadData(iterItid); + if (iterThread->internalPid_ == INVALID_UINT32) { + internalTid = iterItid; + continue; + } + + const auto& iterProcess = traceDataCache_->GetConstProcessData(iterThread->internalPid_); + if (iterProcess.pid_ == pid) { + internalTid = iterItid; + break; + } + } + + return internalTid; +} + +uint32_t ProcessFilter::GetInternalTid(uint32_t tid) const +{ + auto itRange = tidMappingSet_.equal_range(tid); + if (itRange.first != itRange.second) { + auto internalTid = std::prev(itRange.second)->second; + return internalTid; + } + return INVALID_ID; +} + +bool ProcessFilter::isThreadNameEmpty(uint32_t tid) const +{ + auto internalTid = GetInternalTid(tid); + if (internalTid != INVALID_ID) { + auto thread = traceDataCache_->GetThreadData(internalTid); + if (thread->nameIndex_) { + return false; + } + } + return true; +} + +InternalPid ProcessFilter::GetInternalPid(uint32_t pid) const +{ + auto it = pidToInternalPidMap_.find(pid); + if (it != pidToInternalPidMap_.end()) { + return it->second; + } + return INVALID_ID; +} + +InternalPid ProcessFilter::GetOrCreateInternalPid(uint64_t timeStamp, uint32_t pid) +{ + auto ipid = GetInternalPid(pid); + if (ipid != INVALID_ID) { + return ipid; + } + + uint32_t internalPid = 0; + TraceStdtype::Process* process = nullptr; + std::tie(internalPid, process) = CreateProcessMaybe(pid, timeStamp); + return internalPid; +} +std::tuple ProcessFilter::NewThread(uint32_t tid) +{ + uint32_t internalTid = traceDataCache_->NewInternalThread(tid); + tidMappingSet_.emplace(tid, internalTid); + auto thread = traceDataCache_->GetThreadData(internalTid); + + return std::make_tuple(internalTid, thread); +} + +std::tuple ProcessFilter::NewProcess(uint32_t pid) +{ + uint32_t internalPid = traceDataCache_->GetProcessInternalPid(pid); + pidToInternalPidMap_.emplace(pid, internalPid); + auto process = traceDataCache_->GetProcessData(internalPid); + + return std::make_tuple(internalPid, process); +} + +std::tuple ProcessFilter::CreateProcessMaybe(uint32_t pid, uint64_t startT) +{ + uint32_t internalPid = INVALID_ID; + TraceStdtype::Process* process = nullptr; + auto it = pidToInternalPidMap_.find(pid); + if (it != pidToInternalPidMap_.end()) { + internalPid = it->second; + process = traceDataCache_->GetProcessData(internalPid); + } else { + std::tie(internalPid, process) = NewProcess(pid); + void(GetOrCreateThreadWithPid(pid, pid)); + } + + if (process->startT_ == 0) { + process->startT_ = startT; + } + + return std::make_tuple(internalPid, process); +} +void ProcessFilter::Clear() +{ + tidMappingSet_.clear(); + pidToInternalPidMap_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/process_filter.h b/trace_streamer/src/filter/process_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..4c9293ef69cb3def8baec871ab1ba17b8b41187f --- /dev/null +++ b/trace_streamer/src/filter/process_filter.h @@ -0,0 +1,62 @@ +/* + * 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 PROCESS_FILTER_H +#define PROCESS_FILTER_H + +#include + +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class ProcessFilter : private FilterBase { +public: + ProcessFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~ProcessFilter() override; + + uint32_t UpdateOrCreateProcessWithName(uint32_t pid, std::string_view name); + uint32_t UpdateOrCreateThreadWithName(uint64_t timeStamp, uint32_t tid, std::string_view name); + uint32_t UpdateOrCreateThreadWithPidAndName(uint32_t tid, uint32_t pid, std::string_view name); + uint32_t GetOrCreateThreadWithPid(uint32_t tid, uint32_t pid); + uint32_t UpdateOrCreateThread(uint64_t timeStamp, uint32_t tid); + InternalPid GetInternalPid(uint32_t pid) const; + InternalPid GetOrCreateInternalPid(uint64_t timeStamp, uint32_t pid); + bool isThreadNameEmpty(uint32_t tid) const; + InternalTid GetInternalTid(uint32_t tid) const; + uint32_t UpdateOrCreateThreadWithNameIndex(uint64_t timeStamp, uint32_t tid, DataIndex threadNameIndex); + void AddProcessMemory(uint32_t ipid); + void AddThreadSliceNum(uint32_t itid); + void AddCpuStateCount(uint32_t itid); + void AddProcessSliceNum(uint32_t ipid); + void Clear(); + +private: + std::tuple CreateProcessMaybe(uint32_t pid, uint64_t startT); + std::tuple NewThread(uint32_t tid); + std::tuple NewProcess(uint32_t pid); + + InternalTid GetInternalTid(uint32_t tid, uint32_t pid) const; + +private: + std::multimap tidMappingSet_ = {}; + std::map pidToInternalPidMap_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // PROCESS_FILTER_H diff --git a/trace_streamer/src/filter/slice_filter.cpp b/trace_streamer/src/filter/slice_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..932298ccc0605215573a2043fde80c52eae4ee8a --- /dev/null +++ b/trace_streamer/src/filter/slice_filter.cpp @@ -0,0 +1,504 @@ +/* + * 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 "slice_filter.h" +#include +#include +#include + +#include "args_filter.h" +#include "log.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +SliceFilter::SliceFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter), asyncEventMap_(INVALID_UINT64) +{ +} + +SliceFilter::~SliceFilter() = default; + +size_t SliceFilter::BeginSlice(const std::string& comm, + uint64_t timeStamp, + uint32_t pid, + uint32_t threadGroupId, + DataIndex cat, + DataIndex nameIndex) +{ + InternalTid internalTid = INVALID_UTID; + if (threadGroupId > 0) { + internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(pid, threadGroupId, comm); + pidTothreadGroupId_[pid] = threadGroupId; + } else { + internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(timeStamp, pid, comm); + } + // make a SliceData DataItem, {timeStamp, dur, internalTid, cat, nameIndex} + struct SliceData sliceData = {timeStamp, -1, internalTid, cat, nameIndex}; + ArgsSet args; + return StartSlice(timeStamp, pid, cat, nameIndex, args, sliceData); +} + +void SliceFilter::IrqHandlerEntry(uint64_t timeStamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex) +{ + // clear ipi for current cpu and nameIndex + irqDataLinker_.erase(cpu); + struct SliceData sliceData = {timeStamp, 0, cpu, catalog, nameIndex}; + auto slices = traceDataCache_->GetIrqData(); + size_t index = slices->AppendInternalSlice( + sliceData.timeStamp, sliceData.duration, sliceData.internalTid, sliceData.cat, + GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, std::nullopt); + if (irqEventMap_.count(cpu)) { + // not match + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_LOST); + irqEventMap_.at(cpu) = {timeStamp, index}; + } else { + irqEventMap_[cpu] = {timeStamp, index}; + } + return; +} + +void SliceFilter::IrqHandlerExit(uint64_t timeStamp, uint32_t cpu, ArgsSet args) +{ + if (!irqEventMap_.count(cpu)) { + // not match + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_NOTMATCH); + return; + } + uint32_t argSetId = INVALID_UINT32; + auto slices = traceDataCache_->GetIrqData(); + argSetId = streamFilters_->argsFilter_->NewArgs(args); + slices->SetIrqDurAndArg(irqEventMap_.at(cpu).row, timeStamp, argSetId); + auto internalEventRow = irqDataLinker_.find(cpu); + if (internalEventRow != irqDataLinker_.end()) { + slices->SetArgSetId(internalEventRow->second, slices->ArgSetIdsData()[irqEventMap_.at(cpu).row]); + slices->SetDurationEx(irqEventMap_.at(cpu).row, slices->DursData()[internalEventRow->second]); + } else { + slices->SetFlag(irqEventMap_.at(cpu).row, 1); + } + irqDataLinker_.erase(cpu); + irqEventMap_.erase(cpu); + return; +} + +void SliceFilter::IpiHandlerEntry(uint64_t timeStamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex) +{ + irqDataLinker_.erase(cpu); + struct SliceData sliceData = {timeStamp, 0, cpu, catalog, nameIndex}; + auto slices = traceDataCache_->GetIrqData(); + size_t index = slices->AppendInternalSlice( + sliceData.timeStamp, sliceData.duration, sliceData.internalTid, sliceData.cat, + GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, std::nullopt); + if (ipiEventMap_.count(cpu)) { + // not match + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_LOST); + ipiEventMap_.at(cpu) = {timeStamp, index}; + } else { + ipiEventMap_[cpu] = {timeStamp, index}; + } + return; +} +void SliceFilter::IpiHandlerExit(uint64_t timeStamp, uint32_t cpu) +{ + if (!ipiEventMap_.count(cpu)) { + // not match + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST); + return; + } + auto slices = traceDataCache_->GetIrqData(); + slices->SetDurationWithFlag(ipiEventMap_.at(cpu).row, timeStamp); + irqDataLinker_.emplace(cpu, ipiEventMap_.at(cpu).row); + ipiEventMap_.erase(cpu); +} +void SliceFilter::SoftIrqEntry(uint64_t timeStamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex) +{ + struct SliceData sliceData = {timeStamp, 0, cpu, catalog, nameIndex}; + auto slices = traceDataCache_->GetIrqData(); + size_t index = slices->AppendInternalSlice( + sliceData.timeStamp, sliceData.duration, sliceData.internalTid, sliceData.cat, + GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, std::nullopt); + if (softIrqEventMap_.count(cpu)) { + // not match + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_LOST); + softIrqEventMap_.at(cpu) = {timeStamp, index}; + } else { + softIrqEventMap_[cpu] = {timeStamp, index}; + } + return; +} + +void SliceFilter::SoftIrqExit(uint64_t timeStamp, uint32_t cpu, ArgsSet args) +{ + if (!softIrqEventMap_.count(cpu)) { + // not match + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST); + return; + } + uint32_t argSetId = INVALID_UINT32; + auto slices = traceDataCache_->GetIrqData(); + argSetId = streamFilters_->argsFilter_->NewArgs(args); + slices->SetIrqDurAndArg(softIrqEventMap_.at(cpu).row, timeStamp, argSetId); + softIrqEventMap_.erase(cpu); + return; +} + +void SliceFilter::RememberSliceData(InternalTid internalTid, + std::unordered_map& stackMap, + SliceData& slice, + uint32_t depth, + uint64_t index) +{ + if (stackMap.find(internalTid) == stackMap.end()) { + auto& sliceStack = stackMap[internalTid].sliceStack; // this can be a empty call, but it does not matter + slice.depth = depth; + slice.index = index; + sliceStack.push_back(slice); + } else { + auto& sliceStack = stackMap.at(internalTid).sliceStack; // this can be a empty call, but it does not matter + slice.depth = depth; + slice.index = index; + sliceStack.push_back(slice); + } +} +size_t SliceFilter::AsyncBinder(uint64_t timeStamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet& args) +{ + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timeStamp, pid); + struct SliceData sliceData = {timeStamp, 0, internalTid, cat, nameIndex}; + return StartSlice(timeStamp, pid, cat, nameIndex, args, std::move(sliceData)); +} +uint8_t SliceFilter::CurrentDepth(InternalTid internalTid) +{ + if (depthHolder_.find(internalTid) == depthHolder_.end()) { + return 0; + } + auto& depthMap = depthHolder_.at(internalTid); + auto depthSize = depthMap.size(); + for (int32_t i = depthSize - 1; i >= 0; i--) { + if (depthMap.at(i)) { + return i; + } + } + return 0; +} +uint8_t SliceFilter::UpdateDepth(bool increase, InternalTid internalTid, int32_t depth) +{ + if (increase) { + if (depthHolder_.find(internalTid) == depthHolder_.end()) { + StackOnDepth tmp; + tmp.insert(std::make_pair(0, true)); + depthHolder_.insert(std::make_pair(internalTid, tmp)); + return 0; + } + auto& depthMap = depthHolder_.at(internalTid); + auto depthSize = depthMap.size(); + auto lastIndex = 0; + for (int32_t i = depthSize - 1; i >= 0; i--) { + if (depthMap.at(i) && (i == depthSize - 1)) { + depthMap.insert(std::make_pair(depthSize, true)); + return depthSize; + } + if (depthMap.at(i)) { + break; + } + lastIndex = i; + } + + if (!depthMap.at(lastIndex)) { + depthMap.at(lastIndex) = true; + return lastIndex; + } + } else { + if (depthHolder_.find(internalTid) == depthHolder_.end()) { + TS_LOGE("internalTid not found"); + return 0; + } + auto& depthMap = depthHolder_.at(internalTid); + if (depthMap.find(depth) == depthMap.end()) { + return 0; + } + depthMap.at(depth) = false; + } + return depth; +} + +void SliceFilter::CloseUnMatchedSlice(int64_t ts, SlicesStack& stack, InternalTid itid) +{ + auto slices = traceDataCache_->GetInternalSlicesData(); + bool incomplete = false; + for (int32_t i = stack.size() - 1; i >= 0; i--) { + uint32_t sliceIdx = stack[i].index; + int64_t startTs = slices->TimeStampData()[sliceIdx]; + int64_t dur = slices->DursData()[sliceIdx]; + int64_t endTs = startTs + dur; + if (dur == -1) { + incomplete = true; + continue; + } + if (incomplete) { + if (ts <= endTs) { + continue; + } + for (int32_t j = stack.size() - 1; j > i; --j) { + uint32_t childIdx = stack[i].index; + slices->SetDur(childIdx, endTs - slices->TimeStampData()[childIdx]); + stack.pop_back(); + } + stack.pop_back(); + incomplete = false; + continue; + } + if (endTs <= ts) { + stack.pop_back(); + } + } +} + +int32_t SliceFilter::MatchingIncompleteSliceIndex(const SlicesStack& stack, DataIndex category, DataIndex name) +{ + auto slices = traceDataCache_->GetInternalSlicesData(); + for (int32_t i = stack.size() - 1; i >= 0; i--) { + uint32_t sliceIdx = stack[i].index; + if (slices->DursData()[sliceIdx] != -1) { + continue; + } + const DataIndex& categoryLast = slices->CatsData()[sliceIdx]; + if (category != INVALID_UINT64 && (categoryLast != INVALID_UINT64 && category != categoryLast)) { + continue; + } + const DataIndex& nameLast = slices->NamesData()[sliceIdx]; + if (name != INVALID_UINT64 && nameLast != INVALID_UINT64 && name != nameLast) { + continue; + } + return static_cast(i); + } + return -1; +} +size_t SliceFilter::StartSlice(uint64_t timeStamp, + uint32_t pid, + DataIndex cat, + DataIndex nameIndex, + ArgsSet& args, + SliceData sliceData) +{ + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timeStamp, pid); + auto& sliceStack = binderStackMap_[internalTid]; + auto& stack = sliceStack.sliceStack; + if (sliceStack.isAsyncEvent) { + sliceStack.asyncEventCount++; + sliceStack.asyncEventLastBeginTs = timeStamp; + if (!stack.empty()) { + return SIZE_MAX; + } + } + // keep slice of thread + CloseUnMatchedSlice(timeStamp, stack, internalTid); + uint32_t depth = stack.size(); + auto slices = traceDataCache_->GetInternalSlicesData(); + uint32_t parentId = depth == 0 ? INVALID_UINT32 : slices->IdsData()[stack.back().index]; + size_t index = slices->AppendInternalSlice( + sliceData.timeStamp, sliceData.duration, sliceData.internalTid, sliceData.cat, + GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(sliceData.name)), sliceData.name, 0, parentId); + if (depth >= std::numeric_limits::max()) { + return SIZE_MAX; + } + slices->SetDepth(index, depth); + + uint32_t argSetId = INVALID_UINT32; + if (args.valuesMap_.size()) { + if (args.inserted_) { + argSetId = args.argSetId_; + } else { + argSetId = streamFilters_->argsFilter_->NewArgs(args); + sliceRowToArgsSetId_[index] = argSetId; + argsSetIdToSliceRow_[argSetId] = static_cast(index); + args.argSetId_ = argSetId; + args.inserted_ = true; + } + // set ArgSetId here + slices->SetArgSetId(index, argSetId); + } + sliceData.argSetId = argSetId; + RememberSliceData(sliceData.internalTid, binderStackMap_, sliceData, depth, index); + return index; +} +size_t SliceFilter::BeginBinder(uint64_t timeStamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet args) +{ + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timeStamp, pid); + struct SliceData sliceData = {timeStamp, -1, internalTid, cat, nameIndex}; + return StartSlice(timeStamp, pid, cat, nameIndex, args, std::move(sliceData)); +} + +size_t SliceFilter::CompleteSlice(uint64_t timeStamp, uint32_t pid, DataIndex category, DataIndex name, ArgsSet args) +{ + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timeStamp, pid); + if (binderStackMap_.find(internalTid) == binderStackMap_.end()) { + return SIZE_MAX; + } + auto& stackInfo = binderStackMap_[internalTid]; + SlicesStack& stack = stackInfo.sliceStack; + CloseUnMatchedSlice(timeStamp, stack, internalTid); + if (stack.empty()) { + TS_LOGE("a slice end do not match a slice start event"); + callEventDisMatchCount++; + return SIZE_MAX; + } + auto stackIdx = MatchingIncompleteSliceIndex(stack, category, name); + if (stackIdx < 0) { + TS_LOGE("MatchingIncompleteSliceIndex failed"); + return SIZE_MAX; + } + auto lastRow = stack[stackIdx].index; + auto slices = traceDataCache_->GetInternalSlicesData(); + slices->SetDuration(lastRow, timeStamp); + + auto argSize = sliceRowToArgsSetId_.count(lastRow); + size_t argSetId = 0; + if (args.valuesMap_.size()) { + if (!argSize) { + argSetId = streamFilters_->argsFilter_->NewArgs(args); + sliceRowToArgsSetId_[lastRow] = argSetId; + slices->SetArgSetId(lastRow, argSetId); + } else { + argSetId = sliceRowToArgsSetId_.at(lastRow); + } + streamFilters_->argsFilter_->AppendArgs(args, argSetId); + } + if (stackInfo.isAsyncEvent) { + ArgsSet args; + args.AppendArg(asyncBeginCountId_, BASE_DATA_TYPE_INT, stackInfo.asyncEventCount); + args.AppendArg(asyncBeginTsId_, BASE_DATA_TYPE_INT, stackInfo.asyncEventLastBeginTs); + if (!argSetId) { + argSetId = streamFilters_->argsFilter_->NewArgs(args); + sliceRowToArgsSetId_[lastRow] = argSetId; + slices->SetArgSetId(lastRow, argSetId); + } else { + streamFilters_->argsFilter_->AppendArgs(args, argSetId); + } + } + if (stackIdx == stack.size() - 1) { + stack.pop_back(); + } + streamFilters_->processFilter_->AddThreadSliceNum(internalTid); + return lastRow; +} +size_t SliceFilter::EndBinder(uint64_t timeStamp, uint32_t pid, DataIndex category, DataIndex name, ArgsSet args) +{ + return CompleteSlice(timeStamp, pid, category, name, args); +} +std::tuple SliceFilter::AddArgs(uint32_t tid, DataIndex key1, DataIndex key2, ArgsSet& args) +{ + InternalTid internalTid = streamFilters_->processFilter_->GetInternalTid(tid); + if (binderStackMap_.find(internalTid) == binderStackMap_.end()) { + return std::make_tuple(INVALID_UINT32, INVALID_UINT32); + } + auto& stack = binderStackMap_[internalTid]; + auto idx = MatchingIncompleteSliceIndex(stack.sliceStack, key1, key2); + if (idx < 0) { + return std::make_tuple(INVALID_UINT32, INVALID_UINT32); + } + uint32_t argSetId = stack.sliceStack[idx].argSetId; + if (argSetId == INVALID_UINT32) { + argSetId = streamFilters_->argsFilter_->NewArgs(args); + sliceRowToArgsSetId_[stack.sliceStack[idx].index] = argSetId; + stack.sliceStack[idx].argSetId = argSetId; + } else { + streamFilters_->argsFilter_->AppendArgs(args, argSetId); + } + return std::make_tuple(stack.sliceStack[idx].index, argSetId); +} +uint64_t SliceFilter::StartAsyncSlice(uint64_t timeStamp, + uint32_t pid, + uint32_t threadGroupId, + uint64_t cookie, + DataIndex nameIndex) +{ + UNUSED(pid); + InternalPid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timeStamp, threadGroupId); + + auto lastFilterId = asyncEventMap_.Find(internalTid, cookie, nameIndex); + auto slices = traceDataCache_->GetInternalSlicesData(); + if (lastFilterId != INVALID_UINT64) { + asyncEventDisMatchCount++; + return INVALID_UINT64; + } + asyncEventSize_++; + // a pid, cookie and function name determain a callstack + asyncEventMap_.Insert(internalTid, cookie, nameIndex, asyncEventSize_); + // the IDE need a depth to paint call slice in different position of the canvas, the depth of async call + // do not mean the parent-to-child relationship, it is different from no-async call + uint8_t depth = 0; + size_t index = slices->AppendInternalAsyncSlice(timeStamp, -1, internalTid, INVALID_UINT64, + GetNameASCIISumNoNum(traceDataCache_->GetDataFromDict(nameIndex)), + nameIndex, depth, cookie, std::nullopt); + asyncEventFilterMap_.insert(std::make_pair(asyncEventSize_, AsyncEvent{timeStamp, index})); + return index; +} + +uint64_t SliceFilter::FinishAsyncSlice(uint64_t timeStamp, + uint32_t pid, + uint32_t threadGroupId, + uint64_t cookie, + DataIndex nameIndex) +{ + UNUSED(pid); + InternalPid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timeStamp, threadGroupId); + auto lastFilterId = asyncEventMap_.Find(internalTid, cookie, nameIndex); + auto slices = traceDataCache_->GetInternalSlicesData(); + if (lastFilterId == INVALID_UINT64) { // if failed + asyncEventDisMatchCount++; + return INVALID_UINT64; + } + if (asyncEventFilterMap_.find(lastFilterId) == asyncEventFilterMap_.end()) { + TS_LOGE("logic error"); + asyncEventDisMatchCount++; + return INVALID_UINT64; + } + // update timeStamp + asyncEventFilterMap_.at(lastFilterId).timeStamp = timeStamp; + auto lastRow = asyncEventFilterMap_.at(lastFilterId).row; + slices->SetDuration(asyncEventFilterMap_.at(lastFilterId).row, timeStamp); + asyncEventFilterMap_.erase(lastFilterId); + asyncEventMap_.Erase(internalTid, cookie, nameIndex); + streamFilters_->processFilter_->AddThreadSliceNum(internalTid); + return lastRow; +} + +size_t + SliceFilter::EndSlice(uint64_t timeStamp, uint32_t pid, uint32_t threadGroupId, DataIndex category, DataIndex name) +{ + return CompleteSlice(timeStamp, pid, category, name); +} + +void SliceFilter::Clear() +{ + asyncEventMap_.Clear(); + asyncNoEndingEventMap_.clear(); + irqEventMap_.clear(); + softIrqEventMap_.clear(); + asyncEventFilterMap_.clear(); + sliceStackMap_.clear(); + depthHolder_.clear(); + sliceRowToArgsSetId_.clear(); + argsSetIdToSliceRow_.clear(); + argsSetIdToSliceRow_.clear(); + argsSet_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/slice_filter.h b/trace_streamer/src/filter/slice_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..e3b29c8f275bf5a93227ed4d84b94f3071343ffc --- /dev/null +++ b/trace_streamer/src/filter/slice_filter.h @@ -0,0 +1,154 @@ +/* + * 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 SLICE_FILTER_H +#define SLICE_FILTER_H + +#include +#include +#include "args_set.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "triple_map.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +struct SliceData { + uint64_t timeStamp; + int32_t duration; + InternalTid internalTid; + DataIndex cat; + DataIndex name; + uint32_t depth; + uint64_t index; + uint32_t argSetId; +}; +struct AsyncEvent { + uint64_t timeStamp; + size_t row; +}; +class SliceFilter : private FilterBase { +public: + SliceFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~SliceFilter() override; + + size_t BeginSlice(const std::string& comm, + uint64_t timeStamp, + uint32_t pid, + uint32_t threadGroupId, + DataIndex cat, + DataIndex nameIndex); + size_t BeginBinder(uint64_t timeStamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet args = ArgsSet()); + size_t StartSlice(uint64_t timeStamp, + uint32_t pid, + DataIndex cat, + DataIndex nameIndex, + ArgsSet& args, + SliceData sliceData = SliceData()); + size_t AsyncBinder(uint64_t timeStamp, uint32_t pid, DataIndex cat, DataIndex nameIndex, ArgsSet& args); + size_t EndBinder(uint64_t timeStamp, + uint32_t pid, + DataIndex category = INVALID_UINT64, + DataIndex name = INVALID_UINT64, + ArgsSet args = {}); + size_t CompleteSlice(uint64_t timeStamp, + uint32_t pid, + DataIndex category = INVALID_UINT64, + DataIndex name = INVALID_UINT64, + ArgsSet args = {}); + size_t EndSlice(uint64_t timeStamp, + uint32_t pid, + uint32_t threadGroupId, + DataIndex category = INVALID_UINT64, + DataIndex name = INVALID_UINT64); + uint64_t + StartAsyncSlice(uint64_t timeStamp, uint32_t pid, uint32_t threadGroupId, uint64_t cookie, DataIndex nameIndex); + uint64_t FinishAsyncSlice(uint64_t timeStamp, + uint32_t pid, + uint32_t threadGroupId, + uint64_t cookie, + DataIndex nameIndex); + void IrqHandlerEntry(uint64_t timeStamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex); + std::tuple AddArgs(uint32_t tid, DataIndex key1, DataIndex key2, ArgsSet& args); + void IrqHandlerExit(uint64_t timeStamp, uint32_t cpu, ArgsSet args); + void IpiHandlerEntry(uint64_t timeStamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex); + void IpiHandlerExit(uint64_t timeStamp, uint32_t cpu); + void SoftIrqEntry(uint64_t timeStamp, uint32_t cpu, DataIndex catalog, DataIndex nameIndex); + void SoftIrqExit(uint64_t timeStamp, uint32_t cpu, ArgsSet args); + void Clear(); + +private: + struct StackInfo { + bool isAsyncEvent = false; + uint32_t asyncEventCount = 0; + uint32_t asyncEventLastBeginTs = 0; + std::vector sliceStack; + }; + using SlicesStack = std::vector; + using StackOfSlices = StackInfo; + using StackOnDepth = std::map; + // uint64_t GenHashByStack(const StackOfSlices& sliceStack) const; + // bool BeginSliceInternal(const SliceData& sliceData); + void RememberSliceData(InternalTid internalTid, + std::unordered_map& stackMap, + SliceData& slice, + uint32_t depth, + uint64_t index); + uint8_t UpdateDepth(bool increase, InternalTid internalTid, int32_t depth = -1); + void CloseUnMatchedSlice(int64_t ts, SlicesStack& stack, InternalTid itid); + int32_t MatchingIncompleteSliceIndex(const SlicesStack& stack, DataIndex category, DataIndex name); + uint8_t CurrentDepth(InternalTid internalTid); + +private: + // The parameter list is tid, cookid, functionName, asyncCallId. + TripleMap asyncEventMap_; + // this is only used to calc the layer of the async event in same time range + std::map asyncNoEndingEventMap_ = {}; + // irq map, key1 is cpu, key2 + struct IrqRecords { + uint64_t ts; + size_t row; + }; + std::unordered_map irqEventMap_ = {}; + std::unordered_map ipiEventMap_ = {}; + // irq map, key1 is cpu, key2 + std::unordered_map softIrqEventMap_ = {}; + std::map asyncEventFilterMap_ = {}; + std::unordered_map sliceStackMap_ = {}; + std::unordered_map& binderStackMap_ = sliceStackMap_; + std::unordered_map depthHolder_ = {}; + std::unordered_map pidTothreadGroupId_ = {}; + uint64_t asyncEventSize_ = 0; + uint64_t asyncEventDisMatchCount = 0; + uint64_t callEventDisMatchCount = 0; + std::unordered_map sliceRowToArgsSetId_ = {}; + std::unordered_map argsSetIdToSliceRow_ = {}; + std::unordered_map tidToArgsSetId_ = {}; + struct SliceInfo { + uint32_t row; + ArgsSet args_tracker; + }; + std::unordered_map> argsSet_ = {}; + DataIndex asyncBeginCountId_ = traceDataCache_->GetDataIndex("legacy_unnestable_begin_count"); + DataIndex asyncBeginTsId_ = traceDataCache_->GetDataIndex("legacy_unnestable_last_begin_ts"); + DataIndex ipiId_ = traceDataCache_->GetDataIndex("IPI"); + std::map irqDataLinker_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SLICE_FILTER_H diff --git a/trace_streamer/src/filter/stat_filter.cpp b/trace_streamer/src/filter/stat_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8afbb22e3818797d5c594cffd6ee6911e8df555b --- /dev/null +++ b/trace_streamer/src/filter/stat_filter.cpp @@ -0,0 +1,32 @@ +/* + * 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 "stat_filter.h" +#include "filter_filter.h" +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +StatFilter::StatFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) : FilterBase(dataCache, filter) {} + +StatFilter::~StatFilter() {} + +void StatFilter::IncreaseStat(SupportedTraceEventType eventType, StatType type) +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(eventType, type); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/stat_filter.h b/trace_streamer/src/filter/stat_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..2f05116ea1df454df17944c133aae3a25bfa48af --- /dev/null +++ b/trace_streamer/src/filter/stat_filter.h @@ -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. + */ + +#ifndef STAT_FILTER_H +#define STAT_FILTER_H + +#include +#include +#include + +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::TraceCfg; +class StatFilter : private FilterBase { +public: + StatFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + StatFilter(const StatFilter&) = delete; + StatFilter& operator=(const StatFilter&) = delete; + ~StatFilter() override; + void IncreaseStat(SupportedTraceEventType eventType, StatType type); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // THREAD_MEASURE_FILTER_H diff --git a/trace_streamer/src/filter/symbols_filter.cpp b/trace_streamer/src/filter/symbols_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba9497b4d5d3dc1b7ea562478832db1cdf73d0a7 --- /dev/null +++ b/trace_streamer/src/filter/symbols_filter.cpp @@ -0,0 +1,61 @@ +/* + * 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 "symbols_filter.h" +#include +#include +#include + +#include "log.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +SymbolsFilter::SymbolsFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter) +{ +} + +SymbolsFilter::~SymbolsFilter() = default; +void SymbolsFilter::RegisterFunc(uint64_t addr, DataIndex funcNameDictIndex) +{ + if (symbolsMap_.find(addr) == symbolsMap_.end()) { + symbolsMap_.insert(std::make_pair(addr, funcNameDictIndex)); + traceDataCache_->GetSymbolsData()->InsertSymbol(funcNameDictIndex, addr); + } else { + symbolsMap_.at(addr) = funcNameDictIndex; + } +} + +const DataIndex& SymbolsFilter::GetFunc(uint64_t addr) const +{ + if (symbolsMap_.find(addr) == symbolsMap_.end()) { + auto lastAddr = symbolsMap_.lower_bound(addr); + if (lastAddr == symbolsMap_.end()) { + return INVALID_UINT64; + } + return lastAddr->second; + } else { + return symbolsMap_.at(addr); + } +} +void SymbolsFilter::Clear() +{ + symbolsMap_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/symbols_filter.h b/trace_streamer/src/filter/symbols_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..3d9a4524208c6d106728cf78509c07500e60ead7 --- /dev/null +++ b/trace_streamer/src/filter/symbols_filter.h @@ -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. + */ + +#ifndef SYMBOLS_FILTER_H +#define SYMBOLS_FILTER_H + +#include +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class SymbolsFilter : private FilterBase { +public: + SymbolsFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~SymbolsFilter() override; + + void RegisterFunc(uint64_t addr, DataIndex funcNameDictIndex); + + const DataIndex& GetFunc(uint64_t addr) const; + void Clear(); + +private: + std::map symbolsMap_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SLICE_FILTER_H diff --git a/trace_streamer/src/filter/system_event_measure_filter.cpp b/trace_streamer/src/filter/system_event_measure_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad055e191f560b86ee802cf6bc7e49c4d9c7835e --- /dev/null +++ b/trace_streamer/src/filter/system_event_measure_filter.cpp @@ -0,0 +1,82 @@ +/* + * 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 "system_event_measure_filter.h" +#include "filter_filter.h" +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +SystemEventMeasureFilter::SystemEventMeasureFilter(TraceDataCache* dataCache, + const TraceStreamerFilters* filter, + SysEventType e) + : FilterBase(dataCache, filter), filterType_(e) +{ +} + +SystemEventMeasureFilter::~SystemEventMeasureFilter() {} + +void SystemEventMeasureFilter::AppendNewMeasureData(DataIndex nameIndex, uint64_t timeStamp, int64_t value) +{ + auto filterId = GetOrCreateFilterId(nameIndex); + auto row = traceDataCache_->GetSysMemMeasureData()->AppendMeasureData(0, timeStamp, value, filterId); + // if the filterId ever exists + if (filterIdToRow_.count(filterId)) { + traceDataCache_->GetSysMemMeasureData()->SetDur(filterIdToRow_.at(filterId), timeStamp); + filterIdToRow_.at(filterId) = row; + } else { + filterIdToRow_.insert(std::make_pair(filterId, row)); + } +} +uint32_t SystemEventMeasureFilter::AppendNewMeasureFilter(DataIndex nameIndex) +{ + return GetOrCreateFilterId(nameIndex); +} +uint32_t SystemEventMeasureFilter::GetOrCreateFilterId(DataIndex nameIndex) +{ + auto filterId = tidStreamIdFilterIdMap_.find(nameIndex); + if (filterId != tidStreamIdFilterIdMap_.end()) { + return static_cast((tidStreamIdFilterIdMap_.at(nameIndex))); + } + + uint32_t newFilterId = streamFilters_->filterFilter_->AddFilter( + filterTypeValue.at(filterType_), traceDataCache_->GetDataFromDict(nameIndex), INVALID_UINT64); + AddCertainFilterId(nameIndex, newFilterId); + return newFilterId; +} + +void SystemEventMeasureFilter::AddCertainFilterId(DataIndex nameIndex, uint64_t filterId) +{ + tidStreamIdFilterIdMap_.insert(std::make_pair(nameIndex, filterId)); + + if (filterType_ == E_SYS_MEMORY_FILTER) { + traceDataCache_->GetSysMeasureFilterData()->AppendNewFilter(filterId, sysMemoryFilterId_, + static_cast(nameIndex)); + } else if (filterType_ == E_SYS_VIRTUAL_MEMORY_FILTER) { + traceDataCache_->GetSysMeasureFilterData()->AppendNewFilter(filterId, sysVMemoryFilterId_, + static_cast(nameIndex)); + } else if (filterType_ == E_SYS_EVENT_SOURCE_FILTER) { + traceDataCache_->GetSysMeasureFilterData()->AppendNewFilter(filterId, sysEventSourceFilterId_, + static_cast(nameIndex)); + } +} + +void SystemEventMeasureFilter::Clear() +{ + tidStreamIdFilterIdMap_.clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/filter/system_event_measure_filter.h b/trace_streamer/src/filter/system_event_measure_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..f6d31fd63dffd1bc81f95d3c3e8c41c3d06e6e84 --- /dev/null +++ b/trace_streamer/src/filter/system_event_measure_filter.h @@ -0,0 +1,59 @@ +/* + * 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 SYS_EVENT_MEASURE_FILTER_H +#define SYS_EVENT_MEASURE_FILTER_H + +#include +#include +#include + +#include "double_map.h" +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +enum SysEventType { E_SYS_MEMORY_FILTER, E_SYS_VIRTUAL_MEMORY_FILTER, E_SYS_EVENT_SOURCE_FILTER }; + +class SystemEventMeasureFilter : private FilterBase { +public: + SystemEventMeasureFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter, SysEventType); + SystemEventMeasureFilter(const SystemEventMeasureFilter&) = delete; + SystemEventMeasureFilter& operator=(const SystemEventMeasureFilter&) = delete; + ~SystemEventMeasureFilter() override; + void AppendNewMeasureData(DataIndex nameIndex, uint64_t timeStamp, int64_t value); + uint32_t AppendNewMeasureFilter(DataIndex nameIndex); + void Clear(); + +private: + uint32_t GetOrCreateFilterId(DataIndex nameIndex); + void AddCertainFilterId(DataIndex nameIndex, uint64_t filterId); + std::map tidStreamIdFilterIdMap_ = {}; + SysEventType filterType_; + + const std::map filterTypeValue = { + {E_SYS_MEMORY_FILTER, "sys_memory_filter"}, + {E_SYS_VIRTUAL_MEMORY_FILTER, "sys_virtual_memory_filter"}, + {E_SYS_EVENT_SOURCE_FILTER, "sys_event_source_filter"}}; + const DataIndex sysMemoryFilterId_ = traceDataCache_->GetDataIndex("sys_memory_filter"); + const DataIndex sysVMemoryFilterId_ = traceDataCache_->GetDataIndex("sys_virtual_memory_filter"); + const DataIndex sysEventSourceFilterId_ = traceDataCache_->GetDataIndex("sys_event_source_filter"); + std::map filterIdToRow_ = {}; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SYS_EVENT_MEASURE_FILTER_H diff --git a/trace_streamer/src/include/BUILD.gn b/trace_streamer/src/include/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..3b7d9c903fc0017794050afb7addb53806a8a262 --- /dev/null +++ b/trace_streamer/src/include/BUILD.gn @@ -0,0 +1,29 @@ +# 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") +ohos_source_set("ibase") { + subsystem_name = "trace_streamer" + part_name = "ibase" + sources = [ + "codec_cov.h", + "file.h", + "log.h", + "numerical_to_string.h", + "parting_string.h", + "string_to_numerical.h", + ] + include_dirs = [] + public_deps = [] + deps = [] + sources += [ "/usr/x86_64-w64-mingw32/include/windows.h" ] +} diff --git a/trace_streamer/src/include/codec_cov.h b/trace_streamer/src/include/codec_cov.h new file mode 100644 index 0000000000000000000000000000000000000000..9ad79f115b69f9b2171a51266e3d50c5bd998ef0 --- /dev/null +++ b/trace_streamer/src/include/codec_cov.h @@ -0,0 +1,39 @@ +/* + * 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 INCLUDE_TUNING_BASE_CODEC_COV_H_ +#define INCLUDE_TUNING_BASE_CODEC_COV_H_ + +#include + +namespace SysTuning { +namespace base { +int32_t PreNum(unsigned char byte); + +bool IsUTF8(const uint8_t* data, int32_t len); + +bool IsGBK(const uint8_t* data, int32_t len); + +typedef enum { GBK, UTF8, UNKOWN } CODING; + +CODING GetCoding(const uint8_t* data, int32_t len); + +#ifdef _WIN32 +std::string GbkToUtf8(const char* srcStr); +#endif +} // namespace base +} // namespace SysTuning + +#endif diff --git a/trace_streamer/src/include/file.h b/trace_streamer/src/include/file.h new file mode 100644 index 0000000000000000000000000000000000000000..a1516952c939a468e35c70b4969e4c347fdb76d0 --- /dev/null +++ b/trace_streamer/src/include/file.h @@ -0,0 +1,44 @@ +/* + * 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 INCLUDE_TUNING_BASE_FILE_UTILS_H_ +#define INCLUDE_TUNING_BASE_FILE_UTILS_H_ + +#include + +namespace SysTuning { +namespace base { +#define TS_PERMISSION_RW 0600 +#define TS_PERMISSION_RWX 777 +constexpr uint32_t kFileModeInvalid = 0xFFFFFFFF; +enum TraceParserStatus { + TRACE_PARSER_NORMAL = 0, + TRACE_PARSER_FILE_TYPE_ERROR = 1, + TRACE_PARSE_ERROR = 2, + TRACE_PARSER_ABNORMAL = 3 +}; + +void SetAnalysisResult(TraceParserStatus stat); + +TraceParserStatus GetAnalysisResult(); + +ssize_t Read(int32_t fd, uint8_t* dst, size_t dstSize); + +int32_t OpenFile(const std::string& path, int32_t flags, uint32_t mode = kFileModeInvalid); + +std::string GetExecutionDirectoryPath(); +} // namespace base +} // namespace SysTuning +#endif // INCLUDE_TUNING_BASE_FILE_UTILS_H_ diff --git a/trace_streamer/src/include/log.h b/trace_streamer/src/include/log.h new file mode 100644 index 0000000000000000000000000000000000000000..dc766cbe155e38da3cd032ac6ff54e2867e147b6 --- /dev/null +++ b/trace_streamer/src/include/log.h @@ -0,0 +1,66 @@ +/* + * 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 INCLUDE_TS_BASE_LOGGING_H_ +#define INCLUDE_TS_BASE_LOGGING_H_ + +#include +#include + +// namespace SysTuning { +// namespace base { +#define TS_CRASH \ + do { \ + __builtin_trap(); \ + __builtin_unreachable(); \ + } while (0) +enum LogLevel { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR, LOG_FATAL }; +const enum LogLevel g_currentLogLevel = LOG_DEBUG; +extern bool g_cleanMode; +#define LOGWITHLEVEL(level, motify, fmt, ...) \ + do { \ + if (level >= g_currentLogLevel) { \ + if (!g_cleanMode) { \ + fprintf(stdout, "[-%c][%s][%d]: " fmt "\n", motify, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + } \ + if (level == LOG_FATAL) { \ + TS_CRASH; \ + } \ + } \ + } while (0) +#define TS_LOGE(fmt, ...) LOGWITHLEVEL(LOG_ERROR, 'E', fmt, ##__VA_ARGS__) +#define TS_LOGF(fmt, ...) LOGWITHLEVEL(LOG_FATAL, 'F', fmt, ##__VA_ARGS__) +#ifdef NDEBUG +#define TS_LOGI(fmt, ...) LOGWITHLEVEL(LOG_DEBUG, 'I', fmt, ##__VA_ARGS__) +#define TS_LOGD(format, ...) +#define TS_ASSERT(x) +#define TS_LOGW(fmt, ...) LOGWITHLEVEL(LOG_WARN, 'W', fmt, ##__VA_ARGS__) +#else +#define TS_LOGD(fmt, ...) LOGWITHLEVEL(LOG_DEBUG, 'D', fmt, ##__VA_ARGS__) +#define TS_LOGI(fmt, ...) LOGWITHLEVEL(LOG_DEBUG, 'I', fmt, ##__VA_ARGS__) +#define TS_LOGW(fmt, ...) LOGWITHLEVEL(LOG_WARN, 'W', fmt, ##__VA_ARGS__) + +#define TS_ASSERT(x) \ + do { \ + if (!(x)) { \ + TS_CRASH; \ + } \ + } while (0) + +#endif +// } // namespace base +// } // namespace SysTuning + +#endif // INCLUDE_TS_BASE_LOGGING_H_ diff --git a/trace_streamer/src/include/numerical_to_string.h b/trace_streamer/src/include/numerical_to_string.h new file mode 100644 index 0000000000000000000000000000000000000000..e019d789b27e8a9e4c10ecf6b84ccc2625723b53 --- /dev/null +++ b/trace_streamer/src/include/numerical_to_string.h @@ -0,0 +1,35 @@ +/* + * 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 INCLUDE_BASE_NUMERICAL_TO_STRING_H_ +#define INCLUDE_BASE_NUMERICAL_TO_STRING_H_ +#include +#include "string_to_numerical.h" +#include "ts_common.h" + +namespace SysTuning { +namespace base { +// Put uint_ 64 type numbers are converted to hexadecimal numbers and expressed as strings. +inline std::string Uint64ToHexText(uint64_t inputNumber) +{ + if (inputNumber == INVALID_UINT64) { + return ""; + } + std::string str = "0x" + base::number(inputNumber, base::INTEGER_RADIX_TYPE_HEX); + return str; +} +} // namespace base +} // namespace SysTuning + +#endif // INCLUDE_BASE_NUMERICAL_TO_STRING_H_ diff --git a/trace_streamer/src/include/parting_string.h b/trace_streamer/src/include/parting_string.h new file mode 100644 index 0000000000000000000000000000000000000000..91a56bfc587a54edb7c261442e7aafe6f128d4ae --- /dev/null +++ b/trace_streamer/src/include/parting_string.h @@ -0,0 +1,47 @@ +/* + * 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 INCLUDE_BASE_STRING_SPLITTER_H_ +#define INCLUDE_BASE_STRING_SPLITTER_H_ + +#include + +namespace SysTuning { +namespace base { +class PartingString { +public: + PartingString(std::string, char delimiter); + + bool Next(); + + char* GetCur() + { + return cur_; + } + +private: + PartingString(const PartingString&) = delete; + PartingString& operator=(const PartingString&) = delete; + + std::string str_; + char* cur_ = nullptr; + std::string::iterator begin_; + std::string::iterator end_; + const char delimiter_; +}; +} // namespace base +} // namespace SysTuning + +#endif diff --git a/trace_streamer/src/include/string_to_numerical.h b/trace_streamer/src/include/string_to_numerical.h new file mode 100644 index 0000000000000000000000000000000000000000..d932233f1f9ee1ed3492a7aa4d1712ae76de090e --- /dev/null +++ b/trace_streamer/src/include/string_to_numerical.h @@ -0,0 +1,114 @@ +/* + * 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 INCLUDE_BASE_STRING_TO_NUMERICAL_H_ +#define INCLUDE_BASE_STRING_TO_NUMERICAL_H_ + +#include +#include +#include +#include + +namespace SysTuning { +namespace base { +enum IntegerRadixType { INTEGER_RADIX_TYPE_DEC = 10, INTEGER_RADIX_TYPE_HEX = 16 }; +inline uint16_t GetNameASCIISumNoNum(const std::string& str) +{ + uint32_t sum = 0; + int32_t len = str.length() - 1; + while (len >= 0) { + sum += std::isdigit(str.at(len)) ? 0 : str.at(len); + len--; + } + return sum % INTEGER_RADIX_TYPE_HEX; +} +inline std::optional StrToUInt32(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtoul(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::string number(uint64_t value, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + std::stringstream ss; + if (base == INTEGER_RADIX_TYPE_DEC) { + ss << std::dec << value; + } else if (base == INTEGER_RADIX_TYPE_HEX) { + ss << std::hex << value; + } + return ss.str(); +} + +inline std::optional StrToInt32(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtol(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::optional StrToUInt64(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + auto value = static_cast(std::strtoull(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + + return std::nullopt; +} + +inline std::optional StrToInt64(const std::string& str, int32_t base = INTEGER_RADIX_TYPE_DEC) +{ + if (!str.empty()) { + char* endPtr = nullptr; + int64_t value = static_cast(std::strtoll(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } + } + return std::nullopt; +} +inline std::optional StrToDouble(const std::string& str) +{ + if (!str.empty()) { +#ifdef WIN32_ + char* end = nullptr; + double value = std::strtod(str.c_str(), &end); +#else + double value = std::stod(str); +#endif + return std::make_optional(value); + } + return std::nullopt; +} +} // namespace base +} // namespace SysTuning + +#endif // INCLUDE_TUNING_EXT_BASE_STRING_UTILS_H_ diff --git a/trace_streamer/src/main.cpp b/trace_streamer/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36f018495d08510b5b2e0a0baa5ed442ca53aa2e --- /dev/null +++ b/trace_streamer/src/main.cpp @@ -0,0 +1,304 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "codec_cov.h" +#include "file.h" +#include "filter/slice_filter.h" +#include "http_server.h" +#include "log.h" +#include "meta.h" +#include "parser/bytrace_parser/bytrace_event_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parting_string.h" +#include "rpc_server.h" + +#include "thread_state.h" +#include "trace_streamer/trace_streamer_selector.h" +#include "trace_streamer_filters.h" +using namespace SysTuning::TraceStreamer; +using namespace SysTuning; +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::base; +constexpr size_t G_CHUNK_SIZE = 1024 * 1024; +constexpr int G_MIN_PARAM_NUM = 2; +constexpr size_t G_FILE_PERMISSION = 664; +// set version info in meta.cpp please +void ExportStatusToLog(const std::string& dbPath, TraceParserStatus status) +{ + std::string path = dbPath + ".ohos.ts"; + std::ofstream out(path, std::ios_base::trunc); + out << (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) + .count() + << ":" << status << std::endl; + using std::chrono::system_clock; + + system_clock::time_point today = system_clock::now(); + + std::time_t tt = system_clock::to_time_t(today); + out << "last running time is: " << ctime(&tt); + out << "last running status is: " << status; + out.close(); +} +void ShowHelpInfo(const char* argv) +{ + TS_LOGI( + "trace analyze tool, it can transfer a bytrace/htrace file into a " + "SQLite database and save result to a local file trace_streamer.log.\n" + "Usage: %s FILE -e sqlite_out.pb\n" + " or %s FILE -c\n" + "Options:\n" + " -e transfer a bytrace file into a SQLiteBased DB. with -nm to except meta table\n" + " -c command line mode.\n" + " -h start HTTP server.\n" + " -s separate js memory data, and save it in current dir with default filename.\n" + " -p Specify the port of HTTP server, default is 9001.\n" + " -i show information.\n" + " -v show version.", + argv, argv); +} +void PrintInformation() +{ + TraceStreamerConfig cfg; + cfg.PrintInfo(); +} +void PrintVersion() +{ + fprintf(stderr, "version %s\n", TRACE_STREAM_VERSION.c_str()); +} + +bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector& ta, int fd) +{ + auto startTime = + (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) + .count(); + g_loadSize = 0; + while (true) { + std::unique_ptr buf = std::make_unique(G_CHUNK_SIZE); + auto rsize = Read(fd, buf.get(), G_CHUNK_SIZE); + if (rsize == 0) { + break; + } + + if (rsize < 0) { + TS_LOGE("Reading trace file failed (errno: %d, %s)", errno, strerror(errno)); + return false; + } + g_loadSize += rsize; + if (!ta.ParseTraceDataSegment(std::move(buf), static_cast(rsize))) { + return false; + }; + printf("\rLoadingFile:\t%.2f MB\r", static_cast(g_loadSize) / 1E6); + } + ta.WaitForParserEnd(); + auto endTime = + (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) + .count(); + (void)fprintf(stdout, "\nParserDuration:\t%u ms\n", static_cast(endTime - startTime)); + (void)fprintf(stdout, "ParserSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime) / 1E3)); + return true; +} +int OpenAndParserFile(TraceStreamerSelector& ts, const std::string& traceFilePath) +{ + int fd(OpenFile(traceFilePath, O_RDONLY, G_FILE_PERMISSION)); + if (fd < 0) { + TS_LOGE("%s does not exist", traceFilePath.c_str()); + SetAnalysisResult(TRACE_PARSER_ABNORMAL); + return 1; + } + if (!ReadAndParser(ts, fd)) { + close(fd); + SetAnalysisResult(TRACE_PARSER_ABNORMAL); + return 1; + } + MetaData* metaData = ts.GetMetaData(); + + std::string fileNameTmp = traceFilePath; +#ifdef _WIN32 + if (!base::GetCoding(reinterpret_cast(fileNameTmp.c_str()), fileNameTmp.length())) { + fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str()); + } +#endif + metaData->SetSourceFileName(fileNameTmp); + metaData->SetTraceType((ts.DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace"); + + close(fd); + return 0; +} +int ExportDatabase(TraceStreamerSelector& ts, const std::string& sqliteFilePath) +{ + auto startTime = + (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) + .count(); + if (!sqliteFilePath.empty()) { + MetaData* metaData = ts.GetMetaData(); + std::string fileNameTmp = sqliteFilePath; +#ifdef _WIN32 + if (!base::GetCoding(reinterpret_cast(fileNameTmp.c_str()), fileNameTmp.length())) { + fileNameTmp = base::GbkToUtf8(fileNameTmp.c_str()); + } +#endif + metaData->SetOutputFileName(fileNameTmp); + metaData->SetParserToolVersion(TRACE_STREAM_VERSION); + metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION); + metaData->SetTraceDataSize(g_loadSize); + fprintf(stdout, "ExportDatabase begin...\n"); + if (ts.ExportDatabase(sqliteFilePath)) { + fprintf(stdout, "ExportDatabase failed\n"); + ExportStatusToLog(sqliteFilePath, TRACE_PARSER_ABNORMAL); + return 1; + } + fprintf(stdout, "ExportDatabase end\n"); + } + auto endTime = + (std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch())) + .count(); + endTime += 1; // for any exception of endTime == startTime + fprintf(stdout, "ExportDuration:\t%u ms\n", static_cast(endTime - startTime)); + fprintf(stdout, "ExportSpeed:\t%.2f MB/s\n", (g_loadSize / (endTime - startTime)) / 1E3); + return 0; +} + +struct TraceExportOption { + std::string traceFilePath; + std::string sqliteFilePath; + bool interactiveState = false; + bool exportMetaTable = true; + bool separateFile = false; +}; +struct HttpOption { + bool enable = false; + int port = 9001; +}; + +int CheckArgs(int argc, char** argv, TraceExportOption& traceExportOption, HttpOption& httpOption) +{ + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-e")) { + i++; + if (i == argc) { + ShowHelpInfo(argv[0]); + return 1; + } + traceExportOption.sqliteFilePath = std::string(argv[i]); + continue; + } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) { + traceExportOption.interactiveState = true; + continue; + } else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) { + PrintInformation(); + } else if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--s")) { + traceExportOption.separateFile = true; + continue; + } else if (!strcmp(argv[i], "-nm") || !strcmp(argv[i], "--nometa")) { + traceExportOption.exportMetaTable = false; + continue; + } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--v") || !strcmp(argv[i], "-version") || + !strcmp(argv[i], "--version")) { + PrintVersion(); + return 1; + } else if (!strcmp(argv[i], "-h")) { + httpOption.enable = true; + continue; + } else if (!strcmp(argv[i], "-p")) { + if (++i == argc) { + ShowHelpInfo(argv[0]); + return 1; + } + httpOption.port = std::stoi(argv[i]); + continue; + } + traceExportOption.traceFilePath = std::string(argv[i]); + } + if ((traceExportOption.traceFilePath.empty() || + (!traceExportOption.interactiveState && traceExportOption.sqliteFilePath.empty())) && + !httpOption.enable && !traceExportOption.separateFile) { + ShowHelpInfo(argv[0]); + return 1; + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning +int main(int argc, char** argv) +{ + if (argc < G_MIN_PARAM_NUM) { + ShowHelpInfo(argv[0]); + return 1; + } + TraceExportOption tsOption; + HttpOption httpOption; + int ret = CheckArgs(argc, argv, tsOption, httpOption); + if (ret) { + if (!tsOption.sqliteFilePath.empty()) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); + } + return 0; + } + + if (httpOption.enable) { + RpcServer rpcServer; + HttpServer httpServer; + httpServer.RegisterRpcFunction(&rpcServer); + httpServer.Run(httpOption.port); + return 0; + } + TraceStreamerSelector ts; + ts.EnableMetaTable(tsOption.exportMetaTable); + ts.EnableFileSave(tsOption.separateFile); + if (OpenAndParserFile(ts, tsOption.traceFilePath)) { + if (!tsOption.sqliteFilePath.empty()) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); + } + return 1; + } + if (tsOption.interactiveState) { + MetaData* metaData = ts.GetMetaData(); + metaData->SetOutputFileName("command line mode"); + metaData->SetParserToolVersion(TRACE_STREAM_VERSION.c_str()); + metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION.c_str()); + metaData->SetTraceDataSize(g_loadSize); + while (1) { + auto values = ts.SearchData(); + std::string symbolsPath = "default"; + if (!values.empty()) { + ts.ReloadSymbolFiles(symbolsPath, values); + } else { + return 0; + } + } + } + if (!tsOption.sqliteFilePath.empty()) { + if (ExportDatabase(ts, tsOption.sqliteFilePath)) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); + return 1; + } + if (!tsOption.sqliteFilePath.empty()) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); + } + } + return 0; +} diff --git a/trace_streamer/src/parser/BUILD.gn b/trace_streamer/src/parser/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..43a2477d7d3e1afaeebb08c02a021bd2512f559b --- /dev/null +++ b/trace_streamer/src/parser/BUILD.gn @@ -0,0 +1,87 @@ +# 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("//src/ts.gni") + +ohos_source_set("parser") { + subsystem_name = "trace_streamer" + part_name = "parser" + sources = [ + "bytrace_parser/bytrace_event_parser.cpp", + "bytrace_parser/bytrace_event_parser.h", + "bytrace_parser/bytrace_parser.cpp", + "bytrace_parser/bytrace_parser.h", + "common_types.h", + "event_parser_base.cpp", + "event_parser_base.h", + "print_event_parser.cpp", + "print_event_parser.h", + "thread_state.cpp", + "thread_state.h", + ] + deps = [ "ebpf_parser:ebpf_parser" ] + if (is_pbdecoder) { + deps += [ "htrace_parser:htrace_parser" ] + } else { + deps += [ "htrace_pbreader_parser:htrace_pbreader_parser" ] + } + include_dirs = [ + "//third_party/protobuf/src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "${OHOS_PROTO_GEN}/types/plugins/", + "${OHOS_PROTO_GEN}", + "//third_party/sqlite/include", + "//src/base", + "//src/cfg", + "//src/trace_streamer", + "//src/trace_data", + "//src/include", + "//src/filter", + "//src", + ".", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + ] + if (is_pbdecoder) { + include_dirs += [ "htrace_parser" ] + } else { + include_dirs += [ "htrace_pbreader_parser" ] + include_dirs += [ "../proto_reader/include" ] + } + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp b/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..135c6a8c3b94381fe02eec2b2c546551af420a41 --- /dev/null +++ b/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp @@ -0,0 +1,785 @@ +/* + * 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_event_parser.h" +#include "binder_filter.h" +#include "cpu_filter.h" +#include "filter_filter.h" +#include "irq_filter.h" +#include "measure_filter.h" +#include "parting_string.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" +#include "thread_state.h" +#include "ts_common.h" +namespace SysTuning { +namespace TraceStreamer { +namespace { +std::string GetFunctionName(const std::string_view& text, const std::string_view& delimiter) +{ + std::string str(""); + if (delimiter.empty()) { + return str; + } + + std::size_t foundIndex = text.find(delimiter); + if (foundIndex != std::string::npos) { + std::size_t funIndex = foundIndex + delimiter.size(); + str = std::string(text.substr(funIndex, text.size() - funIndex)); + } + return str; +} +} // namespace + +BytraceEventParser::BytraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : EventParserBase(dataCache, filter), printEventParser_(traceDataCache_, streamFilters_) +{ + printEventParser_.SetTraceType(TRACE_FILETYPE_BY_TRACE); + eventToFunctionMap_ = { + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_SWITCH), + bind(&BytraceEventParser::SchedSwitchEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_BLOCKED_REASON), + bind(&BytraceEventParser::BlockedReason, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_TASK_RENAME), + bind(&BytraceEventParser::TaskRenameEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_TASK_NEWTASK), + bind(&BytraceEventParser::TaskNewtaskEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_TRACING_MARK_WRITE), + bind(&BytraceEventParser::TracingMarkWriteOrPrintEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_PRINT), + bind(&BytraceEventParser::TracingMarkWriteOrPrintEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP), + bind(&BytraceEventParser::SchedWakeupEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKING), + bind(&BytraceEventParser::SchedWakingEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_IDLE), + bind(&BytraceEventParser::CpuIdleEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY), + bind(&BytraceEventParser::CpuFrequencyEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY_LIMITS), + bind(&BytraceEventParser::CpuFrequencyLimitsEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_START), + bind(&BytraceEventParser::WorkqueueExecuteStartEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_END), + bind(&BytraceEventParser::WorkqueueExecuteEndEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_SET_RATE), + bind(&BytraceEventParser::SetRateEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_ENABLE), + bind(&BytraceEventParser::ClockEnableEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_DISABLE), + bind(&BytraceEventParser::ClockDisableEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_SET_VOLTAGE), + bind(&BytraceEventParser::RegulatorSetVoltageEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE), + bind(&BytraceEventParser::RegulatorSetVoltageCompleteEvent, this, std::placeholders::_1, + std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_DISABLE), + bind(&BytraceEventParser::RegulatorDisableEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_REGULATOR_DISABLE_COMPLETE), + bind(&BytraceEventParser::RegulatorDisableCompleteEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_IPI_ENTRY), + bind(&BytraceEventParser::IpiEntryEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_IPI_EXIT), + bind(&BytraceEventParser::IpiExitEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_ENTRY), + bind(&BytraceEventParser::IrqHandlerEntryEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_EXIT), + bind(&BytraceEventParser::IrqHandlerExitEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_RAISE), + bind(&BytraceEventParser::SoftIrqRaiseEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_ENTRY), + bind(&BytraceEventParser::SoftIrqEntryEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_EXIT), + bind(&BytraceEventParser::SoftIrqExitEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION), + bind(&BytraceEventParser::BinderTransaction, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED), + bind(&BytraceEventParser::BinderTransactionReceived, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF), + bind(&BytraceEventParser::BinderTransactionAllocBufEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP_NEW), + bind(&BytraceEventParser::SchedWakeupEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_PROCESS_EXIT), + bind(&BytraceEventParser::ProcessExitEvent, this, std::placeholders::_1, std::placeholders::_2)}}; +} + +bool BytraceEventParser::SchedSwitchEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_SCHED_SWITCH_ARGS_COUNT) { + TS_LOGD("Failed to parse sched_switch event, no args or args size < 6"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID); + return false; + } + auto prevCommStr = std::string_view(args.at("prev_comm")); + auto nextCommStr = std::string_view(args.at("next_comm")); + auto prevPrioValue = base::StrToInt32(args.at("prev_prio")); + auto nextPrioValue = base::StrToInt32(args.at("next_prio")); + auto prevPidValue = base::StrToUInt32(args.at("prev_pid")); + auto nextPidValue = base::StrToUInt32(args.at("next_pid")); + DataIndex nextInfo = INVALID_DATAINDEX; + auto nextInfoIt = args.find("next_info"); + if (nextInfoIt != args.end()) { + nextInfo = traceDataCache_->GetDataIndex(std::string_view(args.at("next_info"))); + } + if (!(prevPidValue.has_value() && prevPrioValue.has_value() && nextPidValue.has_value() && + nextPrioValue.has_value())) { + TS_LOGD("Failed to parse sched_switch event"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID); + return false; + } + auto prevStateStr = args.at("prev_state"); + auto threadState = ThreadState(prevStateStr.c_str()); + uint64_t prevState = threadState.State(); + if (!threadState.IsValid()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID); + } + uint32_t nextInternalTid = 0; + uint32_t uprevtid = 0; + nextInternalTid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, nextPidValue.value(), nextCommStr); + + if (!prevCommStr.empty()) { + uprevtid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, prevPidValue.value(), prevCommStr); + } else { + uprevtid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, prevPidValue.value()); + } + streamFilters_->cpuFilter_->InsertSwitchEvent( + line.ts, line.cpu, uprevtid, static_cast(prevPrioValue.value()), prevState, nextInternalTid, + static_cast(nextPrioValue.value()), nextInfo); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_RECEIVED); + return true; +} +bool BytraceEventParser::BlockedReason(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_BLOCKED_REASON_ARGS_COUNT) { + TS_LOGD("Failed to parse blocked_reason event, no args or args size < %d", MIN_BLOCKED_REASON_ARGS_COUNT); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_DATA_INVALID); + return false; + } + auto tid = base::StrToInt32(args.at("pid")); + auto iowaitIt = args.find("iowait"); + if (iowaitIt == args.end()) { + iowaitIt = args.find("io_wait"); + } + auto iowait = base::StrToInt32(iowaitIt->second); + uint32_t delayValue = INVALID_UINT32; + if (args.find("delay") != args.end()) { + auto delay = base::StrToInt32(args.at("delay")); + delayValue = delay.has_value() ? delay.value() : INVALID_UINT32; + } + auto caller = traceDataCache_->GetDataIndex(std::string_view(args.at("caller"))); + if (!(tid.has_value() && iowait.has_value())) { + TS_LOGD("Failed to parse blocked_reason event"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_DATA_INVALID); + return false; + } + auto iTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, tid.value()); + + if (streamFilters_->cpuFilter_->InsertBlockedReasonEvent(line.ts, line.cpu, iTid, iowait.value(), caller, + delayValue)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_RECEIVED); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_NOTMATCH); + } + return true; +} + +bool BytraceEventParser::TaskRenameEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_TASK_RENAME_ARGS_COUNT) { + TS_LOGD("Failed to parse task_rename event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_RENAME, STAT_EVENT_DATA_INVALID); + return false; + } + auto prevCommStr = std::string_view(args.at("newcomm")); + auto pidValue = base::StrToUInt32(args.at("pid")); + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, pidValue.value(), prevCommStr); + return true; +} + +bool BytraceEventParser::TaskNewtaskEvent(const ArgsMap& args, const BytraceLine& line) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_RECEIVED); + // the clone flag from txt trace from kernel original is HEX, but when it is converted from proto + // based trace, it will be OCT number, it is not stable, so we decide to ignore it + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_NOTSUPPORTED); + return true; +} + +bool BytraceEventParser::TracingMarkWriteOrPrintEvent(const ArgsMap& args, const BytraceLine& line) +{ + UNUSED(args); + return printEventParser_.ParsePrintEvent(line.task, line.ts, line.pid, line.argsStr.c_str(), line); +} +// prefer to use waking, unless no waking, can use wakeup +bool BytraceEventParser::SchedWakeupEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.size() < MIN_SCHED_WAKEUP_ARGS_COUNT) { + TS_LOGD("Failed to parse SchedWakeupEvent event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID); + return false; + } + std::optional wakePidValue = base::StrToUInt32(args.at("pid")); + if (!wakePidValue.has_value()) { + TS_LOGD("Failed to convert wake_pid"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID); + return false; + } + auto instants = traceDataCache_->GetInstantsData(); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, wakePidValue.value_or(0)); + streamFilters_->cpuFilter_->InsertWakeupEvent(line.ts, internalTid); + + InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, line.pid); + + instants->AppendInstantEventData(line.ts, schedWakeupName_, internalTid, wakeupFromPid); + std::optional targetCpu = base::StrToUInt32(args.at("target_cpu")); + if (targetCpu.has_value()) { + traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKEUP, targetCpu.value(), wakeupFromPid); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_RECEIVED); + } + return true; +} + +bool BytraceEventParser::SchedWakingEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_SCHED_WAKING_ARGS_COUNT) { + TS_LOGD("Failed to parse sched_waking event, no args or args size < 4"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID); + return false; + } + std::optional wakePidValue = base::StrToUInt32(args.at("pid")); + if (!wakePidValue.has_value()) { + TS_LOGD("Failed to convert wake_pid"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID); + return false; + } + auto instants = traceDataCache_->GetInstantsData(); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, wakePidValue.value()); + DataIndex wakeByPidStrIndex = traceDataCache_->GetDataIndex(line.task); + InternalTid internalTidWakeup = + streamFilters_->processFilter_->UpdateOrCreateThreadWithNameIndex(line.ts, line.pid, wakeByPidStrIndex); + InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, line.pid); + streamFilters_->cpuFilter_->InsertWakeupEvent(line.ts, internalTid, true); + instants->AppendInstantEventData(line.ts, schedWakingName_, internalTid, wakeupFromPid); + std::optional targetCpu = base::StrToUInt32(args.at("target_cpu")); + if (targetCpu.has_value()) { + traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKING, targetCpu.value(), + internalTidWakeup); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_RECEIVED); + } + + return true; +} + +bool BytraceEventParser::CpuIdleEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_CPU_IDLE_ARGS_COUNT) { + TS_LOGD("Failed to parse cpu_idle event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + std::optional eventCpuValue = base::StrToUInt32(args.at("cpu_id")); + std::optional newStateValue = base::StrToInt64(args.at("state")); + if (!eventCpuValue.has_value()) { + TS_LOGD("Failed to convert event cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + if (!newStateValue.has_value()) { + TS_LOGD("Failed to convert state"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + // Add cpu_idle event to raw_data_table + auto cpuidleNameIndex = traceDataCache_->GetDataIndex(line.eventName.c_str()); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuidleNameIndex, line.ts, + config_.GetStateValue(newStateValue.value())); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_RECEIVED); + return true; +} + +bool BytraceEventParser::CpuFrequencyEvent(const ArgsMap& args, const BytraceLine& line) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_RECEIVED); + if (args.empty() || args.size() < MIN_CPU_FREQUENCY_ARGS_COUNT) { + TS_LOGD("Failed to parse cpu_frequency event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + std::optional eventCpuValue = base::StrToUInt32(args.at("cpu_id")); + std::optional newStateValue = base::StrToInt64(args.at("state")); + + if (!newStateValue.has_value()) { + TS_LOGD("Failed to convert state"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + if (!eventCpuValue.has_value()) { + TS_LOGD("Failed to convert event cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + + auto cpuidleNameIndex = traceDataCache_->GetDataIndex(line.eventName.c_str()); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuidleNameIndex, line.ts, + newStateValue.value()); + return true; +} +bool BytraceEventParser::CpuFrequencyLimitsEvent(const ArgsMap& args, const BytraceLine& line) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_RECEIVED); + if (args.empty() || args.size() < MIN_CPU_FREQUENCY_ARGS_COUNT) { + TS_LOGD("Failed to parse cpu_frequency event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID); + return false; + } + std::optional eventCpuValue = base::StrToUInt32(args.at("cpu_id")); + + auto minIt = args.find("min"); + if (minIt == args.end()) { + minIt = args.find("min_freq"); + } + auto maxIt = args.find("max"); + if (maxIt == args.end()) { + maxIt = args.find("max_freq"); + } + std::optional minValue = base::StrToInt64(minIt->second); + std::optional maxValue = base::StrToInt64(maxIt->second); + + if (!minValue.has_value()) { + TS_LOGD("Failed to get frequency minValue"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID); + return false; + } + if (!maxValue.has_value()) { + TS_LOGD("Failed to get frequency maxValue"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID); + return false; + } + if (!eventCpuValue.has_value()) { + TS_LOGD("Failed to get frequency cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_DATA_INVALID); + return false; + } + + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuFrequencyLimitMaxNameId, line.ts, + maxValue.value()); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuFrequencyLimitMinNameId, line.ts, + minValue.value()); + return true; +} + +bool BytraceEventParser::WorkqueueExecuteStartEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + auto splitStr = GetFunctionName(line.argsStr, "function "); + auto splitStrIndex = traceDataCache_->GetDataIndex(splitStr); + size_t result = + streamFilters_->sliceFilter_->BeginSlice(line.task, line.ts, line.pid, 0, workQueueId_, splitStrIndex); + traceDataCache_->GetInternalSlicesData()->AppendDistributeInfo(); + if (result != INVALID_UINT32) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_START, STAT_EVENT_RECEIVED); + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_START, STAT_EVENT_DATA_LOST); + return false; + } +} + +bool BytraceEventParser::WorkqueueExecuteEndEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + if (streamFilters_->sliceFilter_->EndSlice(line.ts, line.pid, 0, workQueueId_)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_RECEIVED); + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_NOTMATCH); + return false; + } +} + +bool BytraceEventParser::ProcessExitEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_PROCESS_EXIT_ARGS_COUNT) { + TS_LOGD("Failed to parse process_exit event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } + auto comm = std::string_view(args.at("comm")); + auto pid = base::StrToUInt32(args.at("pid")); + if (!pid.has_value()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } + auto itid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, pid.value(), comm); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_RECEIVED); + if (streamFilters_->cpuFilter_->InsertProcessExitEvent(line.ts, line.cpu, itid)) { + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_NOTMATCH); + return false; + } +} + +bool BytraceEventParser::SetRateEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_CLOCK_SET_RATE_ARGS_COUNT) { + TS_LOGD("Failed to parse clock_set_rate event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_DATA_INVALID); + return false; + } + auto name = std::string_view(args.at("name")); + auto state = base::StrToInt64(args.at("state")); + auto cpu = base::StrToUInt64(args.at("cpu_id")); + DataIndex nameIndex = traceDataCache_->GetDataIndex(name); + streamFilters_->clockRateFilter_->AppendNewMeasureData(cpu.value(), nameIndex, line.ts, state.value()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_RECEIVED); + return true; +} + +bool BytraceEventParser::ClockEnableEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_CLOCK_ENABLE_ARGS_COUNT) { + TS_LOGD("Failed to parse clock_enable event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_DATA_INVALID); + return false; + } + auto name = std::string_view(args.at("name")); + auto state = base::StrToInt64(args.at("state")); + auto cpuId = base::StrToUInt64(args.at("cpu_id")); + DataIndex nameIndex = traceDataCache_->GetDataIndex(name); + streamFilters_->clockEnableFilter_->AppendNewMeasureData(cpuId.value(), nameIndex, line.ts, state.value()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_RECEIVED); + return true; +} +bool BytraceEventParser::ClockDisableEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_CLOCK_DISABLE_ARGS_COUNT) { + TS_LOGD("Failed to parse clock_disable event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_DATA_INVALID); + return false; + } + auto name = std::string_view(args.at("name")); + auto state = base::StrToInt64(args.at("state")); + auto cpuId = base::StrToUInt64(args.at("cpu_id")); + DataIndex nameIndex = traceDataCache_->GetDataIndex(name); + streamFilters_->clockDisableFilter_->AppendNewMeasureData(cpuId.value(), nameIndex, line.ts, state.value()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_RECEIVED); + return true; +} + +bool BytraceEventParser::RegulatorSetVoltageEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + UNUSED(line); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool BytraceEventParser::RegulatorSetVoltageCompleteEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + UNUSED(line); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_SET_VOLTAGE_COMPLETE, + STAT_EVENT_NOTSUPPORTED); + return true; +} +bool BytraceEventParser::RegulatorDisableEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + UNUSED(line); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool BytraceEventParser::RegulatorDisableCompleteEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + UNUSED(line); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_REGULATOR_DISABLE_COMPLETE, STAT_EVENT_NOTSUPPORTED); + return true; +} + +bool BytraceEventParser::IpiEntryEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_ENTRY, STAT_EVENT_RECEIVED); + streamFilters_->irqFilter_->IpiHandlerEntry(line.ts, line.cpu, traceDataCache_->GetDataIndex(line.argsStr)); + return true; +} +bool BytraceEventParser::IpiExitEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_EXIT, STAT_EVENT_RECEIVED); + streamFilters_->irqFilter_->IpiHandlerExit(line.ts, line.cpu); + return true; +} +bool BytraceEventParser::IrqHandlerEntryEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_IRQ_HANDLER_ENTRY_ARGS_COUNT) { + TS_LOGD("Failed to parse irq_handler_entry event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_INVALID); + return false; + } + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_RECEIVED); + auto name = std::string_view(args.at("name")); + streamFilters_->irqFilter_->IrqHandlerEntry(line.ts, line.cpu, traceDataCache_->GetDataIndex(name)); + return true; +} +bool BytraceEventParser::IrqHandlerExitEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_IRQ_HANDLER_EXIT_ARGS_COUNT) { + TS_LOGD("Failed to parse irq_handler_exit event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_RECEIVED); + uint32_t ret = (args.at("ret") == "handled") ? 1 : 0; + auto irq = base::StrToUInt32(args.at("irq")); + streamFilters_->irqFilter_->IrqHandlerExit(line.ts, line.cpu, irq.value(), ret); + return true; +} +bool BytraceEventParser::SoftIrqRaiseEvent(const ArgsMap& args, const BytraceLine& line) const +{ + UNUSED(args); + UNUSED(line); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool BytraceEventParser::SoftIrqEntryEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_SOFTIRQ_ENTRY_ARGS_COUNT) { + TS_LOGD("Failed to parse softirq_entry event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_INVALID); + return false; + } + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_RECEIVED); + auto vec = base::StrToUInt32(args.at("vec")); + streamFilters_->irqFilter_->SoftIrqEntry(line.ts, line.cpu, vec.value()); + return true; +} +bool BytraceEventParser::SoftIrqExitEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_SOFTIRQ_EXIT_ARGS_COUNT) { + TS_LOGD("Failed to parse softirq_exit event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_RECEIVED); + auto vec = base::StrToUInt32(args.at("vec")); + streamFilters_->irqFilter_->SoftIrqExit(line.ts, line.cpu, vec.value()); + return true; +} + +bool BytraceEventParser::BinderTransaction(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_ARGS_COUNT) { + TS_LOGD("Failed to parse binder_transaction event, no args or args size < 7"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_DATA_INVALID); + return false; + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_RECEIVED); + auto transactionId = base::StrToInt64(args.at("transaction")); + auto destNode = base::StrToUInt32(args.at("dest_node")); + auto destProc = base::StrToUInt32(args.at("dest_proc")); + auto destThread = base::StrToUInt32(args.at("dest_thread")); + auto isReply = base::StrToUInt32(args.at("reply")); + auto flags = base::StrToUInt32(args.at("flags"), base::INTEGER_RADIX_TYPE_HEX); + auto codeStr = base::StrToUInt32(args.at("code"), base::INTEGER_RADIX_TYPE_HEX); + TS_LOGD("ts:%lu, pid:%u, destNode:%u, destTgid:%u, destTid:%u, transactionId:%lu, isReply:%u flags:%u, code:%u", + line.ts, line.pid, destNode.value(), destProc.value(), destThread.value(), transactionId.value(), + isReply.value(), flags.value(), codeStr.value()); + streamFilters_->binderFilter_->SendTraction(line.ts, line.pid, transactionId.value(), destNode.value(), + destProc.value(), destThread.value(), isReply.value(), flags.value(), + codeStr.value()); + return true; +} +bool BytraceEventParser::BinderTransactionReceived(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_RECEIVED_ARGS_COUNT) { + TS_LOGD("Failed to parse binder_transaction_received event, no args or args size < 1"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_DATA_INVALID); + return false; + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_RECEIVED); + auto transactionId = base::StrToInt64(args.at("transaction")); + streamFilters_->binderFilter_->ReceiveTraction(line.ts, line.pid, transactionId.value()); + TS_LOGD("ts:%lu, pid:%u, transactionId:%lu", line.ts, line.pid, transactionId.value()); + return true; +} +bool BytraceEventParser::BinderTransactionAllocBufEvent(const ArgsMap& args, const BytraceLine& line) const +{ + if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_ALLOC_BUF_ARGS_COUNT) { + TS_LOGD("Failed to parse binder_transaction_alloc_buf event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_DATA_INVALID); + return false; + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_RECEIVED); + auto dataSize = base::StrToUInt64(args.at("data_size")); + auto offsetsSize = base::StrToUInt64(args.at("offsets_size")); + streamFilters_->binderFilter_->TransactionAllocBuf(line.ts, line.pid, dataSize.value(), offsetsSize.value()); + TS_LOGD("dataSize:%lu, offsetSize:%lu", dataSize.value(), offsetsSize.value()); + return true; +} +void BytraceEventParser::ParseDataItem(const BytraceLine& line) +{ + eventList_.push_back(std::move(std::make_unique(line.ts, std::move(line)))); + return; +} +void BytraceEventParser::GetDataSegArgs(BytraceLine& bufLine, ArgsMap& args, uint32_t& tgid) const +{ + if (bufLine.tGidStr.size() && bufLine.tGidStr.at(0) != '-') { + tgid = base::StrToUInt32(bufLine.tGidStr).value_or(0); + } else { + tgid = 0; + } + bufLine.tgid = tgid; + + for (base::PartingString ss(bufLine.argsStr, ' '); ss.Next();) { + std::string key; + std::string value; + if (!(std::string(ss.GetCur()).find("=") != std::string::npos)) { + key = "name"; + value = ss.GetCur(); + args.emplace(std::move(key), std::move(value)); + continue; + } + for (base::PartingString inner(ss.GetCur(), '='); inner.Next();) { + if (key.empty()) { + key = inner.GetCur(); + } else { + value = inner.GetCur(); + } + } + args.emplace(std::move(key), std::move(value)); + } +} +void BytraceEventParser::FilterAllEventsTemp() +{ + size_t maxBuffSize = 1000 * 1000; + size_t maxQueue = 2; + if (eventList_.size() < maxBuffSize * maxQueue) { + return; + } + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimestamp < b->eventTimestamp; + }; +#ifdef IS_WASM + std::sort(eventList_.begin(), eventList_.end(), cmp); +#else + std::stable_sort(eventList_.begin(), eventList_.end(), cmp); +#endif + auto endOfList = eventList_.begin() + maxBuffSize; + for (auto itor = eventList_.begin(); itor != endOfList; itor++) { + EventInfo* event = itor->get(); + auto it = eventToFunctionMap_.find(event->line.eventName); + if (it != eventToFunctionMap_.end()) { + uint32_t tgid; + ArgsMap args; + GetDataSegArgs(event->line, args, tgid); + if (tgid) { + streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(event->line.pid, tgid, + event->line.task); + } else { + // When tgid is zero, only use tid create thread + streamFilters_->processFilter_->GetOrCreateThreadWithPid(event->line.pid, tgid); + } + if (it->second(args, event->line)) { + traceDataCache_->UpdateTraceTime(event->line.ts); + } + } else { + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED); + TS_LOGD("UnRecognizable event name:%s", event->line.eventName.c_str()); + } + itor->reset(); + } + eventList_.erase(eventList_.begin(), endOfList); +} + +void BytraceEventParser::FilterAllEvents() +{ + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimestamp < b->eventTimestamp; + }; +#ifdef IS_WASM + std::sort(eventList_.begin(), eventList_.end(), cmp); +#else + std::stable_sort(eventList_.begin(), eventList_.end(), cmp); +#endif + size_t maxBuffSize = 1000 * 1000; + while (eventList_.size()) { + int32_t size = std::min(maxBuffSize, eventList_.size()); + auto endOfList = eventList_.begin() + size; + for (auto itor = eventList_.begin(); itor != endOfList; itor++) { + EventInfo* event = itor->get(); + BeginFilterEvents(event); + itor->reset(); + } + eventList_.erase(eventList_.begin(), endOfList); + } + eventList_.clear(); + streamFilters_->cpuFilter_->Finish(); + traceDataCache_->dataDict_.Finish(); + traceDataCache_->UpdataZeroThreadInfo(); +} + +void BytraceEventParser::BeginFilterEvents(EventInfo* event) +{ + auto it = eventToFunctionMap_.find(event->line.eventName); + if (it != eventToFunctionMap_.end()) { + uint32_t tgid; + ArgsMap args; + GetDataSegArgs(event->line, args, tgid); + if (tgid) { + streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(event->line.pid, tgid, event->line.task); + } else { + // When tgid is zero, only use tid create thread + streamFilters_->processFilter_->GetOrCreateThreadWithPid(event->line.pid, tgid); + } + if (it->second(args, event->line)) { + traceDataCache_->UpdateTraceTime(event->line.ts); + } + } else { + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED); + TS_LOGD("UnRecognizable event name:%s", event->line.eventName.c_str()); + } +} + +void BytraceEventParser::Clear() +{ + streamFilters_->binderFilter_->Clear(); + streamFilters_->sliceFilter_->Clear(); + streamFilters_->cpuFilter_->Clear(); + streamFilters_->irqFilter_->Clear(); + streamFilters_->cpuMeasureFilter_->Clear(); + streamFilters_->threadMeasureFilter_->Clear(); + streamFilters_->threadFilter_->Clear(); + streamFilters_->processMeasureFilter_->Clear(); + streamFilters_->processFilterFilter_->Clear(); + streamFilters_->clockEnableFilter_->Clear(); + streamFilters_->clockDisableFilter_->Clear(); + streamFilters_->clkRateFilter_->Clear(); + streamFilters_->clkDisableFilter_->Clear(); + streamFilters_->binderFilter_->Clear(); + printEventParser_.Finish(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h b/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..9e1a83c5a002747ad64e1792311cf3220520bdf5 --- /dev/null +++ b/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h @@ -0,0 +1,119 @@ +/* + * 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 SRC_BYTRACE_EVENT_PARSER_H +#define SRC_BYTRACE_EVENT_PARSER_H + +#include +#include + +#include "common_types.h" +#include "event_parser_base.h" +#include "print_event_parser.h" +#include "trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +using ArgsMap = std::unordered_map; +class BytraceEventParser : public EventParserBase { +private: + class EventInfo { + public: + EventInfo(uint64_t ts, BytraceLine li) : eventTimestamp(ts), line(li) {} + uint64_t eventTimestamp; + BytraceLine line; + }; + +public: + BytraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + void ParseDataItem(const BytraceLine& line); + void FilterAllEventsTemp(); + void FilterAllEvents(); + void BeginFilterEvents(EventInfo* event); + void Clear(); + +private: + using FuncCall = std::function; + bool SchedSwitchEvent(const ArgsMap& args, const BytraceLine& line) const; + bool BlockedReason(const ArgsMap& args, const BytraceLine& line) const; + bool TaskRenameEvent(const ArgsMap& args, const BytraceLine& line) const; + bool TaskNewtaskEvent(const ArgsMap& args, const BytraceLine& line) const; + bool TracingMarkWriteOrPrintEvent(const ArgsMap& args, const BytraceLine& line); + bool SchedWakeupEvent(const ArgsMap& args, const BytraceLine& line) const; + bool SchedWakingEvent(const ArgsMap& args, const BytraceLine& line) const; + bool CpuIdleEvent(const ArgsMap& args, const BytraceLine& line) const; + bool CpuFrequencyEvent(const ArgsMap& args, const BytraceLine& line) const; + bool CpuFrequencyLimitsEvent(const ArgsMap& args, const BytraceLine& line) const; + bool WorkqueueExecuteStartEvent(const ArgsMap& args, const BytraceLine& line) const; + bool WorkqueueExecuteEndEvent(const ArgsMap& args, const BytraceLine& line) const; + bool ProcessExitEvent(const ArgsMap& args, const BytraceLine& line) const; + bool SetRateEvent(const ArgsMap& args, const BytraceLine& line) const; + bool ClockEnableEvent(const ArgsMap& args, const BytraceLine& line) const; + bool ClockDisableEvent(const ArgsMap& args, const BytraceLine& line) const; + bool RegulatorSetVoltageEvent(const ArgsMap& args, const BytraceLine& line) const; + bool RegulatorSetVoltageCompleteEvent(const ArgsMap& args, const BytraceLine& line) const; + bool RegulatorDisableEvent(const ArgsMap& args, const BytraceLine& line) const; + bool RegulatorDisableCompleteEvent(const ArgsMap& args, const BytraceLine& line) const; + bool IpiEntryEvent(const ArgsMap& args, const BytraceLine& line) const; + bool IpiExitEvent(const ArgsMap& args, const BytraceLine& line) const; + bool IrqHandlerEntryEvent(const ArgsMap& args, const BytraceLine& line) const; + bool IrqHandlerExitEvent(const ArgsMap& args, const BytraceLine& line) const; + bool SoftIrqRaiseEvent(const ArgsMap& args, const BytraceLine& line) const; + bool SoftIrqEntryEvent(const ArgsMap& args, const BytraceLine& line) const; + bool SoftIrqExitEvent(const ArgsMap& args, const BytraceLine& line) const; + bool BinderTransaction(const ArgsMap& args, const BytraceLine& line) const; + bool BinderTransactionReceived(const ArgsMap& args, const BytraceLine& line) const; + bool BinderTransactionAllocBufEvent(const ArgsMap& args, const BytraceLine& line) const; + void GetDataSegArgs(BytraceLine& bufLine, ArgsMap& args, uint32_t& tgid) const; + + std::map eventToFunctionMap_ = {}; + const uint32_t MIN_SCHED_SWITCH_ARGS_COUNT = 6; + const uint32_t MIN_BLOCKED_REASON_ARGS_COUNT = 3; + const uint32_t MIN_SCHED_WAKEUP_ARGS_COUNT = 2; + const uint32_t MIN_TASK_RENAME_ARGS_COUNT = 2; + const uint32_t MIN_SCHED_WAKING_ARGS_COUNT = 4; + const uint32_t MIN_CPU_IDLE_ARGS_COUNT = 2; + const uint32_t MIN_CPU_FREQUENCY_ARGS_COUNT = 2; + const uint32_t MIN_PROCESS_EXIT_ARGS_COUNT = 2; + const uint32_t MIN_CLOCK_SET_RATE_ARGS_COUNT = 3; + const uint32_t MIN_CLOCK_ENABLE_ARGS_COUNT = 3; + const uint32_t MIN_CLOCK_DISABLE_ARGS_COUNT = 3; + const uint32_t MIN_IRQ_HANDLER_ENTRY_ARGS_COUNT = 2; + const uint32_t MIN_IRQ_HANDLER_EXIT_ARGS_COUNT = 2; + const uint32_t MIN_SOFTIRQ_ENTRY_ARGS_COUNT = 2; + const uint32_t MIN_SOFTIRQ_EXIT_ARGS_COUNT = 2; + const uint32_t MIN_BINDER_TRANSACTION_ARGS_COUNT = 7; + const uint32_t MIN_BINDER_TRANSACTION_RECEIVED_ARGS_COUNT = 1; + const uint32_t MIN_BINDER_TRANSACTION_ALLOC_BUF_ARGS_COUNT = 3; + std::vector> eventList_ = {}; + PrintEventParser printEventParser_; + const DataIndex schedWakeupName_ = traceDataCache_->GetDataIndex("sched_wakeup"); + const DataIndex schedWakingName_ = traceDataCache_->GetDataIndex("sched_waking"); + const DataIndex ioWaitId_ = traceDataCache_->GetDataIndex("io_wait"); + const DataIndex workQueueId_ = traceDataCache_->GetDataIndex("workqueue"); + const DataIndex schedWakeupId_ = traceDataCache_->GetDataIndex("sched_wakeup"); + const DataIndex schedBlockedReasonId_ = traceDataCache_->GetDataIndex("sched_blocked_reason"); + const DataIndex cpuFrequencyLimitMaxNameId = traceDataCache_->GetDataIndex("cpu_frequency_limits_max"); + const DataIndex cpuFrequencyLimitMinNameId = traceDataCache_->GetDataIndex("cpu_frequency_limits_min"); + +protected: + TraceStreamerConfig config_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_BYTRACE_EVENT_PARSER_H diff --git a/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp b/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b22fba0dfd03ddd286c9ddcc331eb093ef1b8f0 --- /dev/null +++ b/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp @@ -0,0 +1,432 @@ +/* + * 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_parser.h" +#include +#include +#include +#include "binder_filter.h" +#include "cpu_filter.h" +#include "hi_sysevent_measure_filter.h" +#include "parting_string.h" +#include "stat_filter.h" +#include "system_event_measure_filter.h" +namespace SysTuning { +namespace TraceStreamer { +BytraceParser::BytraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters) + : ParserBase(filters), + eventParser_(std::make_unique(dataCache, filters)), +#ifdef SUPPORTTHREAD + dataSegArray_(std::make_unique(MAX_SEG_ARRAY_SIZE)), + supportThread_(true) +#else + dataSegArray_(std::make_unique(1)) +#endif +{ +} + +BytraceParser::~BytraceParser() = default; + +void BytraceParser::WaitForParserEnd() +{ + if (parseThreadStarted_ || filterThreadStarted_) { + toExit_ = true; + while (!exited_) { + usleep(sleepDur_ * sleepDur_); + } + } + eventParser_->FilterAllEvents(); + eventParser_->Clear(); + dataSegArray_.reset(); +} +void BytraceParser::ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) +{ + if (isParsingOver_) { + return; + } + packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]); + auto packagesBegin = packagesBuffer_.begin(); + while (1) { + auto packagesLine = std::find(packagesBegin, packagesBuffer_.end(), '\n'); + if (packagesLine == packagesBuffer_.end()) { + break; + } + if (packagesLine == packagesBuffer_.begin()) { + packagesLine++; + packagesBegin = packagesLine; + continue; + } + // Support parsing windows file format(ff=dos) + auto extra = *(packagesLine - 1) == '\r' ? 1 : 0; + std::string bufferLine(packagesBegin, packagesLine - extra); + + if (IsTraceComment(bufferLine)) { + traceCommentLines_++; + goto NEXT_LINE; + } + if (bufferLine.empty()) { + parsedTraceInvalidLines_++; + goto NEXT_LINE; + } + + if (bufferLine.find(script_.c_str()) != std::string::npos) { + isParsingOver_ = true; + break; + } + if (isBytrace_) { + if (!traceBegan_) { + traceBegan_ = true; + } + ParseTraceDataItem(bufferLine); + } else { + ParseJsonData(bufferLine); + } + + NEXT_LINE: + packagesBegin = packagesLine + 1; + continue; + } + + if (isParsingOver_) { + packagesBuffer_.clear(); + } else { + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin); + } + return; +} +int32_t BytraceParser::JGetData(json& jMessage, + JsonData& jData, + size_t& maxArraySize, + std::vector& noArrayIndex, + std::vector& arrayIndex) +{ + for (auto i = jMessage.begin(); i != jMessage.end(); i++) { + if (i.key() == "name_") { + jData.eventSource = i.value(); + if (find(eventsAccordingAppNames.begin(), eventsAccordingAppNames.end(), jData.eventSource) == + eventsAccordingAppNames.end()) { + TS_LOGW("event source:%s not supported for hisysevent", jData.eventSource.c_str()); + return -1; + } + continue; + } + if (i.key() == "time_") { + jData.timeStamp = i.value(); + continue; + } + if (i.key() == "tag_" && i.value() != "PowerStats") { + TS_LOGW("energy data without PowerStats tag_ would be invalid"); + return -1; + } + if (i.key() == "APPNAME") { + jData.appName.assign(i.value().begin(), i.value().end()); + } + if (i.value().is_array()) { + maxArraySize = std::max(maxArraySize, i.value().size()); + arrayIndex.push_back(jData.key.size()); + } else { + noArrayIndex.push_back(jData.key.size()); + } + jData.key.push_back(i.key()); + jData.value.push_back(i.value()); + } + return 0; +} + +void BytraceParser::NoArrayDataParse(JsonData jData, std::vector noArrayIndex, DataIndex eventSourceIndex) +{ + for (auto itor = noArrayIndex.begin(); itor != noArrayIndex.end(); itor++) { + auto value = jData.value[*itor]; + std::string key = jData.key[*itor]; + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + DataIndex keyIndex = eventParser_->traceDataCache_->GetDataIndex(key); + if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = eventParser_->traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, 1, + 0, valueIndex); + } else { + DataIndex valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, 0, + valueIndex, 0); + } + } +} +void BytraceParser::ArrayDataParse(JsonData jData, + std::vector arrayIndex, + DataIndex eventSourceIndex, + size_t maxArraySize) +{ + for (int32_t j = 0; j < maxArraySize; j++) { + for (auto itor = arrayIndex.begin(); itor != arrayIndex.end(); itor++) { + auto value = jData.value[*itor][j]; + std::string key = jData.key[*itor]; + DataIndex keyIndex = eventParser_->traceDataCache_->GetDataIndex(key); + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + if (value.is_number()) { + DataIndex valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, + 0, valueIndex, 0); + } else if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = eventParser_->traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, + 1, 0, valueIndex); + } + } + } +} +void BytraceParser::CommonDataParser(JsonData jData, DataIndex eventSourceIndex) +{ + for (int32_t j = 0; j < jData.key.size(); j++) { + std::string key = jData.key[j]; + auto value = jData.value[j]; + DataIndex keyIndex = eventParser_->traceDataCache_->GetDataIndex(key); + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = eventParser_->traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, 1, + 0, valueIndex); + } else { + DataIndex valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(0, jData.timeStamp, eventSourceIndex, keyIndex, 0, + valueIndex, 0); + } + } +} +void BytraceParser::ParseJsonData(const std::string& buffer) +{ + std::stringstream ss; + json jMessage; + ss << buffer; + ss >> jMessage; + JsonData jData; + size_t maxArraySize = 0; + std::vector noArrayIndex = {}; + std::vector arrayIndex = {}; + if (JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex) < 0) { + return; + } + DataIndex eventSourceIndex = eventParser_->traceDataCache_->GetDataIndex(jData.eventSource); + if (maxArraySize) { + NoArrayDataParse(jData, noArrayIndex, eventSourceIndex); + ArrayDataParse(jData, arrayIndex, eventSourceIndex, maxArraySize); + } else { + CommonDataParser(jData, eventSourceIndex); + } + return; +} +void BytraceParser::ParseTraceDataItem(const std::string& buffer) +{ + if (!supportThread_) { + dataSegArray_[rawDataHead_].seg = std::move(buffer); + ParserData(dataSegArray_[rawDataHead_]); + return; + } + int32_t head = rawDataHead_; + while (!toExit_) { + if (dataSegArray_[head].status.load() != TS_PARSE_STATUS_INIT) { + TS_LOGD("rawDataHead_:\t%d, parseHead_:\t%d, filterHead_:\t%d status:\t%d\n", rawDataHead_, parseHead_, + filterHead_, dataSegArray_[head].status.load()); + usleep(sleepDur_); + continue; + } + dataSegArray_[head].seg = std::move(buffer); + dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED; + rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE; + break; + } + if (!parseThreadStarted_) { + parseThreadStarted_ = true; + int32_t tmp = maxThread_; + while (tmp--) { + parserThreadCount_++; + std::thread MatchLineThread(&BytraceParser::ParseThread, this); + MatchLineThread.detach(); + TS_LOGI("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_); + } + } + return; +} +int32_t BytraceParser::GetNextSegment() +{ + int32_t head; + dataSegMux_.lock(); + head = parseHead_; + DataSegment& seg = dataSegArray_[head]; + if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) { + if (toExit_) { + parserThreadCount_--; + TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_); + dataSegMux_.unlock(); + if (!parserThreadCount_ && !filterThreadStarted_) { + exited_ = true; + } + return ERROR_CODE_EXIT; + } + if (seg.status.load() == TS_PARSE_STATUS_PARSING) { + dataSegMux_.unlock(); + usleep(sleepDur_); + return ERROR_CODE_NODATA; + } + dataSegMux_.unlock(); + TS_LOGD("ParseThread watting:\t%d, parseHead_:\t%d, filterHead_:\t%d status:\t%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + usleep(sleepDur_); + return ERROR_CODE_NODATA; + } + parseHead_ = (parseHead_ + 1) % MAX_SEG_ARRAY_SIZE; + seg.status = TS_PARSE_STATUS_PARSING; + dataSegMux_.unlock(); + return head; +} + +void BytraceParser::GetDataSegAttr(DataSegment& seg, const std::smatch& matcheLine) const +{ + const uint64_t S_TO_NS = 1e9; + size_t index = 0; + std::string pidStr = matcheLine[++index].str(); + std::optional optionalPid = base::StrToUInt32(pidStr); + if (!optionalPid.has_value()) { + TS_LOGD("Illegal pid: %s", pidStr.c_str()); + seg.status = TS_PARSE_STATUS_INVALID; + return; + } + + std::string tGidStr = matcheLine[++index].str(); + std::string cpuStr = matcheLine[++index].str(); + std::optional optionalCpu = base::StrToUInt32(cpuStr); + if (!optionalCpu.has_value()) { + TS_LOGD("Illegal cpu %s", cpuStr.c_str()); + seg.status = TS_PARSE_STATUS_INVALID; + return; + } + std::string timeStr = matcheLine[++index].str(); + // Directly parsing double may result in accuracy loss issues + std::optional optionalTime = base::StrToDouble(timeStr); + if (!optionalTime.has_value()) { + TS_LOGD("Illegal ts %s", timeStr.c_str()); + seg.status = TS_PARSE_STATUS_INVALID; + return; + } + std::string eventName = matcheLine[++index].str(); + seg.bufLine.task = StrTrim(matcheLine.prefix()); + if (seg.bufLine.task == "<...>") { + seg.bufLine.task = ""; + } + seg.bufLine.argsStr = StrTrim(matcheLine.suffix()); + seg.bufLine.pid = optionalPid.value(); + seg.bufLine.cpu = optionalCpu.value(); + seg.bufLine.ts = optionalTime.value() * S_TO_NS; + seg.bufLine.tGidStr = tGidStr; + seg.bufLine.eventName = eventName; + seg.status = TS_PARSE_STATUS_PARSED; +} +void BytraceParser::ParseThread() +{ + while (1) { + int32_t head = GetNextSegment(); + if (head < 0) { + if (head == ERROR_CODE_NODATA) { + continue; + } + if (!filterThreadStarted_) { + exited_ = true; + } + return; + } + DataSegment& seg = dataSegArray_[head]; + ParserData(seg); + } +} + +void BytraceParser::ParserData(DataSegment& seg) +{ + std::smatch matcheLine; + if (!std::regex_search(seg.seg, matcheLine, bytraceMatcher_)) { + TS_LOGD("Not support this event (line: %s)", seg.seg.c_str()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + seg.status = TS_PARSE_STATUS_INVALID; + parsedTraceInvalidLines_++; + return; + } else { + parsedTraceValidLines_++; + } + GetDataSegAttr(seg, matcheLine); + if (!supportThread_) { + FilterData(seg); + return; + } + if (!filterThreadStarted_) { + filterThreadStarted_ = true; + std::thread ParserThread(&BytraceParser::FilterThread, this); + ParserThread.detach(); + } +} +void BytraceParser::FilterThread() +{ + while (1) { + DataSegment& seg = dataSegArray_[filterHead_]; + if (!FilterData(seg)) { + return; + } + } +} +bool BytraceParser::FilterData(DataSegment& seg) +{ + if (!supportThread_) { + if (seg.status.load() != TS_PARSE_STATUS_INVALID) { + eventParser_->ParseDataItem(seg.bufLine); + seg.status = TS_PARSE_STATUS_INIT; + return true; + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + return false; + } + if (seg.status.load() == TS_PARSE_STATUS_INVALID) { + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + seg.status = TS_PARSE_STATUS_INIT; + return true; + } + if (seg.status.load() != TS_PARSE_STATUS_PARSED) { + if (toExit_ && !parserThreadCount_) { + TS_LOGI("exiting FilterThread Thread\n"); + exited_ = true; + filterThreadStarted_ = false; + return false; + } + usleep(sleepDur_); + return true; + } + eventParser_->ParseDataItem(seg.bufLine); + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; + seg.status = TS_PARSE_STATUS_INIT; + return true; +} +// Remove space at the beginning and end of the string +std::string BytraceParser::StrTrim(const std::string& input) const +{ + std::string str = input; + if (str.empty()) { + return str; + } + str.erase(0, str.find_first_not_of(" ")); + str.erase(str.find_last_not_of(" ") + 1); + return str; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h b/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..e0a2f7e869af9aa4876ba9c25f3ce62582969081 --- /dev/null +++ b/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h @@ -0,0 +1,170 @@ +/* + * 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 BYTRACE_PARSER_H +#define BYTRACE_PARSER_H + +#include +#include +#include +#include + +#include "bytrace_event_parser.h" +#include "json.hpp" +#include "log.h" +#include "parser_base.h" +#include "string_to_numerical.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class BytraceParser : public ParserBase { +public: + BytraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters); + ~BytraceParser(); + + void ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) override; + size_t ParsedTraceValidLines() const + { + return parsedTraceValidLines_; + } + size_t ParsedTraceInvalidLines() const + { + return parsedTraceInvalidLines_; + } + size_t TraceCommentLines() const + { + return traceCommentLines_; + } + void EnableBytrace(bool enable) + { + isBytrace_ = enable; + } + + void WaitForParserEnd(); + +private: + enum ErrorCode { ERROR_CODE_EXIT = -2, ERROR_CODE_NODATA = -1 }; + int32_t GetNextSegment(); + void GetDataSegAttr(DataSegment& seg, const std::smatch& matcheLine) const; + + void FilterThread(); + inline static bool IsNotSpace(char c) + { + return !std::isspace(c); + } + inline static bool IsTraceComment(const std::string& buffer) + { + return ((buffer[0] == '#') || buffer.find("TASK-PID") != std::string::npos); + } + + void ParseTraceDataItem(const std::string& buffer) override; + std::string StrTrim(const std::string& input) const; + void ParseThread(); + void ParserData(DataSegment& seg); + bool FilterData(DataSegment& seg); + +private: + using json = nlohmann::json; + typedef struct { + std::string eventSource; + uint64_t timeStamp; + std::vector appName; + std::vector appVersions; + std::vector key; + std::vector value; + } JsonData; + void NoArrayDataParse(JsonData jData, std::vector noArrayIndex, DataIndex eventSourceIndex); + void ArrayDataParse(JsonData jData, + std::vector arrayIndex, + DataIndex eventSourceIndex, + size_t maxArraySize); + void CommonDataParser(JsonData jData, DataIndex eventSourceIndex); + int32_t JGetData(json& jMessage, + JsonData& jData, + size_t& maxArraySize, + std::vector& noArrayIndex, + std::vector& arrayIndex); + void ParseJsonData(const std::string& buffer); + +private: + using ArgsMap = std::unordered_map; + bool isParsingOver_ = false; + std::unique_ptr eventParser_; + const std::regex bytraceMatcher_ = std::regex(R"(-(\d+)\s+\(?\s*(\d+|-+)?\)?\s?\[(\d+)\]\s*)" + R"([a-zA-Z0-9.]{0,5}\s+(\d+\.\d+):\s+(\S+):)"); + + const std::string script_ = R"()"; + + std::vector eventsAccordingAppNames = {"POWER_IDE_BATTERY", + "POWER_IDE_CPU", + "POWER_IDE_LOCATION", + "POWER_IDE_GPU", + "POWER_IDE_DISPLAY", + "POWER_IDE_CAMERA", + "POWER_IDE_BLUETOOTH", + "POWER_IDE_FLASHLIGHT", + "POWER_IDE_AUDIO", + "POWER_IDE_WIFISCAN", + "BRIGHTNESS_NIT", + "SIGNAL_LEVEL", + "WIFI_EVENT_RECEIVED", + "AUDIO_STREAM_CHANGE", + "AUDIO_VOLUME_CHANGE", + "WIFI_STATE", + "BLUETOOTH_BR_SWITCH_STATE", + "LOCATION_SWITCH_STATE", + "ENABLE_SENSOR", + "DISABLE_SENSOR", + "WORK_REMOVE", + "WORK_START", + "WORK_STOP", + "WORK_ADD", + "POWER_RUNNINGLOCK", + "GNSS_STATE", + "ANOMALY_SCREEN_OFF_ENERGY", + "ANOMALY_ALARM_WAKEUP", + "ANOMALY_KERNEL_WAKELOCK", + "ANOMALY_RUNNINGLOCK", + "ANORMALY_APP_ENERGY", + "ANOMALY_GNSS_ENERGY", + "ANOMALY_CPU_HIGH_FREQUENCY", + "ANOMALY_CPU_ENERGY", + "ANOMALY_WAKEUP"}; + + size_t parsedTraceValidLines_ = 0; + size_t parsedTraceInvalidLines_ = 0; + size_t traceCommentLines_ = 0; + std::mutex dataSegMux_; + int32_t parseHead_ = 0; + std::atomic filterThreadStarted_{false}; + bool parseThreadStarted_ = false; + const int32_t MAX_SEG_ARRAY_SIZE = 5000; + const int32_t maxThread_ = 4; // 4 is the best on ubuntu 113MB/s, max 138MB/s, 6 is best on mac m1 21MB/s, + int32_t parserThreadCount_ = 0; + bool toExit_ = false; + bool exited_ = false; + std::unique_ptr dataSegArray_; + int32_t rawDataHead_ = 0; + int32_t filterHead_ = 0; + const int32_t sleepDur_ = 100; + bool supportThread_ = false; + bool isBytrace_ = true; + bool traceBegan_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // _BYTRACE_PARSER_H_ diff --git a/trace_streamer/src/parser/common_types.h b/trace_streamer/src/parser/common_types.h new file mode 100644 index 0000000000000000000000000000000000000000..1a2f7fb49a7a8019c8542e75683135fb63fef9ce --- /dev/null +++ b/trace_streamer/src/parser/common_types.h @@ -0,0 +1,167 @@ +/* + * 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 BYTRACE_COMMON_TYPES_H +#define BYTRACE_COMMON_TYPES_H + +#include +#include +#include +#ifndef IS_PBDECODER +#include "cpu_plugin_result.pbreader.h" +#include "diskio_plugin_result.pbreader.h" +#include "hidump_plugin_result.pbreader.h" +#include "hilog_plugin_result.pbreader.h" +#include "hisysevent_plugin_config.pbreader.h" +#include "hisysevent_plugin_result.pbreader.h" +#include "js_heap_config.pbreader.h" +#include "js_heap_result.pbreader.h" +#include "memory_plugin_result.pbreader.h" +#include "native_hook_result.pbreader.h" +#include "network_plugin_result.pbreader.h" +#include "process_plugin_result.pbreader.h" +#include "proto_reader_help.h" +#include "services/common_types.pbreader.h" +#include "trace_plugin_result.pbreader.h" +#include "ts_common.h" +#include "native_hook_result.pbreader.h" +#else +#include "cpu_plugin_result.pb.h" +#include "diskio_plugin_result.pb.h" +#include "hidump_plugin_result.pb.h" +#include "hilog_plugin_result.pb.h" +#include "hisysevent_plugin_config.pb.h" +#include "hisysevent_plugin_result.pb.h" +#include "memory_plugin_result.pb.h" +#include "native_hook_result.pb.h" +#include "network_plugin_result.pb.h" +#include "process_plugin_result.pb.h" +#include "services/common_types.pb.h" +#include "trace_plugin_result.pb.h" +#include "ts_common.h" +#endif + +namespace SysTuning { +namespace TraceStreamer { +enum ParseResult { PARSE_ERROR = 0, PARSE_SUCCESS = 1 }; +enum RawType { RAW_CPU_IDLE = 1, RAW_SCHED_WAKEUP = 2, RAW_SCHED_WAKING = 3 }; +struct BytraceLine { + uint64_t ts = 0; + uint32_t pid = 0; + uint32_t cpu = 0; + + std::string task; // thread name + std::string pidStr; // thread str + std::string tGidStr; // process thread_group + uint32_t tgid = 0; + std::string eventName; + std::string argsStr; +}; +enum ParseStatus { + TS_PARSE_STATUS_INIT = 0, + TS_PARSE_STATUS_SEPRATED = 1, + TS_PARSE_STATUS_PARSING = 2, + TS_PARSE_STATUS_PARSED = 3, + TS_PARSE_STATUS_INVALID = 4 +}; +struct DataSegment { + std::string seg; + BytraceLine bufLine; + std::atomic status{TS_PARSE_STATUS_INIT}; +}; +#ifndef IS_PBDECODER +struct HtraceDataSegment { + std::shared_ptr seg; + uint64_t timeStamp; + BuiltinClocks clockId; + DataSourceType dataType; + std::atomic status{TS_PARSE_STATUS_INIT}; + ProtoReader::BytesView protoData; +}; +#else +struct HtraceDataSegment { + std::string seg; + MemoryData memData; + HilogInfo logData; + BatchNativeHookData batchNativeHookData; + HidumpInfo hidumpInfo; + CpuData cpuInfo; + NetworkDatas networkInfo; + DiskioData diskIOInfo; + ProcessData processInfo; + HisyseventInfo hisyseventInfo; + HisyseventConfig hisyseventConfig; + uint64_t timeStamp; + std::unique_ptr traceData; + BuiltinClocks clockId; + DataSourceType dataType; + std::atomic status{TS_PARSE_STATUS_INIT}; +}; +#endif + +class TracePoint { +public: + TracePoint() {} + TracePoint(const TracePoint& point) + : phase_(point.phase_), + tgid_(point.tgid_), + name_(point.name_), + value_(point.value_), + categoryGroup_(point.categoryGroup_), + chainId_(point.chainId_), + spanId_(point.spanId_), + parentSpanId_(point.parentSpanId_), + flag_(point.flag_), + args_(point.args_), + funcPrefixId_(point.funcPrefixId_), + funcPrefix_(point.funcPrefix_), + funcArgs_(point.funcArgs_) + { + } + void operator=(const TracePoint& point) + { + phase_ = point.phase_; + tgid_ = point.tgid_; + name_ = point.name_; + value_ = point.value_; + categoryGroup_ = point.categoryGroup_; + chainId_ = point.chainId_; + spanId_ = point.spanId_; + parentSpanId_ = point.parentSpanId_; + flag_ = point.flag_; + args_ = point.args_; + funcPrefixId_ = point.funcPrefixId_; + funcPrefix_ = point.funcPrefix_; + funcArgs_ = point.funcArgs_; + } + char phase_ = '\0'; + uint32_t tgid_ = 0; + std::string name_ = ""; + uint64_t value_ = 0; + std::string categoryGroup_ = ""; + // Distributed Data + std::string chainId_ = ""; + std::string spanId_ = ""; + std::string parentSpanId_ = ""; + std::string flag_ = ""; + std::string args_ = ""; + uint32_t funcPrefixId_ = 0; + std::string funcPrefix_ = ""; + std::string funcArgs_ = ""; +}; + +} // namespace TraceStreamer +} // namespace SysTuning +#endif // _BYTRACE_COMMON_TYPES_H_ diff --git a/trace_streamer/src/parser/ebpf_parser/BUILD.gn b/trace_streamer/src/parser/ebpf_parser/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e8284fe9f265b0c5c0d76b0f455c41bb24812e52 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/BUILD.gn @@ -0,0 +1,89 @@ +# 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("../../ts.gni") +ohos_source_set("ebpf_parser_src") { + subsystem_name = "trace_streamer" + part_name = "ebpf_parser_src" + sources = [ + "bio_latency_data_parser.cpp", + "bio_latency_data_parser.h", + "ebpf_base.cpp", + "ebpf_base.h", + "ebpf_data_parser.cpp", + "ebpf_data_parser.h", + "ebpf_data_reader.cpp", + "ebpf_data_reader.h", + "ebpf_stdtype.h", + "file_system_data_parser.cpp", + "file_system_data_parser.h", + "paged_memory_data_parser.cpp", + "paged_memory_data_parser.h", + ] + include_dirs = [ + ".", + "../", + "../htrace_parser", + "../..", + "../../trace_data", + "../../base", + "../../include", + "../../filter", + "../../cfg", + "../../trace_streamer", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "//third_party/protobuf/src", + "//third_party/sqlite/include", + ] + if (is_win || is_macx) { + include_dirs += [ + "//third_party/perf_include/linux", + "//third_party/perf_include/musl", + ] + } + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} + +group("ebpf_parser") { + deps = [ + ":ebpf_parser_src", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] +} diff --git a/trace_streamer/src/parser/ebpf_parser/bio_latency_data_parser.cpp b/trace_streamer/src/parser/ebpf_parser/bio_latency_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac7dd1e37a34be33faaa4d245ce226cd083d0e40 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/bio_latency_data_parser.cpp @@ -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. + */ +#include "bio_latency_data_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" + +namespace SysTuning { +namespace TraceStreamer { +BioLatencyDataParser::BioLatencyDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx), + EbpfBase(dataCache, ctx), + timeParser_(std::make_unique(dataCache, ctx)) +{ +} +BioLatencyDataParser::~BioLatencyDataParser() +{ + TS_LOGI("EBPF Bio data ts MIN:%llu, MAX:%llu", static_cast(timeParser_->GetPluginStartTime()), + static_cast(timeParser_->GetPluginEndTime())); +} +void BioLatencyDataParser::ParseBioLatencyEvent() +{ + if (!reader_->GetBIOSampleMap().size()) { + return; + } + for (auto mapItor = reader_->GetBIOSampleMap().begin(); mapItor != reader_->GetBIOSampleMap().end(); mapItor++) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF_BIO_LATENCY, STAT_EVENT_RECEIVED); + auto bioFixedHeadrAddr = mapItor->second; + bool callIdExistFlag = false; + + auto userIpsAddr = reinterpret_cast(bioFixedHeadrAddr + 1); + if (bioFixedHeadrAddr->nips) { + std::string ipsToStr(reinterpret_cast(userIpsAddr), bioFixedHeadrAddr->nips * SINGLE_IP_SIZE); + auto ipsHashValue = hashFun_(ipsToStr); + auto value = pidAndipsToCallId_.Find(bioFixedHeadrAddr->pid, ipsHashValue); + if (value != INVALID_UINT64) { + callIdExistFlag = true; + currentCallId_ = value; + } else { + pidAndipsToCallId_.Insert(bioFixedHeadrAddr->pid, ipsHashValue, callChainId_); + currentCallId_ = callChainId_++; + } + } else { + currentCallId_ = INVALID_UINT64; + } + + uint32_t type = bioFixedHeadrAddr->type; + // Init process name data + const char* processName = reinterpret_cast(bioFixedHeadrAddr->processName); + uint32_t ipid = + streamFilters_->processFilter_->UpdateOrCreateProcessWithName(bioFixedHeadrAddr->pid, processName); + uint32_t itid = + streamFilters_->processFilter_->GetOrCreateThreadWithPid(bioFixedHeadrAddr->tid, bioFixedHeadrAddr->pid); + uint64_t startTs = bioFixedHeadrAddr->startTime; + uint64_t endTs = bioFixedHeadrAddr->endTime; + auto newStartTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(clockId_, startTs); + timeParser_->UpdatePluginTimeRange(clockId_, startTs, newStartTs); + auto newEndTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(clockId_, endTs); + timeParser_->UpdatePluginTimeRange(clockId_, endTs, newEndTs); + if (newStartTs > newEndTs) { + TS_LOGE("File system event origin startTs = %lu, endTs = %lu, newStartTs = %lu, newEndTs = %lu", startTs, + endTs, newStartTs, newEndTs); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF_PAGED_MEMORY, STAT_EVENT_DATA_INVALID); + return; + } + uint64_t duration = newEndTs - newStartTs; + auto prio = bioFixedHeadrAddr->prio; + auto size = bioFixedHeadrAddr->size; + const int32_t FOUR_KB = 1024 * 4; + uint32_t durPer4K = INVALID_UINT32; + if (size > 0) { + durPer4K = duration / (size / FOUR_KB); + } + + auto blkCount = ConvertToHexTextIndex(bioFixedHeadrAddr->blkcnt); + + auto tracerEventToStrIndexMap = reader_->GetTracerEventToStrIndexMap(); + auto pathId = tracerEventToStrIndexMap.Find(ITEM_EVENT_BIO, type, itid, startTs); + if (pathId != INVALID_UINT64) { + tracerEventToStrIndexMap.Erase(ITEM_EVENT_FS, type, itid, startTs); + } + traceDataCache_->GetBioLatencySampleData()->AppendNewData( + currentCallId_, type, ipid, itid, newStartTs, newEndTs, duration, prio, size, blkCount, pathId, durPer4K); + if (!callIdExistFlag) { + ParseCallStackData(userIpsAddr, bioFixedHeadrAddr->nips, bioFixedHeadrAddr->pid, currentCallId_); + } + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/ebpf_parser/bio_latency_data_parser.h b/trace_streamer/src/parser/ebpf_parser/bio_latency_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..409c9bb0f96df12d82f9affc9d5dd2a0ec0cd09a --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/bio_latency_data_parser.h @@ -0,0 +1,39 @@ +/* + * 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 BIO_LATENCY_DATA_PARSER_H +#define BIO_LATENCY_DATA_PARSER_H +#include "clock_filter.h" +#include "double_map.h" +#include "ebpf_base.h" +#include "htrace_plugin_time_parser.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::EbpfStdtype; +class BioLatencyDataParser : virtual public EbpfBase { +public: + BioLatencyDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~BioLatencyDataParser(); + void ParseBioLatencyEvent(); + +protected: + std::unique_ptr timeParser_; + +private: + uint64_t currentCallId_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // BIO_LATENCY_DATA_PARSER_H diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_base.cpp b/trace_streamer/src/parser/ebpf_parser/ebpf_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de2ff5a44a19ff3a9c80e7fb846ba85f9b9f8ff0 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_base.cpp @@ -0,0 +1,334 @@ +/* + * 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 "ebpf_base.h" + +namespace SysTuning { +namespace TraceStreamer { +EbpfBase::EbpfBase(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx), + pidAndIpToSymbolAndFilePathIndex_(SymbolAndFilePathIndex(false)), + filePathIndexAndStValueToSymAddr_(nullptr), + pidAndipsToCallId_(INVALID_UINT64) +{ +} +EbpfBase::~EbpfBase() +{ + pidAndipsToCallId_.Clear(); + pidAndIpToSymbolAndFilePathIndex_.Clear(); + filePathIndexToPidAndIpMap_.clear(); + filePathIndexAndStValueToSymAddr_.Clear(); +} +bool EbpfBase::InitEbpfDataParser(EbpfDataReader* reader) +{ + auto clockId = reader->GetEbpfDataHeader()->header.clock; + auto itor = ebpfToTSClockType_.find(clockId); + if (itor == ebpfToTSClockType_.end()) { + return false; + } + clockId_ = ebpfToTSClockType_.at(clockId); + reader_ = std::move(reader); + return true; +} + +void EbpfBase::ParseCallStackData(const uint64_t* userIpsAddr, uint16_t count, uint32_t pid, uint32_t callId) +{ + uint64_t depth = 0; + for (auto i = count - 1; i >= 0; i--) { + if (userIpsAddr[i] > MIN_USER_IP) { + auto symbolAndFilePathIndex = GetSymbolAndFilePathIndex(pid, userIpsAddr[i]); + auto ipIndex = ConvertToHexTextIndex(userIpsAddr[i]); + ipStrIndexToIpMap_.insert(std::make_pair(ipIndex, userIpsAddr[i])); + traceDataCache_->GetEbpfCallStack()->AppendNewData( + callId, depth, ipIndex, symbolAndFilePathIndex.symbolIndex, symbolAndFilePathIndex.filePathIndex); + depth++; + } + } + // Only one successful insertion is required, without considering repeated insertion failures + callIdToPid_.insert(std::make_pair(callId, pid)); +} + +SymbolAndFilePathIndex EbpfBase::GetSymbolAndFilePathIndex(uint32_t pid, uint64_t ip) +{ + auto value = pidAndIpToSymbolAndFilePathIndex_.Find(pid, ip); + if (value.flag) { + return value; + } + return GetSymbolNameIndexFromElfSym(pid, ip); +} + +DataIndex EbpfBase::GetSymbolNameIndexFromSymVaddr(const ElfEventFixedHeader* elfHeaderAddr, uint64_t symVaddr) +{ + uint32_t symbolStart = INVALID_UINT32; + auto startValueToSymAddr = reader_->GetElfAddrAndStartValueToSymAddr().Find(elfHeaderAddr); + if (!startValueToSymAddr) { + return INVALID_UINT64; + } + auto end = startValueToSymAddr->upper_bound(symVaddr); + auto symEntLen = elfHeaderAddr->symEntLen; + auto length = std::distance(startValueToSymAddr->begin(), end); + if (length > 0) { + end--; + if (symEntLen == ELF32_SYM) { + GetSymbolStartIndex(reinterpret_cast(end->second), symbolStart, symVaddr); + } else { + GetSymbolStartIndex(reinterpret_cast(end->second), symbolStart, symVaddr); + } + } + if (symbolStart == INVALID_UINT32) { + return INVALID_UINT64; + } + // Take out the string according to the subscript + auto strTabAddr = reinterpret_cast(elfHeaderAddr + 1); + if (symbolStart > elfHeaderAddr->strTabLen) { + TS_LOGE("symbolStart = %u, elfHeaderAddr->strTabLen = %u", symbolStart, elfHeaderAddr->strTabLen); + return INVALID_UINT64; + } + auto mangle = reinterpret_cast(strTabAddr) + symbolStart; + auto demangle = GetDemangleSymbolIndex(mangle); + return traceDataCache_->GetDataIndex(demangle); +} +void EbpfBase::UpdateFilePathIndexToPidAndIpMap(DataIndex filePathIndex, uint32_t pid, uint64_t ip) +{ + auto itor = filePathIndexToPidAndIpMap_.find(filePathIndex); + if (itor != filePathIndexToPidAndIpMap_.end()) { + itor->second->insert(std::make_tuple(pid, ip)); + } else { + auto pidAndIpSet = std::make_shared>>(); + pidAndIpSet->insert(std::make_tuple(pid, ip)); + filePathIndexToPidAndIpMap_.insert(std::make_pair(filePathIndex, pidAndIpSet)); + } +} + +SymbolAndFilePathIndex EbpfBase::GetSymbolNameIndexFromElfSym(uint32_t pid, uint64_t ip) +{ + SymbolAndFilePathIndex symbolAndFilePathIndex(false); + // Follow the rules of front closing and rear opening, [start, end) + if (ip < reader_->maxKernelAddr_ && ip >= reader_->minKernelAddr_) { + symbolAndFilePathIndex = reader_->GetSymbolNameIndexFromElfSym(ip); + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + UpdateFilePathIndexToPidAndIpMap(symbolAndFilePathIndex.filePathIndex, pid, ip); + return symbolAndFilePathIndex; + } + + auto& pidAndStartAddrToMapsAddr = reader_->GetPidAndStartAddrToMapsAddr(); + auto startToMapsAddr = pidAndStartAddrToMapsAddr.Find(pid); + if (!startToMapsAddr) { + symbolAndFilePathIndex.flag = true; + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + UpdateFilePathIndexToPidAndIpMap(symbolAndFilePathIndex.filePathIndex, pid, ip); + return symbolAndFilePathIndex; + } + + uint64_t vmStart = INVALID_UINT64; + uint64_t vmOffset = INVALID_UINT64; + auto end = startToMapsAddr->upper_bound(ip); + auto length = std::distance(startToMapsAddr->begin(), end); + if (length > 0) { + end--; + // Follow the rules of front closing and rear opening, [start, end) + if (ip < end->second->end) { + vmStart = end->first; + vmOffset = end->second->offset; + symbolAndFilePathIndex.filePathIndex = + traceDataCache_->GetDataIndex(reinterpret_cast((end->second) + 1)); + } + } + symbolAndFilePathIndex.flag = true; + if (symbolAndFilePathIndex.filePathIndex == INVALID_INT64) { + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + UpdateFilePathIndexToPidAndIpMap(symbolAndFilePathIndex.filePathIndex, pid, ip); + return symbolAndFilePathIndex; + } + + auto itor = reader_->GetElfPathIndexToElfAddr().find(symbolAndFilePathIndex.filePathIndex); + if (itor == reader_->GetElfPathIndexToElfAddr().end()) { + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + UpdateFilePathIndexToPidAndIpMap(symbolAndFilePathIndex.filePathIndex, pid, ip); + return symbolAndFilePathIndex; + } + uint64_t symVaddr = ip - vmStart + vmOffset + itor->second->textVaddr - itor->second->textOffset; + auto symbolIndex = GetSymbolNameIndexFromSymVaddr(itor->second, symVaddr); + if (symbolIndex != INVALID_UINT64) { + symbolAndFilePathIndex.symbolIndex = symbolIndex; + } + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + UpdateFilePathIndexToPidAndIpMap(symbolAndFilePathIndex.filePathIndex, pid, ip); + return symbolAndFilePathIndex; +} + +DataIndex EbpfBase::ConvertToHexTextIndex(uint64_t number) +{ + if (number == INVALID_UINT64) { + return number; + } + std::string str = "0x" + base::number(number, base::INTEGER_RADIX_TYPE_HEX); + return traceDataCache_->GetDataIndex(str.c_str()); +} +template +void EbpfBase::UpdateFilePathIndexAndStValueToSymAddrMap(T* firstSymbolAddr, const int size, uint32_t filePathIndex) +{ + for (auto i = 0; i < size; i++) { + auto symAddr = firstSymbolAddr + i; + if ((symAddr->st_info & STT_FUNC) && (symAddr->st_value)) { + filePathIndexAndStValueToSymAddr_.Insert(filePathIndex, symAddr->st_value, + reinterpret_cast(symAddr)); + } + } +} +bool EbpfBase::EBPFReloadElfSymbolTable(std::shared_ptr>> elfSymbolTables) +{ + std::set> resymbolizationPidAndIps; + for (auto elfSymbolTable : *elfSymbolTables) { + auto filePathIndex = traceDataCache_->dataDict_.GetStringIndex(elfSymbolTable->filePath); + if (!filePathIndexToPidAndIpMap_.count(filePathIndex)) { + TS_LOGI("ebpf do not support resymbolizaiton use %s", elfSymbolTable->filePath.c_str()); + continue; + } + + uint32_t pid = INVALID_UINT32; + uint64_t ip = INVALID_UINT64; + auto pidAndIpSet = filePathIndexToPidAndIpMap_.at(filePathIndex); + for (auto itor = pidAndIpSet->begin(); itor != pidAndIpSet->end(); itor++) { + std::tie(pid, ip) = *itor; + // only userspace ips need re symbolization + if (ip >= reader_->minKernelAddr_ && ip < reader_->maxKernelAddr_) { + continue; + } + // delete symbolization result + pidAndIpToSymbolAndFilePathIndex_.Erase(pid, ip); + // update pids and ips which needs resymbolization + resymbolizationPidAndIps.insert(std::make_tuple(pid, ip)); + } + // Update Symbolized Auxiliary Data + auto symEntrySize = elfSymbolTable->symEntSize; + auto size = elfSymbolTable->symTable.size() / symEntrySize; + if (symEntrySize == ELF32_SYM) { + UpdateFilePathIndexAndStValueToSymAddrMap( + reinterpret_cast(elfSymbolTable->symTable.data()), size, filePathIndex); + } else { + UpdateFilePathIndexAndStValueToSymAddrMap( + reinterpret_cast(elfSymbolTable->symTable.data()), size, filePathIndex); + } + if (filePathIndexToImportSymbolTableMap_.count(filePathIndex)) { + filePathIndexToImportSymbolTableMap_.at(filePathIndex) = elfSymbolTable; + } else { + filePathIndexToImportSymbolTableMap_.emplace(std::make_pair(filePathIndex, elfSymbolTable)); + } + } + OfflineSymbolization(resymbolizationPidAndIps); + // Update Resymbolization Results + auto ebpfCallStack = traceDataCache_->GetEbpfCallStack(); + for (auto i = 0; i < ebpfCallStack->Size(); i++) { + auto ipStrIndex = ebpfCallStack->Ips()[i]; + if (!ipStrIndexToIpMap_.count(ipStrIndex)) { + continue; + } + auto ip = ipStrIndexToIpMap_.at(ipStrIndex); + auto callId = ebpfCallStack->CallChainIds()[i]; + if (callId == INVALID_UINT32) { + continue; + } + if (!callIdToPid_.count(callId)) { + continue; + } + auto pid = callIdToPid_.at(callId); + auto symbolAndFilePathIndex = pidAndIpToSymbolAndFilePathIndex_.Find(pid, ip); + if (!symbolAndFilePathIndex.flag) { + continue; + } + ebpfCallStack->UpdateSymbolAndFilePathIndex(i, symbolAndFilePathIndex.symbolIndex, + symbolAndFilePathIndex.filePathIndex); + } + return true; +} + +template +void EbpfBase::GetSymbolStartIndex(T* elfSym, uint32_t& symbolStart, uint64_t symVaddr) +{ + if (elfSym->st_value + elfSym->st_size >= symVaddr) { + symbolStart = elfSym->st_name; + } +} +void EbpfBase::OfflineSymbolization(std::set>& pidAndIps) +{ + uint32_t pid = INVALID_UINT32; + uint64_t ip = INVALID_UINT64; + for (auto itor = pidAndIps.begin(); itor != pidAndIps.end(); itor++) { + SymbolAndFilePathIndex symbolAndFilePathIndex(false); + std::tie(pid, ip) = *itor; + auto startToMapsAddr = reader_->GetPidAndStartAddrToMapsAddr().Find(pid); + if (!startToMapsAddr) { + continue; + } + uint64_t vmStart = INVALID_UINT64; + uint64_t vmOffset = INVALID_UINT64; + auto end = startToMapsAddr->upper_bound(ip); + auto length = std::distance(startToMapsAddr->begin(), end); + DataIndex filePathIndex = INVALID_DATAINDEX; + if (length > 0) { + end--; + // Follow the rules of front closing and rear opening, [start, end) + if (ip < end->second->end) { + vmStart = end->first; + vmOffset = end->second->offset; + filePathIndex = traceDataCache_->GetDataIndex(reinterpret_cast((end->second) + 1)); + } + } + symbolAndFilePathIndex.flag = true; + symbolAndFilePathIndex.filePathIndex = filePathIndex; + if (!filePathIndexToImportSymbolTableMap_.count(filePathIndex)) { + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + TS_LOGD("can not find matching symbol table!"); + continue; + } + auto& symbolTable = filePathIndexToImportSymbolTableMap_.at(filePathIndex); + // Calculate virtual address + uint64_t symVaddr = ip - vmStart + vmOffset + symbolTable->textVaddr - symbolTable->textOffset; + // pase sym_table to Elf32_Sym or Elf64_Sym array decided by sym_entry_size. + auto symEntLen = symbolTable->symEntSize; + auto startValueToSymAddrMap = filePathIndexAndStValueToSymAddr_.Find(filePathIndex); + if (!startValueToSymAddrMap) { + // find matching SymbolTable failed, but symVaddr is availiable + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + // find symbolTable failed!!! + TS_LOGD("find symbolTalbe failed!!!"); + continue; + } + // Traverse array, st_value <= symVaddr and symVaddr <= st_value + st_size. then you can get st_name + auto endItor = startValueToSymAddrMap->upper_bound(symVaddr); + length = std::distance(startValueToSymAddrMap->begin(), endItor); + uint32_t symbolStart = INVALID_UINT32; + if (length > 0) { + endItor--; + if (symEntLen == ELF32_SYM) { + GetSymbolStartIndex(reinterpret_cast(endItor->second), symbolStart, symVaddr); + } else { + GetSymbolStartIndex(reinterpret_cast(endItor->second), symbolStart, symVaddr); + } + } + if (symbolStart == INVALID_UINT32 || symbolStart >= symbolTable->strTable.size()) { + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + // find symbolStart failed, but some data is availiable. + TS_LOGD("symbolStart is : %lu invaliable!!!", symbolStart); + continue; + } + auto mangle = symbolTable->strTable.c_str() + symbolStart; + auto demangle = GetDemangleSymbolIndex(mangle); + symbolAndFilePathIndex.symbolIndex = traceDataCache_->GetDataIndex(demangle); + pidAndIpToSymbolAndFilePathIndex_.Insert(pid, ip, symbolAndFilePathIndex); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_base.h b/trace_streamer/src/parser/ebpf_parser/ebpf_base.h new file mode 100644 index 0000000000000000000000000000000000000000..0c8f9889167b55ac0d3be5a79b9c0a42db5f9dd3 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_base.h @@ -0,0 +1,65 @@ +/* + * 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 EBPF_BASE_H +#define EBPF_BASE_H +#include +#include +#include "double_map.h" +#include "ebpf_data_reader.h" +#include "ebpf_stdtype.h" +#include "event_parser_base.h" +#include "string_help.h" +#include "string_to_numerical.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +using namespace SysTuning::EbpfStdtype; + +class EbpfBase : virtual public EventParserBase { +public: + EbpfBase(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~EbpfBase(); + bool InitEbpfDataParser(EbpfDataReader* reader); + bool EBPFReloadElfSymbolTable(std::shared_ptr>> elfSymbolTables); + +protected: + void ParseCallStackData(const uint64_t* userIpsAddr, uint16_t count, uint32_t pid, uint32_t callId); + DataIndex GetSymbolNameIndexFromSymVaddr(const ElfEventFixedHeader* elfHeaderAddr, uint64_t symVaddr); + SymbolAndFilePathIndex GetSymbolAndFilePathIndex(uint32_t pid, uint64_t ip); + SymbolAndFilePathIndex GetSymbolNameIndexFromElfSym(uint32_t pid, uint64_t ip); + void UpdateFilePathIndexToPidAndIpMap(DataIndex filePathIndex, uint32_t pid, uint64_t ip); + DataIndex ConvertToHexTextIndex(uint64_t number); + template + void UpdateFilePathIndexAndStValueToSymAddrMap(T* firstSymbolAddr, const int size, uint32_t filePathIndex); + template + void GetSymbolStartIndex(T* elfSym, uint32_t& symbolStart, uint64_t symVaddr); + void OfflineSymbolization(std::set>& pidAndIps); + ClockId clockId_ = INVALID_UINT32; + std::hash hashFun_; + EbpfDataReader* reader_ = nullptr; + DoubleMap pidAndIpToSymbolAndFilePathIndex_; + std::map>>> filePathIndexToPidAndIpMap_ = {}; + std::map ipStrIndexToIpMap_ = {}; + std::map callIdToPid_ = {}; + DoubleMap filePathIndexAndStValueToSymAddr_; + std::map> filePathIndexToImportSymbolTableMap_ = {}; + DoubleMap pidAndipsToCallId_; + uint64_t callChainId_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_BASE_H diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_data_parser.cpp b/trace_streamer/src/parser/ebpf_parser/ebpf_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca33adec6a126a43dca48b7f32b0ac10b3c520d6 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_data_parser.cpp @@ -0,0 +1,82 @@ +/* + * 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 "ebpf_data_parser.h" +#include "stat_filter.h" + +namespace SysTuning { +namespace TraceStreamer { +EbpfDataParser::EbpfDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx), + EbpfBase(dataCache, ctx), + FileSystemDataParser(dataCache, ctx), + PagedMemoryDataParser(dataCache, ctx), + BioLatencyDataParser(dataCache, ctx), + reader_(std::make_unique(dataCache, ctx)) +{ +} +EbpfDataParser::~EbpfDataParser() +{ + TS_LOGI("EBPF all event data ts MIN:%llu, MAX:%llu", static_cast(ebpfAllEventStartTime_), + static_cast(ebpfAllEventEndTime_)); +} + +bool EbpfDataParser::Init(const std::deque dequeBuffer, uint64_t size) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF, STAT_EVENT_RECEIVED); + if (!reader_->InitEbpfData(dequeBuffer, size)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF, STAT_EVENT_NOTSUPPORTED); + TS_LOGE("InitEbpfData failed!"); + return false; + } + if (!InitEbpfDataParser(reader_.get())) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF, STAT_EVENT_NOTSUPPORTED); + return false; + } + return true; +} + +void EbpfDataParser::InitAndParseEbpfData(const std::deque& dequeBuffer, uint64_t size) +{ + if (!Init(dequeBuffer, size)) { + return; + } + if (reader_->GetFileSystemEventMap().size()) { + ParseFileSystemEvent(); + } + if (reader_->GetPagedMemoryMap().size()) { + ParsePagedMemoryEvent(); + } + if (reader_->GetBIOSampleMap().size()) { + ParseBioLatencyEvent(); + } +} + +void EbpfDataParser::Finish() +{ + ebpfAllEventStartTime_ = std::min(FileSystemDataParser::timeParser_->GetPluginStartTime(), ebpfAllEventStartTime_); + ebpfAllEventStartTime_ = std::min(PagedMemoryDataParser::timeParser_->GetPluginStartTime(), ebpfAllEventStartTime_); + ebpfAllEventStartTime_ = std::min(BioLatencyDataParser::timeParser_->GetPluginStartTime(), ebpfAllEventStartTime_); + ebpfAllEventEndTime_ = std::max(FileSystemDataParser::timeParser_->GetPluginEndTime(), ebpfAllEventEndTime_); + ebpfAllEventEndTime_ = std::max(PagedMemoryDataParser::timeParser_->GetPluginEndTime(), ebpfAllEventEndTime_); + ebpfAllEventEndTime_ = std::max(BioLatencyDataParser::timeParser_->GetPluginEndTime(), ebpfAllEventEndTime_); + // Update trace_range when there is only ebpf data in the trace file + if (traceDataCache_->traceStartTime_ == INVALID_UINT64 || traceDataCache_->traceEndTime_ == 0) { + traceDataCache_->MixTraceTime(ebpfAllEventStartTime_, ebpfAllEventEndTime_); + } else { + TS_LOGI("EBPF data time is not updated, maybe this trace file has other data"); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_data_parser.h b/trace_streamer/src/parser/ebpf_parser/ebpf_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..0143f4b5c0d3cf12a8c051fac28524b5911c795f --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_data_parser.h @@ -0,0 +1,46 @@ +/* + * 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 EBPF_DATA_PARSER_H +#define EBPF_DATA_PARSER_H +#include "bio_latency_data_parser.h" +#include "ebpf_data_reader.h" +#include "ebpf_stdtype.h" +#include "file_system_data_parser.h" +#include "paged_memory_data_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class EbpfDataParser : public FileSystemDataParser, public PagedMemoryDataParser, public BioLatencyDataParser { +public: + EbpfDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~EbpfDataParser(); + void InitAndParseEbpfData(const std::deque& dequeBuffer, uint64_t size); + void Finish(); + bool SupportImportSymbolTable() + { + return reader_ ? true : false; + } + +private: + bool Init(const std::deque dequeBuffer, uint64_t size); + std::unique_ptr reader_; + uint64_t ebpfAllEventStartTime_ = std::numeric_limits::max(); + uint64_t ebpfAllEventEndTime_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_DATA_PARSER_H diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.cpp b/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6ec04fe050449c598ea5cd2a8ff304bc720cc44 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.cpp @@ -0,0 +1,397 @@ +/* + * 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 "ebpf_data_reader.h" +#include "file_system_data_parser.h" +#include "string_help.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +using namespace SysTuning::EbpfStdtype; +EbpfDataReader::EbpfDataReader(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : EventParserBase(dataCache, filter), + ebpfDataHeader_(reinterpret_cast(startAddr_)), + pidAndStartAddrToMapsAddr_(nullptr), + elfAddrAndStValueToSymAddr_(nullptr), + tracerEventToStrIndex_(INVALID_UINT64), + kernelFilePath_(traceDataCache_->GetDataIndex("/proc/kallsyms")) +{ +} +bool EbpfDataReader::InitEbpfData(const std::deque& dequeBuffer, uint64_t size) +{ + buffer_ = std::make_unique(size); + std::copy(dequeBuffer.begin(), dequeBuffer.begin() + size, buffer_.get()); + + startAddr_ = buffer_.get(); + bufferSize_ = size; + unresolvedLen_ = size; + if (!InitEbpfHeader() || !ReadEbpfData()) { + return false; + } + return true; +} + +bool EbpfDataReader::InitEbpfHeader() +{ + if (bufferSize_ < EbpfDataHeader::EBPF_DATA_HEADER_SIZE) { + TS_LOGE("buffer size less than ebpf data header!!!, bufferSize_ = %lu ", bufferSize_); + return false; + } + ebpfDataHeader_ = reinterpret_cast(startAddr_); + + if (ebpfDataHeader_->header.magic != EbpfDataHeader::HEADER_MAGIC) { + TS_LOGE("Get EBPF file header failed! magic = %lx", ebpfDataHeader_->header.magic); + return false; + } + if (ebpfDataHeader_->header.headSize != EbpfDataHeader::EBPF_DATA_HEADER_SIZE) { + TS_LOGE("Get ebpf file header failed! headSize = %u", ebpfDataHeader_->header.headSize); + return false; + } + TS_LOGI("EBPF data header : magic = %llx, headSize = %llu, clock = %llu, cmdline = %s", + ebpfDataHeader_->header.magic, ebpfDataHeader_->header.headSize, ebpfDataHeader_->header.clock, + ebpfDataHeader_->cmdline); + startAddr_ += EbpfDataHeader::EBPF_DATA_HEADER_SIZE; + unresolvedLen_ -= EbpfDataHeader::EBPF_DATA_HEADER_SIZE; + return true; +} + +bool EbpfDataReader::ReadEbpfData() +{ + while (unresolvedLen_ > EBPF_TITLE_SIZE) { + EbpfTypeAndLength* dataTitle = reinterpret_cast(startAddr_); + startAddr_ += EBPF_TITLE_SIZE; + unresolvedLen_ -= EBPF_TITLE_SIZE; + if (dataTitle->length > unresolvedLen_) { + TS_LOGE("Get EBPF data Title failed!"); + TS_LOGE("type = %lx, length = %lx", dataTitle->type, dataTitle->length); + return false; + } + if (dataTitle->length == 0) { + continue; + } + + bool ret = true; + switch (dataTitle->type) { + case ITEM_EVENT_MAPS: { + ret = ReadItemEventMaps(startAddr_, dataTitle->length); + break; + } + case ITEM_SYMBOL_INFO: { + ret = ReadItemSymbolInfo(startAddr_, dataTitle->length); + break; + } + case ITEM_EVENT_FS: { + ret = ReadItemEventFs(startAddr_, dataTitle->length); + break; + } + case ITEM_EVENT_VM: { + ret = ReadItemEventPagedMemory(startAddr_, dataTitle->length); + break; + } + case ITEM_EVENT_BIO: { + ret = ReadItemEventBIO(startAddr_, dataTitle->length); + break; + } + case ITEM_EVENT_STR: { + ret = ReadItemEventStr(startAddr_, dataTitle->length); + break; + } + case ITEM_EVENT_KENEL_SYMBOL_INFO: { + ret = ReaItemKernelSymbolInfo(startAddr_, dataTitle->length); + break; + } + default: + TS_LOGI("Do not support EBPF type: %d, length: %d", dataTitle->type, dataTitle->length); + } + if (!ret) { + return false; + } + startAddr_ += dataTitle->length; + unresolvedLen_ -= dataTitle->length; + } + return true; +} + +bool EbpfDataReader::ReadItemEventMaps(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(MapsFixedHeader)) { + TS_LOGE("get maps addr Failed!!!"); + return false; + } + auto procMapsAddr = reinterpret_cast(buffer); + pidAndStartAddrToMapsAddr_.Insert(procMapsAddr->pid, procMapsAddr->start, procMapsAddr); +#if WITH_EBPF_HELP + if ((procMapsAddr->fileNameLen > size - sizeof(MapsFixedHeader)) || !procMapsAddr->fileNameLen) { + TS_LOGE("maps fileNameLen error!!!"); + return false; + } + auto fileNameAddr = const_cast(reinterpret_cast(procMapsAddr + 1)); + fileNameAddr[procMapsAddr->fileNameLen - 1] = '\0'; + auto fileNameIndex = traceDataCache_->GetDataIndex(fileNameAddr); + + // add proc Maps Data + traceDataCache_->GetEbpfProcessMaps()->AppendNewData(procMapsAddr->start, procMapsAddr->end, procMapsAddr->offset, + procMapsAddr->pid, procMapsAddr->fileNameLen, fileNameIndex); +#endif + return true; +} +template +void EbpfDataReader::AddSymbolsToTable(T* firstSymbolAddr, const int size, const ElfEventFixedHeader* elfAddr) +{ + for (auto i = 0; i < size; i++) { + auto symAddr = firstSymbolAddr + i; + if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) { + elfAddrAndStValueToSymAddr_.Insert(elfAddr, symAddr->st_value, reinterpret_cast(symAddr)); + } + } +} +void EbpfDataReader::UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size) +{ + if (size < sizeof(ElfEventFixedHeader) + elfAddr->strTabLen + elfAddr->symTabLen + elfAddr->fileNameLen) { + TS_LOGE("elf addr size error!!!"); + return; + } + auto symEntLen = elfAddr->symEntLen; + auto symTabHeadAddr = reinterpret_cast(elfAddr + 1) + elfAddr->strTabLen; + if (symEntLen == ELF32_SYM) { + AddSymbolsToTable(reinterpret_cast(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr); + } else { + AddSymbolsToTable(reinterpret_cast(symTabHeadAddr), elfAddr->symTabLen / symEntLen, elfAddr); + } +} +void EbpfDataReader::ReadKernelSymAddrMap(const KernelSymbolInfoHeader* elfAddr, uint32_t size) +{ + if (size < sizeof(KernelSymbolInfoHeader) + elfAddr->symTabLen + elfAddr->strTabLen) { + TS_LOGE("elf addr size error!!!, size is:%u and the symTabLen is:%u, strTabLen is:%u", size, elfAddr->symTabLen, + elfAddr->strTabLen); + return; + } + auto symTabLen = elfAddr->symTabLen; + auto sysItemSize = symTabLen / sizeof(KernelSymItem); + auto start = reinterpret_cast(elfAddr + 1); + auto strTab = reinterpret_cast(start + sysItemSize); + maxKernelAddr_ = elfAddr->vaddrEnd; + minKernelAddr_ = elfAddr->vaddrStart; + for (auto i = 0; i < sysItemSize; i++) { + (void*)memset_s(strSymbolName_, MAX_SYMBOL_LENGTH, 0, MAX_SYMBOL_LENGTH); + auto item = start + i; + if (strncpy_s(strSymbolName_, MAX_SYMBOL_LENGTH, strTab + item->nameOffset, MAX_SYMBOL_LENGTH) < 0) { + TS_LOGE("get kernel symbol name error"); + } + AddrDesc desc{item->size, traceDataCache_->dataDict_.GetStringIndex(strSymbolName_)}; + kernelSymbolMap_.insert(std::make_pair(item->value, desc)); + } +} + +void EbpfDataReader::UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size) +{ + if ((elfAddr->fileNameLen > size - sizeof(ElfEventFixedHeader) - elfAddr->strTabLen - elfAddr->symTabLen) || + !elfAddr->fileNameLen) { + TS_LOGE("elf filename len is error!!!"); + return; + } + + uint64_t fileNameIndex = INVALID_UINT64; + auto fileNameAddr = const_cast(reinterpret_cast(reinterpret_cast(elfAddr + 1) + + elfAddr->strTabLen + elfAddr->symTabLen)); + fileNameAddr[elfAddr->fileNameLen - 1] = '\0'; + fileNameIndex = traceDataCache_->GetDataIndex(std::string(fileNameAddr)); + elfPathIndexToElfFixedHeaderAddr_.insert(std::make_pair(fileNameIndex, elfAddr)); + +#if WITH_EBPF_HELP + // add Elf symbol Data + traceDataCache_->GetEbpfElf()->AppendNewData(elfId_, elfAddr->textVaddr, elfAddr->textOffset, elfAddr->strTabLen, + elfAddr->symTabLen, elfAddr->fileNameLen, elfAddr->symEntLen, + fileNameIndex); +#endif +} + +#if WITH_EBPF_HELP +template +void EbpfDataReader::AppendSymbolsToTable(T* firstSymbolAddr, const int size) +{ + for (auto i = 0; i < size; i++) { + auto symAddr = firstSymbolAddr + i; + if ((symAddr->st_info & STT_FUNC) && symAddr->st_value) { + traceDataCache_->GetEbpfElfSymbol()->AppendNewData(elfId_, symAddr->st_name, symAddr->st_value, + symAddr->st_size); + } + } +} +void EbpfDataReader::UpdateEbpfElfSymbolTable(const ElfEventFixedHeader* elfAddr, uint32_t size) +{ + if (size < sizeof(ElfEventFixedHeader) + elfAddr->strTabLen + elfAddr->symTabLen + elfAddr->fileNameLen) { + TS_LOGE("elf addr size error!!!"); + return; + } + auto symEntLen = elfAddr->symEntLen; + if (symEntLen == ELF32_SYM) { + AppendSymbolsToTable( + reinterpret_cast(reinterpret_cast(elfAddr + 1) + elfAddr->strTabLen), + elfAddr->symTabLen / symEntLen); + } else { + AppendSymbolsToTable( + reinterpret_cast(reinterpret_cast(elfAddr + 1) + elfAddr->strTabLen), + elfAddr->symTabLen / symEntLen); + } +} +#endif + +bool EbpfDataReader::ReadItemSymbolInfo(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(ElfEventFixedHeader)) { + TS_LOGE("get symbol addr failed!!!"); + return false; + } + auto elfAddr = reinterpret_cast(buffer); + UpdateElfAddrAndStValueToSymAddrMap(elfAddr, size); + UpdateElfPathIndexToElfAddrMap(elfAddr, size); +#if WITH_EBPF_HELP + UpdateEbpfElfSymbolTable(elfAddr, size); + elfId_++; +#endif + return true; +} + +bool EbpfDataReader::ReaItemKernelSymbolInfo(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(KernelSymbolInfoHeader)) { + TS_LOGE("get symbol addr failed!!!"); + return false; + } + auto elfAddr = reinterpret_cast(buffer); + ReadKernelSymAddrMap(elfAddr, size); + return true; +} +bool EbpfDataReader::ReadItemEventFs(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(FsFixedHeader)) { + TS_LOGE("get file system event addr failed!!!"); + return false; + } + auto fsFixedHeaderAddr = reinterpret_cast(buffer); + endTsToFsFixedHeader_.insert(std::make_pair(fsFixedHeaderAddr->endTime, fsFixedHeaderAddr)); + return true; +} + +bool EbpfDataReader::ReadItemEventPagedMemory(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(PagedMemoryFixedHeader)) { + TS_LOGE("get page memory event addr failed!!!"); + return false; + } + auto pagedMemoryFixedHeaderAddr = reinterpret_cast(buffer); + endTsToPagedMemoryFixedHeader_.insert( + std::make_pair(pagedMemoryFixedHeaderAddr->endTime, pagedMemoryFixedHeaderAddr)); + return true; +} + +bool EbpfDataReader::ReadItemEventBIO(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(BIOFixedHeader)) { + TS_LOGE("get Block IO event addr failed!!!"); + return false; + } + auto bioFixedHeaderAddr = reinterpret_cast(buffer); + endTsToBIOFixedHeader_.insert(std::make_pair(bioFixedHeaderAddr->endTime, bioFixedHeaderAddr)); + return true; +} + +bool EbpfDataReader::ReadItemEventStr(const uint8_t* buffer, uint32_t size) +{ + if (size < sizeof(StrEventFixedHeader)) { + TS_LOGE("get str event addr failed!!!"); + return false; + } + auto strFixedHeaderAddr = reinterpret_cast(buffer); + auto itid = + streamFilters_->processFilter_->GetOrCreateThreadWithPid(strFixedHeaderAddr->tid, strFixedHeaderAddr->pid); + auto strAddr = const_cast(reinterpret_cast(strFixedHeaderAddr + 1)); + if ((strFixedHeaderAddr->strLen > size - sizeof(StrEventFixedHeader)) || !strFixedHeaderAddr->strLen) { + TS_LOGE("invalid str event, strEventFixedHeader = %u, strlen = %d, size = %d", sizeof(StrEventFixedHeader), + strFixedHeaderAddr->strLen, size); + return true; + } + strAddr[strFixedHeaderAddr->strLen - 1] = '\0'; + auto strIndex = traceDataCache_->GetDataIndex(strAddr); + tracerEventToStrIndex_.Insert(strFixedHeaderAddr->srcTracer, strFixedHeaderAddr->srcType, itid, + strFixedHeaderAddr->startTime, strIndex); + return true; +} + +QuatraMap& EbpfDataReader::GetTracerEventToStrIndexMap() +{ + return tracerEventToStrIndex_; +} + +SymbolAndFilePathIndex EbpfDataReader::GetSymbolNameIndexFromElfSym(uint64_t ip) +{ + SymbolAndFilePathIndex symbolAndFilePathIndex(false); + auto end = kernelSymbolMap_.upper_bound(ip); + auto length = std::distance(kernelSymbolMap_.begin(), end); + if (length > 0) { + end--; + // Follow the rules of front closing and rear opening, [start, end) + if (ip < end->first + end->second.size) { + symbolAndFilePathIndex.flag = true; + symbolAndFilePathIndex.symbolIndex = end->second.name; + symbolAndFilePathIndex.filePathIndex = kernelFilePath_; + // TS_LOGD("ok for ip:%lu, kernelip:%lu, size:%lu", ip, end->first, end->second.size); + } else { + TS_LOGD("failed for ip:%lu, kernelip:%lu, size:%lu", ip, end->first, end->second.size); + } + } + if (!symbolAndFilePathIndex.flag) { + TS_LOGD("failed for ip:%lu", ip); + } + return symbolAndFilePathIndex; +} +const DoubleMap& EbpfDataReader::GetPidAndStartAddrToMapsAddr() const +{ + return pidAndStartAddrToMapsAddr_; +} + +const DoubleMap& + EbpfDataReader::GetElfAddrAndStartValueToSymAddr() const +{ + return elfAddrAndStValueToSymAddr_; +} + +const std::multimap& EbpfDataReader::GetFileSystemEventMap() const +{ + return endTsToFsFixedHeader_; +} + +const std::multimap& EbpfDataReader::GetPagedMemoryMap() const +{ + return endTsToPagedMemoryFixedHeader_; +} + +const std::multimap& EbpfDataReader::GetBIOSampleMap() const +{ + return endTsToBIOFixedHeader_; +} + +const std::map& EbpfDataReader::GetElfPathIndexToElfAddr() const +{ + return elfPathIndexToElfFixedHeaderAddr_; +} +const EbpfDataHeader* EbpfDataReader::GetEbpfDataHeader() const +{ + return const_cast(ebpfDataHeader_); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h b/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..586bfd88aab63c9b2e11281aa3838d2c9fcfb9e8 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_data_reader.h @@ -0,0 +1,98 @@ +/* + * 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 EBPF_DATA_READER_H +#define EBPF_DATA_READER_H +#include +#include +#include "ebpf_stdtype.h" +#include "htrace_plugin_time_parser.h" +#include "process_filter.h" +#include "quatra_map.h" +#include "string_help.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "unordered_map" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::EbpfStdtype; +class EbpfDataReader : private EventParserBase { +public: + EbpfDataReader(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~EbpfDataReader() = default; + bool InitEbpfData(const std::deque& dequeBuffer, uint64_t size); + const EbpfDataHeader* GetEbpfDataHeader() const; + const std::multimap& GetFileSystemEventMap() const; + const std::multimap& GetPagedMemoryMap() const; + const std::multimap& GetBIOSampleMap() const; + const DoubleMap& GetPidAndStartAddrToMapsAddr() const; + const DoubleMap& GetElfAddrAndStartValueToSymAddr() const; + const std::map& GetElfPathIndexToElfAddr() const; + QuatraMap& GetTracerEventToStrIndexMap(); + SymbolAndFilePathIndex GetSymbolNameIndexFromElfSym(uint64_t ip); + +private: + bool ReadEbpfData(); + bool InitEbpfHeader(); + bool ReadItemEventMaps(const uint8_t* buffer, uint32_t size); + bool ReadItemSymbolInfo(const uint8_t* buffer, uint32_t size); + bool ReaItemKernelSymbolInfo(const uint8_t* buffer, uint32_t size); + bool ReadItemEventFs(const uint8_t* buffer, uint32_t size); + bool ReadItemEventPagedMemory(const uint8_t* buffer, uint32_t size); + bool ReadItemEventBIO(const uint8_t* buffer, uint32_t size); + bool ReadItemEventStr(const uint8_t* buffer, uint32_t size); + template + void AddSymbolsToTable(T* firstSymbolAddr, const int size, const ElfEventFixedHeader* elfAddr); + void UpdateElfAddrAndStValueToSymAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size); + void ReadKernelSymAddrMap(const KernelSymbolInfoHeader* elfAddr, uint32_t size); + void UpdateElfPathIndexToElfAddrMap(const ElfEventFixedHeader* elfAddr, uint32_t size); +#if WITH_EBPF_HELP + template + void AppendSymbolsToTable(T* firstSymbolAddr, const int size); + void UpdateEbpfElfSymbolTable(const ElfEventFixedHeader* elfAddr, uint32_t size); +#endif +public: + uint64_t maxKernelAddr_ = 0; + uint64_t minKernelAddr_ = std::numeric_limits::max(); + +private: + std::unique_ptr buffer_; + uint64_t bufferSize_ = 0; + uint64_t unresolvedLen_ = 0; + EbpfDataHeader* ebpfDataHeader_; + uint8_t* startAddr_ = nullptr; +#if WITH_EBPF_HELP + uint64_t elfId_ = 0; +#endif + std::multimap endTsToFsFixedHeader_ = {}; + std::multimap endTsToPagedMemoryFixedHeader_ = {}; + std::multimap endTsToBIOFixedHeader_ = {}; + std::map elfPathIndexToElfFixedHeaderAddr_ = {}; + DoubleMap pidAndStartAddrToMapsAddr_; + DoubleMap elfAddrAndStValueToSymAddr_; + QuatraMap tracerEventToStrIndex_; + DataIndex kernelFilePath_; + struct AddrDesc { + uint64_t size = 0; + DataIndex name = 0; + }; + std::map kernelSymbolMap_ = {}; + static const uint32_t MAX_SYMBOL_LENGTH = 256; + char strSymbolName_[MAX_SYMBOL_LENGTH] = {0}; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_DATA_READER_H diff --git a/trace_streamer/src/parser/ebpf_parser/ebpf_stdtype.h b/trace_streamer/src/parser/ebpf_parser/ebpf_stdtype.h new file mode 100644 index 0000000000000000000000000000000000000000..fd80bb6fa6ed18c6333be38bceaafec51bdc261f --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/ebpf_stdtype.h @@ -0,0 +1,206 @@ +/* + * 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 EBPF_DATA_STD_TYPE_H +#define EBPF_DATA_STD_TYPE_H +#include +#include +#include "ts_common.h" +namespace SysTuning { +namespace EbpfStdtype { +struct EbpfDataHeader { + static constexpr uint32_t EBPF_DATA_HEADER_SIZE = 1024; + static constexpr uint64_t HEADER_MAGIC = 0x454C494646504245uLL; + struct HeaderData { + uint64_t magic = HEADER_MAGIC; + uint32_t headSize = EBPF_DATA_HEADER_SIZE; + uint32_t version; + uint32_t clock; + uint32_t cmdLineLen; + } __attribute__((packed)); + static constexpr uint32_t EBPF_COMMAND_MAX_SIZE = EBPF_DATA_HEADER_SIZE - sizeof(HeaderData); + HeaderData header; + char cmdline[EBPF_COMMAND_MAX_SIZE] = {'\0'}; +}; + +enum EBPF_DATA_TYPE { + ITEM_EVENT_MAPS = 0, + ITEM_SYMBOL_INFO, + ITEM_EVENT_FS, + ITEM_EVENT_VM, + ITEM_EVENT_BIO, + ITEM_EVENT_STR, + ITEM_EVENT_KENEL_SYMBOL_INFO = 0x10001, +}; + +struct EbpfTypeAndLength { + uint32_t type = 0; + uint32_t length = 0; +} __attribute__((packed)); +const uint32_t EBPF_TITLE_SIZE = sizeof(EbpfTypeAndLength); + +struct MapsFixedHeader { + uint64_t start = 0; + uint64_t end = 0; + uint32_t offset = 0; + uint32_t pid = 0; + uint32_t fileNameLen = 0; +} __attribute__((packed)); + +enum SYSTEM_ENTRY_VALUE { ELF32_SYM = 16, ELF64_SYM = 24 }; + +struct ElfEventFixedHeader { + uint64_t textVaddr = 0; + uint32_t textOffset = 0; + uint32_t strTabLen = 0; + uint32_t symTabLen = 0; + uint32_t fileNameLen = 0; + // value range: SYSTEM_ENTRY_LENGTH + uint32_t symEntLen = 0; +} __attribute__((packed)); +// the data following are +// uint8_t aa[strTabLen] // xx, bb, cc, dd +// uint8_t bb[symTabLen] //symEntLen elf64_sym, lef32_sym + +const int32_t ARGS_MAX = 4; +const int32_t MAX_TRACER_SIZE = 8; +const int32_t SINGLE_IP_SIZE = 8; +const int32_t MAX_FS_EVENT_SZIE = 16; +const int32_t MAX_PROCESS_NAME_SZIE = 16; +struct FsFixedHeader { + uint32_t pid = 0; + uint32_t tid = 0; + char tracerName[MAX_TRACER_SIZE] = {0}; + uint64_t startTime = 0; + uint64_t endTime = 0; + char eventType[MAX_FS_EVENT_SZIE] = {0}; + int32_t ret = 0; + uint16_t nrUserIPs = 0; + uint16_t type = 0; + uint64_t args[ARGS_MAX] = {0}; + char processName[MAX_PROCESS_NAME_SZIE] = {0}; +} __attribute__((packed)); +// the data following are ips ... + +const int32_t MAX_TRACER_NAME_LEN = 8; +const int32_t MAX_TYPE_NAME_LEN = 16; +const int32_t MAX_COMM_LEN = 16; +struct PagedMemoryFixedHeader { + uint32_t pid = 0; + uint32_t tid = 0; + char tagName[MAX_TRACER_NAME_LEN] = {0}; + uint64_t startTime = 0; + uint64_t endTime = 0; + char typeName[MAX_TYPE_NAME_LEN] = {0}; + uint64_t addr = 0; + uint32_t size = 0; + uint16_t nips = 0; + uint16_t type = 0; + char comm[MAX_COMM_LEN] = {0}; +} __attribute__((packed)); + +struct BIOFixedHeader { + uint32_t pid = 0; + uint32_t tid = 0; + char processName[MAX_PROCESS_NAME_SZIE] = {0}; + uint64_t startTime = 0; + uint64_t endTime = 0; + uint32_t prio = 0; + uint32_t size = 0; + uint64_t blkcnt = 0; + uint32_t nips = 0; + uint32_t type = 0; + char typeName[MAX_PROCESS_NAME_SZIE] = {0}; +} __attribute__((packed)); + +struct StrEventFixedHeader { + uint32_t pid = 0; + uint32_t tid = 0; + uint64_t startTime = 0; + uint32_t srcTracer = 0; + uint32_t srcType = 0; + uint32_t strLen = 0; + uint32_t padding = 0; +} __attribute__((packed)); + +struct KernelSymbolInfoHeader { + uint64_t vaddrStart = 0; + uint64_t vaddrEnd = 0; + uint32_t symTabLen = 0; + uint32_t strTabLen = 0; + // char* symTab = 0; // this is following the struct + // char* strTab = 0; // the symbols will follow the symTab +} __attribute__((packed)); + +struct KernelSymItem { + uint64_t value = 0; + uint32_t size = 0; + uint32_t nameOffset = 0; +} __attribute__((packed)); + +// EBPF clock relation +enum EbpfClockType { + EBPF_CLOCK_REALTIME = 0, + EBPF_CLOCK_BOOTTIME, + EBPF_CLOCK_MONOTONIC, + EBPF_CLOCK_MONOTONIC_RAW, +}; + +const std::map ebpfToTSClockType_ = { + {EBPF_CLOCK_REALTIME, TS_CLOCK_REALTIME}, + {EBPF_CLOCK_BOOTTIME, TS_CLOCK_BOOTTIME}, + {EBPF_CLOCK_MONOTONIC, TS_MONOTONIC}, + {EBPF_CLOCK_MONOTONIC_RAW, TS_MONOTONIC_RAW}, +}; + +struct SymbolAndFilePathIndex { + SymbolAndFilePathIndex() {} + SymbolAndFilePathIndex(bool invalidValue) : flag(invalidValue) {} + bool flag = false; + DataIndex symbolIndex = INVALID_UINT64; + DataIndex filePathIndex = INVALID_UINT64; +}; +// file system event type +enum FUC_SUB_TYPE { + SYS_OPENAT2 = 1, + SYS_READ = 2, + SYS_WRITE = 3, + SYS_PREAD64 = 4, + SYS_PWRITE64 = 5, + SYS_READV = 6, + SYS_WRITEV = 7, + SYS_PREADV = 8, + SYS_PWRITEV = 9, + SYS_CLOSE = 10, +}; + +const std::map subTypeToName = { + {SYS_OPENAT2, "openat2"}, {SYS_READ, "read"}, {SYS_WRITE, "write"}, {SYS_PREAD64, "pread64"}, + {SYS_PWRITE64, "pwrite64"}, {SYS_READV, "readv"}, {SYS_WRITEV, "writev"}, {SYS_PREADV, "preadv"}, + {SYS_PWRITEV, "pwritev"}, {SYS_CLOSE, "close"}}; + +enum FUC_SUMMARY_TYPE { + OPEN = 0, + CLOSE = 1, + READ = 2, + WRITE = 3, +}; +const std::map fucSubToSummaryType = { + {SYS_OPENAT2, OPEN}, {SYS_READ, READ}, {SYS_WRITE, WRITE}, {SYS_PREAD64, READ}, {SYS_PWRITE64, WRITE}, + {SYS_READV, READ}, {SYS_WRITEV, WRITE}, {SYS_PREADV, READ}, {SYS_PWRITEV, WRITE}, {SYS_CLOSE, CLOSE}, +}; +const uint32_t MIN_USER_IP = 0xffffffff; +} // namespace EbpfStdtype +} // namespace SysTuning +#endif // EBPF_DATA_STD_TYPE_H diff --git a/trace_streamer/src/parser/ebpf_parser/file_system_data_parser.cpp b/trace_streamer/src/parser/ebpf_parser/file_system_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f25ced090d336f11a4e484a20b331752cc02cf6e --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/file_system_data_parser.cpp @@ -0,0 +1,142 @@ +/* + * 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 "file_system_data_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" + +namespace SysTuning { +namespace TraceStreamer { +FileSystemDataParser::FileSystemDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx), + EbpfBase(dataCache, ctx), + timeParser_(std::make_unique(dataCache, ctx)) +{ +} +FileSystemDataParser::~FileSystemDataParser() +{ + TS_LOGI("EBPF FileSystem data ts MIN:%llu, MAX:%llu", + static_cast(timeParser_->GetPluginStartTime()), + static_cast(timeParser_->GetPluginEndTime())); +} +void FileSystemDataParser::ParseFileSystemEvent() +{ + if (!reader_->GetFileSystemEventMap().size()) { + return; + } + auto& tracerEventToStrIndexMap = reader_->GetTracerEventToStrIndexMap(); + for (auto mapItor = reader_->GetFileSystemEventMap().begin(); mapItor != reader_->GetFileSystemEventMap().end(); + mapItor++) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF_FILE_SYSTEM, STAT_EVENT_RECEIVED); + auto fsFixedHeadrAddr = mapItor->second; + bool callIdExistFlag = false; + + auto userIpsAddr = reinterpret_cast(fsFixedHeadrAddr + 1); + if (fsFixedHeadrAddr->nrUserIPs) { + std::string ipsToStr(reinterpret_cast(userIpsAddr), + fsFixedHeadrAddr->nrUserIPs * SINGLE_IP_SIZE); + auto ipsHashValue = hashFun_(ipsToStr); + auto value = pidAndipsToCallId_.Find(fsFixedHeadrAddr->pid, ipsHashValue); + if (value != INVALID_UINT64) { + callIdExistFlag = true; + currentCallId_ = value; + } else { + pidAndipsToCallId_.Insert(fsFixedHeadrAddr->pid, ipsHashValue, callChainId_); + currentCallId_ = callChainId_++; + } + } else { + currentCallId_ = INVALID_UINT64; + } + + uint16_t type = INVALID_UINT16; + auto tmp = fucSubToSummaryType.find(fsFixedHeadrAddr->type); + if (tmp == fucSubToSummaryType.end()) { + return; + } + type = fucSubToSummaryType.at(fsFixedHeadrAddr->type); + + // Init process name data + auto processName = const_cast(fsFixedHeadrAddr->processName); + processName[MAX_PROCESS_NAME_SZIE - 1] = '\0'; + uint32_t ipid = + streamFilters_->processFilter_->UpdateOrCreateProcessWithName(fsFixedHeadrAddr->pid, processName); + uint32_t itid = + streamFilters_->processFilter_->GetOrCreateThreadWithPid(fsFixedHeadrAddr->tid, fsFixedHeadrAddr->pid); + auto newStartTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(clockId_, fsFixedHeadrAddr->startTime); + timeParser_->UpdatePluginTimeRange(clockId_, fsFixedHeadrAddr->startTime, newStartTs); + auto newEndTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(clockId_, fsFixedHeadrAddr->endTime); + timeParser_->UpdatePluginTimeRange(clockId_, fsFixedHeadrAddr->endTime, newEndTs); + if (newStartTs > newEndTs) { + TS_LOGE("File system event origin startTs = %lu, endTs = %lu, newStartTs = %lu, newEndTs = %lu", + fsFixedHeadrAddr->startTime, fsFixedHeadrAddr->endTime, newStartTs, newEndTs); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF_FILE_SYSTEM, STAT_EVENT_DATA_INVALID); + return; + } + uint64_t duration = newEndTs - newStartTs; + DataIndex returnValue = INVALID_UINT64; + DataIndex errorCode = INVALID_UINT64; + if (fsFixedHeadrAddr->ret < 0) { + returnValue = ConvertToHexTextIndex(0); + errorCode = ConvertToHexTextIndex(-fsFixedHeadrAddr->ret); + } else { + returnValue = ConvertToHexTextIndex(fsFixedHeadrAddr->ret); + } + + int32_t i = 0; + auto firstArgument = ConvertToHexTextIndex(fsFixedHeadrAddr->args[i++]); + auto secondArgument = ConvertToHexTextIndex(fsFixedHeadrAddr->args[i++]); + auto thirdArgument = ConvertToHexTextIndex(fsFixedHeadrAddr->args[i++]); + auto fourthArgument = ConvertToHexTextIndex(fsFixedHeadrAddr->args[i]); + + // get file descriptor + auto fd = GetFileDescriptor(fsFixedHeadrAddr, type); + // get file path + uint64_t filePathId = INVALID_UINT64; + filePathId = + tracerEventToStrIndexMap.Find(ITEM_EVENT_FS, fsFixedHeadrAddr->type, itid, fsFixedHeadrAddr->startTime); + if (filePathId != INVALID_UINT64) { + tracerEventToStrIndexMap.Erase(ITEM_EVENT_FS, fsFixedHeadrAddr->type, itid, fsFixedHeadrAddr->startTime); + } + + // get read or writ size + size_t size = MAX_SIZE_T; + if ((type == READ || type == WRITE) && fsFixedHeadrAddr->ret >= 0) { + size = fsFixedHeadrAddr->ret; + } + + traceDataCache_->GetFileSystemSample()->AppendNewData( + currentCallId_, type, ipid, itid, newStartTs, newEndTs, duration, returnValue, errorCode, size, fd, + filePathId, firstArgument, secondArgument, thirdArgument, fourthArgument); + if (!callIdExistFlag) { + ParseCallStackData(userIpsAddr, fsFixedHeadrAddr->nrUserIPs, fsFixedHeadrAddr->pid, currentCallId_); + } + } +} + +int32_t FileSystemDataParser::GetFileDescriptor(const FsFixedHeader* fsFixedHeader, uint32_t fucType) +{ + auto returnValue = fsFixedHeader->ret; + int32_t fd = INVALID_INT32; + if (fucType == OPEN and returnValue >= 0) { + fd = returnValue; + } else if (fucType == READ or fucType == WRITE) { + fd = fsFixedHeader->args[0]; + } else if (fucType == CLOSE) { + fd = fsFixedHeader->args[1]; + } + return fd; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/ebpf_parser/file_system_data_parser.h b/trace_streamer/src/parser/ebpf_parser/file_system_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..c1f869ab3e55ebb7bbb8336bc8f0d779c927ad83 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/file_system_data_parser.h @@ -0,0 +1,40 @@ +/* + * 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 FILE_SYSTEM_DATA_PARSER_H +#define FILE_SYSTEM_DATA_PARSER_H +#include "clock_filter.h" +#include "double_map.h" +#include "ebpf_base.h" +#include "htrace_plugin_time_parser.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::EbpfStdtype; +class FileSystemDataParser : virtual public EbpfBase { +public: + FileSystemDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~FileSystemDataParser(); + void ParseFileSystemEvent(); + +protected: + std::unique_ptr timeParser_; + +private: + int32_t GetFileDescriptor(const FsFixedHeader* fsFixedHeader, uint32_t fucType); + uint64_t currentCallId_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // FILE_SYSTEM_DATA_PARSER_H diff --git a/trace_streamer/src/parser/ebpf_parser/paged_memory_data_parser.cpp b/trace_streamer/src/parser/ebpf_parser/paged_memory_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5e39f7559b4cba65fd92fe6e94e28b6e49d2755 --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/paged_memory_data_parser.cpp @@ -0,0 +1,95 @@ +/* + * 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 "paged_memory_data_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" + +namespace SysTuning { +namespace TraceStreamer { +PagedMemoryDataParser::PagedMemoryDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx), + EbpfBase(dataCache, ctx), + timeParser_(std::make_unique(dataCache, ctx)) +{ +} +PagedMemoryDataParser::~PagedMemoryDataParser() +{ + TS_LOGI("EBPF paged memory data ts MIN:%llu, MAX:%llu", + static_cast(timeParser_->GetPluginStartTime()), + static_cast(timeParser_->GetPluginEndTime())); +} +void PagedMemoryDataParser::ParsePagedMemoryEvent() +{ + if (!reader_->GetPagedMemoryMap().size()) { + return; + } + for (auto mapItor = reader_->GetPagedMemoryMap().begin(); mapItor != reader_->GetPagedMemoryMap().end(); + mapItor++) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF_PAGED_MEMORY, STAT_EVENT_RECEIVED); + auto pagedMemoryFixedHeadrAddr = mapItor->second; + bool callIdExistFlag = false; + + auto userIpsAddr = reinterpret_cast(pagedMemoryFixedHeadrAddr + 1); + if (pagedMemoryFixedHeadrAddr->nips) { + std::string ipsToStr(reinterpret_cast(userIpsAddr), + pagedMemoryFixedHeadrAddr->nips * SINGLE_IP_SIZE); + auto ipsHashValue = hashFun_(ipsToStr); + auto value = pidAndipsToCallId_.Find(pagedMemoryFixedHeadrAddr->pid, ipsHashValue); + if (value != INVALID_UINT64) { + callIdExistFlag = true; + currentCallId_ = value; + } else { + pidAndipsToCallId_.Insert(pagedMemoryFixedHeadrAddr->pid, ipsHashValue, callChainId_); + currentCallId_ = callChainId_++; + } + } else { + currentCallId_ = INVALID_UINT64; + } + + auto type = pagedMemoryFixedHeadrAddr->type; + // Init process name data + const char* processName = reinterpret_cast(pagedMemoryFixedHeadrAddr->comm); + uint32_t ipid = + streamFilters_->processFilter_->UpdateOrCreateProcessWithName(pagedMemoryFixedHeadrAddr->pid, processName); + uint32_t itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(pagedMemoryFixedHeadrAddr->tid, + pagedMemoryFixedHeadrAddr->pid); + uint64_t startTs = pagedMemoryFixedHeadrAddr->startTime; + uint64_t endTs = pagedMemoryFixedHeadrAddr->endTime; + auto newStartTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(clockId_, startTs); + timeParser_->UpdatePluginTimeRange(clockId_, startTs, newStartTs); + auto newEndTs = streamFilters_->clockFilter_->ToPrimaryTraceTime(clockId_, endTs); + timeParser_->UpdatePluginTimeRange(clockId_, endTs, newEndTs); + if (newStartTs > newEndTs) { + TS_LOGE("paged memory startTs = %lu, endTs = %lu, newStartTs = %lu, newEndTs = %lu", startTs, endTs, + newStartTs, newEndTs); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_EBPF_PAGED_MEMORY, STAT_EVENT_DATA_INVALID); + return; + } + uint64_t duration = newEndTs - newStartTs; + + auto addr = ConvertToHexTextIndex(pagedMemoryFixedHeadrAddr->addr); + auto size = pagedMemoryFixedHeadrAddr->size; + + traceDataCache_->GetPagedMemorySampleData()->AppendNewData(currentCallId_, type, ipid, newStartTs, newEndTs, + duration, size, addr, itid); + if (!callIdExistFlag) { + ParseCallStackData(userIpsAddr, pagedMemoryFixedHeadrAddr->nips, pagedMemoryFixedHeadrAddr->pid, + currentCallId_); + } + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/ebpf_parser/paged_memory_data_parser.h b/trace_streamer/src/parser/ebpf_parser/paged_memory_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..1e352387c6d117d757397fe3d382d3d4f80c122b --- /dev/null +++ b/trace_streamer/src/parser/ebpf_parser/paged_memory_data_parser.h @@ -0,0 +1,43 @@ +/* + * 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 PAGED_MEMORY_DATA_PARSER_H +#define PAGED_MEMORY_DATA_PARSER_H +#include "clock_filter.h" +#include "double_map.h" +#include "ebpf_base.h" +#include "ebpf_data_reader.h" +#include "ebpf_stdtype.h" +#include "event_parser_base.h" +#include "htrace_plugin_time_parser.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::EbpfStdtype; + +class PagedMemoryDataParser : virtual public EbpfBase { +public: + PagedMemoryDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~PagedMemoryDataParser(); + void ParsePagedMemoryEvent(); + +protected: + std::unique_ptr timeParser_; + +private: + uint32_t currentCallId_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PAGED_MEMORY_DATA_PARSER_H diff --git a/trace_streamer/src/parser/event_parser_base.cpp b/trace_streamer/src/parser/event_parser_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a4bdbf4f5e4e7ac919ecf6af18f1fe7b6e680f3d --- /dev/null +++ b/trace_streamer/src/parser/event_parser_base.cpp @@ -0,0 +1,24 @@ +/* + * 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 "event_parser_base.h" +namespace SysTuning { +namespace TraceStreamer { +EventParserBase::EventParserBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : streamFilters_(filter), traceDataCache_(dataCache) +{ +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/event_parser_base.h b/trace_streamer/src/parser/event_parser_base.h new file mode 100644 index 0000000000000000000000000000000000000000..60d0dd6b09be4e34a4f66e4895021ac5f5d176d3 --- /dev/null +++ b/trace_streamer/src/parser/event_parser_base.h @@ -0,0 +1,35 @@ +/* + * 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 SRC_EVENT_PARSER_BASE_H +#define SRC_EVENT_PARSER_BASE_H +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::TraceCfg; +class EventParserBase { +public: + EventParserBase(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + virtual ~EventParserBase() = default; + +public: + const TraceStreamerFilters* streamFilters_; + TraceDataCache* traceDataCache_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_PARSER_BASE_H diff --git a/trace_streamer/src/parser/hiperf_parser/BUILD.gn b/trace_streamer/src/parser/hiperf_parser/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..1bafb365cb695529a3d312c106a1a394cfa1aa02 --- /dev/null +++ b/trace_streamer/src/parser/hiperf_parser/BUILD.gn @@ -0,0 +1,68 @@ +# 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("../../ts.gni") +ohos_source_set("hiperf_parser_src") { + subsystem_name = "trace_streamer" + part_name = "hiperf_parser_src" + sources = [ "perf_data_parser.cpp" ] + include_dirs = [ + "//third_party/hiperf/include/nonlinux/linux", + ".", + "../../base", + "../../cfg", + "//third_party/hiperf/include/nonlinux", + "//third_party/hiperf/include", + "../../include", + "../../", + "../../filter", + "../../trace_data", + "..", + "../htrace_parser", + "../../trace_streamer", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + "//third_party/perf_include", + "//third_party/perf_include/libbpf", + ] + include_dirs += [ "//third_party/libunwind/include" ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} + +group("hiperf_parser") { + deps = [ + ":hiperf_parser_src", + "//third_party/hiperf:hiperf", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + if (target != "test" && !is_openharmony) { + deps += [ "//prebuilts/protos:ts_proto_data_cpp" ] + } +} diff --git a/trace_streamer/src/parser/hiperf_parser/perf_data_parser.cpp b/trace_streamer/src/parser/hiperf_parser/perf_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9901047074058eef5eb1f1aa17b62e53a3e6c89 --- /dev/null +++ b/trace_streamer/src/parser/hiperf_parser/perf_data_parser.cpp @@ -0,0 +1,336 @@ +/* + * 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 "perf_data_parser.h" +#include "file.h" +#include "perf_data_filter.h" +#include "stat_filter.h" + +namespace SysTuning { +namespace TraceStreamer { +PerfDataParser::PerfDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx), + configNameIndex_(traceDataCache_->dataDict_.GetStringIndex("config_name")), + workloaderIndex_(traceDataCache_->dataDict_.GetStringIndex("workload_cmd")), + cmdlineIndex_(traceDataCache_->dataDict_.GetStringIndex("cmdline")), + runingStateIndex_(traceDataCache_->dataDict_.GetStringIndex("Running")), + suspendStatIndex_(traceDataCache_->dataDict_.GetStringIndex("Suspend")), + unkonwnStateIndex_(traceDataCache_->dataDict_.GetStringIndex("-")), + frameToCallChainId_(INVALID_UINT32) +{ + SymbolsFile::onRecording_ = false; +} +void PerfDataParser::InitPerfDataAndLoad(const std::deque dequeBuffer, uint64_t size) +{ + bufferSize_ = size; + buffer_ = std::make_unique(size); + std::copy(dequeBuffer.begin(), dequeBuffer.begin() + size, buffer_.get()); + LoadPerfData(); +} +PerfDataParser::~PerfDataParser() +{ + (void)remove(tmpPerfData_.c_str()); + TS_LOGI("perf data ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} + +bool PerfDataParser::PerfReloadSymbolFiles(std::vector& symbolsPaths) +{ + if (access(tmpPerfData_.c_str(), F_OK) != 0) { + TS_LOGE("perf file:%s not exist", tmpPerfData_.c_str()); + return false; + } + recordDataReader_ = PerfFileReader::Instance(tmpPerfData_); + report_ = std::make_unique(); + report_->virtualRuntime_.SetSymbolsPaths(symbolsPaths); + if (recordDataReader_ == nullptr) { + return false; + } + if (Reload()) { + Finish(); + return true; + } else { + return false; + } +} +bool PerfDataParser::LoadPerfData() +{ + // try load the perf data + int32_t fd(base::OpenFile(tmpPerfData_, O_CREAT | O_RDWR, TS_PERMISSION_RW)); + if (!fd) { + fprintf(stdout, "Failed to create file: %s", tmpPerfData_.c_str()); + return false; + } + auto ret = ftruncate(fd, 0); + if (bufferSize_ != write(fd, buffer_.get(), bufferSize_)) { + close(fd); + return false; + } + recordDataReader_ = PerfFileReader::Instance(tmpPerfData_); + report_ = std::make_unique(); + buffer_.release(); + if (recordDataReader_ == nullptr) { + return false; + } + return Reload(); +} +bool PerfDataParser::Reload() +{ + frameToCallChainId_.Clear(); + fileDataDictIdToFileId_.clear(); + tidToPid_.clear(); + streamFilters_->perfDataFilter_->BeforeReload(); + traceDataCache_->GetPerfSampleData()->Clear(); + traceDataCache_->GetPerfThreadData()->Clear(); + + if (!recordDataReader_->ReadFeatureSection()) { + printf("record format error.\n"); + return false; + } + // update perf report table + UpdateEventConfigInfo(); + UpdateReportWorkloadInfo(); + UpdateCmdlineInfo(); + + // update perf Files table + UpdateSymbolAndFilesData(); + + TS_LOGD("process record"); + UpdateClockType(); + recordDataReader_->ReadDataSection(std::bind(&PerfDataParser::RecordCallBack, this, std::placeholders::_1)); + TS_LOGD("process record completed"); + TS_LOGI("load perf data done"); + return true; +} + +void PerfDataParser::UpdateEventConfigInfo() +{ + auto features = recordDataReader_->GetFeatures(); + cpuOffMode_ = find(features.begin(), features.end(), FEATURE::HIPERF_CPU_OFF) != features.end(); + if (cpuOffMode_) { + TS_LOGD("this is cpuOffMode "); + } + const PerfFileSection* featureSection = recordDataReader_->GetFeatureSection(FEATURE::EVENT_DESC); + if (featureSection) { + TS_LOGI("have EVENT_DESC"); + LoadEventDesc(); + } else { + TS_LOGE("Do not have EVENT_DESC !!!"); + } +} + +void PerfDataParser::LoadEventDesc() +{ + const auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::EVENT_DESC); + const auto& sectionEventdesc = *static_cast(featureSection); + TS_LOGI("Event descriptions: %zu", sectionEventdesc.eventDesces_.size()); + for (size_t i = 0; i < sectionEventdesc.eventDesces_.size(); i++) { + const auto& fileAttr = sectionEventdesc.eventDesces_[i]; + TS_LOGI("event name[%zu]: %s ids: %s", i, fileAttr.name.c_str(), VectorToString(fileAttr.ids).c_str()); + for (uint64_t id : fileAttr.ids) { + report_->configIdIndexMaps_[id] = report_->configs_.size(); // setup index + TS_LOGI("add config id map %" PRIu64 " to %zu", id, report_->configs_.size()); + } + // when cpuOffMode_ , don't use count mode , use time mode. + auto& config = report_->configs_.emplace_back(fileAttr.name, fileAttr.attr.type, fileAttr.attr.config, + cpuOffMode_ ? false : true); + config.ids_ = fileAttr.ids; + TS_ASSERT(config.ids_.size() > 0); + + auto perfReportData = traceDataCache_->GetPerfReportData(); + auto configValueIndex = traceDataCache_->dataDict_.GetStringIndex(fileAttr.name.c_str()); + perfReportData->AppendNewPerfReport(configNameIndex_, configValueIndex); + } +} + +void PerfDataParser::UpdateReportWorkloadInfo() const +{ + // workload + auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::HIPERF_WORKLOAD_CMD); + std::string workloader = ""; + if (featureSection) { + TS_LOGI("found HIPERF_META_WORKLOAD_CMD"); + auto sectionString = static_cast(featureSection); + workloader = sectionString->toString(); + } else { + TS_LOGW("NOT found HIPERF_META_WORKLOAD_CMD"); + } + if (workloader.empty()) { + TS_LOGW("NOT found HIPERF_META_WORKLOAD_CMD"); + return; + } + auto perfReportData = traceDataCache_->GetPerfReportData(); + auto workloaderValueIndex = traceDataCache_->dataDict_.GetStringIndex(workloader.c_str()); + perfReportData->AppendNewPerfReport(workloaderIndex_, workloaderValueIndex); +} + +void PerfDataParser::UpdateCmdlineInfo() const +{ + auto cmdline = recordDataReader_->GetFeatureString(FEATURE::CMDLINE); + auto perfReportData = traceDataCache_->GetPerfReportData(); + auto cmdlineValueIndex = traceDataCache_->dataDict_.GetStringIndex(cmdline.c_str()); + perfReportData->AppendNewPerfReport(cmdlineIndex_, cmdlineValueIndex); +} + +void PerfDataParser::UpdateSymbolAndFilesData() +{ + // we need unwind it (for function name match) even not give us path + report_->virtualRuntime_.SetDisableUnwind(false); + + // found symbols in file + const auto featureSection = recordDataReader_->GetFeatureSection(FEATURE::HIPERF_FILES_SYMBOL); + if (featureSection != nullptr) { + const PerfFileSectionSymbolsFiles* sectionSymbolsFiles = + static_cast(featureSection); + report_->virtualRuntime_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_); + } + // fileid, symbolIndex, filePathIndex + uint64_t fileId = 0; + for (auto& symbolsFile : report_->virtualRuntime_.GetSymbolsFiles()) { + auto filePathIndex = traceDataCache_->dataDict_.GetStringIndex(symbolsFile->filePath_.c_str()); + uint32_t serial = 0; + for (auto& symbol : symbolsFile->GetSymbols()) { + auto symbolIndex = traceDataCache_->dataDict_.GetStringIndex(symbol.Name().data()); + streamFilters_->statFilter_->IncreaseStat(TRACE_PERF, STAT_EVENT_RECEIVED); + streamFilters_->perfDataFilter_->AppendPerfFiles(fileId, serial++, symbolIndex, filePathIndex); + } + fileDataDictIdToFileId_.insert(std::make_pair(filePathIndex, fileId)); + ++fileId; + } +} +void PerfDataParser::UpdateClockType() +{ + const auto& attrIds_ = recordDataReader_->GetAttrSection(); + if (attrIds_.size() > 0) { + useClockId_ = attrIds_[0].attr.use_clockid; + clockId_ = attrIds_[0].attr.clockid; + TS_LOGE("useClockId_ = %u, clockId_ = %u", useClockId_, clockId_); + } +} +bool PerfDataParser::RecordCallBack(std::unique_ptr record) +{ + // tell process tree what happend for rebuild symbols + report_->virtualRuntime_.UpdateFromRecord(*record); + + if (record->GetType() == PERF_RECORD_SAMPLE) { + std::unique_ptr sample(static_cast(record.release())); + auto callChainId = UpdatePerfCallChainData(sample); + UpdatePerfSampleData(callChainId, sample); + } else if (record->GetType() == PERF_RECORD_COMM) { + auto recordComm = static_cast(record.get()); + auto range = tidToPid_.equal_range(recordComm->data_.tid); + for (auto it = range.first; it != range.second; it++) { + if (it->second == recordComm->data_.pid) { + return true; + } + } + tidToPid_.insert(std::make_pair(recordComm->data_.tid, recordComm->data_.pid)); + auto perfThreadData = traceDataCache_->GetPerfThreadData(); + auto threadNameIndex = traceDataCache_->dataDict_.GetStringIndex(recordComm->data_.comm); + perfThreadData->AppendNewPerfThread(recordComm->data_.pid, recordComm->data_.tid, threadNameIndex); + } + return true; +} + +uint32_t PerfDataParser::UpdatePerfCallChainData(std::unique_ptr& sample) +{ + uint64_t depth = 0; + bool callStackNotExist = false; + uint32_t callChainId = INVALID_UINT32; + std::vector> callStackTemp = {}; + // Filter callstack unuse data + for (auto frame = sample->callFrames_.rbegin(); frame != sample->callFrames_.rend(); ++frame) { + auto symbolId = frame->symbolIndex_; + if (symbolId == -1 && frame->vaddrInFile_ == 0) { + continue; + } + auto fileDataIndex = traceDataCache_->dataDict_.GetStringIndex(frame->filePath_); + auto itor = fileDataDictIdToFileId_.find(fileDataIndex); + if (itor == fileDataDictIdToFileId_.end()) { + continue; + } + auto fileId = itor->second; + callStackTemp.emplace_back( + std::move(std::make_unique(depth, frame->vaddrInFile_, fileId, symbolId))); + depth++; + } + // Determine whether to write callstack data to cache + auto size = callStackTemp.size(); + for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) { + auto callstack = itor->get(); + auto ret = frameToCallChainId_.Find(callstack->fileId_, callstack->symbolId_, callstack->depth_, size); + if (ret != INVALID_UINT32) { // find it + if (callChainId == INVALID_UINT32) { + callChainId = ret; + } else if (callChainId != ret) { + callStackNotExist = true; + break; + } + } else { // not find it + callStackNotExist = true; + break; + } + } + // write callstack data to cache + if (callStackNotExist) { + callChainId = ++callChainId_; + for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) { + auto callstack = itor->get(); + frameToCallChainId_.Insert(callstack->fileId_, callstack->symbolId_, callstack->depth_, + callStackTemp.size(), callChainId); + streamFilters_->perfDataFilter_->AppendPerfCallChain( + callChainId, callstack->depth_, callstack->vaddrInFile_, callstack->fileId_, callstack->symbolId_); + } + } + callStackTemp.clear(); + return callChainId; +} + +void PerfDataParser::UpdatePerfSampleData(uint32_t callChainId, std::unique_ptr& sample) +{ + auto perfSampleData = traceDataCache_->GetPerfSampleData(); + uint64_t newTimeStamp = 0; + if (useClockId_ == 0) { + newTimeStamp = sample->data_.time; + } else { + newTimeStamp = + streamFilters_->clockFilter_->ToPrimaryTraceTime(perfToTSClockType_.at(clockId_), sample->data_.time); + } + UpdatePluginTimeRange(perfToTSClockType_.at(clockId_), sample->data_.time, newTimeStamp); + + DataIndex threadStatIndex = unkonwnStateIndex_; + auto threadState = report_->GetConfigName(sample->data_.id); + if (threadState.compare(wakingEventName_) == 0) { + threadStatIndex = runingStateIndex_; + } else if (threadState.compare(cpuOffEventName_) == 0) { + threadStatIndex = suspendStatIndex_; + } + auto configIndex = report_->GetConfigIndex(sample->data_.id); + perfSampleData->AppendNewPerfSample(callChainId, sample->data_.time, sample->data_.tid, sample->data_.period, + configIndex, newTimeStamp, sample->data_.cpu, threadStatIndex); +} + +void PerfDataParser::Finish() +{ + streamFilters_->perfDataFilter_->Finish(); + // Update trace_range when there is only perf data in the trace file + if (traceDataCache_->traceStartTime_ == INVALID_UINT64 || traceDataCache_->traceEndTime_ == 0) { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + } else { + TS_LOGI("perfData time is not updated, maybe this trace file has other data"); + } + frameToCallChainId_.Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/hiperf_parser/perf_data_parser.h b/trace_streamer/src/parser/hiperf_parser/perf_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..306fc8dbb7630e73fd75c1a71b18a3e3e6b3c2c6 --- /dev/null +++ b/trace_streamer/src/parser/hiperf_parser/perf_data_parser.h @@ -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. + */ +#ifndef PERF_DATA_PARSER_H +#define PERF_DATA_PARSER_H +#include +#include +#include +#include +#include +#include "htrace_plugin_time_parser.h" +#include "log.h" +#include "perf_events.h" +#include "perf_file_format.h" +#include "perf_file_reader.h" +#include "quatra_map.h" +#include "report.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace OHOS::Developtools::HiPerf; +class PerfDataParser : public HtracePluginTimeParser { +public: + PerfDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~PerfDataParser(); + void InitPerfDataAndLoad(const std::deque dequeBuffer, uint64_t size); + void Finish(); + bool PerfReloadSymbolFiles(std::vector& symbolsPaths); + +private: + bool Reload(); + bool LoadPerfData(); + void UpdateEventConfigInfo(); + void UpdateCmdlineInfo() const; + void LoadEventDesc(); + void UpdateReportWorkloadInfo() const; + void UpdateSymbolAndFilesData(); + void UpdateClockType(); + bool RecordCallBack(std::unique_ptr record); + void UpdatePerfSampleData(uint32_t callChainId, std::unique_ptr& sample); + uint32_t UpdatePerfCallChainData(std::unique_ptr& sample); + + class CallStackTemp { + public: + CallStackTemp() {} + CallStackTemp(uint32_t depth, uint64_t vaddr, uint64_t fileId, uint32_t symbolId) + : depth_(depth), vaddrInFile_(vaddr), fileId_(fileId), symbolId_(symbolId) + { + } + ~CallStackTemp() {} + uint32_t depth_ = 0; + uint64_t vaddrInFile_ = 0; + uint64_t fileId_ = 0; + uint32_t symbolId_ = 0; + }; + uint32_t callChainId_ = 0; + std::unique_ptr recordDataReader_ = nullptr; + const std::string cpuOffEventName_ = "sched:sched_switch"; + const std::string wakingEventName_ = "sched:sched_waking"; + std::unique_ptr buffer_ = {}; + size_t bufferSize_ = 0; + bool cpuOffMode_ = false; + std::unique_ptr report_ = nullptr; + uint32_t useClockId_ = 0; + uint32_t clockId_ = 0; + enum PerfClockType { + PERF_CLOCK_REALTIME = 0, + PERF_CLOCK_MONOTONIC, + PERF_CLOCK_MONOTONIC_RAW = 4, + PERF_CLOCK_BOOTTIME = 7, + }; + DataIndex configNameIndex_ = 0; + DataIndex workloaderIndex_ = 0; + DataIndex cmdlineIndex_ = 0; + DataIndex runingStateIndex_ = 0; + DataIndex suspendStatIndex_ = 0; + DataIndex unkonwnStateIndex_ = 0; + std::unordered_multimap tidToPid_ = {}; + const std::map perfToTSClockType_ = {{PERF_CLOCK_REALTIME, TS_CLOCK_REALTIME}, + {PERF_CLOCK_MONOTONIC, TS_MONOTONIC}, + {PERF_CLOCK_MONOTONIC_RAW, TS_MONOTONIC_RAW}, + {PERF_CLOCK_BOOTTIME, TS_CLOCK_BOOTTIME}}; + std::map fileDataDictIdToFileId_ = {}; + QuatraMap frameToCallChainId_; + const std::string tmpPerfData_ = "ts_tmp.perf.data"; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PERF_DATA_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/BUILD.gn b/trace_streamer/src/parser/htrace_parser/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..e689eb8834a33924872ba01e1a0640f92614d9e4 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/BUILD.gn @@ -0,0 +1,125 @@ +# 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("../../ts.gni") +ohos_source_set("htrace_parser_src") { + subsystem_name = "trace_streamer" + part_name = "htrace_parser_src" + sources = [ + "../parser_base.cpp", + "htrace_clock_detail_parser.cpp", + "htrace_clock_detail_parser.h", + "htrace_cpu_data_parser.cpp", + "htrace_cpu_data_parser.h", + "htrace_cpu_parser/htrace_cpu_detail_parser.cpp", + "htrace_cpu_parser/htrace_cpu_detail_parser.h", + "htrace_disk_io_parser.cpp", + "htrace_disk_io_parser.h", + "htrace_event_parser/htrace_event_parser.cpp", + "htrace_event_parser/htrace_event_parser.h", + "htrace_file_header.h", + "htrace_hidump_parser.cpp", + "htrace_hidump_parser.h", + "htrace_hilog_parser.cpp", + "htrace_hilog_parser.h", + "htrace_hisysevent_parser.cpp", + "htrace_hisysevent_parser.h", + "htrace_mem_parser.cpp", + "htrace_mem_parser.h", + "htrace_native_hook_parser.cpp", + "htrace_native_hook_parser.h", + "htrace_network_parser.cpp", + "htrace_network_parser.h", + "htrace_parser.cpp", + "htrace_plugin_time_parser.cpp", + "htrace_plugin_time_parser.h", + "htrace_process_parser.cpp", + "htrace_process_parser.h", + "htrace_symbols_detail_parser.cpp", + "htrace_symbols_detail_parser.h", + ] + include_dirs = [ + ".", + "htrace_event_parser", + "htrace_cpu_parser", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "../../include", + "../../", + "../", + "../../trace_data", + "../../cfg", + "../../trace_streamer", + "//third_party/protobuf/src", + "//third_party/sqlite/include", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + "../../filter", + "../../base", + "../ebpf_parser", + ] + include_dirs += [ + "//third_party/libunwind/include", + "//third_party/libunwind/src", + ] + if (with_perf) { + include_dirs += [ + "//third_party/perf_include/musl", + "//third_party/hiperf/include", + "//third_party/hiperf/include/nonlinux", + "//third_party/hiperf/include/nonlinux/linux", + "//third_party/perf_include/libbpf", + "//third_party/perf_include/include", + "//third_party/perf_include", + "//third_party/perf_include/linux", + "../hiperf_parser", + "../hiperf_parser/include", + ] + } + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } + public_deps = [] + deps = [] +} +group("htrace_parser") { + deps = [ + ":htrace_parser_src", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + if (!use_wasm && !is_win && !is_macx && !is_test) { + deps += [ "//third_party/libunwind:libunwind" ] + } + if (target != "test" && !is_openharmony) { + deps += [ "//prebuilts/protos:ts_proto_data_cpp" ] + } +} diff --git a/trace_streamer/src/parser/htrace_parser/htrace_clock_detail_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_clock_detail_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82c06002ba2fef330a1f82df36bc7383af81aead --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_clock_detail_parser.cpp @@ -0,0 +1,110 @@ +/* + * 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 "htrace_clock_detail_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceClockDetailParser::HtraceClockDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters) + : EventParserBase(dataCache, filters) +{ + for (auto i = 0; i < MEM_MAX; i++) { + memNameDictMap_.insert( + std::make_pair(static_cast(i), + traceDataCache_->GetDataIndex(config_.memNameMap_.at(static_cast(i))))); + } +} + +HtraceClockDetailParser::~HtraceClockDetailParser() = default; +void HtraceClockDetailParser::Parse(TracePluginResult* tracePacket) const +{ + if (streamFilters_->clockFilter_->HasInitSnapShot()) { + TS_LOGW("already has clock snapshot!!!"); + return; + } + if (!tracePacket->clocks_detail_size()) { + TS_LOGE("!!! no clock snapshot"); + return; + } + std::vector snapShot; + TS_LOGI("got clock snapshot"); + for (int32_t i = 0; i < tracePacket->clocks_detail_size(); i++) { + auto clockInfo = tracePacket->mutable_clocks_detail(i); + TS_LOGI("clockid:%d, ts:%llu", clockInfo->id(), + static_cast(clockInfo->time().tv_nsec() + clockInfo->time().tv_sec() * SEC_TO_NS)); + snapShot.push_back(SnapShot{static_cast(clockInfo->id()), + clockInfo->time().tv_nsec() + clockInfo->time().tv_sec() * SEC_TO_NS}); + } + if (snapShot.size()) { + streamFilters_->clockFilter_->AddClockSnapshot(snapShot); + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SYNC, STAT_EVENT_RECEIVED); +} + +void HtraceClockDetailParser::Parse(const ProfilerTraceFileHeader* profilerTraceFileHeader) const +{ + if (streamFilters_->clockFilter_->HasInitSnapShot()) { + TS_LOGW("already has clock snapshot!!!"); + return; + } + if (!profilerTraceFileHeader->data.boottime) { + TS_LOGW("Profiler header has no clock snapshot!!!"); + return; + } + + std::vector snapShot; + TS_LOGI("got clock snapshot"); + + TS_LOGI("clockid: TS_CLOCK_BOOTTIME, ts:%llu", profilerTraceFileHeader->data.boottime); + if (profilerTraceFileHeader->data.boottime) { + snapShot.push_back(SnapShot{TS_CLOCK_BOOTTIME, profilerTraceFileHeader->data.boottime}); + } + + TS_LOGI("clockid: TS_CLOCK_REALTIME, ts:%llu", profilerTraceFileHeader->data.realtime); + if (profilerTraceFileHeader->data.realtime) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME, profilerTraceFileHeader->data.realtime}); + } + + TS_LOGI("clockid: TS_CLOCK_REALTIME_COARSE, ts:%llu", profilerTraceFileHeader->data.realtimeCoarse); + if (profilerTraceFileHeader->data.realtimeCoarse) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME_COARSE, profilerTraceFileHeader->data.realtimeCoarse}); + } + + TS_LOGI("clockid: TS_MONOTONIC, ts:%llu", profilerTraceFileHeader->data.monotonic); + if (profilerTraceFileHeader->data.monotonic) { + snapShot.push_back(SnapShot{TS_MONOTONIC, profilerTraceFileHeader->data.monotonic}); + } + + TS_LOGI("clockid: TS_MONOTONIC_COARSE, ts:%llu", profilerTraceFileHeader->data.monotonicCoarse); + if (profilerTraceFileHeader->data.monotonicCoarse) { + snapShot.push_back(SnapShot{TS_MONOTONIC_COARSE, profilerTraceFileHeader->data.monotonicCoarse}); + } + + TS_LOGI("clockid: TS_MONOTONIC_RAW, ts:%llu", profilerTraceFileHeader->data.monotonicRaw); + if (profilerTraceFileHeader->data.monotonicRaw) { + snapShot.push_back(SnapShot{TS_MONOTONIC_RAW, profilerTraceFileHeader->data.monotonicRaw}); + } + + if (snapShot.size()) { + streamFilters_->clockFilter_->AddClockSnapshot(snapShot); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SYNC, STAT_EVENT_RECEIVED); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_clock_detail_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_clock_detail_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..c26e0638be8b7e3514bbcba76af21dbe5c215a75 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_clock_detail_parser.h @@ -0,0 +1,46 @@ +/* + * 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 HTRACE_CLOCKDETAIL_PARSER_H +#define HTRACE_CLOCKDETAIL_PARSER_H +#include +#include +#include +#include +#include +#include "event_parser_base.h" +#include "file.h" +#include "htrace_file_header.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pb.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceClockDetailParser : public EventParserBase { +public: + HtraceClockDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters); + ~HtraceClockDetailParser(); + void Parse(TracePluginResult* tracePacket) const; + void Parse(const ProfilerTraceFileHeader* profilerTraceFileHeader) const; + +private: + std::map memNameDictMap_ = {}; + TraceStreamerConfig config_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_CLOCKDETAIL_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_cpu_data_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_cpu_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d3aca8ad7155ed9777e04dd1f924a8961f48a27 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_cpu_data_parser.cpp @@ -0,0 +1,79 @@ +/* + * 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 "htrace_cpu_data_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceCpuDataParser::HtraceCpuDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceCpuDataParser::~HtraceCpuDataParser() +{ + TS_LOGI("cpuData ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceCpuDataParser::Parse(CpuData& tracePacket, uint64_t ts) +{ + if (!tracePacket.has_cpu_usage_info() && !tracePacket.thread_info_size()) { + return; + } + if (tracePacket.has_cpu_usage_info()) { + auto cpuInfo = tracePacket.cpu_usage_info(); + auto userLoad = tracePacket.user_load(); + auto sysLoad = tracePacket.sys_load(); + auto process_num = tracePacket.process_num(); + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts); + auto cpuUsage = std::make_unique(); + streamFilters_->statFilter_->IncreaseStat(TRACE_CPU_USAGE, STAT_EVENT_RECEIVED); + cpuUsage->SetCpuUsage(ts, cpuInfo); + cpuUsage->SetExtInfo(tracePacket.total_load(), userLoad, sysLoad, process_num); + cpuData_.push_back(std::move(cpuUsage)); + } +} +void HtraceCpuDataParser::Finish() +{ + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { return a->ts_ < b->ts_; }; +#ifdef IS_WASM + std::sort(cpuData_.begin(), cpuData_.end(), cmp); +#else + std::stable_sort(cpuData_.begin(), cpuData_.end(), cmp); +#endif + bool firstTime = true; + uint64_t lastTs = 0; + for (auto itor = cpuData_.begin(); itor != cpuData_.end(); itor++) { + auto newTimeStamp = (*itor)->ts_; + if (firstTime) { + lastTs = newTimeStamp; + firstTime = false; + continue; + } + auto dur = newTimeStamp - lastTs; + auto durMs = (*itor)->cpuUsageData_->system_boot_time_ms() - (*itor)->cpuUsageData_->prev_system_boot_time_ms(); + durMs = durMs == 0 ? 1 : durMs; + traceDataCache_->GetCpuUsageInfoData()->AppendNewData( + newTimeStamp, dur, (*itor)->totalLoad_, (*itor)->userLoad_, (*itor)->sysLoad_, (*itor)->process_num_); + lastTs = newTimeStamp; + } + cpuData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_cpu_data_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_cpu_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..62e1ca5a4fdc7f298f90a54494962ecbcf347a24 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_cpu_data_parser.h @@ -0,0 +1,81 @@ +/* + * 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 HTRACE_CPU_DATA_PARSER_H +#define HTRACE_CPU_DATA_PARSER_H +#include +#include +#include +#include "cpu_plugin_result.pb.h" +#include "hilog_plugin_result.pb.h" +#include "htrace_plugin_time_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceCpuDataParser : public HtracePluginTimeParser { +public: + HtraceCpuDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceCpuDataParser(); + void Parse(CpuData& tracePacket, uint64_t ts); + void Finish(); + enum TSCpuDataType { TSCpuDataType_Usage, TSCpuDataType_ThreadInfo, TSCpuDataType_Load }; + class TsCpuData { + public: + TsCpuData() + { + ts_ = 0; + cpuDataType_ = TSCpuDataType_Usage; + } + void SetCpuUsage(uint64_t ts, CpuUsageInfo& usage) + { + ts_ = ts; + cpuUsageData_ = std::make_unique(usage); + cpuDataType_ = TSCpuDataType_Usage; + } + void SetThreadInfo(uint64_t ts, ThreadInfo& threadInfo) + { + ts_ = ts; + threadDataData_ = std::make_unique(threadInfo); + cpuDataType_ = TSCpuDataType_ThreadInfo; + } + void SetExtInfo(double totalLoad, double userLoad, double sysLoad, double process_num) + { + totalLoad_ = totalLoad; + userLoad_ = userLoad; + sysLoad_ = sysLoad; + process_num_ = process_num; + cpuDataType_ = TSCpuDataType_Load; + } + uint64_t ts_; + std::unique_ptr cpuUsageData_; + std::unique_ptr threadDataData_; + TSCpuDataType cpuDataType_; + double userLoad_ = 0; + double sysLoad_ = 0; + double process_num_ = 0; + double totalLoad_ = 0; + }; + std::vector> cpuData_; + +private: + std::string threadStateDesc_[THREAD_WAITING + 1] = {"undefined", "Running", "Sleep", "Sloped", "Watting"}; + uint64_t lastLineSeq_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_CPU_DATA_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_cpu_parser/htrace_cpu_detail_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_cpu_parser/htrace_cpu_detail_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ef34eb5b3d5279f54206f808a4a37299c2fb745 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_cpu_parser/htrace_cpu_detail_parser.cpp @@ -0,0 +1,43 @@ +/* + * 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 "htrace_cpu_detail_parser.h" +#include "htrace_event_parser.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceCpuDetailParser::HtraceCpuDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : eventParser_(std::make_unique(dataCache, ctx)) +{ +} + +HtraceCpuDetailParser::~HtraceCpuDetailParser() = default; +void HtraceCpuDetailParser::Parse(TracePluginResult* tracePacket, BuiltinClocks clock) +{ + if (!tracePacket->ftrace_cpu_detail_size()) { + return; + } + + for (int32_t i = 0; i < tracePacket->ftrace_cpu_detail_size(); i++) { + FtraceCpuDetailMsg* cpuDetail = tracePacket->mutable_ftrace_cpu_detail(i); + eventParser_->ParseDataItem(cpuDetail, clock); + } +} +void HtraceCpuDetailParser::FilterAllEvents() +{ + eventParser_->FilterAllEvents(); + eventParser_->Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_cpu_parser/htrace_cpu_detail_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_cpu_parser/htrace_cpu_detail_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..b7c5cdc9474e70b81cf3ca1f25c91e86fe42dc03 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_cpu_parser/htrace_cpu_detail_parser.h @@ -0,0 +1,45 @@ +/* + * 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 HTRACE_CPU_DETAIL_PARSER_H +#define HTRACE_CPU_DETAIL_PARSER_H +#include +#include +#include +#include +#include +#include "event_parser_base.h" +#include "htrace_event_parser.h" +#include "log.h" +#include "parser_base.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pb.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceCpuDetailParser { +public: + HtraceCpuDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceCpuDetailParser(); + void Parse(TracePluginResult* tracePacket, BuiltinClocks clock); + void FilterAllEvents(); + +private: + std::unique_ptr eventParser_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_CPU_DETAIL_PARSER_H_ diff --git a/trace_streamer/src/parser/htrace_parser/htrace_disk_io_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_disk_io_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c0869fb87ab0559d7b0699a236daf20dcc43e85 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_disk_io_parser.cpp @@ -0,0 +1,86 @@ +/* + * 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 "htrace_disk_io_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceDiskIOParser::HtraceDiskIOParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceDiskIOParser::~HtraceDiskIOParser() +{ + TS_LOGI("diskio ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceDiskIOParser::Parse(DiskioData& tracePacket, uint64_t ts) +{ + auto stat = tracePacket.statsdata(); + if (!stat.statsinfo_size()) { + return; + } + double rdCountPerSec = 0; // The amount of data read from the device per second kB_read/s + double wrCountPerSec = 0; // The amount of data written to the device per second kB_wrtn/s + uint64_t rdCount = 0; // Total amount of data read kB_read + uint64_t wrCount = 0; // The total amount of data written kB_wrtn + for (auto i = 0; i < stat.statsinfo_size(); i++) { + auto statsInfo = stat.statsinfo(i); + rdCountPerSec += statsInfo.rd_per_sec(); + wrCountPerSec += statsInfo.wr_per_sec(); + rdCount += statsInfo.rd_kb(); + wrCount += statsInfo.wr_kb(); + } + + streamFilters_->statFilter_->IncreaseStat(TRACE_DISKIO, STAT_EVENT_RECEIVED); + diskIOData_.push_back(TsDiskIOData{ts, tracePacket.rd_sectors_kb(), tracePacket.wr_sectors_kb(), + tracePacket.prev_rd_sectors_kb(), tracePacket.prev_wr_sectors_kb(), + rdCountPerSec, wrCountPerSec, rdCount, wrCount}); +} +void HtraceDiskIOParser::Finish() +{ + auto cmp = [](const TsDiskIOData& a, const TsDiskIOData& b) { return a.ts < b.ts; }; +#ifdef IS_WASM + std::sort(diskIOData_.begin(), diskIOData_.end(), cmp); +#else + std::stable_sort(diskIOData_.begin(), diskIOData_.end(), cmp); +#endif + bool first = true; + uint64_t lastTs = 0; + for (auto itor = diskIOData_.begin(); itor != diskIOData_.end(); itor++) { + itor->ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, itor->ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, itor->ts, itor->ts); + if (first) { + lastTs = itor->ts; + first = false; + continue; + } + auto dur = itor->ts - lastTs; + auto durS = 1.0 * dur / SEC_TO_NS; + traceDataCache_->GetDiskIOData()->AppendNewData( + itor->ts, itor->ts - lastTs, itor->rdSectorsKb, itor->wrSectorsKb, + 1.0 * (itor->rdSectorsKb - itor->prevRdSectorsKb) / durS, + 1.0 * (itor->wrSectorsKb - itor->prevWrSectorsKb) / durS, itor->rdCountPerSec, itor->wrCountPerSec, + itor->rdCount, itor->wrCount); + lastTs = itor->ts; + } + diskIOData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_disk_io_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_disk_io_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..1366ad491d490da1b21d3144aaeeab682c81f5e8 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_disk_io_parser.h @@ -0,0 +1,51 @@ +/* + * 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 HTRACE_DISKI0_PARSER_H +#define HTRACE_DISKI0_PARSER_H +#include +#include +#include +#include "diskio_plugin_result.pb.h" +#include "htrace_plugin_time_parser.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceDiskIOParser : public HtracePluginTimeParser { +public: + HtraceDiskIOParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceDiskIOParser(); + void Parse(DiskioData& tracePacket, uint64_t ts); + void Finish(); + +private: + struct TsDiskIOData { + uint64_t ts; + int64_t rdSectorsKb; + int64_t wrSectorsKb; + int64_t prevRdSectorsKb; + int64_t prevWrSectorsKb; + double rdCountPerSec; // 每秒从设备读取的数据量 kB_read/s + double wrCountPerSec; // 每秒向设备写入的数据量 kB_wrtn/s + uint64_t rdCount; // 读取的总数据量 kB_read + uint64_t wrCount; // 写入的总数量数据量 kB_wrtn + }; + std::vector diskIOData_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_DISKI0_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_event_parser/htrace_event_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_event_parser/htrace_event_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d9e2a8af281eefc72c0bc6bbb7dd44a47f6339b --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_event_parser/htrace_event_parser.cpp @@ -0,0 +1,825 @@ +/* + * 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 "htrace_event_parser.h" +#include +#include "binder_filter.h" +#include "binder.pb.h" +#include "clock_filter.h" +#include "cpu_filter.h" +#include "ipi.pb.h" +#include "irq_filter.h" +#include "irq.pb.h" +#include "log.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +#include "system_event_measure_filter.h" +#include "thread_state.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceEventParser::HtraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : EventParserBase(dataCache, filter), + workQueueId_(dataCache->dataDict_.GetStringIndex("workqueue")), + printEventParser_(traceDataCache_, streamFilters_) +{ + eventToFunctionMap_ = {{config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION), + std::bind(&HtraceEventParser::BinderTractionEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED), + std::bind(&HtraceEventParser::BinderTractionReceivedEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF), + std::bind(&HtraceEventParser::BinderTractionAllocBufEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_LOCK), + std::bind(&HtraceEventParser::BinderTractionLockEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_LOCKED), + std::bind(&HtraceEventParser::BinderTractionLockedEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK), + std::bind(&HtraceEventParser::BinderTractionUnLockEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_SWITCH), + std::bind(&HtraceEventParser::SchedSwitchEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_BLOCKED_REASON), + std::bind(&HtraceEventParser::SchedBlockReasonEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_TASK_RENAME), + std::bind(&HtraceEventParser::TaskRenameEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_TASK_NEWTASK), + std::bind(&HtraceEventParser::TaskNewtaskEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_PRINT), + std::bind(&HtraceEventParser::ParsePrintEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP), + std::bind(&HtraceEventParser::SchedWakeupEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP_NEW), + std::bind(&HtraceEventParser::SchedWakeupNewEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_PROCESS_EXIT), + std::bind(&HtraceEventParser::ProcessExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_PROCESS_FREE), + std::bind(&HtraceEventParser::ProcessFreeEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKING), + std::bind(&HtraceEventParser::SchedWakingEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_IDLE), + std::bind(&HtraceEventParser::CpuIdleEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY), + std::bind(&HtraceEventParser::CpuFrequencyEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY_LIMITS), + std::bind(&HtraceEventParser::CpuFrequencyLimitsEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SUSPEND_RESUME), + std::bind(&HtraceEventParser::SuspendResumeEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_START), + std::bind(&HtraceEventParser::WorkqueueExecuteStartEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_END), + std::bind(&HtraceEventParser::WorkqueueExecuteEndEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_SET_RATE), + std::bind(&HtraceEventParser::ClockSetRateEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_ENABLE), + std::bind(&HtraceEventParser::ClockEnableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_DISABLE), + std::bind(&HtraceEventParser::ClockDisableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLK_SET_RATE), + std::bind(&HtraceEventParser::ClkSetRateEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLK_ENABLE), + std::bind(&HtraceEventParser::ClkEnableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLK_DISABLE), + std::bind(&HtraceEventParser::ClkDisableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_ENTRY), + std::bind(&HtraceEventParser::IrqHandlerEntryEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_EXIT), + std::bind(&HtraceEventParser::IrqHandlerExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IPI_ENTRY), + std::bind(&HtraceEventParser::IpiHandlerEntryEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IPI_EXIT), + std::bind(&HtraceEventParser::IpiHandlerExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_ENTRY), + std::bind(&HtraceEventParser::SoftIrqEntryEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_RAISE), + std::bind(&HtraceEventParser::SoftIrqRaiseEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_EXIT), + std::bind(&HtraceEventParser::SoftIrqExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SYS_ENTRY), + std::bind(&HtraceEventParser::SysEnterEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SYS_EXIT), + std::bind(&HtraceEventParser::SysExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_OOM_SCORE_ADJ_UPDATE), + std::bind(&HtraceEventParser::OomScoreAdjUpdate, this, std::placeholders::_1)}}; +} + +HtraceEventParser::~HtraceEventParser() +{ + TS_LOGI("thread count:%u", static_cast(tids_.size())); + TS_LOGI("process count:%u", static_cast(pids_.size())); + TS_LOGI("ftrace ts MIN:%llu, MAX:%llu", static_cast(ftraceStartTime_), + static_cast(ftraceEndTime_)); + TS_LOGI("ftrace origin ts MIN:%llu, MAX:%llu", static_cast(ftraceOriginStartTime_), + static_cast(ftraceOriginEndTime_)); +} +void HtraceEventParser::ParseDataItem(const FtraceCpuDetailMsg* cpuDetail, BuiltinClocks clock) +{ + eventCpu_ = cpuDetail->cpu(); + auto events = cpuDetail->event(); + if (!events.size()) { + return; + } + if (cpuDetail->overwrite()) { + if (!lastOverwrite_) { + lastOverwrite_ = cpuDetail->overwrite(); + } + if (lastOverwrite_ != cpuDetail->overwrite()) { + TS_LOGW("lost events:%llu", cpuDetail->overwrite() - lastOverwrite_); + lastOverwrite_ = cpuDetail->overwrite(); + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_LOST); + } + // parser cpu event + for (auto i = 0; i < events.size(); i++) { + auto event = cpuDetail->event(i); + eventTimeStamp_ = event.timestamp(); + comm_ = event.comm(); + ftraceOriginStartTime_ = std::min(ftraceOriginStartTime_, eventTimeStamp_); + ftraceOriginEndTime_ = std::max(ftraceOriginEndTime_, eventTimeStamp_); + eventTimeStamp_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(clock, eventTimeStamp_); + ftraceStartTime_ = std::min(ftraceStartTime_, eventTimeStamp_); + ftraceEndTime_ = std::max(ftraceEndTime_, eventTimeStamp_); + traceDataCache_->UpdateTraceTime(eventTimeStamp_); + if (event.tgid() != INVALID_INT32) { + eventPid_ = event.tgid(); + if (!pids_.count(eventPid_)) { + pids_.insert(eventPid_); + } + streamFilters_->processFilter_->GetOrCreateThreadWithPid(eventPid_, eventPid_); + } + if (event.common_fields().pid() != INVALID_INT32) { + eventTid_ = event.common_fields().pid(); + if (!tids_.count(eventTid_)) { + tids_.insert(eventTid_); + } + streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + } + if (eventTid_ != INVALID_INT32 && eventPid_ != INVALID_INT32) { + streamFilters_->processFilter_->GetOrCreateThreadWithPid(eventTid_, eventPid_); + } + // remember all event + eventList_.push_back(std::move( + std::make_unique(comm_, eventTimeStamp_, eventCpu_, eventPid_, eventTid_, std::move(event)))); + // push all events in queue and finally release it, the data may not be released + // this may limit the max size of data, so we parser data periodicity + FilterAllEventsTemp(); + } +} +void HtraceEventParser::DealEvent(const FtraceEvent& event) +{ + streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(event.common_fields().pid(), event.tgid(), + event.comm()); + if (event.has_sched_switch_format()) { + InvokeFunc(TRACE_EVENT_SCHED_SWITCH, event.sched_switch_format()); + } else if (event.has_sched_blocked_reason_format()) { + InvokeFunc(TRACE_EVENT_SCHED_BLOCKED_REASON, event.sched_blocked_reason_format()); + } else if (event.has_task_rename_format()) { + InvokeFunc(TRACE_EVENT_TASK_RENAME, event.task_rename_format()); + } else if (event.has_task_newtask_format()) { + InvokeFunc(TRACE_EVENT_TASK_NEWTASK, event.task_newtask_format()); + } else if (event.has_sched_wakeup_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKEUP, event.sched_wakeup_format()); + } else if (event.has_sched_wakeup_new_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKEUP, event.sched_wakeup_new_format()); + } else if (event.has_sched_process_exit_format()) { + InvokeFunc(TRACE_EVENT_PROCESS_EXIT, event.sched_process_exit_format()); + } else if (event.has_sched_process_free_format()) { + InvokeFunc(TRACE_EVENT_PROCESS_FREE, event.sched_process_free_format()); + } else if (event.has_sched_waking_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKING, event.sched_waking_format()); + } else if (event.has_cpu_idle_format()) { + InvokeFunc(TRACE_EVENT_CPU_IDLE, event.cpu_idle_format()); + } else if (event.has_cpu_frequency_format()) { + InvokeFunc(TRACE_EVENT_CPU_FREQUENCY, event.cpu_frequency_format()); + } else if (event.has_cpu_frequency_limits_format()) { + InvokeFunc(TRACE_EVENT_CPU_FREQUENCY_LIMITS, event.cpu_frequency_limits_format()); + } else if (event.has_print_format()) { + InvokeFunc(TRACE_EVENT_PRINT, event.print_format()); + } else if (event.has_suspend_resume_format()) { + InvokeFunc(TRACE_EVENT_SUSPEND_RESUME, event.suspend_resume_format()); + } else if (event.has_workqueue_execute_start_format()) { + InvokeFunc(TRACE_EVENT_WORKQUEUE_EXECUTE_START, event.workqueue_execute_start_format()); + } else if (event.has_workqueue_execute_end_format()) { + InvokeFunc(TRACE_EVENT_WORKQUEUE_EXECUTE_END, event.workqueue_execute_end_format()); + } else if (event.has_clock_disable_format()) { + InvokeFunc(TRACE_EVENT_CLOCK_DISABLE, event.clock_disable_format()); + } else if (event.has_clock_enable_format()) { + InvokeFunc(TRACE_EVENT_CLOCK_ENABLE, event.clock_enable_format()); + } else if (event.has_clock_set_rate_format()) { + InvokeFunc(TRACE_EVENT_CLOCK_SET_RATE, event.clock_set_rate_format()); + } else if (event.has_clk_disable_format()) { + InvokeFunc(TRACE_EVENT_CLK_DISABLE, event.clk_disable_format()); + } else if (event.has_clk_enable_format()) { + InvokeFunc(TRACE_EVENT_CLK_ENABLE, event.clk_enable_format()); + } else if (event.has_clk_set_rate_format()) { + InvokeFunc(TRACE_EVENT_CLK_SET_RATE, event.clk_set_rate_format()); + } else if (event.has_sys_enter_format()) { + InvokeFunc(TRACE_EVENT_SYS_ENTRY, event.sys_enter_format()); + } else if (event.has_sys_exit_format()) { + InvokeFunc(TRACE_EVENT_SYS_EXIT, event.sys_exit_format()); + } else if (event.has_binder_transaction_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION, event.binder_transaction_format()); + } else if (event.has_binder_transaction_received_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, event.binder_transaction_received_format()); + } else if (event.has_binder_transaction_alloc_buf_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, event.binder_transaction_alloc_buf_format()); + } else if (event.has_binder_lock_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_LOCK, event.binder_lock_format()); + } else if (event.has_binder_unlock_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, event.binder_unlock_format()); + } else if (event.has_binder_locked_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, event.binder_locked_format()); + } else if (event.has_irq_handler_entry_format()) { + InvokeFunc(TRACE_EVENT_IRQ_HANDLER_ENTRY, event.irq_handler_entry_format()); + } else if (event.has_irq_handler_exit_format()) { + InvokeFunc(TRACE_EVENT_IRQ_HANDLER_EXIT, event.irq_handler_exit_format()); + } else if (event.has_softirq_entry_format()) { + InvokeFunc(TRACE_EVENT_SOFTIRQ_ENTRY, event.softirq_entry_format()); + } else if (event.has_softirq_exit_format()) { + InvokeFunc(TRACE_EVENT_SOFTIRQ_EXIT, event.softirq_exit_format()); + } else if (event.has_oom_score_adj_update_format()) { + InvokeFunc(TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, event.oom_score_adj_update_format()); + } else if (event.has_signal_generate_format()) { + InvokeFunc(TRACE_EVENT_SIGNAL_GENERATE, event.signal_generate_format()); + } else if (event.has_signal_deliver_format()) { + InvokeFunc(TRACE_EVENT_SIGNAL_DELIVER, event.signal_deliver_format()); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED); + } +} +bool HtraceEventParser::BinderTractionAllocBufEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + uint64_t dataSize = msg.data_size(); + uint64_t offsetsSize = msg.offsets_size(); + streamFilters_->binderFilter_->TransactionAllocBuf(eventTimeStamp_, eventTid_, dataSize, offsetsSize); + TS_LOGD("dataSize:%lu, offsetSize:%lu", dataSize, offsetsSize); + return true; +} +bool HtraceEventParser::BinderTractionEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + int32_t destNode = msg.target_node(); + int32_t destTgid = msg.to_proc(); + int32_t destTid = msg.to_thread(); + int32_t transactionId = msg.debug_id(); + bool isReply = msg.reply() == 1; + uint32_t flags = msg.flags(); + TS_LOGD("destNode:%d, destTgid:%d, destTid:%d, transactionId:%d, isReply:%d flags:%d, code:%d", destNode, destTgid, + destTid, transactionId, isReply, flags, msg.code()); + streamFilters_->binderFilter_->SendTraction(eventTimeStamp_, eventTid_, transactionId, destNode, destTgid, destTid, + isReply, flags, msg.code()); + return true; +} +bool HtraceEventParser::BinderTractionReceivedEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + int32_t transactionId = msg.debug_id(); + streamFilters_->binderFilter_->ReceiveTraction(eventTimeStamp_, eventTid_, transactionId); + TS_LOGD("transactionId:%d", transactionId); + return true; +} +bool HtraceEventParser::BinderTractionLockEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCK, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + std::string tag = msg.tag(); + streamFilters_->binderFilter_->TractionLock(eventTimeStamp_, eventTid_, tag); + TS_LOGD("tag:%s", tag.c_str()); + return true; +} +bool HtraceEventParser::BinderTractionLockedEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + std::string tag = msg.tag(); + streamFilters_->binderFilter_->TractionLocked(eventTimeStamp_, eventTid_, tag); + return true; +} +bool HtraceEventParser::BinderTractionUnLockEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + std::string tag = msg.tag(); + streamFilters_->binderFilter_->TractionUnlock(eventTimeStamp_, eventTid_, tag); + return true; +} +bool HtraceEventParser::SchedSwitchEvent(const MessageLite& event) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + uint32_t prevPrioValue = msg.prev_prio(); + uint32_t nextPrioValue = msg.next_prio(); + uint32_t prevPidValue = msg.prev_pid(); + uint32_t nextPidValue = msg.next_pid(); + if (!tids_.count(prevPidValue)) { + tids_.insert(prevPidValue); + } + if (!tids_.count(nextPidValue)) { + tids_.insert(nextPidValue); + } + std::string prevCommStr = msg.prev_comm(); + std::string nextCommStr = msg.next_comm(); + auto prevState = msg.prev_state(); + + auto nextInternalTid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, nextPidValue, nextCommStr); + auto uprevtid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, prevPidValue, prevCommStr); + streamFilters_->cpuFilter_->InsertSwitchEvent(eventTimeStamp_, eventCpu_, uprevtid, + static_cast(prevPrioValue), prevState, nextInternalTid, + static_cast(nextPrioValue), INVALID_DATAINDEX); + return true; +} +bool HtraceEventParser::SchedBlockReasonEvent(const MessageLite& event) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + uint32_t pid = msg.pid(); + uint32_t ioWait = msg.io_wait(); + auto caller = traceDataCache_->GetDataIndex( + std::string_view("0x" + SysTuning::base::number(msg.caller(), SysTuning::base::INTEGER_RADIX_TYPE_HEX))); + auto itid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, pid); + if (!streamFilters_->cpuFilter_->InsertBlockedReasonEvent(eventTimeStamp_, eventCpu_, itid, ioWait, caller, + INVALID_UINT32)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_NOTMATCH); + } + return true; +} +bool HtraceEventParser::ProcessExitEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + uint32_t pidValue = msg.pid(); + std::string commStr = msg.comm(); + auto iTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, pidValue, commStr); + if (streamFilters_->cpuFilter_->InsertProcessExitEvent(eventTimeStamp_, eventCpu_, iTid)) { + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_NOTMATCH); + return false; + } +} +bool HtraceEventParser::ProcessFreeEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_FREE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + uint32_t pidValue = msg.pid(); + std::string commStr = msg.comm(); + auto iTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, pidValue, commStr); + if (streamFilters_->cpuFilter_->InsertProcessFreeEvent(eventTimeStamp_, iTid)) { + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_FREE, STAT_EVENT_NOTMATCH); + return false; + } +} +bool HtraceEventParser::TaskRenameEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_RENAME, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto prevCommStr = msg.newcomm(); + auto pidValue = msg.pid(); + return true; +} +bool HtraceEventParser::TaskNewtaskEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_RECEIVED); + // the clone flag from txt trace from kernel original is HEX, but when it is converted from proto + // based trace, it will be OCT number, it is not stable, so we decide to ignore it + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool HtraceEventParser::ParsePrintEvent(const MessageLite& event) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PRINT, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + BytraceLine line; + line.tgid = eventPid_; + line.pid = eventTid_; + line.ts = eventTimeStamp_; + printEventParser_.ParsePrintEvent(comm_, eventTimeStamp_, eventTid_, msg.buf().c_str(), line); + if (!tids_.count(eventTid_)) { + tids_.insert(eventTid_); + } + return true; +} +bool HtraceEventParser::SchedWakeupEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto instants = traceDataCache_->GetInstantsData(); + + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, msg.pid()); + InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + instants->AppendInstantEventData(eventTimeStamp_, schedWakeupName_, internalTid, wakeupFromPid); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid); + std::optional targetCpu = msg.target_cpu(); + if (targetCpu.has_value()) { + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_SCHED_WAKEUP, targetCpu.value(), + wakeupFromPid); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID); + } + return true; +} +bool HtraceEventParser::SchedWakeupNewEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP_NEW, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto instants = traceDataCache_->GetInstantsData(); + + auto internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, msg.pid()); + auto wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + instants->AppendInstantEventData(eventTimeStamp_, schedWakeupNewName_, internalTid, wakeupFromPid); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid); + std::optional targetCpu = msg.target_cpu(); + if (targetCpu.has_value()) { + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_SCHED_WAKEUP, targetCpu.value(), + wakeupFromPid); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP_NEW, STAT_EVENT_DATA_INVALID); + } + return true; +} +bool HtraceEventParser::SchedWakingEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + std::optional wakePidValue = msg.pid(); + if (!wakePidValue.has_value()) { + TS_LOGD("Failed to convert wake_pid"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID); + return false; + } + auto instants = traceDataCache_->GetInstantsData(); + auto internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, wakePidValue.value()); + auto wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid, true); + instants->AppendInstantEventData(eventTimeStamp_, schedWakingName_, internalTid, wakeupFromPid); + std::optional targetCpu = msg.target_cpu(); + if (targetCpu.has_value()) { + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_SCHED_WAKING, targetCpu.value(), + wakeupFromPid); + } + return true; +} +bool HtraceEventParser::CpuIdleEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + std::optional eventCpuValue = msg.cpu_id(); + std::optional newStateValue = msg.state(); + if (!eventCpuValue.has_value()) { + TS_LOGW("Failed to convert event cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + if (!newStateValue.has_value()) { + TS_LOGW("Failed to convert state"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuIdleName_, eventTimeStamp_, + config_.GetStateValue(newStateValue.value())); + + // Add cpu_idle event to raw_data_table + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_CPU_IDLE, eventCpuValue.value(), 0); + return true; +} +bool HtraceEventParser::CpuFrequencyEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + std::optional newStateValue = msg.state(); + std::optional eventCpuValue = msg.cpu_id(); + + if (!newStateValue.has_value()) { + TS_LOGW("Failed to convert state"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + if (!eventCpuValue.has_value()) { + TS_LOGW("Failed to convert event cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuFrequencyName_, eventTimeStamp_, + newStateValue.value()); + return true; +} +bool HtraceEventParser::CpuFrequencyLimitsEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + uint32_t maxFreq = msg.max_freq(); + uint32_t minFreq = msg.min_freq(); + uint32_t eventCpuValue = msg.cpu_id(); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue, cpuFrequencyLimitMaxNameId, eventTimeStamp_, + maxFreq); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue, cpuFrequencyLimitMinNameId, eventTimeStamp_, + minFreq); + return true; +} +bool HtraceEventParser::SuspendResumeEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SUSPEND_RESUME, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + int32_t val = msg.val(); + uint32_t start = msg.start(); + std::string action = msg.action(); + UNUSED(val); + UNUSED(start); + UNUSED(action); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SUSPEND_RESUME, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool HtraceEventParser::WorkqueueExecuteStartEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_START, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto funcNameIndex = streamFilters_->symbolsFilter_->GetFunc(msg.function()); + size_t result = INVALID_UINT32; + if (funcNameIndex == INVALID_UINT64) { + std::string addrStr = "0x" + base::number(msg.function(), base::INTEGER_RADIX_TYPE_HEX); + auto addStrIndex = traceDataCache_->GetDataIndex(addrStr); + result = streamFilters_->sliceFilter_->BeginSlice(comm_, eventTimeStamp_, eventPid_, eventPid_, workQueueId_, + addStrIndex); + } else { + result = streamFilters_->sliceFilter_->BeginSlice(comm_, eventTimeStamp_, eventPid_, eventPid_, workQueueId_, + funcNameIndex); + } + + traceDataCache_->GetInternalSlicesData()->AppendDistributeInfo(); + if (result == INVALID_UINT32) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_LOST); + } + return true; +} +bool HtraceEventParser::WorkqueueExecuteEndEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + if (streamFilters_->sliceFilter_->EndSlice(eventTimeStamp_, eventPid_, eventPid_, workQueueId_)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_NOTMATCH); + } + return true; +} +bool HtraceEventParser::ClockSetRateEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name()); + streamFilters_->clockRateFilter_->AppendNewMeasureData(msg.cpu_id(), nameIndex, eventTimeStamp_, msg.state()); + return true; +} +bool HtraceEventParser::ClockEnableEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name()); + streamFilters_->clockEnableFilter_->AppendNewMeasureData(msg.cpu_id(), nameIndex, eventTimeStamp_, msg.state()); + return true; +} +bool HtraceEventParser::ClockDisableEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name()); + streamFilters_->clockDisableFilter_->AppendNewMeasureData(msg.cpu_id(), nameIndex, eventTimeStamp_, msg.state()); + return true; +} +bool HtraceEventParser::ClkSetRateEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLK_SET_RATE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name()); + streamFilters_->clkRateFilter_->AppendNewMeasureData(eventCpu_, nameIndex, eventTimeStamp_, msg.rate()); + return true; +} +bool HtraceEventParser::ClkEnableEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLK_ENABLE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name()); + streamFilters_->clkEnableFilter_->AppendNewMeasureData(eventCpu_, nameIndex, eventTimeStamp_, 1); + return true; +} +bool HtraceEventParser::ClkDisableEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLK_DISABLE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name()); + streamFilters_->clkDisableFilter_->AppendNewMeasureData(eventCpu_, nameIndex, eventTimeStamp_, 0); + return true; +} + +bool HtraceEventParser::IrqHandlerEntryEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto name = std::string_view(msg.name()); + streamFilters_->irqFilter_->IrqHandlerEntry(eventTimeStamp_, eventCpu_, traceDataCache_->GetDataIndex(name)); + return true; +} +bool HtraceEventParser::IrqHandlerExitEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + streamFilters_->irqFilter_->IrqHandlerExit(eventTimeStamp_, eventCpu_, msg.irq(), static_cast(msg.ret())); + return true; +} +bool HtraceEventParser::IpiHandlerEntryEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_ENTRY, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto name = std::string_view(msg.reason()); + streamFilters_->irqFilter_->IpiHandlerEntry(eventTimeStamp_, eventCpu_, traceDataCache_->GetDataIndex(name)); + return true; +} +bool HtraceEventParser::IpiHandlerExitEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_EXIT, STAT_EVENT_RECEIVED); + streamFilters_->irqFilter_->IpiHandlerExit(eventTimeStamp_, eventCpu_); + return true; +} +bool HtraceEventParser::SoftIrqEntryEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + streamFilters_->irqFilter_->SoftIrqEntry(eventTimeStamp_, eventCpu_, static_cast(msg.vec())); + return true; +} +bool HtraceEventParser::SoftIrqRaiseEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool HtraceEventParser::SoftIrqExitEvent(const MessageLite& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + streamFilters_->irqFilter_->SoftIrqExit(eventTimeStamp_, eventCpu_, static_cast(msg.vec())); + return true; +} +bool HtraceEventParser::SysEnterEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SYS_ENTRY, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto ipid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventPid_); + traceDataCache_->GetSysCallData()->AppendSysCallData(msg.id(), sysEnterName_, ipid, eventTimeStamp_, 0); + return true; +} +bool HtraceEventParser::SysExitEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SYS_EXIT, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + auto ipid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventPid_); + traceDataCache_->GetSysCallData()->AppendSysCallData(msg.id(), sysExitName_, ipid, eventTimeStamp_, msg.ret()); + return true; +} + +bool HtraceEventParser::OomScoreAdjUpdate(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + streamFilters_->processMeasureFilter_->AppendNewMeasureData(msg.pid(), oomScoreAdjName_, eventTimeStamp_, + msg.oom_score_adj()); + return true; +} + +bool HtraceEventParser::SignalGenerateEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BLOCK_BIO_BACKMERGE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + InternalTid internalTid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, msg.pid(), msg.comm()); + streamFilters_->threadFilter_->AppendNewMeasureData(internalTid, signalGenerateId_, eventTimeStamp_, msg.sig()); + return true; +} +bool HtraceEventParser::SignalDeleverEvent(const MessageLite& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BLOCK_BIO_BACKMERGE, STAT_EVENT_RECEIVED); + const auto msg = static_cast(event); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventPid_); + streamFilters_->threadFilter_->AppendNewMeasureData(internalTid, signalDeliverId_, eventTimeStamp_, msg.sig()); + return true; +} +bool HtraceEventParser::InvokeFunc(const SupportedTraceEventType& eventType, const MessageLite& msgBase) +{ + auto eventName = config_.eventNameMap_.find(eventType); + if (eventName == config_.eventNameMap_.end()) { + // log warn + streamFilters_->statFilter_->IncreaseStat(eventType, STAT_EVENT_NOTSUPPORTED); + return false; + } + auto it = eventToFunctionMap_.find(eventName->second); + if (it == eventToFunctionMap_.end()) { + // log warn + streamFilters_->statFilter_->IncreaseStat(eventType, STAT_EVENT_NOTSUPPORTED); + return false; + } + it->second(msgBase); + return true; +} +void HtraceEventParser::FilterAllEventsTemp() +{ + size_t maxBuffSize = 1000 * 1000; + size_t maxQueue = 2; + if (eventList_.size() < maxBuffSize * maxQueue) { + return; + } + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimeStamp_ < b->eventTimeStamp_; + }; +#ifdef IS_WASM + std::sort(eventList_.begin(), eventList_.end(), cmp); +#else + std::stable_sort(eventList_.begin(), eventList_.end(), cmp); +#endif + + auto endOfList = eventList_.begin() + maxBuffSize; + for (auto itor = eventList_.begin(); itor != endOfList; itor++) { + EventInfo* event = itor->get(); + eventTimeStamp_ = event->eventTimeStamp_; + eventCpu_ = event->eventCpu_; + eventPid_ = event->eventPid_; + eventTid_ = event->eventTid_; + comm_ = event->common_; + DealEvent(event->cpuDetail_); + itor->reset(); + } + eventList_.erase(eventList_.begin(), endOfList); +} +void HtraceEventParser::FilterAllEvents() +{ + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimeStamp_ < b->eventTimeStamp_; + }; +#ifdef IS_WASM + std::sort(eventList_.begin(), eventList_.end(), cmp); +#else + std::stable_sort(eventList_.begin(), eventList_.end(), cmp); +#endif + size_t maxBuffSize = 1000 * 1000; + + while (eventList_.size()) { + int32_t size = std::min(maxBuffSize, eventList_.size()); + auto endOfList = eventList_.begin() + size; + for (auto itor = eventList_.begin(); itor != endOfList; itor++) { + EventInfo* event = itor->get(); + eventTimeStamp_ = event->eventTimeStamp_; + eventCpu_ = event->eventCpu_; + eventPid_ = event->eventPid_; + eventTid_ = event->eventTid_; + comm_ = event->common_; + DealEvent(event->cpuDetail_); + itor->reset(); + } + eventList_.erase(eventList_.begin(), endOfList); + } + eventList_.clear(); + streamFilters_->cpuFilter_->Finish(); + traceDataCache_->dataDict_.Finish(); + traceDataCache_->UpdataZeroThreadInfo(); +} +void HtraceEventParser::Clear() +{ + streamFilters_->binderFilter_->Clear(); + streamFilters_->sliceFilter_->Clear(); + streamFilters_->cpuFilter_->Clear(); + streamFilters_->irqFilter_->Clear(); + streamFilters_->cpuMeasureFilter_->Clear(); + streamFilters_->threadMeasureFilter_->Clear(); + streamFilters_->threadFilter_->Clear(); + streamFilters_->processMeasureFilter_->Clear(); + streamFilters_->processFilterFilter_->Clear(); + streamFilters_->symbolsFilter_->Clear(); + streamFilters_->clockEnableFilter_->Clear(); + streamFilters_->clockDisableFilter_->Clear(); + streamFilters_->clkRateFilter_->Clear(); + streamFilters_->clkDisableFilter_->Clear(); + streamFilters_->binderFilter_->Clear(); + streamFilters_->sysEventMemMeasureFilter_->Clear(); + streamFilters_->sysEventVMemMeasureFilter_->Clear(); + printEventParser_.Finish(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_event_parser/htrace_event_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_event_parser/htrace_event_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..b3eb4d6e891326b6ff9741e44f66c4fabb86bdc9 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_event_parser/htrace_event_parser.h @@ -0,0 +1,147 @@ +/* + * 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 HTRACE_EVENT_PARSER_H +#define HTRACE_EVENT_PARSER_H +#include +#include +#include +#include +#include +#include +#include + +#include "event_parser_base.h" +#include "google/protobuf/message_lite.h" +#include "log.h" +#include "print_event_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pb.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace google::protobuf; +class HtraceEventParser : private EventParserBase { +public: + HtraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~HtraceEventParser(); + void ParseDataItem(const FtraceCpuDetailMsg* cpuDetail, BuiltinClocks clock); + void FilterAllEventsTemp(); + void FilterAllEvents(); + void Clear(); + +private: + void DealEvent(const FtraceEvent& event); + bool BinderTractionEvent(const MessageLite& event) const; + bool BinderTractionReceivedEvent(const MessageLite& event) const; + bool BinderTractionAllocBufEvent(const MessageLite& event) const; + bool BinderTractionLockEvent(const MessageLite& event) const; + bool BinderTractionLockedEvent(const MessageLite& event) const; + bool BinderTractionUnLockEvent(const MessageLite& event) const; + bool SchedSwitchEvent(const MessageLite& event); + bool SchedBlockReasonEvent(const MessageLite& event); + bool ProcessExitEvent(const MessageLite& event) const; + bool ProcessFreeEvent(const MessageLite& event) const; + bool TaskRenameEvent(const MessageLite& event) const; + bool TaskNewtaskEvent(const MessageLite& event) const; + bool ParsePrintEvent(const MessageLite& event); + bool SchedWakeupEvent(const MessageLite& event) const; + bool SchedWakeupNewEvent(const MessageLite& event) const; + bool SchedWakingEvent(const MessageLite& event) const; + bool CpuIdleEvent(const MessageLite& event) const; + bool CpuFrequencyEvent(const MessageLite& event) const; + bool CpuFrequencyLimitsEvent(const MessageLite& event) const; + bool SuspendResumeEvent(const MessageLite& event) const; + bool WorkqueueExecuteStartEvent(const MessageLite& event) const; + bool WorkqueueExecuteEndEvent(const MessageLite& event) const; + bool ClockSetRateEvent(const MessageLite& event) const; + bool ClockEnableEvent(const MessageLite& event) const; + bool ClockDisableEvent(const MessageLite& event) const; + bool ClkSetRateEvent(const MessageLite& event) const; + bool ClkEnableEvent(const MessageLite& event) const; + bool ClkDisableEvent(const MessageLite& event) const; + bool IrqHandlerEntryEvent(const MessageLite& event) const; + bool IrqHandlerExitEvent(const MessageLite& event) const; + bool IpiHandlerEntryEvent(const MessageLite& event) const; + bool IpiHandlerExitEvent(const MessageLite& event) const; + bool SoftIrqEntryEvent(const MessageLite& event) const; + bool SoftIrqRaiseEvent(const MessageLite& event) const; + bool SoftIrqExitEvent(const MessageLite& event) const; + bool SysEnterEvent(const MessageLite& event) const; + bool SysExitEvent(const MessageLite& event) const; + bool OomScoreAdjUpdate(const MessageLite& event) const; + bool SignalGenerateEvent(const MessageLite& event) const; + bool SignalDeleverEvent(const MessageLite& event) const; + bool InvokeFunc(const SupportedTraceEventType& eventType, const MessageLite& msgBase); + class EventInfo { + public: + EventInfo(const std::string& common, + uint64_t eventTimestamp, + uint32_t eventCpu, + uint32_t eventPid, + uint32_t eventTid, + const FtraceEvent& cpuDetail) + : common_(common), + eventTimeStamp_(eventTimestamp), + eventCpu_(eventCpu), + eventPid_(eventPid), + eventTid_(eventTid), + cpuDetail_(std::move(cpuDetail)) + { + } + std::string common_; + uint64_t eventTimeStamp_; + uint32_t eventCpu_; + uint32_t eventPid_; + uint32_t eventTid_; + FtraceEvent cpuDetail_; + }; + using FuncCall = std::function; + uint32_t eventCpu_ = INVALID_UINT32; + uint64_t eventTimeStamp_ = INVALID_UINT64; + std::string comm_ = ""; + uint32_t eventPid_ = INVALID_UINT32; + uint32_t eventTid_ = INVALID_UINT32; + std::map eventToFunctionMap_ = {}; + std::unordered_set tids_ = {}; + std::unordered_set pids_ = {}; + DataIndex workQueueId_ = 0; + PrintEventParser printEventParser_; + uint64_t lastOverwrite_ = 0; + uint64_t ftraceStartTime_ = std::numeric_limits::max(); + uint64_t ftraceEndTime_ = 0; + uint64_t ftraceOriginStartTime_ = std::numeric_limits::max(); + uint64_t ftraceOriginEndTime_ = 0; + std::vector> eventList_ = {}; + const DataIndex signalGenerateId_ = traceDataCache_->GetDataIndex("signal_generate"); + const DataIndex signalDeliverId_ = traceDataCache_->GetDataIndex("signal_deliver"); + const DataIndex schedWakeupName_ = traceDataCache_->GetDataIndex("sched_wakeup"); + const DataIndex schedWakingName_ = traceDataCache_->GetDataIndex("sched_waking"); + const DataIndex schedWakeupNewName_ = traceDataCache_->GetDataIndex("sched_wakeup_new"); + const DataIndex cpuIdleName_ = traceDataCache_->GetDataIndex("cpu_idle"); + const DataIndex cpuFrequencyName_ = traceDataCache_->GetDataIndex("cpu_frequency"); + const DataIndex cpuFrequencyLimitMaxNameId = traceDataCache_->GetDataIndex("cpu_frequency_limits_max"); + const DataIndex cpuFrequencyLimitMinNameId = traceDataCache_->GetDataIndex("cpu_frequency_limits_min"); + const DataIndex sysEnterName_ = traceDataCache_->GetDataIndex("sys_enter"); + const DataIndex sysExitName_ = traceDataCache_->GetDataIndex("sys_exit"); + const DataIndex oomScoreAdjName_ = traceDataCache_->GetDataIndex("oom_score_adj"); + TraceStreamerConfig config_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_EVENT_PARSER_H_ diff --git a/trace_streamer/src/parser/htrace_parser/htrace_file_header.h b/trace_streamer/src/parser/htrace_parser/htrace_file_header.h new file mode 100644 index 0000000000000000000000000000000000000000..9854f21287bca3858ebc5627f4cf270bde2736e2 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_file_header.h @@ -0,0 +1,64 @@ +/* + * 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 HTRACE_FILE_HEADER_H +#define HTRACE_FILE_HEADER_H +namespace SysTuning { +namespace TraceStreamer { +struct ProfilerTraceFileHeader { + // Some space is reserved to facilitate the subsequent addition of fields in the header + static constexpr uint32_t HEADER_SIZE = 1024; + static constexpr uint32_t SHA256_SIZE = 256 / 8; + static constexpr uint64_t HEADER_MAGIC = 0x464F5250534F484FuLL; + static constexpr uint32_t V_MAJOR = 0x0001; + static constexpr uint32_t V_MAJOR_BITS = 16; + static constexpr uint32_t V_MINOR = 0x0000; + static constexpr uint32_t TRACE_VERSION = (V_MAJOR << V_MAJOR_BITS) | V_MINOR; + static constexpr uint8_t PLUGIN_MODULE_NAME_MAX = 127; + static constexpr uint8_t PLUGIN_MODULE_VERSION_MAX = 7; + enum DataType { + HIPROFILER_PROTOBUF_BIN = 0, + HIPERF_DATA, + STANDALONE_DATA = 1000, + UNKNOW_TYPE = 1024, + }; + struct HeaderData { + // Magic number, used to distinguish offline files + uint64_t magic = HEADER_MAGIC; + // Total length, which can be used to check whether the document is truncated; + uint64_t length = HEADER_SIZE; + uint32_t version = TRACE_VERSION; + // The number of segments in the load data. The number of segments is even. One describes the length L and the + // other describes the next data v + uint32_t segments = 0; + // Sha256 of load data is used to verify whether the load data is complete; + uint8_t sha256[SHA256_SIZE] = {}; + uint32_t dataType = UNKNOW_TYPE; + // clock + uint64_t boottime = 0; + uint64_t realtime = 0; + uint64_t realtimeCoarse = 0; + uint64_t monotonic = 0; + uint64_t monotonicCoarse = 0; + uint64_t monotonicRaw = 0; + char standalonePluginName[PLUGIN_MODULE_NAME_MAX + 1] = ""; + char pluginVersion[PLUGIN_MODULE_VERSION_MAX + 1] = ""; + } __attribute__((packed)); + HeaderData data = {}; + uint8_t padding_[HEADER_SIZE - sizeof(data)] = {}; +}; +const std::string EBPF_PLUGIN_NAME = "hiebpf-plugin"; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HTRACE_FILE_HEADER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_hidump_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_hidump_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbe318f5b26537e7c97f44d0421e4d899ecda97e --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_hidump_parser.cpp @@ -0,0 +1,53 @@ +/* + * 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 "htrace_hidump_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceHidumpParser::HtraceHidumpParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx), clockId_(0) +{ +} + +HtraceHidumpParser::~HtraceHidumpParser() +{ + TS_LOGI("Fps data ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceHidumpParser::Parse(HidumpInfo& tracePacket) +{ + if (!tracePacket.fps_event_size()) { + return; + } + for (int32_t i = 0; i < tracePacket.fps_event_size(); i++) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HIDUMP_FPS, STAT_EVENT_RECEIVED); + auto hidumpData = tracePacket.mutable_fps_event(i); + auto timeStamp = hidumpData->time().tv_nsec() + hidumpData->time().tv_sec() * SEC_TO_NS; + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(hidumpData->id(), timeStamp); + UpdatePluginTimeRange(hidumpData->id(), timeStamp, newTimeStamp); + clockId_ = hidumpData->id(); + auto fps = hidumpData->fps(); + traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(newTimeStamp, fps); + } +} +void HtraceHidumpParser::Finish() +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_hidump_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_hidump_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..094a79371c53076f2b5660f68b74ebcc6b319e58 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_hidump_parser.h @@ -0,0 +1,45 @@ +/* + * 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 HTRACE_HIDUMP_PARSER_H +#define HTRACE_HIDUMP_PARSER_H +#include +#include +#include +#include "hidump_plugin_result.pb.h" +#include "htrace_plugin_time_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceHidumpParser : public HtracePluginTimeParser { +public: + HtraceHidumpParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceHidumpParser(); + void Parse(HidumpInfo& tracePacket); + void Finish(); + uint8_t ClockId() + { + return clockId_; + } + +private: + uint8_t clockId_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_HIDUMP_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_hilog_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_hilog_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4319db83d78b7db757dcbc679de7ef93aad61ff --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_hilog_parser.cpp @@ -0,0 +1,71 @@ +/* + * 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 "htrace_hilog_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceHiLogParser::HtraceHiLogParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceHiLogParser::~HtraceHiLogParser() +{ + TS_LOGI("hilog ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceHiLogParser::Parse(HilogInfo& tracePacket) +{ + if (!tracePacket.info_size()) { + return; + } + for (int32_t i = 0; i < tracePacket.info_size(); i++) { + auto hilogLine = tracePacket.mutable_info(i); + uint64_t curLineSeq = hilogLine->id(); + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_RECEIVED); + if (curLineSeq < lastLineSeq_ + 1) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_NOTMATCH); + } else if (curLineSeq > lastLineSeq_ + 1) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_DATA_LOST); + } + lastLineSeq_ = curLineSeq; + auto logData = traceDataCache_->GetDataIndex(hilogLine->context().c_str()); + auto logDetails = hilogLine->detail(); + + streamFilters_->processFilter_->GetOrCreateThreadWithPid(logDetails.tid(), logDetails.pid()); + auto iter = logLevelString_.find(logDetails.level()); + if (iter == logLevelString_.end()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_DATA_INVALID); + TS_LOGD("log level do not exit!!!"); + continue; + } + auto timeStamp = logDetails.tv_nsec() + logDetails.tv_sec() * SEC_TO_NS; + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, newTimeStamp); + DataIndex levelData = traceDataCache_->dataDict_.GetStringIndex(iter->second.c_str()); + DataIndex logTag = traceDataCache_->dataDict_.GetStringIndex(logDetails.tag().c_str()); + traceDataCache_->GetHilogData()->AppendNewLogInfo(curLineSeq, newTimeStamp, logDetails.pid(), logDetails.tid(), + levelData, logTag, logData, timeStamp); + } +} +void HtraceHiLogParser::Finish() +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_hilog_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_hilog_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..ad78b4610bff9c9eb10d155a57cac8a77909f43f --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_hilog_parser.h @@ -0,0 +1,46 @@ +/* + * 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 HTRACE_HILOG_PARSER_H +#define HTRACE_HILOG_PARSER_H +#include +#include +#include +#include "trace_data/trace_data_cache.h" +#include "hilog_plugin_result.pb.h" +#include "htrace_plugin_time_parser.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceHiLogParser : public HtracePluginTimeParser { +public: + HtraceHiLogParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceHiLogParser(); + void Parse(HilogInfo& tracePacket); + std::map logLevelString_ = {{TS_DEBUG, "D"}, + {TS_ERROR, "E"}, + {TS_INFO, "I"}, + {TS_VERBOSE, "V"}, + {TS_WARN, "W"}}; + void Finish(); + +private: + uint64_t lastLineSeq_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_HILOG_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_hisysevent_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_hisysevent_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ee07613dbfd215b75b4d5501b82baced8ead2c2 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_hisysevent_parser.cpp @@ -0,0 +1,210 @@ +/* + * 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 "clock_filter.h" +#include "hi_sysevent_measure_filter.h" +#include "htrace_event_parser.h" +#include "htrace_hisysevent_parser.h" +#include "htrace_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceHisyseventParser::HtraceHisyseventParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} +HtraceHisyseventParser::~HtraceHisyseventParser() +{ + TS_LOGI("hisysevent ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); + TS_LOGI("hisysevent real ts MIN:%llu, MAX:%llu", static_cast(MinTs()), + static_cast(MaxTs())); +} + +int32_t HtraceHisyseventParser::JGetData(json& jMessage, + JsonData& jData, + size_t& maxArraySize, + std::vector& noArrayIndex, + std::vector& arrayIndex) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_RECEIVED); + for (auto i = jMessage.begin(); i != jMessage.end(); i++) { + if (i.key() == "name_") { + if (find(eventsAccordingAppNames.begin(), eventsAccordingAppNames.end(), i.value()) == + eventsAccordingAppNames.end()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_NOTMATCH); + TS_LOGW("event source:%s not supported for hisysevent", std::string(i.value()).c_str()); + return -1; + } + jData.eventSource = i.value(); + continue; + } + if (i.key() == "time_") { + jData.timeStamp = i.value(); + continue; + } + if (i.key() == "tag_" && i.value() != "PowerStats") { + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_DATA_INVALID); + return -1; + } + if (i.key() == "APPNAME") { + jData.appName.assign(i.value().begin(), i.value().end()); + } + if (i.value().is_array()) { + maxArraySize = std::max(maxArraySize, i.value().size()); + arrayIndex.push_back(jData.key.size()); + } else { + noArrayIndex.push_back(jData.key.size()); + } + jData.key.push_back(i.key()); + jData.value.push_back(i.value()); + } + return 0; +} + +void HtraceHisyseventParser::NoArrayDataParse(JsonData jData, + std::vector noArrayIndex, + DataIndex eventSourceIndex, + uint64_t serial) +{ + for (auto itor = noArrayIndex.begin(); itor != noArrayIndex.end(); itor++) { + auto value = jData.value[*itor]; + auto key = jData.key[*itor]; + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + DataIndex keyIndex = traceDataCache_->GetDataIndex(key); + if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 1, 0, valueIndex); + } else { + double valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 0, valueIndex, 0); + } + } +} +void HtraceHisyseventParser::ArrayDataParse(JsonData jData, + std::vector arrayIndex, + DataIndex eventSourceIndex, + size_t maxArraySize, + uint64_t serial) +{ + for (int32_t j = 0; j < maxArraySize; j++) { + for (auto itor = arrayIndex.begin(); itor != arrayIndex.end(); itor++) { + auto value = jData.value[*itor][j]; + std::string key = jData.key[*itor]; + DataIndex keyIndex = traceDataCache_->GetDataIndex(key); + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + if (value.is_number()) { + double valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 0, valueIndex, 0); + } else if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 1, 0, valueIndex); + } + } + } +} +void HtraceHisyseventParser::CommonDataParser(JsonData jData, DataIndex eventSourceIndex, uint64_t serial) +{ + for (int32_t j = 0; j < jData.key.size(); j++) { + std::string key = jData.key[j]; + auto value = jData.value[j]; + DataIndex keyIndex = traceDataCache_->GetDataIndex(key); + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 1, 0, valueIndex); + } else { + double valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 0, valueIndex, 0); + } + } +} +void HtraceHisyseventParser::Finish() +{ + if (GetPluginStartTime() != GetPluginEndTime()) { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + } else { + TS_LOGI("hisysevent time is not updated, maybe this trace file only has one piece of hisysevent data"); + } + TS_LOGI("--------Parse end--------"); +} + +static std::stringstream ss; +void HtraceHisyseventParser::Parse(HisyseventInfo& tracePacket, uint64_t ts) +{ + if (isDeviceState) { + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue( + tracePacket.device_state().brightness_state(), tracePacket.device_state().bt_state(), + tracePacket.device_state().location_state(), tracePacket.device_state().wifi_state(), + tracePacket.device_state().volume_state().stream_default(), + tracePacket.device_state().volume_state().voice_call(), tracePacket.device_state().volume_state().music(), + tracePacket.device_state().volume_state().stream_ring(), tracePacket.device_state().volume_state().media(), + tracePacket.device_state().volume_state().voice_assistant(), + tracePacket.device_state().volume_state().system(), tracePacket.device_state().volume_state().alarm(), + tracePacket.device_state().volume_state().notification(), + tracePacket.device_state().volume_state().bluetoolth_sco(), + tracePacket.device_state().volume_state().enforced_audible(), + tracePacket.device_state().volume_state().stream_dtmf(), + tracePacket.device_state().volume_state().stream_tts(), + tracePacket.device_state().volume_state().accessibility(), + tracePacket.device_state().volume_state().recording(), + tracePacket.device_state().volume_state().stream_all()); + isDeviceState = false; + } + json jMessage; + for (int32_t i = 0; i < tracePacket.info_size(); i++) { + if (tracePacket.info(i).raw_content().front() != '{' || tracePacket.info(i).raw_content().back() != '}') { + continue; + } + ss << tracePacket.info(i).raw_content(); + ss >> jMessage; + size_t maxArraySize = 0; + JsonData jData; + std::vector noArrayIndex = {}; + std::vector arrayIndex = {}; + if (JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex) < 0) { + continue; + } + uint64_t serial = tracePacket.info(i).id(); + DataIndex eventSourceIndex = traceDataCache_->GetDataIndex(jData.eventSource); + jData.timeStamp *= MSEC_TO_NS; + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, jData.timeStamp); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, jData.timeStamp, newTimeStamp); + jData.timeStamp = newTimeStamp; + if (maxArraySize) { + NoArrayDataParse(jData, noArrayIndex, eventSourceIndex, serial); + ArrayDataParse(jData, arrayIndex, eventSourceIndex, maxArraySize, serial); + } else { + CommonDataParser(jData, eventSourceIndex, serial); + } + } +} +void HtraceHisyseventParser::Parse(HisyseventConfig& tracePacket, uint64_t ts) +{ + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue("message", tracePacket.msg()); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue("process_name", tracePacket.process_name()); + return; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_hisysevent_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_hisysevent_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..4fdba73884fb59aab6d1b1365b45b469f67db5d7 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_hisysevent_parser.h @@ -0,0 +1,108 @@ + +/* + * 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 HTRACE_HISYSEVENT_PARSER_H +#define HTRACE_HISYSEVENT_PARSER_H + +#include "clock_filter.h" +#include "hisysevent_plugin_config.pb.h" +#include "hisysevent_plugin_result.pb.h" +#include "htrace_plugin_time_parser.h" +#include "json.hpp" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceHisyseventParser : public HtracePluginTimeParser { +public: + HtraceHisyseventParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceHisyseventParser(); + void Finish(); + void Parse(HisyseventInfo& tracePacket, uint64_t ts); + void Parse(HisyseventConfig& tracePacket, uint64_t ts); + +private: + using json = nlohmann::json; + typedef struct { + std::string eventSource; + uint64_t timeStamp; + std::vector appName; + std::vector appVersions; + std::vector key; + std::vector value; + } JsonData; + +private: + void NoArrayDataParse(JsonData jData, + std::vector noArrayIndex, + DataIndex eventSourceIndex, + uint64_t serial); + void ArrayDataParse(JsonData jData, + std::vector arrayIndex, + DataIndex eventSourceIndex, + size_t maxArraySize, + uint64_t serial); + void CommonDataParser(JsonData jData, DataIndex eventSourceIndex, uint64_t serial); + int32_t JGetData(json& jMessage, + JsonData& jData, + size_t& maxArraySize, + std::vector& noArrayIndex, + std::vector& arrayIndex); + + std::vector eventsAccordingAppNames = {"POWER_IDE_BATTERY", + "POWER_IDE_CPU", + "POWER_IDE_LOCATION", + "POWER_IDE_GPU", + "POWER_IDE_DISPLAY", + "POWER_IDE_CAMERA", + "POWER_IDE_BLUETOOTH", + "POWER_IDE_FLASHLIGHT", + "POWER_IDE_AUDIO", + "POWER_IDE_WIFISCAN", + "BRIGHTNESS_NIT", + "SIGNAL_LEVEL", + "WIFI_EVENT_RECEIVED", + "AUDIO_STREAM_CHANGE", + "AUDIO_VOLUME_CHANGE", + "WIFI_STATE", + "BLUETOOTH_BR_SWITCH_STATE", + "LOCATION_SWITCH_STATE", + "ENABLE_SENSOR", + "DISABLE_SENSOR", + "WORK_REMOVE", + "WORK_START", + "WORK_STOP", + "WORK_ADD", + "POWER_RUNNINGLOCK", + "GNSS_STATE", + "ANOMALY_SCREEN_OFF_ENERGY", + "ANOMALY_ALARM_WAKEUP", + "ANOMALY_KERNEL_WAKELOCK", + "ANOMALY_RUNNINGLOCK", + "ANORMALY_APP_ENERGY", + "ANOMALY_GNSS_ENERGY", + "ANOMALY_CPU_HIGH_FREQUENCY", + "ANOMALY_CPU_ENERGY", + "ANOMALY_WAKEUP"}; + const uint64_t MSEC_TO_NS = 1000 * 1000; + std::vector hisyseventTS_; + bool isDeviceState = true; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HTRACE_HISYSEVENT_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_mem_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_mem_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b99806682179fe34cb303955d5f55f462f3dbc4a --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_mem_parser.cpp @@ -0,0 +1,880 @@ +/* + * 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 "htrace_mem_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +#include "system_event_measure_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceMemParser::HtraceMemParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ + for (auto i = 0; i < MEM_MAX; i++) { + memNameDictMap_.insert( + std::make_pair(static_cast(i), + traceDataCache_->GetDataIndex(config_.memNameMap_.at(static_cast(i))))); + } + for (auto i = 0; i < SysMeminfoType::PMEM_KERNEL_RECLAIMABLE + 1; i++) { + sysMemNameDictMap_.insert( + std::make_pair(static_cast(i), + traceDataCache_->GetDataIndex(config_.sysMemNameMap_.at(static_cast(i))))); + } + for (auto i = 0; i < SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE + 1; i++) { + sysVMemNameDictMap_.insert(std::make_pair( + static_cast(i), + traceDataCache_->GetDataIndex(config_.sysVirtualMemNameMap_.at(static_cast(i))))); + } +} + +HtraceMemParser::~HtraceMemParser() +{ + TS_LOGI("mem ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceMemParser::Parse(const MemoryData& tracePacket, uint64_t timeStamp, BuiltinClocks clock) +{ + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(clock, timeStamp); + UpdatePluginTimeRange(clock, timeStamp, newTimeStamp); + zram_ = tracePacket.zram(); + if (tracePacket.processesinfo_size()) { + ParseProcessInfo(tracePacket, newTimeStamp); + } + if (tracePacket.meminfo_size()) { + ParseMemInfo(tracePacket, newTimeStamp); + } + if (tracePacket.vmeminfo_size()) { + ParseVMemInfo(tracePacket, newTimeStamp); + } +} +void HtraceMemParser::ParseProcessInfo(const MemoryData& tracePacket, uint64_t timeStamp) const +{ + if (tracePacket.processesinfo_size()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_MEMORY, STAT_EVENT_RECEIVED); + } + for (int32_t i = 0; i < tracePacket.processesinfo_size(); i++) { + auto memInfo = tracePacket.processesinfo(i); + auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName(memInfo.pid(), memInfo.name()); + uint32_t hasValue = 0; + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_VM_SIZE), + timeStamp, memInfo.vm_size_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_VM_RSS), + timeStamp, memInfo.vm_rss_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_VM_ANON), + timeStamp, memInfo.rss_anon_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_RSS_FILE), + timeStamp, memInfo.rss_file_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_RSS_SHMEM), + timeStamp, memInfo.rss_shmem_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_VM_SWAP), + timeStamp, memInfo.vm_swap_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_VM_LOCKED), + timeStamp, memInfo.vm_locked_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData(ipid, memNameDictMap_.at(MEM_VM_HWM), + timeStamp, memInfo.vm_hwm_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_OOM_SCORE_ADJ), timeStamp, memInfo.oom_score_adj()); + if (hasValue) { + streamFilters_->processFilter_->AddProcessMemory(ipid); + } + if (memInfo.smapinfo_size()) { + ParseSmapsInfoEasy(memInfo, timeStamp); + } + } +} + +void HtraceMemParser::ParseSmapsInfoEasy(const ProcessMemoryInfo& memInfo, uint64_t timeStamp) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_SMAPS, STAT_EVENT_RECEIVED); + for (auto itor = memInfo.smapinfo().begin(); itor != memInfo.smapinfo().end(); itor++) { + auto startAddr = "0x" + itor->start_addr(); + auto endAddr = "0x" + itor->end_addr(); + uint64_t dirty = itor->dirty(); + uint64_t swapper = itor->swapper(); + uint64_t rss = itor->rss(); + uint64_t pss = itor->pss(); + uint64_t size = itor->size(); + double reside = itor->reside(); + DataIndex protection = traceDataCache_->GetDataIndex(itor->permission()); + DataIndex path = traceDataCache_->GetDataIndex(itor->path()); + traceDataCache_->GetSmapsData()->AppendNewData(timeStamp, startAddr, endAddr, dirty, swapper, rss, pss, size, + reside, protection, path); + } +} + +void HtraceMemParser::ParseMemInfoEasy(const MemoryData& tracePacket, uint64_t timeStamp) const +{ + if (tracePacket.meminfo_size()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + } + for (int32_t i = 0; i < tracePacket.meminfo_size(); i++) { + auto memInfo = tracePacket.meminfo(i); + if (config_.sysMemNameMap_.find(memInfo.key()) != config_.sysMemNameMap_.end()) { + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData(sysMemNameDictMap_.at(memInfo.key()), + timeStamp, memInfo.value()); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_DATA_INVALID); + } + } +} + +void HtraceMemParser::ParseVMemInfoEasy(const MemoryData& tracePacket, uint64_t timeStamp) const +{ + traceDataCache_->UpdateTraceTime(timeStamp); + if (tracePacket.vmeminfo_size()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + } + for (int32_t i = 0; i < tracePacket.vmeminfo_size(); i++) { + auto memInfo = tracePacket.vmeminfo(i); + if (config_.sysVirtualMemNameMap_.find(memInfo.key()) != config_.sysVirtualMemNameMap_.end()) { + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData(sysVMemNameDictMap_.at(memInfo.key()), + timeStamp, memInfo.value()); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_DATA_INVALID); + } + } +} + +void HtraceMemParser::ParseMemInfo(const MemoryData& tracePacket, uint64_t timeStamp) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + for (int32_t i = 0; i < tracePacket.meminfo_size(); i++) { + auto vMemInfo = tracePacket.meminfo(i); + switch (static_cast(vMemInfo.key())) { + case SysMeminfoType::PMEM_UNSPECIFIED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_UNSPECIFIED), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_MEM_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MEM_TOTAL), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_MEM_FREE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MEM_FREE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_MEM_AVAILABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MEM_AVAILABLE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_BUFFERS: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_BUFFERS), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_CACHED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_CACHED), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SWAP_CACHED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SWAP_CACHED), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_ACTIVE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ACTIVE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_INACTIVE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_INACTIVE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_ACTIVE_ANON: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ACTIVE_ANON), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_INACTIVE_ANON: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_INACTIVE_ANON), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_ACTIVE_FILE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ACTIVE_FILE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_INACTIVE_FILE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_INACTIVE_FILE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_UNEVICTABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_UNEVICTABLE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_MLOCKED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MLOCKED), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SWAP_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SWAP_TOTAL), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SWAP_FREE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SWAP_FREE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_DIRTY: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_DIRTY), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_WRITEBACK: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_WRITEBACK), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_ANON_PAGES: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ANON_PAGES), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_MAPPED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MAPPED), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SHMEM: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SHMEM), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SLAB: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SLAB), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SLAB_RECLAIMABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SLAB_RECLAIMABLE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_KERNEL_STACK: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_KERNEL_STACK), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_PAGE_TABLES: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_PAGE_TABLES), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_COMMIT_LIMIT: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_COMMIT_LIMIT), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_COMMITED_AS: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_COMMITED_AS), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_VMALLOC_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_VMALLOC_TOTAL), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_VMALLOC_USED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_VMALLOC_USED), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_VMALLOC_CHUNK: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_VMALLOC_CHUNK), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_CMA_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_CMA_TOTAL), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_CMA_FREE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_CMA_FREE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType::PMEM_KERNEL_RECLAIMABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_KERNEL_RECLAIMABLE), timeStamp, vMemInfo.value()); + break; + case SysMeminfoType_INT_MIN_SENTINEL_DO_NOT_USE_: + case SysMeminfoType_INT_MAX_SENTINEL_DO_NOT_USE_: + default: + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_DATA_INVALID); + break; + } + } + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData(zramIndex_, timeStamp, zram_); +} +void HtraceMemParser::ParseVMemInfo(const MemoryData& tracePacket, uint64_t timeStamp) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + for (int32_t i = 0; i < tracePacket.vmeminfo_size(); i++) { + auto vMemInfo = tracePacket.vmeminfo(i); + switch (static_cast(vMemInfo.key())) { + case SysVMeminfoType::VMEMINFO_UNSPECIFIED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNSPECIFIED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FREE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FREE_PAGES), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ALLOC_BATCH: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ALLOC_BATCH), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_INACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_INACTIVE_ANON), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ACTIVE_ANON), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_INACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_INACTIVE_FILE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ACTIVE_FILE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_UNEVICTABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_UNEVICTABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_MLOCK: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_MLOCK), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ANON_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ANON_PAGES), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_MAPPED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_MAPPED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FILE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FILE_PAGES), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTY: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTY), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_WRITEBACK: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_WRITEBACK), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SLAB_RECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SLAB_RECLAIMABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SLAB_UNRECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SLAB_UNRECLAIMABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_PAGE_TABLE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_PAGE_TABLE_PAGES), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_KERNEL_STACK: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_KERNEL_STACK), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_OVERHEAD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_OVERHEAD), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_UNSTABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_UNSTABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_BOUNCE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_BOUNCE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_VMSCAN_WRITE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_VMSCAN_WRITE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_WRITEBACK_TEMP: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_WRITEBACK_TEMP), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ISOLATED_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ISOLATED_ANON), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ISOLATED_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ISOLATED_FILE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHMEM: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHMEM), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTIED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTIED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_WRITTEN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_WRITTEN), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_PAGES_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_PAGES_SCANNED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_REFAULT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_REFAULT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_ACTIVATE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_ACTIVATE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_NODERECLAIM: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_NODERECLAIM), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FREE_CMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FREE_CMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SWAPCACHE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SWAPCACHE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTY_THRESHOLD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTY_THRESHOLD), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGPGIN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGPGIN), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGPGOUT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGPGOUT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGPGOUTCLEAN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGPGOUTCLEAN), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PSWPIN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PSWPIN), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PSWPOUT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PSWPOUT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGALLOC_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGALLOC_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGALLOC_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGALLOC_NORMAL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGALLOC_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGALLOC_MOVABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGFREE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGFREE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGACTIVATE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGACTIVATE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGDEACTIVATE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGDEACTIVATE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGFAULT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGFAULT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGMAJFAULT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGMAJFAULT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL_NORMAL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL_MOVABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_NORMAL), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_MOVABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_NORMAL), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_MOVABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_NORMAL), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_MOVABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_NORMAL), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_MOVABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_THROTTLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_THROTTLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGINODESTEAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGINODESTEAL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_SLABS_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_SLABS_SCANNED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_KSWAPD_INODESTEAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_KSWAPD_INODESTEAL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PAGEOUTRUN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PAGEOUTRUN), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGROTATED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGROTATED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_DROP_PAGECACHE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_DROP_PAGECACHE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_DROP_SLAB: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_DROP_SLAB), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGMIGRATE_SUCCESS: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGMIGRATE_SUCCESS), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGMIGRATE_FAIL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGMIGRATE_FAIL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_MIGRATE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_MIGRATE_SCANNED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_FREE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_FREE_SCANNED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_ISOLATED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_ISOLATED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_STALL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_STALL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_FAIL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_FAIL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_SUCCESS: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_SUCCESS), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_WAKE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_WAKE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CULLED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CULLED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_SCANNED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_RESCUED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_RESCUED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MLOCKED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MLOCKED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CLEARED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CLEARED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_STRANDED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_STRANDED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZSPAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZSPAGES), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ION_HEAP: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ION_HEAP), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_GPU_HEAP: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_GPU_HEAP), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL_MOVABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL_NORMAL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_FREE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_FREE_SCANNED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FASTRPC: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FASTRPC), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_INDIRECTLY_RECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_INDIRECTLY_RECLAIMABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ION_HEAP_POOL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ION_HEAP_POOL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHADOW_CALL_STACK_BYTES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHADOW_CALL_STACK_BYTES), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHMEM_HUGEPAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHMEM_HUGEPAGES), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHMEM_PMDMAPPED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHMEM_PMDMAPPED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_UNRECLAIMABLE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_UNRECLAIMABLE_PAGES), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_ANON), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_FILE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_ANON), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_FILE), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_UNEVICTABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_UNEVICTABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_WRITE_PENDING: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_WRITE_PENDING), timeStamp, + vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_OOM_KILL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_OOM_KILL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGLAZYFREE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGLAZYFREE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGLAZYFREED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGLAZYFREED), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSKIP_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSKIP_DMA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSKIP_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSKIP_MOVABLE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSKIP_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSKIP_NORMAL), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_SWAP_RA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_SWAP_RA), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_SWAP_RA_HIT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_SWAP_RA_HIT), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE), timeStamp, vMemInfo.value()); + break; + case SysVMeminfoType_INT_MIN_SENTINEL_DO_NOT_USE_: + case SysVMeminfoType_INT_MAX_SENTINEL_DO_NOT_USE_: + default: + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_DATA_INVALID); + } + } +} +void HtraceMemParser::Finish() +{ + if (traceDataCache_->traceStartTime_ == INVALID_UINT64 || traceDataCache_->traceEndTime_ == 0) { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + } else { + TS_LOGI("mem data time is not updated, maybe this trace file has other data"); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_mem_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_mem_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..3ddc2898de2a782affb92a60dfc3599701f379af --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_mem_parser.h @@ -0,0 +1,54 @@ +/* + * 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 HTRACE_MEM_PARSER_H +#define HTRACE_MEM_PARSER_H + +#include +#include +#include +#include +#include +#include "htrace_plugin_time_parser.h" +#include "memory_plugin_result.pb.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceMemParser : public HtracePluginTimeParser { +public: + HtraceMemParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceMemParser(); + void Parse(const MemoryData& tracePacket, uint64_t, BuiltinClocks clock); + void Finish(); + +private: + void ParseProcessInfo(const MemoryData& tracePacket, uint64_t timeStamp) const; + void ParseMemInfo(const MemoryData& tracePacket, uint64_t timeStamp) const; + void ParseMemInfoEasy(const MemoryData& tracePacket, uint64_t timeStamp) const; + void ParseVMemInfo(const MemoryData& tracePacket, uint64_t timeStamp) const; + void ParseVMemInfoEasy(const MemoryData& tracePacket, uint64_t timeStamp) const; + void ParseSmapsInfoEasy(const ProcessMemoryInfo& memInfo, uint64_t timeStamp) const; + std::map memNameDictMap_ = {}; + std::map sysMemNameDictMap_ = {}; + std::map sysVMemNameDictMap_ = {}; + uint64_t zram_ = 0; + const DataIndex zramIndex_ = traceDataCache_->GetDataIndex("sys.mem.zram"); + TraceStreamerConfig config_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_MEM_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_native_hook_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_native_hook_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62581b58e4c10e66ac8cd4c23da0b819e0f0fb54 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_native_hook_parser.cpp @@ -0,0 +1,432 @@ +/* + * 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 "htrace_native_hook_parser.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceNativeHookParser::HtraceNativeHookParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx), frameToFrameId_(INVALID_UINT32) +{ + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/libc++.so")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib64/libc++.so")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-aarch64.so.1")); + invalidLibPathIndexs_.insert(traceDataCache_->dataDict_.GetStringIndex("/system/lib/ld-musl-arm.so.1")); +} + +HtraceNativeHookParser::~HtraceNativeHookParser() +{ + TS_LOGI("native hook data ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); + TS_LOGI("native real ts MIN:%llu, MAX:%llu", static_cast(MinTs()), + static_cast(MaxTs())); +} +// In order to improve the accuracy of data, it is necessary to sort the original data. +// Data sorting will be reduced by 5% to 10% Speed of parsing data. +void HtraceNativeHookParser::Parse(BatchNativeHookData& tracePacket) +{ + for (auto i = 0; i < tracePacket.events_size(); i++) { + auto nativeHookData = std::make_unique(*tracePacket.mutable_events(i)); + auto timeStamp = nativeHookData->tv_nsec() + nativeHookData->tv_sec() * SEC_TO_NS; + tsToMainEventsMap_.insert(std::make_pair(timeStamp, std::move(nativeHookData))); + MaybeParseNativeHookData(); + } + return; +} +template +void HtraceNativeHookParser::UpdateMap(std::unordered_map& sourceMap, T1 key, T2 value) +{ + auto itor = sourceMap.find(key); + if (itor != sourceMap.end()) { + itor->second = value; + } else { + sourceMap.insert(std::make_pair(key, value)); + } +} +void HtraceNativeHookParser::MaybeParseNativeHookData() +{ + if (tsToMainEventsMap_.size() > MAX_CACHE_SIZE) { + ParseNativeHookData(tsToMainEventsMap_.begin()->first, tsToMainEventsMap_.begin()->second.get()); + tsToMainEventsMap_.erase(tsToMainEventsMap_.begin()); + } +} +void HtraceNativeHookParser::FinishParseNativeHookData() +{ + for (auto it = tsToMainEventsMap_.begin(); it != tsToMainEventsMap_.end(); it++) { + ParseNativeHookData(it->first, it->second.get()); + } + if (traceDataCache_->GetNativeHookData()->Size() == 0) { + return; + } + traceDataCache_->GetNativeHookData()->UpdateMemMapSubType(); + // update function name index + traceDataCache_->GetNativeHookFrameData()->UpdateSymbolId(); + // update file path index + traceDataCache_->GetNativeHookFrameData()->UpdateFileId(filePathIdToFilePathName_); + // update instractions vaddr + GetNativeHookFrameVaddrs(); + traceDataCache_->GetNativeHookFrameData()->UpdateVaddrs(vaddrs_); + // update last lib id + GetCallIdToLastLibId(); + if (callIdToLastCallerPathIndex_.size()) { + traceDataCache_->GetNativeHookData()->UpdateLastCallerPathIndexs(callIdToLastCallerPathIndex_); + } + + UpdateThreadNameWithNativeHookData(); + tsToMainEventsMap_.clear(); + threadNameIdToThreadName_.clear(); + itidToThreadNameId_.clear(); + callIdToLastCallerPathIndex_.clear(); + functionNameIndexToVaddr_.clear(); + vaddrs_.clear(); +} +void HtraceNativeHookParser::GetCallIdToLastLibId() +{ + auto size = static_cast(traceDataCache_->GetNativeHookFrameData()->Size()); + uint32_t lastCallChainId = INVALID_UINT32; + bool foundLast = false; + for (auto i = size - 1; i > -1; i--) { + auto callChainId = traceDataCache_->GetNativeHookFrameData()->CallChainIds()[i]; + if (callChainId == lastCallChainId) { + if (foundLast) { + continue; + } + } + if (callChainId != lastCallChainId) { + lastCallChainId = callChainId; + foundLast = false; + } + auto filePathIndex = traceDataCache_->GetNativeHookFrameData()->FilePaths()[i]; + if (!traceDataCache_->GetNativeHookFrameData()->Depths()[i]) { + callIdToLastCallerPathIndex_.insert(std::make_pair(callChainId, filePathIndex)); + foundLast = true; + continue; + } + + auto lower = std::lower_bound(invalidLibPathIndexs_.begin(), invalidLibPathIndexs_.end(), filePathIndex); + if (lower == invalidLibPathIndexs_.end() || *lower != filePathIndex) { // found + auto filePath = traceDataCache_->dataDict_.GetDataFromDict(filePathIndex); + auto ret = filePath.find("libc++_shared.so"); + if (ret == filePath.npos) { + callIdToLastCallerPathIndex_.insert(std::make_pair(callChainId, filePathIndex)); + foundLast = true; + } + } + } +} + +void HtraceNativeHookParser::GetNativeHookFrameVaddrs() +{ + auto size = traceDataCache_->GetNativeHookFrameData()->Size(); + // Traverse every piece of native_hook frame data + for (auto i = 0; i < size; i++) { + auto symbolOffset = traceDataCache_->GetNativeHookFrameData()->SymbolOffsets()[i]; + // When the symbol offset is not 0, vaddr=offset+symbol offset + if (symbolOffset) { + auto fileOffset = traceDataCache_->GetNativeHookFrameData()->Offsets()[i]; + auto vaddr = base::Uint64ToHexText(fileOffset + symbolOffset); + vaddrs_.emplace_back(vaddr); + continue; + } + // When the symbol offset is 0, vaddr takes the string after the plus sign in the function name + auto functionNameIndex = traceDataCache_->GetNativeHookFrameData()->SymbolNames()[i]; + std::string vaddr = ""; + auto itor = functionNameIndexToVaddr_.find(functionNameIndex); + if (itor == functionNameIndexToVaddr_.end()) { + auto functionName = traceDataCache_->dataDict_.GetDataFromDict(functionNameIndex); + auto pos = functionName.rfind("+"); + if (pos != functionName.npos && pos != functionName.length() - 1) { + vaddr = functionName.substr(++pos); + } + // Vaddr keeps "" when lookup failed + functionNameIndexToVaddr_.emplace(std::make_pair(functionNameIndex, vaddr)); + } else { + vaddr = itor->second; + } + vaddrs_.emplace_back(vaddr); + } +} +void HtraceNativeHookParser::ParseAllocEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData) +{ + auto allocEvent = nativeHookData->alloc_event(); + auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(allocEvent.tid(), allocEvent.pid()); + auto ipid = streamFilters_->processFilter_->GetInternalPid(allocEvent.pid()); + if (allocEvent.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, allocEvent.thread_name_id()); + } + auto callChainId = ParseNativeHookFrame(allocEvent.frame_info()); + auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid, itid, allocEvent.GetTypeName(), INVALID_UINT64, newTimeStamp, 0, 0, allocEvent.addr(), + allocEvent.size()); + addrToAllocEventRow_.insert(std::make_pair(allocEvent.addr(), static_cast(row))); + MaybeUpdateCurrentSizeDur(row, newTimeStamp, true); +} +void HtraceNativeHookParser::ParseFreeEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData) +{ + auto freeEvent = nativeHookData->free_event(); + auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(freeEvent.tid(), freeEvent.pid()); + auto ipid = streamFilters_->processFilter_->GetInternalPid(freeEvent.pid()); + if (freeEvent.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, freeEvent.thread_name_id()); + } + int64_t freeHeapSize = 0; + uint64_t row = INVALID_UINT64; + if (addrToAllocEventRow_.count(freeEvent.addr())) { + row = addrToAllocEventRow_.at(freeEvent.addr()); + } + if (row != INVALID_UINT64 && newTimeStamp > traceDataCache_->GetNativeHookData()->TimeStampData()[row]) { + addrToAllocEventRow_.erase(freeEvent.addr()); + traceDataCache_->GetNativeHookData()->UpdateEndTimeStampAndDuration(row, newTimeStamp); + freeHeapSize = traceDataCache_->GetNativeHookData()->MemSizes()[row]; + } else { + TS_LOGD("func addr:%lu is empty", freeEvent.addr()); + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_DATA_INVALID); + return; + } + auto callChainId = ParseNativeHookFrame(freeEvent.frame_info()); + row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid, itid, freeEvent.GetTypeName(), INVALID_UINT64, newTimeStamp, 0, 0, freeEvent.addr(), + freeHeapSize); + if (freeHeapSize != 0) { + MaybeUpdateCurrentSizeDur(row, newTimeStamp, true); + } +} +void HtraceNativeHookParser::ParseMmapEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData) +{ + auto mMapEvent = nativeHookData->mmap_event(); + auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(mMapEvent.tid(), mMapEvent.pid()); + auto ipid = streamFilters_->processFilter_->GetInternalPid(mMapEvent.pid()); + if (mMapEvent.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, mMapEvent.thread_name_id()); + } + DataIndex subType = INVALID_UINT64; + if (!mMapEvent.type().empty()) { + subType = traceDataCache_->dataDict_.GetStringIndex(mMapEvent.type()); + traceDataCache_->GetNativeHookData()->UpdateAddrToMemMapSubType(mMapEvent.addr(), subType); + } + auto callChainId = ParseNativeHookFrame(mMapEvent.frame_info()); + auto row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid, itid, mMapEvent.GetTypeName(), subType, newTimeStamp, 0, 0, mMapEvent.addr(), + mMapEvent.size()); + addrToMmapEventRow_.insert(std::make_pair(mMapEvent.addr(), static_cast(row))); + MaybeUpdateCurrentSizeDur(row, newTimeStamp, false); +} +void HtraceNativeHookParser::ParseMunmapEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData) +{ + auto mUnMapEvent = nativeHookData->munmap_event(); + auto itid = streamFilters_->processFilter_->GetOrCreateThreadWithPid(mUnMapEvent.tid(), mUnMapEvent.pid()); + auto ipid = streamFilters_->processFilter_->GetInternalPid(mUnMapEvent.pid()); + if (mUnMapEvent.thread_name_id() != 0) { + UpdateMap(itidToThreadNameId_, itid, mUnMapEvent.thread_name_id()); + } + uint64_t row = INVALID_UINT64; + if (addrToMmapEventRow_.count(mUnMapEvent.addr())) { + row = addrToMmapEventRow_.at(mUnMapEvent.addr()); + } + int64_t effectiveMUnMapSize = 0; + if (row != INVALID_UINT64 && newTimeStamp > traceDataCache_->GetNativeHookData()->TimeStampData()[row]) { + addrToMmapEventRow_.erase(mUnMapEvent.addr()); + traceDataCache_->GetNativeHookData()->UpdateEndTimeStampAndDuration(row, newTimeStamp); + effectiveMUnMapSize = static_cast(mUnMapEvent.size()); + } else { + TS_LOGD("func addr:%lu is empty", mUnMapEvent.addr()); + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_DATA_INVALID); + return; + } + auto callChainId = ParseNativeHookFrame(mUnMapEvent.frame_info()); + row = traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid, itid, mUnMapEvent.GetTypeName(), INVALID_UINT64, newTimeStamp, 0, 0, mUnMapEvent.addr(), + mUnMapEvent.size()); + if (effectiveMUnMapSize != 0) { + MaybeUpdateCurrentSizeDur(row, newTimeStamp, false); + } +} +void HtraceNativeHookParser::ParseTagEvent(const NativeHookData* nativeHookData) +{ + auto memMapTagEvent = nativeHookData->tag_event(); + auto addr = memMapTagEvent.addr(); + auto size = memMapTagEvent.size(); + auto tagIndex = traceDataCache_->dataDict_.GetStringIndex(memMapTagEvent.tag()); + traceDataCache_->GetNativeHookData()->UpdateAddrToMemMapSubType(addr, tagIndex); +} +void HtraceNativeHookParser::ParseFileEvent(const NativeHookData* nativeHookData) +{ + auto filePathMapMessage = nativeHookData->file_path(); + auto id = filePathMapMessage.id(); + auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(filePathMapMessage.name()); + filePathIdToFilePathName_.insert(std::make_pair(id, nameIndex)); +} +void HtraceNativeHookParser::ParseSymbolEvent(const NativeHookData* nativeHookData) +{ + auto symbolMapMessage = nativeHookData->symbol_name(); + auto id = symbolMapMessage.id(); + auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(symbolMapMessage.name()); + traceDataCache_->GetNativeHookFrameData()->UpdateSymbolIdToNameMap(id, nameIndex); +} +void HtraceNativeHookParser::ParseThreadEvent(const NativeHookData* nativeHookData) +{ + auto threadNameMapMessage = nativeHookData->thread_name_map(); + auto id = threadNameMapMessage.id(); + auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(threadNameMapMessage.name()); + UpdateMap(threadNameIdToThreadName_, id, nameIndex); +} + +void HtraceNativeHookParser::ParseNativeHookData(const uint64_t timeStamp, const NativeHookData* nativeHookData) +{ + auto eventCase = nativeHookData->event_case(); + if (eventCase >= NativeHookData::kAllocEvent && eventCase <= NativeHookData::kMunmapEvent) { + uint64_t newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, newTimeStamp); + switch (eventCase) { + case NativeHookData::kAllocEvent: + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + if (newTimeStamp == timeStamp) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_DATA_INVALID); + } + ParseAllocEvent(newTimeStamp, nativeHookData); + break; + case NativeHookData::kFreeEvent: + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + if (newTimeStamp == timeStamp) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_DATA_INVALID); + } + ParseFreeEvent(newTimeStamp, nativeHookData); + break; + case NativeHookData::kMmapEvent: + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + if (newTimeStamp == timeStamp) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_DATA_INVALID); + } + ParseMmapEvent(newTimeStamp, nativeHookData); + break; + case NativeHookData::kMunmapEvent: + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + if (newTimeStamp == timeStamp) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_DATA_INVALID); + } + ParseMunmapEvent(newTimeStamp, nativeHookData); + break; + default: + TS_LOGE("An unknown type of data was received!"); + break; + } + } else { + switch (eventCase) { + case NativeHookData::kTagEvent: + ParseTagEvent(nativeHookData); + break; + case NativeHookData::kFilePath: + ParseFileEvent(nativeHookData); + break; + case NativeHookData::kSymbolName: + ParseSymbolEvent(nativeHookData); + break; + case NativeHookData::kThreadNameMap: + ParseThreadEvent(nativeHookData); + break; + default: + TS_LOGE("An unknown type of data was received!"); + break; + } + } +} +void HtraceNativeHookParser::MaybeUpdateCurrentSizeDur(uint64_t row, uint64_t timeStamp, bool isMalloc) +{ + auto& lastAnyEventRaw = isMalloc ? lastMallocEventRaw_ : lastMmapEventRaw_; + if (lastAnyEventRaw != INVALID_UINT64) { + traceDataCache_->GetNativeHookData()->UpdateCurrentSizeDur(lastAnyEventRaw, timeStamp); + } + lastAnyEventRaw = row; +} +uint32_t HtraceNativeHookParser::ParseNativeHookFrame(const RepeatedPtrField<::Frame>& repeatedFrame) +{ + // the callstack from nativehook of sourcedata is reverse order + // we need to show the last frame firstly + std::vector> callStackTemp = {}; + auto depth = 0; + for (auto i = repeatedFrame.size() - 1; i >= 0; i--) { + auto frame = repeatedFrame.Get(i); + DataIndex symbolNameIndex = INVALID_UINT64; + DataIndex filePathIndex = INVALID_UINT64; + if (!frame.symbol_name().empty()) { + symbolNameIndex = traceDataCache_->dataDict_.GetStringIndex(frame.symbol_name().c_str()); + traceDataCache_->GetNativeHookFrameData()->UpdateSymbolIdToNameMap(symbolNameIndex, symbolNameIndex); + } else if (frame.symbol_name_id()) { + symbolNameIndex = frame.symbol_name_id(); + } + if (!frame.file_path().empty()) { + filePathIndex = traceDataCache_->dataDict_.GetStringIndex(frame.file_path().c_str()); + filePathIdToFilePathName_.insert(std::make_pair(filePathIndex, filePathIndex)); + } else if (frame.file_path_id()) { + filePathIndex = frame.file_path_id(); + } + callStackTemp.emplace_back(std::move(std::make_unique( + filePathIndex, symbolNameIndex, depth, frame.offset(), frame.symbol_offset()))); + depth++; + } + + // Determine whether to write callstack data to cache + auto callChainId = INVALID_UINT32; + bool callStackNotExist = false; + auto size = callStackTemp.size(); + for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) { + auto callstack = itor->get(); + auto ret = frameToFrameId_.Find(callstack->fileId_, callstack->symbolId_, callstack->depth_, size); + if (ret != INVALID_UINT32) { // find it + if (callChainId == INVALID_UINT32) { + callChainId = ret; + } else if (callChainId != ret) { + callStackNotExist = true; + break; + } + } else { // not find it + callStackNotExist = true; + break; + } + } + // write callstack data to cache + if (callStackNotExist) { + callChainId = ++callChainId_; + for (auto itor = callStackTemp.begin(); itor != callStackTemp.end(); itor++) { + auto callstack = itor->get(); + frameToFrameId_.Insert(callstack->fileId_, callstack->symbolId_, callstack->depth_, callStackTemp.size(), + callChainId); + traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame( + callChainId, callstack->depth_, callstack->ip_, callstack->sp_, callstack->symbolId_, + callstack->fileId_, callstack->offset_, callstack->symbolOffset_); + } + } + callStackTemp.clear(); + return callChainId; +} +void HtraceNativeHookParser::UpdateThreadNameWithNativeHookData() const +{ + if (itidToThreadNameId_.empty() || threadNameIdToThreadName_.empty()) { + return; + } + for (auto itor = itidToThreadNameId_.begin(); itor != itidToThreadNameId_.end(); ++itor) { + auto thread = traceDataCache_->GetThreadData(itor->first); + if (thread->nameIndex_ == 0) { + auto threadNameMapItor = threadNameIdToThreadName_.find(itor->second); + if (threadNameMapItor != threadNameIdToThreadName_.end()) { + thread->nameIndex_ = threadNameMapItor->second; + } + } + } +} +void HtraceNativeHookParser::Finish() +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_native_hook_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_native_hook_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..fe64cc6fae4c58dbcfbc7676858376daeca5a66e --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_native_hook_parser.h @@ -0,0 +1,96 @@ +/* + * 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 HTRACE_NATIVE_HOOK_PARSER_H +#define HTRACE_NATIVE_HOOK_PARSER_H +#include +#include +#include +#include +#include "double_map.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "htrace_plugin_time_parser.h" +#include "native_hook_result.pb.h" +#include "numerical_to_string.h" +#include "process_filter.h" +#include "quatra_map.h" +#include "stat_filter.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceNativeHookParser : public HtracePluginTimeParser { +public: + HtraceNativeHookParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceNativeHookParser(); + void Parse(BatchNativeHookData& tracePacket); + void FinishParseNativeHookData(); + void Finish(); + +private: + class NativeHookFrameTemp { + public: + NativeHookFrameTemp() {} + NativeHookFrameTemp(uint64_t fileId, uint64_t symbolId, uint32_t depth, uint64_t offset, uint64_t symbolOffset) + : fileId_(fileId), symbolId_(symbolId), depth_(depth), offset_(offset), symbolOffset_(symbolOffset) + { + } + ~NativeHookFrameTemp() {} + uint64_t fileId_ = 0; + uint64_t symbolId_ = 0; + uint32_t depth_ = 0; + uint32_t ip_ = 0; + uint32_t sp_ = 0; + uint64_t offset_ = 0; + uint64_t symbolOffset_ = 0; + }; + template + void UpdateMap(std::unordered_map& sourceMap, T1 key, T2 value); + void MaybeParseNativeHookData(); + void ParseNativeHookData(const uint64_t timeStamp, const NativeHookData* nativeHookData); + uint32_t ParseNativeHookFrame(const RepeatedPtrField<::Frame>& repeatedFrame); + void MaybeUpdateCurrentSizeDur(uint64_t row, uint64_t timeStamp, bool isMalloc); + void UpdateThreadNameWithNativeHookData() const; + void ParseAllocEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData); + void ParseFreeEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData); + void ParseMmapEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData); + void ParseMunmapEvent(uint64_t newTimeStamp, const NativeHookData* nativeHookData); + void ParseTagEvent(const NativeHookData* nativeHookData); + void ParseFileEvent(const NativeHookData* nativeHookData); + void ParseSymbolEvent(const NativeHookData* nativeHookData); + void ParseThreadEvent(const NativeHookData* nativeHookData); + void GetCallIdToLastLibId(); + void GetNativeHookFrameVaddrs(); + uint32_t callChainId_ = 0; + std::unordered_map addrToAllocEventRow_; + std::unordered_map addrToMmapEventRow_; + uint64_t lastMallocEventRaw_ = INVALID_UINT64; + uint64_t lastMmapEventRaw_ = INVALID_UINT64; + std::multimap> tsToMainEventsMap_ = {}; + std::unordered_map threadNameIdToThreadName_ = {}; + std::unordered_map itidToThreadNameId_ = {}; + QuatraMap frameToFrameId_; + std::set invalidLibPathIndexs_ = {}; + std::map filePathIdToFilePathName_ = {}; + std::unordered_map callIdToLastCallerPathIndex_ = {}; + std::map functionNameIndexToVaddr_ = {}; + std::deque vaddrs_ = {}; + const size_t MAX_CACHE_SIZE = 200000; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_NATIVE_HOOK_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_network_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_network_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8166eb25e8ca5c81fef99b4a5aeafbcc4c30ab7e --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_network_parser.cpp @@ -0,0 +1,84 @@ +/* + * 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 "htrace_network_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceNetworkParser::HtraceNetworkParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceNetworkParser::~HtraceNetworkParser() +{ + TS_LOGI("network ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} + +void HtraceNetworkParser::Parse(NetworkDatas& tracePacket, uint64_t ts) +{ + auto netSysInfo = tracePacket.network_system_info(); + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + streamFilters_->statFilter_->IncreaseStat(TRACE_NETWORK, STAT_EVENT_RECEIVED); + networkData_.push_back(std::move(TsNetworkData{ts, netSysInfo})); +} +void HtraceNetworkParser::Finish() +{ + auto cmp = [](const TsNetworkData& a, const TsNetworkData& b) { return a.ts < b.ts; }; +#ifdef IS_WASM + std::sort(networkData_.begin(), networkData_.end(), cmp); +#else + std::stable_sort(networkData_.begin(), networkData_.end(), cmp); +#endif + bool firstTime = true; + uint64_t lastTs = 0; + uint64_t lastRx = 0; + uint64_t lastTx = 0; + uint64_t lastPacketIn = 0.0; + uint64_t lastPacketOut = 0.0; + for (auto itor = networkData_.begin(); itor != networkData_.end(); itor++) { + auto networkSysData = itor->networkSysData; + auto newTimeStamp = itor->ts; + UpdatePluginTimeRange(TS_CLOCK_REALTIME, itor->ts, newTimeStamp); + if (firstTime) { + lastTs = newTimeStamp; + lastRx = networkSysData.rx_bytes(); + lastTx = networkSysData.tx_bytes(); + lastPacketIn = networkSysData.rx_packets(); + lastPacketOut = networkSysData.tx_packets(); + firstTime = false; + continue; + } + auto dur = newTimeStamp - lastTs; + auto durS = 1.0 * dur / SEC_TO_NS; + traceDataCache_->GetNetworkData()->AppendNewNetData( + newTimeStamp, networkSysData.tx_bytes(), networkSysData.rx_bytes(), dur, + 1.0 * (networkSysData.rx_bytes() - lastRx) / durS, 1.0 * (networkSysData.tx_bytes() - lastTx) / durS, + networkSysData.rx_packets(), 1.0 * (networkSysData.rx_packets() - lastPacketIn) / durS, + networkSysData.tx_packets(), 1.0 * (networkSysData.tx_packets() - lastPacketOut) / durS, "undefined"); + lastTs = newTimeStamp; + lastRx = networkSysData.rx_bytes(); + lastTx = networkSysData.tx_bytes(); + lastPacketIn = networkSysData.rx_packets(); + lastPacketOut = networkSysData.tx_packets(); + } + networkData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_network_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_network_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..de3704c57a43099f251cb227065f6869c10168d3 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_network_parser.h @@ -0,0 +1,52 @@ +/* + * 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 HTRACE_NETWORK_PARSER_H +#define HTRACE_NETWORK_PARSER_H +#include +#include +#include +#include +#include "htrace_plugin_time_parser.h" +#include "network_plugin_result.pb.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceNetworkParser : public HtracePluginTimeParser { +public: + HtraceNetworkParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceNetworkParser(); + void Parse(NetworkDatas& tracePacket, uint64_t ts); + void Finish(); + struct TsNetworkData { + uint64_t ts; + NetworkSystemData networkSysData; + }; + std::vector networkData_; + +private: + uint64_t lastLineSeq_ = 0; + struct LastNetWorkDetail { + uint64_t rx; + uint64_t tx; + uint64_t ts; + }; + + std::unordered_map lastNetworkDetail_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_NETWORK_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa019290f66e8fdcee4558f5dbec1fc83d7c8f96 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_parser.cpp @@ -0,0 +1,646 @@ +/* + * 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 "htrace_parser.h" +#include +#include "binder_filter.h" +#include "cpu_filter.h" +#include "ftrace_event.pb.h" +#include "log.h" +#include "memory_plugin_result.pb.h" +#include "services/common_types.pb.h" +#include "stat_filter.h" +#include "trace_plugin_result.pb.h" +#if IS_WASM +#include "../rpc/wasm_func.h" +#endif +namespace SysTuning { +namespace TraceStreamer { +HtraceParser::HtraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters) + : ParserBase(filters), + traceDataCache_(dataCache), + htraceCpuDetailParser_(std::make_unique(dataCache, filters)), + htraceSymbolsDetailParser_(std::make_unique(dataCache, filters)), + htraceMemParser_(std::make_unique(dataCache, filters)), + htraceClockDetailParser_(std::make_unique(dataCache, filters)), + htraceHiLogParser_(std::make_unique(dataCache, filters)), + htraceNativeHookParser_(std::make_unique(dataCache, filters)), + htraceHidumpParser_(std::make_unique(dataCache, filters)), + cpuUsageParser_(std::make_unique(dataCache, filters)), + networkParser_(std::make_unique(dataCache, filters)), + diskIOParser_(std::make_unique(dataCache, filters)), + processParser_(std::make_unique(dataCache, filters)), + ebpfDataParser_(std::make_unique(dataCache, filters)), + hisyseventParser_(std::make_unique(dataCache, filters)), +#if WITH_PERF + perfDataParser_(std::make_unique(dataCache, filters)), +#endif +#ifdef SUPPORTTHREAD + dataSegArray_(std::make_unique(MAX_SEG_ARRAY_SIZE)), + supportThread_(true), +#else + dataSegArray_(std::make_unique(1)) +#endif +{ +} + +HtraceParser::~HtraceParser() +{ + TS_LOGI("clockid 2 is for RealTime and 1 is for BootTime"); +} + +void HtraceParser::WaitForParserEnd() +{ + if (parseThreadStarted_ || filterThreadStarted_) { + toExit_ = true; + while (!exited_) { + usleep(sleepDur_ * sleepDur_); + } + } + htraceCpuDetailParser_->FilterAllEvents(); + htraceNativeHookParser_->FinishParseNativeHookData(); + htraceHiLogParser_->Finish(); + htraceNativeHookParser_->Finish(); + htraceHidumpParser_->Finish(); + cpuUsageParser_->Finish(); + networkParser_->Finish(); + processParser_->Finish(); + diskIOParser_->Finish(); + hisyseventParser_->Finish(); + // keep final upate perf and ebpf data time range + ebpfDataParser_->Finish(); +#if WITH_PERF + perfDataParser_->Finish(); +#endif + htraceMemParser_->Finish(); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_TRACE, + dataSourceTypeTraceClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_MEM, dataSourceTypeMemClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_HILOG, + dataSourceTypeHilogClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_ALLOCATION, + dataSourceTypeAllocationClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_FPS, dataSourceTypeFpsClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_NETWORK, + dataSourceTypeNetworkClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_DISKIO, + dataSourceTypeDiskioClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_CPU, dataSourceTypeCpuClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_PROCESS, + dataSourceTypeProcessClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_HISYSEVENT, + dataSourceTypeHisyseventClockid_); + traceDataCache_->GetDataSourceClockIdData()->Finish(); + dataSegArray_.reset(); +} + +void HtraceParser::ParseTraceDataItem(const std::string& buffer) +{ + int32_t head = rawDataHead_; + if (!supportThread_) { + dataSegArray_[head].seg = std::move(buffer); + dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED; + ParserData(dataSegArray_[head]); + return; + } + while (!toExit_) { + if (dataSegArray_[head].status.load() != TS_PARSE_STATUS_INIT) { + usleep(sleepDur_); + continue; + } + dataSegArray_[head].seg = std::move(buffer); + dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED; + rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE; + break; + } + if (!parseThreadStarted_) { + parseThreadStarted_ = true; + int32_t tmp = maxThread_; + while (tmp--) { + parserThreadCount_++; + std::thread ParseTypeThread(&HtraceParser::ParseThread, this); + ParseTypeThread.detach(); + TS_LOGD("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_); + } + } +} +void HtraceParser::FilterData(HtraceDataSegment& seg) +{ + if (seg.dataType == DATA_SOURCE_TYPE_TRACE) { + if (seg.traceData->ftrace_cpu_detail_size()) { + htraceCpuDetailParser_->Parse(seg.traceData.get(), seg.clockId); // has Event + } + if (seg.traceData->symbols_detail_size()) { + htraceSymbolsDetailParser_->Parse(seg.traceData.get()); // has Event + } + if (seg.traceData->clocks_detail_size()) { + htraceClockDetailParser_->Parse(seg.traceData.get()); // has Event + } + } else if (seg.dataType == DATA_SOURCE_TYPE_MEM) { + htraceMemParser_->Parse(seg.memData, seg.timeStamp, seg.clockId); + } else if (seg.dataType == DATA_SOURCE_TYPE_HILOG) { + htraceHiLogParser_->Parse(seg.logData); + } else if (seg.dataType == DATA_SOURCE_TYPE_ALLOCATION) { + htraceNativeHookParser_->Parse(seg.batchNativeHookData); + } else if (seg.dataType == DATA_SOURCE_TYPE_FPS) { + htraceHidumpParser_->Parse(seg.hidumpInfo); + dataSourceTypeFpsClockid_ = htraceHidumpParser_->ClockId(); + } else if (seg.dataType == DATA_SOURCE_TYPE_NETWORK) { + networkParser_->Parse(seg.networkInfo, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_CPU) { + cpuUsageParser_->Parse(seg.cpuInfo, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_PROCESS) { + processParser_->Parse(seg.processInfo, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_DISKIO) { + diskIOParser_->Parse(seg.diskIOInfo, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_HISYSEVENT) { // + hisyseventParser_->Parse(seg.hisyseventInfo, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_HISYSEVENT_CONFIG) { // + hisyseventParser_->Parse(seg.hisyseventConfig, seg.timeStamp); + } + if (supportThread_) { + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; + } + seg.status = TS_PARSE_STATUS_INIT; +} +void HtraceParser::FilterThread() +{ + TS_LOGI("filter thread start work!"); + while (1) { + HtraceDataSegment& seg = dataSegArray_[filterHead_]; + if (seg.status.load() == TS_PARSE_STATUS_INVALID) { + seg.status = TS_PARSE_STATUS_INIT; + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + TS_LOGD("seprateHead_d:\t%d, parseHead_:\t%d, filterHead_:\t%d\n", rawDataHead_, parseHead_, filterHead_); + continue; + } + if (seg.status.load() != TS_PARSE_STATUS_PARSED) { + if (toExit_ && !parserThreadCount_) { + TS_LOGI("exiting Filter Thread"); + exited_ = true; + filterThreadStarted_ = false; + TS_LOGI("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + return; + } + TS_LOGD("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + usleep(sleepDur_); + continue; + } + FilterData(seg); + } +} + +void HtraceParser::ParserData(HtraceDataSegment& dataSeg) +{ + ProfilerPluginData pluginData; + if (!pluginData.ParseFromArray(dataSeg.seg.data(), static_cast(dataSeg.seg.length()))) { + TS_LOGW("ProfilerPluginData ParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.timeStamp = pluginData.tv_nsec() + pluginData.tv_sec() * SEC_TO_NS; + if (pluginData.name() == "memory-plugin") { + ParseMemory(pluginData, dataSeg); + } else if (pluginData.name() == "hilog-plugin" || pluginData.name() == "/data/local/tmp/libhilogplugin.z.so") { + ParseHilog(pluginData, dataSeg); + } else if (pluginData.name() == "ftrace-plugin" || pluginData.name() == "/data/local/tmp/libftrace_plugin.z.so") { + ParseFtrace(pluginData, dataSeg); + } else if (pluginData.name() == "nativehook" || pluginData.name() == "hookdaemon") { + ParseNativeHook(pluginData, dataSeg); + } else if (pluginData.name() == "hidump-plugin" || pluginData.name() == "/data/local/tmp/libhidumpplugin.z.so") { + ParseFPS(pluginData, dataSeg); + } else if (pluginData.name() == "cpu-plugin") { + ParseCpuUsage(pluginData, dataSeg); + } else if (pluginData.name() == "network-plugin") { + ParseNetwork(pluginData, dataSeg); + } else if (pluginData.name() == "diskio-plugin") { + ParseDiskIO(pluginData, dataSeg); + } else if (pluginData.name() == "process-plugin") { + ParseProcess(pluginData, dataSeg); + } else if (pluginData.name() == "hisysevent-plugin") { + ParseHisysevent(pluginData, dataSeg); + } else if (pluginData.name() == "hisysevent-plugin_config") { + ParseHisyseventConfig(pluginData, dataSeg); + } else { +#if IS_WASM + TraceStreamer_Plugin_Out_Filter(pluginData.data().data(), pluginData.data().length(), pluginData.name()); +#endif + dataSeg.status = TS_PARSE_STATUS_INVALID; + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + return; + } + if (!supportThread_) { // do it only in wasm mode, wasm noThead_ will be true + if (dataSeg.status == STAT_EVENT_DATA_INVALID) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + return; + } + FilterData(dataSeg); + } +} +void HtraceParser::ParseThread() +{ + TS_LOGI("parser thread start work!\n"); + while (1) { + if (supportThread_ && !filterThreadStarted_) { + filterThreadStarted_ = true; + std::thread ParserThread(&HtraceParser::FilterThread, this); + TS_LOGD("FilterThread start working ...\n"); + ParserThread.detach(); + } + int32_t head = GetNextSegment(); + if (head < 0) { + if (head == ERROR_CODE_EXIT) { + TS_LOGI("parse thread exit\n"); + return; + } else if (head == ERROR_CODE_NODATA) { + continue; + } + } + HtraceDataSegment& dataSeg = dataSegArray_[head]; + ParserData(dataSeg); + } +} + +void HtraceParser::ParseMemory(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSeg.dataType = DATA_SOURCE_TYPE_MEM; + BuiltinClocks clockId = TS_CLOCK_REALTIME; + auto clockIdTemp = pluginData.clock_id(); + if (clockIdTemp == ProfilerPluginData_ClockId_CLOCKID_REALTIME) { + clockId = TS_CLOCK_REALTIME; + } + dataSourceTypeMemClockid_ = clockId; + dataSeg.memData.Clear(); + if (!dataSeg.memData.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + if (dataSeg.memData.processesinfo_size()) { + dataSeg.dataType = DATA_SOURCE_TYPE_MEM; + dataSeg.clockId = clockId; + dataSeg.status = TS_PARSE_STATUS_PARSED; + } else if (dataSeg.memData.meminfo_size()) { + dataSeg.dataType = DATA_SOURCE_TYPE_MEM; + dataSeg.clockId = clockId; + dataSeg.status = TS_PARSE_STATUS_PARSED; + } else if (dataSeg.memData.vmeminfo_size()) { + dataSeg.dataType = DATA_SOURCE_TYPE_MEM; + dataSeg.clockId = clockId; + dataSeg.status = TS_PARSE_STATUS_PARSED; + } else { + dataSeg.status = TS_PARSE_STATUS_INVALID; + } +} +void HtraceParser::ParseHilog(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSeg.dataType = DATA_SOURCE_TYPE_HILOG; + dataSourceTypeHilogClockid_ = TS_CLOCK_REALTIME; + if (!dataSeg.logData.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + if (dataSeg.logData.info_size()) { + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.status = TS_PARSE_STATUS_INVALID; +} +void HtraceParser::ParseFtrace(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSeg.dataType = DATA_SOURCE_TYPE_TRACE; + dataSeg.traceData = std::make_unique(); + if (!dataSeg.traceData->ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + if (dataSeg.traceData->ftrace_cpu_stats_size()) { + auto cpuStats = dataSeg.traceData->ftrace_cpu_stats(0); + auto s = cpuStats.per_cpu_stats(0); + TS_LOGD("s.overrun():%lu", s.overrun()); + TS_LOGD("s.dropped_events():%lu", s.dropped_events()); + auto clock = cpuStats.trace_clock(); + if (clock == "boot") { + clock_ = TS_CLOCK_BOOTTIME; + } else if (clock == "mono") { + clock_ = TS_MONOTONIC; + } else { + TS_LOGI("invalid clock:%s", clock.c_str()); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.clockId = clock_; + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.clockId = clock_; + dataSourceTypeTraceClockid_ = clock_; + if (dataSeg.traceData->clocks_detail_size() || dataSeg.traceData->ftrace_cpu_detail_size() || + dataSeg.traceData->symbols_detail_size()) { + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.status = TS_PARSE_STATUS_INVALID; +} + +void HtraceParser::ParseNativeHook(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeAllocationClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_ALLOCATION; + if (!dataSeg.batchNativeHookData.ParseFromArray(pluginData.data().data(), + static_cast(pluginData.data().size()))) { + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + if (dataSeg.batchNativeHookData.events_size()) { + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.status = TS_PARSE_STATUS_INVALID; +} + +void HtraceParser::ParseFPS(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSeg.dataType = DATA_SOURCE_TYPE_FPS; + if (!dataSeg.hidumpInfo.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + if (dataSeg.hidumpInfo.fps_event_size()) { + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.status = TS_PARSE_STATUS_INVALID; +} + +void HtraceParser::ParseCpuUsage(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_CPU; + if (!dataSeg.cpuInfo.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + streamFilters_->statFilter_->IncreaseStat(TRACE_CPU_USAGE, STAT_EVENT_DATA_INVALID); + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + if (dataSeg.cpuInfo.has_cpu_usage_info() || dataSeg.cpuInfo.thread_info_size()) { + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.status = TS_PARSE_STATUS_INVALID; +} +void HtraceParser::ParseNetwork(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_NETWORK; + if (!dataSeg.networkInfo.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + streamFilters_->statFilter_->IncreaseStat(TRACE_NETWORK, STAT_EVENT_DATA_INVALID); + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.status = TS_PARSE_STATUS_PARSED; +} +void HtraceParser::ParseDiskIO(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_DISKIO; + if (!dataSeg.diskIOInfo.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + streamFilters_->statFilter_->IncreaseStat(TRACE_DISKIO, STAT_EVENT_DATA_INVALID); + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseProcess(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_BOOTTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_PROCESS; + if (!dataSeg.processInfo.ParseFromArray(pluginData.data().data(), static_cast(pluginData.data().size()))) { + streamFilters_->statFilter_->IncreaseStat(TRACE_PROCESS, STAT_EVENT_DATA_INVALID); + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.timeStamp = pluginData.tv_nsec() + pluginData.tv_sec() * SEC_TO_NS; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseHisysevent(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeHisyseventClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_HISYSEVENT; + if (!dataSeg.hisyseventInfo.ParseFromArray(pluginData.data().data(), + static_cast(pluginData.data().size()))) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_DATA_INVALID); + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.status = TS_PARSE_STATUS_PARSED; +} +void HtraceParser::ParseHisyseventConfig(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg) +{ + dataSourceTypeHisyseventClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_HISYSEVENT_CONFIG; + if (!dataSeg.hisyseventConfig.ParseFromArray(pluginData.data().data(), + static_cast(pluginData.data().size()))) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_DATA_INVALID); + TS_LOGW("tracePacketParseFromArray failed\n"); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +int32_t HtraceParser::GetNextSegment() +{ + int32_t head; + dataSegMux_.lock(); + head = parseHead_; + HtraceDataSegment& seg = dataSegArray_[head]; + if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) { + if (toExit_) { + parserThreadCount_--; + TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_); + TS_LOGD("seprateHead_x:\t%d, parseHead_:\t%d, filterHead_:\t%d status:%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + dataSegMux_.unlock(); + if (!parserThreadCount_ && !filterThreadStarted_) { + exited_ = true; + } + return ERROR_CODE_EXIT; + } + if (seg.status.load() == TS_PARSE_STATUS_PARSING) { + dataSegMux_.unlock(); + usleep(sleepDur_); + return ERROR_CODE_NODATA; + } + dataSegMux_.unlock(); + usleep(sleepDur_); + return ERROR_CODE_NODATA; + } + parseHead_ = (parseHead_ + 1) % MAX_SEG_ARRAY_SIZE; + seg.status = TS_PARSE_STATUS_PARSING; + dataSegMux_.unlock(); + return head; +} +bool HtraceParser::ParseDataRecursively(std::deque::iterator& packagesBegin, size_t& currentLength) +{ + if (!hasGotHeader_) { + if (InitProfilerTraceFileHeader()) { + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBuffer_.begin() + PACKET_HEADER_LENGTH); + currentLength -= PACKET_HEADER_LENGTH; + packagesBegin += PACKET_HEADER_LENGTH; + htraceCurentLength_ = profilerTraceFileHeader_.data.length; + htraceCurentLength_ -= PACKET_HEADER_LENGTH; + hasGotHeader_ = true; + if (!currentLength) { + return false; + } + } else { + TS_LOGE("get profiler trace file header failed"); + return false; + } + } + if (profilerTraceFileHeader_.data.dataType == ProfilerTraceFileHeader::HIPERF_DATA) { + if (packagesBuffer_.size() >= profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH) { +#if WITH_PERF + auto size = profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH; + perfDataParser_->InitPerfDataAndLoad(packagesBuffer_, size); + currentLength -= size; + packagesBegin += size; + profilerTraceFileHeader_.data.dataType = ProfilerTraceFileHeader::UNKNOW_TYPE; + hasGotHeader_ = false; + return true; +#endif + } + return false; + } + if (profilerTraceFileHeader_.data.dataType == ProfilerTraceFileHeader::STANDALONE_DATA) { + if (EBPF_PLUGIN_NAME.compare(profilerTraceFileHeader_.data.standalonePluginName) == 0 && + packagesBuffer_.size() >= profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH) { + auto size = profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH; + ebpfDataParser_->InitAndParseEbpfData(packagesBuffer_, size); + currentLength -= size; + packagesBegin += size; + profilerTraceFileHeader_.data.dataType = ProfilerTraceFileHeader::UNKNOW_TYPE; + hasGotHeader_ = false; + return true; + } +#if IS_WASM + if (packagesBuffer_.size() >= profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH) { + auto thirdPartySize = profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH; + auto buffer = std::make_unique(thirdPartySize).get(); + std::copy(packagesBuffer_.begin(), packagesBuffer_.begin() + thirdPartySize, buffer); + TraceStreamer_Plugin_Out_Filter(reinterpret_cast(buffer), thirdPartySize, + profilerTraceFileHeader_.data.standalonePluginName); + return true; + } +#endif + return false; + } + while (1) { + if (!hasGotSegLength_) { + if (currentLength < PACKET_SEG_LENGTH) { + break; + } + std::string bufferLine(packagesBegin, packagesBegin + PACKET_SEG_LENGTH); + const uint32_t* len = reinterpret_cast(bufferLine.data()); + nextLength_ = *len; + htraceLength_ += nextLength_ + PACKET_SEG_LENGTH; + hasGotSegLength_ = true; + currentLength -= PACKET_SEG_LENGTH; + packagesBegin += PACKET_SEG_LENGTH; + htraceCurentLength_ -= PACKET_SEG_LENGTH; + } + if (currentLength < nextLength_) { + break; + } + std::string bufferLine(packagesBegin, packagesBegin + nextLength_); + ParseTraceDataItem(bufferLine); + hasGotSegLength_ = false; + packagesBegin += nextLength_; + currentLength -= nextLength_; + if (nextLength_ > htraceCurentLength_) { + TS_LOGE("fatal error, data length not match nextLength_:%u, htraceCurentLength_:%llu", nextLength_, + htraceCurentLength_); + } + htraceCurentLength_ -= nextLength_; + if (htraceCurentLength_ == 0) { + hasGotHeader_ = false; + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin); + profilerTraceFileHeader_.data.dataType = ProfilerTraceFileHeader::UNKNOW_TYPE; + TS_LOGD("read proto finished!"); + return ParseDataRecursively(packagesBegin, currentLength); + } + } + return true; +} +void HtraceParser::ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) +{ + packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]); + auto packagesBegin = packagesBuffer_.begin(); + auto currentLength = packagesBuffer_.size(); + if (ParseDataRecursively(packagesBegin, currentLength)) { + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin); + } + return; +} + +bool HtraceParser::InitProfilerTraceFileHeader() +{ + if (packagesBuffer_.size() < PACKET_HEADER_LENGTH) { + TS_LOGE("buffer size less than profiler trace file header"); + return false; + } + uint8_t buffer[PACKET_HEADER_LENGTH]; + (void)memset_s(buffer, PACKET_HEADER_LENGTH, 0, PACKET_HEADER_LENGTH); + int32_t i = 0; + for (auto it = packagesBuffer_.begin(); it != packagesBuffer_.begin() + PACKET_HEADER_LENGTH; ++it, ++i) { + buffer[i] = *it; + } + auto ret = memcpy_s(&profilerTraceFileHeader_, sizeof(profilerTraceFileHeader_), buffer, PACKET_HEADER_LENGTH); + if (ret == -1 || profilerTraceFileHeader_.data.magic != ProfilerTraceFileHeader::HEADER_MAGIC) { + TS_LOGE("Get profiler trace file header failed! ret = %d, magic = %lx", ret, + profilerTraceFileHeader_.data.magic); + return false; + } + if (profilerTraceFileHeader_.data.length <= PACKET_HEADER_LENGTH) { + TS_LOGE("Profiler Trace data is truncated!!!"); + return false; + } + TS_LOGI("magic = %llx, length = %llx, dataType = %llx, boottime = %llx", profilerTraceFileHeader_.data.magic, + profilerTraceFileHeader_.data.length, profilerTraceFileHeader_.data.dataType, + profilerTraceFileHeader_.data.boottime); +#if IS_WASM + const int32_t DATA_TYPE_CLOCK = 100; + TraceStreamer_Plugin_Out_SendData(reinterpret_cast(&profilerTraceFileHeader_), + sizeof(profilerTraceFileHeader_), DATA_TYPE_CLOCK); +#endif + htraceClockDetailParser_->Parse(&profilerTraceFileHeader_); + return true; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..33b02256c019f5d6c7bcfdb9d76ebab5572642df --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_parser.h @@ -0,0 +1,140 @@ +/* + * 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 HTRACE_PARSER_H +#define HTRACE_PARSER_H +#include +#include +#include +#include +#include +#include +#include "common_types.h" +#include "ebpf_data_parser.h" +#include "file.h" +#include "htrace_clock_detail_parser.h" +#include "htrace_cpu_detail_parser.h" +#include "htrace_cpu_data_parser.h" +#include "htrace_disk_io_parser.h" +#include "htrace_file_header.h" +#include "htrace_hidump_parser.h" +#include "htrace_hilog_parser.h" +#include "htrace_hisysevent_parser.h" +#include "htrace_mem_parser.h" +#include "htrace_native_hook_parser.h" +#include "htrace_network_parser.h" +#include "htrace_process_parser.h" +#include "htrace_symbols_detail_parser.h" +#include "log.h" +#include "parser_base.h" +#if WITH_PERF +#include "perf_data_parser.h" +#endif +#include "string_help.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +#if WITH_PERF +using namespace OHOS::Developtools::HiPerf; +#endif +class HtraceParser : public ParserBase { +public: + HtraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters); + ~HtraceParser(); + void ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) override; + void WaitForParserEnd(); + +private: + bool ParseDataRecursively(std::deque::iterator& packagesBegin, size_t& currentLength); + void ParseTraceDataItem(const std::string& buffer) override; + void FilterData(HtraceDataSegment& seg); + void ParserData(HtraceDataSegment& dataSeg); + +private: + void ParseMemory(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseHilog(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseFtrace(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseNativeHook(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseFPS(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseCpuUsage(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseNetwork(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseDiskIO(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseProcess(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseHisysevent(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseHisyseventConfig(const ProfilerPluginData& pluginData, HtraceDataSegment& dataSeg); + void ParseThread(); + int32_t GetNextSegment(); + void FilterThread(); + enum ErrorCode { ERROR_CODE_EXIT = -2, ERROR_CODE_NODATA = -1 }; + bool InitProfilerTraceFileHeader(); + ProfilerTraceFileHeader profilerTraceFileHeader_; + uint64_t htraceCurentLength_ = 0; + bool hasGotSegLength_ = false; + bool hasGotHeader_ = false; + uint32_t nextLength_ = 0; + const size_t PACKET_SEG_LENGTH = 4; + const size_t PACKET_HEADER_LENGTH = 1024; + TraceDataCache* traceDataCache_; + std::unique_ptr htraceCpuDetailParser_; + std::unique_ptr htraceSymbolsDetailParser_; + std::unique_ptr htraceMemParser_; + std::unique_ptr htraceClockDetailParser_; + std::unique_ptr htraceHiLogParser_; + std::unique_ptr htraceNativeHookParser_; + std::unique_ptr htraceHidumpParser_; + std::unique_ptr cpuUsageParser_; + std::unique_ptr networkParser_; + std::unique_ptr diskIOParser_; + std::unique_ptr processParser_; + std::unique_ptr hisyseventParser_; +#if WITH_PERF + std::unique_ptr perfDataParser_; +#endif + std::unique_ptr ebpfDataParser_; + std::atomic filterThreadStarted_{false}; + const int32_t MAX_SEG_ARRAY_SIZE = 10000; + std::unique_ptr dataSegArray_; + int32_t rawDataHead_ = 0; + bool toExit_ = false; + bool exited_ = false; + int32_t filterHead_ = 0; + int32_t parseHead_ = 0; + size_t sizeAll_ = 0; + size_t htraceLength_ = 1024; + const int32_t sleepDur_ = 100; + bool parseThreadStarted_ = false; + const int32_t maxThread_ = 4; // 4 is the best on ubuntu 113MB/s, max 138MB/s, 6 is best on mac m1 21MB/s, + int32_t parserThreadCount_ = 0; + std::mutex dataSegMux_ = {}; + bool supportThread_ = false; + ClockId dataSourceTypeTraceClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeMemClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeHilogClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeAllocationClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeFpsClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeNetworkClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeDiskioClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeCpuClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeProcessClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeHisyseventClockid_ = TS_CLOCK_UNKNOW; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PARSER_H_ diff --git a/trace_streamer/src/parser/htrace_parser/htrace_plugin_time_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_plugin_time_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec3e143ad48656051674401c1f9a7486db9bf30f --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_plugin_time_parser.cpp @@ -0,0 +1,67 @@ +/* + * 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 "htrace_plugin_time_parser.h" +namespace SysTuning { +namespace TraceStreamer { +HtracePluginTimeParser::HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx) +{ + if (!streamFilters_) { + TS_LOGF("streamFilters_ should not be null"); + return; + } + if (!traceDataCache_) { + TS_LOGF("traceDataCache_ should not be null"); + return; + } +} +void HtracePluginTimeParser::UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp) +{ + minTs_ = std::min(minTs_, asyncTimestamp); + maxTs_ = std::max(maxTs_, asyncTimestamp); + if (clockId == streamFilters_->clockFilter_->GetPrimaryClock()) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + return; + } + if (syncTimestamp != asyncTimestamp) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + } else { + asyncHtracePluginStartTime_ = std::min(asyncHtracePluginStartTime_, syncTimestamp); + asyncHtracePluginEndTime_ = std::max(asyncHtracePluginEndTime_, syncTimestamp); + } +} +uint64_t HtracePluginTimeParser::GetPluginStartTime() +{ + if (syncHtracePluginStartTime_ != std::numeric_limits::max()) { + return syncHtracePluginStartTime_; + } else if (asyncHtracePluginStartTime_ != std::numeric_limits::max()) { + return asyncHtracePluginStartTime_; + } + return std::numeric_limits::max(); +} + +uint64_t HtracePluginTimeParser::GetPluginEndTime() +{ + if (syncHtracePluginEndTime_ != 0) { + return syncHtracePluginEndTime_; + } else if (asyncHtracePluginEndTime_ != 0) { + return asyncHtracePluginEndTime_; + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_plugin_time_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_plugin_time_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..a0874ea0a34cc5356c7fdc6e1086ac74c5a28af8 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_plugin_time_parser.h @@ -0,0 +1,52 @@ +/* + * 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 HTRACE_PLUGIN_TIME_PARSER_H +#define HTRACE_PLUGIN_TIME_PARSER_H +#include "clock_filter.h" +#include "event_parser_base.h" +#include "trace_data/trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtracePluginTimeParser : public EventParserBase { +public: + HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + HtracePluginTimeParser(const HtracePluginTimeParser&) = delete; + HtracePluginTimeParser& operator=(const HtracePluginTimeParser&) = delete; + ~HtracePluginTimeParser() = default; + void UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp); + uint64_t GetPluginStartTime(); + uint64_t GetPluginEndTime(); + uint64_t MinTs() + { + return minTs_; + } + uint64_t MaxTs() + { + return maxTs_; + } + +private: + uint64_t syncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t syncHtracePluginEndTime_ = 0; + uint64_t asyncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t asyncHtracePluginEndTime_ = 0; + uint64_t minTs_ = std::numeric_limits::max(); + uint64_t maxTs_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PLUGIN_TIME_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_process_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_process_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e3f0ea1bd8b3db1089eae136689b78df6d9b75f --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_process_parser.cpp @@ -0,0 +1,90 @@ +/* + * 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 "htrace_process_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceProcessParser::HtraceProcessParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceProcessParser::~HtraceProcessParser() +{ + TS_LOGI("process ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); + TS_LOGI("process real ts MIN:%llu, MAX:%llu", static_cast(MinTs()), + static_cast(MaxTs())); +} +void HtraceProcessParser::Parse(ProcessData& tracePacket, uint64_t ts) +{ + for (int32_t i = 0; i < tracePacket.processesinfo_size(); ++i) { + streamFilters_->statFilter_->IncreaseStat(TRACE_PROCESS, STAT_EVENT_START); + auto processesInfo = tracePacket.processesinfo(i); + auto pssInfo = processesInfo.pssinfo(); + auto cpuInfo = CpuInfo(); + if (processesInfo.has_cpuinfo()) { + cpuInfo = processesInfo.cpuinfo(); + } + auto liveProcess = std::make_unique(); + auto diskio = processesInfo.diskinfo(); + liveProcess->SetLiveProcess(ts, processesInfo, cpuInfo, pssInfo, diskio); + liveProcessData_.push_back(std::move(liveProcess)); + } +} +void HtraceProcessParser::Finish() +{ + if (!liveProcessData_.size()) { + TS_LOGW("process no data"); + return; + } + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->ts_ < b->ts_; + }; +#ifdef IS_WASM + std::sort(liveProcessData_.begin(), liveProcessData_.end(), cmp); +#else + std::stable_sort(liveProcessData_.begin(), liveProcessData_.end(), cmp); +#endif + bool first = true; + uint64_t lastTs = 0; + for (auto itor = liveProcessData_.begin(); itor != liveProcessData_.end(); itor++) { + auto tsOld = (*itor)->ts_; + (*itor)->ts_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, (*itor)->ts_); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, tsOld, (*itor)->ts_); + if (first) { + lastTs = (*itor)->ts_; + first = false; + continue; + } + auto dur = (*itor)->ts_ - lastTs; + lastTs = (*itor)->ts_; + if (!(*itor)->processInfo_->pid()) { + continue; + } + traceDataCache_->GetLiveProcessData()->AppendNewData( + (*itor)->ts_, dur, (*itor)->processInfo_->pid(), (*itor)->processInfo_->name(), + (*itor)->processInfo_->ppid(), (*itor)->processInfo_->uid(), std::to_string((*itor)->processInfo_->uid()), + (*itor)->cpuUsageData_->cpu_usage(), (*itor)->pssInfo_->pss_info(), (*itor)->cpuUsageData_->cpu_time_ms(), + (*itor)->cpuUsageData_->thread_sum(), (*itor)->diskio_->wbytes(), (*itor)->diskio_->rbytes()); + } + liveProcessData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_process_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_process_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..345c6a9a1a03c248e14d14d4922f0159da61c421 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_process_parser.h @@ -0,0 +1,57 @@ +/* + * 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 HTRACE_PROCESS_PARSER_H +#define HTRACE_PROCESS_PARSER_H +#include +#include +#include +#include "htrace_plugin_time_parser.h" +#include "process_plugin_result.pb.h" +#include "trace_streamer_filters.h" +#include "cpu_plugin_result.pb.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceProcessParser : public HtracePluginTimeParser { +public: + HtraceProcessParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceProcessParser(); + void Parse(ProcessData& tracePacket, uint64_t ts); + void Finish(); + struct TsLiveProcessData { + void SetLiveProcess(uint64_t ts, + ProcessInfo& liveProcessInfo, + CpuInfo& cpuUsageData, + PssInfo& pssInfo, + DiskioInfo& diskio) + { + ts_ = ts; + processInfo_ = std::make_unique(liveProcessInfo); + cpuUsageData_ = std::make_unique(cpuUsageData); + pssInfo_ = std::make_unique(pssInfo); + diskio_ = std::make_unique(diskio); + } + uint64_t ts_; + std::unique_ptr processInfo_; + std::unique_ptr cpuUsageData_; + std::unique_ptr pssInfo_; + std::unique_ptr diskio_; + }; + std::vector> liveProcessData_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PROCESS_PARSER_H diff --git a/trace_streamer/src/parser/htrace_parser/htrace_symbols_detail_parser.cpp b/trace_streamer/src/parser/htrace_parser/htrace_symbols_detail_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1efcceed6bd30c4041f7c651a32e01adc7b6eaa0 --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_symbols_detail_parser.cpp @@ -0,0 +1,44 @@ +/* + * 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 "htrace_symbols_detail_parser.h" +#include "htrace_event_parser.h" +#include "symbols_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceSymbolsDetailParser::HtraceSymbolsDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : streamFilters_(ctx), traceDataCache_(dataCache) +{ + UNUSED(traceDataCache_); + if (!streamFilters_) { + TS_LOGF("streamFilters_ should not be null"); + return; + } +} + +HtraceSymbolsDetailParser::~HtraceSymbolsDetailParser() = default; +void HtraceSymbolsDetailParser::Parse(const TracePluginResult* tracePacket) +{ + if (!tracePacket->symbols_detail_size()) { + return; + } + for (int32_t i = 0; i < tracePacket->symbols_detail_size(); i++) { + auto symbol = const_cast(tracePacket)->mutable_symbols_detail(i); + // symbol + streamFilters_->symbolsFilter_->RegisterFunc(symbol->symbol_addr(), + traceDataCache_->GetDataIndex(symbol->symbol_name())); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_parser/htrace_symbols_detail_parser.h b/trace_streamer/src/parser/htrace_parser/htrace_symbols_detail_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..34bc1128afbb2c4689e2f9e96674903e84ce189d --- /dev/null +++ b/trace_streamer/src/parser/htrace_parser/htrace_symbols_detail_parser.h @@ -0,0 +1,40 @@ +/* + * 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 HTRACE_SYMBOLS_DETAIL_PARSER_H +#define HTRACE_SYMBOLS_DETAIL_PARSER_H + +#include +#include +#include +#include +#include +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pb.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceSymbolsDetailParser { +public: + HtraceSymbolsDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceSymbolsDetailParser(); + void Parse(const TracePluginResult* tracePacket); + +private: + const TraceStreamerFilters* streamFilters_; + TraceDataCache* traceDataCache_; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HTRACE_SYMBOLS_DETAIL_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/BUILD.gn b/trace_streamer/src/parser/htrace_pbreader_parser/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..b6dbe327c85a631d4a21eed36488805c1574e9b7 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/BUILD.gn @@ -0,0 +1,128 @@ +# 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("../../ts.gni") +ohos_source_set("htrace_pbreader_parser_src") { + subsystem_name = "trace_streamer" + part_name = "htrace_pbreader_parser_src" + sources = [ + "../parser_base.cpp", + "htrace_clock_detail_parser.cpp", + "htrace_clock_detail_parser.h", + "htrace_cpu_data_parser.cpp", + "htrace_cpu_data_parser.h", + "htrace_cpu_parser/htrace_cpu_detail_parser.cpp", + "htrace_cpu_parser/htrace_cpu_detail_parser.h", + "htrace_disk_io_parser.cpp", + "htrace_disk_io_parser.h", + "htrace_event_parser/htrace_event_parser.cpp", + "htrace_event_parser/htrace_event_parser.h", + "htrace_file_header.h", + "htrace_hidump_parser.cpp", + "htrace_hidump_parser.h", + "htrace_hilog_parser.cpp", + "htrace_hilog_parser.h", + "htrace_hisysevent_parser.cpp", + "htrace_hisysevent_parser.h", + "htrace_js_memory_parser.cpp", + "htrace_js_memory_parser.h", + "htrace_mem_parser.cpp", + "htrace_mem_parser.h", + "htrace_native_hook_parser.cpp", + "htrace_native_hook_parser.h", + "htrace_network_parser.cpp", + "htrace_network_parser.h", + "htrace_parser.cpp", + "htrace_plugin_time_parser.cpp", + "htrace_plugin_time_parser.h", + "htrace_process_parser.cpp", + "htrace_process_parser.h", + "htrace_symbols_detail_parser.cpp", + "htrace_symbols_detail_parser.h", + ] + include_dirs = [ + "../../proto_reader/include", + ".", + "htrace_event_parser", + "htrace_cpu_parser", + "${OHOS_PROTO_GEN}", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "../../include", + "../../", + "../", + "../../trace_data", + "../../cfg", + "../../trace_streamer", + "//third_party/protobuf/src", + "//third_party/sqlite/include", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + "../../filter", + "../../base", + "../ebpf_parser", + ] + include_dirs += [ + "//third_party/libunwind/include", + "//third_party/libunwind/src", + ] + if (with_perf) { + include_dirs += [ + "//third_party/perf_include/musl", + "//third_party/hiperf/include", + "//third_party/hiperf/include/nonlinux", + "//third_party/hiperf/include/nonlinux/linux", + "//third_party/perf_include/libbpf", + "//third_party/perf_include/include", + "//third_party/perf_include", + "//third_party/perf_include/linux", + "../hiperf_parser", + "../hiperf_parser/include", + ] + } + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + } + public_deps = [] + deps = [] +} +group("htrace_pbreader_parser") { + deps = [ + ":htrace_pbreader_parser_src", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + if (!use_wasm && !is_win && !is_macx && !is_test) { + deps += [ "//third_party/libunwind:libunwind" ] + } + if (target != "test" && !is_openharmony) { + deps += [ "//prebuilts/protos:ts_proto_data_cpp" ] + } +} diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_clock_detail_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_clock_detail_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72b66b6a799d7cdf3511ad327dbc7e001911ef18 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_clock_detail_parser.cpp @@ -0,0 +1,112 @@ +/* + * 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 "htrace_clock_detail_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceClockDetailParser::HtraceClockDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters) + : EventParserBase(dataCache, filters) +{ + for (auto i = 0; i < MEM_MAX; i++) { + memNameDictMap_.insert( + std::make_pair(static_cast(i), + traceDataCache_->GetDataIndex(config_.memNameMap_.at(static_cast(i))))); + } +} + +HtraceClockDetailParser::~HtraceClockDetailParser() = default; +void HtraceClockDetailParser::Parse(const ProtoReader::BytesView& tracePacket) const +{ + if (streamFilters_->clockFilter_->HasInitSnapShot()) { + TS_LOGW("already has clock snapshot!!!"); + return; + } + ProtoReader::TracePluginResult_Reader reader((const uint8_t*)(tracePacket.data_), tracePacket.size_); + if (!reader.has_clocks_detail()) { + TS_LOGE("!!! no clock snapshot"); + return; + } + std::vector snapShot; + TS_LOGI("got clock snapshot"); + for (auto i = reader.clocks_detail(); i; i++) { + ProtoReader::ClockDetailMsg_Reader clockInfo(i->ToBytes()); + // auto clockInfo = tracePacket->mutable_clocks_detail(i); + auto id = clockInfo.FindDataArea(ProtoReader::ClockDetailMsg_Reader::kIdDataAreaNumber).ToUint32(); + ProtoReader::ClockDetailMsg_TimeSpec_Reader time(clockInfo.time()); + TS_LOGI("clockid:%d, ts:%llu", id, static_cast(time.tv_nsec() + time.tv_sec() * SEC_TO_NS)); + snapShot.push_back(SnapShot{static_cast(id), time.tv_nsec() + time.tv_sec() * SEC_TO_NS}); + } + if (snapShot.size()) { + streamFilters_->clockFilter_->AddClockSnapshot(snapShot); + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SYNC, STAT_EVENT_RECEIVED); +} + +void HtraceClockDetailParser::Parse(const ProfilerTraceFileHeader* profilerTraceFileHeader) const +{ + if (streamFilters_->clockFilter_->HasInitSnapShot()) { + TS_LOGW("already has clock snapshot!!!"); + return; + } + if (!profilerTraceFileHeader->data.boottime) { + TS_LOGW("Profiler header has no clock snapshot!!!"); + return; + } + + std::vector snapShot; + TS_LOGI("got clock snapshot"); + + TS_LOGI("clockid: TS_CLOCK_BOOTTIME, ts:%llu", profilerTraceFileHeader->data.boottime); + if (profilerTraceFileHeader->data.boottime) { + snapShot.push_back(SnapShot{TS_CLOCK_BOOTTIME, profilerTraceFileHeader->data.boottime}); + } + + TS_LOGI("clockid: TS_CLOCK_REALTIME, ts:%llu", profilerTraceFileHeader->data.realtime); + if (profilerTraceFileHeader->data.realtime) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME, profilerTraceFileHeader->data.realtime}); + } + + TS_LOGI("clockid: TS_CLOCK_REALTIME_COARSE, ts:%llu", profilerTraceFileHeader->data.realtimeCoarse); + if (profilerTraceFileHeader->data.realtimeCoarse) { + snapShot.push_back(SnapShot{TS_CLOCK_REALTIME_COARSE, profilerTraceFileHeader->data.realtimeCoarse}); + } + + TS_LOGI("clockid: TS_MONOTONIC, ts:%llu", profilerTraceFileHeader->data.monotonic); + if (profilerTraceFileHeader->data.monotonic) { + snapShot.push_back(SnapShot{TS_MONOTONIC, profilerTraceFileHeader->data.monotonic}); + } + + TS_LOGI("clockid: TS_MONOTONIC_COARSE, ts:%llu", profilerTraceFileHeader->data.monotonicCoarse); + if (profilerTraceFileHeader->data.monotonicCoarse) { + snapShot.push_back(SnapShot{TS_MONOTONIC_COARSE, profilerTraceFileHeader->data.monotonicCoarse}); + } + + TS_LOGI("clockid: TS_MONOTONIC_RAW, ts:%llu", profilerTraceFileHeader->data.monotonicRaw); + if (profilerTraceFileHeader->data.monotonicRaw) { + snapShot.push_back(SnapShot{TS_MONOTONIC_RAW, profilerTraceFileHeader->data.monotonicRaw}); + } + + if (snapShot.size()) { + streamFilters_->clockFilter_->AddClockSnapshot(snapShot); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SYNC, STAT_EVENT_RECEIVED); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_clock_detail_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_clock_detail_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..7222d870bb9e69dd1eaa1a5348e8f4b1c6d15279 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_clock_detail_parser.h @@ -0,0 +1,47 @@ +/* + * 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 HTRACE_CLOCKDETAIL_PARSER_H +#define HTRACE_CLOCKDETAIL_PARSER_H +#include +#include +#include +#include +#include +#include "event_parser_base.h" +#include "file.h" +#include "proto_reader_help.h" +#include "htrace_file_header.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pbreader.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceClockDetailParser : public EventParserBase { +public: + HtraceClockDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters); + ~HtraceClockDetailParser(); + void Parse(const ProtoReader::BytesView& tracePacket) const; + void Parse(const ProfilerTraceFileHeader* profilerTraceFileHeader) const; + +private: + std::map memNameDictMap_ = {}; + TraceStreamerConfig config_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_CLOCKDETAIL_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_data_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_data_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3035393a6687740d8a50c8a42ca9ab14695e9d31 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_data_parser.cpp @@ -0,0 +1,78 @@ +/* + * 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 "htrace_cpu_data_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceCpuDataParser::HtraceCpuDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceCpuDataParser::~HtraceCpuDataParser() +{ + TS_LOGI("cpuData ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceCpuDataParser::Parse(ProtoReader::BytesView tracePacket, uint64_t ts) +{ + ProtoReader::CpuData_Reader cpuData(tracePacket.data_, tracePacket.size_); + if (!cpuData.has_cpu_usage_info() && !cpuData.has_thread_info()) { + return; + } + if (cpuData.has_cpu_usage_info()) { + auto cpuInfo = cpuData.cpu_usage_info(); + auto userLoad = cpuData.user_load(); + auto sysLoad = cpuData.sys_load(); + auto process_num = cpuData.process_num(); + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts); + auto cpuUsage = std::make_unique(); + streamFilters_->statFilter_->IncreaseStat(TRACE_CPU_USAGE, STAT_EVENT_RECEIVED); + cpuUsage->SetCpuUsage(ts); + cpuUsage->SetExtInfo(cpuData.total_load(), userLoad, sysLoad, process_num); + cpuData_.push_back(std::move(cpuUsage)); + } +} +void HtraceCpuDataParser::Finish() +{ + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { return a->ts_ < b->ts_; }; +#ifdef IS_WASM + std::sort(cpuData_.begin(), cpuData_.end(), cmp); +#else + std::stable_sort(cpuData_.begin(), cpuData_.end(), cmp); +#endif + bool firstTime = true; + uint64_t lastTs = 0; + for (auto itor = cpuData_.begin(); itor != cpuData_.end(); itor++) { + auto newTimeStamp = (*itor)->ts_; + if (firstTime) { + lastTs = newTimeStamp; + firstTime = false; + continue; + } + auto dur = newTimeStamp - lastTs; + traceDataCache_->GetCpuUsageInfoData()->AppendNewData( + newTimeStamp, dur, (*itor)->totalLoad_, (*itor)->userLoad_, (*itor)->sysLoad_, (*itor)->process_num_); + lastTs = newTimeStamp; + } + cpuData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_data_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_data_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..f559a1014ac4c41fe32edc0a704b9243339a0e16 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_data_parser.h @@ -0,0 +1,78 @@ +/* + * 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 HTRACE_CPU_DATA_PARSER_H +#define HTRACE_CPU_DATA_PARSER_H +#include +#include +#include +#include "cpu_plugin_result.pbreader.h" +#include "hilog_plugin_result.pbreader.h" +#include "htrace_plugin_time_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceCpuDataParser : public HtracePluginTimeParser { +public: + HtraceCpuDataParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceCpuDataParser(); + void Parse(ProtoReader::BytesView tracePacket, uint64_t ts); + void Finish(); + enum TSCpuDataType { TSCpuDataType_Usage, TSCpuDataType_ThreadInfo, TSCpuDataType_Load }; + class TsCpuData { + public: + TsCpuData() + { + ts_ = 0; + cpuDataType_ = TSCpuDataType_Usage; + } + void SetCpuUsage(uint64_t ts) + { + ts_ = ts; + cpuDataType_ = TSCpuDataType_Usage; + } + void SetThreadInfo(uint64_t ts) + { + ts_ = ts; + cpuDataType_ = TSCpuDataType_ThreadInfo; + } + void SetExtInfo(double totalLoad, double userLoad, double sysLoad, double process_num) + { + totalLoad_ = totalLoad; + userLoad_ = userLoad; + sysLoad_ = sysLoad; + process_num_ = process_num; + cpuDataType_ = TSCpuDataType_Load; + } + uint64_t ts_; + TSCpuDataType cpuDataType_; + double userLoad_ = 0; + double sysLoad_ = 0; + double process_num_ = 0; + double totalLoad_ = 0; + }; + std::vector> cpuData_; + +private: + std::string threadStateDesc_[ProtoReader::THREAD_WAITING + 1] = {"undefined", "Running", "Sleep", "Sloped", + "Watting"}; + uint64_t lastLineSeq_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_CPU_DATA_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_parser/htrace_cpu_detail_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_parser/htrace_cpu_detail_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ed6e2b1f944d735b71ca19a474881f46a04df88 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_parser/htrace_cpu_detail_parser.cpp @@ -0,0 +1,37 @@ +/* + * 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 "htrace_cpu_detail_parser.h" +#include "htrace_event_parser.h" +#include "stat_filter.h" +#include "trace_plugin_result.pbreader.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceCpuDetailParser::HtraceCpuDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : eventParser_(std::make_unique(dataCache, ctx)) +{ +} + +HtraceCpuDetailParser::~HtraceCpuDetailParser() = default; +void HtraceCpuDetailParser::Parse(HtraceDataSegment& tracePacket, BuiltinClocks clock) +{ + eventParser_->ParseDataItem(tracePacket, clock); +} +void HtraceCpuDetailParser::FilterAllEvents() +{ + eventParser_->FilterAllEvents(); + eventParser_->Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_parser/htrace_cpu_detail_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_parser/htrace_cpu_detail_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..10c03a95da4c8fd8b99435c9e973b1289828f05a --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_cpu_parser/htrace_cpu_detail_parser.h @@ -0,0 +1,46 @@ +/* + * 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 HTRACE_CPU_DETAIL_PARSER_H +#define HTRACE_CPU_DETAIL_PARSER_H +#include +#include +#include +#include +#include +#include "event_parser_base.h" +#include "htrace_event_parser.h" +#include "log.h" +#include "parser_base.h" +#include "proto_reader_help.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pbreader.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceCpuDetailParser { +public: + HtraceCpuDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceCpuDetailParser(); + void Parse(HtraceDataSegment& tracePacket, BuiltinClocks clock); + void FilterAllEvents(); + +private: + std::unique_ptr eventParser_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_CPU_DETAIL_PARSER_H_ diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_disk_io_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_disk_io_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7cfa463dff28e66cb13fc73410268bd8f65f17c --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_disk_io_parser.cpp @@ -0,0 +1,85 @@ +/* + * 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 "htrace_disk_io_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceDiskIOParser::HtraceDiskIOParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceDiskIOParser::~HtraceDiskIOParser() +{ + TS_LOGI("diskio ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceDiskIOParser::Parse(ProtoReader::BytesView tracePacket, uint64_t ts) +{ + ProtoReader::DiskioData_Reader diskioData(tracePacket.data_, tracePacket.size_); + auto stat = diskioData.statsdata(); + ProtoReader::StatsData_Reader statsData(stat); + double rdCountPerSec = 0; // The amount of data read from the device per second kB_read/s + double wrCountPerSec = 0; // The amount of data written to the device per second kB_wrtn/s + uint64_t rdCount = 0; // Total amount of data read kB_read + uint64_t wrCount = 0; // The total amount of data written kB_wrtn + for (auto i = statsData.statsinfo(); i; ++i) { + auto statsInfo = ProtoReader::IoStatData_Reader(i->ToBytes()); + rdCountPerSec += statsInfo.rd_per_sec(); + wrCountPerSec += statsInfo.wr_per_sec(); + rdCount += statsInfo.rd_kb(); + wrCount += statsInfo.wr_kb(); + } + + streamFilters_->statFilter_->IncreaseStat(TRACE_DISKIO, STAT_EVENT_RECEIVED); + diskIOData_.push_back(TsDiskIOData{ts, diskioData.rd_sectors_kb(), diskioData.wr_sectors_kb(), + diskioData.prev_rd_sectors_kb(), diskioData.prev_wr_sectors_kb(), rdCountPerSec, + wrCountPerSec, rdCount, wrCount}); +} +void HtraceDiskIOParser::Finish() +{ + auto cmp = [](const TsDiskIOData& a, const TsDiskIOData& b) { return a.ts < b.ts; }; +#ifdef IS_WASM + std::sort(diskIOData_.begin(), diskIOData_.end(), cmp); +#else + std::stable_sort(diskIOData_.begin(), diskIOData_.end(), cmp); +#endif + bool first = true; + uint64_t lastTs = 0; + for (auto itor = diskIOData_.begin(); itor != diskIOData_.end(); itor++) { + itor->ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, itor->ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, itor->ts, itor->ts); + if (first) { + lastTs = itor->ts; + first = false; + continue; + } + auto dur = itor->ts - lastTs; + auto durS = 1.0 * dur / SEC_TO_NS; + traceDataCache_->GetDiskIOData()->AppendNewData( + itor->ts, itor->ts - lastTs, itor->rdSectorsKb, itor->wrSectorsKb, + 1.0 * (itor->rdSectorsKb - itor->prevRdSectorsKb) / durS, + 1.0 * (itor->wrSectorsKb - itor->prevWrSectorsKb) / durS, itor->rdCountPerSec, itor->wrCountPerSec, + itor->rdCount, itor->wrCount); + lastTs = itor->ts; + } + diskIOData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_disk_io_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_disk_io_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..638f37206391b02c765a45233a97d49511dea4ba --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_disk_io_parser.h @@ -0,0 +1,51 @@ +/* + * 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 HTRACE_DISKI0_PARSER_H +#define HTRACE_DISKI0_PARSER_H +#include +#include +#include +#include "common_types.h" +#include "htrace_plugin_time_parser.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceDiskIOParser : public HtracePluginTimeParser { +public: + HtraceDiskIOParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceDiskIOParser(); + void Parse(ProtoReader::BytesView tracePacket, uint64_t ts); + void Finish(); + +private: + struct TsDiskIOData { + uint64_t ts; + int64_t rdSectorsKb; + int64_t wrSectorsKb; + int64_t prevRdSectorsKb; + int64_t prevWrSectorsKb; + double rdCountPerSec; // 每秒从设备读取的数据量 kB_read/s + double wrCountPerSec; // 每秒向设备写入的数据量 kB_wrtn/s + uint64_t rdCount; // 读取的总数据量 kB_read + uint64_t wrCount; // 写入的总数量数据量 kB_wrtn + }; + std::vector diskIOData_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_DISKI0_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_event_parser/htrace_event_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_event_parser/htrace_event_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88db98dccd1f02972d4fd38eeefa66a29e58ca45 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_event_parser/htrace_event_parser.cpp @@ -0,0 +1,902 @@ +/* + * 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 "htrace_event_parser.h" +#include +#include "binder_filter.h" +#include "binder.pbreader.h" +#include "clk.pbreader.h" +#include "clock_filter.h" +#include "cpu_filter.h" +#include "ftrace.pbreader.h" +#include "ftrace_event.pbreader.h" +#include "sched.pbreader.h" +#include "ipi.pbreader.h" +#include "irq_filter.h" +#include "irq.pbreader.h" +#include "log.h" +#include "measure_filter.h" +#include "oom.pbreader.h" +#include "power.pbreader.h" +#include "process_filter.h" +#include "raw_syscalls.pbreader.h" +#include "signal.pbreader.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +#include "system_event_measure_filter.h" +#include "task.pbreader.h" +#include "thread_state.h" +#include "trace_plugin_result.pbreader.h" +#include "workqueue.pbreader.h" +namespace SysTuning { +namespace TraceStreamer { +const int32_t MIN_DATA_AREA = 10; +const int32_t DATA_AREA_START = 1; +const int32_t DATA_AREA_END = 11; + +HtraceEventParser::HtraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : EventParserBase(dataCache, filter), + workQueueId_(dataCache->dataDict_.GetStringIndex("workqueue")), + printEventParser_(traceDataCache_, streamFilters_) +{ + eventToFunctionMap_ = {{config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION), + std::bind(&HtraceEventParser::BinderTractionEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED), + std::bind(&HtraceEventParser::BinderTractionReceivedEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF), + std::bind(&HtraceEventParser::BinderTractionAllocBufEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_LOCK), + std::bind(&HtraceEventParser::BinderTractionLockEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_LOCKED), + std::bind(&HtraceEventParser::BinderTractionLockedEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK), + std::bind(&HtraceEventParser::BinderTractionUnLockEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_SWITCH), + std::bind(&HtraceEventParser::SchedSwitchEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_BLOCKED_REASON), + std::bind(&HtraceEventParser::SchedBlockReasonEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_TASK_RENAME), + std::bind(&HtraceEventParser::TaskRenameEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_TASK_NEWTASK), + std::bind(&HtraceEventParser::TaskNewtaskEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_PRINT), + std::bind(&HtraceEventParser::ParsePrintEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP), + std::bind(&HtraceEventParser::SchedWakeupEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP_NEW), + std::bind(&HtraceEventParser::SchedWakeupNewEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_PROCESS_EXIT), + std::bind(&HtraceEventParser::ProcessExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_PROCESS_FREE), + std::bind(&HtraceEventParser::ProcessFreeEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKING), + std::bind(&HtraceEventParser::SchedWakingEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_IDLE), + std::bind(&HtraceEventParser::CpuIdleEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY), + std::bind(&HtraceEventParser::CpuFrequencyEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CPU_FREQUENCY_LIMITS), + std::bind(&HtraceEventParser::CpuFrequencyLimitsEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SUSPEND_RESUME), + std::bind(&HtraceEventParser::SuspendResumeEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_START), + std::bind(&HtraceEventParser::WorkqueueExecuteStartEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_WORKQUEUE_EXECUTE_END), + std::bind(&HtraceEventParser::WorkqueueExecuteEndEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_SET_RATE), + std::bind(&HtraceEventParser::ClockSetRateEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_ENABLE), + std::bind(&HtraceEventParser::ClockEnableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLOCK_DISABLE), + std::bind(&HtraceEventParser::ClockDisableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLK_SET_RATE), + std::bind(&HtraceEventParser::ClkSetRateEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLK_ENABLE), + std::bind(&HtraceEventParser::ClkEnableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_CLK_DISABLE), + std::bind(&HtraceEventParser::ClkDisableEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_ENTRY), + std::bind(&HtraceEventParser::IrqHandlerEntryEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IRQ_HANDLER_EXIT), + std::bind(&HtraceEventParser::IrqHandlerExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IPI_ENTRY), + std::bind(&HtraceEventParser::IpiHandlerEntryEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_IPI_EXIT), + std::bind(&HtraceEventParser::IpiHandlerExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_ENTRY), + std::bind(&HtraceEventParser::SoftIrqEntryEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_RAISE), + std::bind(&HtraceEventParser::SoftIrqRaiseEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SOFTIRQ_EXIT), + std::bind(&HtraceEventParser::SoftIrqExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SYS_ENTRY), + std::bind(&HtraceEventParser::SysEnterEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_SYS_EXIT), + std::bind(&HtraceEventParser::SysExitEvent, this, std::placeholders::_1)}, + {config_.eventNameMap_.at(TRACE_EVENT_OOM_SCORE_ADJ_UPDATE), + std::bind(&HtraceEventParser::OomScoreAdjUpdate, this, std::placeholders::_1)}}; +} + +HtraceEventParser::~HtraceEventParser() +{ + TS_LOGI("thread count:%u", static_cast(tids_.size())); + TS_LOGI("process count:%u", static_cast(pids_.size())); + TS_LOGI("ftrace ts MIN:%llu, MAX:%llu", static_cast(ftraceStartTime_), + static_cast(ftraceEndTime_)); + TS_LOGI("ftrace origin ts MIN:%llu, MAX:%llu", static_cast(ftraceOriginStartTime_), + static_cast(ftraceOriginEndTime_)); +} + +void HtraceEventParser::ParseDataItem(HtraceDataSegment& tracePacket, BuiltinClocks clock) +{ + if (clock != clock_) { + clock_ = clock; + printEventParser_.SetTraceType(TRACE_FILETYPE_H_TRACE); + printEventParser_.SetTraceClockId(clock); + } + ProtoReader::TracePluginResult_Reader tracePluginResult(tracePacket.protoData); + if (!tracePluginResult.has_ftrace_cpu_detail()) { + return; + } + + for (auto it = tracePluginResult.ftrace_cpu_detail(); it; ++it) { + ProtoReader::FtraceCpuDetailMsg_Reader msg(it->ToBytes()); + eventCpu_ = msg.cpu(); + auto events = msg.event(); + if (!msg.has_event()) { + return; + } + if (msg.overwrite()) { + if (!lastOverwrite_) { + lastOverwrite_ = msg.overwrite(); + } + if (lastOverwrite_ != msg.overwrite()) { + TS_LOGW("lost events:%lu", msg.overwrite() - lastOverwrite_); + lastOverwrite_ = msg.overwrite(); + } + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_LOST); + } + // parser cpu event + auto kTimestampDataAreaNumber = ProtoReader::FtraceEvent_Reader::kTimestampDataAreaNumber; + auto tsTag = CreateTagVarInt(kTimestampDataAreaNumber); + for (auto i = events; i; i++) { + ProtoReader::BytesView event(i->ToBytes()); + uint64_t timeStamp = 0; + if (event.size_ > MIN_DATA_AREA && event.data_[0] == tsTag) { + const uint8_t* nextData = + ProtoReader::VarIntDecode(event.data_ + DATA_AREA_START, event.data_ + DATA_AREA_END, &timeStamp); + } + eventTimeStamp_ = timeStamp; + ftraceOriginStartTime_ = std::min(ftraceOriginStartTime_, eventTimeStamp_); + ftraceOriginEndTime_ = std::max(ftraceOriginEndTime_, eventTimeStamp_); + eventTimeStamp_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(clock, eventTimeStamp_); + ftraceStartTime_ = std::min(ftraceStartTime_, eventTimeStamp_); + ftraceEndTime_ = std::max(ftraceEndTime_, eventTimeStamp_); + traceDataCache_->UpdateTraceTime(eventTimeStamp_); + ProtoReader::BytesView commonField; + eventList_.push_back( + std::move(std::make_unique(eventTimeStamp_, eventCpu_, tracePacket.seg, i->ToBytes()))); + FilterAllEventsReader(); + } + } +} +void HtraceEventParser::DealEvent(ProtoReader::FtraceEvent_Reader* event, + ProtoReader::FtraceEvent_CommonFileds_Reader* comonFields) +{ + if (comonFields->pid() != INVALID_INT32) { + streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(comonFields->pid(), event->tgid(), + event->comm().ToStdString()); + } + if (event->has_sched_switch_format()) { + InvokeFunc(TRACE_EVENT_SCHED_SWITCH, + event->at()); + } else if (event->has_wakeup_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKEUP, event->at()); + } else if (event->has_binder_alloc_lru_end_format()) { + InvokeFunc(TRACE_EVENT_SCHED_SWITCH, + event->at()); + } else if (event->has_task_rename_format()) { + InvokeFunc(TRACE_EVENT_TASK_RENAME, + event->at()); + } else if (event->has_sched_blocked_reason_format()) { + InvokeFunc(TRACE_EVENT_SCHED_BLOCKED_REASON, + event->at()); + } else if (event->has_task_newtask_format()) { + InvokeFunc(TRACE_EVENT_TASK_NEWTASK, + event->at()); + } else if (event->has_sched_wakeup_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKEUP, + event->at()); + } else if (event->has_sched_wakeup_new_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKEUP, + event->at()); + } else if (event->has_sched_process_exit_format()) { + InvokeFunc(TRACE_EVENT_PROCESS_EXIT, + event->at()); + } else if (event->has_sched_process_free_format()) { + InvokeFunc(TRACE_EVENT_PROCESS_FREE, + event->at()); + } else if (event->has_sched_waking_format()) { + InvokeFunc(TRACE_EVENT_SCHED_WAKING, + event->at()); + } else if (event->has_cpu_idle_format()) { + InvokeFunc(TRACE_EVENT_CPU_IDLE, event->at()); + } else if (event->has_cpu_frequency_format()) { + InvokeFunc(TRACE_EVENT_CPU_FREQUENCY, + event->at()); + } else if (event->has_cpu_frequency_limits_format()) { + InvokeFunc(TRACE_EVENT_CPU_FREQUENCY_LIMITS, + event->at()); + } else if (event->has_print_format()) { + InvokeFunc(TRACE_EVENT_PRINT, event->at()); + } else if (event->has_suspend_resume_format()) { + InvokeFunc(TRACE_EVENT_SUSPEND_RESUME, + event->at()); + } else if (event->has_workqueue_execute_start_format()) { + InvokeFunc(TRACE_EVENT_WORKQUEUE_EXECUTE_START, + event->at()); + } else if (event->has_workqueue_execute_end_format()) { + InvokeFunc(TRACE_EVENT_WORKQUEUE_EXECUTE_END, + event->at()); + } else if (event->has_clock_disable_format()) { + InvokeFunc(TRACE_EVENT_CLOCK_DISABLE, + event->at()); + } else if (event->has_clock_enable_format()) { + InvokeFunc(TRACE_EVENT_CLOCK_ENABLE, + event->at()); + } else if (event->has_clock_set_rate_format()) { + InvokeFunc(TRACE_EVENT_CLOCK_SET_RATE, + event->at()); + } else if (event->has_clk_disable_format()) { + InvokeFunc(TRACE_EVENT_CLK_DISABLE, + event->at()); + } else if (event->has_clk_enable_format()) { + InvokeFunc(TRACE_EVENT_CLK_ENABLE, + event->at()); + } else if (event->has_clk_set_rate_format()) { + InvokeFunc(TRACE_EVENT_CLK_SET_RATE, + event->at()); + } else if (event->has_sys_enter_format()) { + InvokeFunc(TRACE_EVENT_SYS_ENTRY, event->at()); + } else if (event->has_sys_exit_format()) { + InvokeFunc(TRACE_EVENT_SYS_EXIT, event->at()); + } else if (event->has_binder_transaction_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION, + event->at()); + } else if (event->has_binder_transaction_received_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, + event->at()); + } else if (event->has_binder_transaction_alloc_buf_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, + event->at()); + } else if (event->has_binder_lock_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_LOCK, + event->at()); + } else if (event->has_binder_unlock_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, + event->at()); + } else if (event->has_binder_locked_format()) { + InvokeFunc(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, + event->at()); + } else if (event->has_irq_handler_entry_format()) { + InvokeFunc(TRACE_EVENT_IRQ_HANDLER_ENTRY, + event->at()); + } else if (event->has_irq_handler_exit_format()) { + InvokeFunc(TRACE_EVENT_IRQ_HANDLER_EXIT, + event->at()); + } else if (event->has_softirq_entry_format()) { + InvokeFunc(TRACE_EVENT_SOFTIRQ_ENTRY, + event->at()); + } else if (event->has_softirq_exit_format()) { + InvokeFunc(TRACE_EVENT_SOFTIRQ_EXIT, + event->at()); + } else if (event->has_oom_score_adj_update_format()) { + InvokeFunc(TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, + event->at()); + } else if (event->has_signal_generate_format()) { + InvokeFunc(TRACE_EVENT_SIGNAL_GENERATE, + event->at()); + } else if (event->has_signal_deliver_format()) { + InvokeFunc(TRACE_EVENT_SIGNAL_DELIVER, + event->at()); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED); + } +} +bool HtraceEventParser::BinderTractionAllocBufEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_RECEIVED); + ProtoReader::BinderTransactionAllocBufFormat_Reader msg(event.Data(), event.Size()); + uint64_t dataSize = msg.data_size(); + uint64_t offsetsSize = msg.offsets_size(); + streamFilters_->binderFilter_->TransactionAllocBuf(eventTimeStamp_, eventTid_, dataSize, offsetsSize); + TS_LOGD("dataSize:%lu, offsetSize:%lu", dataSize, offsetsSize); + return true; +} +bool HtraceEventParser::BinderTractionEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_RECEIVED); + ProtoReader::BinderTransactionFormat_Reader msg(event.Data(), event.Size()); + int32_t destNode = msg.target_node(); + int32_t destTgid = msg.to_proc(); + int32_t destTid = msg.to_thread(); + int32_t transactionId = msg.debug_id(); + bool isReply = msg.reply() == 1; + uint32_t flags = msg.flags(); + TS_LOGD("destNode:%d, destTgid:%d, destTid:%d, transactionId:%d, isReply:%d flags:%d, code:%d", destNode, destTgid, + destTid, transactionId, isReply, flags, msg.code()); + streamFilters_->binderFilter_->SendTraction(eventTimeStamp_, eventTid_, transactionId, destNode, destTgid, destTid, + isReply, flags, msg.code()); + return true; +} +bool HtraceEventParser::BinderTractionReceivedEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_RECEIVED); + ProtoReader::BinderTransactionReceivedFormat_Reader msg(event.Data(), event.Size()); + int32_t transactionId = msg.debug_id(); + streamFilters_->binderFilter_->ReceiveTraction(eventTimeStamp_, eventTid_, transactionId); + TS_LOGD("transactionId:%d", transactionId); + return true; +} +bool HtraceEventParser::BinderTractionLockEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCK, STAT_EVENT_RECEIVED); + ProtoReader::BinderLockFormat_Reader msg(event.Data(), event.Size()); + std::string tag = msg.tag().ToStdString(); + streamFilters_->binderFilter_->TractionLock(eventTimeStamp_, eventTid_, tag); + TS_LOGD("tag:%s", tag.c_str()); + return true; +} +bool HtraceEventParser::BinderTractionLockedEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, STAT_EVENT_RECEIVED); + ProtoReader::BinderLockedFormat_Reader msg(event.Data(), event.Size()); + std::string tag = msg.tag().ToStdString(); + streamFilters_->binderFilter_->TractionLocked(eventTimeStamp_, eventTid_, tag); + return true; +} +bool HtraceEventParser::BinderTractionUnLockEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, STAT_EVENT_RECEIVED); + ProtoReader::BinderUnlockFormat_Reader msg(event.Data(), event.Size()); + std::string tag = msg.tag().ToStdString(); + streamFilters_->binderFilter_->TractionUnlock(eventTimeStamp_, eventTid_, tag); + return true; +} +bool HtraceEventParser::SchedSwitchEvent(const ProtoReader::DataArea& event) +{ + ProtoReader::SchedSwitchFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_RECEIVED); + uint32_t prevPrioValue = msg.prev_prio(); + uint32_t nextPrioValue = msg.next_prio(); + uint32_t prevPidValue = msg.prev_pid(); + uint32_t nextPidValue = msg.next_pid(); + if (!tids_.count(prevPidValue)) { + tids_.insert(prevPidValue); + } + if (!tids_.count(nextPidValue)) { + tids_.insert(nextPidValue); + } + std::string prevCommStr = msg.prev_comm().ToStdString(); + std::string nextCommStr = msg.next_comm().ToStdString(); + auto prevState = msg.prev_state(); + + auto nextInternalTid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, nextPidValue, nextCommStr); + auto uprevtid = + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, prevPidValue, prevCommStr); + streamFilters_->cpuFilter_->InsertSwitchEvent(eventTimeStamp_, eventCpu_, uprevtid, + static_cast(prevPrioValue), prevState, nextInternalTid, + static_cast(nextPrioValue), INVALID_DATAINDEX); + return true; +} +bool HtraceEventParser::SchedBlockReasonEvent(const ProtoReader::DataArea& event) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_RECEIVED); + ProtoReader::SchedBlockedReasonFormat_Reader msg(event.Data(), event.Size()); + uint32_t pid = msg.pid(); + uint32_t ioWait = msg.io_wait(); + auto caller = traceDataCache_->GetDataIndex( + std::string_view("0x" + SysTuning::base::number(msg.caller(), SysTuning::base::INTEGER_RADIX_TYPE_HEX))); + auto itid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, pid); + if (!streamFilters_->cpuFilter_->InsertBlockedReasonEvent(eventTimeStamp_, eventCpu_, itid, ioWait, caller, + INVALID_UINT32)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_BLOCKED_REASON, STAT_EVENT_NOTMATCH); + } + return true; +} +bool HtraceEventParser::ProcessExitEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_RECEIVED); + ProtoReader::SchedProcessExitFormat_Reader msg(event.Data(), event.Size()); + uint32_t pidValue = msg.pid(); + // The tostdstring() here cannot use temporary variables, which will cause occasional garbled characters under wasm + auto iTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, pidValue, + msg.comm().ToStdString()); + if (streamFilters_->cpuFilter_->InsertProcessExitEvent(eventTimeStamp_, eventCpu_, iTid)) { + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_NOTMATCH); + return false; + } +} +bool HtraceEventParser::ProcessFreeEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_FREE, STAT_EVENT_RECEIVED); + ProtoReader::SchedProcessFreeFormat_Reader msg(event.Data(), event.Size()); + uint32_t pidValue = msg.pid(); + // The tostdstring() here cannot use temporary variables, which will cause occasional garbled characters under wasm + auto iTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, pidValue, + msg.comm().ToStdString()); + if (streamFilters_->cpuFilter_->InsertProcessFreeEvent(eventTimeStamp_, iTid)) { + return true; + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_FREE, STAT_EVENT_NOTMATCH); + return false; + } +} +bool HtraceEventParser::TaskRenameEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_RENAME, STAT_EVENT_RECEIVED); + ProtoReader::TaskRenameFormat_Reader msg(event.Data(), event.Size()); + auto commStr = msg.newcomm(); + auto pidValue = msg.pid(); + streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, pidValue, commStr.ToStdString()); + return true; +} +bool HtraceEventParser::TaskNewtaskEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_RECEIVED); + // the clone flag from txt trace from kernel original is HEX, but when it is converted from proto + // based trace, it will be OCT number, it is not stable, so we decide to ignore it + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool HtraceEventParser::ParsePrintEvent(const ProtoReader::DataArea& event) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PRINT, STAT_EVENT_RECEIVED); + ProtoReader::PrintFormat_Reader msg(event.Data(), event.Size()); + BytraceLine line; + line.tgid = eventPid_; + line.pid = eventTid_; + line.ts = eventTimeStamp_; + printEventParser_.ParsePrintEvent(comm_, eventTimeStamp_, eventTid_, msg.buf().ToStdString(), line); + if (!tids_.count(eventTid_)) { + tids_.insert(eventTid_); + } + return true; +} +bool HtraceEventParser::SchedWakeupEvent(const ProtoReader::DataArea& event) const +{ + ProtoReader::SchedWakeupFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_RECEIVED); + auto instants = traceDataCache_->GetInstantsData(); + + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, msg.pid()); + InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + instants->AppendInstantEventData(eventTimeStamp_, schedWakeupName_, internalTid, wakeupFromPid); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid); + uint32_t targetCpu = msg.target_cpu(); + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_SCHED_WAKEUP, targetCpu, internalTid); + return true; +} +bool HtraceEventParser::SchedWakeupNewEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP_NEW, STAT_EVENT_RECEIVED); + ProtoReader::SchedWakeupNewFormat_Reader msg(event.Data(), event.Size()); + auto instants = traceDataCache_->GetInstantsData(); + + auto internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, msg.pid()); + auto wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + instants->AppendInstantEventData(eventTimeStamp_, schedWakeupNewName_, internalTid, wakeupFromPid); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid); + uint32_t targetCpu = msg.target_cpu(); + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_SCHED_WAKEUP, targetCpu, internalTid); + return true; +} +bool HtraceEventParser::SchedWakingEvent(const ProtoReader::DataArea& event) const +{ + ProtoReader::SchedWakingFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_RECEIVED); + uint32_t wakePidValue = msg.pid(); + auto instants = traceDataCache_->GetInstantsData(); + auto internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, wakePidValue); + auto wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid, true); + instants->AppendInstantEventData(eventTimeStamp_, schedWakingName_, internalTid, wakeupFromPid); + streamFilters_->cpuFilter_->InsertWakeupEvent(eventTimeStamp_, internalTid); + uint32_t targetCpu = msg.target_cpu(); + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_SCHED_WAKING, targetCpu, wakeupFromPid); + return true; +} +bool HtraceEventParser::CpuIdleEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_RECEIVED); + ProtoReader::CpuIdleFormat_Reader msg(event.Data(), event.Size()); + std::optional eventCpuValue = msg.cpu_id(); + std::optional newStateValue = msg.state(); + if (!eventCpuValue.has_value()) { + TS_LOGW("Failed to convert event cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + if (!newStateValue.has_value()) { + TS_LOGW("Failed to convert state"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } + + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuIdleName_, eventTimeStamp_, + config_.GetStateValue(newStateValue.value())); + + // Add cpu_idle event to raw_data_table + traceDataCache_->GetRawData()->AppendRawData(0, eventTimeStamp_, RAW_CPU_IDLE, eventCpuValue.value(), 0); + return true; +} +bool HtraceEventParser::CpuFrequencyEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_RECEIVED); + ProtoReader::CpuFrequencyFormat_Reader msg(event.Data(), event.Size()); + std::optional newStateValue = msg.state(); + std::optional eventCpuValue = msg.cpu_id(); + + if (!newStateValue.has_value()) { + TS_LOGW("Failed to convert state"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + if (!eventCpuValue.has_value()) { + TS_LOGW("Failed to convert event cpu"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } + + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue.value(), cpuFrequencyName_, eventTimeStamp_, + newStateValue.value()); + return true; +} +bool HtraceEventParser::CpuFrequencyLimitsEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY_LIMITS, STAT_EVENT_RECEIVED); + ProtoReader::CpuFrequencyLimitsFormat_Reader msg(event.Data(), event.Size()); + uint32_t maxFreq = msg.max_freq(); + uint32_t minFreq = msg.min_freq(); + uint32_t eventCpuValue = msg.cpu_id(); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue, cpuFrequencyLimitMaxNameId, eventTimeStamp_, + maxFreq); + streamFilters_->cpuMeasureFilter_->AppendNewMeasureData(eventCpuValue, cpuFrequencyLimitMinNameId, eventTimeStamp_, + minFreq); + return true; +} +bool HtraceEventParser::SuspendResumeEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SUSPEND_RESUME, STAT_EVENT_RECEIVED); + ProtoReader::SuspendResumeFormat_Reader msg(event.Data(), event.Size()); + int32_t val = msg.val(); + uint32_t start = msg.start(); + std::string action = msg.action().ToStdString(); + UNUSED(val); + UNUSED(start); + UNUSED(action); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SUSPEND_RESUME, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool HtraceEventParser::WorkqueueExecuteStartEvent(const ProtoReader::DataArea& event) const +{ + ProtoReader::WorkqueueExecuteStartFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_START, STAT_EVENT_RECEIVED); + auto funcNameIndex = streamFilters_->symbolsFilter_->GetFunc(msg.function()); + size_t result = INVALID_UINT32; + if (funcNameIndex == INVALID_UINT64) { + std::string addrStr = "0x" + base::number(msg.function(), base::INTEGER_RADIX_TYPE_HEX); + auto addStrIndex = traceDataCache_->GetDataIndex(addrStr); + result = streamFilters_->sliceFilter_->BeginSlice(comm_, eventTimeStamp_, eventPid_, eventPid_, workQueueId_, + addStrIndex); + } else { + result = streamFilters_->sliceFilter_->BeginSlice(comm_, eventTimeStamp_, eventPid_, eventPid_, workQueueId_, + funcNameIndex); + } + + traceDataCache_->GetInternalSlicesData()->AppendDistributeInfo(); + if (result == INVALID_UINT32) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_LOST); + } + return true; +} +bool HtraceEventParser::WorkqueueExecuteEndEvent(const ProtoReader::DataArea& event) const +{ + ProtoReader::WorkqueueExecuteEndFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_RECEIVED); + if (streamFilters_->sliceFilter_->EndSlice(eventTimeStamp_, eventPid_, eventPid_, workQueueId_)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_NOTMATCH); + } + return true; +} +bool HtraceEventParser::ClockSetRateEvent(const ProtoReader::DataArea& event) const +{ + ProtoReader::ClockSetRateFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_RECEIVED); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name().ToStdString()); + streamFilters_->clockRateFilter_->AppendNewMeasureData(msg.cpu_id(), nameIndex, eventTimeStamp_, msg.state()); + return true; +} +bool HtraceEventParser::ClockEnableEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_RECEIVED); + ProtoReader::ClockEnableFormat_Reader msg(event.Data(), event.Size()); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name().ToStdString()); + streamFilters_->clockEnableFilter_->AppendNewMeasureData(msg.cpu_id(), nameIndex, eventTimeStamp_, msg.state()); + return true; +} +bool HtraceEventParser::ClockDisableEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_RECEIVED); + ProtoReader::ClockDisableFormat_Reader msg(event.Data(), event.Size()); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name().ToStdString()); + streamFilters_->clockDisableFilter_->AppendNewMeasureData(msg.cpu_id(), nameIndex, eventTimeStamp_, msg.state()); + return true; +} +bool HtraceEventParser::ClkSetRateEvent(const ProtoReader::DataArea& event) const +{ + ProtoReader::ClkSetRateFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLK_SET_RATE, STAT_EVENT_RECEIVED); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name().ToStdString()); + streamFilters_->clkRateFilter_->AppendNewMeasureData(eventCpu_, nameIndex, eventTimeStamp_, msg.rate()); + return true; +} +bool HtraceEventParser::ClkEnableEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLK_ENABLE, STAT_EVENT_RECEIVED); + ProtoReader::ClkEnableFormat_Reader msg(event.Data(), event.Size()); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name().ToStdString()); + streamFilters_->clkEnableFilter_->AppendNewMeasureData(eventCpu_, nameIndex, eventTimeStamp_, 1); + return true; +} +bool HtraceEventParser::ClkDisableEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLK_DISABLE, STAT_EVENT_RECEIVED); + ProtoReader::ClkDisableFormat_Reader msg(event.Data(), event.Size()); + DataIndex nameIndex = traceDataCache_->GetDataIndex(msg.name().ToStdString()); + streamFilters_->clkDisableFilter_->AppendNewMeasureData(eventCpu_, nameIndex, eventTimeStamp_, 0); + return true; +} + +bool HtraceEventParser::IrqHandlerEntryEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_RECEIVED); + ProtoReader::IrqHandlerEntryFormat_Reader msg(event.Data(), event.Size()); + // The tostdstring() here cannot use temporary variables, which will cause occasional garbled characters under wasm + streamFilters_->irqFilter_->IrqHandlerEntry(eventTimeStamp_, eventCpu_, + traceDataCache_->GetDataIndex(msg.name().ToStdString())); + return true; +} +bool HtraceEventParser::IrqHandlerExitEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_RECEIVED); + ProtoReader::IrqHandlerExitFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->irqFilter_->IrqHandlerExit(eventTimeStamp_, eventCpu_, msg.irq(), static_cast(msg.ret())); + return true; +} +bool HtraceEventParser::IpiHandlerEntryEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_ENTRY, STAT_EVENT_RECEIVED); + ProtoReader::IpiEntryFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->irqFilter_->IpiHandlerEntry(eventTimeStamp_, eventCpu_, + traceDataCache_->GetDataIndex(msg.reason().ToStdString())); + return true; +} +bool HtraceEventParser::IpiHandlerExitEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IPI_EXIT, STAT_EVENT_RECEIVED); + streamFilters_->irqFilter_->IpiHandlerExit(eventTimeStamp_, eventCpu_); + return true; +} +bool HtraceEventParser::SoftIrqEntryEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_RECEIVED); + ProtoReader::SoftirqEntryFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->irqFilter_->SoftIrqEntry(eventTimeStamp_, eventCpu_, static_cast(msg.vec())); + return true; +} +bool HtraceEventParser::SoftIrqRaiseEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_RECEIVED); + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_RAISE, STAT_EVENT_NOTSUPPORTED); + return true; +} +bool HtraceEventParser::SoftIrqExitEvent(const ProtoReader::DataArea& event) const +{ + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_RECEIVED); + ProtoReader::SoftirqExitFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->irqFilter_->SoftIrqExit(eventTimeStamp_, eventCpu_, static_cast(msg.vec())); + return true; +} +bool HtraceEventParser::SysEnterEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SYS_ENTRY, STAT_EVENT_RECEIVED); + ProtoReader::SysEnterFormat_Reader msg(event.Data(), event.Size()); + auto ipid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventPid_); + traceDataCache_->GetSysCallData()->AppendSysCallData(msg.id(), sysEnterName_, ipid, eventTimeStamp_, 0); + return true; +} +bool HtraceEventParser::SysExitEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SYS_EXIT, STAT_EVENT_RECEIVED); + ProtoReader::SysExitFormat_Reader msg(event.Data(), event.Size()); + auto ipid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventPid_); + traceDataCache_->GetSysCallData()->AppendSysCallData(msg.id(), sysExitName_, ipid, eventTimeStamp_, msg.ret()); + return true; +} + +bool HtraceEventParser::OomScoreAdjUpdate(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OOM_SCORE_ADJ_UPDATE, STAT_EVENT_RECEIVED); + ProtoReader::OomScoreAdjUpdateFormat_Reader msg(event.Data(), event.Size()); + streamFilters_->processMeasureFilter_->AppendNewMeasureData(msg.pid(), oomScoreAdjName_, eventTimeStamp_, + msg.oom_score_adj()); + return true; +} + +bool HtraceEventParser::SignalGenerateEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BLOCK_BIO_BACKMERGE, STAT_EVENT_RECEIVED); + ProtoReader::SignalGenerateFormat_Reader msg(event.Data(), event.Size()); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithName(eventTimeStamp_, msg.pid(), + msg.comm().ToStdString()); + streamFilters_->threadFilter_->AppendNewMeasureData(internalTid, signalGenerateId_, eventTimeStamp_, msg.sig()); + return true; +} +bool HtraceEventParser::SignalDeleverEvent(const ProtoReader::DataArea& event) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BLOCK_BIO_BACKMERGE, STAT_EVENT_RECEIVED); + ProtoReader::SignalDeliverFormat_Reader msg(event.Data(), event.Size()); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventPid_); + streamFilters_->threadFilter_->AppendNewMeasureData(internalTid, signalDeliverId_, eventTimeStamp_, msg.sig()); + return true; +} +bool HtraceEventParser::InvokeFunc(const SupportedTraceEventType& eventType, const ProtoReader::DataArea& msgBase) +{ + auto eventName = config_.eventNameMap_.find(eventType); + if (eventName == config_.eventNameMap_.end()) { + // log warn + streamFilters_->statFilter_->IncreaseStat(eventType, STAT_EVENT_NOTSUPPORTED); + return false; + } + auto it = eventToFunctionMap_.find(eventName->second); + if (it == eventToFunctionMap_.end()) { + // log warn + streamFilters_->statFilter_->IncreaseStat(eventType, STAT_EVENT_NOTSUPPORTED); + return false; + } + it->second(msgBase); + return true; +} +void HtraceEventParser::FilterAllEventsReader() +{ + size_t maxBuffSize = 1000 * 1000; + size_t maxQueue = 2; + + if (eventList_.size() < maxBuffSize * maxQueue) { + return; + } + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimeStamp_ < b->eventTimeStamp_; + }; +#ifdef IS_WASM + std::sort(eventList_.begin(), eventList_.end(), cmp); +#else + std::stable_sort(eventList_.begin(), eventList_.end(), cmp); +#endif + + auto endOfList = eventList_.begin() + maxBuffSize; + for (auto itor = eventList_.begin(); itor != endOfList; ++itor) { + EventInfo* event = itor->get(); + ProtoReader::FtraceEvent_Reader ftraceEvent(event->ftraceEventBytes_); + eventTimeStamp_ = event->eventTimeStamp_; + eventCpu_ = event->eventCpu_; + if (ftraceEvent.tgid() != INVALID_INT32) { + eventPid_ = ftraceEvent.tgid(); + if (!pids_.count(eventPid_)) { + pids_.insert(eventPid_); + } + streamFilters_->processFilter_->GetOrCreateThreadWithPid(eventPid_, eventPid_); + } + comm_ = ftraceEvent.comm().ToStdString(); + + ProtoReader::FtraceEvent_CommonFileds_Reader comonFields(ftraceEvent.common_fields().data_, + ftraceEvent.common_fields().size_); + if (comonFields.pid() != INVALID_INT32) { + eventTid_ = comonFields.pid(); + if (!tids_.count(eventTid_)) { + tids_.insert(eventTid_); + } + streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + } + if (eventTid_ != INVALID_INT32 && eventPid_ != INVALID_INT32) { + streamFilters_->processFilter_->GetOrCreateThreadWithPid(eventTid_, eventPid_); + } + DealEvent(&ftraceEvent, &comonFields); + itor->reset(); + } + eventList_.erase(eventList_.begin(), endOfList); +} +void HtraceEventParser::FilterAllEvents() +{ + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimeStamp_ < b->eventTimeStamp_; + }; +#ifdef IS_WASM + std::sort(eventList_.begin(), eventList_.end(), cmp); +#else + std::stable_sort(eventList_.begin(), eventList_.end(), cmp); +#endif + size_t maxBuffSize = 1000 * 1000; + + while (eventList_.size()) { + int32_t size = std::min(maxBuffSize, eventList_.size()); + auto endOfList = eventList_.begin() + size; + for (auto itor = eventList_.begin(); itor != endOfList; itor++) { + EventInfo* event = itor->get(); + ProtoReader::FtraceEvent_Reader ftraceEvent(event->ftraceEventBytes_); + eventTimeStamp_ = event->eventTimeStamp_; + eventCpu_ = event->eventCpu_; + eventPid_ = ftraceEvent.tgid(); + comm_ = ftraceEvent.comm().ToStdString(); + + ProtoReader::FtraceEvent_CommonFileds_Reader comonFields(ftraceEvent.common_fields().data_, + ftraceEvent.common_fields().size_); + if (comonFields.pid() != INVALID_INT32) { + eventTid_ = comonFields.pid(); + if (!tids_.count(eventTid_)) { + tids_.insert(eventTid_); + } + streamFilters_->processFilter_->UpdateOrCreateThread(eventTimeStamp_, eventTid_); + } + if (eventTid_ != INVALID_INT32 && eventPid_ != INVALID_INT32) { + streamFilters_->processFilter_->GetOrCreateThreadWithPid(eventTid_, eventPid_); + } + DealEvent(&ftraceEvent, &comonFields); + itor->reset(); + } + eventList_.erase(eventList_.begin(), endOfList); + } + eventList_.clear(); + streamFilters_->cpuFilter_->Finish(); + traceDataCache_->dataDict_.Finish(); + traceDataCache_->UpdataZeroThreadInfo(); +} +void HtraceEventParser::Clear() +{ + streamFilters_->binderFilter_->Clear(); + streamFilters_->sliceFilter_->Clear(); + streamFilters_->cpuFilter_->Clear(); + streamFilters_->irqFilter_->Clear(); + streamFilters_->cpuMeasureFilter_->Clear(); + streamFilters_->threadMeasureFilter_->Clear(); + streamFilters_->threadFilter_->Clear(); + streamFilters_->processMeasureFilter_->Clear(); + streamFilters_->processFilterFilter_->Clear(); + streamFilters_->symbolsFilter_->Clear(); + streamFilters_->clockEnableFilter_->Clear(); + streamFilters_->clockDisableFilter_->Clear(); + streamFilters_->clkRateFilter_->Clear(); + streamFilters_->clkDisableFilter_->Clear(); + streamFilters_->binderFilter_->Clear(); + streamFilters_->sysEventMemMeasureFilter_->Clear(); + streamFilters_->sysEventVMemMeasureFilter_->Clear(); + printEventParser_.Finish(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_event_parser/htrace_event_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_event_parser/htrace_event_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..abb06fb48bc8ad18a365fbbf7c4562432bff62d8 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_event_parser/htrace_event_parser.h @@ -0,0 +1,144 @@ +/* + * 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 HTRACE_EVENT_PARSER_H +#define HTRACE_EVENT_PARSER_H +#include +#include +#include +#include +#include +#include +#include + +#include "event_parser_base.h" +#include "ftrace_event.pbreader.h" +#include "google/protobuf/message_lite.h" +#include "log.h" +#include "print_event_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pbreader.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace google::protobuf; +class HtraceEventParser : private EventParserBase { +public: + HtraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + ~HtraceEventParser(); + void ParseDataItem(HtraceDataSegment& tracePacket, BuiltinClocks clock); + void FilterAllEventsReader(); + void FilterAllEvents(); + void Clear(); + +private: + void DealEvent(ProtoReader::FtraceEvent_Reader* event, ProtoReader::FtraceEvent_CommonFileds_Reader* comonFields); + bool BinderTractionEvent(const ProtoReader::DataArea& event) const; + bool BinderTractionReceivedEvent(const ProtoReader::DataArea& event) const; + bool BinderTractionAllocBufEvent(const ProtoReader::DataArea& event) const; + bool BinderTractionLockEvent(const ProtoReader::DataArea& event) const; + bool BinderTractionLockedEvent(const ProtoReader::DataArea& event) const; + bool BinderTractionUnLockEvent(const ProtoReader::DataArea& event) const; + bool SchedSwitchEvent(const ProtoReader::DataArea& event); + bool SchedBlockReasonEvent(const ProtoReader::DataArea& event); + bool ProcessExitEvent(const ProtoReader::DataArea& event) const; + bool ProcessFreeEvent(const ProtoReader::DataArea& event) const; + bool TaskRenameEvent(const ProtoReader::DataArea& event) const; + bool TaskNewtaskEvent(const ProtoReader::DataArea& event) const; + bool ParsePrintEvent(const ProtoReader::DataArea& event); + bool SchedWakeupEvent(const ProtoReader::DataArea& event) const; + bool SchedWakeupNewEvent(const ProtoReader::DataArea& event) const; + bool SchedWakingEvent(const ProtoReader::DataArea& event) const; + bool CpuIdleEvent(const ProtoReader::DataArea& event) const; + bool CpuFrequencyEvent(const ProtoReader::DataArea& event) const; + bool CpuFrequencyLimitsEvent(const ProtoReader::DataArea& event) const; + bool SuspendResumeEvent(const ProtoReader::DataArea& event) const; + bool WorkqueueExecuteStartEvent(const ProtoReader::DataArea& event) const; + bool WorkqueueExecuteEndEvent(const ProtoReader::DataArea& event) const; + bool ClockSetRateEvent(const ProtoReader::DataArea& event) const; + bool ClockEnableEvent(const ProtoReader::DataArea& event) const; + bool ClockDisableEvent(const ProtoReader::DataArea& event) const; + bool ClkSetRateEvent(const ProtoReader::DataArea& event) const; + bool ClkEnableEvent(const ProtoReader::DataArea& event) const; + bool ClkDisableEvent(const ProtoReader::DataArea& event) const; + bool IrqHandlerEntryEvent(const ProtoReader::DataArea& event) const; + bool IrqHandlerExitEvent(const ProtoReader::DataArea& event) const; + bool IpiHandlerEntryEvent(const ProtoReader::DataArea& event) const; + bool IpiHandlerExitEvent(const ProtoReader::DataArea& event) const; + bool SoftIrqEntryEvent(const ProtoReader::DataArea& event) const; + bool SoftIrqRaiseEvent(const ProtoReader::DataArea& event) const; + bool SoftIrqExitEvent(const ProtoReader::DataArea& event) const; + bool SysEnterEvent(const ProtoReader::DataArea& event) const; + bool SysExitEvent(const ProtoReader::DataArea& event) const; + bool OomScoreAdjUpdate(const ProtoReader::DataArea& event) const; + bool SignalGenerateEvent(const ProtoReader::DataArea& event) const; + bool SignalDeleverEvent(const ProtoReader::DataArea& event) const; + bool InvokeFunc(const SupportedTraceEventType& eventType, const ProtoReader::DataArea& msgBase); + class EventInfo { + public: + EventInfo(uint64_t eventTimestamp, + uint32_t eventCpu, + std::shared_ptr cpuDetail, + ProtoReader::BytesView ftraceEventBytes) + : eventTimeStamp_(eventTimestamp), + eventCpu_(eventCpu), + cpuDetail_(std::move(cpuDetail)), + ftraceEventBytes_(ftraceEventBytes) + { + } + uint64_t eventTimeStamp_; + uint32_t eventCpu_; + std::shared_ptr cpuDetail_; + ProtoReader::BytesView ftraceEventBytes_; + }; + using FuncCall = std::function; + uint32_t eventCpu_ = INVALID_UINT32; + uint64_t eventTimeStamp_ = INVALID_UINT64; + std::string comm_ = ""; + uint32_t eventPid_ = INVALID_UINT32; + uint32_t eventTid_ = INVALID_UINT32; + std::map eventToFunctionMap_ = {}; + std::unordered_set tids_ = {}; + std::unordered_set pids_ = {}; + DataIndex workQueueId_ = 0; + PrintEventParser printEventParser_; + uint64_t lastOverwrite_ = 0; + uint64_t ftraceStartTime_ = std::numeric_limits::max(); + uint64_t ftraceEndTime_ = 0; + uint64_t ftraceOriginStartTime_ = std::numeric_limits::max(); + uint64_t ftraceOriginEndTime_ = 0; + std::vector> eventList_ = {}; + // std::vector> eventList_ = {}; + const DataIndex signalGenerateId_ = traceDataCache_->GetDataIndex("signal_generate"); + const DataIndex signalDeliverId_ = traceDataCache_->GetDataIndex("signal_deliver"); + const DataIndex schedWakeupName_ = traceDataCache_->GetDataIndex("sched_wakeup"); + const DataIndex schedWakingName_ = traceDataCache_->GetDataIndex("sched_waking"); + const DataIndex schedWakeupNewName_ = traceDataCache_->GetDataIndex("sched_wakeup_new"); + const DataIndex cpuIdleName_ = traceDataCache_->GetDataIndex("cpu_idle"); + const DataIndex cpuFrequencyName_ = traceDataCache_->GetDataIndex("cpu_frequency"); + const DataIndex cpuFrequencyLimitMaxNameId = traceDataCache_->GetDataIndex("cpu_frequency_limits_max"); + const DataIndex cpuFrequencyLimitMinNameId = traceDataCache_->GetDataIndex("cpu_frequency_limits_min"); + const DataIndex sysEnterName_ = traceDataCache_->GetDataIndex("sys_enter"); + const DataIndex sysExitName_ = traceDataCache_->GetDataIndex("sys_exit"); + const DataIndex oomScoreAdjName_ = traceDataCache_->GetDataIndex("oom_score_adj"); + TraceStreamerConfig config_{}; + BuiltinClocks clock_ = TS_CLOCK_BOOTTIME; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_EVENT_PARSER_H_ diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_file_header.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_file_header.h new file mode 100644 index 0000000000000000000000000000000000000000..9854f21287bca3858ebc5627f4cf270bde2736e2 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_file_header.h @@ -0,0 +1,64 @@ +/* + * 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 HTRACE_FILE_HEADER_H +#define HTRACE_FILE_HEADER_H +namespace SysTuning { +namespace TraceStreamer { +struct ProfilerTraceFileHeader { + // Some space is reserved to facilitate the subsequent addition of fields in the header + static constexpr uint32_t HEADER_SIZE = 1024; + static constexpr uint32_t SHA256_SIZE = 256 / 8; + static constexpr uint64_t HEADER_MAGIC = 0x464F5250534F484FuLL; + static constexpr uint32_t V_MAJOR = 0x0001; + static constexpr uint32_t V_MAJOR_BITS = 16; + static constexpr uint32_t V_MINOR = 0x0000; + static constexpr uint32_t TRACE_VERSION = (V_MAJOR << V_MAJOR_BITS) | V_MINOR; + static constexpr uint8_t PLUGIN_MODULE_NAME_MAX = 127; + static constexpr uint8_t PLUGIN_MODULE_VERSION_MAX = 7; + enum DataType { + HIPROFILER_PROTOBUF_BIN = 0, + HIPERF_DATA, + STANDALONE_DATA = 1000, + UNKNOW_TYPE = 1024, + }; + struct HeaderData { + // Magic number, used to distinguish offline files + uint64_t magic = HEADER_MAGIC; + // Total length, which can be used to check whether the document is truncated; + uint64_t length = HEADER_SIZE; + uint32_t version = TRACE_VERSION; + // The number of segments in the load data. The number of segments is even. One describes the length L and the + // other describes the next data v + uint32_t segments = 0; + // Sha256 of load data is used to verify whether the load data is complete; + uint8_t sha256[SHA256_SIZE] = {}; + uint32_t dataType = UNKNOW_TYPE; + // clock + uint64_t boottime = 0; + uint64_t realtime = 0; + uint64_t realtimeCoarse = 0; + uint64_t monotonic = 0; + uint64_t monotonicCoarse = 0; + uint64_t monotonicRaw = 0; + char standalonePluginName[PLUGIN_MODULE_NAME_MAX + 1] = ""; + char pluginVersion[PLUGIN_MODULE_VERSION_MAX + 1] = ""; + } __attribute__((packed)); + HeaderData data = {}; + uint8_t padding_[HEADER_SIZE - sizeof(data)] = {}; +}; +const std::string EBPF_PLUGIN_NAME = "hiebpf-plugin"; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HTRACE_FILE_HEADER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hidump_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hidump_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ada2525e64f48346598afbc345330be28de7ded --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hidump_parser.cpp @@ -0,0 +1,55 @@ +/* + * 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 "htrace_hidump_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceHidumpParser::HtraceHidumpParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx), clockId_(0) +{ +} + +HtraceHidumpParser::~HtraceHidumpParser() +{ + TS_LOGI("Fps data ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceHidumpParser::Parse(ProtoReader::BytesView tracePacket) +{ + ProtoReader::HidumpInfo_Reader hidumpInfo(tracePacket.data_, tracePacket.size_); + if (!hidumpInfo.has_fps_event()) { + return; + } + for (auto i = hidumpInfo.fps_event(); i; ++i) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HIDUMP_FPS, STAT_EVENT_RECEIVED); + ProtoReader::FpsData_Reader hidumpData(i->ToBytes()); + auto hidumpTime = ProtoReader::FpsData_TimeSpec_Reader(hidumpData.time()); + auto timeStamp = hidumpTime.tv_nsec() + hidumpTime.tv_sec() * SEC_TO_NS; + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(hidumpData.id(), timeStamp); + UpdatePluginTimeRange(hidumpData.id(), timeStamp, newTimeStamp); + clockId_ = hidumpData.id(); + auto fps = hidumpData.fps(); + traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(newTimeStamp, fps); + } +} +void HtraceHidumpParser::Finish() +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hidump_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hidump_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..dc226921a276095d75cf77dc145b32fc8a77cad5 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hidump_parser.h @@ -0,0 +1,45 @@ +/* + * 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 HTRACE_HIDUMP_PARSER_H +#define HTRACE_HIDUMP_PARSER_H +#include +#include +#include +#include "common_types.h" +#include "htrace_plugin_time_parser.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceHidumpParser : public HtracePluginTimeParser { +public: + HtraceHidumpParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceHidumpParser(); + void Parse(ProtoReader::BytesView tracePacket); + void Finish(); + uint8_t ClockId() + { + return clockId_; + } + +private: + uint8_t clockId_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_HIDUMP_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hilog_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hilog_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9cfe42065c602ca4a27809dd3f2aa217254c6b2a --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hilog_parser.cpp @@ -0,0 +1,71 @@ +/* + * 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 "htrace_hilog_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceHiLogParser::HtraceHiLogParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceHiLogParser::~HtraceHiLogParser() +{ + TS_LOGI("hilog ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceHiLogParser::Parse(ProtoReader::BytesView tracePacket) +{ + ProtoReader::HilogInfo_Reader hilogInfo(tracePacket.data_, tracePacket.size_); + if (!hilogInfo.has_info()) { + return; + } + for (auto i = hilogInfo.info(); i; ++i) { + ProtoReader::HilogLine_Reader hilogLine(i->ToBytes()); + uint64_t curLineSeq = hilogLine.id(); + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_RECEIVED); + if (curLineSeq < lastLineSeq_ + 1) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_NOTMATCH); + } else if (curLineSeq > lastLineSeq_ + 1) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_DATA_LOST); + } + lastLineSeq_ = curLineSeq; + auto logData = traceDataCache_->GetDataIndex(hilogLine.context().ToStdString()); + ProtoReader::HilogDetails_Reader logDetails(hilogLine.detail()); + streamFilters_->processFilter_->GetOrCreateThreadWithPid(logDetails.tid(), logDetails.pid()); + auto iter = logLevelString_.find(logDetails.level()); + if (iter == logLevelString_.end()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HILOG, STAT_EVENT_DATA_INVALID); + TS_LOGD("log level do not exit!!!"); + continue; + } + auto timeStamp = logDetails.tv_nsec() + logDetails.tv_sec() * SEC_TO_NS; + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, newTimeStamp); + DataIndex levelData = traceDataCache_->dataDict_.GetStringIndex(iter->second.c_str()); + DataIndex logTag = traceDataCache_->dataDict_.GetStringIndex(logDetails.tag().ToStdString()); + traceDataCache_->GetHilogData()->AppendNewLogInfo(curLineSeq, newTimeStamp, logDetails.pid(), logDetails.tid(), + levelData, logTag, logData, timeStamp); + } +} +void HtraceHiLogParser::Finish() +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hilog_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hilog_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..e357bbe697932ef625ae52a58d6365c50326b33b --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hilog_parser.h @@ -0,0 +1,47 @@ +/* + * 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 HTRACE_HILOG_PARSER_H +#define HTRACE_HILOG_PARSER_H +#include +#include +#include +#include "common_types.h" +#include "trace_data/trace_data_cache.h" +#include "hilog_plugin_result.pb.h" +#include "htrace_plugin_time_parser.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceHiLogParser : public HtracePluginTimeParser { +public: + HtraceHiLogParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceHiLogParser(); + void Parse(ProtoReader::BytesView tracePacket); + std::map logLevelString_ = {{TS_DEBUG, "D"}, + {TS_ERROR, "E"}, + {TS_INFO, "I"}, + {TS_VERBOSE, "V"}, + {TS_WARN, "W"}}; + void Finish(); + +private: + uint64_t lastLineSeq_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_HILOG_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hisysevent_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hisysevent_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f9c67f6bc9f106e4647984bd5a303064a21fa1c --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hisysevent_parser.cpp @@ -0,0 +1,206 @@ +/* + * 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 "clock_filter.h" +#include "hi_sysevent_measure_filter.h" +#include "htrace_event_parser.h" +#include "htrace_hisysevent_parser.h" +#include "htrace_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceHisyseventParser::HtraceHisyseventParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} +HtraceHisyseventParser::~HtraceHisyseventParser() +{ + TS_LOGI("hisysevent ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); + TS_LOGI("hisysevent real ts MIN:%llu, MAX:%llu", static_cast(MinTs()), + static_cast(MaxTs())); +} + +int32_t HtraceHisyseventParser::JGetData(json& jMessage, + JsonData& jData, + size_t& maxArraySize, + std::vector& noArrayIndex, + std::vector& arrayIndex) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_RECEIVED); + for (auto i = jMessage.begin(); i != jMessage.end(); i++) { + if (i.key() == "name_") { + if (find(eventsAccordingAppNames.begin(), eventsAccordingAppNames.end(), i.value()) == + eventsAccordingAppNames.end()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_NOTMATCH); + TS_LOGW("event source:%s not supported for hisysevent", std::string(i.value()).c_str()); + return -1; + } + jData.eventSource = i.value(); + continue; + } + if (i.key() == "time_") { + jData.timeStamp = i.value(); + continue; + } + if (i.key() == "tag_" && i.value() != "PowerStats") { + streamFilters_->statFilter_->IncreaseStat(TRACE_HISYSEVENT, STAT_EVENT_DATA_INVALID); + return -1; + } + if (i.key() == "APPNAME") { + jData.appName.assign(i.value().begin(), i.value().end()); + } + if (i.value().is_array()) { + maxArraySize = std::max(maxArraySize, i.value().size()); + arrayIndex.push_back(jData.key.size()); + } else { + noArrayIndex.push_back(jData.key.size()); + } + jData.key.push_back(i.key()); + jData.value.push_back(i.value()); + } + return 0; +} + +void HtraceHisyseventParser::NoArrayDataParse(JsonData jData, + std::vector noArrayIndex, + DataIndex eventSourceIndex, + uint64_t serial) +{ + for (auto itor = noArrayIndex.begin(); itor != noArrayIndex.end(); itor++) { + auto value = jData.value[*itor]; + auto key = jData.key[*itor]; + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + DataIndex keyIndex = traceDataCache_->GetDataIndex(key); + if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 1, 0, valueIndex); + } else { + double valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 0, valueIndex, 0); + } + } +} +void HtraceHisyseventParser::ArrayDataParse(JsonData jData, + std::vector arrayIndex, + DataIndex eventSourceIndex, + size_t maxArraySize, + uint64_t serial) +{ + for (int32_t j = 0; j < maxArraySize; j++) { + for (auto itor = arrayIndex.begin(); itor != arrayIndex.end(); itor++) { + auto value = jData.value[*itor][j]; + std::string key = jData.key[*itor]; + DataIndex keyIndex = traceDataCache_->GetDataIndex(key); + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + if (value.is_number()) { + double valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 0, valueIndex, 0); + } else if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 1, 0, valueIndex); + } + } + } +} +void HtraceHisyseventParser::CommonDataParser(JsonData jData, DataIndex eventSourceIndex, uint64_t serial) +{ + for (int32_t j = 0; j < jData.key.size(); j++) { + std::string key = jData.key[j]; + auto value = jData.value[j]; + DataIndex keyIndex = traceDataCache_->GetDataIndex(key); + streamFilters_->hiSysEventMeasureFilter_->GetOrCreateFilterId(eventSourceIndex); + if (value.is_string()) { + std::string strValue = value; + DataIndex valueIndex = traceDataCache_->GetDataIndex(strValue); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 1, 0, valueIndex); + } else { + double valueIndex = value; + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue(serial, jData.timeStamp, eventSourceIndex, + keyIndex, 0, valueIndex, 0); + } + } +} +void HtraceHisyseventParser::Finish() +{ + if (GetPluginStartTime() != GetPluginEndTime()) { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + } else { + TS_LOGI("hisysevent time is not updated, maybe this trace file only has one piece of hisysevent data"); + } + TS_LOGI("--------Parse end--------"); +} + +static std::stringstream ss; +void HtraceHisyseventParser::Parse(ProtoReader::HisyseventInfo_Reader* tracePacket, uint64_t ts) +{ + ProtoReader::DeviceStat_Reader deviceStat(tracePacket->device_state()); + ProtoReader::AudioVolumeInfo_Reader audioVolumeInfo(deviceStat.volume_state()); + if (isDeviceState) { + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue( + deviceStat.brightness_state(), deviceStat.bt_state(), deviceStat.location_state(), deviceStat.wifi_state(), + audioVolumeInfo.stream_default(), audioVolumeInfo.voice_call(), audioVolumeInfo.music(), + audioVolumeInfo.stream_ring(), audioVolumeInfo.media(), audioVolumeInfo.voice_assistant(), + audioVolumeInfo.system(), audioVolumeInfo.alarm(), audioVolumeInfo.notification(), + audioVolumeInfo.bluetoolth_sco(), audioVolumeInfo.enforced_audible(), audioVolumeInfo.stream_dtmf(), + audioVolumeInfo.stream_tts(), audioVolumeInfo.accessibility(), audioVolumeInfo.recording(), + audioVolumeInfo.stream_all()); + isDeviceState = false; + } + json jMessage; + for (auto i = tracePacket->info(); i; ++i) { + ProtoReader::HisyseventLine_Reader hisyseventLine(i->ToBytes()); + if (hisyseventLine.raw_content().ToStdString().front() != '{' || + hisyseventLine.raw_content().ToStdString().back() != '}') { + continue; + } + ss << hisyseventLine.raw_content().ToStdString(); + ss >> jMessage; + size_t maxArraySize = 0; + JsonData jData; + std::vector noArrayIndex = {}; + std::vector arrayIndex = {}; + if (JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex) < 0) { + continue; + } + uint64_t serial = hisyseventLine.id(); + DataIndex eventSourceIndex = traceDataCache_->GetDataIndex(jData.eventSource); + jData.timeStamp *= MSEC_TO_NS; + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, jData.timeStamp); + UpdatePluginTimeRange(TS_CLOCK_BOOTTIME, jData.timeStamp, newTimeStamp); + jData.timeStamp = newTimeStamp; + if (maxArraySize) { + NoArrayDataParse(jData, noArrayIndex, eventSourceIndex, serial); + ArrayDataParse(jData, arrayIndex, eventSourceIndex, maxArraySize, serial); + } else { + CommonDataParser(jData, eventSourceIndex, serial); + } + } +} +void HtraceHisyseventParser::Parse(ProtoReader::HisyseventConfig_Reader* tracePacket, uint64_t ts) +{ + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue("message", tracePacket->msg().ToStdString()); + streamFilters_->hiSysEventMeasureFilter_->AppendNewValue("process_name", tracePacket->process_name().ToStdString()); + return; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hisysevent_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hisysevent_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..8a3697f10d50a4a700d2e48c92c458c41bc71868 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_hisysevent_parser.h @@ -0,0 +1,106 @@ + +/* + * 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 HTRACE_HISYSEVENT_PARSER_H +#define HTRACE_HISYSEVENT_PARSER_H + +#include "clock_filter.h" +#include "htrace_plugin_time_parser.h" +#include "json.hpp" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceHisyseventParser : public HtracePluginTimeParser { +public: + HtraceHisyseventParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceHisyseventParser(); + void Finish(); + void Parse(ProtoReader::HisyseventInfo_Reader* tracePacket, uint64_t ts); + void Parse(ProtoReader::HisyseventConfig_Reader* tracePacket, uint64_t ts); + +private: + using json = nlohmann::json; + typedef struct { + std::string eventSource; + uint64_t timeStamp; + std::vector appName; + std::vector appVersions; + std::vector key; + std::vector value; + } JsonData; + +private: + void NoArrayDataParse(JsonData jData, + std::vector noArrayIndex, + DataIndex eventSourceIndex, + uint64_t serial); + void ArrayDataParse(JsonData jData, + std::vector arrayIndex, + DataIndex eventSourceIndex, + size_t maxArraySize, + uint64_t serial); + void CommonDataParser(JsonData jData, DataIndex eventSourceIndex, uint64_t serial); + int32_t JGetData(json& jMessage, + JsonData& jData, + size_t& maxArraySize, + std::vector& noArrayIndex, + std::vector& arrayIndex); + + std::vector eventsAccordingAppNames = {"POWER_IDE_BATTERY", + "POWER_IDE_CPU", + "POWER_IDE_LOCATION", + "POWER_IDE_GPU", + "POWER_IDE_DISPLAY", + "POWER_IDE_CAMERA", + "POWER_IDE_BLUETOOTH", + "POWER_IDE_FLASHLIGHT", + "POWER_IDE_AUDIO", + "POWER_IDE_WIFISCAN", + "BRIGHTNESS_NIT", + "SIGNAL_LEVEL", + "WIFI_EVENT_RECEIVED", + "AUDIO_STREAM_CHANGE", + "AUDIO_VOLUME_CHANGE", + "WIFI_STATE", + "BLUETOOTH_BR_SWITCH_STATE", + "LOCATION_SWITCH_STATE", + "ENABLE_SENSOR", + "DISABLE_SENSOR", + "WORK_REMOVE", + "WORK_START", + "WORK_STOP", + "WORK_ADD", + "POWER_RUNNINGLOCK", + "GNSS_STATE", + "ANOMALY_SCREEN_OFF_ENERGY", + "ANOMALY_ALARM_WAKEUP", + "ANOMALY_KERNEL_WAKELOCK", + "ANOMALY_RUNNINGLOCK", + "ANORMALY_APP_ENERGY", + "ANOMALY_GNSS_ENERGY", + "ANOMALY_CPU_HIGH_FREQUENCY", + "ANOMALY_CPU_ENERGY", + "ANOMALY_WAKEUP"}; + const uint64_t MSEC_TO_NS = 1000 * 1000; + std::vector hisyseventTS_; + bool isDeviceState = true; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HTRACE_HISYSEVENT_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_js_memory_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_js_memory_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9fb6ebe075c6b04783dcde35171e06485a6ab9d6 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_js_memory_parser.cpp @@ -0,0 +1,560 @@ +/* + * 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 +#include +#include +#include "htrace_js_memory_parser.h" +#include "clock_filter.h" +#include "fcntl.h" +#include "file.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "unistd.h" +namespace SysTuning { +namespace TraceStreamer { +namespace jsonns { +const int32_t OFFSET_FIRST = 1; +const int32_t OFFSET_SECOND = 2; +const int32_t OFFSET_THIRD = 3; +const int32_t OFFSET_FOURTH = 4; +const int32_t OFFSET_FIFTH = 5; +const int32_t OFFSET_SIXTH = 6; +struct Meta { + std::vector nodeFields; + std::vector> nodeTypes; + std::vector edgeFields; + std::vector> edgeTypes; + std::vector traceFunctionInfoFields; + std::vector traceNodeFields; + std::vector sampleFields; + std::vector locationFields; +}; +struct Snapshot { + Meta meta; + int32_t nodeCount; + int32_t edgeCount; + int32_t traceFunctionCount; +}; +void from_json(const json& j, Meta& v) +{ + for (int32_t i = 0; i < j["node_fields"].size(); i++) { + v.nodeFields.emplace_back(j["node_fields"][i]); + } + for (int32_t i = 0; i < j["node_types"].size(); i++) { + std::vector nodeTypes; + if (j["node_types"][i].is_array()) { + for (int32_t m = 0; m < j["node_types"][i].size(); m++) { + nodeTypes.emplace_back(j["node_types"][i][m]); + } + v.nodeTypes.emplace_back(nodeTypes); + } else { + nodeTypes.emplace_back(j["node_types"][i]); + v.nodeTypes.emplace_back(nodeTypes); + } + } + for (int32_t i = 0; i < j["edge_fields"].size(); i++) { + v.edgeFields.emplace_back(j["edge_fields"][i]); + } + for (int32_t i = 0; i < j["edge_types"].size(); i++) { + std::vector edgeTypes; + if (j["edge_types"][i].is_array()) { + for (int32_t m = 0; m < j["edge_types"][i].size(); m++) { + edgeTypes.emplace_back(j["edge_types"][i][m]); + } + v.edgeTypes.emplace_back(edgeTypes); + } else { + edgeTypes.emplace_back(j["edge_types"][i]); + v.edgeTypes.emplace_back(edgeTypes); + } + } + for (int32_t i = 0; i < j["trace_function_info_fields"].size(); i++) { + v.traceFunctionInfoFields.emplace_back(j["trace_function_info_fields"][i]); + } + for (int32_t i = 0; i < j["trace_node_fields"].size(); i++) { + v.traceNodeFields.emplace_back(j["trace_node_fields"][i]); + } + for (int32_t i = 0; i < j["sample_fields"].size(); i++) { + v.sampleFields.emplace_back(j["sample_fields"][i]); + } + for (int32_t i = 0; i < j["location_fields"].size(); i++) { + v.locationFields.emplace_back(j["location_fields"][i]); + } + return; +} + +void from_json(const json& j, Snapshot& v) +{ + j.at("meta").get_to(v.meta); + j.at("node_count").get_to(v.nodeCount); + j.at("edge_count").get_to(v.edgeCount); + j.at("trace_function_count").get_to(v.traceFunctionCount); + return; +} + +struct Nodes { + std::vector types; + std::vector names; + std::vector ids; + std::vector selfSizes; + std::vector edgeCounts; + std::vector traceNodeIds; + std::vector detachedness; +}; +const int32_t NODES_SINGLE_LENGTH = 7; +std::vector g_fromNodeIds; +std::vector g_ids; +void from_json(const json& j, Nodes& v) +{ + int32_t edgeIndex = 0; + for (int32_t i = 0; i < j.size() / NODES_SINGLE_LENGTH; i++) { + v.types.emplace_back(j[i * NODES_SINGLE_LENGTH]); + v.names.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_FIRST]); + v.ids.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_SECOND]); + v.selfSizes.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_THIRD]); + v.edgeCounts.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_FOURTH]); + for (int32_t m = edgeIndex; m < edgeIndex + v.edgeCounts.at(i); m++) { + g_fromNodeIds.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_SECOND]); + } + edgeIndex += v.edgeCounts.at(i); + v.traceNodeIds.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_FIFTH]); + v.detachedness.emplace_back(j[i * NODES_SINGLE_LENGTH + OFFSET_SIXTH]); + } + for (int32_t m = 0; m < j.size(); m++) { + g_ids.emplace_back(j[m]); + } +} + +struct Edges { + std::vector types; + std::vector nameOrIndexes; + std::vector toNodes; + std::vector fromNodeIds; + std::vector toNodeIds; +}; +const int32_t EDGES_SINGLE_LENGTH = 3; +void from_json(const json& j, Edges& v) +{ + v.fromNodeIds = g_fromNodeIds; + for (int32_t i = 0; i < j.size() / EDGES_SINGLE_LENGTH; i++) { + v.types.emplace_back(j[i * EDGES_SINGLE_LENGTH]); + v.nameOrIndexes.emplace_back(j[i * EDGES_SINGLE_LENGTH + OFFSET_FIRST]); + v.toNodes.emplace_back(j[i * EDGES_SINGLE_LENGTH + OFFSET_SECOND]); + v.toNodeIds.emplace_back(g_ids[v.toNodes[i] + OFFSET_SECOND]); + } + return; +} + +struct Location { + std::vector objectIndexes; + std::vector scriptIds; + std::vector lines; + std::vector columns; +}; +const int32_t LOCATION_SINGLE_LENGTH = 4; +void from_json(const json& j, Location& v) +{ + for (int32_t i = 0; i < j.size() / LOCATION_SINGLE_LENGTH; i++) { + v.objectIndexes.emplace_back(j[i * LOCATION_SINGLE_LENGTH]); + v.scriptIds.emplace_back(j[i * LOCATION_SINGLE_LENGTH + OFFSET_FIRST]); + v.lines.emplace_back(j[i * LOCATION_SINGLE_LENGTH + OFFSET_SECOND]); + v.columns.emplace_back(j[i * LOCATION_SINGLE_LENGTH + OFFSET_THIRD]); + } +} + +struct Sample { + std::vector timestampUs; + std::vector lastAssignedIds; +}; +const int32_t SAMPLE_SINGLE_LENGTH = 2; +void from_json(const json& j, Sample& v) +{ + for (int32_t i = 0; i < j.size() / SAMPLE_SINGLE_LENGTH; i++) { + v.timestampUs.emplace_back(j[i * SAMPLE_SINGLE_LENGTH]); + v.lastAssignedIds.emplace_back(j[i * SAMPLE_SINGLE_LENGTH + OFFSET_FIRST]); + } +} + +struct Strings { + std::vector strings; +}; +void from_json(const json& j, Strings& v) +{ + for (int32_t i = 0; i < j.size(); i++) { + v.strings.emplace_back(j[i]); + } +} + +struct TraceFuncInfo { + std::vector functionIds; + std::vector names; + std::vector scriptNames; + std::vector scriptIds; + std::vector lines; + std::vector columns; +}; +const int32_t TRACE_FUNC_INFO_SINGLE_LENGTH = 6; +void from_json(const json& j, TraceFuncInfo& v) +{ + for (int32_t i = 0; i < j.size() / TRACE_FUNC_INFO_SINGLE_LENGTH; i++) { + v.functionIds.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH]); + v.names.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_FIRST]); + v.scriptNames.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_SECOND]); + v.scriptIds.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_THIRD]); + v.lines.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_FOURTH]); + v.columns.emplace_back(j[i * TRACE_FUNC_INFO_SINGLE_LENGTH + OFFSET_FIFTH]); + } +} + +struct TraceTree { + std::vector ids; + std::vector functionInfoIndexes; + std::vector counts; + std::vector sizes; + std::vector parentIds; +}; + +struct ParentFunc { + uint32_t id; + uint32_t functionInfoIndex; + uint32_t count; + uint32_t size; + std::vector> children; + ParentFunc* parent = nullptr; + ParentFunc() + { + id = 0; + functionInfoIndex = 0; + count = 0; + size = 0; + } +}; + +class TraceParser { +public: + void parse_trace_node(const json& array, + std::vector>& funcList, + ParentFunc* parent = nullptr) + { + int32_t singleLength = 5; + int32_t functionCount = array.size() / singleLength; + for (int32_t i = 0; i < functionCount; ++i) { + auto item = std::make_unique(); + if (parent != nullptr) { + item->parent = parent; + } + item->id = array[i * singleLength]; + item->functionInfoIndex = array[i * singleLength + OFFSET_FIRST]; + item->count = array[i * singleLength + OFFSET_SECOND]; + item->size = array[i * singleLength + OFFSET_THIRD]; + auto childrenArray = array[i * singleLength + OFFSET_FOURTH]; + funcList.push_back(std::move(item)); + if (!childrenArray.empty()) { + parse_trace_node(childrenArray, funcList, funcList.back().get()); + } + } + } +}; +void from_json(const json& j, TraceTree& v) +{ + std::vector> funcList; + TraceParser parser; + parser.parse_trace_node(j, funcList); + for (auto& func : funcList) { + v.ids.emplace_back(func->id); + v.functionInfoIndexes.emplace_back(func->functionInfoIndex); + v.counts.emplace_back(func->count); + v.sizes.emplace_back(func->size); + v.parentIds.emplace_back(func->parent ? func->parent->id : std::numeric_limits::max()); + } +} +} // namespace jsonns + +const int32_t END_POS = 3; +const int32_t CHUNK_POS = 8; + +HtraceJSMemoryParser::HtraceJSMemoryParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ + DIR* dir = opendir("."); + if (dir != nullptr) { + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + std::string filename(entry->d_name); + if (filename.find(tmpJsMemorySnapshotData_) != string::npos) { + (void)std::remove(filename.c_str()); + } + } + closedir(dir); + } +} + +HtraceJSMemoryParser::~HtraceJSMemoryParser() +{ + TS_LOGI("JS memory ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} + +void HtraceJSMemoryParser::ParseJSMemoryConfig(ProtoReader::BytesView tracePacket) +{ + ProtoReader::JsHeapConfig_Reader jsHeapConfig(tracePacket.data_, tracePacket.size_); + type_ = jsHeapConfig.type(); + pid_ = jsHeapConfig.pid(); +} + +void HtraceJSMemoryParser::Parse(ProtoReader::BytesView tracePacket, uint64_t ts) +{ + ProtoReader::JsHeapResult_Reader jsHeapResult(tracePacket.data_, tracePacket.size_); + auto result = jsHeapResult.result().ToStdString(); + std::string fileName = ""; + if (result == snapshotEnd_ || result == timeLineEnd_) { + std::regex strEscapeInvalid("\\\\n"); + std::regex strInvalid("\\\\\""); + auto strEscape = std::regex_replace(jsMemoryString_, strEscapeInvalid, ""); + auto str = std::regex_replace(strEscape, strInvalid, "\""); + if (type_ == ProtoReader::JsHeapConfig_HeapType::JsHeapConfig_HeapType_SNAPSHOT) { + fileName = "Snapshot" + std::to_string(fileId_); + ParseSnapshot(fileId_, str); + jsMemoryString_ = ""; + } else if (type_ == ProtoReader::JsHeapConfig_HeapType::JsHeapConfig_HeapType_TIMELINE) { + if (result == snapshotEnd_) { + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts); + startTime_ = ts; + return; + } + fileName = "Timeline"; + ParseTimeLine(fileId_, str); + jsMemoryString_ = ""; + } + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts); + (void)traceDataCache_->GetJsHeapFilesData()->AppendNewData(fileId_, fileName, startTime_, ts, pid_); + fileId_++; + isFirst_ = true; + return; + } + auto pos = result.find("chunk"); + if (pos != string::npos) { + if (isFirst_ && type_ == ProtoReader::JsHeapConfig_HeapType::JsHeapConfig_HeapType_SNAPSHOT) { + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, ts, ts); + startTime_ = ts; + isFirst_ = false; + } + auto resultJson = result.substr(pos + CHUNK_POS, result.size() - pos - CHUNK_POS - END_POS); + jsMemoryString_ += resultJson; + } +} + +void HtraceJSMemoryParser::ParseTimeLine(int32_t fileId, const std::string& jsonString) +{ + if (enableFileSave_) { + (void)write(jsFileId_, jsonString.data(), jsonString.size()); + } + json jMessage = json::parse(jsonString); + ParserJSSnapInfo(fileId, jMessage); + ParseNodes(fileId, jMessage); + ParseEdges(fileId, jMessage); + ParseLocation(fileId, jMessage); + ParseSample(fileId, jMessage); + ParseString(fileId, jMessage); + ParseTraceFuncInfo(fileId, jMessage); + ParseTraceNode(fileId, jMessage); + streamFilters_->statFilter_->IncreaseStat(TRACE_JS_MEMORY, STAT_EVENT_RECEIVED); + return; +} +void HtraceJSMemoryParser::ParserSnapInfo(int32_t fileId, + const std::string& key, + const std::vector>& types) +{ + for (int32_t m = 0; m < types[0].size(); ++m) { + (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, key, 0, std::numeric_limits::max(), + types[0][m]); + } + for (int32_t i = 1; i < types.size(); ++i) { + (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, key, 1, std::numeric_limits::max(), + types[i][0]); + } + return; +} + +const std::string NODE_TYPES = "node_types"; +const std::string EDGE_TYPES = "edge_types"; +void HtraceJSMemoryParser::ParserJSSnapInfo(int32_t fileId, const json& jMessage) +{ + jsonns::Snapshot snapshot = jMessage.at("snapshot"); + ParserSnapInfo(fileId, NODE_TYPES, snapshot.meta.nodeTypes); + ParserSnapInfo(fileId, EDGE_TYPES, snapshot.meta.edgeTypes); + auto nodeCount = snapshot.nodeCount; + auto edgeCount = snapshot.edgeCount; + auto traceFuncCount = snapshot.traceFunctionCount; + (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, "node_count", 0, nodeCount, ""); + (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, "edge_count", 0, edgeCount, ""); + (void)traceDataCache_->GetJsHeapInfoData()->AppendNewData(fileId, "trace_function_count", 0, traceFuncCount, ""); + return; +} + +void HtraceJSMemoryParser::ParseNodes(int32_t fileId, const json& jMessage) +{ + jsonns::Nodes node = jMessage.at("nodes"); + for (int32_t i = 0; i < node.names.size(); ++i) { + auto type = node.types[i]; + auto name = node.names[i]; + auto id = node.ids[i]; + auto selfSize = node.selfSizes[i]; + auto edgeCount = node.edgeCounts[i]; + auto traceNodeId = node.traceNodeIds[i]; + auto detachedness = node.detachedness[i]; + (void)traceDataCache_->GetJsHeapNodesData()->AppendNewData(fileId, i, type, name, id, selfSize, edgeCount, + traceNodeId, detachedness); + } + return; +} + +void HtraceJSMemoryParser::ParseEdges(int32_t fileId, const json& jMessage) +{ + jsonns::Edges edge = jMessage.at("edges"); + for (int32_t i = 0; i < edge.types.size(); ++i) { + auto type = edge.types[i]; + auto nameOrIndex = edge.nameOrIndexes[i]; + auto toNode = edge.toNodes[i]; + auto fromNodeId = edge.fromNodeIds[i]; + auto toNodeid = edge.toNodeIds[i]; + (void)traceDataCache_->GetJsHeapEdgesData()->AppendNewData(fileId, i, type, nameOrIndex, toNode, fromNodeId, + toNodeid); + } + return; +} + +void HtraceJSMemoryParser::ParseLocation(int32_t fileId, const json& jMessage) +{ + jsonns::Location location = jMessage.at("locations"); + for (int32_t i = 0; i < location.columns.size(); ++i) { + auto objectIndex = location.objectIndexes[i]; + auto scriptId = location.scriptIds[i]; + auto line = location.lines[i]; + auto column = location.columns[i]; + (void)traceDataCache_->GetJsHeapLocationData()->AppendNewData(fileId, objectIndex, scriptId, line, column); + } + return; +} +void HtraceJSMemoryParser::ParseSample(int32_t fileId, const json& jMessage) +{ + jsonns::Sample sample = jMessage.at("samples"); + for (int32_t i = 0; i < sample.timestampUs.size(); ++i) { + auto timestampUs = sample.timestampUs[i]; + auto lastAssignedId = sample.lastAssignedIds[i]; + (void)traceDataCache_->GetJsHeapSampleData()->AppendNewData(fileId, timestampUs, lastAssignedId); + } + return; +} +void HtraceJSMemoryParser::ParseString(int32_t fileId, const json& jMessage) +{ + jsonns::Strings string = jMessage.at("strings"); + for (int32_t i = 0; i < string.strings.size(); ++i) { + (void)traceDataCache_->GetJsHeapStringData()->AppendNewData(fileId, i, string.strings[i]); + } + return; +} +void HtraceJSMemoryParser::ParseTraceFuncInfo(int32_t fileId, const json& jMessage) +{ + jsonns::TraceFuncInfo traceFuncInfo = jMessage.at("trace_function_infos"); + for (int32_t i = 0; i < traceFuncInfo.functionIds.size(); ++i) { + auto functionId = traceFuncInfo.functionIds[i]; + auto name = traceFuncInfo.names[i]; + auto scriptName = traceFuncInfo.scriptNames[i]; + auto scriptId = traceFuncInfo.scriptIds[i]; + auto line = traceFuncInfo.lines[i]; + auto column = traceFuncInfo.columns[i]; + (void)traceDataCache_->GetJsHeapTraceFuncInfoData()->AppendNewData(fileId, i, functionId, name, scriptName, + scriptId, line, column); + } + return; +} +void HtraceJSMemoryParser::ParseTraceNode(int32_t fileId, const json& jMessage) +{ + jsonns::TraceTree traceTree = jMessage.at("trace_tree"); + for (int32_t i = 0; i < traceTree.ids.size(); ++i) { + auto id = traceTree.ids[i]; + auto funcInfoIndex = traceTree.functionInfoIndexes[i]; + auto count = traceTree.counts[i]; + auto size = traceTree.sizes[i]; + auto parentId = traceTree.parentIds[i]; + (void)traceDataCache_->GetJsHeapTraceNodeData()->AppendNewData(fileId, id, funcInfoIndex, count, size, + parentId); + } + return; +} +void HtraceJSMemoryParser::ParseSnapshot(int32_t fileId, const std::string& jsonString) +{ + if (enableFileSave_) { + if (jsFileId_) { + close(jsFileId_); + jsFileId_ = 0; + if (access(tmpJsMemoryTimelineData_.c_str(), F_OK) == 0) { + (void)remove(tmpJsMemoryTimelineData_.c_str()); + } + } + jsFileId_ = base::OpenFile(tmpJsMemorySnapshotData_ + "_" + base::number(fileId) + jsSnapshotFileTail, + O_CREAT | O_RDWR, TS_PERMISSION_RW); + if (!jsFileId_) { + fprintf(stdout, "Failed to create file: %s", jsSnapshotFileTail.c_str()); + exit(-1); + } + (void)ftruncate(jsFileId_, 0); + (void)write(jsFileId_, jsonString.data(), jsonString.size()); + close(jsFileId_); + jsFileId_ = 0; + } + json jMessage = json::parse(jsonString); + ParserJSSnapInfo(fileId, jMessage); + ParseNodes(fileId, jMessage); + ParseEdges(fileId, jMessage); + ParseLocation(fileId, jMessage); + ParseSample(fileId, jMessage); + ParseString(fileId, jMessage); + ParseTraceFuncInfo(fileId, jMessage); + ParseTraceNode(fileId, jMessage); + streamFilters_->statFilter_->IncreaseStat(TRACE_JS_MEMORY, STAT_EVENT_RECEIVED); + return; +} +void HtraceJSMemoryParser::EnableSaveFile(bool enable) +{ + enableFileSave_ = enable; + if (enable) { + jsFileId_ = base::OpenFile(tmpJsMemoryTimelineData_, O_CREAT | O_RDWR, TS_PERMISSION_RW); + if (!jsFileId_) { + fprintf(stdout, "Failed to create file: %s", tmpJsMemoryTimelineData_.c_str()); + exit(-1); + } + (void)ftruncate(jsFileId_, 0); + } else { + if (jsFileId_) { + close(jsFileId_); + jsFileId_ = 0; + } + if (access(tmpJsMemoryTimelineData_.c_str(), F_OK) == 0) { + (void)remove(tmpJsMemoryTimelineData_.c_str()); + } + } +} +void HtraceJSMemoryParser::Finish() +{ + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + return; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_js_memory_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_js_memory_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..5cb55726c3fe09d1de1164e674a2043b6ea4548b --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_js_memory_parser.h @@ -0,0 +1,68 @@ +/* + * 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 HTRACE_JS_MEMORY_PARSER_H +#define HTRACE_JS_MEMORY_PARSER_H +#include +#include +#include +#include "common_types.h" +#include "htrace_plugin_time_parser.h" +#include "json.hpp" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +using json = nlohmann::json; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceJSMemoryParser : public HtracePluginTimeParser { +public: + HtraceJSMemoryParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceJSMemoryParser(); + void ParseJSMemoryConfig(ProtoReader::BytesView tracePacket); + void Parse(ProtoReader::BytesView tracePacket, uint64_t ts); + void EnableSaveFile(bool enable); + void Finish(); + +private: + void ParseTimeLine(int32_t fileId, const std::string& jsonString); + void ParseSnapshot(int32_t fileId, const std::string& jsonString); + void ParserJSSnapInfo(int32_t fileId, const json& jMessage); + void ParseNodes(int32_t fileId, const json& jMessage); + void ParseEdges(int32_t fileId, const json& jMessage); + void ParseLocation(int32_t fileId, const json& jMessage); + void ParseSample(int32_t fileId, const json& jMessage); + void ParseString(int32_t fileId, const json& jMessage); + void ParseTraceFuncInfo(int32_t fileId, const json& jMessage); + void ParseTraceNode(int32_t fileId, const json& jMessage); + void ParserSnapInfo(int32_t fileId, const std::string& key, const std::vector>& types); + int32_t type_ = 0; + int32_t pid_ = 0; + const std::string snapshotEnd_ = "{\"id\":1,\"result\":{}}"; + const std::string timeLineEnd_ = "{\"id\":2,\"result\":{}}"; + uint64_t startTime_ = std::numeric_limits::max(); + bool isFirst_ = true; + std::string jsMemoryString_ = ""; + int32_t fileId_ = 0; + int32_t jsFileId_ = 0; + std::list fileIds_ = {}; + bool enableFileSave_ = false; + const std::string tmpJsMemoryTimelineData_ = "ts_tmp.jsmemory_timeline.heapsnapshot"; + const std::string tmpJsMemorySnapshotData_ = "ts_tmp.jsmemory_snapshot"; + const std::string jsSnapshotFileTail = ".heapsnapshot"; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_JS_MEMORY_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_mem_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_mem_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02928a777160a7ffd435406b0c3b6ee041ab1935 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_mem_parser.cpp @@ -0,0 +1,905 @@ +/* + * 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 "htrace_mem_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +#include "system_event_measure_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceMemParser::HtraceMemParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ + for (auto i = 0; i < MEM_MAX; i++) { + memNameDictMap_.insert( + std::make_pair(static_cast(i), + traceDataCache_->GetDataIndex(config_.memNameMap_.at(static_cast(i))))); + } + for (auto i = 0; i < SysMeminfoType::PMEM_KERNEL_RECLAIMABLE + 1; i++) { + sysMemNameDictMap_.insert( + std::make_pair(static_cast(i), + traceDataCache_->GetDataIndex(config_.sysMemNameMap_.at(static_cast(i))))); + } + for (auto i = 0; i < SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE + 1; i++) { + sysVMemNameDictMap_.insert(std::make_pair( + static_cast(i), + traceDataCache_->GetDataIndex(config_.sysVirtualMemNameMap_.at(static_cast(i))))); + } +} + +HtraceMemParser::~HtraceMemParser() +{ + TS_LOGI("mem ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} +void HtraceMemParser::Parse(HtraceDataSegment& seg, uint64_t timeStamp, BuiltinClocks clock) +{ + ProtoReader::MemoryData_Reader memData(seg.protoData.data_, seg.protoData.size_); + auto newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(clock, timeStamp); + UpdatePluginTimeRange(clock, timeStamp, newTimeStamp); + zram_ = memData.zram(); + if (memData.has_processesinfo()) { + ParseProcessInfo(&memData, newTimeStamp); + } + if (memData.has_meminfo()) { + ParseMemInfo(&memData, newTimeStamp); + } + if (memData.has_vmeminfo()) { + ParseVMemInfo(&memData, newTimeStamp); + } +} +void HtraceMemParser::ParseProcessInfo(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const +{ + if (tracePacket->has_processesinfo()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_MEMORY, STAT_EVENT_RECEIVED); + } + for (auto i = tracePacket->processesinfo(); i; ++i) { + ProtoReader::ProcessMemoryInfo_Reader processMemoryInfo(i->ToBytes().data_, i->ToBytes().size_); + auto ipid = streamFilters_->processFilter_->UpdateOrCreateProcessWithName( + processMemoryInfo.pid(), processMemoryInfo.name().ToStdString()); + uint32_t hasValue = 0; + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_VM_SIZE), timeStamp, processMemoryInfo.vm_size_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_VM_RSS), timeStamp, processMemoryInfo.vm_rss_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_VM_ANON), timeStamp, processMemoryInfo.rss_anon_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_RSS_FILE), timeStamp, processMemoryInfo.rss_file_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_RSS_SHMEM), timeStamp, processMemoryInfo.rss_shmem_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_VM_SWAP), timeStamp, processMemoryInfo.vm_swap_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_VM_LOCKED), timeStamp, processMemoryInfo.vm_locked_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_VM_HWM), timeStamp, processMemoryInfo.vm_hwm_kb()); + hasValue += streamFilters_->processMeasureFilter_->AppendNewMeasureData( + ipid, memNameDictMap_.at(MEM_OOM_SCORE_ADJ), timeStamp, processMemoryInfo.oom_score_adj()); + if (hasValue) { + streamFilters_->processFilter_->AddProcessMemory(ipid); + } + if (processMemoryInfo.has_smapinfo()) { + ParseSmapsInfoEasy(&processMemoryInfo, timeStamp); + } + } +} + +void HtraceMemParser::ParseSmapsInfoEasy(const ProtoReader::ProcessMemoryInfo_Reader* memInfo, uint64_t timeStamp) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_SMAPS, STAT_EVENT_RECEIVED); + for (auto i = memInfo->smapinfo(); i; ++i) { + ProtoReader::SmapsInfo_Reader smapsInfo(i->ToBytes().data_, i->ToBytes().size_); + auto startAddr = "0x" + smapsInfo.start_addr().ToStdString(); + auto endAddr = "0x" + smapsInfo.end_addr().ToStdString(); + uint64_t dirty = smapsInfo.dirty(); + uint64_t swapper = smapsInfo.swapper(); + uint64_t rss = smapsInfo.rss(); + uint64_t pss = smapsInfo.pss(); + uint64_t size = smapsInfo.size(); + double reside = smapsInfo.reside(); + DataIndex protection = traceDataCache_->GetDataIndex(smapsInfo.permission().ToStdString()); + DataIndex path = traceDataCache_->GetDataIndex(smapsInfo.path().ToStdString()); + traceDataCache_->GetSmapsData()->AppendNewData(timeStamp, startAddr, endAddr, dirty, swapper, rss, pss, size, + reside, protection, path); + } +} + +void HtraceMemParser::ParseMemInfoEasy(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const +{ + if (tracePacket->has_meminfo()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + } + for (auto i = tracePacket->meminfo(); i; ++i) { + ProtoReader::SysMeminfo_Reader sysMeminfo(i->ToBytes()); + if (config_.sysMemNameMap_.find(SysMeminfoType(sysMeminfo.key())) != config_.sysMemNameMap_.end()) { + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType(sysMeminfo.key())), timeStamp, sysMeminfo.value()); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_DATA_INVALID); + } + } +} + +void HtraceMemParser::ParseVMemInfoEasy(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const +{ + traceDataCache_->UpdateTraceTime(timeStamp); + if (tracePacket->has_vmeminfo()) { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + } + for (auto i = tracePacket->vmeminfo(); i; ++i) { + ProtoReader::SysVMeminfo_Reader sysVMeminfo(i->ToBytes()); + if (config_.sysVirtualMemNameMap_.find(SysVMeminfoType(sysVMeminfo.key())) != + config_.sysVirtualMemNameMap_.end()) { + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType(sysVMeminfo.key())), timeStamp, sysVMeminfo.value()); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_DATA_INVALID); + } + } +} + +void HtraceMemParser::ParseMemInfo(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + for (auto i = tracePacket->meminfo(); i; ++i) { + ProtoReader::SysMeminfo_Reader sysMeminfo(i->ToBytes()); + switch (sysMeminfo.key()) { + case SysMeminfoType::PMEM_UNSPECIFIED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_UNSPECIFIED), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_MEM_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MEM_TOTAL), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_MEM_FREE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MEM_FREE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_MEM_AVAILABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MEM_AVAILABLE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_BUFFERS: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_BUFFERS), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_CACHED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_CACHED), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SWAP_CACHED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SWAP_CACHED), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_ACTIVE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ACTIVE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_INACTIVE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_INACTIVE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_ACTIVE_ANON: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ACTIVE_ANON), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_INACTIVE_ANON: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_INACTIVE_ANON), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_ACTIVE_FILE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ACTIVE_FILE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_INACTIVE_FILE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_INACTIVE_FILE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_UNEVICTABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_UNEVICTABLE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_MLOCKED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MLOCKED), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SWAP_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SWAP_TOTAL), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SWAP_FREE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SWAP_FREE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_DIRTY: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_DIRTY), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_WRITEBACK: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_WRITEBACK), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_ANON_PAGES: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_ANON_PAGES), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_MAPPED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_MAPPED), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SHMEM: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SHMEM), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SLAB: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SLAB), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SLAB_RECLAIMABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SLAB_RECLAIMABLE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_KERNEL_STACK: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_KERNEL_STACK), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_PAGE_TABLES: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_PAGE_TABLES), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_COMMIT_LIMIT: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_COMMIT_LIMIT), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_COMMITED_AS: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_COMMITED_AS), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_VMALLOC_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_VMALLOC_TOTAL), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_VMALLOC_USED: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_VMALLOC_USED), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_VMALLOC_CHUNK: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_VMALLOC_CHUNK), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_CMA_TOTAL: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_CMA_TOTAL), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_CMA_FREE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_CMA_FREE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType::PMEM_KERNEL_RECLAIMABLE: + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData( + sysMemNameDictMap_.at(SysMeminfoType::PMEM_KERNEL_RECLAIMABLE), timeStamp, sysMeminfo.value()); + break; + case SysMeminfoType_INT_MIN_SENTINEL_DO_NOT_USE_: + case SysMeminfoType_INT_MAX_SENTINEL_DO_NOT_USE_: + default: + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_MEMORY, STAT_EVENT_DATA_INVALID); + break; + } + } + streamFilters_->sysEventMemMeasureFilter_->AppendNewMeasureData(zramIndex_, timeStamp, zram_); +} +void HtraceMemParser::ParseVMemInfo(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + for (auto i = tracePacket->vmeminfo(); i; ++i) { + ProtoReader::SysVMeminfo_Reader sysVMeminfo(i->ToBytes()); + switch (sysVMeminfo.key()) { + case SysVMeminfoType::VMEMINFO_UNSPECIFIED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNSPECIFIED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FREE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FREE_PAGES), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ALLOC_BATCH: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ALLOC_BATCH), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_INACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_INACTIVE_ANON), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ACTIVE_ANON), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_INACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_INACTIVE_FILE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ACTIVE_FILE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_UNEVICTABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_UNEVICTABLE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_MLOCK: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_MLOCK), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ANON_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ANON_PAGES), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_MAPPED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_MAPPED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FILE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FILE_PAGES), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTY: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTY), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_WRITEBACK: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_WRITEBACK), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SLAB_RECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SLAB_RECLAIMABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SLAB_UNRECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SLAB_UNRECLAIMABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_PAGE_TABLE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_PAGE_TABLE_PAGES), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_KERNEL_STACK: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_KERNEL_STACK), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_OVERHEAD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_OVERHEAD), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_UNSTABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_UNSTABLE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_BOUNCE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_BOUNCE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_VMSCAN_WRITE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_VMSCAN_WRITE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_WRITEBACK_TEMP: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_WRITEBACK_TEMP), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ISOLATED_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ISOLATED_ANON), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ISOLATED_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ISOLATED_FILE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHMEM: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHMEM), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTIED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTIED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_WRITTEN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_WRITTEN), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_PAGES_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_PAGES_SCANNED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_REFAULT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_REFAULT), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_ACTIVATE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_ACTIVATE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_NODERECLAIM: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_NODERECLAIM), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FREE_CMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FREE_CMA), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SWAPCACHE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SWAPCACHE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTY_THRESHOLD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTY_THRESHOLD), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGPGIN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGPGIN), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGPGOUT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGPGOUT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGPGOUTCLEAN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGPGOUTCLEAN), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PSWPIN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PSWPIN), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PSWPOUT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PSWPOUT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGALLOC_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGALLOC_DMA), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGALLOC_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGALLOC_NORMAL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGALLOC_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGALLOC_MOVABLE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGFREE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGFREE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGACTIVATE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGACTIVATE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGDEACTIVATE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGDEACTIVATE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGFAULT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGFAULT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGMAJFAULT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGMAJFAULT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL_DMA), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL_NORMAL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL_MOVABLE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_DMA), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_NORMAL), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD_MOVABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_DMA), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_NORMAL), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT_MOVABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_DMA), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_NORMAL), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD_MOVABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_DMA), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_NORMAL), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_MOVABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_THROTTLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT_THROTTLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGINODESTEAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGINODESTEAL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_SLABS_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_SLABS_SCANNED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_KSWAPD_INODESTEAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_KSWAPD_INODESTEAL), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PAGEOUTRUN: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PAGEOUTRUN), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGROTATED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGROTATED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_DROP_PAGECACHE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_DROP_PAGECACHE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_DROP_SLAB: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_DROP_SLAB), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGMIGRATE_SUCCESS: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGMIGRATE_SUCCESS), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGMIGRATE_FAIL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGMIGRATE_FAIL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_MIGRATE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_MIGRATE_SCANNED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_FREE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_FREE_SCANNED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_ISOLATED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_ISOLATED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_STALL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_STALL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_FAIL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_FAIL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_SUCCESS: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_SUCCESS), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_WAKE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_WAKE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CULLED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CULLED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_SCANNED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_RESCUED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_RESCUED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MLOCKED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MLOCKED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CLEARED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_CLEARED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_STRANDED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_UNEVICTABLE_PGS_STRANDED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZSPAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZSPAGES), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ION_HEAP: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ION_HEAP), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_GPU_HEAP: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_GPU_HEAP), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL_DMA), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL_MOVABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_ALLOCSTALL_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_ALLOCSTALL_NORMAL), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_FREE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_FREE_SCANNED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_FASTRPC: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_FASTRPC), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_INDIRECTLY_RECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_INDIRECTLY_RECLAIMABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ION_HEAP_POOL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ION_HEAP_POOL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHADOW_CALL_STACK_BYTES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHADOW_CALL_STACK_BYTES), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHMEM_HUGEPAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHMEM_HUGEPAGES), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_SHMEM_PMDMAPPED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_SHMEM_PMDMAPPED), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_UNRECLAIMABLE_PAGES: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_UNRECLAIMABLE_PAGES), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_ANON), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_ACTIVE_FILE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_ANON: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_ANON), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_FILE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_INACTIVE_FILE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_UNEVICTABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_UNEVICTABLE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_NR_ZONE_WRITE_PENDING: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_NR_ZONE_WRITE_PENDING), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_OOM_KILL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_OOM_KILL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGLAZYFREE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGLAZYFREE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGLAZYFREED: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGLAZYFREED), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGREFILL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGREFILL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_DIRECT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSCAN_KSWAPD), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSKIP_DMA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSKIP_DMA), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSKIP_MOVABLE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSKIP_MOVABLE), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSKIP_NORMAL: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSKIP_NORMAL), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_DIRECT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_PGSTEAL_KSWAPD), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_SWAP_RA: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_SWAP_RA), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_SWAP_RA_HIT: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_SWAP_RA_HIT), timeStamp, sysVMeminfo.value()); + break; + case SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE: + streamFilters_->sysEventVMemMeasureFilter_->AppendNewMeasureData( + sysVMemNameDictMap_.at(SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE), timeStamp, + sysVMeminfo.value()); + break; + case SysVMeminfoType_INT_MIN_SENTINEL_DO_NOT_USE_: + case SysVMeminfoType_INT_MAX_SENTINEL_DO_NOT_USE_: + default: + streamFilters_->statFilter_->IncreaseStat(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_DATA_INVALID); + } + } +} +void HtraceMemParser::Finish() +{ + if (traceDataCache_->traceStartTime_ == INVALID_UINT64 || traceDataCache_->traceEndTime_ == 0) { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + } else { + TS_LOGI("mem data time is not updated, maybe this trace file has other data"); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_mem_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_mem_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..fdfedf666f7d22683a3266bc7931174cc3deee8a --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_mem_parser.h @@ -0,0 +1,55 @@ +/* + * 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 HTRACE_MEM_PARSER_H +#define HTRACE_MEM_PARSER_H + +#include +#include +#include +#include +#include +#include "common_types.h" +#include "htrace_plugin_time_parser.h" +#include "memory_plugin_result.pbreader.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceMemParser : public HtracePluginTimeParser { +public: + HtraceMemParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceMemParser(); + void Parse(HtraceDataSegment& seg, uint64_t, BuiltinClocks clock); + void Finish(); + +private: + void ParseProcessInfo(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const; + void ParseMemInfo(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const; + void ParseMemInfoEasy(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const; + void ParseVMemInfo(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const; + void ParseVMemInfoEasy(const ProtoReader::MemoryData_Reader* tracePacket, uint64_t timeStamp) const; + void ParseSmapsInfoEasy(const ProtoReader::ProcessMemoryInfo_Reader* memInfo, uint64_t timeStamp) const; + std::map memNameDictMap_ = {}; + std::map sysMemNameDictMap_ = {}; + std::map sysVMemNameDictMap_ = {}; + uint64_t zram_ = 0; + const DataIndex zramIndex_ = traceDataCache_->GetDataIndex("sys.mem.zram"); + TraceStreamerConfig config_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_MEM_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_native_hook_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_native_hook_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71c97541452b1847ee9d6f40227e51376a4f75e1 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_native_hook_parser.cpp @@ -0,0 +1,164 @@ +/* + * 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 "htrace_native_hook_parser.h" +#include "clock_filter.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceNativeHookParser::HtraceNativeHookParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx), nativeHookFilter_(std::make_unique(dataCache, ctx)) +{ +} + +HtraceNativeHookParser::~HtraceNativeHookParser() +{ + TS_LOGI("native hook data ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); + TS_LOGI("native real ts MIN:%llu, MAX:%llu", static_cast(MinTs()), + static_cast(MaxTs())); +} + +void HtraceNativeHookParser::ParseStackMap(const ProtoReader::BytesView& bytesView) +{ + ProtoReader::StackMap_Reader stackMapReader(bytesView); + auto stackId = stackMapReader.id(); + bool parseError = false; + // stores frames info. if offlineSymbolization is true, storing ips data, else storing FrameMap id. + std::vector frames; + if (stackMapReader.has_frame_map_id()) { + auto itor = stackMapReader.frame_map_id(&parseError); + if (parseError) { + TS_LOGE("Parse packed varInt in ParseStackMap function failed!!!"); + return; + } + while (itor) { + frames.emplace_back(*itor); + itor++; + } + } else if (stackMapReader.has_ip()) { + auto itor = stackMapReader.ip(&parseError); + if (parseError) { + TS_LOGE("Parse packed varInt in ParseStackMap function failed!!!"); + return; + } + while (itor) { + frames.emplace_back(*itor); + itor++; + } + } + nativeHookFilter_->AppendStackMaps(stackId, frames); + return; +} + +void HtraceNativeHookParser::ParseFrameMap(std::unique_ptr& nativeHookMetaData) +{ + segs_.emplace_back(nativeHookMetaData->seg_); + ProtoReader::FrameMap_Reader frameMapReader(nativeHookMetaData->reader_->frame_map()); + // when callstack is compressed, Frame message only has ip data area. + nativeHookFilter_->AppendFrameMaps(frameMapReader.id(), frameMapReader.frame()); +} +void HtraceNativeHookParser::ParseTagEvent(const ProtoReader::BytesView& bytesView) +{ + ProtoReader::MemTagEvent_Reader memTagEventReader(bytesView); + auto tagIndex = traceDataCache_->dataDict_.GetStringIndex(memTagEventReader.tag().ToStdString()); + traceDataCache_->GetNativeHookData()->UpdateAddrToMemMapSubType(memTagEventReader.addr(), tagIndex); +} +void HtraceNativeHookParser::ParseFileEvent(const ProtoReader::BytesView& bytesView) +{ + ProtoReader::FilePathMap_Reader filePathMapReader(bytesView); + auto id = filePathMapReader.id(); + auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(filePathMapReader.name().ToStdString()); + nativeHookFilter_->AppendFilePathMaps(id, nameIndex); +} +void HtraceNativeHookParser::ParseSymbolEvent(const ProtoReader::BytesView& bytesView) +{ + ProtoReader::SymbolMap_Reader symbolMapReader(bytesView); + auto id = symbolMapReader.id(); + auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(symbolMapReader.name().ToStdString()); + nativeHookFilter_->AppendSymbolMap(id, nameIndex); +} +void HtraceNativeHookParser::ParseThreadEvent(const ProtoReader::BytesView& bytesView) +{ + ProtoReader::ThreadNameMap_Reader threadNameMapReader(bytesView); + auto id = threadNameMapReader.id(); + auto nameIndex = traceDataCache_->dataDict_.GetStringIndex(threadNameMapReader.name().ToStdString()); + nativeHookFilter_->AppendThreadNameMap(id, nameIndex); +} + +void HtraceNativeHookParser::ParseNativeHookAuxiliaryEvent(std::unique_ptr& nativeHookMetaData) +{ + auto& reader = nativeHookMetaData->reader_; + if (reader->has_stack_map()) { + ParseStackMap(reader->stack_map()); + } else if (reader->has_frame_map()) { + ParseFrameMap(nativeHookMetaData); + } else if (reader->has_tag_event()) { + ParseTagEvent(reader->tag_event()); + } else if (reader->has_file_path()) { + ParseFileEvent(reader->file_path()); + } else if (reader->has_symbol_name()) { + ParseSymbolEvent(reader->symbol_name()); + } else if (reader->has_thread_name_map()) { + ParseThreadEvent(reader->thread_name_map()); + } else if (reader->has_maps_info()) { + nativeHookFilter_->ParseMapsEvent(nativeHookMetaData); + } else if (reader->has_symbol_tab()) { + nativeHookFilter_->ParseSymbolTableEvent(nativeHookMetaData); + } else { + TS_LOGE("unsupported native_hook data!"); + } +} +// In order to improve the accuracy of data, it is necessary to sort the original data. +// Data sorting will be reduced by 5% to 10% Speed of parsing data. +void HtraceNativeHookParser::Parse(HtraceDataSegment& dataSeg) +{ + auto batchNativeHookDataReader = ProtoReader::BatchNativeHookData_Reader(dataSeg.protoData); + for (auto itor = batchNativeHookDataReader.events(); itor; itor++) { + auto nativeHookDataReader = std::make_unique(itor->ToBytes()); + auto timeStamp = nativeHookDataReader->tv_nsec() + nativeHookDataReader->tv_sec() * SEC_TO_NS; + if (nativeHookDataReader->has_alloc_event() || nativeHookDataReader->has_free_event() || + nativeHookDataReader->has_mmap_event() || nativeHookDataReader->has_munmap_event() || + nativeHookDataReader->has_statistics_event()) { + uint64_t newTimeStamp = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, timeStamp); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, timeStamp, newTimeStamp); + auto nativeHookMetaData = + std::make_unique(dataSeg.seg, std::move(nativeHookDataReader)); + nativeHookFilter_->MaybeParseNativeHookMainEvent(newTimeStamp, std::move(nativeHookMetaData)); + } else { + auto nativeHookMetaData = + std::make_unique(dataSeg.seg, std::move(nativeHookDataReader)); + ParseNativeHookAuxiliaryEvent(nativeHookMetaData); + } + } +} +void HtraceNativeHookParser::ParseConfigInfo(HtraceDataSegment& dataSeg) +{ + nativeHookFilter_->ParseConfigInfo(dataSeg.protoData); +} +void HtraceNativeHookParser::FinishParseNativeHookData() +{ + nativeHookFilter_->FinishParseNativeHookData(); +} +void HtraceNativeHookParser::Finish() +{ + if (GetPluginStartTime() != GetPluginEndTime()) { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); + } else { + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginStartTime() + 1); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_native_hook_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_native_hook_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..0322459ede2d9264fa1c2d15aefb8e42abd9720a --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_native_hook_parser.h @@ -0,0 +1,65 @@ +/* + * 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 HTRACE_NATIVE_HOOK_PARSER_H +#define HTRACE_NATIVE_HOOK_PARSER_H +#include +#include +#include +#include +#include "common_types.h" +#include "htrace_event_parser.h" +#include "htrace_plugin_time_parser.h" +#include "native_hook_config.pbreader.h" +#include "native_hook_filter.h" +#include "native_hook_result.pbreader.h" +#include "offline_symbolization_filter.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceNativeHookParser : public HtracePluginTimeParser { +public: + HtraceNativeHookParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceNativeHookParser(); + void ParseConfigInfo(HtraceDataSegment& dataSeg); + void Parse(HtraceDataSegment& dataSeg); + void FinishParseNativeHookData(); + void Finish(); + bool NativeHookReloadElfSymbolTable(std::shared_ptr>> elfSymbolTables) + { + return nativeHookFilter_->NativeHookReloadElfSymbolTable(elfSymbolTables); + } + bool SupportImportSymbolTable() + { + return nativeHookFilter_->SupportImportSymbolTable(); + } + +private: + void ParseNativeHookAuxiliaryEvent(std::unique_ptr& nativeHookMetaData); + void ParseTagEvent(const ProtoReader::BytesView& bytesView); + void ParseFileEvent(const ProtoReader::BytesView& bytesView); + void ParseSymbolEvent(const ProtoReader::BytesView& bytesView); + void ParseThreadEvent(const ProtoReader::BytesView& bytesView); + void ParseFrameMap(std::unique_ptr& nativeHookMetaData); + void ParseStackMap(const ProtoReader::BytesView& bytesView); + +private: + std::vector> segs_ = {}; + std::unique_ptr nativeHookFilter_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_NATIVE_HOOK_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_network_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_network_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5834a7637cf8daef081ba5b9ecac4930a2c3b82 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_network_parser.cpp @@ -0,0 +1,90 @@ +/* + * 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 "htrace_network_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceNetworkParser::HtraceNetworkParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceNetworkParser::~HtraceNetworkParser() +{ + TS_LOGI("network ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); +} + +void HtraceNetworkParser::Parse(ProtoReader::BytesView tracePacket, uint64_t ts) +{ + ProtoReader::NetworkDatas_Reader networkData(tracePacket.data_, tracePacket.size_); + ProtoReader::NetworkSystemData_Reader networkSystemData(networkData.network_system_info()); + auto tv_sec = networkSystemData.tv_sec(); + auto tv_nsec = networkSystemData.tv_nsec(); + auto rx_bytes = networkSystemData.rx_bytes(); + auto rx_packets = networkSystemData.rx_packets(); + auto tx_bytes = networkSystemData.tx_bytes(); + auto tx_packets = networkSystemData.tx_packets(); + + ts = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, ts); + streamFilters_->statFilter_->IncreaseStat(TRACE_NETWORK, STAT_EVENT_RECEIVED); + networkData_.push_back(std::move(TsNetworkData{ts, tv_sec, tv_nsec, rx_bytes, rx_packets, tx_bytes, tx_packets})); +} +void HtraceNetworkParser::Finish() +{ + auto cmp = [](const TsNetworkData& a, const TsNetworkData& b) { return a.ts < b.ts; }; +#ifdef IS_WASM + std::sort(networkData_.begin(), networkData_.end(), cmp); +#else + std::stable_sort(networkData_.begin(), networkData_.end(), cmp); +#endif + bool firstTime = true; + uint64_t lastTs = 0; + uint64_t lastRx = 0; + uint64_t lastTx = 0; + uint64_t lastPacketIn = 0.0; + uint64_t lastPacketOut = 0.0; + for (auto itor = networkData_.begin(); itor != networkData_.end(); itor++) { + auto newTimeStamp = itor->ts; + UpdatePluginTimeRange(TS_CLOCK_REALTIME, itor->ts, newTimeStamp); + if (firstTime) { + lastTs = newTimeStamp; + lastRx = itor->rx_bytes; + lastTx = itor->tx_bytes; + lastPacketIn = itor->rx_packets; + lastPacketOut = itor->tx_packets; + firstTime = false; + continue; + } + auto dur = newTimeStamp - lastTs; + auto durS = 1.0 * dur / SEC_TO_NS; + traceDataCache_->GetNetworkData()->AppendNewNetData( + newTimeStamp, itor->tx_bytes, itor->rx_bytes, dur, 1.0 * (itor->rx_bytes - lastRx) / durS, + 1.0 * (itor->tx_bytes - lastTx) / durS, itor->rx_packets, 1.0 * (itor->rx_packets - lastPacketIn) / durS, + itor->tx_packets, 1.0 * (itor->tx_packets - lastPacketOut) / durS, "undefined"); + lastTs = newTimeStamp; + lastRx = itor->rx_bytes; + lastTx = itor->tx_bytes; + lastPacketIn = itor->rx_packets; + lastPacketOut = itor->tx_packets; + } + networkData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_network_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_network_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..0a29ec49662917256e0f8ae31f0623aaeab55d61 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_network_parser.h @@ -0,0 +1,47 @@ +/* + * 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 HTRACE_NETWORK_PARSER_H +#define HTRACE_NETWORK_PARSER_H +#include +#include +#include +#include +#include "common_types.h" +#include "htrace_plugin_time_parser.h" +#include "trace_streamer_config.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceNetworkParser : public HtracePluginTimeParser { +public: + HtraceNetworkParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceNetworkParser(); + void Parse(ProtoReader::BytesView tracePacket, uint64_t ts); + void Finish(); + struct TsNetworkData { + uint64_t ts; + uint64_t tv_sec; + uint64_t tv_nsec; + uint64_t rx_bytes; + uint64_t rx_packets; + uint64_t tx_bytes; + uint64_t tx_packets; + }; + std::vector networkData_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_NETWORK_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e49f7a09e5ee568b3723041c6e807ad561b3303 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_parser.cpp @@ -0,0 +1,702 @@ +/* + * 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 "htrace_parser.h" +#include +#include "binder_filter.h" +#include "cpu_filter.h" +#include "data_area.h" +#include "ftrace_event.pbreader.h" +#include "log.h" +#include "memory_plugin_result.pbreader.h" +#include "services/common_types.pbreader.h" +#include "stat_filter.h" +#include "trace_plugin_result.pbreader.h" +#if IS_WASM +#include "../rpc/wasm_func.h" +#endif +namespace SysTuning { +namespace TraceStreamer { +HtraceParser::HtraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters) + : ParserBase(filters), + traceDataCache_(dataCache), + htraceCpuDetailParser_(std::make_unique(dataCache, filters)), + htraceSymbolsDetailParser_(std::make_unique(dataCache, filters)), + htraceMemParser_(std::make_unique(dataCache, filters)), + htraceClockDetailParser_(std::make_unique(dataCache, filters)), + htraceHiLogParser_(std::make_unique(dataCache, filters)), + htraceNativeHookParser_(std::make_unique(dataCache, filters)), + htraceHidumpParser_(std::make_unique(dataCache, filters)), + cpuUsageParser_(std::make_unique(dataCache, filters)), + networkParser_(std::make_unique(dataCache, filters)), + diskIOParser_(std::make_unique(dataCache, filters)), + processParser_(std::make_unique(dataCache, filters)), + ebpfDataParser_(std::make_unique(dataCache, filters)), + hisyseventParser_(std::make_unique(dataCache, filters)), + jsMemoryParser_(std::make_unique(dataCache, filters)), +#if WITH_PERF + perfDataParser_(std::make_unique(dataCache, filters)), +#endif +#ifdef SUPPORTTHREAD + supportThread_(true), + dataSegArray_(std::make_unique(MAX_SEG_ARRAY_SIZE)) +#else + dataSegArray_(std::make_unique(1)) +#endif +{ +} +void HtraceParser::GetSymbols(std::unique_ptr elfPtr, + std::shared_ptr symbols, + const std::string& filename) +{ + symbols->filePath = std::move(filename); + symbols->textVaddr = (std::numeric_limits::max)(); + for (auto& item : elfPtr->phdrs_) { + if ((item->type_ == PT_LOAD) && (item->flags_ & PF_X)) { + // find the min addr + if (symbols->textVaddr != (std::min)(symbols->textVaddr, item->vaddr_)) { + symbols->textVaddr = (std::min)(symbols->textVaddr, item->vaddr_); + symbols->textOffset = item->offset_; + } + } + } + if (symbols->textVaddr == (std::numeric_limits::max)()) { + TS_LOGE("GetSymbols get textVaddr failed"); + return; + } + + std::string symSecName; + std::string strSecName; + if (elfPtr->shdrs_.find(".symtab") != elfPtr->shdrs_.end()) { + symSecName = ".symtab"; + strSecName = ".strtab"; + } else if (elfPtr->shdrs_.find(".dynsym") != elfPtr->shdrs_.end()) { + symSecName = ".dynsym"; + strSecName = ".dynstr"; + } else { + return; + } + const auto& sym = elfPtr->shdrs_[static_cast(symSecName)]; + const uint8_t* symData = elfPtr->GetSectionData(sym->secIndex_); + const auto& str = elfPtr->shdrs_[static_cast(strSecName)]; + const uint8_t* strData = elfPtr->GetSectionData(str->secIndex_); + + if (!sym->secSize_ || !str->secSize_) { + TS_LOGE( + "GetSymbols get section size failed, \ + sym size: %" PRIu64 ", str size: %" PRIu64 "", + sym->secSize_, str->secSize_); + return; + } + symbols->symEntSize = sym->secEntrySize_; + std::string symTable(symData, symData + sym->secSize_); + symbols->symTable = std::move(symTable); + std::string strTable(strData, strData + str->secSize_); + symbols->strTable = std::move(strTable); +} + +bool HtraceParser::ParserFileSO(std::string& directory, std::vector& relativeFilePaths) +{ + elfSymbolTables_ = std::make_shared>>(); + std::cout << "start Parser File so" << std::endl; + for (auto relativeFilePath : relativeFilePaths) { + if (relativeFilePath.compare(0, directory.length(), directory)) { + TS_LOGI("%s not in directory %s", relativeFilePath.c_str(), directory.c_str()); + continue; + } + std::unique_ptr elfFile = ElfFile::MakeUnique(relativeFilePath); + if (elfFile == nullptr) { + TS_LOGI("elf %s load failed", relativeFilePath.c_str()); + continue; + } else { + TS_LOGI("loaded elf %s", relativeFilePath.c_str()); + } + auto symbolInfo = std::make_shared(); + auto absoluteFilePath = relativeFilePath.substr(directory.length()); + GetSymbols(std::move(elfFile), symbolInfo, absoluteFilePath); + elfSymbolTables_->emplace_back(symbolInfo); + } + if (!elfSymbolTables_->size()) { + return false; + } + return true; +} + +HtraceParser::~HtraceParser() +{ + TS_LOGI("clockid 2 is for RealTime and 1 is for BootTime"); +} + +bool HtraceParser::ReparseSymbolFilesAndResymbolization(std::string& symbolsPath, + std::vector& symbolsPaths) +{ + auto parsePerfStatus = false; +#if WITH_PERF + std::vector dir; + dir.emplace_back(symbolsPath); + parsePerfStatus = perfDataParser_->PerfReloadSymbolFiles(dir); +#endif + auto parseFileSOStatus = ParserFileSO(symbolsPath, symbolsPaths); + if (!parseFileSOStatus) { + return parsePerfStatus; + } + if (htraceNativeHookParser_->SupportImportSymbolTable()) { + htraceNativeHookParser_->NativeHookReloadElfSymbolTable(elfSymbolTables_); + } + if (ebpfDataParser_->SupportImportSymbolTable()) { + ebpfDataParser_->EBPFReloadElfSymbolTable(elfSymbolTables_); + } + return true; +} +void HtraceParser::WaitForParserEnd() +{ + if (parseThreadStarted_ || filterThreadStarted_) { + toExit_ = true; + while (!exited_) { + usleep(sleepDur_ * sleepDur_); + } + } + htraceCpuDetailParser_->FilterAllEvents(); + htraceNativeHookParser_->FinishParseNativeHookData(); + htraceHiLogParser_->Finish(); + htraceNativeHookParser_->Finish(); + htraceHidumpParser_->Finish(); + cpuUsageParser_->Finish(); + networkParser_->Finish(); + processParser_->Finish(); + diskIOParser_->Finish(); + hisyseventParser_->Finish(); + jsMemoryParser_->Finish(); + // keep final upate perf and ebpf data time range + ebpfDataParser_->Finish(); +#if WITH_PERF + perfDataParser_->Finish(); +#endif + htraceMemParser_->Finish(); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_TRACE, + dataSourceTypeTraceClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_MEM, dataSourceTypeMemClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_HILOG, + dataSourceTypeHilogClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_NATIVEHOOK, + dataSourceTypeNativeHookClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_FPS, dataSourceTypeFpsClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_NETWORK, + dataSourceTypeNetworkClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_DISKIO, + dataSourceTypeDiskioClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_CPU, dataSourceTypeCpuClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_PROCESS, + dataSourceTypeProcessClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_HISYSEVENT, + dataSourceTypeHisyseventClockid_); + traceDataCache_->GetDataSourceClockIdData()->SetDataSourceClockId(DATA_SOURCE_TYPE_JSMEMORY, + dataSourceTypeJSMemoryClockid_); + traceDataCache_->GetDataSourceClockIdData()->Finish(); + dataSegArray_.reset(); +} + +void HtraceParser::ParseTraceDataItem(const std::string& buffer) +{ + int32_t head = rawDataHead_; + if (!supportThread_) { + dataSegArray_[head].seg = std::make_shared(std::move(buffer)); + dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED; + ParserData(dataSegArray_[head]); + return; + } + while (!toExit_) { + if (dataSegArray_[head].status.load() != TS_PARSE_STATUS_INIT) { + usleep(sleepDur_); + continue; + } + dataSegArray_[head].seg = std::make_shared(std::move(buffer)); + dataSegArray_[head].status = TS_PARSE_STATUS_SEPRATED; + rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE; + break; + } + if (!parseThreadStarted_) { + parseThreadStarted_ = true; + int32_t tmp = maxThread_; + while (tmp--) { + parserThreadCount_++; + std::thread ParseTypeThread(&HtraceParser::ParseThread, this); + ParseTypeThread.detach(); + TS_LOGD("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_); + } + } +} + +void HtraceParser::EnableFileSeparate(bool enabled) +{ + jsMemoryParser_->EnableSaveFile(enabled); +} +void HtraceParser::FilterData(HtraceDataSegment& seg) +{ + if (seg.dataType == DATA_SOURCE_TYPE_NATIVEHOOK) { + htraceNativeHookParser_->Parse(seg); + } else if (seg.dataType == DATA_SOURCE_TYPE_NATIVEHOOK_CONFIG) { + htraceNativeHookParser_->ParseConfigInfo(seg); + } else if (seg.dataType == DATA_SOURCE_TYPE_TRACE) { + ProtoReader::TracePluginResult_Reader tracePluginResult(seg.protoData); + if (tracePluginResult.has_ftrace_cpu_detail()) { + htraceCpuDetailParser_->Parse(seg, seg.clockId); + } + if (tracePluginResult.has_symbols_detail()) { + htraceSymbolsDetailParser_->Parse(seg.protoData); // has Event + } + if (tracePluginResult.has_clocks_detail()) { + htraceClockDetailParser_->Parse(seg.protoData); // has Event + } + } else if (seg.dataType == DATA_SOURCE_TYPE_MEM) { + htraceMemParser_->Parse(seg, seg.timeStamp, seg.clockId); + } else if (seg.dataType == DATA_SOURCE_TYPE_HILOG) { + htraceHiLogParser_->Parse(seg.protoData); + } else if (seg.dataType == DATA_SOURCE_TYPE_CPU) { + cpuUsageParser_->Parse(seg.protoData, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_FPS) { + htraceHidumpParser_->Parse(seg.protoData); + dataSourceTypeFpsClockid_ = htraceHidumpParser_->ClockId(); + } else if (seg.dataType == DATA_SOURCE_TYPE_NETWORK) { + networkParser_->Parse(seg.protoData, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_PROCESS) { + processParser_->Parse(seg.protoData, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_DISKIO) { + diskIOParser_->Parse(seg.protoData, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_JSMEMORY) { + jsMemoryParser_->Parse(seg.protoData, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_JSMEMORY_CONFIG) { + jsMemoryParser_->ParseJSMemoryConfig(seg.protoData); + } else if (seg.dataType == DATA_SOURCE_TYPE_HISYSEVENT) { + ProtoReader::HisyseventInfo_Reader hisyseventInfo(seg.protoData.data_, seg.protoData.size_); + hisyseventParser_->Parse(&hisyseventInfo, seg.timeStamp); + } else if (seg.dataType == DATA_SOURCE_TYPE_HISYSEVENT_CONFIG) { + ProtoReader::HisyseventConfig_Reader hisyseventConfig(seg.protoData.data_, seg.protoData.size_); + hisyseventParser_->Parse(&hisyseventConfig, seg.timeStamp); + } + if (supportThread_) { + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; + } + seg.status = TS_PARSE_STATUS_INIT; +} +void HtraceParser::FilterThread() +{ + TS_LOGI("filter thread start work!"); + while (1) { + HtraceDataSegment& seg = dataSegArray_[filterHead_]; + if (seg.status.load() == TS_PARSE_STATUS_INVALID) { + seg.status = TS_PARSE_STATUS_INIT; + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + TS_LOGD("seprateHead_d:\t%d, parseHead_:\t%d, filterHead_:\t%d\n", rawDataHead_, parseHead_, filterHead_); + continue; + } + if (seg.status.load() != TS_PARSE_STATUS_PARSED) { + if (toExit_ && !parserThreadCount_) { + TS_LOGI("exiting Filter Thread"); + exited_ = true; + filterThreadStarted_ = false; + TS_LOGI("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + return; + } + TS_LOGD("seprateHead:\t%d, parseHead_:\t%d, filterHead_:\t%d, status:%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + usleep(sleepDur_); + continue; + } + FilterData(seg); + } +} +void HtraceParser::ParserData(HtraceDataSegment& dataSeg) +{ + ProtoReader::ProfilerPluginData_Reader pluginDataZero(reinterpret_cast(dataSeg.seg->c_str()), + dataSeg.seg->length()); + std::string pluginName; + if (pluginDataZero.has_name()) { + pluginName = pluginDataZero.name().ToStdString(); + } + if (pluginDataZero.has_tv_sec() && pluginDataZero.has_tv_nsec()) { + dataSeg.timeStamp = pluginDataZero.tv_sec() * SEC_TO_NS + pluginDataZero.tv_nsec(); + } + if (pluginName == "nativehook" || pluginName == "hookdaemon") { + dataSourceTypeNativeHookClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_NATIVEHOOK; + dataSeg.protoData = pluginDataZero.data(); + } else if (pluginName == "nativehook_config") { + dataSeg.dataType = DATA_SOURCE_TYPE_NATIVEHOOK_CONFIG; + dataSeg.protoData = pluginDataZero.data(); + } else if (pluginDataZero.name().ToStdString() == "ftrace-plugin" || + pluginDataZero.name().ToStdString() == "/data/local/tmp/libftrace_plugin.z.so") { // ok + dataSeg.dataType = DATA_SOURCE_TYPE_TRACE; + dataSeg.protoData = pluginDataZero.data(); + ParseFtrace(dataSeg); + } else if (pluginName == "memory-plugin") { + dataSeg.protoData = pluginDataZero.data(); + dataSeg.dataType = DATA_SOURCE_TYPE_MEM; + ParseMemory(&pluginDataZero, dataSeg); + } else if (pluginName == "hilog-plugin" || pluginName == "/data/local/tmp/libhilogplugin.z.so") { + dataSeg.protoData = pluginDataZero.data(); + ParseHilog(dataSeg); + } else if (pluginName == "hidump-plugin" || pluginName == "/data/local/tmp/libhidumpplugin.z.so") { + dataSeg.protoData = pluginDataZero.data(); + ParseFPS(dataSeg); + } else if (pluginName == "cpu-plugin") { + dataSeg.protoData = pluginDataZero.data(); + ParseCpuUsage(dataSeg); + } else if (pluginName == "network-plugin") { + dataSeg.protoData = pluginDataZero.data(); + ParseNetwork(dataSeg); + } else if (pluginName == "diskio-plugin") { + dataSeg.protoData = pluginDataZero.data(); + ParseDiskIO(dataSeg); + } else if (pluginName == "process-plugin") { + dataSeg.protoData = pluginDataZero.data(); + ParseProcess(dataSeg); + } else if (pluginName == "hisysevent-plugin") { + dataSeg.protoData = pluginDataZero.data(); + ParseHisysevent(dataSeg); + } else if (pluginName == "hisysevent-plugin_config") { + dataSeg.protoData = pluginDataZero.data(); + ParseHisyseventConfig(dataSeg); + } else if (pluginName == "js-memory") { + dataSeg.protoData = pluginDataZero.data(); + ParseJSMemory(dataSeg); + } else if (pluginName == "js-memory_config") { + dataSeg.protoData = pluginDataZero.data(); + ParseJSMemoryConfig(dataSeg); + } else { +#if IS_WASM + TraceStreamer_Plugin_Out_Filter(reinterpret_cast(pluginDataZero.data().data_), + pluginDataZero.data().size_, pluginName); +#endif + dataSeg.status = TS_PARSE_STATUS_INVALID; + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + return; + } + if (!supportThread_) { // do it only in wasm mode, wasm noThead_ will be true + if (dataSeg.status == STAT_EVENT_DATA_INVALID) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); + return; + } + FilterData(dataSeg); + } +} +void HtraceParser::ParseThread() +{ + TS_LOGI("parser thread start work!\n"); + while (1) { + if (supportThread_ && !filterThreadStarted_) { + filterThreadStarted_ = true; + std::thread ParserThread(&HtraceParser::FilterThread, this); + TS_LOGD("FilterThread start working ...\n"); + ParserThread.detach(); + } + int32_t head = GetNextSegment(); + if (head < 0) { + if (head == ERROR_CODE_EXIT) { + TS_LOGI("parse thread exit\n"); + return; + } else if (head == ERROR_CODE_NODATA) { + continue; + } + } + HtraceDataSegment& dataSeg = dataSegArray_[head]; + ParserData(dataSeg); + } +} + +void HtraceParser::ParseMemory(ProtoReader::ProfilerPluginData_Reader* pluginDataZero, HtraceDataSegment& dataSeg) +{ + BuiltinClocks clockId = TS_CLOCK_REALTIME; + auto clockIdTemp = pluginDataZero->clock_id(); + if (clockIdTemp == ProtoReader::ProfilerPluginData_ClockId_CLOCKID_REALTIME) { + clockId = TS_CLOCK_REALTIME; + } + dataSourceTypeMemClockid_ = clockId; + dataSeg.dataType = DATA_SOURCE_TYPE_MEM; + dataSeg.clockId = clockId; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} +void HtraceParser::ParseHilog(HtraceDataSegment& dataSeg) +{ + dataSeg.dataType = DATA_SOURCE_TYPE_HILOG; + dataSourceTypeHilogClockid_ = TS_CLOCK_REALTIME; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseFtrace(HtraceDataSegment& dataSeg) +{ + ProtoReader::TracePluginResult_Reader tracePluginResult(dataSeg.protoData); + if (tracePluginResult.has_ftrace_cpu_stats()) { + auto cpuStats = *tracePluginResult.ftrace_cpu_stats(); + ProtoReader::FtraceCpuStatsMsg_Reader ftraceCpuStatsMsg(cpuStats.data_, cpuStats.size_); + auto s = *ftraceCpuStatsMsg.per_cpu_stats(); + ProtoReader::PerCpuStatsMsg_Reader perCpuStatsMsg(s.data_, s.size_); + TS_LOGD("s.overrun():%lu", perCpuStatsMsg.overrun()); + TS_LOGD("s.dropped_events():%lu", perCpuStatsMsg.dropped_events()); + auto clock = ftraceCpuStatsMsg.trace_clock().ToStdString(); + if (clock == "boot") { + clock_ = TS_CLOCK_BOOTTIME; + } else if (clock == "mono") { + clock_ = TS_MONOTONIC; + } else { + TS_LOGI("invalid clock:%s", clock.c_str()); + dataSeg.status = TS_PARSE_STATUS_INVALID; + return; + } + dataSeg.clockId = clock_; + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.clockId = clock_; + dataSourceTypeTraceClockid_ = clock_; + if (tracePluginResult.has_clocks_detail() || tracePluginResult.has_ftrace_cpu_detail() || + tracePluginResult.has_symbols_detail()) { + dataSeg.status = TS_PARSE_STATUS_PARSED; + return; + } + dataSeg.status = TS_PARSE_STATUS_INVALID; +} + +void HtraceParser::ParseFPS(HtraceDataSegment& dataSeg) +{ + dataSeg.dataType = DATA_SOURCE_TYPE_FPS; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseCpuUsage(HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_CPU; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} +void HtraceParser::ParseNetwork(HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_NETWORK; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} +void HtraceParser::ParseDiskIO(HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_DISKIO; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseProcess(HtraceDataSegment& dataSeg) +{ + dataSourceTypeProcessClockid_ = TS_CLOCK_BOOTTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_PROCESS; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseHisysevent(HtraceDataSegment& dataSeg) +{ + dataSourceTypeHisyseventClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_HISYSEVENT; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} +void HtraceParser::ParseHisyseventConfig(HtraceDataSegment& dataSeg) +{ + dataSourceTypeHisyseventClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_HISYSEVENT_CONFIG; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseJSMemory(HtraceDataSegment& dataSeg) +{ + dataSourceTypeJSMemoryClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_JSMEMORY; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +void HtraceParser::ParseJSMemoryConfig(HtraceDataSegment& dataSeg) +{ + dataSourceTypeJSMemoryClockid_ = TS_CLOCK_REALTIME; + dataSeg.dataType = DATA_SOURCE_TYPE_JSMEMORY_CONFIG; + dataSeg.status = TS_PARSE_STATUS_PARSED; +} + +int32_t HtraceParser::GetNextSegment() +{ + int32_t head; + dataSegMux_.lock(); + head = parseHead_; + HtraceDataSegment& seg = dataSegArray_[head]; + if (seg.status.load() != TS_PARSE_STATUS_SEPRATED) { + if (toExit_) { + parserThreadCount_--; + TS_LOGI("exiting parser, parserThread Count:%d\n", parserThreadCount_); + TS_LOGD("seprateHead_x:\t%d, parseHead_:\t%d, filterHead_:\t%d status:%d\n", rawDataHead_, parseHead_, + filterHead_, seg.status.load()); + dataSegMux_.unlock(); + if (!parserThreadCount_ && !filterThreadStarted_) { + exited_ = true; + } + return ERROR_CODE_EXIT; + } + if (seg.status.load() == TS_PARSE_STATUS_PARSING) { + dataSegMux_.unlock(); + usleep(sleepDur_); + return ERROR_CODE_NODATA; + } + dataSegMux_.unlock(); + usleep(sleepDur_); + return ERROR_CODE_NODATA; + } + parseHead_ = (parseHead_ + 1) % MAX_SEG_ARRAY_SIZE; + seg.status = TS_PARSE_STATUS_PARSING; + dataSegMux_.unlock(); + return head; +} +bool HtraceParser::ParseDataRecursively(std::deque::iterator& packagesBegin, size_t& currentLength) +{ + if (!hasGotHeader_) { + if (InitProfilerTraceFileHeader()) { + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBuffer_.begin() + PACKET_HEADER_LENGTH); + currentLength -= PACKET_HEADER_LENGTH; + packagesBegin += PACKET_HEADER_LENGTH; + htraceCurentLength_ = profilerTraceFileHeader_.data.length; + htraceCurentLength_ -= PACKET_HEADER_LENGTH; + hasGotHeader_ = true; + if (!currentLength) { + return false; + } + } else { + TS_LOGE("get profiler trace file header failed"); + return false; + } + } + if (profilerTraceFileHeader_.data.dataType == ProfilerTraceFileHeader::HIPERF_DATA) { + if (packagesBuffer_.size() >= profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH) { +#if WITH_PERF + auto size = profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH; + perfDataParser_->InitPerfDataAndLoad(packagesBuffer_, size); + currentLength -= size; + packagesBegin += size; + profilerTraceFileHeader_.data.dataType = ProfilerTraceFileHeader::UNKNOW_TYPE; + hasGotHeader_ = false; + return true; +#endif + } + return false; + } + if (profilerTraceFileHeader_.data.dataType == ProfilerTraceFileHeader::STANDALONE_DATA) { + if (EBPF_PLUGIN_NAME.compare(profilerTraceFileHeader_.data.standalonePluginName) == 0 && + packagesBuffer_.size() >= profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH) { + auto size = profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH; + ebpfDataParser_->InitAndParseEbpfData(packagesBuffer_, size); + currentLength -= size; + packagesBegin += size; + profilerTraceFileHeader_.data.dataType = ProfilerTraceFileHeader::UNKNOW_TYPE; + hasGotHeader_ = false; + return true; + } +#if IS_WASM + if (packagesBuffer_.size() >= profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH) { + auto thirdPartySize = profilerTraceFileHeader_.data.length - PACKET_HEADER_LENGTH; + auto buffer = std::make_unique(thirdPartySize).get(); + std::copy(packagesBuffer_.begin(), packagesBuffer_.begin() + thirdPartySize, buffer); + TraceStreamer_Plugin_Out_Filter(reinterpret_cast(buffer), thirdPartySize, + profilerTraceFileHeader_.data.standalonePluginName); + return true; + } +#endif + return false; + } + while (1) { + if (!hasGotSegLength_) { + if (currentLength < PACKET_SEG_LENGTH) { + break; + } + std::string bufferLine(packagesBegin, packagesBegin + PACKET_SEG_LENGTH); + const uint32_t* len = reinterpret_cast(bufferLine.data()); + nextLength_ = *len; + htraceLength_ += nextLength_ + PACKET_SEG_LENGTH; + hasGotSegLength_ = true; + currentLength -= PACKET_SEG_LENGTH; + packagesBegin += PACKET_SEG_LENGTH; + htraceCurentLength_ -= PACKET_SEG_LENGTH; + } + if (currentLength < nextLength_) { + break; + } + std::string bufferLine(packagesBegin, packagesBegin + nextLength_); + ParseTraceDataItem(bufferLine); + hasGotSegLength_ = false; + packagesBegin += nextLength_; + currentLength -= nextLength_; + if (nextLength_ > htraceCurentLength_) { + TS_LOGE("fatal error, data length not match nextLength_:%u, htraceCurentLength_:%llu", nextLength_, + htraceCurentLength_); + } + htraceCurentLength_ -= nextLength_; + if (htraceCurentLength_ == 0) { + hasGotHeader_ = false; + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin); + profilerTraceFileHeader_.data.dataType = ProfilerTraceFileHeader::UNKNOW_TYPE; + TS_LOGD("read proto finished!"); + return ParseDataRecursively(packagesBegin, currentLength); + } + } + return true; +} +void HtraceParser::ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) +{ + packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]); + auto packagesBegin = packagesBuffer_.begin(); + auto currentLength = packagesBuffer_.size(); + if (ParseDataRecursively(packagesBegin, currentLength)) { + packagesBuffer_.erase(packagesBuffer_.begin(), packagesBegin); + } + return; +} + +bool HtraceParser::InitProfilerTraceFileHeader() +{ + if (packagesBuffer_.size() < PACKET_HEADER_LENGTH) { + TS_LOGE("buffer size less than profiler trace file header"); + return false; + } + uint8_t buffer[PACKET_HEADER_LENGTH]; + (void)memset_s(buffer, PACKET_HEADER_LENGTH, 0, PACKET_HEADER_LENGTH); + int32_t i = 0; + for (auto it = packagesBuffer_.begin(); it != packagesBuffer_.begin() + PACKET_HEADER_LENGTH; ++it, ++i) { + buffer[i] = *it; + } + auto ret = memcpy_s(&profilerTraceFileHeader_, sizeof(profilerTraceFileHeader_), buffer, PACKET_HEADER_LENGTH); + if (ret == -1 || profilerTraceFileHeader_.data.magic != ProfilerTraceFileHeader::HEADER_MAGIC) { + TS_LOGE("Get profiler trace file header failed! ret = %d, magic = %lx", ret, + profilerTraceFileHeader_.data.magic); + return false; + } + if (profilerTraceFileHeader_.data.length <= PACKET_HEADER_LENGTH) { + TS_LOGE("Profiler Trace data is truncated!!!"); + return false; + } + TS_LOGI("magic = %lx, length = %llx, dataType = %llx, boottime = %llx", profilerTraceFileHeader_.data.magic, + profilerTraceFileHeader_.data.length, profilerTraceFileHeader_.data.dataType, + profilerTraceFileHeader_.data.boottime); +#if IS_WASM + const int32_t DATA_TYPE_CLOCK = 100; + TraceStreamer_Plugin_Out_SendData(reinterpret_cast(&profilerTraceFileHeader_), + sizeof(profilerTraceFileHeader_), DATA_TYPE_CLOCK); +#endif + htraceClockDetailParser_->Parse(&profilerTraceFileHeader_); + return true; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..9a59cb638da21fae3aacb68656ef2dcd7398f4d6 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_parser.h @@ -0,0 +1,155 @@ +/* + * 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 HTRACE_PARSER_H +#define HTRACE_PARSER_H +#include +#include +#include +#include +#include +#include +#include "common_types.h" +#include "ebpf_data_parser.h" +#include "elf_parser.h" +#include "file.h" +#include "htrace_clock_detail_parser.h" +#include "htrace_cpu_detail_parser.h" +#include "htrace_cpu_data_parser.h" +#include "htrace_disk_io_parser.h" +#include "htrace_file_header.h" +#include "htrace_hidump_parser.h" +#include "htrace_hilog_parser.h" +#include "htrace_hisysevent_parser.h" +#include "htrace_js_memory_parser.h" +#include "htrace_mem_parser.h" +#include "htrace_native_hook_parser.h" +#include "htrace_network_parser.h" +#include "htrace_process_parser.h" +#include "htrace_symbols_detail_parser.h" +#include "log.h" +#include "parser_base.h" +#if WITH_PERF +#include "perf_data_parser.h" +#endif +#include "proto_reader_help.h" +#include "string_help.h" +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +using namespace OHOS::Developtools::HiPerf::ELF; +#if WITH_PERF +using namespace OHOS::Developtools::HiPerf; +#endif +class HtraceParser : public ParserBase { +public: + HtraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters); + ~HtraceParser(); + void ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) override; + bool ReparseSymbolFilesAndResymbolization(std::string& symbolsPath, std::vector& symbolsPaths); + void WaitForParserEnd(); + void EnableFileSeparate(bool enabled); + + void GetSymbols(std::unique_ptr elfPtr, + std::shared_ptr symbols, + const std::string& filename); + bool ParserFileSO(std::string& directory, std::vector& relativeFilePaths); + +private: + bool ParseDataRecursively(std::deque::iterator& packagesBegin, size_t& currentLength); + void ParseTraceDataItem(const std::string& buffer) override; + void FilterData(HtraceDataSegment& seg); + void ParserData(HtraceDataSegment& dataSeg); + +private: + void ParseMemory(ProtoReader::ProfilerPluginData_Reader* pluginDataZero, HtraceDataSegment& dataSeg); + void ParseHilog(HtraceDataSegment& dataSeg); + void ParseFtrace(HtraceDataSegment& dataSeg); + void ParseFPS(HtraceDataSegment& dataSeg); + void ParseCpuUsage(HtraceDataSegment& dataSeg); + void ParseNetwork(HtraceDataSegment& dataSeg); + void ParseDiskIO(HtraceDataSegment& dataSeg); + void ParseProcess(HtraceDataSegment& dataSeg); + void ParseHisysevent(HtraceDataSegment& dataSeg); + void ParseHisyseventConfig(HtraceDataSegment& dataSeg); + void ParseJSMemory(HtraceDataSegment& dataSeg); + void ParseJSMemoryConfig(HtraceDataSegment& dataSeg); + void ParseThread(); + int32_t GetNextSegment(); + void FilterThread(); + enum ErrorCode { ERROR_CODE_EXIT = -2, ERROR_CODE_NODATA = -1 }; + bool InitProfilerTraceFileHeader(); + ProfilerTraceFileHeader profilerTraceFileHeader_; + uint64_t htraceCurentLength_ = 0; + bool hasGotSegLength_ = false; + bool hasGotHeader_ = false; + uint32_t nextLength_ = 0; + const size_t PACKET_SEG_LENGTH = 4; + const size_t PACKET_HEADER_LENGTH = 1024; + TraceDataCache* traceDataCache_; + std::unique_ptr htraceCpuDetailParser_; + std::unique_ptr htraceSymbolsDetailParser_; + std::unique_ptr htraceMemParser_; + std::unique_ptr htraceClockDetailParser_; + std::unique_ptr htraceHiLogParser_; + std::unique_ptr htraceNativeHookParser_; + std::unique_ptr htraceHidumpParser_; + std::unique_ptr cpuUsageParser_; + std::unique_ptr networkParser_; + std::unique_ptr diskIOParser_; + std::unique_ptr processParser_; + std::unique_ptr hisyseventParser_; + std::unique_ptr jsMemoryParser_; +#if WITH_PERF + std::unique_ptr perfDataParser_; +#endif + std::unique_ptr ebpfDataParser_; + std::atomic filterThreadStarted_{false}; + const int32_t MAX_SEG_ARRAY_SIZE = 10000; + std::shared_ptr dataSegArray_; + int32_t rawDataHead_ = 0; + bool toExit_ = false; + bool exited_ = false; + int32_t filterHead_ = 0; + int32_t parseHead_ = 0; + size_t sizeAll_ = 0; + size_t htraceLength_ = 1024; + const int32_t sleepDur_ = 100; + bool parseThreadStarted_ = false; + const int32_t maxThread_ = 4; // 4 is the best on ubuntu 113MB/s, max 138MB/s, 6 is best on mac m1 21MB/s, + int32_t parserThreadCount_ = 0; + std::mutex dataSegMux_ = {}; + bool supportThread_ = false; + ClockId dataSourceTypeTraceClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeMemClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeHilogClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeNativeHookClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeFpsClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeNetworkClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeDiskioClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeCpuClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeProcessClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeHisyseventClockid_ = TS_CLOCK_UNKNOW; + ClockId dataSourceTypeJSMemoryClockid_ = TS_CLOCK_UNKNOW; + std::shared_ptr>> elfSymbolTables_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PARSER_H_ diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_plugin_time_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_plugin_time_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec3e143ad48656051674401c1f9a7486db9bf30f --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_plugin_time_parser.cpp @@ -0,0 +1,67 @@ +/* + * 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 "htrace_plugin_time_parser.h" +namespace SysTuning { +namespace TraceStreamer { +HtracePluginTimeParser::HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : EventParserBase(dataCache, ctx) +{ + if (!streamFilters_) { + TS_LOGF("streamFilters_ should not be null"); + return; + } + if (!traceDataCache_) { + TS_LOGF("traceDataCache_ should not be null"); + return; + } +} +void HtracePluginTimeParser::UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp) +{ + minTs_ = std::min(minTs_, asyncTimestamp); + maxTs_ = std::max(maxTs_, asyncTimestamp); + if (clockId == streamFilters_->clockFilter_->GetPrimaryClock()) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + return; + } + if (syncTimestamp != asyncTimestamp) { + syncHtracePluginStartTime_ = std::min(syncHtracePluginStartTime_, syncTimestamp); + syncHtracePluginEndTime_ = std::max(syncHtracePluginEndTime_, syncTimestamp); + } else { + asyncHtracePluginStartTime_ = std::min(asyncHtracePluginStartTime_, syncTimestamp); + asyncHtracePluginEndTime_ = std::max(asyncHtracePluginEndTime_, syncTimestamp); + } +} +uint64_t HtracePluginTimeParser::GetPluginStartTime() +{ + if (syncHtracePluginStartTime_ != std::numeric_limits::max()) { + return syncHtracePluginStartTime_; + } else if (asyncHtracePluginStartTime_ != std::numeric_limits::max()) { + return asyncHtracePluginStartTime_; + } + return std::numeric_limits::max(); +} + +uint64_t HtracePluginTimeParser::GetPluginEndTime() +{ + if (syncHtracePluginEndTime_ != 0) { + return syncHtracePluginEndTime_; + } else if (asyncHtracePluginEndTime_ != 0) { + return asyncHtracePluginEndTime_; + } + return 0; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_plugin_time_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_plugin_time_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..a0874ea0a34cc5356c7fdc6e1086ac74c5a28af8 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_plugin_time_parser.h @@ -0,0 +1,52 @@ +/* + * 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 HTRACE_PLUGIN_TIME_PARSER_H +#define HTRACE_PLUGIN_TIME_PARSER_H +#include "clock_filter.h" +#include "event_parser_base.h" +#include "trace_data/trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtracePluginTimeParser : public EventParserBase { +public: + HtracePluginTimeParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + HtracePluginTimeParser(const HtracePluginTimeParser&) = delete; + HtracePluginTimeParser& operator=(const HtracePluginTimeParser&) = delete; + ~HtracePluginTimeParser() = default; + void UpdatePluginTimeRange(ClockId clockId, uint64_t asyncTimestamp, uint64_t syncTimestamp); + uint64_t GetPluginStartTime(); + uint64_t GetPluginEndTime(); + uint64_t MinTs() + { + return minTs_; + } + uint64_t MaxTs() + { + return maxTs_; + } + +private: + uint64_t syncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t syncHtracePluginEndTime_ = 0; + uint64_t asyncHtracePluginStartTime_ = std::numeric_limits::max(); + uint64_t asyncHtracePluginEndTime_ = 0; + uint64_t minTs_ = std::numeric_limits::max(); + uint64_t maxTs_ = 0; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PLUGIN_TIME_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_process_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_process_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a31ae5390398fadc1b78456c15f1f14ffc7097c --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_process_parser.cpp @@ -0,0 +1,98 @@ +/* + * 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 "htrace_process_parser.h" +#include "clock_filter.h" +#include "htrace_event_parser.h" +#include "process_filter.h" +#include "stat_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceProcessParser::HtraceProcessParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : HtracePluginTimeParser(dataCache, ctx) +{ +} + +HtraceProcessParser::~HtraceProcessParser() +{ + TS_LOGI("process ts MIN:%llu, MAX:%llu", static_cast(GetPluginStartTime()), + static_cast(GetPluginEndTime())); + TS_LOGI("process real ts MIN:%llu, MAX:%llu", static_cast(MinTs()), + static_cast(MaxTs())); +} +void HtraceProcessParser::Parse(ProtoReader::BytesView tracePacket, uint64_t ts) +{ + ProtoReader::ProcessData_Reader processData(tracePacket.data_, tracePacket.size_); + for (auto i = processData.processesinfo(); i; ++i) { + streamFilters_->statFilter_->IncreaseStat(TRACE_PROCESS, STAT_EVENT_START); + ProtoReader::ProcessInfo_Reader processInfoParser(i->ToBytes()); + ProtoReader::CpuInfo_Reader cpuInfoParser(processInfoParser.cpuinfo()); + ProtoReader::PssInfo_Reader pssInfoParser(processInfoParser.pssinfo()); + ProtoReader::DiskioInfo_Reader diskioInfoParser(processInfoParser.diskinfo()); + auto liveProcess = std::make_unique(); + auto processInfo = + std::make_unique(processInfoParser.pid(), processInfoParser.name().ToStdString(), + processInfoParser.ppid(), processInfoParser.uid()); + auto cpuInfo = std::make_unique(cpuInfoParser.cpu_usage(), cpuInfoParser.thread_sum(), + cpuInfoParser.cpu_time_ms()); + auto pssInfo = std::make_unique(pssInfoParser.pss_info()); + auto diskioInfo = std::make_unique( + diskioInfoParser.rchar(), diskioInfoParser.wchar(), diskioInfoParser.syscr(), diskioInfoParser.syscw(), + diskioInfoParser.rbytes(), diskioInfoParser.wbytes(), diskioInfoParser.cancelled_wbytes()); + liveProcess->SetLiveProcess(ts, std::move(processInfo), std::move(cpuInfo), std::move(pssInfo), + std::move(diskioInfo)); + liveProcessData_.push_back(std::move(liveProcess)); + } +} +void HtraceProcessParser::Finish() +{ + if (!liveProcessData_.size()) { + TS_LOGW("process no data"); + return; + } + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->ts_ < b->ts_; + }; +#ifdef IS_WASM + std::sort(liveProcessData_.begin(), liveProcessData_.end(), cmp); +#else + std::stable_sort(liveProcessData_.begin(), liveProcessData_.end(), cmp); +#endif + bool first = true; + uint64_t lastTs = 0; + for (auto itor = liveProcessData_.begin(); itor != liveProcessData_.end(); itor++) { + auto tsOld = (*itor)->ts_; + (*itor)->ts_ = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, (*itor)->ts_); + UpdatePluginTimeRange(TS_CLOCK_REALTIME, tsOld, (*itor)->ts_); + if (first) { + lastTs = (*itor)->ts_; + first = false; + continue; + } + auto dur = (*itor)->ts_ - lastTs; + lastTs = (*itor)->ts_; + if (!(*itor)->processInfo_->pid_) { + continue; + } + traceDataCache_->GetLiveProcessData()->AppendNewData( + (*itor)->ts_, dur, (*itor)->processInfo_->pid_, (*itor)->processInfo_->name_, (*itor)->processInfo_->ppid_, + (*itor)->processInfo_->uid_, std::to_string((*itor)->processInfo_->uid_), + (*itor)->cpuUsageData_->cpu_usage_, (*itor)->pssInfo_->pss_info_, (*itor)->cpuUsageData_->cpu_time_ms_, + (*itor)->cpuUsageData_->thread_sum_, (*itor)->diskio_->wbytes_, (*itor)->diskio_->rbytes_); + } + liveProcessData_.clear(); + traceDataCache_->MixTraceTime(GetPluginStartTime(), GetPluginEndTime()); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_process_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_process_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..88587eee5bdccce80e2d2b83c1731989fdcd2623 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_process_parser.h @@ -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 HTRACE_PROCESS_PARSER_H +#define HTRACE_PROCESS_PARSER_H +#include +#include +#include +#include "common_types.h" +#include "htrace_plugin_time_parser.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class HtraceProcessParser : public HtracePluginTimeParser { +public: + HtraceProcessParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceProcessParser(); + void Parse(ProtoReader::BytesView tracePacket, uint64_t ts); + void Finish(); + struct DiskioInfo { + DiskioInfo(uint64_t rchar, + uint64_t wchar, + uint64_t syscr, + uint64_t syscw, + uint64_t rbytes, + uint64_t wbytes, + uint64_t cancelled_wbytes) + : rchar_(rchar), + wchar_(wchar), + syscr_(syscr), + syscw_(syscw), + rbytes_(rbytes), + wbytes_(wbytes), + cancelled_wbytes_(cancelled_wbytes) + { + } + uint64_t rchar_; + uint64_t wchar_; + uint64_t syscr_; + uint64_t syscw_; + uint64_t rbytes_; + uint64_t wbytes_; + uint64_t cancelled_wbytes_; + }; + struct PssInfo { + PssInfo(int32_t pss_info) : pss_info_(pss_info) {} + int32_t pss_info_; + }; + struct CpuInfo { + CpuInfo(double cpu_usage, int32_t thread_sum, uint64_t cpu_time_ms) + : cpu_usage_(cpu_usage), thread_sum_(thread_sum), cpu_time_ms_(cpu_time_ms) + { + } + double cpu_usage_; + int32_t thread_sum_; + uint64_t cpu_time_ms_; + }; + struct ProcessInfo { + ProcessInfo(int32_t pid, const std::string& name, int32_t ppid, int32_t uid) + : pid_(pid), name_(name), ppid_(ppid), uid_(uid) + { + } + int32_t pid_; + std::string name_; + int32_t ppid_; + int32_t uid_; + }; + struct TsLiveProcessData { + void SetLiveProcess(uint64_t ts, + std::unique_ptr liveProcessInfo, + std::unique_ptr cpuUsageData, + std::unique_ptr pssInfo, + std::unique_ptr diskio) + { + ts_ = ts; + processInfo_ = std::move(liveProcessInfo); + cpuUsageData_ = std::move(cpuUsageData); + pssInfo_ = std::move(pssInfo); + diskio_ = std::move(diskio); + } + uint64_t ts_; + std::unique_ptr processInfo_; + std::unique_ptr cpuUsageData_; + std::unique_ptr pssInfo_; + std::unique_ptr diskio_; + }; + std::vector> liveProcessData_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // HTRACE_PROCESS_PARSER_H diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_symbols_detail_parser.cpp b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_symbols_detail_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f90cc017a41735388f8213ccd0ae3c5a87c4e9b9 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_symbols_detail_parser.cpp @@ -0,0 +1,44 @@ +/* + * 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 "htrace_symbols_detail_parser.h" +#include "htrace_event_parser.h" +#include "symbols_filter.h" +namespace SysTuning { +namespace TraceStreamer { +HtraceSymbolsDetailParser::HtraceSymbolsDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx) + : streamFilters_(ctx), traceDataCache_(dataCache) +{ + UNUSED(traceDataCache_); + if (!streamFilters_) { + TS_LOGF("streamFilters_ should not be null"); + return; + } +} + +HtraceSymbolsDetailParser::~HtraceSymbolsDetailParser() = default; +void HtraceSymbolsDetailParser::Parse(ProtoReader::BytesView tracePacket) +{ + ProtoReader::TracePluginResult_Reader reader((const uint8_t*)(tracePacket.data_), tracePacket.size_); + if (!reader.has_symbols_detail()) { + return; + } + for (auto i = reader.symbols_detail(); i; ++i) { + ProtoReader::SymbolsDetailMsg_Reader reader(i->ToBytes()); + streamFilters_->symbolsFilter_->RegisterFunc(reader.symbol_addr(), + traceDataCache_->GetDataIndex(reader.symbol_name().ToStdString())); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/htrace_pbreader_parser/htrace_symbols_detail_parser.h b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_symbols_detail_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..c80379e79b40db3b36908e07a5e1a59bf9d0a9b8 --- /dev/null +++ b/trace_streamer/src/parser/htrace_pbreader_parser/htrace_symbols_detail_parser.h @@ -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. + */ +#ifndef HTRACE_SYMBOLS_DETAIL_PARSER_H +#define HTRACE_SYMBOLS_DETAIL_PARSER_H + +#include +#include +#include +#include +#include +#include "proto_reader/include/data_area.h" +#include "trace_data/trace_data_cache.h" +#include "trace_plugin_result.pbreader.h" +#include "trace_streamer_filters.h" +namespace SysTuning { +namespace TraceStreamer { +class HtraceSymbolsDetailParser { +public: + HtraceSymbolsDetailParser(TraceDataCache* dataCache, const TraceStreamerFilters* ctx); + ~HtraceSymbolsDetailParser(); + void Parse(ProtoReader::BytesView tracePacket); + +private: + const TraceStreamerFilters* streamFilters_; + TraceDataCache* traceDataCache_; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HTRACE_SYMBOLS_DETAIL_PARSER_H diff --git a/trace_streamer/src/parser/parser_base.cpp b/trace_streamer/src/parser/parser_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad069faf44445d560cde48e3520e98aab03e3f17 --- /dev/null +++ b/trace_streamer/src/parser/parser_base.cpp @@ -0,0 +1,21 @@ +/* + * 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 "parser_base.h" +namespace SysTuning { +namespace TraceStreamer { +ParserBase::ParserBase(const TraceStreamerFilters* filter) : streamFilters_(filter), clock_(TS_CLOCK_UNKNOW) {} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/parser_base.h b/trace_streamer/src/parser/parser_base.h new file mode 100644 index 0000000000000000000000000000000000000000..7b00d31353869bb1f59e580e854a69a2fccb315e --- /dev/null +++ b/trace_streamer/src/parser/parser_base.h @@ -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 SRC_PARSER_BASE_H +#define SRC_PARSER_BASE_H +#include +#include +#include "trace_streamer_filters.h" +#include "ts_common.h" +namespace SysTuning { +namespace TraceStreamer { +class ParserBase { +public: + explicit ParserBase(const TraceStreamerFilters* filter); + virtual ~ParserBase() = default; + virtual void ParseTraceDataSegment(std::unique_ptr, size_t size) = 0; + +protected: + virtual void ParseTraceDataItem(const std::string& buffer) = 0; + std::deque packagesBuffer_ = {}; + const TraceStreamerFilters* streamFilters_; + BuiltinClocks clock_; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/parser/print_event_parser.cpp b/trace_streamer/src/parser/print_event_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf3a55046a6a57d6c263f23280878fa968c67ad6 --- /dev/null +++ b/trace_streamer/src/parser/print_event_parser.cpp @@ -0,0 +1,466 @@ +/* + * 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 "print_event_parser.h" +#include "clock_filter.h" +#include "frame_filter.h" +#include "stat_filter.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +PrintEventParser::PrintEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : EventParserBase(dataCache, filter), pointLength_(1), maxPointLength_(2) +{ + eventToFrameFunctionMap_ = { + {recvievVsync_, bind(&PrintEventParser::ReciveVsync, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)}, + {rsOnVsyncEvent_, bind(&PrintEventParser::RSReciveOnVsync, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)}, + {marshRwTransactionData_, bind(&PrintEventParser::OnRwTransaction, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)}, + {rsMainThreadProcessCmd_, bind(&PrintEventParser::OnMainThreadProcessCmd, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)}}; +} + +bool PrintEventParser::ParsePrintEvent(const std::string& comm, + uint64_t ts, + uint32_t pid, + std::string_view event, + const BytraceLine& line) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_RECEIVED); + TracePoint point; + if (GetTracePoint(event, point) != PARSE_SUCCESS) { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_INVALID); + return false; + } + if (point.tgid_) { + streamFilters_->processFilter_->GetOrCreateInternalPid(ts, point.tgid_); + } + switch (point.phase_) { + case 'B': { + uint32_t index = streamFilters_->sliceFilter_->BeginSlice(comm, ts, pid, point.tgid_, INVALID_DATAINDEX, + traceDataCache_->GetDataIndex(point.name_)); + if (index != INVALID_UINT32) { + // add distributed data + traceDataCache_->GetInternalSlicesData()->SetDistributeInfo( + index, point.chainId_, point.spanId_, point.parentSpanId_, point.flag_, point.args_); + if (pid == point.tgid_) { + HandleFrameSliceBeginEvent(point.funcPrefixId_, index, point.funcArgs_, line); + } + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_LOST); + } + break; + } + case 'E': { + uint32_t index = streamFilters_->sliceFilter_->EndSlice(ts, pid, point.tgid_); + if (pid == point.tgid_) { + HandleFrameSliceEndEvent(ts, point.tgid_, pid, index); + } + break; + } + case 'S': { + auto cookie = static_cast(point.value_); + auto index = streamFilters_->sliceFilter_->StartAsyncSlice(ts, pid, point.tgid_, cookie, + traceDataCache_->GetDataIndex(point.name_)); + if (point.name_ == onFrameQueeuStartEvent_ && index != INVALID_UINT64) { + OnFrameQueueStart(ts, index, point.tgid_); + } + break; + } + case 'F': { + auto cookie = static_cast(point.value_); + auto index = streamFilters_->sliceFilter_->FinishAsyncSlice(ts, pid, point.tgid_, cookie, + traceDataCache_->GetDataIndex(point.name_)); + HandleFrameQueueEndEvent(ts, point.tgid_, point.tgid_, index); + break; + } + case 'C': { + DataIndex nameIndex = traceDataCache_->GetDataIndex(point.name_); + uint32_t internalPid = streamFilters_->processFilter_->GetInternalPid(point.tgid_); + if (internalPid != INVALID_ID) { + streamFilters_->processMeasureFilter_->AppendNewMeasureData(internalPid, nameIndex, ts, point.value_); + streamFilters_->processFilter_->AddProcessMemory(internalPid); + } else { + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TRACING_MARK_WRITE, STAT_EVENT_DATA_INVALID); + } + break; + } + default: + TS_LOGD("point missing!"); + return false; + } + return true; +} +void PrintEventParser::SetTraceType(TraceFileType traceType) +{ + traceType_ = traceType; +} +void PrintEventParser::SetTraceClockId(BuiltinClocks clock) +{ + if (clock != clock_) { + clock_ = clock; + } +} +void PrintEventParser::Finish() +{ + eventToFrameFunctionMap_.clear(); + frameCallIds_.clear(); + vsyncSliceIds_.clear(); + streamFilters_->frameFilter_->Finish(); +} +ParseResult PrintEventParser::CheckTracePoint(std::string_view pointStr) const +{ + if (pointStr.size() == 0) { + TS_LOGD("get trace point data size is 0!"); + return PARSE_ERROR; + } + + std::string clockSyncSts = "trace_event_clock_sync"; + if (pointStr.compare(0, clockSyncSts.length(), clockSyncSts.c_str()) == 0) { + TS_LOGD("skip trace point :%s!", clockSyncSts.c_str()); + return PARSE_ERROR; + } + + if (pointStr.find_first_of('B') != 0 && pointStr.find_first_of('E') != 0 && pointStr.find_first_of('C') != 0 && + pointStr.find_first_of('S') != 0 && pointStr.find_first_of('F') != 0) { + TS_LOGD("trace point not supported : [%c] !", pointStr[0]); + return PARSE_ERROR; + } + + if (pointStr.find_first_of('E') != 0 && pointStr.size() == 1) { + TS_LOGD("point string size error!"); + return PARSE_ERROR; + } + + if (pointStr.size() >= maxPointLength_) { + if ((pointStr[1] != '|') && (pointStr[1] != '\n')) { + TS_LOGD("not support data formart!"); + return PARSE_ERROR; + } + } + + return PARSE_SUCCESS; +} + +std::string_view PrintEventParser::GetPointNameForBegin(std::string_view pointStr, size_t tGidlength) const +{ + size_t index = maxPointLength_ + tGidlength + pointLength_; + + size_t length = pointStr.size() - index - ((pointStr.back() == '\n') ? 1 : 0); + std::string_view name = std::string_view(pointStr.data() + index, length); + return name; +} + +ParseResult PrintEventParser::HandlerB(std::string_view pointStr, TracePoint& outPoint, size_t tGidlength) const +{ + outPoint.name_ = GetPointNameForBegin(pointStr, tGidlength); + if (outPoint.name_.empty()) { + TS_LOGD("point name is empty!"); + return PARSE_ERROR; + } + // Use $# to differentiate distributed data + if (outPoint.name_.find("$#") == std::string::npos) { + auto space = outPoint.name_.find(' '); + if (space != std::string::npos) { + outPoint.funcPrefix_ = outPoint.name_.substr(0, space); + outPoint.funcPrefixId_ = traceDataCache_->GetDataIndex(outPoint.funcPrefix_); + outPoint.funcArgs_ = outPoint.name_.substr(space + 1, -1); + } else { + outPoint.funcPrefixId_ = traceDataCache_->GetDataIndex(outPoint.name_); + } + return PARSE_SUCCESS; + } + // Resolve distributed calls + // the normal data mybe like: + // system-1298 ( 1298) [001] ...1 174330.287420: tracing_mark_write: B|1298|[8b00e96b2,2,1]:C$#decodeFrame$#" + // "{\"Process\":\"DecodeVideoFrame\",\"frameTimestamp\":37313484466} \ + // system - 1298(1298)[001]... 1 174330.287622 : tracing_mark_write : E | 1298 \n + const std::regex distributeMatcher = std::regex(R"((?:^\[([a-z0-9]+),(\d+),(\d+)\]:?([CS]?)\$#)?(.*)\$#(.*)$)"); + std::smatch matcheLine; + bool matched = std::regex_match(outPoint.name_, matcheLine, distributeMatcher); + if (matched) { + size_t index = 0; + outPoint.chainId_ = matcheLine[++index].str(); + outPoint.spanId_ = matcheLine[++index].str(); + outPoint.parentSpanId_ = matcheLine[++index].str(); + outPoint.flag_ = matcheLine[++index].str(); + outPoint.name_ = matcheLine[++index].str(); + outPoint.args_ = matcheLine[++index].str(); + } + return PARSE_SUCCESS; +} + +void PrintEventParser::HandleFrameSliceBeginEvent(DataIndex eventName, + size_t callStackRow, + std::string& args, + const BytraceLine& line) +{ + auto it = eventToFrameFunctionMap_.find(eventName); + if (it != eventToFrameFunctionMap_.end()) { + it->second(callStackRow, args, line); + } +} +bool PrintEventParser::ReciveVsync(size_t callStackRow, std::string& args, const BytraceLine& line) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_VSYNC, STAT_EVENT_RECEIVED); + // args is like "dataCount:24bytes now:211306766162 expectedEnd:211323423844 vsyncId:3179" + TS_LOGD("ts:%lu tid:%d, %s callStackRow:%lu", line.ts, line.pid, args.c_str(), callStackRow); + std::sregex_iterator it(args.begin(), args.end(), recvVsyncPattern_); + std::sregex_iterator end; + uint64_t now = INVALID_UINT64; + uint64_t expectEnd = INVALID_UINT64; + uint32_t vsyncId = INVALID_UINT32; + while (it != end) { + std::smatch match = *it; + std::string key = match.str(1); + std::string value = match.str(2); + if (key == "now") { + now = base::StrToUInt64(value).value(); + } else if (key == "expectedEnd") { + expectEnd = base::StrToUInt64(value).value(); + } else if (key == "vsyncId") { + vsyncId = base::StrToUInt64(value).value(); + } + ++it; + } + if (convertVsyncTs_ && traceType_ == TRACE_FILETYPE_H_TRACE) { + if (now != INVALID_UINT64) { + now = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, now); + } + if (expectEnd != INVALID_UINT64) { + expectEnd = streamFilters_->clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, expectEnd); + } + } + auto iTid = streamFilters_->processFilter_->GetInternalTid(line.pid); + auto iPid = streamFilters_->processFilter_->GetInternalPid(line.tgid); + streamFilters_->frameFilter_->BeginVsyncEvent(line.ts, iPid, iTid, now, expectEnd, vsyncId, callStackRow); + vsyncSliceIds_.push_back(callStackRow); + return true; +} +bool PrintEventParser::RSReciveOnVsync(size_t callStackRow, std::string& args, const BytraceLine& line) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_ONVSYNC, STAT_EVENT_RECEIVED); + TS_LOGD("ts:%lu tid:%d, %s callStackRow:%lu", line.ts, line.pid, args.c_str(), callStackRow); + auto iTid = streamFilters_->processFilter_->GetInternalTid(line.pid); + (void)streamFilters_->frameFilter_->MarkRSOnvsyncEvent(line.ts, iTid); + return true; +} +bool PrintEventParser::OnRwTransaction(size_t callStackRow, std::string& args, const BytraceLine& line) +{ + // H:MarshRSTransactionData cmdCount:20 transactionFlag:[3799,8] isUni:1 + TS_LOGD("ts:%lu tid:%d, %s callStackRow:%lu", line.ts, line.pid, args.c_str(), callStackRow); + std::smatch match; + if (std::regex_search(args, match, transFlagPattern_)) { + std::string flag2 = match.str(2); + auto iTid = streamFilters_->processFilter_->GetInternalTid(line.pid); + return streamFilters_->frameFilter_->BeginRSTransactionData(line.ts, iTid, base::StrToUInt32(flag2).value()); + } + return true; +} +bool PrintEventParser::OnMainThreadProcessCmd(size_t callStackRow, std::string& args, const BytraceLine& line) +{ + TS_LOGD("ts:%lu tid:%d, %s callStackRow:%lu", line.ts, line.pid, args.c_str(), callStackRow); + std::sregex_iterator it(args.begin(), args.end(), mainProcessCmdPattern); + std::sregex_iterator end; + std::vector frames; + while (it != end) { + std::smatch match = *it; + std::string value1 = match.str(1); + std::string value2 = match.str(2); + frames.push_back({streamFilters_->processFilter_->GetInternalTid(base::StrToUInt32(value1).value()), + base::StrToUInt32(value2).value()}); + ++it; + } + auto iTid = streamFilters_->processFilter_->GetInternalTid(line.pid); + return streamFilters_->frameFilter_->BeginProcessCommandUni(line.ts, iTid, frames, callStackRow); +} +bool PrintEventParser::OnFrameQueueStart(uint64_t ts, size_t callStackRow, uint64_t pid) +{ + streamFilters_->statFilter_->IncreaseStat(TRACE_FRAMEQUEUE, STAT_EVENT_RECEIVED); + TS_LOGD("ts:%llu tid:%llu, callStackRow:%zu", ts, pid, callStackRow); + auto iTid = streamFilters_->processFilter_->GetInternalTid(pid); + if (streamFilters_->frameFilter_->StartFrameQueue(ts, iTid)) { + frameCallIds_.push_back(callStackRow); + } + return true; +} +void PrintEventParser::HandleFrameSliceEndEvent(uint64_t ts, uint64_t pid, uint64_t tid, size_t callStackRow) +{ + // it can be frame or slice + auto iTid = streamFilters_->processFilter_->GetInternalTid(tid); + auto pos = std::find(vsyncSliceIds_.begin(), vsyncSliceIds_.end(), callStackRow); + if (pos != vsyncSliceIds_.end()) { + TS_LOGD("ts:%llu, RenderSliceEnd:%llu, callStackRow:%zu", ts, tid, callStackRow); + if (!streamFilters_->frameFilter_->EndVsyncEvent(ts, iTid)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_VSYNC, STAT_EVENT_NOTMATCH); + TS_LOGW("ts:%llu, RenderSliceEnd:%llu, callStackRow:%zu failed", ts, tid, callStackRow); + } + vsyncSliceIds_.erase(pos); + } + return; +} + +void PrintEventParser::HandleFrameQueueEndEvent(uint64_t ts, uint64_t pid, uint64_t tid, size_t callStackRow) +{ + // it can be frame or slice + auto iTid = streamFilters_->processFilter_->GetInternalTid(tid); + auto pos = std::find(frameCallIds_.begin(), frameCallIds_.end(), callStackRow); + if (pos != frameCallIds_.end()) { + TS_LOGD("ts:%llu, frameSliceEnd:%u", ts, tid); + if (!streamFilters_->frameFilter_->EndFrameQueue(ts, iTid)) { + streamFilters_->statFilter_->IncreaseStat(TRACE_FRAMEQUEUE, STAT_EVENT_NOTMATCH); + TS_LOGW("ts:%llu, frameSliceEnd:%lu failed", ts, tid); + } + frameCallIds_.erase(pos); + } + return; +} +ParseResult PrintEventParser::HandlerE(void) +{ + return PARSE_SUCCESS; +} + +size_t PrintEventParser::GetNameLength(std::string_view pointStr, size_t nameIndex) +{ + size_t namelength = 0; + for (size_t i = nameIndex; i < pointStr.size(); i++) { + if (pointStr[i] == ' ') { + namelength = i - nameIndex; + } + if (pointStr[i] == '|') { + namelength = i - nameIndex; + break; + } + } + return namelength; +} + +size_t PrintEventParser::GetValueLength(std::string_view pointStr, size_t valueIndex) const +{ + size_t valuePipe = pointStr.find('|', valueIndex); + size_t valueLen = pointStr.size() - valueIndex; + if (valuePipe != std::string_view::npos) { + valueLen = valuePipe - valueIndex; + } + + if (valueLen == 0) { + return 0; + } + + if (pointStr[valueIndex + valueLen - pointLength_] == '\n') { + valueLen--; + } + + return valueLen; +} + +ParseResult PrintEventParser::HandlerCSF(std::string_view pointStr, TracePoint& outPoint, size_t tGidlength) const +{ + // point name + size_t nameIndex = maxPointLength_ + tGidlength + pointLength_; + size_t namelength = GetNameLength(pointStr, nameIndex); + if (namelength == 0) { + TS_LOGD("point name length is error!"); + return PARSE_ERROR; + } + outPoint.name_ = std::string_view(pointStr.data() + nameIndex, namelength); + + // point value + size_t valueIndex = nameIndex + namelength + pointLength_; + size_t valueLen = GetValueLength(pointStr, valueIndex); + if (valueLen == 0) { + TS_LOGD("point value length is error!"); + return PARSE_ERROR; + } + + std::string valueStr(pointStr.data() + valueIndex, valueLen); + if (!base::StrToUInt64(valueStr).has_value()) { + TS_LOGD("point value is error!"); + return PARSE_ERROR; + } + outPoint.value_ = base::StrToUInt64(valueStr).value(); + + size_t valuePipe = pointStr.find('|', valueIndex); + if (valuePipe != std::string_view::npos) { + size_t groupLen = pointStr.size() - valuePipe - pointLength_; + if (groupLen == 0) { + return PARSE_ERROR; + } + + if (pointStr[pointStr.size() - pointLength_] == '\n') { + groupLen--; + } + + outPoint.categoryGroup_ = std::string_view(pointStr.data() + valuePipe + 1, groupLen); + } + + return PARSE_SUCCESS; +} + +ParseResult PrintEventParser::GetTracePoint(std::string_view pointStr, TracePoint& outPoint) const +{ + if (CheckTracePoint(pointStr) != PARSE_SUCCESS) { + return PARSE_ERROR; + } + + size_t tGidlength = 0; + // we may get wrong format data like tracing_mark_write: E + // while the format data must be E|call-tid + // please use a regular-format to get all the data + outPoint.phase_ = pointStr.front(); + outPoint.tgid_ = GetThreadGroupId(pointStr, tGidlength); + + ParseResult ret = PARSE_ERROR; + switch (outPoint.phase_) { + case 'B': { + ret = HandlerB(pointStr, outPoint, tGidlength); + break; + } + case 'E': { + ret = HandlerE(); + break; + } + case 'S': + case 'F': + case 'C': { + ret = HandlerCSF(pointStr, outPoint, tGidlength); + break; + } + default: + return PARSE_ERROR; + } + return ret; +} + +uint32_t PrintEventParser::GetThreadGroupId(std::string_view pointStr, size_t& length) const +{ + for (size_t i = maxPointLength_; i < pointStr.size(); i++) { + if (pointStr[i] == '|' || pointStr[i] == '\n') { + break; + } + + if (pointStr[i] < '0' || pointStr[i] > '9') { + return PARSE_ERROR; + } + + length++; + } + + std::string str(pointStr.data() + maxPointLength_, length); + return base::StrToUInt32(str).value_or(0); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/print_event_parser.h b/trace_streamer/src/parser/print_event_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..fca52f7da10c98f1184443187b9fd671b3532163 --- /dev/null +++ b/trace_streamer/src/parser/print_event_parser.h @@ -0,0 +1,86 @@ +/* + * 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 SRC_PRINT_EVENT_PARSER_H +#define SRC_PRINT_EVENT_PARSER_H +#include +#include +#include "common_types.h" +#include "event_parser_base.h" +#include "filter/measure_filter.h" +#include "filter/process_filter.h" +#include "filter/slice_filter.h" +#include "string_to_numerical.h" +#include "trace_streamer_config.h" +namespace SysTuning { +namespace TraceStreamer { +class PrintEventParser : private EventParserBase { +public: + PrintEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter); + bool ParsePrintEvent(const std::string& comm, + uint64_t ts, + uint32_t pid, + std::string_view event, + const BytraceLine& line); + void Finish(); + void SetTraceType(TraceFileType traceType); + void SetTraceClockId(BuiltinClocks clock); + +private: + using FrameFuncCall = std::function; + ParseResult GetTracePoint(std::string_view pointStr, TracePoint& outPoint) const; + ParseResult CheckTracePoint(std::string_view pointStr) const; + uint32_t GetThreadGroupId(std::string_view pointStr, size_t& length) const; + std::string_view GetPointNameForBegin(std::string_view pointStr, size_t tGidlength) const; + ParseResult HandlerB(std::string_view pointStr, TracePoint& outPoint, size_t tGidlength) const; + void HandleFrameSliceBeginEvent(DataIndex eventName, + size_t callStackRow, + std::string& args, + const BytraceLine& line); + void HandleFrameSliceEndEvent(uint64_t ts, uint64_t pid, uint64_t tid, size_t callStackRow); + void HandleFrameQueueEndEvent(uint64_t ts, uint64_t pid, uint64_t tid, size_t callStackRow); + static ParseResult HandlerE(void); + ParseResult HandlerCSF(std::string_view pointStr, TracePoint& outPoint, size_t tGidlength) const; + static size_t GetNameLength(std::string_view pointStr, size_t nameIndex); + size_t GetValueLength(std::string_view pointStr, size_t valueIndex) const; + bool ReciveVsync(size_t callStackRow, std::string& args, const BytraceLine& line); + bool RSReciveOnVsync(size_t callStackRow, std::string& args, const BytraceLine& line); + bool OnRwTransaction(size_t callStackRow, std::string& args, const BytraceLine& line); + bool OnMainThreadProcessCmd(size_t callStackRow, std::string& args, const BytraceLine& line); + bool OnFrameQueueStart(uint64_t ts, size_t callStackRow, uint64_t pid); + +private: + std::map eventToFrameFunctionMap_ = {}; + const uint32_t pointLength_; + const uint32_t maxPointLength_; + TraceStreamerConfig config_{}; + const DataIndex recvievVsync_ = traceDataCache_->GetDataIndex("H:ReceiveVsync"); + const DataIndex rsOnVsyncEvent_ = traceDataCache_->GetDataIndex("H:RSMainThread::OnVsync"); + const std::string onFrameQueeuStartEvent_ = "H:M: Frame queued"; + const DataIndex marshRwTransactionData_ = traceDataCache_->GetDataIndex("H:MarshRSTransactionData"); + const DataIndex rsMainThreadProcessCmd_ = traceDataCache_->GetDataIndex("H:RSMainThread::ProcessCommandUni"); + const std::regex recvVsyncPattern_ = std::regex("(\\w+):(\\w+)"); + const std::regex transFlagPattern_ = std::regex("transactionFlag:\\[(\\d+),(\\d+)\\]"); + const std::regex mainProcessCmdPattern = std::regex("\\[(\\d+),(\\d+)\\]"); + std::vector frameCallIds_ = {}; + std::vector vsyncSliceIds_ = {}; + TraceFileType traceType_ = TRACE_FILETYPE_H_TRACE; + BuiltinClocks clock_ = TS_CLOCK_BOOTTIME; + // if convert vsync's now and expectEnd + bool convertVsyncTs_ = true; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_PRINT_EVENT_PARSER_H diff --git a/trace_streamer/src/parser/thread_state.cpp b/trace_streamer/src/parser/thread_state.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a373a7855acd5ae90291c03526b82dbb94b5895a --- /dev/null +++ b/trace_streamer/src/parser/thread_state.cpp @@ -0,0 +1,60 @@ +/* + * 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 "thread_state.h" + +namespace SysTuning { +namespace TraceStreamer { +Direction ThreadState::SetStatByChar(char ch) +{ + if (ch == 'R') { + if (state_ == 0) { + return NEED_CONTINUE; + } + } + + if (statMap_.find(ch) == statMap_.end()) { + return NEED_BREAK; + } + + state_ |= statMap_[ch]; + return NEED_GO; +} + +void ThreadState::ProcessSate(const std::string& stateStr) +{ + for (size_t i = 0; i < stateStr.size(); i++) { + if (stateStr[i] == '+') { + invalid_ = true; + SetStat(TASKNEW); + continue; + } + + Direction ret = SetStatByChar(stateStr[i]); + if (ret == NEED_CONTINUE) { + invalid_ = true; + continue; + } else if (ret == NEED_BREAK) { + break; + } + } +} + +ThreadState::ThreadState(const std::string& stateStr) +{ + ProcessSate(stateStr); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/parser/thread_state.h b/trace_streamer/src/parser/thread_state.h new file mode 100644 index 0000000000000000000000000000000000000000..23a741534950ae38d545d69a4b500dc9c42738ca --- /dev/null +++ b/trace_streamer/src/parser/thread_state.h @@ -0,0 +1,86 @@ +/* + * 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 BYTRACE_THREAD_STATES_H +#define BYTRACE_THREAD_STATES_H + +#include +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Direction { NEED_GO = 0, NEED_CONTINUE, NEED_BREAK }; +enum Stat : uint32_t { + RUNNABLE = 0, + INTERRUPTABLESLEEP = 1, + UNINTERRUPTIBLESLEEP = 2, + STOPPED = 4, + TRACED = 8, // the process is being debug + EXITDEAD = 16, + EXITZOMBIE = 32, + TASKDEAD = 64, + WAKEKILL = 128, + WAKING = 256, + PARKED = 512, + NOLOAD = 1024, + TASKNEW = 2048, + VALID = 0X8000, +}; +class ThreadState { +public: + explicit ThreadState(const std::string& stateStr); + ~ThreadState() {} + + uint32_t State() const + { + return state_ & ~VALID; + } + bool IsValid() const + { + return invalid_; + } + +private: + void SetStat(Stat value) + { + state_ |= value; + } + + void ProcessSate(const std::string& stateStr); + Direction SetStatByChar(char ch); + +private: + uint32_t state_ = 0; + std::map statMap_ = { + {'R', RUNNABLE}, + {'S', INTERRUPTABLESLEEP}, + {'D', UNINTERRUPTIBLESLEEP}, + {'T', STOPPED}, + {'t', TRACED}, + {'X', EXITDEAD}, + {'Z', EXITZOMBIE}, + {'x', TASKDEAD}, + {'I', TASKDEAD}, + {'K', WAKEKILL}, + {'P', PARKED}, + {'N', NOLOAD}, + {'|', VALID}, + }; + bool invalid_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // _BYTRACE_THREAD_STATES_H_ diff --git a/trace_streamer/src/proto_reader/BUILD.gn b/trace_streamer/src/proto_reader/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..81d1eabca399089bfbc0a98bf15d2850723e5a62 --- /dev/null +++ b/trace_streamer/src/proto_reader/BUILD.gn @@ -0,0 +1,28 @@ +# 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("//src/ts.gni") +ohos_source_set("proto_reader") { + subsystem_name = "trace_streamer" + part_name = "proto_reader" + public_configs = [ "../../gn:default_config" ] + public_deps = [] + include_dirs = [ "include" ] + deps = [ "../../gn:default_deps" ] + sources = [ "proto_reader.cpp" ] + include_dirs += [ + "../include", + "../base", + ] +} diff --git a/trace_streamer/src/proto_reader/include/data_area.h b/trace_streamer/src/proto_reader/include/data_area.h new file mode 100644 index 0000000000000000000000000000000000000000..1a3ac3fec63f7526391b8f81f9c089d682d9259f --- /dev/null +++ b/trace_streamer/src/proto_reader/include/data_area.h @@ -0,0 +1,214 @@ +/* + * 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 PROTO_READER_FIELD_H +#define PROTO_READER_FIELD_H + +#include +#include +#include +#include "proto_reader_help.h" +#include "string_help.h" +namespace SysTuning { +namespace ProtoReader { +class DataArea { +public: + bool DataAreaValid() const + { + return dataAreaID_ != 0; + } + uint16_t DataAreaId() const + { + return dataAreaID_; + } + explicit operator bool() const + { + return DataAreaValid(); + } + + ProtoWireType Type() const + { + auto res = static_cast(type_); + return res; + } + + bool ToBool() const + { + return static_cast(intValue_); + } + + uint32_t ToUint32() const + { + return static_cast(intValue_); + } + + int32_t ToInt32() const + { + return static_cast(intValue_); + } + + int32_t ToSint32() const + { + return ZigZagDecode(static_cast(intValue_)); + } + + uint64_t ToUint64() const + { + return intValue_; + } + + int64_t ToInt64() const + { + return static_cast(intValue_); + } + + int64_t ToSint64() const + { + return ZigZagDecode(static_cast(intValue_)); + } + + float ToFloat() const + { + float res; + uint32_t value32 = static_cast(intValue_); + (void*)memcpy_s(&res, sizeof(res), &value32, sizeof(value32)); + return res; + } + + double ToDouble() const + { + double res; + (void*)memcpy_s(&res, sizeof(res), &intValue_, sizeof(intValue_)); + return res; + } + + CharsView ToString() const + { + return CharsView{reinterpret_cast(Data()), size_}; + } + + std::string ToStdString() const + { + return ToString().ToStdString(); + } + + BytesView ToBytes() const + { + return BytesView(Data(), size_); + } + + const uint8_t* Data() const + { + return reinterpret_cast(intValue_); + } + + size_t Size() const + { + return size_; + } + + uint64_t RawIntValue() const + { + return intValue_; + } + + void SetDataAreaId(uint16_t id) + { + dataAreaID_ = id; + } + void SetDataAreaType(uint8_t type) + { + type_ = type; + } + void SetDataAreaIntValue(uint64_t intValue) + { + intValue_ = intValue; + } + void SetDataAreaSize(uint32_t size) + { + size_ = size; + } + void Initialize(uint16_t id, uint8_t type, uint64_t intValue, uint32_t size) + { + dataAreaID_ = id; + type_ = type; + intValue_ = intValue; + size_ = size; + } + + void GetValue(bool* val) const + { + *val = ToBool(); + } + void GetValue(uint32_t* val) const + { + *val = ToUint32(); + } + void GetValue(int32_t* val) const + { + *val = ToInt32(); + } + void GetValue(uint64_t* val) const + { + *val = ToUint64(); + } + void GetValue(int64_t* val) const + { + *val = ToInt64(); + } + void GetValue(float* val) const + { + *val = ToFloat(); + } + void GetValue(double* val) const + { + *val = ToDouble(); + } + void GetValue(std::string* val) const + { + *val = ToStdString(); + } + void GetValue(CharsView* val) const + { + *val = ToString(); + } + void GetValue(BytesView* val) const + { + *val = ToBytes(); + } + void GetSignedValue(int32_t* val) const + { + *val = ToSint32(); + } + void GetSignedValue(int64_t* val) const + { + *val = ToSint64(); + } + + template ::value, T>::type> + void getT(T* val) const + { + *val = static_cast(ToInt32()); + } + +private: + uint64_t intValue_; + uint32_t size_; + uint16_t dataAreaID_; + uint8_t type_; +}; +} // namespace ProtoReader +} // namespace SysTuning +#endif // PROTO_READER_FIELD_H diff --git a/trace_streamer/src/proto_reader/include/proto_reader.h b/trace_streamer/src/proto_reader/include/proto_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..30703e555752c563e3ded8535c2644b2cd204d4f --- /dev/null +++ b/trace_streamer/src/proto_reader/include/proto_reader.h @@ -0,0 +1,299 @@ +/* + * 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 TS_PROTO_READER_H_ +#define TS_PROTO_READER_H_ + +#include +#include +#include +#include +#include + +#include "data_area.h" +#include "log.h" +#include "proto_reader_help.h" + +namespace SysTuning { +namespace ProtoReader { +constexpr uint8_t DATA_AREA_TYPE_BITS = 3; +constexpr uint8_t DATA_AREA_TYPE_VALUE = 7; +constexpr uint32_t INVALID_DATA_AREA_ID = 0; +constexpr uint8_t BYTE_HIGHEST_BIT_MARK = 0x80; +const std::map fixedTypeToSizeMap_ = {{ProtoWireType::kFixed32, sizeof(uint32_t)}, + {ProtoWireType::kFixed64, sizeof(uint64_t)}}; +template +class RepeatedDataAreaIterator { +public: + RepeatedDataAreaIterator() = default; + RepeatedDataAreaIterator(uint32_t dataAreaId, + const DataArea* currentAddr, + const DataArea* endAddr, + const DataArea* lastAddr) + : dataAreaId_(dataAreaId), currentAddr_(currentAddr), endAddr_(endAddr), lastAddr_(lastAddr) + { + FindNextMatchingDataAreaId(); + } + + explicit operator bool() const + { + return currentAddr_ != endAddr_; + } + const DataArea& GetDataArea() const + { + return *currentAddr_; + } + + T operator*() const + { + T value{}; + currentAddr_->GetValue(&value); + return value; + } + const DataArea* operator->() const + { + return currentAddr_; + } + + RepeatedDataAreaIterator& operator++() + { + if (currentAddr_ != lastAddr_) { + currentAddr_++; + FindNextMatchingDataAreaId(); + return *this; + } + currentAddr_ = endAddr_; + return *this; + } + + RepeatedDataAreaIterator operator++(int32_t) + { + RepeatedDataAreaIterator itor(*this); + ++(*this); + return itor; + } + +private: + void FindNextMatchingDataAreaId() + { + while (currentAddr_ != endAddr_) { + if (currentAddr_->DataAreaId() == dataAreaId_) { + return; + } + ++currentAddr_; + } + currentAddr_ = lastAddr_->DataAreaValid() ? lastAddr_ : endAddr_; + } + + uint32_t dataAreaId_ = INVALID_DATA_AREA_ID; + const DataArea* currentAddr_ = nullptr; + const DataArea* endAddr_ = nullptr; + const DataArea* lastAddr_ = nullptr; +}; + +template +class PackedRepeatedDataAreaIterator { +public: + PackedRepeatedDataAreaIterator(const uint8_t* startAddr, size_t length, bool* parseStatus) + : endAddr_(startAddr ? startAddr + length : nullptr), currentReadAddr_(startAddr), parseStatus_(parseStatus) + { + static_assert(wireType != ProtoWireType::kLengthDelimited, "invalid type"); + + if (length == 0) { + currentValueValid_ = false; + return; + } + auto itor = fixedTypeToSizeMap_.find(wireType); + if (itor != fixedTypeToSizeMap_.end() && (length % itor->second)) { + *parseStatus_ = false; + currentValueValid_ = false; + return; + } + ++(*this); + } + + const cppType operator*() const + { + return currentValue_; + } + explicit operator bool() const + { + return currentValueValid_; + } + + PackedRepeatedDataAreaIterator& operator++() + { + if (!currentValueValid_) { + return *this; + } + + if (currentReadAddr_ == endAddr_) { + currentValueValid_ = false; + return *this; + } + + if (wireType == ProtoWireType::kVarInt) { + uint64_t newValue = 0; + const uint8_t* nextPos = VarIntDecode(currentReadAddr_, endAddr_, &newValue); + + if (nextPos != currentReadAddr_) { + currentReadAddr_ = nextPos; + currentValue_ = static_cast(newValue); + } else { + *parseStatus_ = true; + currentValueValid_ = false; + } + } else { // kFixed32 or kFixed64 + auto step = fixedTypeToSizeMap_.at(wireType); + memcpy(¤tValue_, currentReadAddr_, sizeof(cppType)); + currentReadAddr_ += step; + } + + return *this; + } + + PackedRepeatedDataAreaIterator operator++(int32_t) + { + PackedRepeatedDataAreaIterator itor(*this); + ++(*this); + return itor; + } + +private: + const uint8_t* const endAddr_; + const uint8_t* currentReadAddr_; + cppType currentValue_ = 0; + bool currentValueValid_ = true; + bool* const parseStatus_; +}; + +enum ParseProtoStatus { ABORT, SKIP, OK }; +struct ParseDataAreaResult { + ParseProtoStatus status; + const uint8_t* next; + DataArea dataArea; +}; + +class ProtoReaderBase { +public: + ProtoReaderBase() : startAddr_(0), endAddr_(0) {} + ProtoReaderBase(DataArea* storage, uint32_t dataAreasCount, const uint8_t* buffer, size_t length); + const uint8_t* GetStartAddr() const + { + return startAddr_; + } + const uint8_t* GetEndAddr() const + { + return endAddr_; + } + void ResetCurrentAddr() + { + currentReadAddr_ = startAddr_; + } + + void ResetCurrentAddr(const uint8_t* pos) + { + currentReadAddr_ = pos; + } + + size_t GetCurrentOffset() const + { + return static_cast(currentReadAddr_ - startAddr_); + } + + size_t GetCurrentLeft() const + { + return static_cast(endAddr_ - currentReadAddr_); + } + + DataArea ReadNextDataArea(); + DataArea FindDataArea(uint32_t dataAreaId); + const DataArea& Get(uint32_t id) const + { + if (id < dataAreasCount_) { + return dataAreas_[id]; + } + return dataAreas_[0]; + } + + template + RepeatedDataAreaIterator GetRepeated(uint32_t dataAreaId) const + { + return RepeatedDataAreaIterator(dataAreaId, &dataAreas_[dataAreasCount_], &dataAreas_[size_], + &dataAreas_[dataAreaId]); + } + + template + PackedRepeatedDataAreaIterator GetPackedRepeated(uint32_t dataAreaId, bool* parseErrorAddr) const + { + const DataArea& dataArea = Get(dataAreaId); + if (dataArea.DataAreaValid()) { + return PackedRepeatedDataAreaIterator(dataArea.Data(), dataArea.Size(), parseErrorAddr); + } else { + return PackedRepeatedDataAreaIterator(nullptr, 0, parseErrorAddr); + } + } + +protected: + ParseDataAreaResult ParseOneDataArea(const uint8_t* const startAddr, const uint8_t* const endAddr); + void ParseAllDataAreas(); + void MoveToLargerHeapStorage(); + + const uint8_t* const startAddr_; + const uint8_t* const endAddr_; + const uint8_t* currentReadAddr_ = nullptr; + std::unique_ptr lagerHeapStorage_; + DataArea* dataAreas_; + uint32_t dataAreasCount_; + uint32_t size_; + uint32_t volume_; + +private: + const uint8_t* GetNextProtoTag(const uint8_t* const startAddr, const uint8_t* const endAddr, uint64_t* dataAreaTag); + bool ParseVarIntValue(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr); + bool ParseLengthDelimitedValue(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr); + bool ParseFixed64Value(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr); + bool ParseFixed32Value(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr); + using ParseDataAreaValueByType = std::function; + std::map dataAreaTypeToParseFuncMap_ = {}; +}; + +template +class TypedProtoReader : public ProtoReaderBase { +public: + TypedProtoReader(const uint8_t* buffer, size_t length) + : ProtoReaderBase(defaultStorage_, MAX_DATA_AREA_ID + 1, buffer, length) + { + ProtoReaderBase::ParseAllDataAreas(); + } + TypedProtoReader(TypedProtoReader&& other) noexcept : ProtoReaderBase(std::move(other)) + { + if (dataAreas_ == other.defaultStorage_) { + dataAreas_ = defaultStorage_; + memcpy_s(defaultStorage_, sizeof(defaultStorage_), other.defaultStorage_, sizeof(defaultStorage_)); + } + } + template + const DataArea& at() const + { + return dataAreas_[DATA_AREA_ID]; + } + +private: + DataArea defaultStorage_[MAX_DATA_AREA_ID + 1]; +}; +} // namespace ProtoReader +} // namespace SysTuning +#endif // TS_PROTO_READER_H_ diff --git a/trace_streamer/src/proto_reader/include/proto_reader_help.h b/trace_streamer/src/proto_reader/include/proto_reader_help.h new file mode 100644 index 0000000000000000000000000000000000000000..9ece9fa4d691134d9e7eaf971b744ec5a5524504 --- /dev/null +++ b/trace_streamer/src/proto_reader/include/proto_reader_help.h @@ -0,0 +1,165 @@ +/* + * 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 PROTO_READER_HELP_H +#define PROTO_READER_HELP_H + +#include +#include +#include + +namespace SysTuning { +namespace ProtoReader { +class BytesView { +public: + BytesView() : data_(nullptr), size_(0) {} + BytesView(const uint8_t* data, size_t size) : data_(data), size_(size) {} + BytesView(const BytesView& bytesView) + { + data_ = bytesView.data_; + size_ = bytesView.size_; + } + BytesView& operator=(const BytesView& bytesView) + { + data_ = bytesView.data_; + size_ = bytesView.size_; + return *this; + } + std::string ToStdString() const + { + return std::string(reinterpret_cast(data_), size_); + } + size_t Size() const + { + return size_; + } + const uint8_t* Data() const + { + return data_; + } + const uint8_t* data_; + size_t size_; +}; + +struct CharsView { + std::string ToStdString() const + { + return std::string(data, size); + } + + const char* data; + size_t size; +}; + +enum class ProtoWireType : uint8_t { + kVarInt = 0, + kFixed64 = 1, + kLengthDelimited = 2, + kFixed32 = 5, +}; + +inline uint32_t CreateTagVarInt(uint32_t DataAreaId) +{ + return (DataAreaId << 3) | static_cast(ProtoWireType::kVarInt); +} + +inline std::vector TableNameSplitToVec(std::string& str, const std::string& pat) +{ + std::string::size_type pos; + std::vector result; + str += pat; + int32_t size = str.size(); + for (int32_t i = 0; i < size; i++) { + pos = str.find(pat, i); + if (pos == std::string::npos) { + break; + } + if (pos < size) { + std::string s = str.substr(i, pos - i); + result.push_back(s); + i = pos + pat.size() - 1; + } + } + return result; +} + +inline char Lowercase(char c) +{ + return ('A' <= c && c <= 'Z') ? static_cast(c - ('A' - 'a')) : c; +} + +inline char Uppercase(char c) +{ + return ('a' <= c && c <= 'z') ? static_cast(c + ('A' - 'a')) : c; +} + +inline std::string ToUppercase(const std::string& str) +{ + std::string string(str); + auto end = string.end(); + for (auto c = string.begin(); c != end; ++c) + *c = Uppercase(*c); + return string; +} + +inline std::string ToLowercase(const std::string& str) +{ + std::string string(str); + auto end = string.end(); + for (auto c = string.begin(); c != end; ++c) + *c = Lowercase(*c); + return string; +} + +constexpr size_t kMessageLengthFieldSize = 4; +constexpr size_t kMaxMessageLength = (1u << (kMessageLengthFieldSize * 7)) - 1; + +constexpr size_t kMaxTagEncodedSize = 5; +constexpr size_t kMaxSimpleFieldEncodedSize = kMaxTagEncodedSize + 10; + +template +inline typename std::make_signed::type ZigZagDecode(T value) +{ + using UnsignedType = typename std::make_unsigned::type; + using SignedType = typename std::make_signed::type; + auto unsignedValue = static_cast(value); + auto unsignedmask = static_cast(-static_cast(unsignedValue & 1)); + return static_cast((unsignedValue >> 1) ^ unsignedmask); +} + +constexpr uint8_t varIntValueBits = 7; +constexpr uint8_t varIntValueMask = 0x7f; // 111 1111b +constexpr uint8_t varIntValueDecodeMaxOffset = 64; +constexpr uint8_t byteHighestBitMark = 0x80; // 1000 0000b +inline const uint8_t* VarIntDecode(const uint8_t* start, const uint8_t* end, uint64_t* varIntValue) +{ + const uint8_t* cursor = start; + uint64_t temp = 0; + uint32_t shift = 0; + do { + uint8_t currentByte = *cursor++; + temp |= static_cast(currentByte & varIntValueMask) << shift; + if (!(currentByte & byteHighestBitMark)) { + *varIntValue = temp; + return cursor; + } + shift += varIntValueBits; + } while (cursor < end && shift < varIntValueDecodeMaxOffset); + *varIntValue = 0; + return start; +} +} // namespace ProtoReader +} // namespace SysTuning +#endif // PROTO_READER_HELP_H diff --git a/trace_streamer/src/proto_reader/proto_reader.cpp b/trace_streamer/src/proto_reader/proto_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c0db3284127dc5198045e39a56dd167f5245f86 --- /dev/null +++ b/trace_streamer/src/proto_reader/proto_reader.cpp @@ -0,0 +1,236 @@ +/* + * 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 "proto_reader.h" +#include "optimize.h" + +namespace SysTuning { +namespace ProtoReader { +ProtoReaderBase::ProtoReaderBase(DataArea* storage, uint32_t dataAreasCount, const uint8_t* buffer, size_t length) + : startAddr_(buffer), + endAddr_(startAddr_ + length), + currentReadAddr_(startAddr_), + dataAreas_(storage), + dataAreasCount_(dataAreasCount), + size_(dataAreasCount), + volume_(dataAreasCount) +{ + auto dataAreasSize = sizeof(DataArea) * dataAreasCount_; + (void)memset_s(dataAreas_, dataAreasSize, 0, dataAreasSize); + dataAreaTypeToParseFuncMap_ = { + {ProtoWireType::kVarInt, std::bind(&ProtoReaderBase::ParseVarIntValue, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)}, + {ProtoWireType::kLengthDelimited, + std::bind(&ProtoReaderBase::ParseLengthDelimitedValue, this, std::placeholders::_1, std::placeholders::_2, + std::placeholders::_3)}, + {ProtoWireType::kFixed64, std::bind(&ProtoReaderBase::ParseFixed64Value, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)}, + {ProtoWireType::kFixed32, std::bind(&ProtoReaderBase::ParseFixed32Value, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3)}}; +} + +// return next parse addr and dataAreaTag. if failed returns nullptr +const uint8_t* ProtoReaderBase::GetNextProtoTag(const uint8_t* const startAddr, + const uint8_t* const endAddr, + uint64_t* dataAreaTag) +{ + const uint8_t* cursor = startAddr; + if (*cursor & BYTE_HIGHEST_BIT_MARK) { + const uint8_t* nextAddr = VarIntDecode(cursor, endAddr, dataAreaTag); + if (cursor == nextAddr) { + return nullptr; + } + cursor = nextAddr; + } else { + *dataAreaTag = *(cursor++); + } + if (cursor >= endAddr) { + return nullptr; + } + return cursor; +} + +bool ProtoReaderBase::ParseVarIntValue(ParseDataAreaResult& result, + const uint8_t* startAddr, + const uint8_t* const endAddr) +{ + uint64_t intValue = 0; + auto cursor = VarIntDecode(startAddr, endAddr, &intValue); + if (cursor == startAddr) { + return false; + } + result.dataArea.SetDataAreaIntValue(intValue); + result.next = cursor; + result.status = OK; + return true; +} + +bool ProtoReaderBase::ParseLengthDelimitedValue(ParseDataAreaResult& result, + const uint8_t* startAddr, + const uint8_t* const endAddr) +{ + uint64_t length = 0; + auto cursor = VarIntDecode(startAddr, endAddr, &length); + if (cursor == startAddr || length > static_cast(endAddr - cursor)) { + return false; + } + const uintptr_t dataStartAddr = reinterpret_cast(cursor); + result.dataArea.SetDataAreaIntValue(dataStartAddr); + result.dataArea.SetDataAreaSize(length); + result.next = cursor + length; + if (length > kMaxMessageLength) { + TS_LOGD("Skip this data, because it is too large. length: %d", length); + result.status = SKIP; + return true; + } + result.status = OK; + return true; +} + +bool ProtoReaderBase::ParseFixed64Value(ParseDataAreaResult& result, + const uint8_t* startAddr, + const uint8_t* const endAddr) +{ + uint64_t intValue = 0; + auto cursor = startAddr + sizeof(uint64_t); + if (cursor > endAddr) { + return false; + } + + (void*)memcpy_s(&intValue, sizeof(uint64_t), startAddr, sizeof(uint64_t)); + result.dataArea.SetDataAreaIntValue(intValue); + result.next = cursor; + result.status = OK; + return true; +} + +bool ProtoReaderBase::ParseFixed32Value(ParseDataAreaResult& result, + const uint8_t* startAddr, + const uint8_t* const endAddr) +{ + uint64_t intValue = 0; + auto cursor = startAddr + sizeof(uint32_t); + if (cursor > endAddr) { + return false; + } + (void*)memcpy_s(&intValue, sizeof(uint64_t), startAddr, sizeof(uint32_t)); + result.dataArea.SetDataAreaIntValue(intValue); + result.next = cursor; + result.status = OK; + return true; +} + +ParseDataAreaResult ProtoReaderBase::ParseOneDataArea(const uint8_t* const startAddr, const uint8_t* const endAddr) +{ + ParseDataAreaResult result = {ABORT, startAddr, DataArea{}}; + if (!startAddr || startAddr >= endAddr) { + return result; + } + uint64_t dataAreaTag = 0; + auto cursor = GetNextProtoTag(startAddr, endAddr, &dataAreaTag); + if (!cursor) { + return result; + } + uint32_t dataAreaId = static_cast(dataAreaTag >> DATA_AREA_TYPE_BITS); + if (dataAreaId == 0) { + return result; + } + + if (TS_UNLIKELY(dataAreaId > std::numeric_limits::max())) { + TS_LOGD("Skip dataArea %d because its too big", dataAreaId); + result.status = ParseProtoStatus::SKIP; + return result; + } + result.dataArea.SetDataAreaId(dataAreaId); + + auto dataAreaType = static_cast(dataAreaTag) & DATA_AREA_TYPE_VALUE; + result.dataArea.SetDataAreaType(dataAreaType); + + auto itor = dataAreaTypeToParseFuncMap_.find(static_cast(dataAreaType)); + if (itor == dataAreaTypeToParseFuncMap_.end()) { + return result; + } + itor->second(result, cursor, endAddr_); + return result; +} + +DataArea ProtoReaderBase::FindDataArea(uint32_t dataAreaId) +{ + DataArea dataArea{}; + auto temp = currentReadAddr_; + currentReadAddr_ = startAddr_; + for (auto nextDataArea = ReadNextDataArea(); nextDataArea.DataAreaValid(); nextDataArea = ReadNextDataArea()) { + if (nextDataArea.DataAreaId() == dataAreaId) { + dataArea = nextDataArea; + break; + } + } + currentReadAddr_ = temp; + return dataArea; +} +TS_INLINE +DataArea ProtoReaderBase::ReadNextDataArea() +{ + ParseDataAreaResult result = {ABORT, currentReadAddr_, DataArea{}}; + do { + result = ParseOneDataArea(currentReadAddr_, endAddr_); + currentReadAddr_ = result.next; + } while (result.status == ParseProtoStatus::SKIP); + return result.dataArea; +} + +void ProtoReaderBase::ParseAllDataAreas() +{ + const uint8_t* cur = startAddr_; + ParseDataAreaResult result = {ABORT, startAddr_, DataArea{}}; + while (true) { + result = ParseOneDataArea(cur, endAddr_); + cur = result.next; + if (result.status == ParseProtoStatus::SKIP) { + continue; + } else if (result.status == ParseProtoStatus::ABORT) { + break; + } + auto dataAreaId = result.dataArea.DataAreaId(); + if (dataAreaId >= dataAreasCount_) { + continue; + } + + DataArea* dataArea = &dataAreas_[dataAreaId]; + if (!dataArea->DataAreaValid()) { + *dataArea = std::move(result.dataArea); + } else { + if (size_ >= volume_) { + MoveToLargerHeapStorage(); + dataArea = &dataAreas_[dataAreaId]; + } + dataAreas_[size_++] = *dataArea; + *dataArea = std::move(result.dataArea); + } + } + currentReadAddr_ = result.next; +} + +void ProtoReaderBase::MoveToLargerHeapStorage() +{ + uint32_t largerVolume = volume_ << 1; + std::unique_ptr largerVolumeStorage(new DataArea[largerVolume]); + (void*)memcpy_s(&largerVolumeStorage[0], sizeof(DataArea) * largerVolume, dataAreas_, sizeof(DataArea) * size_); + lagerHeapStorage_ = std::move(largerVolumeStorage); + dataAreas_ = &lagerHeapStorage_[0]; + volume_ = largerVolume; +} +} // namespace ProtoReader +} // namespace SysTuning diff --git a/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn b/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..e967af6e1cd86d367e8f7fc7ae38a437eaef6427 --- /dev/null +++ b/trace_streamer/src/proto_reader/protoc_plugin/BUILD.gn @@ -0,0 +1,22 @@ +# 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. +if (target != "wasm") { + executable("protoreader_plugin") { + sources = [ "proto_reader_plugin.cpp" ] + deps = [ + "//third_party/protobuf:protoc", + "//third_party/protobuf:protoc_lib", + ] + include_dirs = [ "//third_party/protobuf/src" ] + } +} diff --git a/trace_streamer/src/proto_reader/protoc_plugin/proto_reader_plugin.cpp b/trace_streamer/src/proto_reader/protoc_plugin/proto_reader_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b61cc62a32b0c3986fbe04f796e781e9ee7c227f --- /dev/null +++ b/trace_streamer/src/proto_reader/protoc_plugin/proto_reader_plugin.cpp @@ -0,0 +1,328 @@ +/* + * 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 "proto_reader_plugin.h" +namespace SysTuning { +namespace ProtoReader { +const std::string SYS_NAMESPACE = "SysTuning"; +const int32_t MAX_DECODER_FIELDID = 999; +const int32_t MIN_OPTIONS_SIZE = 2; + +bool ProtoReaderPlugin::Generate(const FileDescriptor* file, + const std::string& options, + GeneratorContext* context, + std::string* error) const +{ + std::string newFileName = file->name().substr(0, file->name().find("proto")) + "pbreader"; + const std::unique_ptr generateFile(context->Open(newFileName + ".h")); + Printer generatePrinterHead(generateFile.get(), '$'); + ProtoReaderGenerator protoReaderGenerator(file, &generatePrinterHead); + std::vector option = SplitStringToVec(const_cast(options), "="); + if (option.size() < MIN_OPTIONS_SIZE) { + return false; + } + if (option[0] == "wrapper_namespace") { + protoReaderGenerator.wrapperNamespace_ = option[1]; + } + if (!protoReaderGenerator.WriteProtoReader()) { + *error = protoReaderGenerator.GetError(); + return false; + } + return true; +} + +bool ProtoReaderGenerator::WriteProtoReader() +{ + GetPBReaderInfo(); + WriteBegin(); + for (const EnumDescriptor* enumDescriptor : vEnumDescriptor_) { + WriteEnumDescriptor(enumDescriptor); + } + + for (const Descriptor* descriptor : vDescriptor_) { + WriteDecoder(descriptor); + } + WriteEnd(); + return error_.empty(); +} +void ProtoReaderGenerator::ParserDescriptors() +{ + std::vector vDescriptor; + vDescriptor.reserve(static_cast(fileDescriptor_->message_type_count())); + for (int32_t i = 0; i < fileDescriptor_->message_type_count(); ++i) { + vDescriptor.push_back(fileDescriptor_->message_type(i)); + } + + while (!vDescriptor.empty()) { + const Descriptor* descriptor = vDescriptor.back(); + vDescriptor.pop_back(); + vDescriptor_.push_back(descriptor); + for (int32_t i = 0; i < descriptor->nested_type_count(); ++i) { + vDescriptor.push_back(descriptor->nested_type(i)); + } + } + + for (int32_t i = 0; i < fileDescriptor_->enum_type_count(); ++i) { + vEnumDescriptor_.push_back(fileDescriptor_->enum_type(i)); + } + + for (const Descriptor* descriptor : vDescriptor_) { + for (int32_t i = 0; i < descriptor->enum_type_count(); ++i) { + vEnumDescriptor_.push_back(descriptor->enum_type(i)); + } + } +} + +void ProtoReaderGenerator::ParserDependencies() +{ + for (int32_t i = 0; i < fileDescriptor_->public_dependency_count(); ++i) { + publicImports_.insert(fileDescriptor_->public_dependency(i)); + } + + std::vector vFileDescriptor; + for (int32_t i = 0; i < fileDescriptor_->dependency_count(); ++i) { + const FileDescriptor* fileDescriptor = fileDescriptor_->dependency(i); + vFileDescriptor.push_back(fileDescriptor); + } + + for (const FileDescriptor* fileDescriptor : vFileDescriptor) { + for (int32_t i = 0; i < fileDescriptor->public_dependency_count(); ++i) { + vFileDescriptor.push_back(fileDescriptor->public_dependency(i)); + } + } + + for (const Descriptor* descriptor : vDescriptor_) { + for (int32_t i = 0; i < descriptor->field_count(); ++i) { + + if (descriptor->field(i)->type() == FieldDescriptor::TYPE_MESSAGE) { + if (!publicImports_.count(descriptor->field(i)->message_type()->file())) { + referencedMessages_.insert(descriptor->field(i)->message_type()); + } + } else if (descriptor->field(i)->type() == FieldDescriptor::TYPE_ENUM) { + if (!publicImports_.count(descriptor->field(i)->enum_type()->file())) { + referencedEnums_.insert(descriptor->field(i)->enum_type()); + } + } + } + } +} + +void ProtoReaderGenerator::ParserNamespace() +{ + vNamespaces_.push_back(SYS_NAMESPACE); + // vNamespaces_.push_back(PROTOREADER); + if (!wrapperNamespace_.empty()) { + vNamespaces_.push_back(wrapperNamespace_); + } + + fullNamespacePrefix_ = "::"; + for (const std::string& namespaces : vNamespaces_) + fullNamespacePrefix_ += namespaces + "::"; +} + +void ProtoReaderGenerator::GetPBReaderInfo() +{ + ParserNamespace(); + ParserDescriptors(); + ParserDependencies(); +} + +void ProtoReaderGenerator::WriteBegin() +{ + std::string notify = "// Autogenerated by the ProtoReader plugin. DO NOT EDIT.\n"; + std::string fileDefinded = fileDescriptor_->name() + "_H"; + fileDefinded = ToUppercase(fileDefinded); + fileDefinded_ = fileDefinded.replace(fileDefinded.find("."), 1, "_"); + + codePrinter_->Print( + "$notify$\n" + "#ifndef $fileDefinded$\n" + "#define $fileDefinded$\n\n" + "#include \n" + "#include \n\n" + "#include \"proto_reader/include/proto_reader.h\"\n" + "#include \"proto_reader/include/data_area.h\"\n", + "notify", notify, "fileDefinded", fileDefinded_); + codePrinter_->Print("\n"); + + for (const std::string& tsNamespace : vNamespaces_) { + codePrinter_->Print("namespace $namespace$ {\n", "namespace", tsNamespace); + } + codePrinter_->Print("\n"); + + for (const Descriptor* descriptor : referencedMessages_) { + codePrinter_->Print("class $class$;\n", "class", GetDescriptorClass(descriptor)); + } + for (const EnumDescriptor* enumDescriptor : referencedEnums_) { + codePrinter_->Print("enum $class$ : int32_t;\n", "class", GetDescriptorClass(enumDescriptor)); + } + codePrinter_->Print("\n"); +} + +void ProtoReaderGenerator::WriteEnumDescriptor(const EnumDescriptor* enumDescriptor) +{ + codePrinter_->Print("enum $class$ : int32_t {\n", "class", GetDescriptorClass(enumDescriptor)); + codePrinter_->Indent(); + + std::string minName = ""; + std::string maxName = ""; + int32_t minNum = std::numeric_limits::max(); + int32_t maxNum = -1; + + std::string containingName; + if (enumDescriptor->containing_type() != nullptr) { + containingName = GetDescriptorClass(enumDescriptor) + "_"; + } + + for (int32_t i = 0; i < enumDescriptor->value_count(); ++i) { + codePrinter_->Print("$name$ = $number$,\n", "name", containingName + enumDescriptor->value(i)->name(), "number", + std::to_string(enumDescriptor->value(i)->number())); + if (enumDescriptor->value(i)->number() < minNum) { + minNum = enumDescriptor->value(i)->number(); + minName = containingName + enumDescriptor->value(i)->name(); + } + if (enumDescriptor->value(i)->number() > maxNum) { + maxNum = enumDescriptor->value(i)->number(); + maxName = containingName + enumDescriptor->value(i)->name(); + } + } + codePrinter_->Outdent(); + codePrinter_->Print("};\n\n"); + codePrinter_->Print("const $class$ $class$_MIN = $min$;\n", "class", GetDescriptorClass(enumDescriptor), "min", + minName); + codePrinter_->Print("const $class$ $class$_MAX = $max$;\n", "class", GetDescriptorClass(enumDescriptor), "max", + maxName); + codePrinter_->Print("\n"); +} + +void ProtoReaderGenerator::WriteDecoder(const Descriptor* descriptor) +{ + int32_t maxFieldID = 0; + for (int32_t i = 0; i < descriptor->field_count(); ++i) { + const FieldDescriptor* field = descriptor->field(i); + maxFieldID = std::max(maxFieldID, field->number()); + } + + std::string className = GetDescriptorClass(descriptor) + "_Reader"; + codePrinter_->Print( + "class $name$ : public " + "TypedProtoReader<$maxDataAreaID$> {\n", + "name", className, "maxDataAreaID", std::to_string(maxFieldID)); + codePrinter_->Print(" public:\n"); + maxFieldID = 1 + maxFieldID; + + WriteEnum(descriptor); + codePrinter_->Indent(); + codePrinter_->Print( + "$name$(const uint8_t* data, size_t len) " + ": TypedProtoReader(data, len) {}\n", + "name", className); + codePrinter_->Print( + "explicit $name$(const std::string& raw) : " + "TypedProtoReader(reinterpret_cast(raw.data()), " + "raw.size()) {}\n", + "name", className); + codePrinter_->Print( + "explicit $name$(const BytesView& raw) : " + "TypedProtoReader(raw.data_, raw.size_) {}\n", + "name", className); + + for (int32_t i = 0; i < descriptor->field_count(); ++i) { + const FieldDescriptor* field = descriptor->field(i); + if (field->number() > maxFieldID) { + codePrinter_->Print("// dataArea $name$ exceeded the maximum\n", "name", field->name()); + continue; + } + TypeDesc typeDesc{}; + auto t = fieldTypeDesc_.find(field->type()); + if (t != fieldTypeDesc_.end()) { + typeDesc = t->second; + } + std::string toFunc = typeDesc.toFunc; + std::string type = typeDesc.type; + codePrinter_->Print("bool has_$name$() const { return at<$id$>().DataAreaValid(); }\n", "name", + field->lowercase_name(), "id", std::to_string(field->number())); + if (field->is_packed()) { + TypeDesc fieldTypeDesc{}; + auto fieldType = fieldTypeDesc_.find(field->type()); + if (fieldType != fieldTypeDesc_.end()) { + fieldTypeDesc = fieldType->second; + } + const char* protoReaderWireType = fieldTypeDesc.packedBufferType.c_str(); + codePrinter_->Print( + "PackedRepeatedDataAreaIterator " + "$name$(bool* parseErrorInfo) const { return " + "GetPackedRepeated($id$, " + "parseErrorInfo); }\n", + "protoReaderWireType", protoReaderWireType, "type", type, "name", field->lowercase_name(), "id", + std::to_string(field->number())); + } else if (field->is_repeated()) { + codePrinter_->Print( + "RepeatedDataAreaIterator<$type$> $name$() const { " + "return " + "ProtoReaderBase::GetRepeated<$type$>($id$); }\n", + "name", field->lowercase_name(), "type", type, "id", std::to_string(field->number())); + } else { + codePrinter_->Print("$type$ $name$() const { return at<$id$>().$toFunc$(); }\n", "name", + field->lowercase_name(), "id", std::to_string(field->number()), "type", type, "toFunc", + toFunc); + } + } + codePrinter_->Outdent(); + codePrinter_->Print("};\n\n"); +} + +void ProtoReaderGenerator::WriteEnum(const Descriptor* descriptor) +{ + if (descriptor->field_count()) { + codePrinter_->Print("enum : int32_t {\n"); + codePrinter_->Indent(); + + for (int32_t i = 0; i < descriptor->field_count(); ++i) { + const FieldDescriptor* field = descriptor->field(i); + codePrinter_->Print("$name$ = $id$,\n", "name", GetFieldNumberConstant(field), "id", + std::to_string(field->number())); + } + codePrinter_->Outdent(); + codePrinter_->Print("};\n"); + } +} + +void ProtoReaderGenerator::WriteEnd() +{ + for (uint32_t i = vNamespaces_.size(); i > 0; --i) { + codePrinter_->Print("} // namespace $namespace$\n", "namespace", vNamespaces_.at(i - 1)); + } + codePrinter_->Print("#endif // $fileDefinded$\n", "fileDefinded", fileDefinded_); +} + +std::string ProtoReaderGenerator::GetFieldNumberConstant(const FieldDescriptor* field) +{ + std::string name = field->camelcase_name(); + if (!name.empty()) { + name.at(0) = Uppercase(name.at(0)); + name = "k" + name + "DataAreaNumber"; + return name; + } + return ""; +} +} // namespace ProtoReader +} // namespace SysTuning + +int main(int argc, char* argv[]) +{ + SysTuning::ProtoReader::ProtoReaderPlugin protoReaderGenerate; + return google::protobuf::compiler::PluginMain(argc, argv, &protoReaderGenerate); +} diff --git a/trace_streamer/src/proto_reader/protoc_plugin/proto_reader_plugin.h b/trace_streamer/src/proto_reader/protoc_plugin/proto_reader_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..e1537f4c77f7588f1d1d64f4f32a981a086e00a5 --- /dev/null +++ b/trace_streamer/src/proto_reader/protoc_plugin/proto_reader_plugin.h @@ -0,0 +1,161 @@ +/* + * 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 PROTO_READER_PLUGIN_H +#define PROTO_READER_PLUGIN_H +#include +#include +#include +#include +#include +#include +#include + +namespace SysTuning { +namespace ProtoReader { +using google::protobuf::Descriptor; +using google::protobuf::EnumDescriptor; +using google::protobuf::FieldDescriptor; +using google::protobuf::FileDescriptor; +using google::protobuf::compiler::GeneratorContext; +using google::protobuf::io::Printer; +using google::protobuf::io::ZeroCopyOutputStream; + +inline std::vector SplitStringToVec(std::string& str, const std::string& pat) +{ + std::vector result = {}; + str += pat; + int32_t size = str.size(); + for (int32_t i = 0; i < size; i++) { + auto pos = str.find(pat, i); + if (pos == std::string::npos) { + break; + } + if (pos < size) { + std::string s = str.substr(i, pos - i); + result.push_back(s); + i = pos + pat.size() - 1; + } + } + return result; +} +inline char Uppercase(char c) +{ + return ('a' <= c && c <= 'z') ? static_cast(c + ('A' - 'a')) : c; +} + +inline std::string ToUppercase(const std::string& str) +{ + std::string string(str); + auto end = string.end(); + for (auto c = string.begin(); c != end; ++c) { + *c = Uppercase(*c); + } + return string; +} + +class ProtoReaderGenerator { +public: + ProtoReaderGenerator(const FileDescriptor* file, Printer* printer) : fileDescriptor_(file), codePrinter_(printer) {} + bool WriteProtoReader(); + void ParserNamespace(); + void ParserDescriptors(); + void ParserDependencies(); + void GetPBReaderInfo(); + void WriteBegin(); + void WriteEnumDescriptor(const EnumDescriptor* enumeration); + void WriteDecoder(const Descriptor* descriptor); + void WriteEnum(const Descriptor* descriptor); + void WriteEnd(); + const std::string& GetError() const + { + return error_; + } + +public: + std::string wrapperNamespace_; + +private: + template + inline std::string GetDescriptorName(const T* descriptor) const + { + if (!package_.empty()) { + auto strTmp = package_ + "."; + return descriptor->full_name().substr(descriptor->full_name().find(strTmp) + sizeof(strTmp)); + } else { + return descriptor->full_name(); + } + } + template + std::string GetDescriptorClass(const T* descriptor) + { + std::string name = GetDescriptorName(descriptor); + size_t pos = name.find("."); + if (pos != std::string::npos) { + name = name.replace(name.find("."), 1, "_"); + } + return name; + } + std::string GetFieldNumberConstant(const FieldDescriptor* field); + +private: + struct TypeDesc { + std::string toFunc; + std::string type; + std::string packedBufferType; + }; + std::map fieldTypeDesc_ = { + {FieldDescriptor::TYPE_BOOL, {"ToBool", "bool", "kVarInt"}}, + {FieldDescriptor::TYPE_SFIXED32, {"ToInt32", "int32_t", "kFixed32"}}, + {FieldDescriptor::TYPE_SINT32, {"ToInt32", "int32_t", "kVarInt"}}, + {FieldDescriptor::TYPE_INT32, {"ToInt32", "int32_t", "kVarInt"}}, + {FieldDescriptor::TYPE_SFIXED64, {"ToInt64", "int64_t", "kFixed64"}}, + {FieldDescriptor::TYPE_SINT64, {"ToInt64", "int64_t", "kVarInt"}}, + {FieldDescriptor::TYPE_INT64, {"ToInt64", "int64_t", "kVarInt"}}, + {FieldDescriptor::TYPE_FIXED32, {"ToUint32", "uint32_t", "kFixed32"}}, + {FieldDescriptor::TYPE_UINT32, {"ToUint32", "uint32_t", "kVarInt"}}, + {FieldDescriptor::TYPE_FIXED64, {"ToUint64", "uint64_t", "kFixed64"}}, + {FieldDescriptor::TYPE_UINT64, {"ToUint64", "uint64_t", "kVarInt"}}, + {FieldDescriptor::TYPE_FLOAT, {"ToFloat", "float", "kFixed32"}}, + {FieldDescriptor::TYPE_DOUBLE, {"ToDouble", "double", "kFixed64"}}, + {FieldDescriptor::TYPE_ENUM, {"ToInt32", "int32_t", "kVarInt"}}, + {FieldDescriptor::TYPE_STRING, {"ToString", "CharsView", ""}}, + {FieldDescriptor::TYPE_MESSAGE, {"ToBytes", "BytesView", ""}}, + {FieldDescriptor::TYPE_BYTES, {"ToBytes", "BytesView", ""}}, + }; + const FileDescriptor* const fileDescriptor_; + Printer* const codePrinter_; + std::string error_; + std::string fileDefinded_; + std::string package_; + std::vector vNamespaces_; + std::string fullNamespacePrefix_; + std::vector vDescriptor_; + std::vector vEnumDescriptor_; + std::set publicImports_; + std::set referencedMessages_; + std::set referencedEnums_; +}; +class ProtoReaderPlugin : public ::google::protobuf::compiler::CodeGenerator { +public: + explicit ProtoReaderPlugin(){}; + ~ProtoReaderPlugin() override{}; + bool Generate(const FileDescriptor* file, + const std::string& options, + GeneratorContext* context, + std::string* error) const override; +}; +} // namespace ProtoReader +} // namespace SysTuning +#endif // PROTO_READER_PLUGIN_H diff --git a/trace_streamer/src/protos/README_zh.md b/trace_streamer/src/protos/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..6e49694e23aafe5dcfd18c921519b3f5edda1911 --- /dev/null +++ b/trace_streamer/src/protos/README_zh.md @@ -0,0 +1,10 @@ +# protos 代码仓 + + + +`services` 目录下存放的是 服务接口定义, + +`types` 目录下存放的是 具体插件业务相关的类型定义,主要为配置类型和结果类型定义。 + +例如,`types/plugins/cpu_data/` 目录存放CPU数据插件的配置类型和结果类型。 + diff --git a/trace_streamer/src/protos/protogen.sh b/trace_streamer/src/protos/protogen.sh new file mode 100755 index 0000000000000000000000000000000000000000..ca54664d837485f4ffcc787175251db0d1dbfef9 --- /dev/null +++ b/trace_streamer/src/protos/protogen.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# 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. +set -e +protoc='protoc' +proto_dir='.' +case "$OSTYPE" in + msys*) out='../../out/windows' protoc='protoc.exe' proto_dir=$( cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) ;; + darwin*) out='../../out/macx' proto_dir=$( cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) ;; + linux*) out='../../out/linux' proto_dir=$( cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) ;; + *) echo "other: $OSTYPE" ;; +esac +echo $proto_dir +SOURCE="${BASH_SOURCE[0]}" +cd $(dirname ${SOURCE}) +if [ ! -f "$out/$protoc" ];then + echo "no $out/$protoc found, you need to run \"./build.sh protoc\" at root folder, and copy protoc.exe to $out/$protoc" + exit +fi +echo "begin to generate proto based files" +SOURCE=$(dirname ${SOURCE}) +services_dir="$proto_dir/services" +# kernel_version="5.10.79_aarch64" +kernel_version="." +ftrace_data_dir="$proto_dir/types/plugins/ftrace_data/$kernel_version" +memory_data_dir="$proto_dir/types/plugins/memory_data" +hilog_data_dir="$proto_dir/types/plugins/hilog_data" +native_hook_dir="$proto_dir/types/plugins/native_hook" +hidump_data_dir="$proto_dir/types/plugins/hidump_data" +network_data_dir="$proto_dir/types/plugins/network_data" +cpu_data_dir="$proto_dir/types/plugins/cpu_data" +diskio_data_dir="$proto_dir/types/plugins/diskio_data" +process_data_dir="$proto_dir/types/plugins/process_data" +hisysevent_data_dir="$proto_dir/types/plugins/hisysevent_data" +test_data_dir="$proto_dir/types/plugins/test_data" +js_memory_dir="$proto_dir/types/plugins/js_memory" +proto_array=("${services_dir}/common_types.proto" + "$ftrace_data_dir/trace_plugin_result.proto" + "$ftrace_data_dir/ftrace_event.proto" + "$ftrace_data_dir/irq.proto" + "$ftrace_data_dir/vmscan.proto" + "$ftrace_data_dir/workqueue.proto" + "$ftrace_data_dir/task.proto" + "$ftrace_data_dir/power.proto" + "$ftrace_data_dir/sched.proto" + "$ftrace_data_dir/filemap.proto" + "$ftrace_data_dir/i2c.proto" + "$ftrace_data_dir/kmem.proto" + "$ftrace_data_dir/block.proto" + "$ftrace_data_dir/ipi.proto" + "$ftrace_data_dir/ftrace.proto" + "$ftrace_data_dir/ext4.proto" + "$ftrace_data_dir/oom.proto" + "$ftrace_data_dir/compaction.proto" + "$ftrace_data_dir/clk.proto" + "$ftrace_data_dir/cgroup.proto" + "$ftrace_data_dir/binder.proto" + "$ftrace_data_dir/signal.proto" + "$ftrace_data_dir/sunrpc.proto" + "$ftrace_data_dir/net.proto" + "$ftrace_data_dir/cpuhp.proto" + "$ftrace_data_dir/writeback.proto" + "$ftrace_data_dir/v4l2.proto" + "$ftrace_data_dir/pagemap.proto" + "$ftrace_data_dir/dma_fence.proto" + "$ftrace_data_dir/printk.proto" + "$ftrace_data_dir/filelock.proto" + "$ftrace_data_dir/gpio.proto" + "$ftrace_data_dir/timer.proto" + "$ftrace_data_dir/raw_syscalls.proto" + "$ftrace_data_dir/rcu.proto" + "$memory_data_dir/memory_plugin_common.proto" + "$memory_data_dir/memory_plugin_config.proto" + "$memory_data_dir/memory_plugin_result.proto" + "$hilog_data_dir/hilog_plugin_result.proto" + "$native_hook_dir/native_hook_result.proto" + "$native_hook_dir/native_hook_config.proto" + "$hidump_data_dir/hidump_plugin_result.proto" + "$network_data_dir/network_plugin_result.proto" + "$cpu_data_dir/cpu_plugin_result.proto" + "$diskio_data_dir/diskio_plugin_result.proto" + "$hisysevent_data_dir/hisysevent_plugin_config.proto" + "$process_data_dir/process_plugin_result.proto" + "$hisysevent_data_dir/hisysevent_plugin_result.proto" + "$js_memory_dir/js_heap_result.proto" + "$js_memory_dir/js_heap_config.proto" + "$test_data_dir/test.proto") + +export LD_LIBRARY_PATH=$out +for ((i = 0; i < ${#proto_array[@]}; i ++)) +do + newpath=$(dirname ${proto_array[$i]}) + tailpath='\'${newpath#$proto_dir} + newpath=${tailpath:2} + cppout=../../third_party/protogen/$newpath + mkdir -p $cppout + $out/$protoc --proto_path=$memory_data_dir:$native_hook_dir:$hidump_data_dir:$hilog_data_dir:$ftrace_data_dir:$js_memory_dir:$services_dir:$network_data_dir:$cpu_data_dir:$diskio_data_dir:$process_data_dir:$hisysevent_data_dir:$test_data_dir --cpp_out=$cppout ${proto_array[$i]} + $out/$protoc --proto_path=$memory_data_dir:$native_hook_dir:$hidump_data_dir:$hilog_data_dir:$ftrace_data_dir:$js_memory_dir:$services_dir:$network_data_dir:$cpu_data_dir:$diskio_data_dir:$process_data_dir:$hisysevent_data_dir:$test_data_dir --plugin=protoc-gen-plugin=$out/protoreader_plugin --plugin_out=wrapper_namespace=ProtoReader:$cppout ${proto_array[$i]} +done +echo "generate proto based files over" diff --git a/trace_streamer/src/protos/protos.gni b/trace_streamer/src/protos/protos.gni new file mode 100755 index 0000000000000000000000000000000000000000..f8582402a8b542f4435fdeda2e18278b1bd725e7 --- /dev/null +++ b/trace_streamer/src/protos/protos.gni @@ -0,0 +1,36 @@ +# 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/config.gni") + +subsys_name = OHOS_PROFILER_SUBSYS_NAME +part_name = OHOS_PROFILER_PART_NAME +subsys_x64_out = "clang_x64/$subsys_name/$part_name" +libc_dir_proto = rebase_path("$asdk_libs_dir", "//") +root_output_dir_proto = rebase_path("$root_out_dir", "//") + +#host:clang_x64 default:arm mingw:mingw_x86_64 +if (current_toolchain != host_toolchain) { + if (current_toolchain == default_toolchain) { + root_output_dir_proto = "$root_output_dir_proto/clang_x64" + } else { + root_output_dir_proto = + get_path_info("$root_output_dir_proto", "dir") + "/clang_x64" + } +} +protoc = root_output_dir_proto +print("default_toolchain = ", default_toolchain) +print("current_toolchain = ", current_toolchain) +print("host_toolchain = ", host_toolchain) +print("root_out_dir = ", root_out_dir) +print("root_output_dir_proto = ", root_output_dir_proto) diff --git a/trace_streamer/src/protos/services/BUILD.gn b/trace_streamer/src/protos/services/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..6829542564bc43fd4cdab66ec8578d1e00d74351 --- /dev/null +++ b/trace_streamer/src/protos/services/BUILD.gn @@ -0,0 +1,225 @@ +# 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("../protos.gni") + +proto_types_defines = [ + "./common_types.proto", + "./plugin_service_types.proto", + "./profiler_service_types.proto", +] + +plugin_services_defines = [ "./plugin_service.proto" ] + +profiler_services_defines = [ "./profiler_service.proto" ] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) +print("proto_out_dir", proto_out_dir, proto_rel_out_dir) + +grpc_cpp_plugin = "$subsys_x64_out/grpc_cpp_plugin" +ipc_cpp_plugin = "$subsys_x64_out/protoc_gen_ipc" + +####################################################### +proto_types_codegen = [] +foreach(proto, proto_types_defines) { + name = get_path_info(proto, "name") + proto_types_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +action("service_types_proto_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = proto_types_defines + outputs = proto_types_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ + "${OHOS_PROFILER_3RDPARTY_GRPC_DIR}:grpc_cpp_plugin(${host_toolchain})", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + ] +} + +config("service_types_proto_config") { + include_dirs = [ "$proto_out_dir" ] +} + +source_set("service_types_proto") { + deps = [ ":service_types_proto_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":service_types_proto_config" ] + sources = proto_types_codegen +} + +source_set("service_types_proto_static") { + deps = [ ":service_types_proto_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":service_types_proto_config" ] + sources = proto_types_codegen +} + +####################################################### +profiler_services_codegen = [] +foreach(proto, profiler_services_defines) { + name = get_path_info(proto, "name") + profiler_services_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + "$proto_out_dir/$name.grpc.pb.h", + "$proto_out_dir/$name.grpc.pb.cc", + ] +} + +action("profiler_services_proto_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = profiler_services_defines + outputs = profiler_services_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--plugin=protoc-gen-grpc=$grpc_cpp_plugin", + "--grpc_out", + "$proto_rel_out_dir", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ + "${OHOS_PROFILER_3RDPARTY_GRPC_DIR}:grpc_cpp_plugin(${host_toolchain})", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + ] +} + +config("profiler_services_proto_config") { + include_dirs = [ "$proto_out_dir" ] +} + +source_set("profiler_services_proto") { + deps = [ + ":profiler_services_proto_gen", + ":service_types_proto", + ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_GRPC_DIR}:grpc", + "${OHOS_PROFILER_3RDPARTY_GRPC_DIR}:grpcxx", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":profiler_services_proto_config" ] + sources = profiler_services_codegen +} + +####################################################### +plugin_services_codegen = [] +foreach(proto, plugin_services_defines) { + name = get_path_info(proto, "name") + plugin_services_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + "$proto_out_dir/$name.ipc.h", + "$proto_out_dir/$name.ipc.cc", + ] +} + +action("plugin_services_proto_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = plugin_services_defines + outputs = plugin_services_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--plugin=protoc-gen-ipc=$ipc_cpp_plugin", + "--ipc_out", + "$proto_rel_out_dir", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})", + "${OHOS_PROFILER_DIR}/device/services/ipc:protoc_gen_ipc(${host_toolchain})", + ] +} + +config("plugin_services_proto_config") { + include_dirs = [ "$proto_out_dir" ] +} + +source_set("plugin_services_proto") { + deps = [ + ":plugin_services_proto_gen", + ":service_types_proto", + ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + "${OHOS_PROFILER_DIR}/device/services/ipc:ipc", + ] + include_dirs = [ + "$proto_out_dir", + "${OHOS_PROFILER_DIR}/device/services/ipc/include", + ] + public_configs = [ ":plugin_services_proto_config" ] + sources = plugin_services_codegen +} + +source_set("plugin_services_proto_static") { + deps = [ + ":plugin_services_proto_gen", + ":service_types_proto_static", + ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite_static", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_static", + "${OHOS_PROFILER_DIR}/device/services/ipc:ipc", + ] + include_dirs = [ + "$proto_out_dir", + "${OHOS_PROFILER_DIR}/device/services/ipc/include", + ] + public_configs = [ ":plugin_services_proto_config" ] + sources = plugin_services_codegen +} + +####################################################### +source_set("proto_services_cpp") { + public_deps = [ + ":plugin_services_proto", + ":profiler_services_proto", + ":service_types_proto", + ] +} diff --git a/trace_streamer/src/protos/services/common_types.proto b/trace_streamer/src/protos/services/common_types.proto new file mode 100755 index 0000000000000000000000000000000000000000..32559daf3b07a34bf9c80c78495bc41adf6e3652 --- /dev/null +++ b/trace_streamer/src/protos/services/common_types.proto @@ -0,0 +1,59 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +// Common message define for profiler tools, imported by profiler and plugin proto file. +message ProfilerPluginConfig { + string name = 1; + string plugin_sha256 = 2; + uint32 sample_interval = 3; + bytes config_data = 4; +} + +message ProfilerPluginState { + string name = 1; + enum State { + INITED = 0; + REGISTERED = 1; // registered to plugin service. + LOADED = 2; // have created session. + IN_SESSION = 3; // have started session. + }; + State state = 2; +} + +// for FetchDataResponse +message ProfilerPluginData { + string name = 1; + uint32 status = 2; + bytes data = 3; + enum ClockId { + CLOCKID_REALTIME = 0; + CLOCKID_REALTIME_ALARM = 1; // since Linux 3.0; Linux-specific + CLOCKID_REALTIME_COARSE = 2; // since Linux 2.6.32; Linux-specific + CLOCKID_TAI = 3; // since Linux 3.10; Linux-specific + CLOCKID_MONOTONIC = 4; + CLOCKID_MONOTONIC_COARSE = 5; // since Linux 2.6.32; Linux-specific + CLOCKID_MONOTONIC_RAW = 6; // since Linux 2.6.28; Linux-specific + CLOCKID_BOOTTIME = 7; // since Linux 2.6.39; Linux-specific + CLOCKID_BOOTTIME_ALARM = 8; // since Linux 3.0; Linux-specific + CLOCKID_PROCESS_CPUTIME_ID = 9; // since Linux 2.6.12 + CLOCKID_THREAD_CPUTIME_ID = 10; // since Linux 2.6.12 + }; + ClockId clock_id = 4; + uint64 tv_sec = 5; + uint64 tv_nsec = 6; + string version = 7; // "1.01" +} diff --git a/trace_streamer/src/protos/services/plugin_service.proto b/trace_streamer/src/protos/services/plugin_service.proto new file mode 100755 index 0000000000000000000000000000000000000000..ab8583d216c151f1dbdf4839c1f94a00f65a6bcf --- /dev/null +++ b/trace_streamer/src/protos/services/plugin_service.proto @@ -0,0 +1,31 @@ +// 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. + +syntax = "proto3"; + +import "plugin_service_types.proto"; + +// IPC interface between profiler service and plugin service. +// Use protobuf plug-ins to convert proto define to +// source and header files during the build process. +service IPluginService { + + rpc RegisterPlugin(RegisterPluginRequest) returns (RegisterPluginResponse); + + rpc UnregisterPlugin(UnregisterPluginRequest) returns (UnregisterPluginResponse); + + // service will use this interface to push commands with streamed return channel. + rpc GetCommand(GetCommandRequest) returns (stream GetCommandResponse); + + rpc NotifyResult(NotifyResultRequest) returns (NotifyResultResponse); +}; diff --git a/trace_streamer/src/protos/services/plugin_service_types.proto b/trace_streamer/src/protos/services/plugin_service_types.proto new file mode 100755 index 0000000000000000000000000000000000000000..3f54f23066364586a6a53543be59c258e8f98806 --- /dev/null +++ b/trace_streamer/src/protos/services/plugin_service_types.proto @@ -0,0 +1,103 @@ +// 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. + +syntax = "proto3"; + +import "common_types.proto"; + +// Message define for IPC interface, imported by plugin service proto file. +// for RegisterPlugin API +message RegisterPluginRequest { + uint32 request_id = 1; + string path = 2; + string sha256 = 3; + + string name = 4; + uint32 buffer_size_hint = 5; +} + +message RegisterPluginResponse { + uint32 status = 1; + uint32 plugin_id = 2; +} + +// for UnregisterPlugin API +message UnregisterPluginRequest { + uint32 request_id = 1; + uint32 plugin_id = 2; +} + +message UnregisterPluginResponse { + uint32 status = 1; +} + +// for GetCommand API +message GetCommandRequest { + uint32 request_id = 1; +} + +message CreateSessionCmd { + repeated uint32 buffer_sizes = 1; + repeated ProfilerPluginConfig plugin_configs = 2; +} + +message DestroySessionCmd { + repeated uint32 plugin_ids = 1; +} + +message StartSessionCmd { + repeated uint32 plugin_ids = 1; + repeated ProfilerPluginConfig plugin_configs = 2; +} + +message StopSessionCmd { + repeated uint32 plugin_ids = 1; +} + +message GetCommandResponse { + uint32 status = 1; + bool has_more = 2; + uint32 command_id = 3; + oneof command { + CreateSessionCmd create_session_cmd = 10; + DestroySessionCmd destroy_session_cmd = 11; + StartSessionCmd start_session_cmd = 12; + StopSessionCmd stop_session_cmd = 13; + } +} + +// for NotifyResult API +message BufferDescriptor { + int32 buffer_id = 1; + uint32 offset = 2; + uint32 length = 3; +} + +message PluginResult { + uint32 plugin_id = 1; + oneof descriptor { + bytes data = 2; + BufferDescriptor buffer = 3; + }; + ProfilerPluginState status = 10; +} + +message NotifyResultRequest { + uint32 request_id = 1; + uint32 command_id = 2; + repeated PluginResult result = 3; +} + +message NotifyResultResponse { + uint32 status = 1; +} diff --git a/trace_streamer/src/protos/services/profiler_service.proto b/trace_streamer/src/protos/services/profiler_service.proto new file mode 100755 index 0000000000000000000000000000000000000000..35e1e1866dcc847bb4fe1a9b6882b94355fb0471 --- /dev/null +++ b/trace_streamer/src/protos/services/profiler_service.proto @@ -0,0 +1,44 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +import "profiler_service_types.proto"; + +// RPC interface between profiler service and host service +// Use protobuf plug-ins to convert proto define to +// source and header files during the build process. +service IProfilerService { + // get all plugin infos and capabilities. + rpc GetCapabilities(GetCapabilitiesRequest) returns (GetCapabilitiesResponse); + + // create tracing sesion and pass tracing config to plugins. + rpc CreateSession(CreateSessionRequest) returns (CreateSessionResponse); + + // start tracing session, active server side tracing triggers. + rpc StartSession(StartSessionRequest) returns (StartSessionResponse); + + // get server-side cached tracing data since current session started. + rpc FetchData(FetchDataRequest) returns (stream FetchDataResponse); + + // stop tracing session, deactivate server side tracing triggers. + rpc StopSession(StopSessionRequest) returns (StopSessionResponse); + + // destroy tracing session. + rpc DestroySession(DestroySessionRequest) returns (DestroySessionResponse); + + // keep tracing session alive, call this interface will restart session expire count down task. + rpc KeepSession(KeepSessionRequest) returns (KeepSessionResponse); +} diff --git a/trace_streamer/src/protos/services/profiler_service_types.proto b/trace_streamer/src/protos/services/profiler_service_types.proto new file mode 100755 index 0000000000000000000000000000000000000000..a557e620a7e79f61ed99c19f93e91293aa6d1e2b --- /dev/null +++ b/trace_streamer/src/protos/services/profiler_service_types.proto @@ -0,0 +1,129 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; + +import "common_types.proto"; + +// Message define for profiler service, imported by profiler service proto file. +// for GetCapabilities +message GetCapabilitiesRequest { + uint32 request_id = 1; +} + +message ProfilerPluginCapability { + string path = 1; + string name = 2; +} + +message GetCapabilitiesResponse { + uint32 status = 1; + repeated ProfilerPluginCapability capabilities = 2; +} + + +// for CreateSessionRequest +message ProfilerSessionConfig { + message BufferConfig { + enum Policy { + RECYCLE = 0; + FLATTEN = 1; + }; + uint32 pages = 1; + Policy policy = 2; + } + repeated BufferConfig buffers = 1; + + enum Mode { + OFFLINE = 0; // save all plugin results to result file. + ONLINE = 1; // push all plugin results to host PC with streamed FetchDataResponse. + }; + Mode session_mode = 2; + string result_file = 3; // for OFFLINE mode, result file path + uint32 result_max_size = 4; // for OFFLINE mode, result file max size in KB + uint32 sample_duration = 5; // for OFFLINE mode, sample duration in ms + uint32 keep_alive_time = 6; // if set to non-zero value, session will auto-destroyed after CreateSession in ms +} + +message CreateSessionRequest { + uint32 request_id = 1; + ProfilerSessionConfig session_config = 2; + repeated ProfilerPluginConfig plugin_configs = 3; +} + +message CreateSessionResponse { + uint32 status = 1; + uint32 session_id = 2; + repeated ProfilerPluginState plugin_status = 3; +} + +// for StartSession +message StartSessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; + repeated ProfilerPluginConfig update_configs = 3; +} + +message StartSessionResponse { + uint32 status = 1; + repeated ProfilerPluginState plugin_status = 3; +} + +// for FetchData +message FetchDataRequest { + uint32 request_id = 1; + uint32 session_id = 2; + bytes addtion_data = 3; +} + +message FetchDataResponse { + uint32 status = 1; + uint32 response_id = 2; + bool has_more = 3; + repeated ProfilerPluginData plugin_data = 4; +} + +// for StopSession +message StopSessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; +} + +message StopSessionResponse { + uint32 status = 1; + repeated ProfilerPluginState plugin_status = 3; +} + +// for DestroySession +message DestroySessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; +} + +message DestroySessionResponse { + uint32 status = 1; + repeated ProfilerPluginState plugin_status = 3; +} + +// for KeepSession +message KeepSessionRequest { + uint32 request_id = 1; + uint32 session_id = 2; + uint32 keep_alive_time = 3; +} + +message KeepSessionResponse { + uint32 status = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..bf26ed894ea66e3734ef961c4b683aef1fa1f7d5 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/BUILD.gn @@ -0,0 +1,69 @@ +# 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("../../../protos.gni") + +agent_sources = [ + "./agent_plugin_app_data.proto", + "./agent_plugin_config.proto", + "./agent_plugin_energy_data.proto", + "./agent_plugin_java_heap.proto", + "./agent_plugin_network_data.proto", + "./agent_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +agent_data_codegen = [] +foreach(proto, agent_sources) { + name = get_path_info(proto, "name") + agent_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("agent_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("agent_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = agent_sources + outputs = agent_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("agent_data_cpp") { + deps = [ ":agent_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":agent_include_config" ] + sources = agent_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_app_data.proto b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_app_data.proto new file mode 100755 index 0000000000000000000000000000000000000000..5ae99f08e7d6c56e36e6ffb53b898cd8ed41c397 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_app_data.proto @@ -0,0 +1,68 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message AbilityStateInfo { + enum AbilityState { + UNSPECIFIED = 0; + START = 1; + INACTIVE = 2; + ACTIVE = 3; + BACKGROUND = 4; + FOREGROUND = 5; + STOP = 6; + } + int32 life_cycle_id = 1; + string ability_name = 2; + AbilityState state = 3; +} + +message KeyEvent { + int32 key_type = 1; + bool is_down = 2; +} + +message TouchEvent { + int32 touch_type = 1; +} + +message MouseEvent { + int32 action_type = 1; + int32 action_button = 2; +} + +message RotationEvent { + float value = 1; +} + +message AgentAbilityEvent { + // timestamp obtained by CLOCK_REALTIME + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + + oneof event { + AbilityStateInfo ability_state = 3; + KeyEvent key_event = 4; + TouchEvent touch_event = 5; + MouseEvent mouse_event = 6; + RotationEvent rotation_event = 7; + } +} + +message BatchAgentAbilityEvent { + repeated AgentAbilityEvent events = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_config.proto b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..470d9461c87fef829dffe3eb1e828a5b7663901e --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_config.proto @@ -0,0 +1,23 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + + +message AgentConfig { + int32 pid = 1; + int32 stack_depth = 2; +} diff --git a/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_energy_data.proto b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_energy_data.proto new file mode 100755 index 0000000000000000000000000000000000000000..575dcfff62d80a94e58a8b6a99a949584ad27149 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_energy_data.proto @@ -0,0 +1,201 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message RunningLockBegin { + enum Type { + UNSPECIFIED = 0; + BACKGROUND = 1; + PROXIMITY_SCREEN_CONTROL = 2; + } + + int32 lock_id = 1; // 锁ID + Type type = 2; // 唤醒锁的类型 + string name = 3; // 唤醒锁名称 +} + +message RunningLockEnd { + int32 lock_id = 1; // 锁ID +} + +message PendingIntent { + string creator_package = 1; // 创建此PendingIntent的应用程序的程序包名称 + int32 creator_uid = 2; // 应用程序UID +} + +enum TimerType { + UNSPECIFIED = 0; + TIMER_TYPE_REALTIME = 1; + TIMER_TYPE_WAKEUP = 2; + TIMER_TYPE_EXACT = 4; + TIMER_TYPE_IDLE = 8; +} + +message OneShotStart { + PendingIntent intent = 1; + int64 oneshot_id = 2; + TimerType type = 3; + int64 triggertime_ns = 4; +} + +message RepeatStart { + PendingIntent intent = 1; + int64 repeat_id = 2; + TimerType type = 3; + int64 triggertime_ns = 4; + int64 interval_ns = 5; +} + +message TimerStop { + int64 stop_id = 1; +} + +message LocationRequest { + enum Priority { + UNSPECIFIED = 0; + PRIORITY_UNSET = 512; + PRIORITY_ACCURACY = 513; + PRIORITY_LOW_POWER = 514; + PRIORITY_FAST_FIRST_FIX = 515; + } + string provider = 1; // 提供位置的程序名称。通过LocationManager设置,则可以是“gps”、“network”、“passive”或空。通过FusedLocationProviderClient设置,则是“fused”。 + int64 interval_ms = 2; // 位置请求所需的间隔时间(ms),间隔时间越短越耗电 + int64 fastest_interval_ms = 3; // 位置请求的最快间隔时间(ms) + Priority priority = 4; // 位置请求精确度,精确度越高越耗电 +} + +message LocationUpdateRequested { + PendingIntent intent = 1; // 要为每个位置更新发送的挂起内容的元数据 + int32 location_id = 2; // 位置ID + LocationRequest request = 3; // 位置更新请求 +} + +message LocationReport { + int32 location_id = 1; // 位置ID + float accuracy_of_metre = 2; // 该位置的估计水平精度,径向,单位为米。 +} + +message LocationUpdateRemoved { + int32 location_id = 1; // 位置ID +} + +message WorkInfo { + enum BatteryLevel { + BATTERY_LEVEL_LOW = 0; + BATTERY_LEVEL_OKAY = 1; + BATTERY_LEVEL_LOW_OR_OKAY = 2; + } + enum ChargeType { + CHARGING_PLUGGED_ANY = 0; + CHARGING_PLUGGED_AC = 1; + CHARGING_PLUGGED_USB = 2; + CHARGING_PLUGGED_WIRELESS = 3; + } + enum NetworkType { + NETWORK_TYPE_ANY = 0; + NETWORK_TYPE_MOBILE = 1; + NETWORK_TYPE_WIFI = 2; + NETWORK_TYPE_BLUETOOTH = 3; + NETWORK_TYPE_WIFI_P2P = 4; + NETWORK_TYPE_ETHERNET = 5; + } + enum StorageType { + STORAGE_LEVEL_LOW = 0; + STORAGE_LEVEL_OKAY = 1; + STORAGE_LEVEL_LOW_OR_OKAY = 2; + } + + string ability_name = 1; // 运行作业的页面名称 + string bundle_name = 2; // 运行作业的程序名称 + int32 repeat_counter = 3; // 重复作业次数 + int64 repeat_cycle_time = 4; // 定期作业重复的间隔时间 + BatteryLevel battery_level = 5; // 作业设备的电池等级 + int32 battery_status = 6; // 作业设备的电池状态 + ChargeType charge_type = 7; // 作业设备的充电类型 + int32 wait_time = 8; // 非定期作业的延迟时间 + NetworkType network_type = 9; // 作业运行的网络类型 + StorageType storage_type = 10; // 作业设备的存储类型 + bool is_request_battery = 11; // 作业是否需要设备的电池电量不低于临界阈值 + bool is_request_charging = 12; // 作业是否需要充电 + bool is_request_deep_idle = 13; // 作业是否需要设备处于空闲维护窗口中 + bool is_request_delay = 14; // 作业是否需要延迟 + bool is_request_network = 15; // 作业是否需要网络 + bool is_request_persisted = 16; // 是否应跨设备重新引导持久化此作业 + bool is_request_repeat = 17; // 是否在给定时间内重复作业 + bool is_request_storage = 18; // 作业是否需要设备的存储空间不低 + bool is_work_info_valid = 19; // 作业是否有效 +} + +message WorkStart { + int64 work_id = 1; + WorkInfo work_info = 2; + bool start_now = 3; + bool is_start = 4; +} + +message WorkCancel { + int64 work_id = 1; + bool is_cancel = 2; +} + +message WorkStop { + int64 work_id = 1; + bool is_stop = 2; +} + +message BackgroundWork { + int64 work_id = 1; + int32 actual_delay_time = 2; + int32 request_id = 3; + string reason = 4; +} + +message OnStartWork { + int64 work_id = 1; + WorkInfo work_info = 2; +} + +message OnStopWork { + int64 work_id = 1; +} + +message AgentEnergyEvent { + // timestamp obtained by CLOCK_REALTIME + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + string callstack = 3; // 生成此事件的调用堆栈 + oneof data { + RunningLockBegin runlock_begin = 4; // 获取唤醒锁(强制设备保持唤醒) + RunningLockEnd runlock_end = 5; // 释放唤醒锁 + OneShotStart oneshot_start = 6; // 闹钟 + RepeatStart repeat_start = 7; // 需要重复的闹钟 + TimerStop timer_stop = 8; + LocationUpdateRequested location_update_requested = 9; // 位置更新请求 + LocationReport location_report = 10; + LocationUpdateRemoved location_update_removed = 11; // 位置更新请求已删除 + WorkStart work_start = 12; + WorkCancel work_cancel = 13; + WorkStop work_stop = 14; + BackgroundWork back_work = 15; + OnStartWork on_start = 16; // 启动承载work的服务 + OnStopWork on_stop = 17; // 停止承载work的服务 + } +} + +message BatchAgentEnergyEvent { + repeated AgentEnergyEvent events = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_java_heap.proto b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_java_heap.proto new file mode 100755 index 0000000000000000000000000000000000000000..7b8930931acfcf27b02a64dcb15dd23670c1eb7e --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_java_heap.proto @@ -0,0 +1,62 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +// Java heap memory event from jvmti interface. +message ClassInfo { + int32 class_id = 1; + string class_name = 2; +} + +message AllocationInfo { + int32 object_id = 1; + int32 class_id = 2; + int32 object_size = 3; + int32 array_length = 4; + int32 heap_id = 5; + string thread_name = 6; + + message StackFrameInfo { + int32 frame_id = 1; + string class_name = 2; + string method_name = 3; + string file_name = 4; + int32 line_number = 5; + } + // First element means stack top. + repeated StackFrameInfo frame_info = 7; +} + +message DeallocationInfo { + int32 object_id = 1; +} + +message AgentMemoryEvent { + // timestamp obtained by CLOCK_REALTIME + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + + oneof event { + ClassInfo class_data = 3; + AllocationInfo alloc_data = 4; + DeallocationInfo free_data = 5; + } +} + +message BatchAgentMemoryEvent { + repeated AgentMemoryEvent events = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_network_data.proto b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_network_data.proto new file mode 100755 index 0000000000000000000000000000000000000000..918af6320a8c3b796c6343981fd2d5630d357c24 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_network_data.proto @@ -0,0 +1,64 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message HttpRequestHead { + string url = 1; + string method = 2; + string fields = 3; + string trace = 4; +} + +message HttpResponseHead { + string fields = 1; +} + +message HttpBody { + string payload_id = 1; + int32 payload_size = 2; + bytes payload_fields = 3; +} + +message HttpEndStatus { + bool aborted = 1; +} + +// thread +message AgentThread { + int64 id = 1; + string name = 2; +} + +message AgentNetworkEvent { + // timestamp obtained by CLOCK_REALTIME + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + int64 event_id = 3; + + oneof event { + HttpRequestHead request_head = 4; + HttpResponseHead response_head = 5; + HttpBody request_body = 6; + HttpBody response_body = 7; + HttpEndStatus end_status = 8; + AgentThread agent_thread = 9; + } +} + +message BatchAgentNetworkEvent { + repeated AgentNetworkEvent events = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_result.proto b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..ad9a3704af99363009136628db1a735ccdd40af6 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/agent_data/agent_plugin_result.proto @@ -0,0 +1,31 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +import "agent_plugin_java_heap.proto"; +import "agent_plugin_app_data.proto"; +import "agent_plugin_network_data.proto"; +import "agent_plugin_energy_data.proto"; + +message AgentData { + oneof data { + BatchAgentMemoryEvent javaheap_data = 1; + BatchAgentAbilityEvent app_data = 2; + BatchAgentNetworkEvent network_data = 3; + BatchAgentEnergyEvent energy_data = 4; + } +} diff --git a/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn b/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..a7b85d48602cd61601d2ef4b1d483ed3a1d1c10a --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/bytrace_plugin/BUILD.gn @@ -0,0 +1,63 @@ +# 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("../../../protos.gni") + +bytrace_plugin_protos_defines = [ "./bytrace_plugin_config.proto" ] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) +print("proto_out_dir", proto_out_dir, proto_rel_out_dir) + +####################################################### +bytrace_plugin_protos_codegen = [] +foreach(proto, bytrace_plugin_protos_defines) { + name = get_path_info(proto, "name") + bytrace_plugin_protos_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +action("bytrace_plugin_protos_protoc") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = bytrace_plugin_protos_defines + outputs = bytrace_plugin_protos_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +config("bytrace_plugin_protos_config") { + include_dirs = [ "$proto_out_dir" ] +} + +source_set("bytrace_plugin_protos_cpp") { + deps = [ ":bytrace_plugin_protos_protoc" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":bytrace_plugin_protos_config" ] + sources = bytrace_plugin_protos_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/bytrace_plugin/bytrace_plugin_config.proto b/trace_streamer/src/protos/types/plugins/bytrace_plugin/bytrace_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..8c26822268288ae9adca92f98e862583e0f141f5 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/bytrace_plugin/bytrace_plugin_config.proto @@ -0,0 +1,24 @@ +// 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. + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; + +message BytracePluginConfig { + uint32 buffe_size = 1; // Sets the size of the buffer (KB) for storing and reading traces. + repeated string categories = 2; // Lists available bytrace categories. + uint32 time = 3; // Sets the bytrace running duration in seconds (5s by default) + string clock = 4; // Sets the clock, which can be boot (default), global, mono, uptime, or perf. + string outfile_name = 5; // Sets the name of the target file (stdout by default). + bool is_root = 6; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..2725868646f3d6803db23fba03a1fd52f95b2225 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/cpu_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +cpu_data_sources = [ + "./cpu_plugin_config.proto", + "./cpu_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +cpu_data_codegen = [] +foreach(proto, cpu_data_sources) { + name = get_path_info(proto, "name") + cpu_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("cpu_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("cpu_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = cpu_data_sources + outputs = cpu_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("cpu_data_cpp") { + deps = [ ":cpu_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":cpu_include_config" ] + sources = cpu_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/cpu_data/cpu_plugin_config.proto b/trace_streamer/src/protos/types/plugins/cpu_data/cpu_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..f3a730c9846020f333726a3630bf8d16151ebe6c --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/cpu_data/cpu_plugin_config.proto @@ -0,0 +1,23 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + + +// Cpu plug-in configuration, passed to plug-in by plug-in service. +message CpuConfig { + int32 pid = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/cpu_data/cpu_plugin_result.proto b/trace_streamer/src/protos/types/plugins/cpu_data/cpu_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..781a8f521fea4878fc1bf53c040e32ec4d31d829 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/cpu_data/cpu_plugin_result.proto @@ -0,0 +1,75 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message SampleTimeStamp { + uint64 tv_sec = 1; + uint64 tv_nsec = 2; +} + +message CpuCoreFrequency { + int32 min_frequency_khz = 1; + int32 max_frequency_khz = 2; + int32 cur_frequency_khz = 3; +} + +message CpuCoreUsageInfo { + int32 cpu_core = 1; + int64 prev_system_cpu_time_ms = 2; + int64 prev_system_boot_time_ms = 3; + int64 system_cpu_time_ms = 4; + int64 system_boot_time_ms = 5; + CpuCoreFrequency frequency = 6; + bool is_little_core = 7; +} + +message CpuUsageInfo { + int64 prev_process_cpu_time_ms = 1; + int64 prev_system_cpu_time_ms = 2; + int64 prev_system_boot_time_ms = 3; + int64 process_cpu_time_ms = 4; + int64 system_cpu_time_ms = 5; + int64 system_boot_time_ms = 6; + repeated CpuCoreUsageInfo cores = 7; + SampleTimeStamp timestamp = 8; +} + +enum ThreadState { + THREAD_UNSPECIFIED = 0; + THREAD_RUNNING = 1; + THREAD_SLEEPING = 2; + THREAD_STOPPED = 3; + THREAD_WAITING = 4; +} + +message ThreadInfo { + int32 tid = 1; + string thread_name = 2; + ThreadState thread_state = 3; + int64 prev_thread_cpu_time_ms = 4; + int64 thread_cpu_time_ms = 5; + SampleTimeStamp timestamp = 6; +} + +message CpuData { + CpuUsageInfo cpu_usage_info = 1; + repeated ThreadInfo thread_info = 2; + int64 process_num = 3; + double user_load = 4; + double sys_load = 5; + double total_load = 6; +} diff --git a/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..b8011c2bbb269dc0153cc24af58c43a6e922a95d --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/diskio_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +diskio_data_sources = [ + "./diskio_plugin_config.proto", + "./diskio_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +diskio_data_codegen = [] +foreach(proto, diskio_data_sources) { + name = get_path_info(proto, "name") + diskio_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("diskio_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("diskio_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = diskio_data_sources + outputs = diskio_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("diskio_data_cpp") { + deps = [ ":diskio_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":diskio_include_config" ] + sources = diskio_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/diskio_data/diskio_plugin_config.proto b/trace_streamer/src/protos/types/plugins/diskio_data/diskio_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..8caac241978ff6910abff7aead9b0e60f22aa649 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/diskio_data/diskio_plugin_config.proto @@ -0,0 +1,28 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +// Diskio plug-in configuration, passed to plug-in by plug-in service. +message DiskioConfig { + int32 unspeci_fied = 1; // Reserved field, not used + enum IoReportType { + UNSPECIFIED = 0; + IO_REPORT = 1; + IO_REPORT_EX = 2; + } + IoReportType report_io_stats = 2; +} diff --git a/trace_streamer/src/protos/types/plugins/diskio_data/diskio_plugin_result.proto b/trace_streamer/src/protos/types/plugins/diskio_data/diskio_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..faabd31436d4dbf58c62c68330367b60b7c97cc4 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/diskio_data/diskio_plugin_result.proto @@ -0,0 +1,88 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message CollectTimeStamp { + uint64 tv_sec = 1; + uint64 tv_nsec = 2; +} + +message CpuStats { + string name = 1; + double cpu_user = 2; + double cpu_nice = 3; + double cpu_sys = 4; + double cpu_idle = 5; + double cpu_iowait = 6; + double cpu_steal = 7; +} + +message IoStatData { + string name = 1; + double ios_per_sec = 2; // 设备每秒的传输次数 + double rd_per_sec = 3; // 每秒从设备读取的数据量 kB_read/s + double wr_per_sec = 4; // 每秒向设备写入的数据量 kB_wrtn/s + double dc_per_sec = 5; // kB_dscd/s + uint64 rd_kb = 6; // 读取的总数据量 kB_read + uint64 wr_kb = 7; // 写入的总数量数据量 kB_wrtn + uint64 dc_kb = 8; // kB_dscd +} + +message IoStatExData { + string name = 1; + uint64 io_rd = 2; // r/s + uint64 io_rsectors = 3; // kB/s, r+w+d + uint64 io_rrqm = 4; // rrqm/s + uint64 io_rrqm_pc = 5; // %rrqm + uint64 io_r_await = 6; // r_await + uint64 io_rarqsz = 7; // rareq-sz + + uint64 io_wr = 8; // w/s + uint64 io_wsectors = 9; // wkB/s , r+w+d + uint64 io_wrqm = 10; // wrqm/s + uint64 io_wrqm_pc = 11; // %wrqm + uint64 io_w_await = 12; // w_await + uint64 io_warqsz = 13; // wareq-sz + + uint64 io_dc = 14; // d/s + uint64 io_dsectors = 15; // dkB/s, r+w+d + uint64 io_drqm = 16; // drqm/s + uint64 io_drqm_pc = 17; // %drqm + uint64 io_d_await = 18; // d_await + uint64 io_darqsz = 19; // dareq-sz + + uint64 io_fd = 20; // f/s + uint64 io_f_await = 21; // f_await + uint64 io_farqsz = 22; // fareq-sz + uint64 disk_util = 23; // fareq-sz +} + +message StatsData { + repeated CpuStats cpuinfo = 1; + repeated IoStatData statsinfo = 2; + repeated IoStatExData estatsinfo = 3; +} + +message DiskioData { + int64 prev_rd_sectors_kb = 1; + int64 prev_wr_sectors_kb = 2; + CollectTimeStamp prev_timestamp = 3; + int64 rd_sectors_kb = 4; + int64 wr_sectors_kb = 5; + CollectTimeStamp timestamp = 6; + StatsData statsData = 7; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/ftrace_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..642ccb83faa19bde9acbedb9efd1733f15baa848 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/BUILD.gn @@ -0,0 +1,67 @@ +# 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("../../../protos.gni") +import("autogenerated.gni") + +ftrace_data_sources = auto_generated_ftrace_proto_sources + [ + "trace_plugin_config.proto", + "trace_plugin_result.proto", + ] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +ftrace_data_codegen = [] +foreach(proto, ftrace_data_sources) { + dir = get_path_info(proto, "dir") + name = get_path_info(proto, "name") + ftrace_data_codegen += [ + "$proto_out_dir/$dir/$name.pb.h", + "$proto_out_dir/$dir/$name.pb.cc", + ] +} + +config("ftrace_data_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("ftrace_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = ftrace_data_sources + outputs = ftrace_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("ftrace_data_cpp") { + deps = [ ":ftrace_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":ftrace_data_include_config" ] + sources = ftrace_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/autogenerated.gni b/trace_streamer/src/protos/types/plugins/ftrace_data/autogenerated.gni new file mode 100755 index 0000000000000000000000000000000000000000..fcae596874f54b553a799e96b3f2022460405093 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/autogenerated.gni @@ -0,0 +1,48 @@ +# THIS FILE IS GENERATE BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +# 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. +auto_generated_ftrace_proto_sources = [ + "binder.proto", + "block.proto", + "cgroup.proto", + "clk.proto", + "compaction.proto", + "cpuhp.proto", + "dma_fence.proto", + "ext4.proto", + "filelock.proto", + "filemap.proto", + "ftrace.proto", + "ftrace_event.proto", + "gpio.proto", + "i2c.proto", + "ipi.proto", + "irq.proto", + "kmem.proto", + "net.proto", + "oom.proto", + "pagemap.proto", + "power.proto", + "printk.proto", + "raw_syscalls.proto", + "rcu.proto", + "sched.proto", + "signal.proto", + "sunrpc.proto", + "task.proto", + "timer.proto", + "v4l2.proto", + "vmscan.proto", + "workqueue.proto", + "writeback.proto", +] diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/binder.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/binder.proto new file mode 100755 index 0000000000000000000000000000000000000000..f1d0acd59d8986e9b5606fa3684bdebc76057726 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/binder.proto @@ -0,0 +1,216 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: binder +// /sys/kernel/debug/tracing/events/binder/binder_alloc_lru_end/format +message BinderAllocLruEndFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_alloc_lru_start/format +message BinderAllocLruStartFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_alloc_page_end/format +message BinderAllocPageEndFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_alloc_page_start/format +message BinderAllocPageStartFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_command/format +message BinderCommandFormat { + uint32 cmd = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_free_lru_end/format +message BinderFreeLruEndFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_free_lru_start/format +message BinderFreeLruStartFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_ioctl/format +message BinderIoctlFormat { + uint32 cmd = 1; + uint64 arg = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_ioctl_done/format +message BinderIoctlDoneFormat { + int32 ret = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_lock/format +message BinderLockFormat { + string tag = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_locked/format +message BinderLockedFormat { + string tag = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_read_done/format +message BinderReadDoneFormat { + int32 ret = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_return/format +message BinderReturnFormat { + uint32 cmd = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction/format +message BinderTransactionFormat { + int32 debug_id = 1; + int32 target_node = 2; + int32 to_proc = 3; + int32 to_thread = 4; + int32 reply = 5; + uint32 code = 6; + uint32 flags = 7; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_alloc_buf/format +message BinderTransactionAllocBufFormat { + int32 debug_id = 1; + uint64 data_size = 2; + uint64 offsets_size = 3; + uint64 extra_buffers_size = 4; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_buffer_release/format +message BinderTransactionBufferReleaseFormat { + int32 debug_id = 1; + uint64 data_size = 2; + uint64 offsets_size = 3; + uint64 extra_buffers_size = 4; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_failed_buffer_release/format +message BinderTransactionFailedBufferReleaseFormat { + int32 debug_id = 1; + uint64 data_size = 2; + uint64 offsets_size = 3; + uint64 extra_buffers_size = 4; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_fd/format +message BinderTransactionFdFormat { + int32 debug_id = 1; + int32 src_fd = 2; + int32 dest_fd = 3; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_node_to_ref/format +message BinderTransactionNodeToRefFormat { + int32 debug_id = 1; + int32 node_debug_id = 2; + uint64 node_ptr = 3; + int32 ref_debug_id = 4; + uint32 ref_desc = 5; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_received/format +message BinderTransactionReceivedFormat { + int32 debug_id = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_ref_to_node/format +message BinderTransactionRefToNodeFormat { + int32 debug_id = 1; + int32 ref_debug_id = 2; + uint32 ref_desc = 3; + int32 node_debug_id = 4; + uint64 node_ptr = 5; +} + +// /sys/kernel/debug/tracing/events/binder/binder_transaction_ref_to_ref/format +message BinderTransactionRefToRefFormat { + int32 debug_id = 1; + int32 node_debug_id = 2; + int32 src_ref_debug_id = 3; + uint32 src_ref_desc = 4; + int32 dest_ref_debug_id = 5; + uint32 dest_ref_desc = 6; +} + +// /sys/kernel/debug/tracing/events/binder/binder_unlock/format +message BinderUnlockFormat { + string tag = 1; +} + +// /sys/kernel/debug/tracing/events/binder/binder_unmap_kernel_end/format +message BinderUnmapKernelEndFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_unmap_kernel_start/format +message BinderUnmapKernelStartFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_unmap_user_end/format +message BinderUnmapUserEndFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_unmap_user_start/format +message BinderUnmapUserStartFormat { + int32 proc = 1; + uint64 page_index = 2; +} + +// /sys/kernel/debug/tracing/events/binder/binder_update_page_range/format +message BinderUpdatePageRangeFormat { + int32 proc = 1; + uint32 allocate = 2; + uint64 offset = 3; + uint64 size = 4; +} + +// /sys/kernel/debug/tracing/events/binder/binder_wait_for_work/format +message BinderWaitForWorkFormat { + uint32 proc_work = 1; + uint32 transaction_stack = 2; + uint32 thread_todo = 3; +} + +// /sys/kernel/debug/tracing/events/binder/binder_write_done/format +message BinderWriteDoneFormat { + int32 ret = 1; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/block.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/block.proto new file mode 100755 index 0000000000000000000000000000000000000000..5975c0e3ff1d4a4e6bd2cdd26e9ca4bba2409d1a --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/block.proto @@ -0,0 +1,179 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: block +// /sys/kernel/debug/tracing/events/block/block_bio_backmerge/format +message BlockBioBackmergeFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_bio_bounce/format +message BlockBioBounceFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_bio_complete/format +message BlockBioCompleteFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + int32 error = 4; + string rwbs = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_bio_frontmerge/format +message BlockBioFrontmergeFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_bio_queue/format +message BlockBioQueueFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_bio_remap/format +message BlockBioRemapFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + uint64 old_dev = 4; + uint64 old_sector = 5; + string rwbs = 6; +} + +// /sys/kernel/debug/tracing/events/block/block_dirty_buffer/format +message BlockDirtyBufferFormat { + uint64 dev = 1; + uint64 sector = 2; + uint64 size = 3; +} + +// /sys/kernel/debug/tracing/events/block/block_getrq/format +message BlockGetrqFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_plug/format +message BlockPlugFormat { + string comm = 1; +} + +// /sys/kernel/debug/tracing/events/block/block_rq_complete/format +message BlockRqCompleteFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + int32 error = 4; + string rwbs = 5; + string cmd = 6; +} + +// /sys/kernel/debug/tracing/events/block/block_rq_insert/format +message BlockRqInsertFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + uint32 bytes = 4; + string rwbs = 5; + string comm = 6; + string cmd = 7; +} + +// /sys/kernel/debug/tracing/events/block/block_rq_issue/format +message BlockRqIssueFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + uint32 bytes = 4; + string rwbs = 5; + string comm = 6; + string cmd = 7; +} + +// /sys/kernel/debug/tracing/events/block/block_rq_remap/format +message BlockRqRemapFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + uint64 old_dev = 4; + uint64 old_sector = 5; + uint32 nr_bios = 6; + string rwbs = 7; +} + +// /sys/kernel/debug/tracing/events/block/block_rq_requeue/format +message BlockRqRequeueFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string cmd = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_sleeprq/format +message BlockSleeprqFormat { + uint64 dev = 1; + uint64 sector = 2; + uint32 nr_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_split/format +message BlockSplitFormat { + uint64 dev = 1; + uint64 sector = 2; + uint64 new_sector = 3; + string rwbs = 4; + string comm = 5; +} + +// /sys/kernel/debug/tracing/events/block/block_touch_buffer/format +message BlockTouchBufferFormat { + uint64 dev = 1; + uint64 sector = 2; + uint64 size = 3; +} + +// /sys/kernel/debug/tracing/events/block/block_unplug/format +message BlockUnplugFormat { + int32 nr_rq = 1; + string comm = 2; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/cgroup.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/cgroup.proto new file mode 100755 index 0000000000000000000000000000000000000000..22544329885160245b94d20d0d8a6e1d51877328 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/cgroup.proto @@ -0,0 +1,93 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: cgroup +// /sys/kernel/debug/tracing/events/cgroup/cgroup_attach_task/format +message CgroupAttachTaskFormat { + int32 dst_root = 1; + int32 dst_id = 2; + int32 dst_level = 3; + int32 pid = 4; + string dst_path = 5; + string comm = 6; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_destroy_root/format +message CgroupDestroyRootFormat { + int32 root = 1; + uint32 ss_mask = 2; + string name = 3; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_mkdir/format +message CgroupMkdirFormat { + int32 root = 1; + int32 id = 2; + int32 level = 3; + string path = 4; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_release/format +message CgroupReleaseFormat { + int32 root = 1; + int32 id = 2; + int32 level = 3; + string path = 4; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_remount/format +message CgroupRemountFormat { + int32 root = 1; + uint32 ss_mask = 2; + string name = 3; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_rename/format +message CgroupRenameFormat { + int32 root = 1; + int32 id = 2; + int32 level = 3; + string path = 4; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_rmdir/format +message CgroupRmdirFormat { + int32 root = 1; + int32 id = 2; + int32 level = 3; + string path = 4; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_setup_root/format +message CgroupSetupRootFormat { + int32 root = 1; + uint32 ss_mask = 2; + string name = 3; +} + +// /sys/kernel/debug/tracing/events/cgroup/cgroup_transfer_tasks/format +message CgroupTransferTasksFormat { + int32 dst_root = 1; + int32 dst_id = 2; + int32 dst_level = 3; + int32 pid = 4; + string dst_path = 5; + string comm = 6; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/clk.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/clk.proto new file mode 100755 index 0000000000000000000000000000000000000000..0f74b25fb2eef0935707786bcf3402d169dd55f8 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/clk.proto @@ -0,0 +1,96 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: clk +// /sys/kernel/debug/tracing/events/clk/clk_disable/format +message ClkDisableFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_disable_complete/format +message ClkDisableCompleteFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_enable/format +message ClkEnableFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_enable_complete/format +message ClkEnableCompleteFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_prepare/format +message ClkPrepareFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_prepare_complete/format +message ClkPrepareCompleteFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_set_parent/format +message ClkSetParentFormat { + string name = 1; + string pname = 2; +} + +// /sys/kernel/debug/tracing/events/clk/clk_set_parent_complete/format +message ClkSetParentCompleteFormat { + string name = 1; + string pname = 2; +} + +// /sys/kernel/debug/tracing/events/clk/clk_set_phase/format +message ClkSetPhaseFormat { + string name = 1; + int32 phase = 2; +} + +// /sys/kernel/debug/tracing/events/clk/clk_set_phase_complete/format +message ClkSetPhaseCompleteFormat { + string name = 1; + int32 phase = 2; +} + +// /sys/kernel/debug/tracing/events/clk/clk_set_rate/format +message ClkSetRateFormat { + string name = 1; + uint64 rate = 2; +} + +// /sys/kernel/debug/tracing/events/clk/clk_set_rate_complete/format +message ClkSetRateCompleteFormat { + string name = 1; + uint64 rate = 2; +} + +// /sys/kernel/debug/tracing/events/clk/clk_unprepare/format +message ClkUnprepareFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/clk/clk_unprepare_complete/format +message ClkUnprepareCompleteFormat { + string name = 1; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/compaction.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/compaction.proto new file mode 100755 index 0000000000000000000000000000000000000000..2df331f2893674fb8d8d65163e25a9efba26e3e2 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/compaction.proto @@ -0,0 +1,114 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: compaction +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_begin/format +message MmCompactionBeginFormat { + uint64 zone_start = 1; + uint64 migrate_pfn = 2; + uint64 free_pfn = 3; + uint64 zone_end = 4; + uint32 sync = 5; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_defer_compaction/format +message MmCompactionDeferCompactionFormat { + int32 nid = 1; + uint32 idx = 2; + int32 order = 3; + uint32 considered = 4; + uint32 defer_shift = 5; + int32 order_failed = 6; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_defer_reset/format +message MmCompactionDeferResetFormat { + int32 nid = 1; + uint32 idx = 2; + int32 order = 3; + uint32 considered = 4; + uint32 defer_shift = 5; + int32 order_failed = 6; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_deferred/format +message MmCompactionDeferredFormat { + int32 nid = 1; + uint32 idx = 2; + int32 order = 3; + uint32 considered = 4; + uint32 defer_shift = 5; + int32 order_failed = 6; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_end/format +message MmCompactionEndFormat { + uint64 zone_start = 1; + uint64 migrate_pfn = 2; + uint64 free_pfn = 3; + uint64 zone_end = 4; + uint32 sync = 5; + int32 status = 6; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_finished/format +message MmCompactionFinishedFormat { + int32 nid = 1; + uint32 idx = 2; + int32 order = 3; + int32 ret = 4; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_isolate_freepages/format +message MmCompactionIsolateFreepagesFormat { + uint64 start_pfn = 1; + uint64 end_pfn = 2; + uint64 nr_scanned = 3; + uint64 nr_taken = 4; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_isolate_migratepages/format +message MmCompactionIsolateMigratepagesFormat { + uint64 start_pfn = 1; + uint64 end_pfn = 2; + uint64 nr_scanned = 3; + uint64 nr_taken = 4; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_migratepages/format +message MmCompactionMigratepagesFormat { + uint64 nr_migrated = 1; + uint64 nr_failed = 2; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_suitable/format +message MmCompactionSuitableFormat { + int32 nid = 1; + uint32 idx = 2; + int32 order = 3; + int32 ret = 4; +} + +// /sys/kernel/debug/tracing/events/compaction/mm_compaction_try_to_compact_pages/format +message MmCompactionTryToCompactPagesFormat { + int32 order = 1; + uint32 gfp_mask = 2; + int32 prio = 3; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/cpuhp.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/cpuhp.proto new file mode 100755 index 0000000000000000000000000000000000000000..db805bc33e41cdc383846b1f81ab9dd358456cc5 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/cpuhp.proto @@ -0,0 +1,44 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: cpuhp +// /sys/kernel/debug/tracing/events/cpuhp/cpuhp_enter/format +message CpuhpEnterFormat { + uint32 cpu = 1; + int32 target = 2; + int32 idx = 3; + uint64 fun = 4; +} + +// /sys/kernel/debug/tracing/events/cpuhp/cpuhp_exit/format +message CpuhpExitFormat { + uint32 cpu = 1; + int32 state = 2; + int32 idx = 3; + int32 ret = 4; +} + +// /sys/kernel/debug/tracing/events/cpuhp/cpuhp_multi_enter/format +message CpuhpMultiEnterFormat { + uint32 cpu = 1; + int32 target = 2; + int32 idx = 3; + uint64 fun = 4; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/dma_fence.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/dma_fence.proto new file mode 100755 index 0000000000000000000000000000000000000000..74b511b8f5be7f6f77db7b9dfd351393dc38c53e --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/dma_fence.proto @@ -0,0 +1,76 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: dma_fence +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_destroy/format +message DmaFenceDestroyFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_emit/format +message DmaFenceEmitFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_enable_signal/format +message DmaFenceEnableSignalFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_init/format +message DmaFenceInitFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_signaled/format +message DmaFenceSignaledFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_wait_end/format +message DmaFenceWaitEndFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + +// /sys/kernel/debug/tracing/events/dma_fence/dma_fence_wait_start/format +message DmaFenceWaitStartFormat { + string driver = 1; + string timeline = 2; + uint32 context = 3; + uint32 seqno = 4; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/ext4.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/ext4.proto new file mode 100755 index 0000000000000000000000000000000000000000..d66f4baaebf2e2bba8ee3428377e76ee502a1e02 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/ext4.proto @@ -0,0 +1,872 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: ext4 +// /sys/kernel/debug/tracing/events/ext4/ext4_alloc_da_blocks/format +message Ext4AllocDaBlocksFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 data_blocks = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_allocate_blocks/format +message Ext4AllocateBlocksFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 block = 3; + uint32 len = 4; + uint32 logical = 5; + uint32 lleft = 6; + uint32 lright = 7; + uint64 goal = 8; + uint64 pleft = 9; + uint64 pright = 10; + uint32 flags = 11; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_allocate_inode/format +message Ext4AllocateInodeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 dir = 3; + uint32 mode = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_begin_ordered_truncate/format +message Ext4BeginOrderedTruncateFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 new_size = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_collapse_range/format +message Ext4CollapseRangeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 offset = 3; + uint64 len = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_release_space/format +message Ext4DaReleaseSpaceFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 i_blocks = 3; + int32 freed_blocks = 4; + int32 reserved_data_blocks = 5; + uint32 mode = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_reserve_space/format +message Ext4DaReserveSpaceFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 i_blocks = 3; + int32 reserved_data_blocks = 4; + uint32 mode = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_update_reserve_space/format +message Ext4DaUpdateReserveSpaceFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 i_blocks = 3; + int32 used_blocks = 4; + int32 reserved_data_blocks = 5; + int32 quota_claim = 6; + uint32 mode = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/format +message Ext4DaWriteBeginFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint32 len = 4; + uint32 flags = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/format +message Ext4DaWriteEndFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint32 len = 4; + uint32 copied = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_write_pages/format +message Ext4DaWritePagesFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 first_page = 3; + uint64 nr_to_write = 4; + int32 sync_mode = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_da_write_pages_extent/format +message Ext4DaWritePagesExtentFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 lblk = 3; + uint32 len = 4; + uint32 flags = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_direct_IO_enter/format +message Ext4DirectIoEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint64 len = 4; + int32 rw = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_direct_IO_exit/format +message Ext4DirectIoExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint64 len = 4; + int32 rw = 5; + int32 ret = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_discard_blocks/format +message Ext4DiscardBlocksFormat { + uint64 dev = 1; + uint64 blk = 2; + uint64 count = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_discard_preallocations/format +message Ext4DiscardPreallocationsFormat { + uint64 dev = 1; + uint64 ino = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_drop_inode/format +message Ext4DropInodeFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 drop = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_cache_extent/format +message Ext4EsCacheExtentFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint64 pblk = 5; + uint32 status = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_find_delayed_extent_range_enter/format +message Ext4EsFindDelayedExtentRangeEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_find_delayed_extent_range_exit/format +message Ext4EsFindDelayedExtentRangeExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint64 pblk = 5; + uint32 status = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_insert_extent/format +message Ext4EsInsertExtentFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint64 pblk = 5; + uint32 status = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_enter/format +message Ext4EsLookupExtentEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_lookup_extent_exit/format +message Ext4EsLookupExtentExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint64 pblk = 5; + uint32 status = 6; + int32 found = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_remove_extent/format +message Ext4EsRemoveExtentFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 lblk = 3; + uint64 len = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_shrink/format +message Ext4EsShrinkFormat { + uint64 dev = 1; + int32 nr_shrunk = 2; + uint64 scan_time = 3; + int32 nr_skipped = 4; + int32 retried = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_shrink_count/format +message Ext4EsShrinkCountFormat { + uint64 dev = 1; + int32 nr_to_scan = 2; + int32 cache_cnt = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_shrink_scan_enter/format +message Ext4EsShrinkScanEnterFormat { + uint64 dev = 1; + int32 nr_to_scan = 2; + int32 cache_cnt = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_es_shrink_scan_exit/format +message Ext4EsShrinkScanExitFormat { + uint64 dev = 1; + int32 nr_shrunk = 2; + int32 cache_cnt = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_evict_inode/format +message Ext4EvictInodeFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 nlink = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_convert_to_initialized_enter/format +message Ext4ExtConvertToInitializedEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 m_lblk = 3; + uint32 m_len = 4; + uint32 u_lblk = 5; + uint32 u_len = 6; + uint64 u_pblk = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_convert_to_initialized_fastpath/format +message Ext4ExtConvertToInitializedFastpathFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 m_lblk = 3; + uint32 m_len = 4; + uint32 u_lblk = 5; + uint32 u_len = 6; + uint64 u_pblk = 7; + uint32 i_lblk = 8; + uint32 i_len = 9; + uint64 i_pblk = 10; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_handle_unwritten_extents/format +message Ext4ExtHandleUnwrittenExtentsFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 flags = 3; + uint32 lblk = 4; + uint64 pblk = 5; + uint32 len = 6; + uint32 allocated = 7; + uint64 newblk = 8; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_in_cache/format +message Ext4ExtInCacheFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + int32 ret = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_load_extent/format +message Ext4ExtLoadExtentFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pblk = 3; + uint32 lblk = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_map_blocks_enter/format +message Ext4ExtMapBlocksEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint32 flags = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_map_blocks_exit/format +message Ext4ExtMapBlocksExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 flags = 3; + uint64 pblk = 4; + uint32 lblk = 5; + uint32 len = 6; + uint32 mflags = 7; + int32 ret = 8; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_put_in_cache/format +message Ext4ExtPutInCacheFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint64 start = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_remove_space/format +message Ext4ExtRemoveSpaceFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 start = 3; + uint32 end = 4; + int32 depth = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_remove_space_done/format +message Ext4ExtRemoveSpaceDoneFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 start = 3; + uint32 end = 4; + int32 depth = 5; + uint64 partial = 6; + uint32 eh_entries = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_rm_idx/format +message Ext4ExtRmIdxFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pblk = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_rm_leaf/format +message Ext4ExtRmLeafFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 partial = 3; + uint32 start = 4; + uint32 ee_lblk = 5; + uint64 ee_pblk = 6; + int32 ee_len = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ext_show_extent/format +message Ext4ExtShowExtentFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pblk = 3; + uint32 lblk = 4; + uint32 len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_fallocate_enter/format +message Ext4FallocateEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 offset = 3; + uint64 len = 4; + int32 mode = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_fallocate_exit/format +message Ext4FallocateExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint32 blocks = 4; + int32 ret = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_find_delalloc_range/format +message Ext4FindDelallocRangeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 from = 3; + uint32 to = 4; + int32 reverse = 5; + int32 found = 6; + uint32 found_blk = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_forget/format +message Ext4ForgetFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 block = 3; + int32 is_metadata = 4; + uint32 mode = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_free_blocks/format +message Ext4FreeBlocksFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 block = 3; + uint64 count = 4; + int32 flags = 5; + uint32 mode = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_free_inode/format +message Ext4FreeInodeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 uid = 3; + uint32 gid = 4; + uint64 blocks = 5; + uint32 mode = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_get_implied_cluster_alloc_exit/format +message Ext4GetImpliedClusterAllocExitFormat { + uint64 dev = 1; + uint32 flags = 2; + uint32 lblk = 3; + uint64 pblk = 4; + uint32 len = 5; + int32 ret = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_get_reserved_cluster_alloc/format +message Ext4GetReservedClusterAllocFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ind_map_blocks_enter/format +message Ext4IndMapBlocksEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 lblk = 3; + uint32 len = 4; + uint32 flags = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_ind_map_blocks_exit/format +message Ext4IndMapBlocksExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 flags = 3; + uint64 pblk = 4; + uint32 lblk = 5; + uint32 len = 6; + uint32 mflags = 7; + int32 ret = 8; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_insert_range/format +message Ext4InsertRangeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 offset = 3; + uint64 len = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_invalidatepage/format +message Ext4InvalidatepageFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 index = 3; + uint32 offset = 4; + uint32 length = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_journal_start/format +message Ext4JournalStartFormat { + uint64 dev = 1; + uint64 ip = 2; + int32 blocks = 3; + int32 rsv_blocks = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_journal_start_reserved/format +message Ext4JournalStartReservedFormat { + uint64 dev = 1; + uint64 ip = 2; + int32 blocks = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_journalled_invalidatepage/format +message Ext4JournalledInvalidatepageFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 index = 3; + uint32 offset = 4; + uint32 length = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_journalled_write_end/format +message Ext4JournalledWriteEndFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint32 len = 4; + uint32 copied = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_load_inode/format +message Ext4LoadInodeFormat { + uint64 dev = 1; + uint64 ino = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_load_inode_bitmap/format +message Ext4LoadInodeBitmapFormat { + uint64 dev = 1; + uint32 group = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mark_inode_dirty/format +message Ext4MarkInodeDirtyFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 ip = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_bitmap_load/format +message Ext4MbBitmapLoadFormat { + uint64 dev = 1; + uint32 group = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_buddy_bitmap_load/format +message Ext4MbBuddyBitmapLoadFormat { + uint64 dev = 1; + uint32 group = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_discard_preallocations/format +message Ext4MbDiscardPreallocationsFormat { + uint64 dev = 1; + int32 needed = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_new_group_pa/format +message Ext4MbNewGroupPaFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pa_pstart = 3; + uint64 pa_lstart = 4; + uint32 pa_len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_new_inode_pa/format +message Ext4MbNewInodePaFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pa_pstart = 3; + uint64 pa_lstart = 4; + uint32 pa_len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_release_group_pa/format +message Ext4MbReleaseGroupPaFormat { + uint64 dev = 1; + uint64 pa_pstart = 2; + uint32 pa_len = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mb_release_inode_pa/format +message Ext4MbReleaseInodePaFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 block = 3; + uint32 count = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mballoc_alloc/format +message Ext4MballocAllocFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 orig_logical = 3; + int32 orig_start = 4; + uint32 orig_group = 5; + int32 orig_len = 6; + uint32 goal_logical = 7; + int32 goal_start = 8; + uint32 goal_group = 9; + int32 goal_len = 10; + uint32 result_logical = 11; + int32 result_start = 12; + uint32 result_group = 13; + int32 result_len = 14; + uint32 found = 15; + uint32 groups = 16; + uint32 buddy = 17; + uint32 flags = 18; + uint32 tail = 19; + uint32 cr = 20; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mballoc_discard/format +message Ext4MballocDiscardFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 result_start = 3; + uint32 result_group = 4; + int32 result_len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mballoc_free/format +message Ext4MballocFreeFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 result_start = 3; + uint32 result_group = 4; + int32 result_len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_mballoc_prealloc/format +message Ext4MballocPreallocFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 orig_logical = 3; + int32 orig_start = 4; + uint32 orig_group = 5; + int32 orig_len = 6; + uint32 result_logical = 7; + int32 result_start = 8; + uint32 result_group = 9; + int32 result_len = 10; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_other_inode_update_time/format +message Ext4OtherInodeUpdateTimeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 orig_ino = 3; + uint32 uid = 4; + uint32 gid = 5; + uint32 mode = 6; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_punch_hole/format +message Ext4PunchHoleFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 offset = 3; + uint64 len = 4; + int32 mode = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_read_block_bitmap_load/format +message Ext4ReadBlockBitmapLoadFormat { + uint64 dev = 1; + uint32 group = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_readpage/format +message Ext4ReadpageFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 index = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_releasepage/format +message Ext4ReleasepageFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 index = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_remove_blocks/format +message Ext4RemoveBlocksFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 from = 3; + uint32 to = 4; + uint64 partial = 5; + uint64 ee_pblk = 6; + uint32 ee_lblk = 7; + uint32 ee_len = 8; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_request_blocks/format +message Ext4RequestBlocksFormat { + uint64 dev = 1; + uint64 ino = 2; + uint32 len = 3; + uint32 logical = 4; + uint32 lleft = 5; + uint32 lright = 6; + uint64 goal = 7; + uint64 pleft = 8; + uint64 pright = 9; + uint32 flags = 10; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_request_inode/format +message Ext4RequestInodeFormat { + uint64 dev = 1; + uint64 dir = 2; + uint32 mode = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/format +message Ext4SyncFileEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 parent = 3; + int32 datasync = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/format +message Ext4SyncFileExitFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 ret = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_sync_fs/format +message Ext4SyncFsFormat { + uint64 dev = 1; + int32 wait = 2; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_trim_all_free/format +message Ext4TrimAllFreeFormat { + int32 dev_major = 1; + int32 dev_minor = 2; + uint32 group = 3; + int32 start = 4; + int32 len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_trim_extent/format +message Ext4TrimExtentFormat { + int32 dev_major = 1; + int32 dev_minor = 2; + uint32 group = 3; + int32 start = 4; + int32 len = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_truncate_enter/format +message Ext4TruncateEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 blocks = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_truncate_exit/format +message Ext4TruncateExitFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 blocks = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_unlink_enter/format +message Ext4UnlinkEnterFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 parent = 3; + uint64 size = 4; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_unlink_exit/format +message Ext4UnlinkExitFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 ret = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_write_begin/format +message Ext4WriteBeginFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint32 len = 4; + uint32 flags = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_write_end/format +message Ext4WriteEndFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 pos = 3; + uint32 len = 4; + uint32 copied = 5; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_writepage/format +message Ext4WritepageFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 index = 3; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_writepages/format +message Ext4WritepagesFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 nr_to_write = 3; + uint64 pages_skipped = 4; + uint64 range_start = 5; + uint64 range_end = 6; + uint64 writeback_index = 7; + int32 sync_mode = 8; + uint32 for_kupdate = 9; + uint32 range_cyclic = 10; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_writepages_result/format +message Ext4WritepagesResultFormat { + uint64 dev = 1; + uint64 ino = 2; + int32 ret = 3; + int32 pages_written = 4; + uint64 pages_skipped = 5; + uint64 writeback_index = 6; + int32 sync_mode = 7; +} + +// /sys/kernel/debug/tracing/events/ext4/ext4_zero_range/format +message Ext4ZeroRangeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 offset = 3; + uint64 len = 4; + int32 mode = 5; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/filelock.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/filelock.proto new file mode 100755 index 0000000000000000000000000000000000000000..1a52d8c9f3c34b90b57db8f8da444eb2d7c62c91 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/filelock.proto @@ -0,0 +1,97 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: filelock +// /sys/kernel/debug/tracing/events/filelock/break_lease_block/format +message BreakLeaseBlockFormat { + uint64 fl = 1; + uint64 i_ino = 2; + uint64 s_dev = 3; + uint64 fl_next = 4; + uint32 fl_owner = 5; + uint32 fl_flags = 6; + uint32 fl_type = 7; + uint64 fl_break_time = 8; + uint64 fl_downgrade_time = 9; +} + +// /sys/kernel/debug/tracing/events/filelock/break_lease_noblock/format +message BreakLeaseNoblockFormat { + uint64 fl = 1; + uint64 i_ino = 2; + uint64 s_dev = 3; + uint64 fl_next = 4; + uint32 fl_owner = 5; + uint32 fl_flags = 6; + uint32 fl_type = 7; + uint64 fl_break_time = 8; + uint64 fl_downgrade_time = 9; +} + +// /sys/kernel/debug/tracing/events/filelock/break_lease_unblock/format +message BreakLeaseUnblockFormat { + uint64 fl = 1; + uint64 i_ino = 2; + uint64 s_dev = 3; + uint64 fl_next = 4; + uint32 fl_owner = 5; + uint32 fl_flags = 6; + uint32 fl_type = 7; + uint64 fl_break_time = 8; + uint64 fl_downgrade_time = 9; +} + +// /sys/kernel/debug/tracing/events/filelock/generic_add_lease/format +message GenericAddLeaseFormat { + uint64 i_ino = 1; + int32 wcount = 2; + int32 dcount = 3; + int32 icount = 4; + uint64 s_dev = 5; + uint32 fl_owner = 6; + uint32 fl_flags = 7; + uint32 fl_type = 8; +} + +// /sys/kernel/debug/tracing/events/filelock/generic_delete_lease/format +message GenericDeleteLeaseFormat { + uint64 fl = 1; + uint64 i_ino = 2; + uint64 s_dev = 3; + uint64 fl_next = 4; + uint32 fl_owner = 5; + uint32 fl_flags = 6; + uint32 fl_type = 7; + uint64 fl_break_time = 8; + uint64 fl_downgrade_time = 9; +} + +// /sys/kernel/debug/tracing/events/filelock/time_out_leases/format +message TimeOutLeasesFormat { + uint64 fl = 1; + uint64 i_ino = 2; + uint64 s_dev = 3; + uint64 fl_next = 4; + uint32 fl_owner = 5; + uint32 fl_flags = 6; + uint32 fl_type = 7; + uint64 fl_break_time = 8; + uint64 fl_downgrade_time = 9; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/filemap.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/filemap.proto new file mode 100755 index 0000000000000000000000000000000000000000..5410c6f4f35946198bab32688f1f0eae025873ee --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/filemap.proto @@ -0,0 +1,36 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: filemap +// /sys/kernel/debug/tracing/events/filemap/mm_filemap_add_to_page_cache/format +message MmFilemapAddToPageCacheFormat { + uint64 pfn = 1; + uint64 i_ino = 2; + uint64 index = 3; + uint64 s_dev = 4; +} + +// /sys/kernel/debug/tracing/events/filemap/mm_filemap_delete_from_page_cache/format +message MmFilemapDeleteFromPageCacheFormat { + uint64 pfn = 1; + uint64 i_ino = 2; + uint64 index = 3; + uint64 s_dev = 4; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/ftrace.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/ftrace.proto new file mode 100755 index 0000000000000000000000000000000000000000..80c23a999c8129916bd7608b0e3c99fe107181b4 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/ftrace.proto @@ -0,0 +1,115 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: ftrace +// /sys/kernel/debug/tracing/events/ftrace/bputs/format +message BputsFormat { + uint64 ip = 1; + string str = 2; +} + +// /sys/kernel/debug/tracing/events/ftrace/branch/format +message BranchFormat { + uint32 line = 1; + string func = 2; + string file = 3; + uint32 correct = 4; + uint32 constant = 5; +} + +// /sys/kernel/debug/tracing/events/ftrace/context_switch/format +message ContextSwitchFormat { + uint32 prev_pid = 1; + uint32 next_pid = 2; + uint32 next_cpu = 3; + uint32 prev_prio = 4; + uint32 prev_state = 5; + uint32 next_prio = 6; + uint32 next_state = 7; +} + +// /sys/kernel/debug/tracing/events/ftrace/funcgraph_entry/format +message FuncgraphEntryFormat { + uint64 func = 1; + int32 depth = 2; +} + +// /sys/kernel/debug/tracing/events/ftrace/funcgraph_exit/format +message FuncgraphExitFormat { + uint64 func = 1; + uint64 calltime = 2; + uint64 rettime = 3; + uint64 overrun = 4; + int32 depth = 5; +} + +// /sys/kernel/debug/tracing/events/ftrace/function/format +message FunctionFormat { + uint64 ip = 1; + uint64 parent_ip = 2; +} + +// /sys/kernel/debug/tracing/events/ftrace/kernel_stack/format +message KernelStackFormat { + int32 size = 1; + repeated uint64 caller = 2; +} + +// /sys/kernel/debug/tracing/events/ftrace/mmiotrace_map/format +message MmiotraceMapFormat { + uint64 phys = 1; + uint64 virt = 2; + uint64 len = 3; + int32 map_id = 4; + uint32 opcode = 5; +} + +// /sys/kernel/debug/tracing/events/ftrace/mmiotrace_rw/format +message MmiotraceRwFormat { + uint64 phys = 1; + uint64 value = 2; + uint64 pc = 3; + int32 map_id = 4; + uint32 opcode = 5; + uint32 width = 6; +} + +// /sys/kernel/debug/tracing/events/ftrace/print/format +message PrintFormat { + uint64 ip = 1; + string buf = 2; +} + +// /sys/kernel/debug/tracing/events/ftrace/user_stack/format +message UserStackFormat { + uint32 tgid = 1; + repeated uint64 caller = 2; +} + +// /sys/kernel/debug/tracing/events/ftrace/wakeup/format +message WakeupFormat { + uint32 prev_pid = 1; + uint32 next_pid = 2; + uint32 next_cpu = 3; + uint32 prev_prio = 4; + uint32 prev_state = 5; + uint32 next_prio = 6; + uint32 next_state = 7; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/ftrace_event.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/ftrace_event.proto new file mode 100755 index 0000000000000000000000000000000000000000..3ddd7e4aef2ce6a84e9eaae7fa7a6733c3a720f0 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/ftrace_event.proto @@ -0,0 +1,453 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +import "binder.proto"; +import "block.proto"; +import "cgroup.proto"; +import "clk.proto"; +import "compaction.proto"; +import "cpuhp.proto"; +import "dma_fence.proto"; +import "ext4.proto"; +import "filelock.proto"; +import "filemap.proto"; +import "ftrace.proto"; +import "gpio.proto"; +import "i2c.proto"; +import "ipi.proto"; +import "irq.proto"; +import "kmem.proto"; +import "net.proto"; +import "oom.proto"; +import "pagemap.proto"; +import "power.proto"; +import "printk.proto"; +import "raw_syscalls.proto"; +import "rcu.proto"; +import "sched.proto"; +import "signal.proto"; +import "sunrpc.proto"; +import "task.proto"; +import "timer.proto"; +import "v4l2.proto"; +import "vmscan.proto"; +import "workqueue.proto"; +import "writeback.proto"; + +message FtraceEvent { + uint64 timestamp = 1; + int32 tgid = 2; + string comm = 3; + + message CommonFileds { + uint32 type = 1; + uint32 flags = 2; + uint32 preempt_count = 3; + int32 pid = 4; + }; + CommonFileds common_fields = 50; + + oneof event { + BinderAllocLruEndFormat binder_alloc_lru_end_format = 100; + BinderAllocLruStartFormat binder_alloc_lru_start_format = 101; + BinderAllocPageEndFormat binder_alloc_page_end_format = 102; + BinderAllocPageStartFormat binder_alloc_page_start_format = 103; + BinderCommandFormat binder_command_format = 104; + BinderFreeLruEndFormat binder_free_lru_end_format = 105; + BinderFreeLruStartFormat binder_free_lru_start_format = 106; + BinderIoctlFormat binder_ioctl_format = 107; + BinderIoctlDoneFormat binder_ioctl_done_format = 108; + BinderLockFormat binder_lock_format = 109; + BinderLockedFormat binder_locked_format = 110; + BinderReadDoneFormat binder_read_done_format = 111; + BinderReturnFormat binder_return_format = 112; + BinderTransactionFormat binder_transaction_format = 113; + BinderTransactionAllocBufFormat binder_transaction_alloc_buf_format = 114; + BinderTransactionBufferReleaseFormat binder_transaction_buffer_release_format = 115; + BinderTransactionFailedBufferReleaseFormat binder_transaction_failed_buffer_release_format = 116; + BinderTransactionFdFormat binder_transaction_fd_format = 117; + BinderTransactionNodeToRefFormat binder_transaction_node_to_ref_format = 118; + BinderTransactionReceivedFormat binder_transaction_received_format = 119; + BinderTransactionRefToNodeFormat binder_transaction_ref_to_node_format = 120; + BinderTransactionRefToRefFormat binder_transaction_ref_to_ref_format = 121; + BinderUnlockFormat binder_unlock_format = 122; + BinderUnmapKernelEndFormat binder_unmap_kernel_end_format = 123; + BinderUnmapKernelStartFormat binder_unmap_kernel_start_format = 124; + BinderUnmapUserEndFormat binder_unmap_user_end_format = 125; + BinderUnmapUserStartFormat binder_unmap_user_start_format = 126; + BinderUpdatePageRangeFormat binder_update_page_range_format = 127; + BinderWaitForWorkFormat binder_wait_for_work_format = 128; + BinderWriteDoneFormat binder_write_done_format = 129; + BlockBioBackmergeFormat block_bio_backmerge_format = 200; + BlockBioBounceFormat block_bio_bounce_format = 201; + BlockBioCompleteFormat block_bio_complete_format = 202; + BlockBioFrontmergeFormat block_bio_frontmerge_format = 203; + BlockBioQueueFormat block_bio_queue_format = 204; + BlockBioRemapFormat block_bio_remap_format = 205; + BlockDirtyBufferFormat block_dirty_buffer_format = 206; + BlockGetrqFormat block_getrq_format = 207; + BlockPlugFormat block_plug_format = 208; + BlockRqCompleteFormat block_rq_complete_format = 209; + BlockRqInsertFormat block_rq_insert_format = 210; + BlockRqIssueFormat block_rq_issue_format = 211; + BlockRqRemapFormat block_rq_remap_format = 212; + BlockRqRequeueFormat block_rq_requeue_format = 213; + BlockSleeprqFormat block_sleeprq_format = 214; + BlockSplitFormat block_split_format = 215; + BlockTouchBufferFormat block_touch_buffer_format = 216; + BlockUnplugFormat block_unplug_format = 217; + CgroupAttachTaskFormat cgroup_attach_task_format = 300; + CgroupDestroyRootFormat cgroup_destroy_root_format = 301; + CgroupMkdirFormat cgroup_mkdir_format = 302; + CgroupReleaseFormat cgroup_release_format = 303; + CgroupRemountFormat cgroup_remount_format = 304; + CgroupRenameFormat cgroup_rename_format = 305; + CgroupRmdirFormat cgroup_rmdir_format = 306; + CgroupSetupRootFormat cgroup_setup_root_format = 307; + CgroupTransferTasksFormat cgroup_transfer_tasks_format = 308; + ClkDisableFormat clk_disable_format = 400; + ClkDisableCompleteFormat clk_disable_complete_format = 401; + ClkEnableFormat clk_enable_format = 402; + ClkEnableCompleteFormat clk_enable_complete_format = 403; + ClkPrepareFormat clk_prepare_format = 404; + ClkPrepareCompleteFormat clk_prepare_complete_format = 405; + ClkSetParentFormat clk_set_parent_format = 406; + ClkSetParentCompleteFormat clk_set_parent_complete_format = 407; + ClkSetPhaseFormat clk_set_phase_format = 408; + ClkSetPhaseCompleteFormat clk_set_phase_complete_format = 409; + ClkSetRateFormat clk_set_rate_format = 410; + ClkSetRateCompleteFormat clk_set_rate_complete_format = 411; + ClkUnprepareFormat clk_unprepare_format = 412; + ClkUnprepareCompleteFormat clk_unprepare_complete_format = 413; + MmCompactionBeginFormat mm_compaction_begin_format = 500; + MmCompactionDeferCompactionFormat mm_compaction_defer_compaction_format = 501; + MmCompactionDeferResetFormat mm_compaction_defer_reset_format = 502; + MmCompactionDeferredFormat mm_compaction_deferred_format = 503; + MmCompactionEndFormat mm_compaction_end_format = 504; + MmCompactionFinishedFormat mm_compaction_finished_format = 505; + MmCompactionIsolateFreepagesFormat mm_compaction_isolate_freepages_format = 506; + MmCompactionIsolateMigratepagesFormat mm_compaction_isolate_migratepages_format = 507; + MmCompactionMigratepagesFormat mm_compaction_migratepages_format = 508; + MmCompactionSuitableFormat mm_compaction_suitable_format = 509; + MmCompactionTryToCompactPagesFormat mm_compaction_try_to_compact_pages_format = 510; + CpuhpEnterFormat cpuhp_enter_format = 600; + CpuhpExitFormat cpuhp_exit_format = 601; + CpuhpMultiEnterFormat cpuhp_multi_enter_format = 602; + DmaFenceDestroyFormat dma_fence_destroy_format = 700; + DmaFenceEmitFormat dma_fence_emit_format = 701; + DmaFenceEnableSignalFormat dma_fence_enable_signal_format = 702; + DmaFenceInitFormat dma_fence_init_format = 703; + DmaFenceSignaledFormat dma_fence_signaled_format = 704; + DmaFenceWaitEndFormat dma_fence_wait_end_format = 705; + DmaFenceWaitStartFormat dma_fence_wait_start_format = 706; + Ext4AllocDaBlocksFormat ext4_alloc_da_blocks_format = 800; + Ext4AllocateBlocksFormat ext4_allocate_blocks_format = 801; + Ext4AllocateInodeFormat ext4_allocate_inode_format = 802; + Ext4BeginOrderedTruncateFormat ext4_begin_ordered_truncate_format = 803; + Ext4CollapseRangeFormat ext4_collapse_range_format = 804; + Ext4DaReleaseSpaceFormat ext4_da_release_space_format = 805; + Ext4DaReserveSpaceFormat ext4_da_reserve_space_format = 806; + Ext4DaUpdateReserveSpaceFormat ext4_da_update_reserve_space_format = 807; + Ext4DaWriteBeginFormat ext4_da_write_begin_format = 808; + Ext4DaWriteEndFormat ext4_da_write_end_format = 809; + Ext4DaWritePagesFormat ext4_da_write_pages_format = 810; + Ext4DaWritePagesExtentFormat ext4_da_write_pages_extent_format = 811; + Ext4DirectIoEnterFormat ext4_direct_io_enter_format = 812; + Ext4DirectIoExitFormat ext4_direct_io_exit_format = 813; + Ext4DiscardBlocksFormat ext4_discard_blocks_format = 814; + Ext4DiscardPreallocationsFormat ext4_discard_preallocations_format = 815; + Ext4DropInodeFormat ext4_drop_inode_format = 816; + Ext4EsCacheExtentFormat ext4_es_cache_extent_format = 817; + Ext4EsFindDelayedExtentRangeEnterFormat ext4_es_find_delayed_extent_range_enter_format = 818; + Ext4EsFindDelayedExtentRangeExitFormat ext4_es_find_delayed_extent_range_exit_format = 819; + Ext4EsInsertExtentFormat ext4_es_insert_extent_format = 820; + Ext4EsLookupExtentEnterFormat ext4_es_lookup_extent_enter_format = 821; + Ext4EsLookupExtentExitFormat ext4_es_lookup_extent_exit_format = 822; + Ext4EsRemoveExtentFormat ext4_es_remove_extent_format = 823; + Ext4EsShrinkFormat ext4_es_shrink_format = 824; + Ext4EsShrinkCountFormat ext4_es_shrink_count_format = 825; + Ext4EsShrinkScanEnterFormat ext4_es_shrink_scan_enter_format = 826; + Ext4EsShrinkScanExitFormat ext4_es_shrink_scan_exit_format = 827; + Ext4EvictInodeFormat ext4_evict_inode_format = 828; + Ext4ExtConvertToInitializedEnterFormat ext4_ext_convert_to_initialized_enter_format = 829; + Ext4ExtConvertToInitializedFastpathFormat ext4_ext_convert_to_initialized_fastpath_format = 830; + Ext4ExtHandleUnwrittenExtentsFormat ext4_ext_handle_unwritten_extents_format = 831; + Ext4ExtInCacheFormat ext4_ext_in_cache_format = 832; + Ext4ExtLoadExtentFormat ext4_ext_load_extent_format = 833; + Ext4ExtMapBlocksEnterFormat ext4_ext_map_blocks_enter_format = 834; + Ext4ExtMapBlocksExitFormat ext4_ext_map_blocks_exit_format = 835; + Ext4ExtPutInCacheFormat ext4_ext_put_in_cache_format = 836; + Ext4ExtRemoveSpaceFormat ext4_ext_remove_space_format = 837; + Ext4ExtRemoveSpaceDoneFormat ext4_ext_remove_space_done_format = 838; + Ext4ExtRmIdxFormat ext4_ext_rm_idx_format = 839; + Ext4ExtRmLeafFormat ext4_ext_rm_leaf_format = 840; + Ext4ExtShowExtentFormat ext4_ext_show_extent_format = 841; + Ext4FallocateEnterFormat ext4_fallocate_enter_format = 842; + Ext4FallocateExitFormat ext4_fallocate_exit_format = 843; + Ext4FindDelallocRangeFormat ext4_find_delalloc_range_format = 844; + Ext4ForgetFormat ext4_forget_format = 845; + Ext4FreeBlocksFormat ext4_free_blocks_format = 846; + Ext4FreeInodeFormat ext4_free_inode_format = 847; + Ext4GetImpliedClusterAllocExitFormat ext4_get_implied_cluster_alloc_exit_format = 848; + Ext4GetReservedClusterAllocFormat ext4_get_reserved_cluster_alloc_format = 849; + Ext4IndMapBlocksEnterFormat ext4_ind_map_blocks_enter_format = 850; + Ext4IndMapBlocksExitFormat ext4_ind_map_blocks_exit_format = 851; + Ext4InsertRangeFormat ext4_insert_range_format = 852; + Ext4InvalidatepageFormat ext4_invalidatepage_format = 853; + Ext4JournalStartFormat ext4_journal_start_format = 854; + Ext4JournalStartReservedFormat ext4_journal_start_reserved_format = 855; + Ext4JournalledInvalidatepageFormat ext4_journalled_invalidatepage_format = 856; + Ext4JournalledWriteEndFormat ext4_journalled_write_end_format = 857; + Ext4LoadInodeFormat ext4_load_inode_format = 858; + Ext4LoadInodeBitmapFormat ext4_load_inode_bitmap_format = 859; + Ext4MarkInodeDirtyFormat ext4_mark_inode_dirty_format = 860; + Ext4MbBitmapLoadFormat ext4_mb_bitmap_load_format = 861; + Ext4MbBuddyBitmapLoadFormat ext4_mb_buddy_bitmap_load_format = 862; + Ext4MbDiscardPreallocationsFormat ext4_mb_discard_preallocations_format = 863; + Ext4MbNewGroupPaFormat ext4_mb_new_group_pa_format = 864; + Ext4MbNewInodePaFormat ext4_mb_new_inode_pa_format = 865; + Ext4MbReleaseGroupPaFormat ext4_mb_release_group_pa_format = 866; + Ext4MbReleaseInodePaFormat ext4_mb_release_inode_pa_format = 867; + Ext4MballocAllocFormat ext4_mballoc_alloc_format = 868; + Ext4MballocDiscardFormat ext4_mballoc_discard_format = 869; + Ext4MballocFreeFormat ext4_mballoc_free_format = 870; + Ext4MballocPreallocFormat ext4_mballoc_prealloc_format = 871; + Ext4OtherInodeUpdateTimeFormat ext4_other_inode_update_time_format = 872; + Ext4PunchHoleFormat ext4_punch_hole_format = 873; + Ext4ReadBlockBitmapLoadFormat ext4_read_block_bitmap_load_format = 874; + Ext4ReadpageFormat ext4_readpage_format = 875; + Ext4ReleasepageFormat ext4_releasepage_format = 876; + Ext4RemoveBlocksFormat ext4_remove_blocks_format = 877; + Ext4RequestBlocksFormat ext4_request_blocks_format = 878; + Ext4RequestInodeFormat ext4_request_inode_format = 879; + Ext4SyncFileEnterFormat ext4_sync_file_enter_format = 880; + Ext4SyncFileExitFormat ext4_sync_file_exit_format = 881; + Ext4SyncFsFormat ext4_sync_fs_format = 882; + Ext4TrimAllFreeFormat ext4_trim_all_free_format = 883; + Ext4TrimExtentFormat ext4_trim_extent_format = 884; + Ext4TruncateEnterFormat ext4_truncate_enter_format = 885; + Ext4TruncateExitFormat ext4_truncate_exit_format = 886; + Ext4UnlinkEnterFormat ext4_unlink_enter_format = 887; + Ext4UnlinkExitFormat ext4_unlink_exit_format = 888; + Ext4WriteBeginFormat ext4_write_begin_format = 889; + Ext4WriteEndFormat ext4_write_end_format = 890; + Ext4WritepageFormat ext4_writepage_format = 891; + Ext4WritepagesFormat ext4_writepages_format = 892; + Ext4WritepagesResultFormat ext4_writepages_result_format = 893; + Ext4ZeroRangeFormat ext4_zero_range_format = 894; + BreakLeaseBlockFormat break_lease_block_format = 900; + BreakLeaseNoblockFormat break_lease_noblock_format = 901; + BreakLeaseUnblockFormat break_lease_unblock_format = 902; + GenericAddLeaseFormat generic_add_lease_format = 903; + GenericDeleteLeaseFormat generic_delete_lease_format = 904; + TimeOutLeasesFormat time_out_leases_format = 905; + MmFilemapAddToPageCacheFormat mm_filemap_add_to_page_cache_format = 1000; + MmFilemapDeleteFromPageCacheFormat mm_filemap_delete_from_page_cache_format = 1001; + BputsFormat bputs_format = 1100; + BranchFormat branch_format = 1101; + ContextSwitchFormat context_switch_format = 1102; + FuncgraphEntryFormat funcgraph_entry_format = 1103; + FuncgraphExitFormat funcgraph_exit_format = 1104; + FunctionFormat function_format = 1105; + KernelStackFormat kernel_stack_format = 1106; + MmiotraceMapFormat mmiotrace_map_format = 1107; + MmiotraceRwFormat mmiotrace_rw_format = 1108; + PrintFormat print_format = 1109; + UserStackFormat user_stack_format = 1110; + WakeupFormat wakeup_format = 1111; + GpioDirectionFormat gpio_direction_format = 1200; + GpioValueFormat gpio_value_format = 1201; + I2cReadFormat i2c_read_format = 1300; + I2cReplyFormat i2c_reply_format = 1301; + I2cResultFormat i2c_result_format = 1302; + I2cWriteFormat i2c_write_format = 1303; + IpiEntryFormat ipi_entry_format = 1400; + IpiExitFormat ipi_exit_format = 1401; + IpiRaiseFormat ipi_raise_format = 1402; + IrqHandlerEntryFormat irq_handler_entry_format = 1500; + IrqHandlerExitFormat irq_handler_exit_format = 1501; + SoftirqEntryFormat softirq_entry_format = 1502; + SoftirqExitFormat softirq_exit_format = 1503; + SoftirqRaiseFormat softirq_raise_format = 1504; + KfreeFormat kfree_format = 1600; + KmallocFormat kmalloc_format = 1601; + KmallocNodeFormat kmalloc_node_format = 1602; + KmemCacheAllocFormat kmem_cache_alloc_format = 1603; + KmemCacheAllocNodeFormat kmem_cache_alloc_node_format = 1604; + KmemCacheFreeFormat kmem_cache_free_format = 1605; + MmPageAllocFormat mm_page_alloc_format = 1606; + MmPageAllocExtfragFormat mm_page_alloc_extfrag_format = 1607; + MmPageAllocZoneLockedFormat mm_page_alloc_zone_locked_format = 1608; + MmPageFreeFormat mm_page_free_format = 1609; + MmPageFreeBatchedFormat mm_page_free_batched_format = 1610; + MmPagePcpuDrainFormat mm_page_pcpu_drain_format = 1611; + NapiGroFragsEntryFormat napi_gro_frags_entry_format = 1700; + NapiGroReceiveEntryFormat napi_gro_receive_entry_format = 1701; + NetDevQueueFormat net_dev_queue_format = 1702; + NetDevStartXmitFormat net_dev_start_xmit_format = 1703; + NetDevXmitFormat net_dev_xmit_format = 1704; + NetifReceiveSkbFormat netif_receive_skb_format = 1705; + NetifReceiveSkbEntryFormat netif_receive_skb_entry_format = 1706; + NetifRxFormat netif_rx_format = 1707; + NetifRxEntryFormat netif_rx_entry_format = 1708; + NetifRxNiEntryFormat netif_rx_ni_entry_format = 1709; + OomScoreAdjUpdateFormat oom_score_adj_update_format = 1800; + MmLruActivateFormat mm_lru_activate_format = 1900; + MmLruInsertionFormat mm_lru_insertion_format = 1901; + ClockDisableFormat clock_disable_format = 2000; + ClockEnableFormat clock_enable_format = 2001; + ClockSetRateFormat clock_set_rate_format = 2002; + CpuFrequencyFormat cpu_frequency_format = 2003; + CpuFrequencyLimitsFormat cpu_frequency_limits_format = 2004; + CpuIdleFormat cpu_idle_format = 2005; + DevPmQosAddRequestFormat dev_pm_qos_add_request_format = 2006; + DevPmQosRemoveRequestFormat dev_pm_qos_remove_request_format = 2007; + DevPmQosUpdateRequestFormat dev_pm_qos_update_request_format = 2008; + DevicePmCallbackEndFormat device_pm_callback_end_format = 2009; + DevicePmCallbackStartFormat device_pm_callback_start_format = 2010; + PmQosAddRequestFormat pm_qos_add_request_format = 2011; + PmQosRemoveRequestFormat pm_qos_remove_request_format = 2012; + PmQosUpdateFlagsFormat pm_qos_update_flags_format = 2013; + PmQosUpdateRequestFormat pm_qos_update_request_format = 2014; + PmQosUpdateRequestTimeoutFormat pm_qos_update_request_timeout_format = 2015; + PmQosUpdateTargetFormat pm_qos_update_target_format = 2016; + PowerDomainTargetFormat power_domain_target_format = 2017; + PstateSampleFormat pstate_sample_format = 2018; + SuspendResumeFormat suspend_resume_format = 2019; + WakeupSourceActivateFormat wakeup_source_activate_format = 2020; + WakeupSourceDeactivateFormat wakeup_source_deactivate_format = 2021; + ConsoleFormat console_format = 2100; + SysEnterFormat sys_enter_format = 2200; + SysExitFormat sys_exit_format = 2201; + RcuUtilizationFormat rcu_utilization_format = 2300; + SchedKthreadStopFormat sched_kthread_stop_format = 2400; + SchedKthreadStopRetFormat sched_kthread_stop_ret_format = 2401; + SchedMigrateTaskFormat sched_migrate_task_format = 2402; + SchedMoveNumaFormat sched_move_numa_format = 2403; + SchedPiSetprioFormat sched_pi_setprio_format = 2404; + SchedProcessExecFormat sched_process_exec_format = 2405; + SchedProcessExitFormat sched_process_exit_format = 2406; + SchedProcessForkFormat sched_process_fork_format = 2407; + SchedProcessFreeFormat sched_process_free_format = 2408; + SchedProcessWaitFormat sched_process_wait_format = 2409; + SchedStatBlockedFormat sched_stat_blocked_format = 2410; + SchedStatIowaitFormat sched_stat_iowait_format = 2411; + SchedStatRuntimeFormat sched_stat_runtime_format = 2412; + SchedStatSleepFormat sched_stat_sleep_format = 2413; + SchedStatWaitFormat sched_stat_wait_format = 2414; + SchedStickNumaFormat sched_stick_numa_format = 2415; + SchedSwapNumaFormat sched_swap_numa_format = 2416; + SchedSwitchFormat sched_switch_format = 2417; + SchedWaitTaskFormat sched_wait_task_format = 2418; + SchedWakeIdleWithoutIpiFormat sched_wake_idle_without_ipi_format = 2419; + SchedWakeupFormat sched_wakeup_format = 2420; + SchedWakeupNewFormat sched_wakeup_new_format = 2421; + SchedWakingFormat sched_waking_format = 2422; + SignalDeliverFormat signal_deliver_format = 2500; + SignalGenerateFormat signal_generate_format = 2501; + RpcBindStatusFormat rpc_bind_status_format = 2600; + RpcCallStatusFormat rpc_call_status_format = 2601; + RpcConnectStatusFormat rpc_connect_status_format = 2602; + RpcSocketCloseFormat rpc_socket_close_format = 2603; + RpcSocketConnectFormat rpc_socket_connect_format = 2604; + RpcSocketErrorFormat rpc_socket_error_format = 2605; + RpcSocketResetConnectionFormat rpc_socket_reset_connection_format = 2606; + RpcSocketShutdownFormat rpc_socket_shutdown_format = 2607; + RpcSocketStateChangeFormat rpc_socket_state_change_format = 2608; + RpcTaskBeginFormat rpc_task_begin_format = 2609; + RpcTaskCompleteFormat rpc_task_complete_format = 2610; + RpcTaskRunActionFormat rpc_task_run_action_format = 2611; + RpcTaskSleepFormat rpc_task_sleep_format = 2612; + RpcTaskWakeupFormat rpc_task_wakeup_format = 2613; + SvcHandleXprtFormat svc_handle_xprt_format = 2614; + SvcProcessFormat svc_process_format = 2615; + SvcRecvFormat svc_recv_format = 2616; + SvcSendFormat svc_send_format = 2617; + SvcWakeUpFormat svc_wake_up_format = 2618; + SvcXprtDequeueFormat svc_xprt_dequeue_format = 2619; + SvcXprtDoEnqueueFormat svc_xprt_do_enqueue_format = 2620; + XprtCompleteRqstFormat xprt_complete_rqst_format = 2621; + XprtLookupRqstFormat xprt_lookup_rqst_format = 2622; + XprtTransmitFormat xprt_transmit_format = 2623; + XsTcpDataReadyFormat xs_tcp_data_ready_format = 2624; + XsTcpDataRecvFormat xs_tcp_data_recv_format = 2625; + TaskNewtaskFormat task_newtask_format = 2700; + TaskRenameFormat task_rename_format = 2701; + HrtimerCancelFormat hrtimer_cancel_format = 2800; + HrtimerExpireEntryFormat hrtimer_expire_entry_format = 2801; + HrtimerExpireExitFormat hrtimer_expire_exit_format = 2802; + HrtimerInitFormat hrtimer_init_format = 2803; + HrtimerStartFormat hrtimer_start_format = 2804; + ItimerExpireFormat itimer_expire_format = 2805; + ItimerStateFormat itimer_state_format = 2806; + TimerCancelFormat timer_cancel_format = 2807; + TimerExpireEntryFormat timer_expire_entry_format = 2808; + TimerExpireExitFormat timer_expire_exit_format = 2809; + TimerInitFormat timer_init_format = 2810; + TimerStartFormat timer_start_format = 2811; + V4l2DqbufFormat v4l2_dqbuf_format = 2900; + V4l2QbufFormat v4l2_qbuf_format = 2901; + Vb2V4l2BufDoneFormat vb2_v4l2_buf_done_format = 2902; + Vb2V4l2BufQueueFormat vb2_v4l2_buf_queue_format = 2903; + Vb2V4l2DqbufFormat vb2_v4l2_dqbuf_format = 2904; + Vb2V4l2QbufFormat vb2_v4l2_qbuf_format = 2905; + MmShrinkSlabEndFormat mm_shrink_slab_end_format = 3000; + MmShrinkSlabStartFormat mm_shrink_slab_start_format = 3001; + MmVmscanDirectReclaimBeginFormat mm_vmscan_direct_reclaim_begin_format = 3002; + MmVmscanDirectReclaimEndFormat mm_vmscan_direct_reclaim_end_format = 3003; + MmVmscanKswapdSleepFormat mm_vmscan_kswapd_sleep_format = 3004; + MmVmscanKswapdWakeFormat mm_vmscan_kswapd_wake_format = 3005; + MmVmscanLruIsolateFormat mm_vmscan_lru_isolate_format = 3006; + MmVmscanLruShrinkInactiveFormat mm_vmscan_lru_shrink_inactive_format = 3007; + MmVmscanWakeupKswapdFormat mm_vmscan_wakeup_kswapd_format = 3008; + MmVmscanWritepageFormat mm_vmscan_writepage_format = 3009; + WorkqueueActivateWorkFormat workqueue_activate_work_format = 3100; + WorkqueueExecuteEndFormat workqueue_execute_end_format = 3101; + WorkqueueExecuteStartFormat workqueue_execute_start_format = 3102; + WorkqueueQueueWorkFormat workqueue_queue_work_format = 3103; + BalanceDirtyPagesFormat balance_dirty_pages_format = 3200; + BdiDirtyRatelimitFormat bdi_dirty_ratelimit_format = 3201; + GlobalDirtyStateFormat global_dirty_state_format = 3202; + WbcWritepageFormat wbc_writepage_format = 3203; + WritebackBdiRegisterFormat writeback_bdi_register_format = 3204; + WritebackCongestionWaitFormat writeback_congestion_wait_format = 3205; + WritebackDirtyInodeFormat writeback_dirty_inode_format = 3206; + WritebackDirtyInodeEnqueueFormat writeback_dirty_inode_enqueue_format = 3207; + WritebackDirtyInodeStartFormat writeback_dirty_inode_start_format = 3208; + WritebackDirtyPageFormat writeback_dirty_page_format = 3209; + WritebackExecFormat writeback_exec_format = 3210; + WritebackLazytimeFormat writeback_lazytime_format = 3211; + WritebackLazytimeIputFormat writeback_lazytime_iput_format = 3212; + WritebackMarkInodeDirtyFormat writeback_mark_inode_dirty_format = 3213; + WritebackPagesWrittenFormat writeback_pages_written_format = 3214; + WritebackQueueFormat writeback_queue_format = 3215; + WritebackQueueIoFormat writeback_queue_io_format = 3216; + WritebackSbInodesRequeueFormat writeback_sb_inodes_requeue_format = 3217; + WritebackSingleInodeFormat writeback_single_inode_format = 3218; + WritebackSingleInodeStartFormat writeback_single_inode_start_format = 3219; + WritebackStartFormat writeback_start_format = 3220; + WritebackWaitFormat writeback_wait_format = 3221; + WritebackWaitIffCongestedFormat writeback_wait_iff_congested_format = 3222; + WritebackWakeBackgroundFormat writeback_wake_background_format = 3223; + WritebackWriteInodeFormat writeback_write_inode_format = 3224; + WritebackWriteInodeStartFormat writeback_write_inode_start_format = 3225; + WritebackWrittenFormat writeback_written_format = 3226; + SchedBlockedReasonFormat sched_blocked_reason_format = 4002; + } +} diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/gpio.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/gpio.proto new file mode 100755 index 0000000000000000000000000000000000000000..1410af52c24e250e5aa6434c7993537c2f918a25 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/gpio.proto @@ -0,0 +1,34 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: gpio +// /sys/kernel/debug/tracing/events/gpio/gpio_direction/format +message GpioDirectionFormat { + uint32 gpio = 1; + int32 in = 2; + int32 err = 3; +} + +// /sys/kernel/debug/tracing/events/gpio/gpio_value/format +message GpioValueFormat { + uint32 gpio = 1; + int32 get = 2; + int32 value = 3; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/i2c.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/i2c.proto new file mode 100755 index 0000000000000000000000000000000000000000..4f1de54988f7d1c3b06502630e09b60c4258e0b9 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/i2c.proto @@ -0,0 +1,56 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: i2c +// /sys/kernel/debug/tracing/events/i2c/i2c_read/format +message I2cReadFormat { + int32 adapter_nr = 1; + uint32 msg_nr = 2; + uint32 addr = 3; + uint32 flags = 4; + uint32 len = 5; +} + +// /sys/kernel/debug/tracing/events/i2c/i2c_reply/format +message I2cReplyFormat { + int32 adapter_nr = 1; + uint32 msg_nr = 2; + uint32 addr = 3; + uint32 flags = 4; + uint32 len = 5; + uint32 buf = 6; +} + +// /sys/kernel/debug/tracing/events/i2c/i2c_result/format +message I2cResultFormat { + int32 adapter_nr = 1; + uint32 nr_msgs = 2; + int32 ret = 3; +} + +// /sys/kernel/debug/tracing/events/i2c/i2c_write/format +message I2cWriteFormat { + int32 adapter_nr = 1; + uint32 msg_nr = 2; + uint32 addr = 3; + uint32 flags = 4; + uint32 len = 5; + uint32 buf = 6; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/ipi.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/ipi.proto new file mode 100755 index 0000000000000000000000000000000000000000..0eda02f6e3b3485f07125e6bfb5baa1ceb34b004 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/ipi.proto @@ -0,0 +1,36 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: ipi +// /sys/kernel/debug/tracing/events/ipi/ipi_entry/format +message IpiEntryFormat { + string reason = 1; +} + +// /sys/kernel/debug/tracing/events/ipi/ipi_exit/format +message IpiExitFormat { + string reason = 1; +} + +// /sys/kernel/debug/tracing/events/ipi/ipi_raise/format +message IpiRaiseFormat { + uint64 target_cpus = 1; + string reason = 2; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/irq.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/irq.proto new file mode 100755 index 0000000000000000000000000000000000000000..1e3ce1afebc69cd764ddb991914090168d3b79e1 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/irq.proto @@ -0,0 +1,47 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: irq +// /sys/kernel/debug/tracing/events/irq/irq_handler_entry/format +message IrqHandlerEntryFormat { + int32 irq = 1; + string name = 2; +} + +// /sys/kernel/debug/tracing/events/irq/irq_handler_exit/format +message IrqHandlerExitFormat { + int32 irq = 1; + int32 ret = 2; +} + +// /sys/kernel/debug/tracing/events/irq/softirq_entry/format +message SoftirqEntryFormat { + uint32 vec = 1; +} + +// /sys/kernel/debug/tracing/events/irq/softirq_exit/format +message SoftirqExitFormat { + uint32 vec = 1; +} + +// /sys/kernel/debug/tracing/events/irq/softirq_raise/format +message SoftirqRaiseFormat { + uint32 vec = 1; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/kmem.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/kmem.proto new file mode 100755 index 0000000000000000000000000000000000000000..51b7d49818bf0c51b463d641ccf495dbbb6907a4 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/kmem.proto @@ -0,0 +1,113 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: kmem +// /sys/kernel/debug/tracing/events/kmem/kfree/format +message KfreeFormat { + uint64 call_site = 1; + uint64 ptr = 2; +} + +// /sys/kernel/debug/tracing/events/kmem/kmalloc/format +message KmallocFormat { + uint64 call_site = 1; + uint64 ptr = 2; + uint64 bytes_req = 3; + uint64 bytes_alloc = 4; + uint32 gfp_flags = 5; +} + +// /sys/kernel/debug/tracing/events/kmem/kmalloc_node/format +message KmallocNodeFormat { + uint64 call_site = 1; + uint64 ptr = 2; + uint64 bytes_req = 3; + uint64 bytes_alloc = 4; + uint32 gfp_flags = 5; + int32 node = 6; +} + +// /sys/kernel/debug/tracing/events/kmem/kmem_cache_alloc/format +message KmemCacheAllocFormat { + uint64 call_site = 1; + uint64 ptr = 2; + uint64 bytes_req = 3; + uint64 bytes_alloc = 4; + uint32 gfp_flags = 5; +} + +// /sys/kernel/debug/tracing/events/kmem/kmem_cache_alloc_node/format +message KmemCacheAllocNodeFormat { + uint64 call_site = 1; + uint64 ptr = 2; + uint64 bytes_req = 3; + uint64 bytes_alloc = 4; + uint32 gfp_flags = 5; + int32 node = 6; +} + +// /sys/kernel/debug/tracing/events/kmem/kmem_cache_free/format +message KmemCacheFreeFormat { + uint64 call_site = 1; + uint64 ptr = 2; +} + +// /sys/kernel/debug/tracing/events/kmem/mm_page_alloc/format +message MmPageAllocFormat { + uint64 pfn = 1; + uint32 order = 2; + uint32 gfp_flags = 3; + int32 migratetype = 4; +} + +// /sys/kernel/debug/tracing/events/kmem/mm_page_alloc_extfrag/format +message MmPageAllocExtfragFormat { + uint64 pfn = 1; + int32 alloc_order = 2; + int32 fallback_order = 3; + int32 alloc_migratetype = 4; + int32 fallback_migratetype = 5; + int32 change_ownership = 6; +} + +// /sys/kernel/debug/tracing/events/kmem/mm_page_alloc_zone_locked/format +message MmPageAllocZoneLockedFormat { + uint64 pfn = 1; + uint32 order = 2; + int32 migratetype = 3; +} + +// /sys/kernel/debug/tracing/events/kmem/mm_page_free/format +message MmPageFreeFormat { + uint64 pfn = 1; + uint32 order = 2; +} + +// /sys/kernel/debug/tracing/events/kmem/mm_page_free_batched/format +message MmPageFreeBatchedFormat { + uint64 pfn = 1; +} + +// /sys/kernel/debug/tracing/events/kmem/mm_page_pcpu_drain/format +message MmPagePcpuDrainFormat { + uint64 pfn = 1; + uint32 order = 2; + int32 migratetype = 3; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/net.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/net.proto new file mode 100755 index 0000000000000000000000000000000000000000..c4b3c31fcf7a647765843c4d694dde9ace41f7fb --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/net.proto @@ -0,0 +1,185 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: net +// /sys/kernel/debug/tracing/events/net/napi_gro_frags_entry/format +message NapiGroFragsEntryFormat { + string name = 1; + uint32 napi_id = 2; + uint32 queue_mapping = 3; + uint64 skbaddr = 4; + uint32 vlan_tagged = 5; + uint32 vlan_proto = 6; + uint32 vlan_tci = 7; + uint32 protocol = 8; + uint32 ip_summed = 9; + uint32 hash = 10; + uint32 l4_hash = 11; + uint32 len = 12; + uint32 data_len = 13; + uint32 truesize = 14; + uint32 mac_header_valid = 15; + int32 mac_header = 16; + uint32 nr_frags = 17; + uint32 gso_size = 18; + uint32 gso_type = 19; +} + +// /sys/kernel/debug/tracing/events/net/napi_gro_receive_entry/format +message NapiGroReceiveEntryFormat { + string name = 1; + uint32 napi_id = 2; + uint32 queue_mapping = 3; + uint64 skbaddr = 4; + uint32 vlan_tagged = 5; + uint32 vlan_proto = 6; + uint32 vlan_tci = 7; + uint32 protocol = 8; + uint32 ip_summed = 9; + uint32 hash = 10; + uint32 l4_hash = 11; + uint32 len = 12; + uint32 data_len = 13; + uint32 truesize = 14; + uint32 mac_header_valid = 15; + int32 mac_header = 16; + uint32 nr_frags = 17; + uint32 gso_size = 18; + uint32 gso_type = 19; +} + +// /sys/kernel/debug/tracing/events/net/net_dev_queue/format +message NetDevQueueFormat { + uint64 skbaddr = 1; + uint32 len = 2; + string name = 3; +} + +// /sys/kernel/debug/tracing/events/net/net_dev_start_xmit/format +message NetDevStartXmitFormat { + string name = 1; + uint32 queue_mapping = 2; + uint64 skbaddr = 3; + uint32 vlan_tagged = 4; + uint32 vlan_proto = 5; + uint32 vlan_tci = 6; + uint32 protocol = 7; + uint32 ip_summed = 8; + uint32 len = 9; + uint32 data_len = 10; + int32 network_offset = 11; + uint32 transport_offset_valid = 12; + int32 transport_offset = 13; + uint32 tx_flags = 14; + uint32 gso_size = 15; + uint32 gso_segs = 16; + uint32 gso_type = 17; +} + +// /sys/kernel/debug/tracing/events/net/net_dev_xmit/format +message NetDevXmitFormat { + uint64 skbaddr = 1; + uint32 len = 2; + int32 rc = 3; + string name = 4; +} + +// /sys/kernel/debug/tracing/events/net/netif_receive_skb/format +message NetifReceiveSkbFormat { + uint64 skbaddr = 1; + uint32 len = 2; + string name = 3; +} + +// /sys/kernel/debug/tracing/events/net/netif_receive_skb_entry/format +message NetifReceiveSkbEntryFormat { + string name = 1; + uint32 napi_id = 2; + uint32 queue_mapping = 3; + uint64 skbaddr = 4; + uint32 vlan_tagged = 5; + uint32 vlan_proto = 6; + uint32 vlan_tci = 7; + uint32 protocol = 8; + uint32 ip_summed = 9; + uint32 hash = 10; + uint32 l4_hash = 11; + uint32 len = 12; + uint32 data_len = 13; + uint32 truesize = 14; + uint32 mac_header_valid = 15; + int32 mac_header = 16; + uint32 nr_frags = 17; + uint32 gso_size = 18; + uint32 gso_type = 19; +} + +// /sys/kernel/debug/tracing/events/net/netif_rx/format +message NetifRxFormat { + uint64 skbaddr = 1; + uint32 len = 2; + string name = 3; +} + +// /sys/kernel/debug/tracing/events/net/netif_rx_entry/format +message NetifRxEntryFormat { + string name = 1; + uint32 napi_id = 2; + uint32 queue_mapping = 3; + uint64 skbaddr = 4; + uint32 vlan_tagged = 5; + uint32 vlan_proto = 6; + uint32 vlan_tci = 7; + uint32 protocol = 8; + uint32 ip_summed = 9; + uint32 hash = 10; + uint32 l4_hash = 11; + uint32 len = 12; + uint32 data_len = 13; + uint32 truesize = 14; + uint32 mac_header_valid = 15; + int32 mac_header = 16; + uint32 nr_frags = 17; + uint32 gso_size = 18; + uint32 gso_type = 19; +} + +// /sys/kernel/debug/tracing/events/net/netif_rx_ni_entry/format +message NetifRxNiEntryFormat { + string name = 1; + uint32 napi_id = 2; + uint32 queue_mapping = 3; + uint64 skbaddr = 4; + uint32 vlan_tagged = 5; + uint32 vlan_proto = 6; + uint32 vlan_tci = 7; + uint32 protocol = 8; + uint32 ip_summed = 9; + uint32 hash = 10; + uint32 l4_hash = 11; + uint32 len = 12; + uint32 data_len = 13; + uint32 truesize = 14; + uint32 mac_header_valid = 15; + int32 mac_header = 16; + uint32 nr_frags = 17; + uint32 gso_size = 18; + uint32 gso_type = 19; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/oom.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/oom.proto new file mode 100755 index 0000000000000000000000000000000000000000..d7b6b9c60bb8b17f279c158396f78af802d5bdcc --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/oom.proto @@ -0,0 +1,27 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: oom +// /sys/kernel/debug/tracing/events/oom/oom_score_adj_update/format +message OomScoreAdjUpdateFormat { + int32 pid = 1; + string comm = 2; + int32 oom_score_adj = 3; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/pagemap.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/pagemap.proto new file mode 100755 index 0000000000000000000000000000000000000000..c931e12f275aead37148fc5395a94829b4d2153b --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/pagemap.proto @@ -0,0 +1,34 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: pagemap +// /sys/kernel/debug/tracing/events/pagemap/mm_lru_activate/format +message MmLruActivateFormat { + uint64 page = 1; + uint64 pfn = 2; +} + +// /sys/kernel/debug/tracing/events/pagemap/mm_lru_insertion/format +message MmLruInsertionFormat { + uint64 page = 1; + uint64 pfn = 2; + int32 lru = 3; + uint64 flags = 4; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/power.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/power.proto new file mode 100755 index 0000000000000000000000000000000000000000..3a223d1b3d640688eef81982287ec3fb99ba43dd --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/power.proto @@ -0,0 +1,175 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: power +// /sys/kernel/debug/tracing/events/power/clock_disable/format +message ClockDisableFormat { + string name = 1; + uint64 state = 2; + uint64 cpu_id = 3; +} + +// /sys/kernel/debug/tracing/events/power/clock_enable/format +message ClockEnableFormat { + string name = 1; + uint64 state = 2; + uint64 cpu_id = 3; +} + +// /sys/kernel/debug/tracing/events/power/clock_set_rate/format +message ClockSetRateFormat { + string name = 1; + uint64 state = 2; + uint64 cpu_id = 3; +} + +// /sys/kernel/debug/tracing/events/power/cpu_frequency/format +message CpuFrequencyFormat { + uint32 state = 1; + uint32 cpu_id = 2; +} + +// /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/format +message CpuFrequencyLimitsFormat { + uint32 min_freq = 1; + uint32 max_freq = 2; + uint32 cpu_id = 3; +} + +// /sys/kernel/debug/tracing/events/power/cpu_idle/format +message CpuIdleFormat { + uint32 state = 1; + uint32 cpu_id = 2; +} + +// /sys/kernel/debug/tracing/events/power/dev_pm_qos_add_request/format +message DevPmQosAddRequestFormat { + string name = 1; + uint32 type = 2; + int32 new_value = 3; +} + +// /sys/kernel/debug/tracing/events/power/dev_pm_qos_remove_request/format +message DevPmQosRemoveRequestFormat { + string name = 1; + uint32 type = 2; + int32 new_value = 3; +} + +// /sys/kernel/debug/tracing/events/power/dev_pm_qos_update_request/format +message DevPmQosUpdateRequestFormat { + string name = 1; + uint32 type = 2; + int32 new_value = 3; +} + +// /sys/kernel/debug/tracing/events/power/device_pm_callback_end/format +message DevicePmCallbackEndFormat { + string device = 1; + string driver = 2; + int32 error = 3; +} + +// /sys/kernel/debug/tracing/events/power/device_pm_callback_start/format +message DevicePmCallbackStartFormat { + string device = 1; + string driver = 2; + string parent = 3; + string pm_ops = 4; + int32 event = 5; +} + +// /sys/kernel/debug/tracing/events/power/pm_qos_add_request/format +message PmQosAddRequestFormat { + int32 pm_qos_class = 1; + int32 value = 2; +} + +// /sys/kernel/debug/tracing/events/power/pm_qos_remove_request/format +message PmQosRemoveRequestFormat { + int32 pm_qos_class = 1; + int32 value = 2; +} + +// /sys/kernel/debug/tracing/events/power/pm_qos_update_flags/format +message PmQosUpdateFlagsFormat { + uint32 action = 1; + int32 prev_value = 2; + int32 curr_value = 3; +} + +// /sys/kernel/debug/tracing/events/power/pm_qos_update_request/format +message PmQosUpdateRequestFormat { + int32 pm_qos_class = 1; + int32 value = 2; +} + +// /sys/kernel/debug/tracing/events/power/pm_qos_update_request_timeout/format +message PmQosUpdateRequestTimeoutFormat { + int32 pm_qos_class = 1; + int32 value = 2; + uint64 timeout_us = 3; +} + +// /sys/kernel/debug/tracing/events/power/pm_qos_update_target/format +message PmQosUpdateTargetFormat { + uint32 action = 1; + int32 prev_value = 2; + int32 curr_value = 3; +} + +// /sys/kernel/debug/tracing/events/power/power_domain_target/format +message PowerDomainTargetFormat { + string name = 1; + uint64 state = 2; + uint64 cpu_id = 3; +} + +// /sys/kernel/debug/tracing/events/power/pstate_sample/format +message PstateSampleFormat { + uint32 core_busy = 1; + uint32 scaled_busy = 2; + uint32 from = 3; + uint32 to = 4; + uint64 mperf = 5; + uint64 aperf = 6; + uint64 tsc = 7; + uint32 freq = 8; + uint32 io_boost = 9; +} + +// /sys/kernel/debug/tracing/events/power/suspend_resume/format +message SuspendResumeFormat { + string action = 1; + int32 val = 2; + uint32 start = 3; +} + +// /sys/kernel/debug/tracing/events/power/wakeup_source_activate/format +message WakeupSourceActivateFormat { + string name = 1; + uint64 state = 2; +} + +// /sys/kernel/debug/tracing/events/power/wakeup_source_deactivate/format +message WakeupSourceDeactivateFormat { + string name = 1; + uint64 state = 2; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/printk.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/printk.proto new file mode 100755 index 0000000000000000000000000000000000000000..39be37e143ef980b271bb70391613cdd71966345 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/printk.proto @@ -0,0 +1,25 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: printk +// /sys/kernel/debug/tracing/events/printk/console/format +message ConsoleFormat { + string msg = 1; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/raw_syscalls.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/raw_syscalls.proto new file mode 100755 index 0000000000000000000000000000000000000000..590b964924c3d87e36e3e542eaf1fb891371f209 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/raw_syscalls.proto @@ -0,0 +1,32 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: raw_syscalls +// /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/format +message SysEnterFormat { + uint64 id = 1; + string args = 2; +} + +// /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/format +message SysExitFormat { + uint64 id = 1; + uint64 ret = 2; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/rcu.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/rcu.proto new file mode 100755 index 0000000000000000000000000000000000000000..5448d1e605bf867d5745d8aff4b391622b909490 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/rcu.proto @@ -0,0 +1,25 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: rcu +// /sys/kernel/debug/tracing/events/rcu/rcu_utilization/format +message RcuUtilizationFormat { + string s = 1; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/sched.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/sched.proto new file mode 100755 index 0000000000000000000000000000000000000000..13dcccb7aac708b77526d474e791255adeb1cb6f --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/sched.proto @@ -0,0 +1,212 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; +// category: sched +// /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/format +message SchedBlockedReasonFormat { + int32 pid = 1; + uint64 caller = 2; + uint32 io_wait = 3; +} +// category: sched +// /sys/kernel/debug/tracing/events/sched/sched_kthread_stop/format +message SchedKthreadStopFormat { + string comm = 1; + int32 pid = 2; +} + +// /sys/kernel/debug/tracing/events/sched/sched_kthread_stop_ret/format +message SchedKthreadStopRetFormat { + int32 ret = 1; +} + +// /sys/kernel/debug/tracing/events/sched/sched_migrate_task/format +message SchedMigrateTaskFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; + int32 orig_cpu = 4; + int32 dest_cpu = 5; +} + +// /sys/kernel/debug/tracing/events/sched/sched_move_numa/format +message SchedMoveNumaFormat { + int32 pid = 1; + int32 tgid = 2; + int32 ngid = 3; + int32 src_cpu = 4; + int32 src_nid = 5; + int32 dst_cpu = 6; + int32 dst_nid = 7; +} + +// /sys/kernel/debug/tracing/events/sched/sched_pi_setprio/format +message SchedPiSetprioFormat { + string comm = 1; + int32 pid = 2; + int32 oldprio = 3; + int32 newprio = 4; +} + +// /sys/kernel/debug/tracing/events/sched/sched_process_exec/format +message SchedProcessExecFormat { + string filename = 1; + int32 pid = 2; + int32 old_pid = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_process_exit/format +message SchedProcessExitFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_process_fork/format +message SchedProcessForkFormat { + string parent_comm = 1; + int32 parent_pid = 2; + string child_comm = 3; + int32 child_pid = 4; +} + +// /sys/kernel/debug/tracing/events/sched/sched_process_free/format +message SchedProcessFreeFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_process_wait/format +message SchedProcessWaitFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_stat_blocked/format +message SchedStatBlockedFormat { + string comm = 1; + int32 pid = 2; + uint64 delay = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_stat_iowait/format +message SchedStatIowaitFormat { + string comm = 1; + int32 pid = 2; + uint64 delay = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_stat_runtime/format +message SchedStatRuntimeFormat { + string comm = 1; + int32 pid = 2; + uint64 runtime = 3; + uint64 vruntime = 4; +} + +// /sys/kernel/debug/tracing/events/sched/sched_stat_sleep/format +message SchedStatSleepFormat { + string comm = 1; + int32 pid = 2; + uint64 delay = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_stat_wait/format +message SchedStatWaitFormat { + string comm = 1; + int32 pid = 2; + uint64 delay = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_stick_numa/format +message SchedStickNumaFormat { + int32 pid = 1; + int32 tgid = 2; + int32 ngid = 3; + int32 src_cpu = 4; + int32 src_nid = 5; + int32 dst_cpu = 6; + int32 dst_nid = 7; +} + +// /sys/kernel/debug/tracing/events/sched/sched_swap_numa/format +message SchedSwapNumaFormat { + int32 src_pid = 1; + int32 src_tgid = 2; + int32 src_ngid = 3; + int32 src_cpu = 4; + int32 src_nid = 5; + int32 dst_pid = 6; + int32 dst_tgid = 7; + int32 dst_ngid = 8; + int32 dst_cpu = 9; + int32 dst_nid = 10; +} + +// /sys/kernel/debug/tracing/events/sched/sched_switch/format +message SchedSwitchFormat { + string prev_comm = 1; + int32 prev_pid = 2; + int32 prev_prio = 3; + uint64 prev_state = 4; + string next_comm = 5; + int32 next_pid = 6; + int32 next_prio = 7; +} + +// /sys/kernel/debug/tracing/events/sched/sched_wait_task/format +message SchedWaitTaskFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; +} + +// /sys/kernel/debug/tracing/events/sched/sched_wake_idle_without_ipi/format +message SchedWakeIdleWithoutIpiFormat { + int32 cpu = 1; +} + +// /sys/kernel/debug/tracing/events/sched/sched_wakeup/format +message SchedWakeupFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; + int32 success = 4; + int32 target_cpu = 5; +} + +// /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/format +message SchedWakeupNewFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; + int32 success = 4; + int32 target_cpu = 5; +} + +// /sys/kernel/debug/tracing/events/sched/sched_waking/format +message SchedWakingFormat { + string comm = 1; + int32 pid = 2; + int32 prio = 3; + int32 success = 4; + int32 target_cpu = 5; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/signal.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/signal.proto new file mode 100755 index 0000000000000000000000000000000000000000..01246e67df9f2004cd132d2b688a5de74174bae5 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/signal.proto @@ -0,0 +1,40 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: signal +// /sys/kernel/debug/tracing/events/signal/signal_deliver/format +message SignalDeliverFormat { + int32 sig = 1; + int32 error_code = 2; + int32 code = 3; + uint64 sig_handler = 4; + uint64 sig_flags = 5; +} + +// /sys/kernel/debug/tracing/events/signal/signal_generate/format +message SignalGenerateFormat { + int32 sig = 1; + int32 error_code = 2; + int32 code = 3; + string comm = 4; + int32 pid = 5; + int32 group = 6; + int32 result = 7; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/sunrpc.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/sunrpc.proto new file mode 100755 index 0000000000000000000000000000000000000000..35c4f67cb56077b32598918dd8dbede5dd329c4c --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/sunrpc.proto @@ -0,0 +1,247 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: sunrpc +// /sys/kernel/debug/tracing/events/sunrpc/rpc_bind_status/format +message RpcBindStatusFormat { + uint32 task_id = 1; + uint32 client_id = 2; + int32 status = 3; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_call_status/format +message RpcCallStatusFormat { + uint32 task_id = 1; + uint32 client_id = 2; + int32 status = 3; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_connect_status/format +message RpcConnectStatusFormat { + uint32 task_id = 1; + uint32 client_id = 2; + int32 status = 3; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_socket_close/format +message RpcSocketCloseFormat { + uint32 socket_state = 1; + uint32 sock_state = 2; + uint64 ino = 3; + string dstaddr = 4; + string dstport = 5; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_socket_connect/format +message RpcSocketConnectFormat { + int32 error = 1; + uint32 socket_state = 2; + uint32 sock_state = 3; + uint64 ino = 4; + string dstaddr = 5; + string dstport = 6; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_socket_error/format +message RpcSocketErrorFormat { + int32 error = 1; + uint32 socket_state = 2; + uint32 sock_state = 3; + uint64 ino = 4; + string dstaddr = 5; + string dstport = 6; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_socket_reset_connection/format +message RpcSocketResetConnectionFormat { + int32 error = 1; + uint32 socket_state = 2; + uint32 sock_state = 3; + uint64 ino = 4; + string dstaddr = 5; + string dstport = 6; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_socket_shutdown/format +message RpcSocketShutdownFormat { + uint32 socket_state = 1; + uint32 sock_state = 2; + uint64 ino = 3; + string dstaddr = 4; + string dstport = 5; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_socket_state_change/format +message RpcSocketStateChangeFormat { + uint32 socket_state = 1; + uint32 sock_state = 2; + uint64 ino = 3; + string dstaddr = 4; + string dstport = 5; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_task_begin/format +message RpcTaskBeginFormat { + uint32 task_id = 1; + uint32 client_id = 2; + uint64 action = 3; + uint64 runstate = 4; + int32 status = 5; + uint32 flags = 6; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_task_complete/format +message RpcTaskCompleteFormat { + uint32 task_id = 1; + uint32 client_id = 2; + uint64 action = 3; + uint64 runstate = 4; + int32 status = 5; + uint32 flags = 6; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_task_run_action/format +message RpcTaskRunActionFormat { + uint32 task_id = 1; + uint32 client_id = 2; + uint64 action = 3; + uint64 runstate = 4; + int32 status = 5; + uint32 flags = 6; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_task_sleep/format +message RpcTaskSleepFormat { + uint32 task_id = 1; + uint32 client_id = 2; + uint64 timeout = 3; + uint64 runstate = 4; + int32 status = 5; + uint32 flags = 6; + string q_name = 7; +} + +// /sys/kernel/debug/tracing/events/sunrpc/rpc_task_wakeup/format +message RpcTaskWakeupFormat { + uint32 task_id = 1; + uint32 client_id = 2; + uint64 timeout = 3; + uint64 runstate = 4; + int32 status = 5; + uint32 flags = 6; + string q_name = 7; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_handle_xprt/format +message SvcHandleXprtFormat { + uint64 xprt = 1; + int32 len = 2; + uint64 flags = 3; + string addr = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_process/format +message SvcProcessFormat { + uint32 xid = 1; + uint32 vers = 2; + uint32 proc = 3; + string service = 4; + string addr = 5; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_recv/format +message SvcRecvFormat { + uint32 xid = 1; + int32 len = 2; + uint64 flags = 3; + string addr = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_send/format +message SvcSendFormat { + uint32 xid = 1; + int32 status = 2; + uint64 flags = 3; + string addr = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_wake_up/format +message SvcWakeUpFormat { + int32 pid = 1; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_xprt_dequeue/format +message SvcXprtDequeueFormat { + uint64 xprt = 1; + uint64 flags = 2; + uint64 wakeup = 3; + string addr = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/svc_xprt_do_enqueue/format +message SvcXprtDoEnqueueFormat { + uint64 xprt = 1; + int32 pid = 2; + uint64 flags = 3; + string addr = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/xprt_complete_rqst/format +message XprtCompleteRqstFormat { + uint32 xid = 1; + int32 status = 2; + string addr = 3; + string port = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/xprt_lookup_rqst/format +message XprtLookupRqstFormat { + uint32 xid = 1; + int32 status = 2; + string addr = 3; + string port = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/xprt_transmit/format +message XprtTransmitFormat { + uint32 xid = 1; + int32 status = 2; + string addr = 3; + string port = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/xs_tcp_data_ready/format +message XsTcpDataReadyFormat { + int32 err = 1; + uint32 total = 2; + string addr = 3; + string port = 4; +} + +// /sys/kernel/debug/tracing/events/sunrpc/xs_tcp_data_recv/format +message XsTcpDataRecvFormat { + string addr = 1; + string port = 2; + uint32 xid = 3; + uint64 flags = 4; + uint64 copied = 5; + uint32 reclen = 6; + uint64 offset = 7; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/task.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/task.proto new file mode 100755 index 0000000000000000000000000000000000000000..82177f60b5bd3e1d62077d63627490c360280624 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/task.proto @@ -0,0 +1,36 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: task +// /sys/kernel/debug/tracing/events/task/task_newtask/format +message TaskNewtaskFormat { + int32 pid = 1; + string comm = 2; + uint64 clone_flags = 3; + int32 oom_score_adj = 4; +} + +// /sys/kernel/debug/tracing/events/task/task_rename/format +message TaskRenameFormat { + int32 pid = 1; + string oldcomm = 2; + string newcomm = 3; + int32 oom_score_adj = 4; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/timer.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/timer.proto new file mode 100755 index 0000000000000000000000000000000000000000..d85b207f4e7532ea457dbc8b054fd594115c513c --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/timer.proto @@ -0,0 +1,101 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: timer +// /sys/kernel/debug/tracing/events/timer/hrtimer_cancel/format +message HrtimerCancelFormat { + uint64 hrtimer = 1; +} + +// /sys/kernel/debug/tracing/events/timer/hrtimer_expire_entry/format +message HrtimerExpireEntryFormat { + uint64 hrtimer = 1; + int64 now = 2; + uint64 function = 3; +} + +// /sys/kernel/debug/tracing/events/timer/hrtimer_expire_exit/format +message HrtimerExpireExitFormat { + uint64 hrtimer = 1; +} + +// /sys/kernel/debug/tracing/events/timer/hrtimer_init/format +message HrtimerInitFormat { + uint64 hrtimer = 1; + int32 clockid = 2; + uint32 mode = 3; +} + +// /sys/kernel/debug/tracing/events/timer/hrtimer_start/format +message HrtimerStartFormat { + uint64 hrtimer = 1; + uint64 function = 2; + int64 expires = 3; + int64 softexpires = 4; + uint32 mode = 5; +} + +// /sys/kernel/debug/tracing/events/timer/itimer_expire/format +message ItimerExpireFormat { + int32 which = 1; + int32 pid = 2; + uint64 now = 3; +} + +// /sys/kernel/debug/tracing/events/timer/itimer_state/format +message ItimerStateFormat { + int32 which = 1; + uint64 expires = 2; + uint64 value_sec = 3; + uint64 value_usec = 4; + uint64 interval_sec = 5; + uint64 interval_usec = 6; +} + +// /sys/kernel/debug/tracing/events/timer/timer_cancel/format +message TimerCancelFormat { + uint64 timer = 1; +} + +// /sys/kernel/debug/tracing/events/timer/timer_expire_entry/format +message TimerExpireEntryFormat { + uint64 timer = 1; + uint64 now = 2; + uint64 function = 3; +} + +// /sys/kernel/debug/tracing/events/timer/timer_expire_exit/format +message TimerExpireExitFormat { + uint64 timer = 1; +} + +// /sys/kernel/debug/tracing/events/timer/timer_init/format +message TimerInitFormat { + uint64 timer = 1; +} + +// /sys/kernel/debug/tracing/events/timer/timer_start/format +message TimerStartFormat { + uint64 timer = 1; + uint64 function = 2; + uint64 expires = 3; + uint64 now = 4; + uint32 flags = 5; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/trace_plugin_config.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/trace_plugin_config.proto new file mode 100644 index 0000000000000000000000000000000000000000..e56265861500c204d39f398e9e674eaaafcb2f25 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/trace_plugin_config.proto @@ -0,0 +1,28 @@ +// 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. + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; + +message TracePluginConfig { + repeated string ftrace_events = 1; + repeated string bytrace_categories = 2; + repeated string bytrace_apps = 3; + uint32 buffer_size_kb = 4; // for ftrace procfs + uint32 flush_interval_ms = 5; + uint32 flush_threshold_kb = 6; + bool parse_ksyms = 7; // enable /proc/kallsyms parser + string clock = 8; + uint32 trace_period_ms = 10; + string raw_data_prefix = 13; +} diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/trace_plugin_result.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/trace_plugin_result.proto new file mode 100644 index 0000000000000000000000000000000000000000..96476feea7211c28e737ede7ec903f924075ac86 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/trace_plugin_result.proto @@ -0,0 +1,80 @@ +// 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. + +syntax = "proto3"; + +import "ftrace_event.proto"; + +option optimize_for = LITE_RUNTIME; + +message TracePluginResult { + repeated FtraceCpuStatsMsg ftrace_cpu_stats = 1; + repeated FtraceCpuDetailMsg ftrace_cpu_detail = 2; + repeated SymbolsDetailMsg symbols_detail = 5; + repeated ClockDetailMsg clocks_detail = 6; +} + +message ClockDetailMsg { + // man clock_gettime + enum ClockId { + UNKNOW = 0; + BOOTTIME = 1; + REALTIME = 2; + REALTIME_COARSE = 3; + MONOTONIC = 4; + MONOTONIC_COARSE = 5; + MONOTONIC_RAW = 6; + } + ClockId id = 1; + message TimeSpec { + uint32 tv_sec = 1; + uint32 tv_nsec = 2; + }; + TimeSpec time = 2; + TimeSpec resolution = 3; +}; + +message SymbolsDetailMsg { + uint64 symbol_addr = 1; // symbol address + string symbol_name = 2; // symbol name +} + +message FtraceCpuStatsMsg { + enum Status { + TRACE_START = 0; + TRACE_END = 1; + } + + Status status = 1; + repeated PerCpuStatsMsg per_cpu_stats = 2; + string trace_clock = 3; +} + +// cat /sys/kernel/debug/tracing/per_cpu/cpu0/stats +message PerCpuStatsMsg { + uint64 cpu = 1; + uint64 entries = 2; + uint64 overrun = 3; + uint64 commit_overrun = 4; + uint64 bytes = 5; + double oldest_event_ts = 6; + double now_ts = 7; + uint64 dropped_events = 8; + uint64 read_events = 9; +} + +message FtraceCpuDetailMsg { + uint32 cpu = 1; + repeated FtraceEvent event = 2; + uint64 overwrite = 3; +} diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/v4l2.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/v4l2.proto new file mode 100755 index 0000000000000000000000000000000000000000..7ca31b507160e8a66bd9ddeb1b485d957dcb6c50 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/v4l2.proto @@ -0,0 +1,140 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: v4l2 +// /sys/kernel/debug/tracing/events/v4l2/v4l2_dqbuf/format +message V4l2DqbufFormat { + int32 minor = 1; + uint32 index = 2; + uint32 type = 3; + uint32 bytesused = 4; + uint32 flags = 5; + uint32 field = 6; + int64 timestamp = 7; + uint32 timecode_type = 8; + uint32 timecode_flags = 9; + uint32 timecode_frames = 10; + uint32 timecode_seconds = 11; + uint32 timecode_minutes = 12; + uint32 timecode_hours = 13; + uint32 timecode_userbits0 = 14; + uint32 timecode_userbits1 = 15; + uint32 timecode_userbits2 = 16; + uint32 timecode_userbits3 = 17; + uint32 sequence = 18; +} + +// /sys/kernel/debug/tracing/events/v4l2/v4l2_qbuf/format +message V4l2QbufFormat { + int32 minor = 1; + uint32 index = 2; + uint32 type = 3; + uint32 bytesused = 4; + uint32 flags = 5; + uint32 field = 6; + int64 timestamp = 7; + uint32 timecode_type = 8; + uint32 timecode_flags = 9; + uint32 timecode_frames = 10; + uint32 timecode_seconds = 11; + uint32 timecode_minutes = 12; + uint32 timecode_hours = 13; + uint32 timecode_userbits0 = 14; + uint32 timecode_userbits1 = 15; + uint32 timecode_userbits2 = 16; + uint32 timecode_userbits3 = 17; + uint32 sequence = 18; +} + +// /sys/kernel/debug/tracing/events/v4l2/vb2_v4l2_buf_done/format +message Vb2V4l2BufDoneFormat { + int32 minor = 1; + uint32 flags = 2; + uint32 field = 3; + uint64 timestamp = 4; + uint32 timecode_type = 5; + uint32 timecode_flags = 6; + uint32 timecode_frames = 7; + uint32 timecode_seconds = 8; + uint32 timecode_minutes = 9; + uint32 timecode_hours = 10; + uint32 timecode_userbits0 = 11; + uint32 timecode_userbits1 = 12; + uint32 timecode_userbits2 = 13; + uint32 timecode_userbits3 = 14; + uint32 sequence = 15; +} + +// /sys/kernel/debug/tracing/events/v4l2/vb2_v4l2_buf_queue/format +message Vb2V4l2BufQueueFormat { + int32 minor = 1; + uint32 flags = 2; + uint32 field = 3; + uint64 timestamp = 4; + uint32 timecode_type = 5; + uint32 timecode_flags = 6; + uint32 timecode_frames = 7; + uint32 timecode_seconds = 8; + uint32 timecode_minutes = 9; + uint32 timecode_hours = 10; + uint32 timecode_userbits0 = 11; + uint32 timecode_userbits1 = 12; + uint32 timecode_userbits2 = 13; + uint32 timecode_userbits3 = 14; + uint32 sequence = 15; +} + +// /sys/kernel/debug/tracing/events/v4l2/vb2_v4l2_dqbuf/format +message Vb2V4l2DqbufFormat { + int32 minor = 1; + uint32 flags = 2; + uint32 field = 3; + uint64 timestamp = 4; + uint32 timecode_type = 5; + uint32 timecode_flags = 6; + uint32 timecode_frames = 7; + uint32 timecode_seconds = 8; + uint32 timecode_minutes = 9; + uint32 timecode_hours = 10; + uint32 timecode_userbits0 = 11; + uint32 timecode_userbits1 = 12; + uint32 timecode_userbits2 = 13; + uint32 timecode_userbits3 = 14; + uint32 sequence = 15; +} + +// /sys/kernel/debug/tracing/events/v4l2/vb2_v4l2_qbuf/format +message Vb2V4l2QbufFormat { + int32 minor = 1; + uint32 flags = 2; + uint32 field = 3; + uint64 timestamp = 4; + uint32 timecode_type = 5; + uint32 timecode_flags = 6; + uint32 timecode_frames = 7; + uint32 timecode_seconds = 8; + uint32 timecode_minutes = 9; + uint32 timecode_hours = 10; + uint32 timecode_userbits0 = 11; + uint32 timecode_userbits1 = 12; + uint32 timecode_userbits2 = 13; + uint32 timecode_userbits3 = 14; + uint32 sequence = 15; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/vmscan.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/vmscan.proto new file mode 100755 index 0000000000000000000000000000000000000000..c9f1867f74c298e46b96323be93926d24cf1c0d7 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/vmscan.proto @@ -0,0 +1,111 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: vmscan +// /sys/kernel/debug/tracing/events/vmscan/mm_shrink_slab_end/format +message MmShrinkSlabEndFormat { + uint64 shr = 1; + int32 nid = 2; + uint64 shrink = 3; + uint64 unused_scan = 4; + uint64 new_scan = 5; + int32 retval = 6; + uint64 total_scan = 7; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_shrink_slab_start/format +message MmShrinkSlabStartFormat { + uint64 shr = 1; + uint64 shrink = 2; + int32 nid = 3; + uint64 nr_objects_to_shrink = 4; + uint32 gfp_flags = 5; + uint64 cache_items = 6; + uint64 delta = 7; + uint64 total_scan = 8; + int32 priority = 9; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/format +message MmVmscanDirectReclaimBeginFormat { + int32 order = 1; + int32 may_writepage = 2; + uint32 gfp_flags = 3; + int32 classzone_idx = 4; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/format +message MmVmscanDirectReclaimEndFormat { + uint64 nr_reclaimed = 1; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/format +message MmVmscanKswapdSleepFormat { + int32 nid = 1; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/format +message MmVmscanKswapdWakeFormat { + int32 nid = 1; + int32 zid = 2; + int32 order = 3; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_lru_isolate/format +message MmVmscanLruIsolateFormat { + int32 classzone_idx = 1; + int32 order = 2; + uint64 nr_requested = 3; + uint64 nr_scanned = 4; + uint64 nr_skipped = 5; + uint64 nr_taken = 6; + uint32 isolate_mode = 7; + int32 lru = 8; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_lru_shrink_inactive/format +message MmVmscanLruShrinkInactiveFormat { + int32 nid = 1; + uint64 nr_scanned = 2; + uint64 nr_reclaimed = 3; + uint64 nr_dirty = 4; + uint64 nr_writeback = 5; + uint64 nr_congested = 6; + uint64 nr_immediate = 7; + uint64 nr_activate = 8; + uint64 nr_ref_keep = 9; + uint64 nr_unmap_fail = 10; + int32 priority = 11; + int32 reclaim_flags = 12; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_wakeup_kswapd/format +message MmVmscanWakeupKswapdFormat { + int32 nid = 1; + int32 zid = 2; + int32 order = 3; + uint32 gfp_flags = 4; +} + +// /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_writepage/format +message MmVmscanWritepageFormat { + uint64 pfn = 1; + int32 reclaim_flags = 2; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/workqueue.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/workqueue.proto new file mode 100755 index 0000000000000000000000000000000000000000..040e5abf1bfc038ee0be5ea33de0c25e4bcfd68c --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/workqueue.proto @@ -0,0 +1,45 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: workqueue +// /sys/kernel/debug/tracing/events/workqueue/workqueue_activate_work/format +message WorkqueueActivateWorkFormat { + uint64 work = 1; +} + +// /sys/kernel/debug/tracing/events/workqueue/workqueue_execute_end/format +message WorkqueueExecuteEndFormat { + uint64 work = 1; +} + +// /sys/kernel/debug/tracing/events/workqueue/workqueue_execute_start/format +message WorkqueueExecuteStartFormat { + uint64 work = 1; + uint64 function = 2; +} + +// /sys/kernel/debug/tracing/events/workqueue/workqueue_queue_work/format +message WorkqueueQueueWorkFormat { + uint64 work = 1; + uint64 function = 2; + uint64 workqueue = 3; + uint32 req_cpu = 4; + uint32 cpu = 5; +} + diff --git a/trace_streamer/src/protos/types/plugins/ftrace_data/writeback.proto b/trace_streamer/src/protos/types/plugins/ftrace_data/writeback.proto new file mode 100755 index 0000000000000000000000000000000000000000..fdf2bdb1002df4a7593eff0e1725366237357420 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/ftrace_data/writeback.proto @@ -0,0 +1,288 @@ +// THIS FILE IS GENERATED BY ftrace_proto_generator.py, PLEASE DON'T EDIT IT! +// 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. +// + +syntax = "proto3"; + +option optimize_for = LITE_RUNTIME; + +// category: writeback +// /sys/kernel/debug/tracing/events/writeback/balance_dirty_pages/format +message BalanceDirtyPagesFormat { + string bdi = 1; + uint64 limit = 2; + uint64 setpoint = 3; + uint64 dirty = 4; + uint64 bdi_setpoint = 5; + uint64 bdi_dirty = 6; + uint64 dirty_ratelimit = 7; + uint64 task_ratelimit = 8; + uint32 dirtied = 9; + uint32 dirtied_pause = 10; + uint64 paused = 11; + uint64 pause = 12; + uint64 period = 13; + uint64 think = 14; + uint32 cgroup_ino = 15; +} + +// /sys/kernel/debug/tracing/events/writeback/bdi_dirty_ratelimit/format +message BdiDirtyRatelimitFormat { + string bdi = 1; + uint64 write_bw = 2; + uint64 avg_write_bw = 3; + uint64 dirty_rate = 4; + uint64 dirty_ratelimit = 5; + uint64 task_ratelimit = 6; + uint64 balanced_dirty_ratelimit = 7; + uint32 cgroup_ino = 8; +} + +// /sys/kernel/debug/tracing/events/writeback/global_dirty_state/format +message GlobalDirtyStateFormat { + uint64 nr_dirty = 1; + uint64 nr_writeback = 2; + uint64 nr_unstable = 3; + uint64 background_thresh = 4; + uint64 dirty_thresh = 5; + uint64 dirty_limit = 6; + uint64 nr_dirtied = 7; + uint64 nr_written = 8; +} + +// /sys/kernel/debug/tracing/events/writeback/wbc_writepage/format +message WbcWritepageFormat { + string name = 1; + uint64 nr_to_write = 2; + uint64 pages_skipped = 3; + int32 sync_mode = 4; + int32 for_kupdate = 5; + int32 for_background = 6; + int32 for_reclaim = 7; + int32 range_cyclic = 8; + uint64 range_start = 9; + uint64 range_end = 10; + uint32 cgroup_ino = 11; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_bdi_register/format +message WritebackBdiRegisterFormat { + string name = 1; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_congestion_wait/format +message WritebackCongestionWaitFormat { + uint32 usec_timeout = 1; + uint32 usec_delayed = 2; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_dirty_inode/format +message WritebackDirtyInodeFormat { + string name = 1; + uint64 ino = 2; + uint64 state = 3; + uint64 flags = 4; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_dirty_inode_enqueue/format +message WritebackDirtyInodeEnqueueFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 state = 3; + uint32 mode = 4; + uint64 dirtied_when = 5; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_dirty_inode_start/format +message WritebackDirtyInodeStartFormat { + string name = 1; + uint64 ino = 2; + uint64 state = 3; + uint64 flags = 4; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_dirty_page/format +message WritebackDirtyPageFormat { + string name = 1; + uint64 ino = 2; + uint64 index = 3; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_exec/format +message WritebackExecFormat { + string name = 1; + uint64 nr_pages = 2; + uint64 sb_dev = 3; + int32 sync_mode = 4; + int32 for_kupdate = 5; + int32 range_cyclic = 6; + int32 for_background = 7; + int32 reason = 8; + uint32 cgroup_ino = 9; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_lazytime/format +message WritebackLazytimeFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 state = 3; + uint32 mode = 4; + uint64 dirtied_when = 5; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_lazytime_iput/format +message WritebackLazytimeIputFormat { + uint64 dev = 1; + uint64 ino = 2; + uint64 state = 3; + uint32 mode = 4; + uint64 dirtied_when = 5; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_mark_inode_dirty/format +message WritebackMarkInodeDirtyFormat { + string name = 1; + uint64 ino = 2; + uint64 state = 3; + uint64 flags = 4; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_pages_written/format +message WritebackPagesWrittenFormat { + uint64 pages = 1; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_queue/format +message WritebackQueueFormat { + string name = 1; + uint64 nr_pages = 2; + uint64 sb_dev = 3; + int32 sync_mode = 4; + int32 for_kupdate = 5; + int32 range_cyclic = 6; + int32 for_background = 7; + int32 reason = 8; + uint32 cgroup_ino = 9; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_queue_io/format +message WritebackQueueIoFormat { + string name = 1; + uint64 older = 2; + uint64 age = 3; + int32 moved = 4; + int32 reason = 5; + uint32 cgroup_ino = 6; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_sb_inodes_requeue/format +message WritebackSbInodesRequeueFormat { + string name = 1; + uint64 ino = 2; + uint64 state = 3; + uint64 dirtied_when = 4; + uint32 cgroup_ino = 5; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_single_inode/format +message WritebackSingleInodeFormat { + string name = 1; + uint64 ino = 2; + uint64 state = 3; + uint64 dirtied_when = 4; + uint64 writeback_index = 5; + uint64 nr_to_write = 6; + uint64 wrote = 7; + uint32 cgroup_ino = 8; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_single_inode_start/format +message WritebackSingleInodeStartFormat { + string name = 1; + uint64 ino = 2; + uint64 state = 3; + uint64 dirtied_when = 4; + uint64 writeback_index = 5; + uint64 nr_to_write = 6; + uint64 wrote = 7; + uint32 cgroup_ino = 8; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_start/format +message WritebackStartFormat { + string name = 1; + uint64 nr_pages = 2; + uint64 sb_dev = 3; + int32 sync_mode = 4; + int32 for_kupdate = 5; + int32 range_cyclic = 6; + int32 for_background = 7; + int32 reason = 8; + uint32 cgroup_ino = 9; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_wait/format +message WritebackWaitFormat { + string name = 1; + uint64 nr_pages = 2; + uint64 sb_dev = 3; + int32 sync_mode = 4; + int32 for_kupdate = 5; + int32 range_cyclic = 6; + int32 for_background = 7; + int32 reason = 8; + uint32 cgroup_ino = 9; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_wait_iff_congested/format +message WritebackWaitIffCongestedFormat { + uint32 usec_timeout = 1; + uint32 usec_delayed = 2; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_wake_background/format +message WritebackWakeBackgroundFormat { + string name = 1; + uint32 cgroup_ino = 2; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_write_inode/format +message WritebackWriteInodeFormat { + string name = 1; + uint64 ino = 2; + int32 sync_mode = 3; + uint32 cgroup_ino = 4; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_write_inode_start/format +message WritebackWriteInodeStartFormat { + string name = 1; + uint64 ino = 2; + int32 sync_mode = 3; + uint32 cgroup_ino = 4; +} + +// /sys/kernel/debug/tracing/events/writeback/writeback_written/format +message WritebackWrittenFormat { + string name = 1; + uint64 nr_pages = 2; + uint64 sb_dev = 3; + int32 sync_mode = 4; + int32 for_kupdate = 5; + int32 range_cyclic = 6; + int32 for_background = 7; + int32 reason = 8; + uint32 cgroup_ino = 9; +} + diff --git a/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..0a2abcb11d0c0bc85a5e6e834ea354b77b9f07eb --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hidump_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +hidump_data_sources = [ + "./hidump_plugin_config.proto", + "./hidump_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +hidump_data_codegen = [] +foreach(proto, hidump_data_sources) { + name = get_path_info(proto, "name") + hidump_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("hidump_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("hidump_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = hidump_data_sources + outputs = hidump_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("hidump_data_cpp") { + deps = [ ":hidump_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":hidump_include_config" ] + sources = hidump_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/hidump_data/hidump_plugin_config.proto b/trace_streamer/src/protos/types/plugins/hidump_data/hidump_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..46e33f6a89516b63123fb03cea6252c6900a5543 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hidump_data/hidump_plugin_config.proto @@ -0,0 +1,20 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + + +message HidumpConfig { + bool report_fps = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/hidump_data/hidump_plugin_result.proto b/trace_streamer/src/protos/types/plugins/hidump_data/hidump_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..5cf6e5534268dd72699a0384e3779615ff0ee77e --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hidump_data/hidump_plugin_result.proto @@ -0,0 +1,39 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + + +message FpsData { + enum ClockId { + UNKNOW = 0; + BOOTTIME = 1; + REALTIME = 2; + REALTIME_COARSE = 3; + MONOTONIC = 4; + MONOTONIC_COARSE = 5; + MONOTONIC_RAW = 6; + } + ClockId id = 1; + message TimeSpec { + uint32 tv_sec = 1; + uint32 tv_nsec = 2; + }; + TimeSpec time = 2; + uint32 fps = 3; +} + +message HidumpInfo { + repeated FpsData fps_event = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..80ed343a2a45c8c545cf7d8af3cd4e3468248b68 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hilog_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +hilog_data_sources = [ + "./hilog_plugin_config.proto", + "./hilog_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +hilog_data_codegen = [] +foreach(proto, hilog_data_sources) { + name = get_path_info(proto, "name") + hilog_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("hilog_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("hilog_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = hilog_data_sources + outputs = hilog_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("hilog_data_cpp") { + deps = [ ":hilog_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":hilog_include_config" ] + sources = hilog_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/hilog_data/hilog_plugin_config.proto b/trace_streamer/src/protos/types/plugins/hilog_data/hilog_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..1b1872474f4bdc4d2f18284015dc6aabbb359b75 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hilog_data/hilog_plugin_config.proto @@ -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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +enum Type { + TYPE_UNSPECIFIED = 0; + HI3516 = 1; + P40 = 2; +} + +enum Level { + LEVEL_UNSPECIFIED = 0; + ERROR = 1; + INFO = 2; + DEBUG = 3; + WARN = 4; +} + +message HilogConfig { + Type device_type = 1; + Level log_level = 2; + + int32 pid = 3; + bool need_record = 4; + bool need_clear = 5; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/hilog_data/hilog_plugin_result.proto b/trace_streamer/src/protos/types/plugins/hilog_data/hilog_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..64e678def7dcc24176e55185be17027c34c0d15c --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hilog_data/hilog_plugin_result.proto @@ -0,0 +1,36 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message HilogDetails { + // log time + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + uint32 pid = 3; + uint32 tid = 4; + uint32 level = 5; + string tag = 6; +} + +message HilogLine { + HilogDetails detail = 1; + string context = 2; + uint64 id = 3; +} + +message HilogInfo { + repeated HilogLine info = 1; + uint32 clock = 2; // 空值 +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn b/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..d59bfb255a4434bcb934d903f22881e8cd9ee8fa --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/BUILD.gn @@ -0,0 +1,63 @@ +# 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("../../../protos.gni") + +hiperf_call_plugin_protos_defines = [ "./hiperf_call_plugin_config.proto" ] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) +print("proto_out_dir", proto_out_dir, proto_rel_out_dir) + +####################################################### +hiperf_call_plugin_protos_codegen = [] +foreach(proto, hiperf_call_plugin_protos_defines) { + name = get_path_info(proto, "name") + hiperf_call_plugin_protos_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +action("hiperf_call_plugin_protos_protoc") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = hiperf_call_plugin_protos_defines + outputs = hiperf_call_plugin_protos_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +config("hiperf_call_plugin_protos_config") { + include_dirs = [ "$proto_out_dir" ] +} + +source_set("hiperf_call_plugin_protos_cpp") { + deps = [ ":hiperf_call_plugin_protos_protoc" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":hiperf_call_plugin_protos_config" ] + sources = hiperf_call_plugin_protos_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/hiperf_call_plugin_config.proto b/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/hiperf_call_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..e11b279f296a3ebf0b5bc52ce51b0fd88311ccc7 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hiperf_call_plugin/hiperf_call_plugin_config.proto @@ -0,0 +1,26 @@ +// 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. + +syntax = "proto3"; +option optimize_for = LITE_RUNTIME; + +message HiperfCallPluginConfig { + int32 pid = 1; // pid of app. + string app_name = 2; // app name. + string outfile = 4; // the name of the output target file. + + uint32 frequency = 3; // Set the counts of dumpping records per second, default 1000. + bool is_trace = 5; // Set if using --trace-offcpu, default true. + bool is_root = 6; // Set if using root privilege, default true. + bool is_emulator = 7; // Set if the device is emulator, default false. +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..64bf34a022c1e3b988cd9eb0462ac47bed0e2248 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hisysevent_data/BUILD.gn @@ -0,0 +1,87 @@ +# 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("../../../protos.gni") + +hisysevent_data_sources = [ + "./hisysevent_plugin_config.proto", + "./hisysevent_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +hisysevent_data_codegen = [] +hisysevent_data_codegen_standard = [] +hisysevent_data_codegen_all = [] + +foreach(proto, hisysevent_data_sources) { + name = get_path_info(proto, "name") + hisysevent_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] + hisysevent_data_codegen_standard += [ + "$proto_out_dir/${name}_standard.pb.h", + "$proto_out_dir/${name}_standard.pb.cc", + ] +} + +hisysevent_data_codegen_all += hisysevent_data_codegen +hisysevent_data_codegen_all += hisysevent_data_codegen_standard + +config("hisysevent_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("hisysevent_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = hisysevent_data_sources + outputs = hisysevent_data_codegen_all + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "$proto_rel_out_dir", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("hisysevent_data_cpp") { + deps = [ ":hisysevent_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":hisysevent_include_config" ] + sources = hisysevent_data_codegen +} + +source_set("hisysevent_data_cpp_standard") { + deps = [ ":hisysevent_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":hisysevent_include_config" ] + sources = hisysevent_data_codegen_standard +} diff --git a/trace_streamer/src/protos/types/plugins/hisysevent_data/hisysevent_plugin_config.proto b/trace_streamer/src/protos/types/plugins/hisysevent_data/hisysevent_plugin_config.proto new file mode 100644 index 0000000000000000000000000000000000000000..9b7a6e5270599141a658551e9e6377e8c291d395 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hisysevent_data/hisysevent_plugin_config.proto @@ -0,0 +1,21 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +// TODO Save the fetch data +message HisyseventConfig { + string msg = 1; + string process_name = 2; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/hisysevent_data/hisysevent_plugin_result.proto b/trace_streamer/src/protos/types/plugins/hisysevent_data/hisysevent_plugin_result.proto new file mode 100644 index 0000000000000000000000000000000000000000..4dba0ff2b16e93fa2b68917d8e10ec619b72efd2 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/hisysevent_data/hisysevent_plugin_result.proto @@ -0,0 +1,55 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +// For Device Stat all below. +message AudioVolumeInfo { + int32 stream_default = 1; + int32 voice_call = 2; + int32 music = 3; + int32 stream_ring = 4; + int32 media = 5; + int32 voice_assistant = 6; + int32 system = 7; + int32 alarm = 8; + int32 notification = 9; + int32 bluetoolth_sco = 10; + int32 enforced_audible = 11; + int32 stream_dtmf = 12; + int32 stream_tts = 13; + int32 accessibility = 14; + int32 recording = 15; + int32 stream_all = 16; +} + +// NODE Save the Device Stat +message DeviceStat { + uint32 brightness_state = 1; + int32 bt_state = 2; + bool location_state = 3; + int32 wifi_state = 4; + AudioVolumeInfo volume_state = 5; +} + +// NODE Save the captured data +message HisyseventLine { + string raw_content = 1; + uint64 id = 2; +} + +message HisyseventInfo { + repeated HisyseventLine info = 1; + DeviceStat device_state = 2; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn b/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..931eb4c2955da6163e926e185ad6ee07ba6833fa --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/js_memory/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +js_memory_sources = [ + "./js_heap_config.proto", + "./js_heap_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +js_memory_codegen = [] +foreach(proto, js_memory_sources) { + name = get_path_info(proto, "name") + js_memory_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("js_memory_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("js_memory_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = js_memory_sources + outputs = js_memory_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("js_memory_cpp") { + deps = [ ":js_memory_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":js_memory_include_config" ] + sources = js_memory_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/js_memory/js_heap_config.proto b/trace_streamer/src/protos/types/plugins/js_memory/js_heap_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..2a9442e2a574ab15a2e74064684f081e6bfed161 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/js_memory/js_heap_config.proto @@ -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. + +syntax = "proto3"; + +message JsHeapConfig { + enum HeapType { + SNAPSHOT = 0; + TIMELINE = 1; + // ALLOC_SAMPLE = 2; + } + int32 pid = 1; + HeapType type = 2; + uint32 interval = 3; // seconds + bool capture_numeric_value = 4; + bool track_allocations = 5; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/js_memory/js_heap_result.proto b/trace_streamer/src/protos/types/plugins/js_memory/js_heap_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..4291e6b1fafd7870ded81946dc011bfba81df988 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/js_memory/js_heap_result.proto @@ -0,0 +1,17 @@ +// 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. + +syntax = "proto3"; +message JsHeapResult { + bytes result = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..fa25351a2ece5839a50c60e674d1f68e24dc2700 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/memory_data/BUILD.gn @@ -0,0 +1,66 @@ +# 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("../../../protos.gni") + +memory_data_sources = [ + "./memory_plugin_common.proto", + "./memory_plugin_config.proto", + "./memory_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +memory_data_codegen = [] +foreach(proto, memory_data_sources) { + name = get_path_info(proto, "name") + memory_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("memory_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("memory_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = memory_data_sources + outputs = memory_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("memory_data_cpp") { + deps = [ ":memory_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":memory_include_config" ] + sources = memory_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_common.proto b/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_common.proto new file mode 100755 index 0000000000000000000000000000000000000000..361b65e87016a5e9f253c3529aa9a7437954c380 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_common.proto @@ -0,0 +1,188 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +// Common define for memory plug-in, imported by memory data and config proto file. +enum SysMeminfoType { + PMEM_UNSPECIFIED = 0; + PMEM_MEM_TOTAL = 1; + PMEM_MEM_FREE = 2; + PMEM_MEM_AVAILABLE = 3; + PMEM_BUFFERS = 4; + PMEM_CACHED = 5; + PMEM_SWAP_CACHED = 6; + PMEM_ACTIVE = 7; + PMEM_INACTIVE = 8; + PMEM_ACTIVE_ANON = 9; + PMEM_INACTIVE_ANON = 10; + PMEM_ACTIVE_FILE = 11; + PMEM_INACTIVE_FILE = 12; + PMEM_UNEVICTABLE = 13; + PMEM_MLOCKED = 14; + PMEM_SWAP_TOTAL = 15; + PMEM_SWAP_FREE = 16; + PMEM_DIRTY = 17; + PMEM_WRITEBACK = 18; + PMEM_ANON_PAGES = 19; + PMEM_MAPPED = 20; + PMEM_SHMEM = 21; + PMEM_SLAB = 22; + PMEM_SLAB_RECLAIMABLE = 23; + PMEM_SLAB_UNRECLAIMABLE = 24; + PMEM_KERNEL_STACK = 25; + PMEM_PAGE_TABLES = 26; + PMEM_COMMIT_LIMIT = 27; + PMEM_COMMITED_AS = 28; + PMEM_VMALLOC_TOTAL = 29; + PMEM_VMALLOC_USED = 30; + PMEM_VMALLOC_CHUNK = 31; + PMEM_CMA_TOTAL = 32; + PMEM_CMA_FREE = 33; + PMEM_KERNEL_RECLAIMABLE = 34; +} + +enum SysVMeminfoType { + VMEMINFO_UNSPECIFIED = 0; + VMEMINFO_NR_FREE_PAGES = 1; + VMEMINFO_NR_ALLOC_BATCH = 2; + VMEMINFO_NR_INACTIVE_ANON = 3; + VMEMINFO_NR_ACTIVE_ANON = 4; + VMEMINFO_NR_INACTIVE_FILE = 5; + VMEMINFO_NR_ACTIVE_FILE = 6; + VMEMINFO_NR_UNEVICTABLE = 7; + VMEMINFO_NR_MLOCK = 8; + VMEMINFO_NR_ANON_PAGES = 9; + VMEMINFO_NR_MAPPED = 10; + VMEMINFO_NR_FILE_PAGES = 11; + VMEMINFO_NR_DIRTY = 12; + VMEMINFO_NR_WRITEBACK = 13; + VMEMINFO_NR_SLAB_RECLAIMABLE = 14; + VMEMINFO_NR_SLAB_UNRECLAIMABLE = 15; + VMEMINFO_NR_PAGE_TABLE_PAGES = 16; + VMEMINFO_NR_KERNEL_STACK = 17; + VMEMINFO_NR_OVERHEAD = 18; + VMEMINFO_NR_UNSTABLE = 19; + VMEMINFO_NR_BOUNCE = 20; + VMEMINFO_NR_VMSCAN_WRITE = 21; + VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM = 22; + VMEMINFO_NR_WRITEBACK_TEMP = 23; + VMEMINFO_NR_ISOLATED_ANON = 24; + VMEMINFO_NR_ISOLATED_FILE = 25; + VMEMINFO_NR_SHMEM = 26; + VMEMINFO_NR_DIRTIED = 27; + VMEMINFO_NR_WRITTEN = 28; + VMEMINFO_NR_PAGES_SCANNED = 29; + VMEMINFO_WORKINGSET_REFAULT = 30; + VMEMINFO_WORKINGSET_ACTIVATE = 31; + VMEMINFO_WORKINGSET_NODERECLAIM = 32; + VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES = 33; + VMEMINFO_NR_FREE_CMA = 34; + VMEMINFO_NR_SWAPCACHE = 35; + VMEMINFO_NR_DIRTY_THRESHOLD = 36; + VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD = 37; + VMEMINFO_PGPGIN = 38; + VMEMINFO_PGPGOUT = 39; + VMEMINFO_PGPGOUTCLEAN = 40; + VMEMINFO_PSWPIN = 41; + VMEMINFO_PSWPOUT = 42; + VMEMINFO_PGALLOC_DMA = 43; + VMEMINFO_PGALLOC_NORMAL = 44; + VMEMINFO_PGALLOC_MOVABLE = 45; + VMEMINFO_PGFREE = 46; + VMEMINFO_PGACTIVATE = 47; + VMEMINFO_PGDEACTIVATE = 48; + VMEMINFO_PGFAULT = 49; + VMEMINFO_PGMAJFAULT = 50; + VMEMINFO_PGREFILL_DMA = 51; + VMEMINFO_PGREFILL_NORMAL = 52; + VMEMINFO_PGREFILL_MOVABLE = 53; + VMEMINFO_PGSTEAL_KSWAPD_DMA = 54; + VMEMINFO_PGSTEAL_KSWAPD_NORMAL = 55; + VMEMINFO_PGSTEAL_KSWAPD_MOVABLE = 56; + VMEMINFO_PGSTEAL_DIRECT_DMA = 57; + VMEMINFO_PGSTEAL_DIRECT_NORMAL = 58; + VMEMINFO_PGSTEAL_DIRECT_MOVABLE = 59; + VMEMINFO_PGSCAN_KSWAPD_DMA = 60; + VMEMINFO_PGSCAN_KSWAPD_NORMAL = 61; + VMEMINFO_PGSCAN_KSWAPD_MOVABLE = 62; + VMEMINFO_PGSCAN_DIRECT_DMA = 63; + VMEMINFO_PGSCAN_DIRECT_NORMAL = 64; + VMEMINFO_PGSCAN_DIRECT_MOVABLE = 65; + VMEMINFO_PGSCAN_DIRECT_THROTTLE = 66; + VMEMINFO_PGINODESTEAL = 67; + VMEMINFO_SLABS_SCANNED = 68; + VMEMINFO_KSWAPD_INODESTEAL = 69; + VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY = 70; + VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY = 71; + VMEMINFO_PAGEOUTRUN = 72; + VMEMINFO_ALLOCSTALL = 73; + VMEMINFO_PGROTATED = 74; + VMEMINFO_DROP_PAGECACHE = 75; + VMEMINFO_DROP_SLAB = 76; + VMEMINFO_PGMIGRATE_SUCCESS = 77; + VMEMINFO_PGMIGRATE_FAIL = 78; + VMEMINFO_COMPACT_MIGRATE_SCANNED = 79; + VMEMINFO_COMPACT_FREE_SCANNED = 80; + VMEMINFO_COMPACT_ISOLATED = 81; + VMEMINFO_COMPACT_STALL = 82; + VMEMINFO_COMPACT_FAIL = 83; + VMEMINFO_COMPACT_SUCCESS = 84; + VMEMINFO_COMPACT_DAEMON_WAKE = 85; + VMEMINFO_UNEVICTABLE_PGS_CULLED = 86; + VMEMINFO_UNEVICTABLE_PGS_SCANNED = 87; + VMEMINFO_UNEVICTABLE_PGS_RESCUED = 88; + VMEMINFO_UNEVICTABLE_PGS_MLOCKED = 89; + VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED = 90; + VMEMINFO_UNEVICTABLE_PGS_CLEARED = 91; + VMEMINFO_UNEVICTABLE_PGS_STRANDED = 92; + VMEMINFO_NR_ZSPAGES = 93; + VMEMINFO_NR_ION_HEAP = 94; + VMEMINFO_NR_GPU_HEAP = 95; + VMEMINFO_ALLOCSTALL_DMA = 96; + VMEMINFO_ALLOCSTALL_MOVABLE = 97; + VMEMINFO_ALLOCSTALL_NORMAL = 98; + VMEMINFO_COMPACT_DAEMON_FREE_SCANNED = 99; + VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED = 100; + VMEMINFO_NR_FASTRPC = 101; + VMEMINFO_NR_INDIRECTLY_RECLAIMABLE = 102; + VMEMINFO_NR_ION_HEAP_POOL = 103; + VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE = 104; + VMEMINFO_NR_SHADOW_CALL_STACK_BYTES = 105; + VMEMINFO_NR_SHMEM_HUGEPAGES = 106; + VMEMINFO_NR_SHMEM_PMDMAPPED = 107; + VMEMINFO_NR_UNRECLAIMABLE_PAGES = 108; + VMEMINFO_NR_ZONE_ACTIVE_ANON = 109; + VMEMINFO_NR_ZONE_ACTIVE_FILE = 110; + VMEMINFO_NR_ZONE_INACTIVE_ANON = 111; + VMEMINFO_NR_ZONE_INACTIVE_FILE = 112; + VMEMINFO_NR_ZONE_UNEVICTABLE = 113; + VMEMINFO_NR_ZONE_WRITE_PENDING = 114; + VMEMINFO_OOM_KILL = 115; + VMEMINFO_PGLAZYFREE = 116; + VMEMINFO_PGLAZYFREED = 117; + VMEMINFO_PGREFILL = 118; + VMEMINFO_PGSCAN_DIRECT = 119; + VMEMINFO_PGSCAN_KSWAPD = 120; + VMEMINFO_PGSKIP_DMA = 121; + VMEMINFO_PGSKIP_MOVABLE = 122; + VMEMINFO_PGSKIP_NORMAL = 123; + VMEMINFO_PGSTEAL_DIRECT = 124; + VMEMINFO_PGSTEAL_KSWAPD = 125; + VMEMINFO_SWAP_RA = 126; + VMEMINFO_SWAP_RA_HIT = 127; + VMEMINFO_WORKINGSET_RESTORE = 128; +} diff --git a/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_config.proto b/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..72f824df4f75a37224bcf24fb4d50181c1093f4f --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_config.proto @@ -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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +import "memory_plugin_common.proto"; + +// Memory plug-in configuration, passed to plug-in by plug-in service. +message MemoryConfig { + // set true to report process list + bool report_process_tree = 1; + // set true to report memory counter from /proc/meminfo + bool report_sysmem_mem_info = 2; + // set required counter list of system meminfo, eg:MemTotal, MemFree, etc. + repeated SysMeminfoType sys_meminfo_counters = 3; + // set true to report memory counter from /proc/vmstat + bool report_sysmem_vmem_info = 4; + // set required counter list of virtual system meminfo, eg:nr_free_pages, nr_anon_pages, etc. + repeated SysVMeminfoType sys_vmeminfo_counters = 5; + // set true to report process meminfo from /proc/${pid}/stat + bool report_process_mem_info = 6; + // set true to report application memory usage summary, eg:java heap memory, native heap, stack memory, etc. + bool report_app_mem_info = 7; + // set true to report application memory by dumpsys service, otherwise, + // application memory will count up by /proc/${pid}/smaps information + bool report_app_mem_by_dumpsys = 8; + // set required pid list + repeated int32 pid = 9; +} diff --git a/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_result.proto b/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..f639590d69e8c2e9b64becf19337cdf2c5620a3f --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/memory_data/memory_plugin_result.proto @@ -0,0 +1,79 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +import "memory_plugin_common.proto"; + +// Data format of memory collect plug-in. +// Various memory data count, including system level and application level. +// Obtained from the proc file system or system service. +message SysMeminfo { + SysMeminfoType key = 1; + uint64 value = 2; +}; +message SysVMeminfo { + SysVMeminfoType key = 1; + uint64 value = 2; +}; + +message SmapsInfo { + string start_addr = 1; + string end_addr = 2; + string permission = 3; + string path = 4; + uint64 size = 5; + uint64 rss = 6; + uint64 pss = 7; + double reside = 8; + uint64 dirty = 9; + uint64 swapper = 10; +}; + +message AppSummary { + uint64 java_heap = 1; + uint64 native_heap = 2; + uint64 code = 3; + uint64 stack = 4; + uint64 graphics = 5; + uint64 private_other = 6; + uint64 system = 7; +}; + +message ProcessMemoryInfo { + int32 pid = 1; + string name = 2; + // data from /proc/$pid/stat + uint64 vm_size_kb = 3; + uint64 vm_rss_kb = 4; + uint64 rss_anon_kb = 5; + uint64 rss_file_kb = 6; + uint64 rss_shmem_kb = 7; + uint64 vm_swap_kb = 8; + uint64 vm_locked_kb = 9; + uint64 vm_hwm_kb = 10; + int64 oom_score_adj = 11; + // data from /proc/$pid/smaps + repeated SmapsInfo smapinfo = 12; + AppSummary memsummary = 13; +} + +message MemoryData { + repeated ProcessMemoryInfo processesinfo = 1; + repeated SysMeminfo meminfo = 2; + repeated SysVMeminfo vmeminfo = 3; + uint64 zram = 4; +} diff --git a/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn b/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..7f3c49746438d574eb4f23fdf021d20c5cd7df14 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/native_hook/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +native_hook_sources = [ + "./native_hook_config.proto", + "./native_hook_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +native_hook_codegen = [] +foreach(proto, native_hook_sources) { + name = get_path_info(proto, "name") + native_hook_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("native_hook_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("native_hook_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = native_hook_sources + outputs = native_hook_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("native_hook_cpp") { + deps = [ ":native_hook_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":native_hook_include_config" ] + sources = native_hook_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/native_hook/native_hook_config.proto b/trace_streamer/src/protos/types/plugins/native_hook/native_hook_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..0d9891650d6cb99c78b59e0e2ec37033104d9646 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/native_hook/native_hook_config.proto @@ -0,0 +1,43 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + + +message NativeHookConfig { + int32 pid = 1; + bool save_file = 2; + string file_name = 3; + int32 filter_size = 4; + int32 smb_pages = 5; + int32 max_stack_depth = 6; + string process_name = 7; + bool malloc_disable = 8; + bool mmap_disable = 9; + bool free_stack_report = 10; + bool munmap_stack_report = 11; + uint32 malloc_free_matching_interval = 12; + uint32 malloc_free_matching_cnt = 13; + bool string_compressed = 14; + bool fp_unwind = 15; + bool blocked = 16; + bool record_accurately = 17; + bool startup_mode = 18; + bool memtrace_enable = 19; + bool offline_symbolization = 20; + bool callframe_compressed = 21; + uint32 statistics_interval = 22; +} diff --git a/trace_streamer/src/protos/types/plugins/native_hook/native_hook_result.proto b/trace_streamer/src/protos/types/plugins/native_hook/native_hook_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..8de441d5daccbc82b7c2f7d44b636c10ab017539 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/native_hook/native_hook_result.proto @@ -0,0 +1,155 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message Frame { + uint64 ip = 1; + uint64 sp = 2; + string symbol_name = 3; + string file_path = 4; + uint64 offset = 5; + uint64 symbol_offset = 6; + uint32 symbol_name_id = 7; + uint32 file_path_id = 8; +} + +message AllocEvent { + int32 pid = 1; + int32 tid = 2; + uint64 addr = 3; + uint32 size = 4; + repeated Frame frame_info = 5; + uint32 thread_name_id = 6; + uint32 stack_id = 7; +} + +message FreeEvent { + int32 pid = 1; + int32 tid = 2; + uint64 addr = 3; + repeated Frame frame_info = 4; + uint32 thread_name_id = 5; + uint32 stack_id = 6; +} + +message MmapEvent { + int32 pid = 1; + int32 tid = 2; + uint64 addr = 3; + string type = 4; + uint32 size = 5; + repeated Frame frame_info = 6; + uint32 thread_name_id = 7; + uint32 stack_id = 8; +} + +message MunmapEvent { + int32 pid = 1; + int32 tid = 2; + uint64 addr = 3; + uint32 size = 4; + repeated Frame frame_info = 5; + uint32 thread_name_id = 6; + uint32 stack_id = 7; +} + +message StackMap { + uint32 id = 1; + repeated uint64 frame_map_id = 2; // online symbolization use frame_map_id + repeated uint64 ip = 3; // offline symbolization use ip +} + +message FrameMap { + uint32 id = 1; + Frame frame = 2; +} + +message MemTagEvent { + uint64 addr = 1; + uint32 size = 2; + string tag = 3; +} + +message FilePathMap { + uint32 id = 1; + string name = 2; +} + +message SymbolMap { + uint32 id = 1; + string name = 2; +} + +message ThreadNameMap { + uint32 id = 1; + string name = 2; +} + +message MapsInfo { + uint32 pid = 1; + uint64 start = 2; + uint64 end = 3; + uint64 offset = 4; + uint32 file_path_id = 5; +} + +message SymbolTable { + uint32 file_path_id = 1; + uint64 text_exec_vaddr = 2; + uint64 text_exec_vaddr_file_offset = 3; + uint32 sym_entry_size = 4; + bytes sym_table = 5; + bytes str_table = 6; +} + +message RecordStatisticsEvent { + uint32 pid = 1; + uint32 callstack_id = 2; + enum MemoryType { + MALLOC = 0; + MMAP = 1; + }; + MemoryType type = 3; + uint64 apply_count = 4; + uint64 release_count = 5; + uint64 apply_size = 6; + uint64 release_size = 7; +} + +message NativeHookData { + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + oneof event { + AllocEvent alloc_event = 3; + FreeEvent free_event = 4; + MmapEvent mmap_event = 5; + MunmapEvent munmap_event = 6; + MemTagEvent tag_event = 7; + FilePathMap file_path = 8; + SymbolMap symbol_name = 9; + ThreadNameMap thread_name_map = 10; + MapsInfo maps_info = 11; + SymbolTable symbol_tab = 12; + FrameMap frame_map = 13; + StackMap stack_map = 14; + RecordStatisticsEvent statistics_event = 15; + } +} + +message BatchNativeHookData { + repeated NativeHookData events = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..a1155307a98cbd7ac3a5e9be0e74ae71386d09a9 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/network_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +network_data_sources = [ + "./network_plugin_config.proto", + "./network_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +network_data_codegen = [] +foreach(proto, network_data_sources) { + name = get_path_info(proto, "name") + network_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("network_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("network_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = network_data_sources + outputs = network_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("network_data_cpp") { + deps = [ ":network_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":network_include_config" ] + sources = network_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/network_data/network_plugin_config.proto b/trace_streamer/src/protos/types/plugins/network_data/network_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..b993e8c595554e5e9408c2aa43b8e4489c2fbc1e --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/network_data/network_plugin_config.proto @@ -0,0 +1,21 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message NetworkConfig { + repeated int32 pid = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/network_data/network_plugin_result.proto b/trace_streamer/src/protos/types/plugins/network_data/network_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..2ce759cc660ed0abf3f6c3a42cdbd7e74c5eb68d --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/network_data/network_plugin_result.proto @@ -0,0 +1,57 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message NetworkDetails { + uint64 tx_bytes = 1; + uint64 rx_bytes = 2; + string type = 3; // e.g. "wlan0", "rmnet0", etc. +} + +message NetworkData { + int32 pid = 1; + // timestamp obtained by CLOCK_REALTIME + uint64 tv_sec = 2; + uint64 tv_nsec = 3; + uint64 tx_bytes = 4; + uint64 rx_bytes = 5; + repeated NetworkDetails details = 6; +} + +message NetworkSystemDetails { + string type = 1; // e.g. "wlan0", "rmnet0", etc. + uint64 rx_bytes = 2; + uint64 rx_packets = 3; + uint64 tx_bytes = 4; + uint64 tx_packets = 5; +} + +message NetworkSystemData { + // timestamp obtained by CLOCK_REALTIME + uint64 tv_sec = 1; + uint64 tv_nsec = 2; + uint64 rx_bytes = 3; + uint64 rx_packets = 4; + uint64 tx_bytes = 5; + uint64 tx_packets = 6; + repeated NetworkSystemDetails details = 7; +} + +message NetworkDatas { + repeated NetworkData networkinfo = 1; + NetworkSystemData network_system_info = 2; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..e519eb418fdb26a42f3f621274c9b79cc8d431e8 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/process_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +process_data_sources = [ + "./process_plugin_config.proto", + "./process_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +process_data_codegen = [] +foreach(proto, process_data_sources) { + name = get_path_info(proto, "name") + process_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("process_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("process_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = process_data_sources + outputs = process_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("process_data_cpp") { + deps = [ ":process_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":process_include_config" ] + sources = process_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/process_data/process_plugin_config.proto b/trace_streamer/src/protos/types/plugins/process_data/process_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..ecb8389276bd5e728f4bd14edf8a66710d7d6b13 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/process_data/process_plugin_config.proto @@ -0,0 +1,22 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message ProcessConfig { + // set true to report process list + bool report_process_tree = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/process_data/process_plugin_result.proto b/trace_streamer/src/protos/types/plugins/process_data/process_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..8f790ed024b487fab19cb058da0bfa27c708904b --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/process_data/process_plugin_result.proto @@ -0,0 +1,53 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message DiskioInfo { + // read /proc/pid/io + uint64 rchar = 1; + uint64 wchar = 2; + uint64 syscr = 3; + uint64 syscw = 4; + uint64 rbytes = 5; + uint64 wbytes = 6; + uint64 cancelled_wbytes = 7; +} + +message PssInfo { + // read /proc/pid/smaps_rollup + int32 pss_info = 1; +} + +message CpuInfo { + double cpu_usage = 1; + int32 thread_sum = 2; + uint64 cpu_time_ms = 3; +} + +message ProcessInfo { + int32 pid = 1; + string name = 2; + int32 ppid = 3; + int32 uid = 4; + CpuInfo cpuinfo = 5; + PssInfo pssinfo = 6; + DiskioInfo diskinfo = 7; +} + +message ProcessData { + repeated ProcessInfo processesinfo = 1; +} diff --git a/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..1173d1ac8737a9c31561a8bb5bf930e4c3b5fea5 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/sample_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +sample_data_sources = [ + "./sample_plugin_config.proto", + "./sample_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +sample_data_codegen = [] +foreach(proto, sample_data_sources) { + name = get_path_info(proto, "name") + sample_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("sample_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("sample_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = sample_data_sources + outputs = sample_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("sample_data_cpp") { + deps = [ ":sample_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":sample_include_config" ] + sources = sample_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/sample_data/sample_plugin_config.proto b/trace_streamer/src/protos/types/plugins/sample_data/sample_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..262398e4f7ef762650353047c804927db761f6c8 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/sample_data/sample_plugin_config.proto @@ -0,0 +1,19 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message SampleConfig { + int32 pid = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/sample_data/sample_plugin_result.proto b/trace_streamer/src/protos/types/plugins/sample_data/sample_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..0a8d74393c6387eb5d0bfd4ce8a5a2bdc0d289c0 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/sample_data/sample_plugin_result.proto @@ -0,0 +1,19 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message SampleData { + uint64 time_ms = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..5c991ecd27c6e5c0215cc0b5c47acce704f26a54 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/stream_data/BUILD.gn @@ -0,0 +1,65 @@ +# 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("../../../protos.gni") + +stream_data_sources = [ + "./stream_plugin_config.proto", + "./stream_plugin_result.proto", +] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +stream_data_codegen = [] +foreach(proto, stream_data_sources) { + name = get_path_info(proto, "name") + stream_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("stream_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("stream_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = stream_data_sources + outputs = stream_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("stream_data_cpp") { + deps = [ ":stream_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":stream_include_config" ] + sources = stream_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/stream_data/stream_plugin_config.proto b/trace_streamer/src/protos/types/plugins/stream_data/stream_plugin_config.proto new file mode 100755 index 0000000000000000000000000000000000000000..9d124a74c2b03a0bd03313bdd35bc66c73c1730d --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/stream_data/stream_plugin_config.proto @@ -0,0 +1,19 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message StreamConfig { + int32 pid = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/stream_data/stream_plugin_result.proto b/trace_streamer/src/protos/types/plugins/stream_data/stream_plugin_result.proto new file mode 100755 index 0000000000000000000000000000000000000000..ece7d24105cc0f46574aefe0d7b4c2a456e746a1 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/stream_data/stream_plugin_result.proto @@ -0,0 +1,19 @@ +// 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. +syntax = "proto3"; +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message StreamData { + uint64 time_ms = 1; +} \ No newline at end of file diff --git a/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn b/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2befc06544c23f958a1e19c7c75410f383d67bb2 --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/test_data/BUILD.gn @@ -0,0 +1,62 @@ +# 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("../../../protos.gni") + +test_data_sources = [ "./test.proto" ] + +####################################################### +proto_out_dir = "$root_gen_dir/cpp/" + rebase_path(".", "//") +proto_rel_out_dir = rebase_path(proto_out_dir, root_build_dir) + +test_data_codegen = [] +foreach(proto, test_data_sources) { + name = get_path_info(proto, "name") + test_data_codegen += [ + "$proto_out_dir/$name.pb.h", + "$proto_out_dir/$name.pb.cc", + ] +} + +config("test_include_config") { + include_dirs = [ "$proto_out_dir" ] +} + +####################################################### +action("test_data_cpp_gen") { + script = "${OHOS_PROFILER_DIR}/build/protoc.sh" + sources = test_data_sources + outputs = test_data_codegen + args = [ + "$libc_dir_proto", + "$root_output_dir_proto", + "--cpp_out", + "$proto_rel_out_dir", + "--proto_path", + rebase_path(".", root_build_dir), + ] + args += rebase_path(sources, root_build_dir) + deps = [ "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protoc(${host_toolchain})" ] +} + +source_set("test_data_cpp") { + deps = [ ":test_data_cpp_gen" ] + public_deps = [ + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf", + "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", + ] + include_dirs = [ "$proto_out_dir" ] + public_configs = [ ":test_include_config" ] + sources = test_data_codegen +} diff --git a/trace_streamer/src/protos/types/plugins/test_data/test.proto b/trace_streamer/src/protos/types/plugins/test_data/test.proto new file mode 100755 index 0000000000000000000000000000000000000000..6c258861b6887d589cb477575be70d1fd3dede9e --- /dev/null +++ b/trace_streamer/src/protos/types/plugins/test_data/test.proto @@ -0,0 +1,56 @@ +// 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. + +syntax = "proto3"; + +option java_package = "ohos.devtools.datasources.transport.grpc.service"; +option optimize_for = LITE_RUNTIME; + +message Test { + int32 number = 1; + uint64 tv_nsec = 2; + string name = 3; + bool is_test = 4; + enum State { + INITED = 0; + REGISTERED = 1; + }; + State state = 5; + oneof event { + int32 alloc_event = 6; + string free_event = 7; + } +} + +message NumberTest { + repeated int32 numberText = 1; +} + +message Fixed64Test { + repeated double fixed64NumberText = 1; +} + +message Fixed32Test { + repeated float fixed32NumberText = 1; +} + +message CpuInfoTest { + repeated Test test = 1; +} +message TestParser { + int32 count = 1; + CpuInfoTest cores = 2; + NumberTest numberTest = 3; + Fixed64Test fixed64Test = 4; + Fixed32Test fixed32Test = 5; +} diff --git a/trace_streamer/src/rpc/http_server.cpp b/trace_streamer/src/rpc/http_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a324e55a121a5625491049518c8106346b42c355 --- /dev/null +++ b/trace_streamer/src/rpc/http_server.cpp @@ -0,0 +1,457 @@ +/* + * 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 "http_server.h" +#include +#include +#include +#include // for macx +#include +#ifdef _WIN32 +#include +#else +#include +#include +#endif +#include "log.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +void HttpServer::RegisterRpcFunction(RpcServer* rpc) +{ + rpcFunctions_.clear(); + + using std::placeholders::_1; + using std::placeholders::_2; + using std::placeholders::_3; + + auto parsedata = std::bind(&RpcServer::ParseData, rpc, _1, _2, _3); + rpcFunctions_["/parsedata"] = parsedata; + + auto parsedataover = std::bind(&RpcServer::ParseDataOver, rpc, _1, _2, _3); + rpcFunctions_["/parsedataover"] = parsedataover; + + auto sqlquery = std::bind(&RpcServer::SqlQuery, rpc, _1, _2, _3); + rpcFunctions_["/sqlquery"] = sqlquery; + + auto sqloperate = std::bind(&RpcServer::SqlOperate, rpc, _1, _2, _3); + rpcFunctions_["/sqloperate"] = sqloperate; + + auto reset = std::bind(&RpcServer::Reset, rpc, _1, _2, _3); + rpcFunctions_["/reset"] = reset; +} + +#ifdef _WIN32 +void HttpServer::Run(int32_t port) +{ + WSADATA ws{}; + if (WSAStartup(MAKEWORD(WS_VERSION_FIRST, WS_VERSION_SEC), &ws) != 0) { + return; + } + if (!CreateSocket(port)) { + return; + } + WSAEVENT events[COUNT_SOCKET]; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + if ((events[i] = WSACreateEvent()) == WSA_INVALID_EVENT) { + TS_LOGE("WSACreateEvent error %d", WSAGetLastError()); + return; + } + WSAEventSelect(sockets_[i].GetFd(), events[i], FD_ACCEPT | FD_CLOSE); + } + + while (!isExit_) { + ClearDeadClientThread(); + + int32_t index = WSAWaitForMultipleEvents(COUNT_SOCKET, events, false, pollTimeOut_, false); + if (index == WSA_WAIT_FAILED) { + TS_LOGE("WSAWaitForMultipleEvents error %d", WSAGetLastError()); + break; + } else if (index == WSA_WAIT_TIMEOUT) { + continue; + } + + index = index - WSA_WAIT_EVENT_0; + WSANETWORKEVENTS event; + WSAEnumNetworkEvents(sockets_[index].GetFd(), events[index], &event); + if (event.lNetworkEvents & FD_ACCEPT) { + if (event.iErrorCode[FD_ACCEPT_BIT] != 0) { + continue; + } + + std::unique_ptr client = std::make_unique(); + if (sockets_[index].Accept(client->sock_)) { + client->thread_ = std::thread(&HttpServer::ProcessClient, this, std::ref(client->sock_)); + clientThreads_.push_back(std::move(client)); + } else { + TS_LOGE("http socket accept error"); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + for (const auto& it : clientThreads_) { + if (it->thread_.joinable()) { + it->sock_.Close(); + it->thread_.join(); + } + } + clientThreads_.clear(); + + WSACleanup(); +} +#else +void HttpServer::Run(int32_t port) +{ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { + return; + } + + if (!CreateSocket(port)) { + return; + } + TS_LOGI("http server running"); + struct pollfd fds[COUNT_SOCKET]; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + fds[i] = {sockets_[i].GetFd(), POLLIN, 0}; + } + while (!isExit_) { + ClearDeadClientThread(); + if (poll(fds, sizeof(fds) / sizeof(pollfd), pollTimeOut_) <= 0) { + continue; // try again + } + + for (int32_t i = 0; i < 1; i++) { + if (fds[i].revents != POLLIN) { + continue; + } + std::unique_ptr client = std::make_unique(); + if (sockets_[i].Accept(client->sock_)) { + client->thread_ = std::thread(&HttpServer::ProcessClient, this, std::ref(client->sock_)); + clientThreads_.push_back(std::move(client)); + } else { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } + } + + for (const auto& it : clientThreads_) { + if (it->thread_.joinable()) { + it->sock_.Close(); + it->thread_.join(); + } + } + clientThreads_.clear(); + + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + sockets_[i].Close(); + } + TS_LOGI("http server exit"); +} +#endif + +void HttpServer::Exit() +{ + isExit_ = true; + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + sockets_[i].Close(); + } +} + +bool HttpServer::CreateSocket(int32_t port) +{ + for (int32_t i = 0; i < COUNT_SOCKET; i++) { + if (!sockets_[i].CreateSocket(i == 0 ? AF_INET : AF_INET6)) { + TS_LOGE("Create http socket error"); + return false; + } + if (!sockets_[i].Bind(port)) { + TS_LOGE("bind http socket error"); + return false; + } + if (!sockets_[i].Listen(SOMAXCONN)) { + TS_LOGE("listen http socket error"); + return false; + } + } + + return true; +} + +void HttpServer::ClearDeadClientThread() +{ + for (auto it = clientThreads_.begin(); it != clientThreads_.end();) { + if (it->get()->sock_.GetFd() != -1) { + it++; + continue; + } + if (it->get()->thread_.joinable()) { + it->get()->thread_.join(); + } + it = clientThreads_.erase(it); + } +} + +#ifdef _WIN32 +void HttpServer::ProcessClient(HttpSocket& client) +{ + std::vector recvBuf(MAXLEN_REQUEST); + size_t recvLen = recvBuf.size(); + size_t recvPos = 0; + RequestST reqST; + WSAEVENT recvEvent = WSACreateEvent(); + if (recvEvent == WSA_INVALID_EVENT) { + TS_LOGE("WSACreateEvent error %d", WSAGetLastError()); + return; + } + WSAEventSelect(client.GetFd(), recvEvent, FD_READ | FD_CLOSE); + while (!isExit_) { + int32_t index = WSAWaitForMultipleEvents(1, &recvEvent, false, pollTimeOut_, false); + if (index == WSA_WAIT_FAILED) { + TS_LOGE("WSAWaitForMultipleEvents error %d", WSAGetLastError()); + break; + } else if (index == WSA_WAIT_TIMEOUT) { + if (reqST.stat != RequstParseStat::INIT) { + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + recvPos = 0; + recvLen = recvBuf.size(); + } + continue; + } + + WSANETWORKEVENTS event; + WSAEnumNetworkEvents(client.GetFd(), recvEvent, &event); + if (event.lNetworkEvents & FD_READ) { + if (event.iErrorCode[FD_READ_BIT] != 0) { + continue; + } + if (!client.Recv(recvBuf.data() + recvPos, recvLen)) { + break; + } + recvPos += recvLen; + ParseRequest(recvBuf.data(), recvPos, reqST); + recvLen = recvBuf.size() - recvPos; + if (reqST.stat == RequstParseStat::RECVING) { + continue; + } + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + } else if (event.lNetworkEvents & FD_CLOSE) { + TS_LOGI("client close socket(%d)", client.GetFd()); + break; + } + } + TS_LOGI("recive client thread exit. socket(%d)", client.GetFd()); + + client.Close(); +} +#else +void HttpServer::ProcessClient(HttpSocket& client) +{ + std::vector recvBuf(MAXLEN_REQUEST); + size_t recvLen = recvBuf.size(); + size_t recvPos = 0; + RequestST reqST; + + struct pollfd fd = {client.GetFd(), POLLIN, 0}; + while (!isExit_) { + int32_t pollRet = poll(&fd, sizeof(fd) / sizeof(pollfd), pollTimeOut_); + if (pollRet < 0) { + TS_LOGE("poll client socket(%d) error: %d:%s", client.GetFd(), errno, strerror(errno)); + break; + } + if (pollRet == 0) { + if (reqST.stat != RequstParseStat::INIT) { + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + recvPos = 0; + recvLen = recvBuf.size(); + } + continue; + } + if (!client.Recv(recvBuf.data() + recvPos, recvLen)) { + TS_LOGI("client exit"); + break; + } + recvPos += recvLen; + ParseRequest(recvBuf.data(), recvPos, reqST); + recvLen = recvBuf.size() - recvPos; + if (reqST.stat == RequstParseStat::RECVING) { + continue; + } + ProcessRequest(client, reqST); + reqST.stat = RequstParseStat::INIT; + } + TS_LOGI("recive client thread exit. socket(%d)", client.GetFd()); + + client.Close(); + TS_LOGI("thread exit"); +} +#endif + +void HttpServer::ProcessRequest(HttpSocket& client, RequestST& request) +{ + if (request.stat == RequstParseStat::RECVING) { + TS_LOGE("http request data missing, client %d\n", client.GetFd()); + HttpResponse(client, "408 Request Time-out\r\n"); + return; + } else if (request.stat != RequstParseStat::OK) { + TS_LOGE("bad http request, client %d\n", client.GetFd()); + HttpResponse(client, "400 Bad Request\r\n"); + return; + } + if (request.method == "OPTIONS") { + HttpResponse(client, + "204 No Content\r\n" + "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n" + "Access-Control-Allow-Headers: *\r\n" + "Access-Control-Max-Age: 86400\r\n"); + return; + } else if (request.method != "POST" && request.method != "GET") { + TS_LOGE("method(%s) not allowed, client %d", request.method.c_str(), client.GetFd()); + HttpResponse(client, "405 Method Not Allowed\r\n"); + return; + } + auto it = rpcFunctions_.find(request.uri); + if (it == rpcFunctions_.end()) { + TS_LOGE("http uri(%s) not found, client %d", request.uri.c_str(), client.GetFd()); + HttpResponse(client, "404 Not Found\r\n"); + return; + } + HttpResponse(client, "200 OK\r\n", true); + auto resultCallback = [&client](const std::string& result, int32_t) { + std::stringstream chunkLenbuff; + chunkLenbuff << std::hex << result.size() << "\r\n"; + if (!client.Send(chunkLenbuff.str().data(), chunkLenbuff.str().size())) { + TS_LOGE("send client socket(%d) error", client.GetFd()); + return; + } + if (!client.Send(result.data(), result.size())) { + TS_LOGE("send client socket(%d) error", client.GetFd()); + return; + } + if (!client.Send("\r\n", strlen("\r\n"))) { + TS_LOGE("send client socket(%d) error", client.GetFd()); + return; + } + }; + it->second(request.body, request.bodyLen, resultCallback); + if (!client.Send("0\r\n\r\n", strlen("0\r\n\r\n"))) { // chunk tail + TS_LOGE("send client socket(%d) error", client.GetFd()); + } +} + +void HttpServer::ParseRequest(const uint8_t* requst, size_t& len, RequestST& httpReq) +{ + std::string_view reqStr(reinterpret_cast(requst), len); + size_t bodyPos = reqStr.find("\r\n\r\n"); + if (bodyPos == 0) { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } else if (bodyPos == std::string_view::npos) { + httpReq.stat = RequstParseStat::RECVING; + return; + } + std::string_view header = reqStr.substr(0, bodyPos); + bodyPos += strlen("\r\n\r\n"); + httpReq.bodyLen = reqStr.size() - bodyPos; + + std::vector headerlines = StringSplit(header, "\r\n"); + // at least 1 line in headerlines, such as "GET /parsedata HTTP/1.1" + std::vector requestItems = StringSplit(headerlines[0], " "); + const size_t indexHttpMethod = 0; + const size_t indexHttpUri = 1; + const size_t indexHttpVersion = 2; + const size_t countRequestItems = 3; + if (requestItems.size() != countRequestItems || requestItems[indexHttpVersion] != "HTTP/1.1") { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } + httpReq.method = requestItems[indexHttpMethod]; + httpReq.uri = requestItems[indexHttpUri]; + + for (size_t i = 1; i < headerlines.size(); i++) { + size_t tagPos = headerlines[i].find(":"); + if (tagPos == std::string_view::npos) { + len = 0; + httpReq.stat = RequstParseStat::BAD; + return; + } + std::string_view tag = headerlines[i].substr(0, tagPos); + if (strncasecmp(tag.data(), "Content-Length", tag.size()) == 0) { + std::string value(headerlines[i].data() + tagPos + strlen(":"), + headerlines[i].size() - tagPos - strlen(":")); + size_t conterntLen = atoi(value.c_str()); + if (conterntLen > httpReq.bodyLen) { + httpReq.stat = RequstParseStat::RECVING; + return; + } else if (conterntLen < httpReq.bodyLen) { + httpReq.bodyLen = conterntLen; + } + } + } + + if (httpReq.bodyLen > 0) { + httpReq.body = (requst + bodyPos); + } + httpReq.stat = RequstParseStat::OK; + len -= (bodyPos + httpReq.bodyLen); + return; +} + +void HttpServer::HttpResponse(HttpSocket& client, const std::string& status, bool hasBody) +{ + std::string res; + const size_t maxLenResponse = 1024; + res.reserve(maxLenResponse); + res += "HTTP/1.1 "; + res += status; + + res += "Connection: Keep-Alive\r\n"; + if (hasBody) { + res += "Content-Type: application/json\r\n"; + res += "Transfer-Encoding: chunked\r\n"; + } + res += "\r\n"; + if (!client.Send(res.data(), res.size())) { + TS_LOGE("send client socket(%d) error", client.GetFd()); + } +} + +std::vector HttpServer::StringSplit(std::string_view source, std::string_view split) +{ + std::vector result; + if (!split.empty()) { + size_t pos = 0; + while ((pos = source.find(split)) != std::string_view::npos) { + // split + std::string_view token = source.substr(0, pos); + if (!token.empty()) { + result.push_back(token); + } + source = source.substr(pos + split.size(), source.size() - token.size() - split.size()); + } + } + // add last token + if (!source.empty()) { + result.push_back(source); + } + return result; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/rpc/http_server.h b/trace_streamer/src/rpc/http_server.h new file mode 100644 index 0000000000000000000000000000000000000000..5ff2fc12f551929c481d39283abf4c577d7ea5db --- /dev/null +++ b/trace_streamer/src/rpc/http_server.h @@ -0,0 +1,75 @@ +/* + * 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 RPC_HTTPD_H +#define RPC_HTTPD_H + +#include +#include +#include +#include +#include +#include "http_socket.h" +#include "rpc_server.h" +namespace SysTuning { +namespace TraceStreamer { +class HttpServer { +public: + void RegisterRpcFunction(RpcServer* rpc); + void Run(int32_t port = 9001); + void Exit(); + + static constexpr size_t MAXLEN_REQUEST = 2 * 1024 + 1024 * 1024; // header 2K + body 1M + +private: + struct ClientThread { + HttpSocket sock_; + std::thread thread_; + }; + + enum RequstParseStat { INIT = 0, OK, BAD, RECVING }; + + struct RequestST { + int32_t stat = RequstParseStat::INIT; + std::string method; + std::string uri; + const uint8_t* body; + size_t bodyLen; + }; + + bool CreateSocket(int32_t port); + void ProcessClient(HttpSocket& client); + void ProcessRequest(HttpSocket& client, RequestST& request); + static void HttpResponse(HttpSocket& client, const std::string& status, bool hasBody = false); + void ParseRequest(const uint8_t* requst, size_t& len, RequestST& httpReq); + void ClearDeadClientThread(); + static std::vector StringSplit(std::string_view source, std::string_view split); + + static const int32_t COUNT_SOCKET = 1; + HttpSocket sockets_[COUNT_SOCKET]; // ipv4 and ipv6 + std::atomic_bool isExit_ = {false}; + std::vector> clientThreads_; + using RpcFunction = std::function; + std::map rpcFunctions_; + const int32_t pollTimeOut_ = 1000; +#ifdef _WIN32 + const uint32_t WS_VERSION_FIRST = 2; + const uint32_t WS_VERSION_SEC = 2; +#endif +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // RPC_HTTPD_H diff --git a/trace_streamer/src/rpc/http_socket.cpp b/trace_streamer/src/rpc/http_socket.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51c327ddbea5dbcf2179ee9063ba258c9296eb38 --- /dev/null +++ b/trace_streamer/src/rpc/http_socket.cpp @@ -0,0 +1,173 @@ +/* + * 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 "http_socket.h" +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#endif +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +HttpSocket::~HttpSocket() +{ + Close(); +} +bool HttpSocket::CreateSocket(int32_t domain) +{ + SOCKET sockId = socket(domain, SOCK_STREAM, 0); + if (sockId == INVALID_SOCKET) { + TS_LOGE("CreateSocket socket error, domain %d: %d:%s", domain, errno, strerror(errno)); + return false; + } + sockId_ = sockId; + if (domain == AF_INET || domain == AF_INET6) { + int32_t enable = 1; + if (setsockopt(sockId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&enable), sizeof(enable)) == + SOCKET_ERROR) { + Close(); + return false; + } + if (domain == AF_INET6) { + if (setsockopt(sockId, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&enable), sizeof(enable)) == + SOCKET_ERROR) { + Close(); + return false; + } + } + } + domain_ = domain; + TS_LOGI("CreateSocket socket ok, socket %d domain %d", sockId_, domain); + return true; +} + +bool HttpSocket::Bind(int32_t port) +{ + if (sockId_ == INVALID_SOCKET) { + TS_LOGE("the socket not created"); + return false; + } + + if (domain_ == AF_INET) { + struct sockaddr_in addr; + std::fill(reinterpret_cast(&addr), reinterpret_cast(&addr) + sizeof(addr), 0); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htons(INADDR_ANY); + addr.sin_port = htons(static_cast(port)); + if (bind(sockId_, reinterpret_cast(&addr), sizeof(addr)) == -1) { + TS_LOGE("bind ipv4 socket error, port %d: %d:%s", port, errno, strerror(errno)); + return false; + } + } else if (domain_ == AF_INET6) { + struct sockaddr_in6 addr; + std::fill(reinterpret_cast(&addr), reinterpret_cast(&addr) + sizeof(addr), 0); + addr.sin6_family = AF_INET6; + addr.sin6_addr = in6addr_any; + addr.sin6_port = htons(static_cast(port)); + if (bind(sockId_, reinterpret_cast(&addr), sizeof(addr)) == -1) { + TS_LOGE("bind ipv6 socket error, port %d: %d:%s", port, errno, strerror(errno)); + return false; + } + } else { + return false; + } + TS_LOGI("bind socket ok, port %d", port); + return true; +} + +bool HttpSocket::Listen(int32_t maxConn) +{ + if (listen(sockId_, maxConn) == SOCKET_ERROR) { + TS_LOGE("listen socket error: %d:%s", errno, strerror(errno)); + return false; + } + TS_LOGI("listen socket ok, maxConn %d", maxConn); + return true; +} + +bool HttpSocket::Accept(HttpSocket& client) +{ + int32_t clientId = accept(sockId_, nullptr, nullptr); + if (clientId == INVALID_SOCKET) { + TS_LOGE("accept socket error: %d:%s", errno, strerror(errno)); + return false; + } + + client.domain_ = domain_; + client.sockId_ = clientId; + TS_LOGI("accept client socket id %d domain %d", clientId, domain_); + return true; +} + +bool HttpSocket::Recv(void* data, size_t& len) +{ +#ifdef _WIN32 + ssize_t recvLen = recv(sockId_, static_cast(data), len, 0); +#else + ssize_t recvLen = recv(sockId_, data, len, 0); +#endif + if (recvLen == SOCKET_ERROR) { + if (errno == EAGAIN) { + recvLen = 0; + } else { + TS_LOGE("recv from socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + return false; + } + } else if (recvLen == 0) { + TS_LOGI("client socket(%d) closed", sockId_); + return false; + } + len = recvLen; + TS_LOGD("Recv from socket(%d) len %zu", sockId_, len); + return true; +} + +bool HttpSocket::Send(const void* data, size_t len) +{ +#ifdef _WIN32 + ssize_t sendLen = send(sockId_, static_cast(data), len, 0); +#else + ssize_t sendLen = send(sockId_, data, len, 0); +#endif + if (sendLen == SOCKET_ERROR) { + TS_LOGE("send to socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + return false; + } + TS_LOGI("send to socket(%d) len %zu", sockId_, len); + return true; +} + +void HttpSocket::Close() +{ + if (sockId_ == INVALID_SOCKET) { + return; + } + TS_LOGI("close socket(%d)", sockId_); +#ifdef _WIN32 + if (closesocket(sockId_) == SOCKET_ERROR) { +#else + if (close(sockId_) == SOCKET_ERROR) { +#endif + TS_LOGE("close socket(%d) error: %d:%s", sockId_, errno, strerror(errno)); + } + sockId_ = INVALID_SOCKET; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/rpc/http_socket.h b/trace_streamer/src/rpc/http_socket.h new file mode 100644 index 0000000000000000000000000000000000000000..39bf9849c368309b90aec74919d83293acb416d0 --- /dev/null +++ b/trace_streamer/src/rpc/http_socket.h @@ -0,0 +1,53 @@ +/* + * 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 RPC_HTTPSOCKET_H +#define RPC_HTTPSOCKET_H + +#include +namespace SysTuning { +namespace TraceStreamer { +class HttpSocket { +public: + HttpSocket() {} + HttpSocket(int32_t sockId, int32_t domain) : sockId_(sockId), domain_(domain) {} + ~HttpSocket(); + + bool CreateSocket(int32_t domain); + bool Bind(int32_t port); + bool Listen(int32_t maxConn); + bool Accept(HttpSocket& client); + bool Recv(void* data, size_t& len); + bool Send(const void* data, size_t len); + void Close(); + bool IsValid() const + { + return sockId_ != INVALID_SOCKET; + } + int32_t GetFd() const + { + return sockId_; + } + +private: + int32_t sockId_ = -1; + int32_t domain_ = 0; + using SOCKET = int32_t; + const int32_t SOCKET_ERROR = -1; + const SOCKET INVALID_SOCKET = -1; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RPC_HTTPSOCKET_H diff --git a/trace_streamer/src/rpc/rpc_server.cpp b/trace_streamer/src/rpc/rpc_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72e087f4fdbb33ba68e190379cf366315625e28f --- /dev/null +++ b/trace_streamer/src/rpc/rpc_server.cpp @@ -0,0 +1,270 @@ +/* + * 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 "rpc_server.h" + +#include +#include +#include +#if IS_WASM +#include +#endif +#include "log.h" +#include "meta.h" +#include "string_help.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +namespace SysTuning { +namespace TraceStreamer { +const int32_t MAX_LEN_STR = 100; +uint32_t g_fileLen = 0; +bool RpcServer::ParseData(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + g_loadSize += len; + size_t blockSize = 1024 * 1024; + do { + size_t parseSize = std::min(len, blockSize); + std::unique_ptr buf = std::make_unique(parseSize); + std::copy(data, data + parseSize, buf.get()); + if (!ts_->ParseTraceDataSegment(std::move(buf), parseSize)) { + if (resultCallBack) { + resultCallBack("formaterror\r\n", SEND_FINISH); + } + return false; + } + data += parseSize; + len -= parseSize; + lenParseData_ += parseSize; + } while (len > 0); + if (resultCallBack) { + resultCallBack("ok\r\n", SEND_FINISH); + } + return true; +} + +int32_t RpcServer::UpdateTraceTime(const uint8_t* data, int32_t len) +{ + std::unique_ptr buf = std::make_unique(len); + std::copy(data, data + len, buf.get()); + ts_->UpdateTraceRangeTime(buf.get(), len); + return 0; +} + +int32_t RpcServer::TraceStreamer_Init_ThirdParty_Config(const uint8_t* data, int32_t len) +{ + TS_LOGE("TraceStreamer_Init_ThirdParty_Config is comming!"); + std::string thirdPartyConfig = reinterpret_cast(data); + TS_LOGE("thirdPartyConfig = %s", thirdPartyConfig.c_str()); + int32_t size = thirdPartyConfig.size(); + std::vector comPonentStr; + for (int32_t i = 0, pos = 0; i < size; i++) { + pos = thirdPartyConfig.find(";", i); + if (pos == std::string::npos) { + break; + } + if (pos < size) { + std::string s = thirdPartyConfig.substr(i, pos - i); + comPonentStr.push_back(s); + i = pos; + } + } + const int32_t EVENT_COUNT_PAIR = 2; + if (comPonentStr.size() % EVENT_COUNT_PAIR != 0) { + TS_LOGE("thirdPartyConfig is wrong!"); + return -1; + } + for (int32_t m = 0; m < comPonentStr.size(); m += EVENT_COUNT_PAIR) { + int32_t componentId = std::stoi(comPonentStr.at(m)); + std::string componentName = comPonentStr.at(m + 1); + TS_LOGE("comPonentStr[m] = %d, comPonentStr[m + 1] = %s", componentId, componentName.c_str()); + g_thirdPartyConfig.insert((std::map::value_type(componentId, componentName))); + } + return 0; +} + +bool RpcServer::ParseDataOver(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + UNUSED(data); + UNUSED(len); + MetaData* metaData = ts_->GetMetaData(); + metaData->SetSourceFileName("input stream mode"); + metaData->SetOutputFileName("wasm mode"); + metaData->SetParserToolVersion(TRACE_STREAM_VERSION); + metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION); + metaData->SetTraceDataSize(g_loadSize); + metaData->SetTraceType((ts_->DataType() == TRACE_FILETYPE_H_TRACE) ? "proto-based-trace" : "txt-based-trace"); + TS_LOGI("RPC ParseDataOver, has parsed len %zu", lenParseData_); + + ts_->WaitForParserEnd(); +#ifndef USE_VTABLE + ts_->Clear(); +#endif + if (resultCallBack) { + resultCallBack("ok\r\n", SEND_FINISH); + } + lenParseData_ = 0; + g_loadSize = 0; + return true; +} + +bool RpcServer::SqlOperate(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("RPC SqlOperate(%s, %zu)", sql.c_str(), len); + + int32_t ret = ts_->OperateDatabase(sql); + if (resultCallBack) { + std::string response = "ok\r\n"; + if (ret != 0) { + response = "dberror\r\n"; + } + resultCallBack(response, SEND_FINISH); + } + return (ret == 0); +} + +bool RpcServer::SqlQuery(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("RPC SqlQuery %zu:%s", len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, resultCallBack); + if (resultCallBack && ret != 0) { + resultCallBack("dberror\r\n", SEND_FINISH); + } + ts_->SetCancel(false); + return (ret == 0); +} + +void RpcServer::CancelSqlQuery() +{ + ts_->SetCancel(true); +} + +bool RpcServer::Reset(const uint8_t* data, size_t len, ResultCallBack resultCallBack) +{ + UNUSED(data); + UNUSED(len); + TS_LOGI("RPC reset trace_streamer"); + + ts_->WaitForParserEnd(); + ts_ = std::make_unique(); + if (resultCallBack) { + resultCallBack("ok\r\n", SEND_FINISH); + } + return true; +} + +int32_t RpcServer::WasmSqlQuery(const uint8_t* data, size_t len, uint8_t* out, int32_t outLen) +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("WASM RPC SqlQuery outlen(%d) sql(%zu:%s)", outLen, len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, out, outLen); + return ret; +} +int32_t RpcServer::WasmSqlQueryWithCallback(const uint8_t* data, size_t len, ResultCallBack callback) const +{ + ts_->SetCancel(false); + std::string sql(reinterpret_cast(data), len); + TS_LOGI("WASM RPC SqlQuery sql(%zu:%s)", len, sql.c_str()); + + int32_t ret = ts_->SearchDatabase(sql, callback); + return ret; +} + +int32_t RpcServer::WasmExportDatabase(ResultCallBack resultCallBack) +{ + return ts_->ExportDatabase("default.db", resultCallBack); +} + +#if IS_WASM +int32_t RpcServer::DownloadELFCallback(const std::string fileName, + size_t totalLen, + const uint8_t* data, + size_t len, + int32_t count, + int32_t finish, + ParseELFFileCallBack parseELFFile) +{ + g_fileLen += len; + FILE* fd; + std::string filePath = ""; + TS_LOGI("fileName = %s", fileName.c_str()); + std::string symbolsPath = fileName.substr(0, fileName.find("/")); + TS_LOGI("symbolsPath = %s", symbolsPath.c_str()); + filePath = fileName.substr(0, fileName.find_last_of("/")); + TS_LOGI("filePath = %s", filePath.c_str()); + if (std::filesystem::create_directories(filePath)) { + TS_LOGI("create_directories success"); + } + if (g_fileLen < totalLen) { + fd = fopen(fileName.c_str(), "a+"); + if (fd == nullptr) { + TS_LOGE("wasm file create failed"); + fclose(fd); + return false; + } + int32_t writeLength = fwrite(data, len, 1, fd); + if (!writeLength) { + fclose(fd); + TS_LOGE("wasm write file failed"); + return false; + } + fclose(fd); + return false; + } + g_fileLen = 0; + fd = fopen(fileName.c_str(), "a+"); + if (fd == nullptr) { + fclose(fd); + TS_LOGE("wasm file open failed"); + return false; + } + + int32_t writeLength = fwrite(data, len, 1, fd); + if (!writeLength) { + TS_LOGE("wasm write file failed"); + return false; + } + (void)fclose(fd); + TS_LOGI("symbolsPath = %s, fileName = %s", symbolsPath.c_str(), fileName.c_str()); + symbolsPathFiles_.emplace_back(fileName); + parseELFFile("file send over\r\n", SEND_FINISH); + + if (finish) { + if (!ts_->ReloadSymbolFiles(symbolsPath, symbolsPathFiles_)) { + if (parseELFFile) { + parseELFFile("formaterror\r\n", SEND_FINISH); + } + return false; + } + if (parseELFFile) { + parseELFFile("ok\r\n", SEND_FINISH); + } + std::filesystem::remove_all(filePath); + } + return true; +} +#endif + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/rpc/rpc_server.h b/trace_streamer/src/rpc/rpc_server.h new file mode 100644 index 0000000000000000000000000000000000000000..58ebd9b0c0c6098c3b2cef1029933526039d6079 --- /dev/null +++ b/trace_streamer/src/rpc/rpc_server.h @@ -0,0 +1,61 @@ +/* + * 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 RPC_RPC_H +#define RPC_RPC_H + +#include +#include +#include "trace_streamer_selector.h" +namespace SysTuning { +namespace TraceStreamer { +class RpcServer { +public: + using ResultCallBack = std::function; + using ParseELFFileCallBack = std::function; + using SendDataCallBack = std::function; + // In order to bind HTTP, maintain a unified interface, even if some parameters are useless + bool ParseData(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool ParseDataOver(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool SqlOperate(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool SqlQuery(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + bool Reset(const uint8_t* data, size_t len, ResultCallBack resultCallBack); + void CancelSqlQuery(); + + // only for wasm, no callback + int32_t WasmSqlQuery(const uint8_t* data, size_t len, uint8_t* out, int32_t outLen); + int32_t WasmSqlQueryWithCallback(const uint8_t* data, size_t len, ResultCallBack callback) const; + int32_t UpdateTraceTime(const uint8_t* data, int32_t len); + int32_t TraceStreamer_Init_ThirdParty_Config(const uint8_t* data, int32_t len); + int32_t WasmExportDatabase(ResultCallBack resultCallBack); +#if IS_WASM + int32_t DownloadELFCallback(const std::string fileName, + size_t totalLen, + const uint8_t* data, + size_t len, + int32_t count, + int32_t finish, + ParseELFFileCallBack parseELFFile); +#endif + std::map g_thirdPartyConfig; + +private: + std::unique_ptr ts_ = std::make_unique(); + size_t lenParseData_ = 0; + std::vector symbolsPathFiles_; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RPC_RPC_H diff --git a/trace_streamer/src/rpc/wasm_func.cpp b/trace_streamer/src/rpc/wasm_func.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89712a731ff444e30eaf2bb3441528657cfc66e7 --- /dev/null +++ b/trace_streamer/src/rpc/wasm_func.cpp @@ -0,0 +1,199 @@ +/* + * 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 "wasm_func.h" + +namespace SysTuning { +namespace TraceStreamer { +RpcServer g_wasmTraceStreamer; +extern "C" { +using ReplyFunction = void (*)(const char* data, uint32_t len, int32_t finish); +ReplyFunction g_reply; +uint8_t* g_reqBuf; +uint32_t g_reqBufferSize; + +using SendDataCallBack = void (*)(const char* data, int32_t len, int32_t componentId); +SendDataCallBack g_sendData = nullptr; +uint8_t* g_sendDataBuf; +uint32_t g_sendDataBufSize; + +using ExportDBCallback = void (*)(const char* data, uint32_t len, int32_t finish); +ExportDBCallback g_dbCallback; + +using ParseELFFunction = void (*)(const char* data, uint32_t len, int32_t finish); +ParseELFFunction g_parseELFCallback; +uint8_t* g_FileNameBuf; +uint32_t g_FileNameSize; + +void ResultCallback(const std::string& jsonResult, int32_t finish) +{ + g_reply(jsonResult.data(), jsonResult.size(), finish); +} + +void ParseELFCallback(const std::string& SODataResult, int32_t finish) +{ + g_parseELFCallback(SODataResult.data(), SODataResult.size(), finish); +} +EMSCRIPTEN_KEEPALIVE uint8_t* Initialize(ReplyFunction replyFunction, uint32_t reqBufferSize) +{ + g_reply = replyFunction; + g_reqBuf = new uint8_t[reqBufferSize]; + g_reqBufferSize = reqBufferSize; + return g_reqBuf; +} + +EMSCRIPTEN_KEEPALIVE uint8_t* InitFileName(ParseELFFunction parseELFCallback, uint32_t reqBufferSize) +{ + g_parseELFCallback = parseELFCallback; + if (reqBufferSize > NAME_MAX) { + return nullptr; + } + g_FileNameBuf = new uint8_t[reqBufferSize]; + if (!g_FileNameBuf) { + return nullptr; + } + g_FileNameSize = reqBufferSize; + return g_FileNameBuf; +} + +EMSCRIPTEN_KEEPALIVE int32_t UpdateTraceTime(int32_t len) +{ + return g_wasmTraceStreamer.UpdateTraceTime(g_reqBuf, len); +} + +void ThirdPary_SendDataCallback(const char* pluginData, int32_t len, int32_t componentId) +{ + if (g_sendData) { + g_sendData(pluginData, len, componentId); + } +} + +EMSCRIPTEN_KEEPALIVE uint8_t* TraceStreamer_Set_ThirdParty_DataDealer(SendDataCallBack sendDataCallBack, + uint32_t reqBufferSize) +{ + g_sendData = sendDataCallBack; + g_sendDataBuf = new uint8_t[reqBufferSize]; + g_sendDataBufSize = reqBufferSize; + return g_sendDataBuf; +} + +int32_t TraceStreamer_Plugin_Out_Filter(const char* pluginData, int32_t len, const std::string& componentName) +{ + std::map::iterator itor = g_wasmTraceStreamer.g_thirdPartyConfig.begin(); + int32_t componentId = 0; + for (; itor != g_wasmTraceStreamer.g_thirdPartyConfig.end(); ++itor) { + if (itor->second == componentName) { + componentId = itor->first; + return TraceStreamer_Plugin_Out_SendData(pluginData, len, componentId); + } + } + return -1; +} + +// Tell js to call the corresponding third-party parser interface according to the compositeId +int32_t TraceStreamer_Plugin_Out_SendData(const char* pluginData, int32_t len, int32_t componentId) +{ + ThirdPary_SendDataCallback(pluginData, len, componentId); + return 0; +} + +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamer_Init_ThirdParty_Config(int32_t dataLen) +{ + return g_wasmTraceStreamer.TraceStreamer_Init_ThirdParty_Config(g_reqBuf, dataLen); +} + +// return 0 while ok, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerParseData(const uint8_t* data, int32_t dataLen) +{ + if (g_wasmTraceStreamer.ParseData(data, dataLen, nullptr)) { + return 0; + } + return -1; +} +// return 0 while ok, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerParseDataEx(int32_t dataLen) +{ + if (g_wasmTraceStreamer.ParseData(g_reqBuf, dataLen, nullptr)) { + return 0; + } + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t + TraceStreamerDownloadELFEx(int32_t totalLen, int32_t fileNameLen, int32_t dataLen, int32_t count, int32_t finish) +{ + std::string fileName(reinterpret_cast(g_FileNameBuf), fileNameLen); +#if IS_WASM + if (g_wasmTraceStreamer.DownloadELFCallback(fileName, totalLen, g_reqBuf, dataLen, count, finish, + &ParseELFCallback)) { + return 0; + } +#endif + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerParseDataOver() +{ + if (g_wasmTraceStreamer.ParseDataOver(nullptr, 0, nullptr)) { + return 0; + } + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlOperate(const uint8_t* sql, int32_t sqlLen) +{ + if (g_wasmTraceStreamer.SqlOperate(sql, sqlLen, nullptr)) { + return 0; + } + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlOperateEx(int32_t sqlLen) +{ + if (g_wasmTraceStreamer.SqlOperate(g_reqBuf, sqlLen, nullptr)) { + return 0; + } + return -1; +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerReset() +{ + g_wasmTraceStreamer.Reset(nullptr, 0, nullptr); + return 0; +} +// return the length of result, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlQuery(const uint8_t* sql, int32_t sqlLen, uint8_t* out, int32_t outLen) +{ + return g_wasmTraceStreamer.WasmSqlQuery(sql, sqlLen, out, outLen); +} +// return the length of result, -1 while failed +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerSqlQueryEx(int32_t sqlLen) +{ + return g_wasmTraceStreamer.WasmSqlQueryWithCallback(g_reqBuf, sqlLen, &ResultCallback); +} +EMSCRIPTEN_KEEPALIVE int32_t TraceStreamerCancel() +{ + g_wasmTraceStreamer.CancelSqlQuery(); + return 0; +} + +void ExportDatabaseCallback(const std::string& jsonResult, int32_t finish) +{ + g_dbCallback(jsonResult.data(), jsonResult.size(), finish); +} + +EMSCRIPTEN_KEEPALIVE int32_t WasmExportDatabase(ExportDBCallback fun) +{ + g_dbCallback = fun; + return g_wasmTraceStreamer.WasmExportDatabase(&ExportDatabaseCallback); +} +} // extern "C" +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/rpc/wasm_func.h b/trace_streamer/src/rpc/wasm_func.h new file mode 100644 index 0000000000000000000000000000000000000000..dc4c9057676a4535071ac89691b86eb6d9c0f8b6 --- /dev/null +++ b/trace_streamer/src/rpc/wasm_func.h @@ -0,0 +1,54 @@ +/* + * 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 RPC_WASM_FUNC_H +#define RPC_WASM_FUNC_H + +#include +#ifndef IS_UT +#include +#endif +#ifdef IS_UT +#define EMSCRIPTEN_KEEPALIVE __attribute__((used)) + +#ifdef __wasm__ +#define EM_IMPORT(NAME) __attribute__((import_module("env"), import_name(#NAME))) +#else +#define EM_IMPORT(NAME) +#endif + +#endif +#include "rpc_server.h" + +namespace SysTuning { +namespace TraceStreamer { +extern "C" { +int32_t TraceStreamerParseData(const uint8_t* data, int32_t dataLen); +int32_t TraceStreamerParseDataEx(int32_t dataLen); +int32_t TraceStreamerParseDataOver(); +int32_t TraceStreamerSqlOperate(const uint8_t* sql, int32_t sqlLen); +int32_t TraceStreamerSqlOperateEx(int32_t sqlLen); +int32_t TraceStreamerReset(); +int32_t TraceStreamerSqlQuery(const uint8_t* sql, int32_t sqlLen, uint8_t* out, int32_t outLen); +int32_t TraceStreamer_Plugin_Out_SendData(const char* pluginData, int32_t len, int32_t componentId); +int32_t TraceStreamer_Plugin_Out_Filter(const char* pluginData, int32_t len, const std::string& componentName); + +int32_t TraceStreamerSqlQueryEx(int32_t sqlLen); +int32_t TraceStreamerCancel(); +} // extern "C" +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // RPC_WASM_FUNC_H diff --git a/trace_streamer/src/table/BUILD.gn b/trace_streamer/src/table/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9b7f6f438af9930926dc42a4047e4dc854499ab0 --- /dev/null +++ b/trace_streamer/src/table/BUILD.gn @@ -0,0 +1,58 @@ +# 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("//src/ts.gni") +ohos_source_set("table") { + subsystem_name = "trace_streamer" + part_name = "table" + include_dirs = [ + "//third_party/sqlite/include", + "//src/base", + "../parser", + "base", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } + deps = [ + "base:base_tables", + "ebpf:ebpf_tables", + "ftrace:ftrace_tables", + "hi_sysevent:hi_sysevent_tables", + "js_memory:js_memory_tables", + "monitor:monitor_tables", + "native_hook:native_hook_tables", + ] + if (with_perf) { + deps += [ "hiperf:hiperf_tables" ] + } +} diff --git a/trace_streamer/src/table/base/BUILD.gn b/trace_streamer/src/table/base/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a2571577b85a47866e5bfa6ee21855e100b70087 --- /dev/null +++ b/trace_streamer/src/table/base/BUILD.gn @@ -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("//src/ts.gni") +ohos_source_set("base_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "args_table.cpp", + "args_table.h", + "data_dict_table.cpp", + "data_dict_table.h", + "data_type_table.cpp", + "data_type_table.h", + "datasource_clockid_table.cpp", + "datasource_clockid_table.h", + "filter_constraints.cpp", + "filter_constraints.h", + "index_map.cpp", + "index_map.h", + "meta_table.cpp", + "meta_table.h", + "range_table.cpp", + "range_table.h", + "span_join.cpp", + "span_join.h", + "stat_table.cpp", + "stat_table.h", + "symbols_table.cpp", + "symbols_table.h", + "table_base.cpp", + "table_base.h", + "trace_config_table.cpp", + "trace_config_table.h", + ] + include_dirs = [ + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/base/args_table.cpp b/trace_streamer/src/table/base/args_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d09ac7ee4b35d73c9e824f64745649a603034480 --- /dev/null +++ b/trace_streamer/src/table/base/args_table.cpp @@ -0,0 +1,224 @@ +/* + * 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 "args_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, KEY, DATATYPE, VALUE, ARGSETID }; +ArgsTable::ArgsTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("key", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("datatype", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("argset", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ArgsTable::~ArgsTable() {} + +void ArgsTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstArgSetData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ArgsTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ArgsTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr ArgsTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ArgsTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstArgSetData().Size())), + argSet_(dataCache->GetConstArgSetData()) +{ +} + +ArgsTable::Cursor::~Cursor() {} + +int32_t ArgsTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ArgsTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, CurrentRow()); // IdsData() will be optimized + break; + case KEY: + sqlite3_result_int64(context_, static_cast(argSet_.NamesData()[CurrentRow()])); + break; + case DATATYPE: + sqlite3_result_int64(context_, static_cast(argSet_.DataTypes()[CurrentRow()])); + break; + case VALUE: + sqlite3_result_int64(context_, static_cast(argSet_.ValuesData()[CurrentRow()])); + break; + case ARGSETID: + sqlite3_result_int64(context_, static_cast(argSet_.ArgsData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +void ArgsTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/args_table.h b/trace_streamer/src/table/base/args_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6e9ae79955b489e7f33722570b470bb1ecc32667 --- /dev/null +++ b/trace_streamer/src/table/base/args_table.h @@ -0,0 +1,53 @@ +/* + * 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 ARGS_TABLE_H +#define ARGS_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ArgsTable : public TableBase { +public: + enum Column { ID = 0, TYPE = 1, NAME = 2, ARG_ID = 3 }; + explicit ArgsTable(const TraceDataCache* dataCache); + ~ArgsTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + void FilterId(unsigned char op, sqlite3_value* argv) override; + + private: + const ArgSet& argSet_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // ARGS_TABLE_H diff --git a/trace_streamer/src/table/base/data_dict_table.cpp b/trace_streamer/src/table/base/data_dict_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36e5426c78d60d8a03f407fd828037041df1bcdb --- /dev/null +++ b/trace_streamer/src/table/base/data_dict_table.cpp @@ -0,0 +1,179 @@ +/* + * 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 "data_dict_table.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, STR }; +DataDictTable::DataDictTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("data", "TEXT")); + tablePriKey_.push_back("id"); +} + +DataDictTable::~DataDictTable() {} + +void DataDictTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->DataDictSize(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void DataDictTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool DataDictTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr DataDictTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +DataDictTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->DataDictSize())) +{ +} + +DataDictTable::Cursor::~Cursor() {} + +int32_t DataDictTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t DataDictTable::Cursor::Column(int32_t col) const +{ + DataIndex index = static_cast(CurrentRow()); + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case STR: + sqlite3_result_text(context_, dataCache_->GetDataFromDict(index).c_str(), STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unknown column %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/data_dict_table.h b/trace_streamer/src/table/base/data_dict_table.h new file mode 100644 index 0000000000000000000000000000000000000000..0ec1e9798ce54e646df3fecc8fa70148383f5d24 --- /dev/null +++ b/trace_streamer/src/table/base/data_dict_table.h @@ -0,0 +1,46 @@ +/* + * 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 DATA_DICT_TABLE_H +#define DATA_DICT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class DataDictTable : public TableBase { +public: + explicit DataDictTable(const TraceDataCache* dataCache); + ~DataDictTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // DATA_DICT_TABLE_H diff --git a/trace_streamer/src/table/base/data_type_table.cpp b/trace_streamer/src/table/base/data_type_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..483b8bc9b30d03940526e9c23700f6b16f6724b7 --- /dev/null +++ b/trace_streamer/src/table/base/data_type_table.cpp @@ -0,0 +1,184 @@ +/* + * 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 "data_type_table.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPEID, DESC }; +DataTypeTable::DataTypeTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("typeId", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("desc", "TEXT")); + tablePriKey_.push_back("id"); +} + +DataTypeTable::~DataTypeTable() {} + +void DataTypeTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstDataTypeData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void DataTypeTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool DataTypeTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr DataTypeTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +DataTypeTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstDataTypeData().Size())), + dataTypeObj_(dataCache->GetConstDataTypeData()) +{ +} + +DataTypeTable::Cursor::~Cursor() {} + +int32_t DataTypeTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t DataTypeTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TYPEID: + sqlite3_result_int64(context_, static_cast(dataTypeObj_.DataTypes()[CurrentRow()])); + break; + case DESC: + sqlite3_result_text(context_, dataCache_->GetDataFromDict(dataTypeObj_.DataDesc()[CurrentRow()]).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unknown column %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/data_type_table.h b/trace_streamer/src/table/base/data_type_table.h new file mode 100644 index 0000000000000000000000000000000000000000..56b62825e55925ffaf0bd8ad55cb6f58ca235046 --- /dev/null +++ b/trace_streamer/src/table/base/data_type_table.h @@ -0,0 +1,49 @@ +/* + * 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 DATA_TYPE_TABLE_H +#define DATA_TYPE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class DataTypeTable : public TableBase { +public: + explicit DataTypeTable(const TraceDataCache*); + ~DataTypeTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + private: + const DataType& dataTypeObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // DATA_TYPE_TABLE_H diff --git a/trace_streamer/src/table/base/datasource_clockid_table.cpp b/trace_streamer/src/table/base/datasource_clockid_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..196a638c74ac655e214d63e9d4e876947b40941b --- /dev/null +++ b/trace_streamer/src/table/base/datasource_clockid_table.cpp @@ -0,0 +1,65 @@ +/* + * 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 "datasource_clockid_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, NAME, CLOCK_ID }; +DataSourceClockIdTableTable::DataSourceClockIdTableTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("data_source_name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("clock_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +DataSourceClockIdTableTable::~DataSourceClockIdTableTable() {} + +std::unique_ptr DataSourceClockIdTableTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +DataSourceClockIdTableTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstDataSourceClockIdData().Size())), + dataSourceClockIdData_(dataCache->GetConstDataSourceClockIdData()) +{ +} + +DataSourceClockIdTableTable::Cursor::~Cursor() {} + +int32_t DataSourceClockIdTableTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, CurrentRow()); + break; + case NAME: + sqlite3_result_text(context_, dataSourceClockIdData_.Names()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + break; + case CLOCK_ID: + sqlite3_result_int(context_, static_cast(dataSourceClockIdData_.ClockIds()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/datasource_clockid_table.h b/trace_streamer/src/table/base/datasource_clockid_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6ad1597e05b2007e93a1e64c265374b12cabd94f --- /dev/null +++ b/trace_streamer/src/table/base/datasource_clockid_table.h @@ -0,0 +1,49 @@ +/* + * 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 DATASOURCE_CLOCKID_TABLE_H +#define DATASOURCE_CLOCKID_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" +namespace SysTuning { +namespace TraceStreamer { +class DataSourceClockIdTableTable : public TableBase { +public: + explicit DataSourceClockIdTableTable(const TraceDataCache* dataCache); + ~DataSourceClockIdTableTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t column) const override; + + private: + const DataSourceClockIdData& dataSourceClockIdData_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // DATASOURCE_CLOCKID_TABLE_H diff --git a/trace_streamer/src/table/base/filter_constraints.cpp b/trace_streamer/src/table/base/filter_constraints.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd79bce8c5f922d97914e2549f6b37ff7400cfb8 --- /dev/null +++ b/trace_streamer/src/table/base/filter_constraints.cpp @@ -0,0 +1,132 @@ +/* + * 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 "filter_constraints.h" + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +void FilterConstraints::AddConstraint(int32_t idx, int32_t col, unsigned char op, bool isSupport) +{ + Constraint& c = constraints_.emplace_back(); + c.idxInaConstraint = idx; + c.col = col; + c.op = op; + c.isSupport = isSupport; +} + +void FilterConstraints::UpdateConstraint(int32_t idx, bool isSupport) +{ + if (idx >= 0 && static_cast(idx) < constraints_.size()) { + constraints_[idx].isSupport = isSupport; + } +} + +void FilterConstraints::AddOrderBy(int32_t col, unsigned char desc) +{ + OrderBy& o = orderBys_.emplace_back(); + o.iColumn = col; + o.desc = desc; +} + +void FilterConstraints::Clear() +{ + constraints_.clear(); + orderBys_.clear(); +} + +void FilterConstraints::ToString(std::string& idxStr) const +{ + idxStr.clear(); + idxStr.reserve(idxStrSize_); + idxStr = "C" + std::to_string(constraints_.size()); + for (size_t i = 0; i < constraints_.size(); i++) { + idxStr += " " + std::to_string(constraints_[i].col); + idxStr += " " + std::to_string(constraints_[i].op); + } + idxStr += " O" + std::to_string(orderBys_.size()); + for (size_t i = 0; i < orderBys_.size(); i++) { + idxStr += " " + std::to_string(orderBys_[i].iColumn); + idxStr += " " + std::to_string(orderBys_[i].desc); + } +} + +void FilterConstraints::FromString(const std::string& idxStr) +{ + const char* p = static_cast(idxStr.c_str()); + char* pNext = nullptr; + TS_ASSERT(*p == 'C'); + errno = 0; + int32_t constraintCount = static_cast(strtol(p + 1, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + for (int32_t i = 0; i < constraintCount; i++) { + p = pNext; + errno = 0; + int32_t col = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + p = pNext; + errno = 0; + unsigned char op = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + + AddConstraint(i, col, op); + } + + pNext++; // jump the ' ' + p = pNext; + TS_ASSERT(*p == 'O'); + errno = 0; + int32_t orderbyCount = static_cast(strtol(p + 1, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + for (int32_t i = 0; i < orderbyCount; i++) { + p = pNext; + errno = 0; + int32_t col = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + p = pNext; + errno = 0; + unsigned char desc = static_cast(strtol(p, &pNext, 10)); + if (errno != 0) { + TS_LOGW("strtol failed!"); + return; + } + TS_ASSERT(p != pNext); + + AddOrderBy(col, desc); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/filter_constraints.h b/trace_streamer/src/table/base/filter_constraints.h new file mode 100644 index 0000000000000000000000000000000000000000..19cdd1372e1a084af3d680147bf7c426462f6bf6 --- /dev/null +++ b/trace_streamer/src/table/base/filter_constraints.h @@ -0,0 +1,65 @@ +/* + * 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 TABLE_FILTER_CONSTRAINTS_H +#define TABLE_FILTER_CONSTRAINTS_H + +#include +#include +#include "sqlite3.h" + +namespace SysTuning { +namespace TraceStreamer { +class FilterConstraints { +public: + struct Constraint { + int32_t idxInaConstraint; // index in sqlite3_index_info.aConstraint[] + int32_t col; // Column this constraint refers to + unsigned char op; // SQLite op for the constraint + bool isSupport = false; + }; + using OrderBy = sqlite3_index_info::sqlite3_index_orderby; + + FilterConstraints() {} + ~FilterConstraints() {} + void AddConstraint(int32_t idx, int32_t col, unsigned char op, bool isSupport = false); + void UpdateConstraint(int32_t idx, bool isSupport); + void AddOrderBy(int32_t col, unsigned char desc); + void Clear(); + + const std::vector& GetOrderBys() const + { + return orderBys_; + } + + const std::vector& GetConstraints() const + { + return constraints_; + } + + // idxStr format: C col1 op1 ... colN opN O col1 desc1 ... colM descM + // like as "C2 0 2 1 4 O1 0 1" + void ToString(std::string& idxStr) const; + void FromString(const std::string& idxStr); + +private: + std::vector constraints_; + std::vector orderBys_; + const std::size_t idxStrSize_ = 512; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_FILTER_CONSTRAINTS_H diff --git a/trace_streamer/src/table/base/index_map.cpp b/trace_streamer/src/table/base/index_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dff042838a8cf20edf10b5c27fd71f0404db8c92 --- /dev/null +++ b/trace_streamer/src/table/base/index_map.cpp @@ -0,0 +1,271 @@ +/* + * 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 "index_map.h" + +#include + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +IndexMap::IndexMap(TableRowId start, TableRowId end) : end_(end), current_(start), start_(start), type_(COMPACT) {} + +void IndexMap::CovertToIndexMap() +{ + if (converted_) { + indexType_ = INDEX_TYPE_OUTER_INDEX; + return; + } + converted_ = true; + if (indexType_ == INDEX_TYPE_ID && HasData()) { + for (auto i = start_; i < end_; i++) { + rowIndex_.push_back(i); + } + current_ = start_ = 0; + end_ = rowIndex_.size(); + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + empty_ = false; +} + +void IndexMap::Print() +{ + for (auto itor = rowIndex_.begin(); itor != rowIndex_.end(); itor++) { + fprintf(stdout, "%d,", *itor); + } + fflush(stdout); +} +void IndexMap::Sort() {} + +void IndexMap::Init() +{ + intersectEable_ = HasData(); +} +bool IndexMap::HasData() +{ + return !empty_; +} +void IndexMap::Intersect(TableRowId start, TableRowId end) +{ + if (indexType_ == INDEX_TYPE_OUTER_INDEX) { + bool changed = false; + rowIndexBak_.clear(); + for (auto i = rowIndex_.begin(); i != rowIndex_.end(); i++) { + if (*i >= start && *i < end) { + changed = true; + rowIndexBak_.push_back(*i); + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + start_ = current_ = 0; + end_ = rowIndex_.size(); + } else { + start_ = std::max(start_, start); + end_ = std::min(end_, end); + current_ = start_; + } + empty_ = false; +} + +size_t IndexMap::Size() const +{ + return end_ - start_; +} + +void IndexMap::Next() +{ + if (desc_) { + if (current_ > start_ - 1) { + if (current_ == 0) { + current_ = 0; + } + current_--; + } + } else { + if (current_ < end_) { + current_++; + } + } +} +void IndexMap::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + Intersect(0, 0); + return; + } + if (HasData()) { + CovertToIndexMap(); + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + Intersect(v, end_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + Intersect(v, end_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} + +void IndexMap::FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times) +{ + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint64_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + IntersectabcEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + IntersectGreaterEqual(times, v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + IntersectLessEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: { + RemoveNullElements(times, v); + break; + } + default: + break; + } // end of switch (op) + } +} +void IndexMap::Merge(IndexMap* other) +{ + if (indexType_ == INDEX_TYPE_ID && other->indexType_ == INDEX_TYPE_ID) { + if ((other->start_ >= start_ && other->start_ <= end_) || (start_ >= other->start_ && start_ <= other->end_)) { + start_ = std::min(start_, other->start_); + end_ = std::max(end_, other->end_); + } else if (start_ > other->start_) { + this->CovertToIndexMap(); + other->CovertToIndexMap(); + const std::vector b = other->rowIndex_; + uint32_t bIndex = 0; + uint32_t bSize = b.size(); + while (bIndex != bSize) { + rowIndex_.push_back(b[bIndex]); + } + start_ = current_ = 0; + end_ = rowIndex_.size(); + } else { + this->CovertToIndexMap(); + other->CovertToIndexMap(); + std::vector c = other->rowIndex_; + uint32_t aIndex = 0; + uint32_t aSize = rowIndex_.size(); + while (aIndex != aSize) { + c.push_back(rowIndex_[aIndex]); + } + start_ = current_ = 0; + end_ = rowIndex_.size(); + } + return; + } + this->CovertToIndexMap(); + other->CovertToIndexMap(); + const std::vector b = other->rowIndex_; + const std::vector& a = rowIndex_; + std::vector c; + uint32_t aIndex = 0; + uint32_t aSize = a.size(); + uint32_t bIndex = 0; + uint32_t bSize = b.size(); + while (aIndex != aSize || bIndex != bSize) { + if (aIndex == aSize) { + while (bIndex != bSize) { + c.push_back(b[bIndex]); + bIndex++; + } + break; + } + if (bIndex == bSize) { + while (aIndex != aSize) { + c.push_back(a[aIndex]); + bIndex++; + } + break; + } + if (a[aIndex] < b[bIndex]) { + c.push_back(a[aIndex]); + aIndex++; + } else if (a[aIndex] == b[bIndex]) { + c.push_back(a[aIndex]); + aIndex++; + bIndex++; + } else { + c.push_back(b[bIndex]); + bIndex++; + } + } + rowIndex_ = c; + start_ = current_ = 0; + end_ = rowIndex_.size(); +} + +bool IndexMap::Eof() const +{ + if (desc_) { + return current_ <= start_ - 1; + } else { + return current_ >= end_; + } +} + +TableRowId IndexMap::CurrentRow() const +{ + auto current = current_; + if (indexType_ == INDEX_TYPE_ID) { + return current; + } else { + return rowIndex_[current]; + } +} + +void IndexMap::SortBy(bool desc) +{ + if (desc) { + current_ = end_ - 1; + } else { + current_ = start_; + } + desc_ = desc; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/index_map.h b/trace_streamer/src/table/base/index_map.h new file mode 100644 index 0000000000000000000000000000000000000000..1433ef2c31c1ae67246346cae0724a775a4bfcf6 --- /dev/null +++ b/trace_streamer/src/table/base/index_map.h @@ -0,0 +1,371 @@ +/* + * 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 TABLE_INDEX_MAP_H +#define TABLE_INDEX_MAP_H + +#include +#include +#include +#include +#include "sqlite3.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStreamer { +class IndexMap { +public: + IndexMap() {} + ~IndexMap() {} + + IndexMap(TableRowId start, TableRowId end); + void CovertToIndexMap(); + void Sort(); + void Print(); + void Init(); + void Merge(IndexMap* other); + void FilterId(unsigned char op, sqlite3_value* argv); + void FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times); + template + void MixRange(unsigned char op, T value, const std::deque& dataQueue) + { + filters_++; + auto invalidValue = std::numeric_limits::max(); + bool remove = false; + if (HasData()) { + CovertToIndexMap(); + remove = true; + } + auto size = dataQueue.size(); + rowIndexBak_.clear(); + bool changed = false; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] != value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] == value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_NE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] == value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] != value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNULL: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] != invalidValue) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] == invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] == invalidValue) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] != invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] <= value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] > value) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] < value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] >= invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] > value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] < invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (dataQueue[*i] >= value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (dataQueue[i] < invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + break; + + default: + break; + } // end of switch (op) + empty_ = false; + } + void FixSize() + { + if (indexType_ == INDEX_TYPE_OUTER_INDEX) { + end_ = rowIndex_.size(); + current_ = 0; + } + } + void Remove(TableRowId row) + { + (void)std::remove(rowIndex_.begin(), rowIndex_.end(), row); + } + void Set(TableRowId start, TableRowId end) + { + if (indexType_ == INDEX_TYPE_ID) { + end_ = std::min(end_, end); + current_ = start_ = std::max(start_, start); + } + } + + size_t Size() const; + + void Next(); + + bool Eof() const; + + TableRowId CurrentRow() const; + + void SortBy(bool desc); + void Intersect(TableRowId start, TableRowId end); + + // the follow functions require that thecolData is sotred + template + void IntersectabcEqual(const std::deque& rows, Val v, GetV getValue) + { + auto start = std::lower_bound(rows.begin() + start_, rows.begin() + end_, v); + auto end = std::upper_bound(start, rows.begin() + end_, v); + auto newStart = std::distance(rows.begin(), start); + auto newEnd = std::distance(rows.begin(), end); + Intersect(newStart, newEnd); + return; + } + + template + void IntersectGreaterEqual(const std::deque& rows, Val v, GetV getValue) + { + auto start = std::lower_bound(rows.begin() + start_, rows.begin() + end_, v, + [&](const Row& row, const Val& v) { return v > getValue(row); }); + auto newStart = std::distance(rows.begin(), start); + Intersect(newStart, INVALID_INT32); + return; + } + + template + void IntersectLessEqual(const std::deque& rows, Val v, GetV getValue) + { + auto end = std::upper_bound(rows.begin() + start_, rows.begin() + end_, v, + [&](const Row& row, const Val& v) { return v > getValue(row); }); + auto newEnd = std::distance(rows.begin(), end); + Intersect(0, newEnd); + return; + } + template + void RemoveNullElements(const std::deque& rows, T v) + { + auto invalidValue = std::numeric_limits::max(); + bool remove = false; + if (HasData()) { + CovertToIndexMap(); + remove = true; + } + + if (remove) { + for (auto i = rowIndex_.begin(); i != rowIndex_.end();) { + if (rows[*i] == invalidValue) { + i = rowIndex_.erase(i); + } else { + i++; + } + } + } else { + auto size = rows.size(); + for (auto i = 0; i < size; i++) { + if (rows[i] != invalidValue) { + rowIndex_.push_back(i); + } + } + } + indexType_ = INDEX_TYPE_OUTER_INDEX; + FixSize(); + return; + } + bool HasData(); + std::vector rowIndex_ = {}; + std::vector rowIndexBak_ = {}; + +private: + TableRowId end_ = INVALID_INT32; + TableRowId current_ = 0; + TableRowId start_ = 0; + enum FindIndexType { + INDEX_TYPE_ID, + INDEX_TYPE_OUTER_INDEX, + }; + FindIndexType indexType_ = INDEX_TYPE_ID; + uint32_t indexSize_ = 0; + uint32_t index_ = 0; + + enum IndexType { COMPACT, SPARSE }; + uint8_t type_ = COMPACT; + bool empty_ = true; + bool desc_ = false; + bool converted_ = false; + uint8_t filters_ = 0; + bool intersectEable_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_INDEX_MAP_H diff --git a/trace_streamer/src/table/base/meta_table.cpp b/trace_streamer/src/table/base/meta_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64a48510befcb6c9923529f4b79a8a34345f918b --- /dev/null +++ b/trace_streamer/src/table/base/meta_table.cpp @@ -0,0 +1,60 @@ +/* + * 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 "meta_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { NAMEINDEX = 0, VALUE }; +MetaTable::MetaTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "TEXT")); + tablePriKey_.push_back("name"); +} + +MetaTable::~MetaTable() {} + +std::unique_ptr MetaTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +MetaTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, METADATA_ITEM_MAX) +{ +} + +MetaTable::Cursor::~Cursor() {} + +int32_t MetaTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case NAMEINDEX: + sqlite3_result_text(context_, dataCache_->GetConstMetaData().Name(CurrentRow()).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + case VALUE: + sqlite3_result_text(context_, dataCache_->GetConstMetaData().Value(CurrentRow()).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/meta_table.h b/trace_streamer/src/table/base/meta_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6269067d1742020d3e4fb82adbf5fdfc42c651c5 --- /dev/null +++ b/trace_streamer/src/table/base/meta_table.h @@ -0,0 +1,49 @@ +/* + * 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 META_TABLE_H +#define META_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class MetaTable : public TableBase { +public: + explicit MetaTable(const TraceDataCache* dataCache); + ~MetaTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // META_TABLE_H diff --git a/trace_streamer/src/table/base/range_table.cpp b/trace_streamer/src/table/base/range_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53476ad50efd794822f40bd96cbb68419e2f7dfd --- /dev/null +++ b/trace_streamer/src/table/base/range_table.cpp @@ -0,0 +1,57 @@ +/* + * 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 "range_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { START_TS = 0, END_TS }; +RangeTable::RangeTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tablePriKey_.push_back("start_ts"); +} + +RangeTable::~RangeTable() {} + +std::unique_ptr RangeTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +RangeTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) : TableBase::Cursor(dataCache, table, 1) +{ +} + +RangeTable::Cursor::~Cursor() {} + +int32_t RangeTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case START_TS: + sqlite3_result_int64(context_, static_cast(dataCache_->TraceStartTime())); + break; + case END_TS: + sqlite3_result_int64(context_, static_cast(dataCache_->TraceEndTime())); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/range_table.h b/trace_streamer/src/table/base/range_table.h new file mode 100644 index 0000000000000000000000000000000000000000..8538ca3eaa26427dd2ab5ae93a13921a4dc48178 --- /dev/null +++ b/trace_streamer/src/table/base/range_table.h @@ -0,0 +1,49 @@ +/* + * 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 RANGE_TABLE_H +#define RANGE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class RangeTable : public TableBase { +public: + explicit RangeTable(const TraceDataCache* dataCache); + ~RangeTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RANGE_TABLE_H diff --git a/trace_streamer/src/table/base/span_join.cpp b/trace_streamer/src/table/base/span_join.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c7fa738bb23d98caae88cdda570bd67289c94d0 --- /dev/null +++ b/trace_streamer/src/table/base/span_join.cpp @@ -0,0 +1,451 @@ +/* + * 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 "span_join.h" +#include + +namespace SysTuning { +namespace TraceStreamer { + +const std::string TS_COLUMN_NAME = "ts"; +const std::string DUR_COLUMN_NAME = "dur"; +constexpr int32_t MINSIZE = 5; +constexpr int32_t MAXSIZE = 1024; +constexpr int32_t NEXT_NUMBER = 1; +constexpr int32_t TSANDDUR_COLUMN = 2; +constexpr int32_t PARTITIONED_COUNT = 3; + +enum Index { TS, DUR, PARTITION }; + +SpanJoin::SpanJoin(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_ = {}; + tablePriKey_ = {}; +} + +void SpanJoin::Init(int32_t argc, const char* const* argv) +{ + if (argc < MINSIZE) { + return; + } + // Parse the fields of the two tables separately + TableParse tableFirstParse; + Parse(std::string(reinterpret_cast(argv[3])), tableFirstParse); + TableParse tableSecondParse; + Parse(std::string(reinterpret_cast(argv[4])), tableSecondParse); + + // you must ensure that the two partitions exist and are the same when using + if (tableFirstDesc_.partition != tableSecondDesc_.partition) { + return; + } + isSamepartitioning_ = true; + GetTableField(tableFirstParse, tableFirstDesc_); + GetTableField(tableSecondParse, tableSecondDesc_); + tableColumn_.emplace_back(TS_COLUMN_NAME, "INTEGER"); + tableColumn_.emplace_back(DUR_COLUMN_NAME, "INTEGER"); + tableColumn_.emplace_back(tableFirstDesc_.partition, "INTEGER"); + CreateCols(tableFirstDesc_, tableColumn_); + CreateCols(tableSecondDesc_, tableColumn_); + std::vector primaryKeys = {"ts"}; + primaryKeys.push_back(tableFirstDesc_.partition); + tablePriKey_ = primaryKeys; + return; +} + +void SpanJoin::CreateCols(TableDesc& tableDesc, std::vector& cols) +{ + for (int32_t i = 0; i < tableDesc.cols.size(); i++) { + auto& n = tableDesc.cols.at(i).name_; + if (IsTsOrDurCol(n)) { + continue; + } + auto columnInfo = &mTableColumnInfo_[cols.size()]; + columnInfo->tableDesc = &tableDesc; + columnInfo->colIdx = i; + if (!DeduplicationForColumn(n, cols)) { + continue; + } + cols.emplace_back(n, tableDesc.cols.at(i).type_); + } +} + +bool SpanJoin::DeduplicationForColumn(const std::string& name, std::vector& cols) +{ + for (size_t i = 0; i < cols.size(); i++) { + if (name == cols.at(i).name_) { + return false; + } + } + return true; +} + +std::vector SpanJoin::TableNameSplitToVec(std::string& str, const std::string& pat) +{ + std::string::size_type pos; + std::vector result; + str += pat; + int32_t size = str.size(); + for (int32_t i = 0; i < size; i++) { + pos = str.find(pat, i); + if (pos == std::string::npos) { + break; + } + if (pos < size) { + std::string s = str.substr(i, pos - i); + result.push_back(s); + i = pos + pat.size() - 1; + } + } + return result; +} + +void SpanJoin::Parse(const std::string& tablePartition, TableParse& tableParse) +{ + std::vector result = TableNameSplitToVec(const_cast(tablePartition), " "); + if (result.size() < PARTITIONED_COUNT) { + TS_LOGW("span_join sql is invalid!"); + } + tableParse.name = result.at(0); + if (0 != strcasecmp(result.at(1).c_str(), "PARTITIONED")) { + TS_LOGW("sql has not PARTITIONED"); + return; + } + tableParse.partitionCol = result.at(2); + return; +} + +bool SpanJoin::IsTsOrDurCol(const std::string& name) +{ + if (name == TS_COLUMN_NAME || name == DUR_COLUMN_NAME) { + return true; + } + return false; +} + +void SpanJoin::GetTableField(TableParse& tableParse, TableDesc& tableDesc) +{ + std::vector cols; + GetColumns(dataCache_, tableParse.name, cols); + int32_t tsDurCount = 0; + for (int32_t i = 0; i < cols.size(); i++) { + auto col = cols.at(i); + if (IsTsOrDurCol(col.name_)) { + tsDurCount++; + } + if (col.name_ == TS_COLUMN_NAME) { + tableDesc.tsIdx = i; + } else if (col.name_ == DUR_COLUMN_NAME) { + tableDesc.durIdx = i; + } else if (col.name_ == tableParse.partitionCol) { + tableDesc.partitionIdx = i; + } + } + if (tsDurCount != TSANDDUR_COLUMN) { + return; + } + tableDesc.name = tableParse.name; + tableDesc.partition = tableParse.partitionCol; + tableDesc.cols = std::move(cols); + return; +} + +void SpanJoin::GetColumns(const TraceDataCache* dataCache, + const std::string& tableName, + std::vector& columns) +{ + char sql[MAXSIZE]; + std::string querySql = "SELECT name, type from PRAGMA_table_info(\"%s\")"; + int32_t n = snprintf(sql, sizeof(sql), querySql.c_str(), tableName.c_str()); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(dataCache->db_, sql, n, &stmt, nullptr); + while (!ret) { + int32_t err = sqlite3_step(stmt); + if (err == SQLITE_ROW) { + columns.emplace_back((reinterpret_cast(sqlite3_column_text(stmt, 0))), + reinterpret_cast(sqlite3_column_text(stmt, 1))); + continue; + } + if (err == SQLITE_DONE) { + break; + } + ret = err; + } + return; +} + +SpanJoin::CaclSpan::CaclSpan(TableBase* tableBase, const TableDesc* tableDesc, sqlite3* db) + : desc_(tableDesc), db_(db), table_(reinterpret_cast(tableBase)) +{ +} + +SpanJoin::CaclSpan::~CaclSpan() = default; + +int32_t SpanJoin::CaclSpan::InitQuerySql(sqlite3_value** argv) +{ + sqlQuery_ = GetSqlQuery(); + bool status = IsQueryNext(); + if (!status) { + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +std::string SpanJoin::CaclSpan::GetSqlQuery() +{ + std::vector columnNames; + for (int32_t i = 0; i < desc_->cols.size(); i++) { + columnNames.push_back(desc_->cols.at(i).name_); + } + std::string str; + str = GetMergeColumns(columnNames); + std::string sql = "SELECT " + str + " FROM " + desc_->name + " ORDER BY " + desc_->partition + ", " + "ts;"; + return sql; +} + +void SpanJoin::CaclSpan::setResult(sqlite3_context* context, size_t index) const +{ + if (partitionState_ != PartitionState::TS_REAL) { + sqlite3_result_null(context); + return; + } + int32_t sqliteType = sqlite3_column_type(stmt_, index); + if (sqliteType == SQLITE_TEXT) { + sqlite3_result_text(context, reinterpret_cast(sqlite3_column_int64(stmt_, index)), -1, + reinterpret_cast(-1)); + } else if (sqliteType == SQLITE_INTEGER) { + sqlite3_result_int64(context, sqlite3_column_int64(stmt_, index)); + } else if (sqliteType == SQLITE_FLOAT) { + sqlite3_result_double(context, sqlite3_column_double(stmt_, index)); + } +} + +bool SpanJoin::CaclSpan::GetCursorNext() +{ + int32_t res; + int32_t rowType; + do { + res = sqlite3_step(stmt_); + rowType = sqlite3_column_type(stmt_, desc_->partitionIdx); + } while (res == SQLITE_ROW && rowType == SQLITE_NULL); + if (res != SQLITE_ROW) { + isEof_ = true; + } else { + isEof_ = false; + } + + return res == SQLITE_ROW || res == SQLITE_DONE; +} + +void SpanJoin::CaclSpan::Next() +{ + GetNextState(); + SearchNextslice(); +} + +bool SpanJoin::CaclSpan::IsQueryNext() +{ + int32_t res = sqlite3_prepare_v2(db_, sqlQuery_.c_str(), static_cast(sqlQuery_.size()), &stmt_, nullptr); + isEof_ = res != SQLITE_OK; + if (res != SQLITE_OK) { + return true; + } + auto status = GetCursorNext(); + if (!status) { + return false; + } + missPartitionEnd_ = sqlite3_column_int64(stmt_, static_cast(desc_->partitionIdx)); + status = SearchNextslice(); + return status; +} + +bool SpanJoin::CaclSpan::SearchNextslice() +{ + while (partitionState_ != TS_REAL) { + bool status = GetNextState(); + if (!status) { + return false; + } + } + return true; +} + +bool SpanJoin::CaclSpan::GetNextState() +{ + switch (partitionState_) { + case PartitionState::TS_REAL: { + GetCursorNext(); + partitionState_ = PartitionState::TS_PARTITION; + ts_ = endTs_; + if (isEof_ || partition_ != sqlite3_column_int64(stmt_, static_cast(desc_->partitionIdx))) { + endTs_ = std::numeric_limits::max(); + } else { + endTs_ = sqlite3_column_int64(stmt_, static_cast(desc_->tsIdx)); + } + return true; + } + case PartitionState::TS_PARTITION: { + if (endTs_ == std::numeric_limits::max()) { + partitionState_ = PartitionState::TS_MISSING; + if (isEof_) { + missPartitionEnd_ = std::numeric_limits::max(); + } else { + missPartitionEnd_ = sqlite3_column_int64(stmt_, static_cast(desc_->partitionIdx)); + } + missPartitionStart_ = partition_ + NEXT_NUMBER; + ts_ = 0; + } else { + partitionState_ = PartitionState::TS_REAL; + ts_ = sqlite3_column_int64(stmt_, static_cast(desc_->tsIdx)); + endTs_ = ts_ + sqlite3_column_int64(stmt_, static_cast(desc_->durIdx)); + } + return true; + } + case PartitionState::TS_MISSING: { + if (missPartitionEnd_ == std::numeric_limits::max()) { + partitionState_ = PartitionState::TS_EOF; + } else { + partitionState_ = PartitionState::TS_PARTITION; + ts_ = 0; + endTs_ = sqlite3_column_int64(stmt_, static_cast(desc_->tsIdx)); + partition_ = missPartitionEnd_; + } + return true; + } + default: + return false; + } +} + +std::string SpanJoin::CaclSpan::GetMergeColumns(std::vector& columns) +{ + std::string str; + int32_t size = columns.size(); + for (int32_t i = 0; i < size; i++) { + if (i == size - 1) { + str += columns.at(i); + } else { + str += columns.at(i) + ", "; + } + } + return str; +} + +int64_t SpanJoin::CaclSpan::GetPatitonForMiss() +{ + return partitionState_ == TS_MISSING ? missPartitionEnd_ - NEXT_NUMBER : partition_; +} + +std::unique_ptr SpanJoin::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SpanJoin::Cursor::Cursor(const TraceDataCache* dataCache, SpanJoin* table) + : TableBase::Cursor(dataCache, table, 0), + tableFirst_(table, &table->tableFirstDesc_, dataCache_->db_), + tableSecond_(table, &table->tableSecondDesc_, dataCache_->db_), + spanTable_(table) +{ +} + +int32_t SpanJoin::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + tableFirst_.InitQuerySql(argv); + tableSecond_.InitQuerySql(argv); + auto status = IsFindSpan(); + if (!status) { + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +bool SpanJoin::Cursor::CaclOverLap() +{ + if (tableFirst_.ts_ >= tableSecond_.ts_) { + if ((tableFirst_.partitionState_ == PartitionState::TS_REAL && + tableSecond_.partitionState_ == PartitionState::TS_REAL) || + tableFirst_.ts_ < tableSecond_.endTs_) { + return true; + } + } else if (tableFirst_.ts_ <= tableSecond_.ts_ && tableSecond_.ts_ < tableFirst_.endTs_) { + return true; + } + return false; +} + +bool SpanJoin::Cursor::IsFindSpan() +{ + for (;;) { + if (tableFirst_.isEof_ || tableSecond_.isEof_) { + break; + } + queryNext_ = FindQueryResult(); + if (CaclOverLap()) { + break; + } + queryNext_->Next(); + } + return true; +} + +SpanJoin::CaclSpan* SpanJoin::Cursor::FindQueryResult() +{ + if (!spanTable_->isSamepartitioning_) { + return nullptr; + } + + auto tableFirstResult = std::make_tuple(tableFirst_.GetPatitonForMiss(), tableFirst_.endTs_, + tableFirst_.partitionState_ == PartitionState::TS_REAL ? true : false); + auto tableSecondResult = std::make_tuple(tableSecond_.GetPatitonForMiss(), tableSecond_.endTs_, + tableSecond_.partitionState_ == PartitionState::TS_REAL ? true : false); + if (tableFirstResult < tableSecondResult) { + return &tableFirst_; + } + return &tableSecond_; +} + +int32_t SpanJoin::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(std::max(tableFirst_.ts_, tableSecond_.ts_))); + break; + } + case DUR: { + sqlite3_result_int64(context_, + static_cast(std::min(tableFirst_.endTs_, tableSecond_.endTs_) - + std::max(tableFirst_.ts_, tableSecond_.ts_))); + break; + } + case PARTITION: { + auto partResult = tableFirst_.partitionState_ == PartitionState::TS_REAL ? tableFirst_.partition_ + : tableSecond_.partition_; + sqlite3_result_int64(context_, static_cast(partResult)); + break; + } + default: { + const auto ColumnInfo = spanTable_->mTableColumnInfo_[column]; + if (ColumnInfo.tableDesc == tableFirst_.desc_) { + tableFirst_.setResult(context_, ColumnInfo.colIdx); + } else { + tableSecond_.setResult(context_, ColumnInfo.colIdx); + } + } + } + return SQLITE_OK; +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/span_join.h b/trace_streamer/src/table/base/span_join.h new file mode 100644 index 0000000000000000000000000000000000000000..74a87ede1567724a006a9292a13977bf1d810885 --- /dev/null +++ b/trace_streamer/src/table/base/span_join.h @@ -0,0 +1,135 @@ + +/* + * 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 SAPN_JOIN_H +#define SAPN_JOIN_H +#include "table_base.h" +#include "trace_data_cache.h" +namespace SysTuning { +namespace TraceStreamer { +struct TableParse { + std::string name; + std::string partitionCol; +}; + +struct TableDesc { + std::string name; + std::string partition; + std::vector cols; + int32_t tsIdx; + int32_t durIdx; + int32_t partitionIdx; +}; + +struct TableColumnInfo { + TableDesc* tableDesc; + int32_t colIdx; +}; + +enum PartitionState { + TS_REAL, + TS_PARTITION, + TS_MISSING, + TS_EOF, +}; + +class SpanJoin : public TableBase { +public: + SpanJoin(const TraceDataCache*); + ~SpanJoin() override{}; + void Parse(const std::string& tablePartition, TableParse& tableParse); + std::vector TableNameSplitToVec(std::string& str, const std::string& pat); + void GetTableField(TableParse& tableParse, TableDesc& tableDesc); + void GetColumns(const TraceDataCache* dataCache, + const std::string& tableName, + std::vector& columns); + void CreateCols(TableDesc& tableDesc, std::vector& cols); + bool IsTsOrDurCol(const std::string& name); + bool DeduplicationForColumn(const std::string& name, std::vector& cols); + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + void Init(int32_t argc, const char* const* argv) override; + std::unique_ptr CreateCursor() override; + + class CaclSpan { + public: + CaclSpan(TableBase* tableBase, const TableDesc* tableDesc, sqlite3* db); + virtual ~CaclSpan(); + static std::string GetMergeColumns(std::vector& columns); + int32_t InitQuerySql(sqlite3_value** argv); + bool IsQueryNext(); + bool GetCursorNext(); + bool GetNextState(); + bool SearchNextslice(); + void Next(); + std::string GetSqlQuery(); + void setResult(sqlite3_context* context, size_t index) const; + int64_t GetPatitonForMiss(); + + public: + bool isEof_ = false; + int64_t ts_ = 0; + int64_t endTs_ = 0; + PartitionState partitionState_ = PartitionState::TS_MISSING; + int32_t partition_ = 0; + int32_t missPartitionStart_ = 0; + int32_t missPartitionEnd_ = 0; + std::string sqlQuery_; + sqlite3_stmt* stmt_; + const TableDesc* desc_ = nullptr; + sqlite3* db_ = nullptr; + SpanJoin* table_ = nullptr; + }; + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, SpanJoin* table); + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + int32_t Next() override + { + queryNext_->Next(); + auto status = IsFindSpan(); + if (!status) { + return SQLITE_ERROR; + } + return SQLITE_OK; + } + int32_t Eof() override + { + return tableFirst_.isEof_ || tableSecond_.isEof_; + } + + private: + bool IsFindSpan(); + bool CaclOverLap(); + CaclSpan* FindQueryResult(); + CaclSpan tableFirst_; + CaclSpan tableSecond_; + CaclSpan* queryNext_ = nullptr; + SpanJoin* spanTable_; + }; + +public: + bool isSamepartitioning_ = false; + +private: + TableDesc tableFirstDesc_; + TableDesc tableSecondDesc_; + std::unordered_map mTableColumnInfo_; +}; + +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SAPN_JOIN_H diff --git a/trace_streamer/src/table/base/stat_table.cpp b/trace_streamer/src/table/base/stat_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4934c85dabb35d3fbd1da40e025827584ab62814 --- /dev/null +++ b/trace_streamer/src/table/base/stat_table.cpp @@ -0,0 +1,79 @@ +/* + * 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 "stat_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { EVENT_NAME = 0, STAT_EVENT_TYPE = 1, COUNT = 2, SEVERITY = 3, SOURCE = 4 }; +StatTable::StatTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("event_name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("stat_type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("serverity", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("source", "TEXT")); + tablePriKey_.push_back("event_name"); + tablePriKey_.push_back("stat_type"); +} + +StatTable::~StatTable() {} + +std::unique_ptr StatTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +StatTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, STAT_EVENT_MAX * TRACE_EVENT_MAX) +{ +} + +StatTable::Cursor::~Cursor() {} + +int32_t StatTable::Cursor::Column(int32_t column) const +{ + const StatAndInfo stat = dataCache_->GetConstStatAndInfo(); + SupportedTraceEventType eventType = static_cast(CurrentRow() / STAT_EVENT_MAX); + StatType statType = static_cast(CurrentRow() % STAT_EVENT_MAX); + switch (column) { + case EVENT_NAME: + sqlite3_result_text(context_, dataCache_->GetConstStatAndInfo().GetEvent(eventType).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case STAT_EVENT_TYPE: + sqlite3_result_text(context_, dataCache_->GetConstStatAndInfo().GetStat(statType).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + case COUNT: + sqlite3_result_int64(context_, + static_cast(dataCache_->GetConstStatAndInfo().GetValue(eventType, statType))); + break; + case SEVERITY: + sqlite3_result_text(context_, + dataCache_->GetConstStatAndInfo().GetSeverityDesc(eventType, statType).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case SOURCE: + sqlite3_result_text(context_, "trace", STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/stat_table.h b/trace_streamer/src/table/base/stat_table.h new file mode 100644 index 0000000000000000000000000000000000000000..4cdbdf66fae1c5fe37cdf29423ebbaf81f4ccc30 --- /dev/null +++ b/trace_streamer/src/table/base/stat_table.h @@ -0,0 +1,49 @@ +/* + * 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 STAT_TABLE_H +#define STAT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class StatTable : public TableBase { +public: + explicit StatTable(const TraceDataCache* dataCache); + ~StatTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // STAT_TABLE_H diff --git a/trace_streamer/src/table/base/symbols_table.cpp b/trace_streamer/src/table/base/symbols_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..532308f540b0f48314062e4f1099c7165164f319 --- /dev/null +++ b/trace_streamer/src/table/base/symbols_table.cpp @@ -0,0 +1,187 @@ +/* + * 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 "symbols_table.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, STR, ADDR }; +SymbolsTable::SymbolsTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("funcname", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("addr", "INTEGER")); + tablePriKey_.push_back("id"); +} + +SymbolsTable::~SymbolsTable() {} + +void SymbolsTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + size_t rowCount = dataCache_->GetConstSymbolsData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void SymbolsTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool SymbolsTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr SymbolsTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SymbolsTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSymbolsData().Size())) +{ +} + +SymbolsTable::Cursor::~Cursor() {} + +int32_t SymbolsTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t SymbolsTable::Cursor::Column(int32_t col) const +{ + DataIndex index = static_cast(CurrentRow()); + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case STR: + sqlite3_result_text( + context_, + dataCache_->GetDataFromDict(dataCache_->GetConstSymbolsData().GetConstFuncNames()[index]).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case ADDR: + sqlite3_result_int64(context_, + static_cast(dataCache_->GetConstSymbolsData().GetConstAddrs()[index])); + break; + default: + TS_LOGF("Unknown column %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/symbols_table.h b/trace_streamer/src/table/base/symbols_table.h new file mode 100644 index 0000000000000000000000000000000000000000..00848594a386d2ccc600171f1f6b767d9f11f16f --- /dev/null +++ b/trace_streamer/src/table/base/symbols_table.h @@ -0,0 +1,46 @@ +/* + * 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 SYMBOLS_DICT_TABLE_H +#define SYMBOLS_DICT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SymbolsTable : public TableBase { +public: + explicit SymbolsTable(const TraceDataCache* dataCache); + ~SymbolsTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SYMBOLS_DICT_TABLE_H diff --git a/trace_streamer/src/table/base/table_base.cpp b/trace_streamer/src/table/base/table_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6c4e55ba992e9713be5ac32c540d8ac76eab67c8 --- /dev/null +++ b/trace_streamer/src/table/base/table_base.cpp @@ -0,0 +1,311 @@ +/* + * 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 "table_base.h" + +#include +#include + +#include "log.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) + +namespace SysTuning { +namespace TraceStreamer { +namespace { +struct TableContext { + TabTemplate tmplate; + TraceDataCache* dataCache; + sqlite3_module module; + std::string tableName; +}; +} // namespace + +TableBase::~TableBase() +{ + dataCache_ = nullptr; + cursor_ = nullptr; +} + +void TableBase::TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate) +{ + std::unique_ptr context(std::make_unique()); + context->dataCache = cache; + context->tmplate = tmplate; + context->tableName = tableName; + sqlite3_module& module = context->module; + module = {0}; + + auto createFn = [](sqlite3* xdb, void* pAux, int32_t argc, const char* const* argv, sqlite3_vtab** ppVTab, + char** pzErr) { + UNUSED(argc); + UNUSED(argv); + UNUSED(pzErr); + auto xdesc = static_cast(pAux); + auto table = xdesc->tmplate(xdesc->dataCache); + table->name_ = xdesc->tableName; + if (table->name_ == "process" || table->name_ == "thread") { + table->wdataCache_ = xdesc->dataCache; + } + + table->Init(argc, argv); + std::string createStmt = table->CreateTableSql(); + TS_LOGD("xCreate table %s, statement: %s", table->name_.c_str(), createStmt.c_str()); + int32_t ret = sqlite3_declare_vtab(xdb, createStmt.c_str()); + if (ret != SQLITE_OK) { + if ((table->name_ == "span_join") || (table->name_ == "_span_join")) { + return ret; + } + TS_LOGE("sqlite3_declare_vtab %s faild: %s", table->name_.c_str(), createStmt.c_str()); + return ret; + } + *ppVTab = table.release(); + return SQLITE_OK; + }; + + auto destroyFn = [](sqlite3_vtab* t) { + TS_LOGD("xDestroy table %s", static_cast(t)->name_.c_str()); + delete static_cast(t); + return SQLITE_OK; + }; + module.xCreate = createFn; + module.xConnect = createFn; + module.xDisconnect = destroyFn; + module.xDestroy = destroyFn; + + module.xOpen = [](sqlite3_vtab* pVTab, sqlite3_vtab_cursor** ppCursor) { + TS_LOGD("xOpen: %s", static_cast(pVTab)->name_.c_str()); + return static_cast(pVTab)->Open(ppCursor); + }; + + module.xClose = [](sqlite3_vtab_cursor* vc) { + TS_LOGD("xClose: %s", static_cast(vc)->table_->name_.c_str()); + delete static_cast(vc); + return SQLITE_OK; + }; + + module.xBestIndex = [](sqlite3_vtab* pVTab, sqlite3_index_info* idxInfo) { + TS_LOGD("xBestIndex: %s %d", static_cast(pVTab)->name_.c_str(), idxInfo->nConstraint); + return static_cast(pVTab)->BestIndex(idxInfo); + }; + + module.xFilter = [](sqlite3_vtab_cursor* vc, int32_t idxNum, const char* idxStr, int32_t argc, + sqlite3_value** argv) { + auto* c = static_cast(vc); + c->Reset(); + TS_LOGD("xFilter %s: [%d]%s", static_cast(vc)->table_->name_.c_str(), idxNum, idxStr); + if (c->table_->cacheIdxNum_ != idxNum) { + c->table_->cacheConstraint_.Clear(); + c->table_->cacheConstraint_.FromString(idxStr); + c->table_->cacheIdxNum_ = idxNum; + } + return c->Filter(c->table_->cacheConstraint_, argv); + }; + + module.xNext = [](sqlite3_vtab_cursor* vc) { return static_cast(vc)->Next(); }; + module.xEof = [](sqlite3_vtab_cursor* vc) { return static_cast(vc)->Eof(); }; + module.xColumn = [](sqlite3_vtab_cursor* vc, sqlite3_context* ctx, int32_t col) { + static_cast(vc)->context_ = ctx; + return static_cast(vc)->Column(col); + }; + if (tableName == "process" || tableName == "thread") { + module.xUpdate = [](sqlite3_vtab* pVTab, int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) { + TS_LOGD("xUpdate: %s", static_cast(pVTab)->name_.c_str()); + return static_cast(pVTab)->Update(argc, argv, pRowid); + }; + } + + sqlite3_create_module_v2(&db, tableName.c_str(), &module, context.release(), + [](void* arg) { delete static_cast(arg); }); +} + +std::string TableBase::CreateTableSql() const +{ + std::string stmt = "CREATE TABLE x("; + for (const auto& col : tableColumn_) { + stmt += " " + col.name_ + " " + col.type_; + stmt += ","; + } + stmt += " PRIMARY KEY("; + for (size_t i = 0; i < tablePriKey_.size(); i++) { + if (i != 0) + stmt += ", "; + stmt += tablePriKey_.at(i); + } + stmt += ")) WITHOUT ROWID;"; + return stmt; +} +int32_t TableBase::Cursor::Next() +{ + indexMap_->Next(); + return SQLITE_OK; +} + +int32_t TableBase::Cursor::Eof() +{ + return dataCache_->Cancel() || indexMap_->Eof(); +} +uint32_t TableBase::Cursor::CurrentRow() const +{ + return indexMap_->CurrentRow(); +} +void TableBase::Cursor::FilterEnd() +{ + indexMap_->Sort(); +} +int32_t TableBase::BestIndex(sqlite3_index_info* idxInfo) +{ + FilterConstraints filterConstraints; + for (int32_t i = 0; i < idxInfo->nConstraint; i++) { + const auto& constraint = idxInfo->aConstraint[i]; + if (constraint.usable) { + filterConstraints.AddConstraint(i, constraint.iColumn, constraint.op); + } + } + for (int32_t i = 0; i < idxInfo->nOrderBy; i++) { + filterConstraints.AddOrderBy(idxInfo->aOrderBy[i].iColumn, idxInfo->aOrderBy[i].desc); + } + + EstimatedIndexInfo estimate = {idxInfo->estimatedRows, idxInfo->estimatedCost, false}; + EstimateFilterCost(filterConstraints, estimate); + idxInfo->orderByConsumed = estimate.isOrdered; + idxInfo->estimatedCost = estimate.estimatedCost; + idxInfo->estimatedRows = estimate.estimatedRows; + + auto cs = filterConstraints.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + auto& c = cs[i]; + idxInfo->aConstraintUsage[c.idxInaConstraint].argvIndex = static_cast(i + 1); + idxInfo->aConstraintUsage[c.idxInaConstraint].omit = c.isSupport; + } + + std::string str; + filterConstraints.ToString(str); + char* pIdxStr = static_cast(sqlite3_malloc(str.size() + 1)); + std::copy(str.begin(), str.end(), pIdxStr); + pIdxStr[str.size()] = '\0'; + idxInfo->idxStr = pIdxStr; + idxInfo->needToFreeIdxStr = true; + idxInfo->idxNum = ++bestIndexNum_; + + TS_LOGD("%s BestIndex return: %d: %s", name_.c_str(), idxInfo->idxNum, str.c_str()); + TS_LOGD("%s, aConstraintUsage[%d]", idxInfo->idxStr, idxInfo->nConstraint); + for (int32_t i = 0; i < idxInfo->nConstraint; i++) { + TS_LOGD("col: %d op: %d, argvindex: %d omit: %d", idxInfo->aConstraint[i].iColumn, idxInfo->aConstraint[i].op, + idxInfo->aConstraintUsage[i].argvIndex, idxInfo->aConstraintUsage[i].omit); + } + TS_LOGD("estimated: %lld cost:%.3f", idxInfo->estimatedRows, idxInfo->estimatedCost); + + return SQLITE_OK; +} + +int32_t TableBase::Open(sqlite3_vtab_cursor** ppCursor) +{ + *ppCursor = static_cast(CreateCursor().release()); + return SQLITE_OK; +} + +TableBase::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount) + : context_(nullptr), + table_(table), + dataCache_(dataCache), + indexMap_(std::make_unique(0, rowCount)), + rowCount_(rowCount) +{ +} + +TableBase::Cursor::~Cursor() +{ + context_ = nullptr; + dataCache_ = nullptr; +} +void TableBase::Cursor::FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times) +{ + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint64_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(times, v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(times, v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: { + indexMap_->RemoveNullElements(times, v); + break; + } + default: + break; + } // end of switch (op) + } +} + +int32_t TableBase::Cursor::RowId(sqlite3_int64* id) +{ + if (dataCache_->Cancel() || indexMap_->Eof()) { + return SQLITE_ERROR; + } + *id = static_cast(indexMap_->CurrentRow()); + return SQLITE_OK; +} +void TableBase::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + if (indexMap_->HasData()) { + indexMap_->CovertToIndexMap(); + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/table_base.h b/trace_streamer/src/table/base/table_base.h new file mode 100644 index 0000000000000000000000000000000000000000..499eb9a30ad1e58a9927891923dd9aa3af27fb80 --- /dev/null +++ b/trace_streamer/src/table/base/table_base.h @@ -0,0 +1,132 @@ +/* + * 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 TABLE_H +#define TABLE_H + +#include +#include +#include + +#include "filter_constraints.h" +#include "index_map.h" +#include "sqlite3.h" +#include "trace_data_cache.h" + +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +namespace SysTuning { +namespace TraceStreamer { +class TableBase; +using TabTemplate = std::unique_ptr (*)(const TraceDataCache* dataCache); +class TableBase : public sqlite3_vtab { +public: + virtual ~TableBase(); + TableBase(const TableBase&) = delete; + TableBase& operator=(const TableBase&) = delete; + + template + static void TableDeclare(sqlite3& db, TraceDataCache* dataCache, const std::string& tableName) + { + TableRegister(db, dataCache, tableName, [](const TraceDataCache* cache) { + return std::unique_ptr(std::make_unique(cache)); + }); + dataCache->AppendNewTable(tableName); + } + std::string CreateTableSql() const; + + class Cursor : public sqlite3_vtab_cursor { + public: + Cursor(const TraceDataCache* dataCache, TableBase* table, uint32_t rowCount); + virtual ~Cursor(); + virtual void Reset() + { + indexMap_ = std::make_unique(0, rowCount_); + } + + virtual int32_t Next(); + + virtual int32_t Eof(); + + virtual uint32_t CurrentRow() const; + virtual void FilterTS(unsigned char op, sqlite3_value* argv, const std::deque& times); + + virtual int32_t RowId(sqlite3_int64* id); + virtual int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) = 0; + virtual int32_t Column(int32_t n) const = 0; + virtual void FilterId(unsigned char op, sqlite3_value* argv); + virtual void FilterEnd(); + + public: + sqlite3_context* context_; + TableBase* table_ = nullptr; + + protected: + const TraceDataCache* dataCache_; + std::unique_ptr indexMap_; + uint32_t rowCount_; + }; + + struct ColumnInfo { + ColumnInfo(const std::string& name, const std::string& type) : name_(name), type_(type) {} + std::string name_; + std::string type_; + }; + +protected: + explicit TableBase(const TraceDataCache* dataCache) : dataCache_(dataCache), cursor_(nullptr) {} + + struct EstimatedIndexInfo { + int64_t estimatedRows = 0; + double estimatedCost = 0.0; + bool isOrdered = false; + }; + + static void TableRegister(sqlite3& db, TraceDataCache* cache, const std::string& tableName, TabTemplate tmplate); + virtual int32_t Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) + { + return SQLITE_READONLY; + } + int32_t BestIndex(sqlite3_index_info* idxInfo); + // needs to correspond to Cursor::Filter() + virtual void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) = 0; + virtual std::unique_ptr CreateCursor() = 0; + int32_t Open(sqlite3_vtab_cursor** ppCursor); + virtual void Init(int32_t, const char* const*) + { + return; + }; + +public: + std::string name_; + +protected: + std::vector tableColumn_ = {}; + std::vector tablePriKey_ = {}; + const TraceDataCache* dataCache_; + TraceDataCache* wdataCache_ = nullptr; + std::unique_ptr cursor_; + +private: + uint16_t bestIndexNum_ = 0; + int32_t cacheIdxNum_ = 0; + FilterConstraints cacheConstraint_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TABLE_H diff --git a/trace_streamer/src/table/base/trace_config_table.cpp b/trace_streamer/src/table/base/trace_config_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf1a96f8b26b511dcbb31721f4b6a5f5605caf5c --- /dev/null +++ b/trace_streamer/src/table/base/trace_config_table.cpp @@ -0,0 +1,70 @@ +/* + * 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 "trace_config_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TRACE_SOURCE, KEY, VALUE }; +TraceConfigTable::TraceConfigTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("trace_source", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("key", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "TEXT")); + tablePriKey_.push_back("id"); +} + +TraceConfigTable::~TraceConfigTable() {} + +std::unique_ptr TraceConfigTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +TraceConfigTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstTraceConfigData().Size())), + TraceConfigData_(dataCache->GetConstTraceConfigData()) +{ +} + +TraceConfigTable::Cursor::~Cursor() {} + +int32_t TraceConfigTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TRACE_SOURCE: + sqlite3_result_text(context_, dataCache_->GetConstTraceConfigData().TraceSource()[CurrentRow()].c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case KEY: + sqlite3_result_text(context_, dataCache_->GetConstTraceConfigData().Key()[CurrentRow()].c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case VALUE: + sqlite3_result_text(context_, dataCache_->GetConstTraceConfigData().Value()[CurrentRow()].c_str(), + STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/base/trace_config_table.h b/trace_streamer/src/table/base/trace_config_table.h new file mode 100644 index 0000000000000000000000000000000000000000..254ec0b360b516f0c399ee8d3cddff2527b7e9f5 --- /dev/null +++ b/trace_streamer/src/table/base/trace_config_table.h @@ -0,0 +1,52 @@ +/* + * 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 TEACE_CONFIG_TABLE_H +#define TEACE_CONFIG_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class TraceConfigTable : public TableBase { +public: + explicit TraceConfigTable(const TraceDataCache*); + ~TraceConfigTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const TraceConfigData& TraceConfigData_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // TRACE_CONFIG_TABLE_H diff --git a/trace_streamer/src/table/ebpf/BUILD.gn b/trace_streamer/src/table/ebpf/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..1712e2890f6d603ef891ff28f1792dad84e2fd7b --- /dev/null +++ b/trace_streamer/src/table/ebpf/BUILD.gn @@ -0,0 +1,65 @@ +# 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("//src/ts.gni") +ohos_source_set("ebpf_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "bio_latency_sample_table.cpp", + "bio_latency_sample_table.h", + "ebpf_callstack_table.cpp", + "ebpf_callstack_table.h", + "file_system_sample_table.cpp", + "file_system_sample_table.h", + ] + + if (with_ebpf_help_table) { + sources += [ + "ebpf_elf_symbol_table.cpp", + "ebpf_elf_symbol_table.h", + "ebpf_elf_table.cpp", + "ebpf_elf_table.h", + "ebpf_process_maps_table.cpp", + "ebpf_process_maps_table.h", + ] + } + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/ebpf/bio_latency_sample_table.cpp b/trace_streamer/src/table/ebpf/bio_latency_sample_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2bdf58dc10e9a855371b0fc824a9435287a45fd9 --- /dev/null +++ b/trace_streamer/src/table/ebpf/bio_latency_sample_table.cpp @@ -0,0 +1,272 @@ +/* + * 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 "bio_latency_sample_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + CALLCHAIN_ID, + TYPE, + IPID, + ITID, + START_TS, + END_TS, + LATENCY_DUR, + TIER, + SIZE, + BLOCK_NUMBER, + PATH, + DUR_PER_4K, +}; +BioLatencySampleTable::BioLatencySampleTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("latency_dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("tier", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("block_number", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("path_id", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("dur_per_4k", "INTEGER")); + tablePriKey_.push_back("id"); +} + +BioLatencySampleTable::~BioLatencySampleTable() {} + +void BioLatencySampleTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void BioLatencySampleTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool BioLatencySampleTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr BioLatencySampleTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +BioLatencySampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstBioLatencySampleData().Size())), + bioLatencySampleObj_(dataCache->GetConstBioLatencySampleData()) +{ +} + +BioLatencySampleTable::Cursor::~Cursor() {} + +int32_t BioLatencySampleTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t BioLatencySampleTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.IdsData()[CurrentRow()])); + break; + case CALLCHAIN_ID: + if (bioLatencySampleObj_.CallChainIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.CallChainIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.Types()[CurrentRow()])); + break; + case IPID: { + if (bioLatencySampleObj_.Ipids()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.Ipids()[CurrentRow()])); + } + break; + } + case ITID: { + if (bioLatencySampleObj_.Itids()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.Itids()[CurrentRow()])); + } + break; + } + case START_TS: { + if (bioLatencySampleObj_.StartTs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.StartTs()[CurrentRow()])); + } + break; + } + case END_TS: { + if (bioLatencySampleObj_.EndTs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.EndTs()[CurrentRow()])); + } + break; + } + case LATENCY_DUR: { + if (bioLatencySampleObj_.LatencyDurs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.LatencyDurs()[CurrentRow()])); + } + break; + } + case TIER: { + if (bioLatencySampleObj_.Tiers()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.Tiers()[CurrentRow()])); + } + break; + } + case SIZE: { + if (bioLatencySampleObj_.Sizes()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.Sizes()[CurrentRow()])); + } + break; + } + case BLOCK_NUMBER: { + if (bioLatencySampleObj_.BlockNumbers()[CurrentRow()] != INVALID_UINT64) { + auto returnValueIndex0 = bioLatencySampleObj_.BlockNumbers()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(returnValueIndex0).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case PATH: { + if (bioLatencySampleObj_.FilePathIds()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.FilePathIds()[CurrentRow()])); + } + break; + } + case DUR_PER_4K: { + if (bioLatencySampleObj_.DurPer4k()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(bioLatencySampleObj_.DurPer4k()[CurrentRow()])); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ebpf/bio_latency_sample_table.h b/trace_streamer/src/table/ebpf/bio_latency_sample_table.h new file mode 100644 index 0000000000000000000000000000000000000000..38a3596b24d478cf77ee4c04bad13a2ae37ca395 --- /dev/null +++ b/trace_streamer/src/table/ebpf/bio_latency_sample_table.h @@ -0,0 +1,49 @@ +/* + * 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 BIO_LATENCY_SAMPLE_TABLE_H +#define BIO_LATENCY_SAMPLE_TABLE_H + +#include "table_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +class BioLatencySampleTable : public TableBase { +public: + explicit BioLatencySampleTable(const TraceDataCache* dataCache); + ~BioLatencySampleTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const BioLatencySampleData& bioLatencySampleObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // BIO_LATENCY_SAMPLE_TABLE_H diff --git a/trace_streamer/src/table/ebpf/ebpf_callstack_table.cpp b/trace_streamer/src/table/ebpf/ebpf_callstack_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68a6e834c3b8e54b06bef8e93a63675d044182d9 --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_callstack_table.cpp @@ -0,0 +1,212 @@ +/* + * 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 "ebpf_callstack_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + CALLCHAIN_ID, + DEPTH, + IP, + SYMBOLS_ID, + FILE_PATH_ID, +}; +EbpfCallStackTable::EbpfCallStackTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ip", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("symbols_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_path_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +EbpfCallStackTable::~EbpfCallStackTable() {} + +void EbpfCallStackTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void EbpfCallStackTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool EbpfCallStackTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr EbpfCallStackTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +EbpfCallStackTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstEbpfCallStackData().Size())), + ebpfCallStackObj_(dataCache->GetConstEbpfCallStackData()) +{ +} + +EbpfCallStackTable::Cursor::~Cursor() {} + +int32_t EbpfCallStackTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t EbpfCallStackTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(ebpfCallStackObj_.IdsData()[CurrentRow()])); + break; + case CALLCHAIN_ID: + sqlite3_result_int64(context_, static_cast(ebpfCallStackObj_.CallChainIds()[CurrentRow()])); + break; + case DEPTH: + sqlite3_result_int64(context_, static_cast(ebpfCallStackObj_.Depths()[CurrentRow()])); + break; + case IP: { + if (ebpfCallStackObj_.Ips()[CurrentRow()] != INVALID_UINT64) { + auto returnValueIndex = ebpfCallStackObj_.Ips()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(returnValueIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case SYMBOLS_ID: { + if (ebpfCallStackObj_.SymbolIds()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(ebpfCallStackObj_.SymbolIds()[CurrentRow()])); + } + break; + } + case FILE_PATH_ID: { + if (ebpfCallStackObj_.FilePathIds()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(ebpfCallStackObj_.FilePathIds()[CurrentRow()])); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ebpf/ebpf_callstack_table.h b/trace_streamer/src/table/ebpf/ebpf_callstack_table.h new file mode 100644 index 0000000000000000000000000000000000000000..5d7cf621d675533092501c9db806be47ce2fe778 --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_callstack_table.h @@ -0,0 +1,49 @@ +/* + * 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 EBPF_CALLSTACK_TABLE_H +#define EBPF_CALLSTACK_TABLE_H + +#include "table_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +class EbpfCallStackTable : public TableBase { +public: + explicit EbpfCallStackTable(const TraceDataCache* dataCache); + ~EbpfCallStackTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const EbpfCallStackData& ebpfCallStackObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_CALLSTACK_TABLE_H diff --git a/trace_streamer/src/table/ebpf/ebpf_elf_symbol_table.cpp b/trace_streamer/src/table/ebpf/ebpf_elf_symbol_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fb79fd0590b69524cfcfa6fca45f73b7a55662c --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_elf_symbol_table.cpp @@ -0,0 +1,229 @@ +/* + * 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 "ebpf_elf_symbol_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + ELF_ID, + ST_NAME, + ST_VALUE, + ST_SIZE, +}; +EbpfElfSymbolTable::EbpfElfSymbolTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("elf_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("st_name", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("st_value", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("st_size", "INTEGER")); + tablePriKey_.push_back("id"); +} + +EbpfElfSymbolTable::~EbpfElfSymbolTable() {} + +void EbpfElfSymbolTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void EbpfElfSymbolTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool EbpfElfSymbolTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr EbpfElfSymbolTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +EbpfElfSymbolTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstEbpfElfSymbol().Size())), + ebpfElfSymbolObj_(dataCache->GetConstEbpfElfSymbol()) +{ +} + +EbpfElfSymbolTable::Cursor::~Cursor() {} + +int32_t EbpfElfSymbolTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t EbpfElfSymbolTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(ebpfElfSymbolObj_.IdsData()[CurrentRow()])); + break; + case ELF_ID: + sqlite3_result_int64(context_, static_cast(ebpfElfSymbolObj_.ElfIds()[CurrentRow()])); + break; + case ST_NAME: + sqlite3_result_int64(context_, static_cast(ebpfElfSymbolObj_.StNames()[CurrentRow()])); + break; + case ST_VALUE: + sqlite3_result_int64(context_, static_cast(ebpfElfSymbolObj_.StValues()[CurrentRow()])); + break; + case ST_SIZE: + sqlite3_result_int64(context_, static_cast(ebpfElfSymbolObj_.StSizes()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} + +void EbpfElfSymbolTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ebpf/ebpf_elf_symbol_table.h b/trace_streamer/src/table/ebpf/ebpf_elf_symbol_table.h new file mode 100644 index 0000000000000000000000000000000000000000..39fadf42602e819ae7c7955aeb1e49b828abca77 --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_elf_symbol_table.h @@ -0,0 +1,50 @@ +/* + * 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 EBPF_ELF_SYMBOL_TABLE_H +#define EBPF_ELF_SYMBOL_TABLE_H + +#include "table_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +class EbpfElfSymbolTable : public TableBase { +public: + explicit EbpfElfSymbolTable(const TraceDataCache* dataCache); + ~EbpfElfSymbolTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + void FilterId(unsigned char op, sqlite3_value* argv) override; + + private: + const EbpfElfSymbol& ebpfElfSymbolObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_ELF_SYMBOL_TABLE_H diff --git a/trace_streamer/src/table/ebpf/ebpf_elf_table.cpp b/trace_streamer/src/table/ebpf/ebpf_elf_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..330eb2a88f84a5abd540cf682cfba664e7091587 --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_elf_table.cpp @@ -0,0 +1,261 @@ +/* + * 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 "ebpf_elf_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + ELF_ID, + TEXT_VADDR, + TEXT_OFFSET, + STR_TAB_LEN, + SYM_TAB_LEN, + FILE_NAME_LEN, + SYM_ENT_LEN, + FILE_PATH_ID, +}; +EbpfElfTable::EbpfElfTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("elf_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("text_vaddr", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("text_offset", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("str_tab_len", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("sym_tab_len", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_name_len", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("sym_ent_len", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_path_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +EbpfElfTable::~EbpfElfTable() {} + +void EbpfElfTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void EbpfElfTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool EbpfElfTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr EbpfElfTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +EbpfElfTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstEbpfElf().Size())), + ebpfElfObj_(dataCache->GetConstEbpfElf()) +{ +} + +EbpfElfTable::Cursor::~Cursor() {} + +int32_t EbpfElfTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t EbpfElfTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.IdsData()[CurrentRow()])); + break; + case ELF_ID: + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.ElfIds()[CurrentRow()])); + break; + case TEXT_VADDR: + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.TextVaddrs()[CurrentRow()])); + break; + case TEXT_OFFSET: + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.TextOffsets()[CurrentRow()])); + break; + case STR_TAB_LEN: + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.StrTabLens()[CurrentRow()])); + break; + case SYM_TAB_LEN: { + if (ebpfElfObj_.SymTabLens()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.SymTabLens()[CurrentRow()])); + } + break; + } + case FILE_NAME_LEN: { + if (ebpfElfObj_.FileNameLens()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.FileNameLens()[CurrentRow()])); + } + break; + } + case SYM_ENT_LEN: { + if (ebpfElfObj_.SymEntLens()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.SymEntLens()[CurrentRow()])); + } + break; + } + case FILE_PATH_ID: { + if (ebpfElfObj_.FileNameIndexs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(ebpfElfObj_.FileNameIndexs()[CurrentRow()])); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} + +void EbpfElfTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ebpf/ebpf_elf_table.h b/trace_streamer/src/table/ebpf/ebpf_elf_table.h new file mode 100644 index 0000000000000000000000000000000000000000..86bc77b079f43086200ee10b7f9da2ee8f16f3a3 --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_elf_table.h @@ -0,0 +1,50 @@ +/* + * 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 EBPF_ELF_TABLE_H +#define EBPF_ELF_TABLE_H + +#include "table_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +class EbpfElfTable : public TableBase { +public: + explicit EbpfElfTable(const TraceDataCache* dataCache); + ~EbpfElfTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + void FilterId(unsigned char op, sqlite3_value* argv) override; + + private: + const EbpfElf& ebpfElfObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_ELF_TABLE_H diff --git a/trace_streamer/src/table/ebpf/ebpf_process_maps_table.cpp b/trace_streamer/src/table/ebpf/ebpf_process_maps_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47f1d14753f6393933de31d35143355842cb11a7 --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_process_maps_table.cpp @@ -0,0 +1,249 @@ +/* + * 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 "ebpf_process_maps_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + START_ADDR, + END_ADDR, + OFFSETS, + PID, + FILE_NAME_LEN, + FILE_PATH_ID, +}; +EbpfProcessMapsTable::EbpfProcessMapsTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start_addr", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_addr", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("offset", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_path_len", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_path_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +EbpfProcessMapsTable::~EbpfProcessMapsTable() {} + +void EbpfProcessMapsTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void EbpfProcessMapsTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool EbpfProcessMapsTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr EbpfProcessMapsTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +EbpfProcessMapsTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstEbpfProcessMaps().Size())), + ebpfProcessMapsObj_(dataCache->GetConstEbpfProcessMaps()) +{ +} + +EbpfProcessMapsTable::Cursor::~Cursor() {} + +int32_t EbpfProcessMapsTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t EbpfProcessMapsTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(ebpfProcessMapsObj_.IdsData()[CurrentRow()])); + break; + case START_ADDR: + sqlite3_result_int64(context_, static_cast(ebpfProcessMapsObj_.Starts()[CurrentRow()])); + break; + case END_ADDR: + sqlite3_result_int64(context_, static_cast(ebpfProcessMapsObj_.Ends()[CurrentRow()])); + break; + case OFFSETS: + sqlite3_result_int64(context_, static_cast(ebpfProcessMapsObj_.Offsets()[CurrentRow()])); + break; + case PID: { + if (ebpfProcessMapsObj_.Pids()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(ebpfProcessMapsObj_.Pids()[CurrentRow()])); + } + break; + } + case FILE_NAME_LEN: { + if (ebpfProcessMapsObj_.FileNameLens()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(ebpfProcessMapsObj_.FileNameLens()[CurrentRow()])); + } + break; + } + case FILE_PATH_ID: { + if (ebpfProcessMapsObj_.FileNameIndexs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, + static_cast(ebpfProcessMapsObj_.FileNameIndexs()[CurrentRow()])); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} + +void EbpfProcessMapsTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ebpf/ebpf_process_maps_table.h b/trace_streamer/src/table/ebpf/ebpf_process_maps_table.h new file mode 100644 index 0000000000000000000000000000000000000000..ee6285b0c2dea6a6806af7c91a487ae0f10cb84c --- /dev/null +++ b/trace_streamer/src/table/ebpf/ebpf_process_maps_table.h @@ -0,0 +1,50 @@ +/* + * 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 EBPF_PROCESS_MAPS_TABLE_H +#define EBPF_PROCESS_MAPS_TABLE_H + +#include "table_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +class EbpfProcessMapsTable : public TableBase { +public: + explicit EbpfProcessMapsTable(const TraceDataCache* dataCache); + ~EbpfProcessMapsTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + void FilterId(unsigned char op, sqlite3_value* argv) override; + + private: + const EbpfProcessMaps& ebpfProcessMapsObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // EBPF_PROCESS_MAPS_TABLE_H diff --git a/trace_streamer/src/table/ebpf/file_system_sample_table.cpp b/trace_streamer/src/table/ebpf/file_system_sample_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a944ecc69827b5efdcdafb8d0c1bad8bce860b9 --- /dev/null +++ b/trace_streamer/src/table/ebpf/file_system_sample_table.cpp @@ -0,0 +1,303 @@ +/* + * 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 "file_system_sample_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + CALLCHAIN_ID, + TYPE, + IPID, + ITID, + START_TS, + END_TS, + DUR, + RETURN_VALUE, + ERROR_VALUE, + FD, + FILE_ID, + SIZE, + FIRST_ARGUMENT, + SECOND_ARGUMENT, + THIRD_ARGUMENT, + FOURTH_ARGUMENT, +}; +FileSystemSampleTable::FileSystemSampleTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("return_value", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("error_code", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("fd", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("first_argument", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("second_argument", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("third_argument", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("fourth_argument", "TEXT")); + tablePriKey_.push_back("id"); +} + +FileSystemSampleTable::~FileSystemSampleTable() {} + +void FileSystemSampleTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void FileSystemSampleTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool FileSystemSampleTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr FileSystemSampleTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +FileSystemSampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstFileSystemSample().Size())), + fileSystemSampleTableObj_(dataCache->GetConstFileSystemSample()) +{ +} + +FileSystemSampleTable::Cursor::~Cursor() {} + +int32_t FileSystemSampleTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case TYPE: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + fileSystemSampleTableObj_.Types()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + return SQLITE_OK; +} + +int32_t FileSystemSampleTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.IdsData()[CurrentRow()])); + break; + case CALLCHAIN_ID: + if (fileSystemSampleTableObj_.CallChainIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, + static_cast(fileSystemSampleTableObj_.CallChainIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.Types()[CurrentRow()])); + break; + case IPID: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.Ipids()[CurrentRow()])); + break; + case ITID: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.Itids()[CurrentRow()])); + break; + case START_TS: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.StartTs()[CurrentRow()])); + break; + case END_TS: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.EndTs()[CurrentRow()])); + break; + case DUR: + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.Durs()[CurrentRow()])); + break; + case RETURN_VALUE: { + if (fileSystemSampleTableObj_.ReturnValues()[CurrentRow()] != INVALID_UINT64) { + auto returnValueIndex = fileSystemSampleTableObj_.ReturnValues()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(returnValueIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case ERROR_VALUE: { + if (fileSystemSampleTableObj_.ErrorCodes()[CurrentRow()] != INVALID_UINT64) { + auto errorValueIndex = fileSystemSampleTableObj_.ErrorCodes()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(errorValueIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case FD: { + if (fileSystemSampleTableObj_.Fds()[CurrentRow()] != INVALID_INT32) { + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.Fds()[CurrentRow()])); + } + break; + } + case FILE_ID: { + if (fileSystemSampleTableObj_.FileIds()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.FileIds()[CurrentRow()])); + } + break; + } + case SIZE: { + if (fileSystemSampleTableObj_.Sizes()[CurrentRow()] != MAX_SIZE_T) { + sqlite3_result_int64(context_, static_cast(fileSystemSampleTableObj_.Sizes()[CurrentRow()])); + } + break; + } + case FIRST_ARGUMENT: { + if (fileSystemSampleTableObj_.FirstArguments()[CurrentRow()] != INVALID_UINT64) { + auto firstArgIndex = fileSystemSampleTableObj_.FirstArguments()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(firstArgIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case SECOND_ARGUMENT: { + if (fileSystemSampleTableObj_.SecondArguments()[CurrentRow()] != INVALID_UINT64) { + auto secondArgIndex = fileSystemSampleTableObj_.SecondArguments()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(secondArgIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case THIRD_ARGUMENT: { + if (fileSystemSampleTableObj_.ThirdArguments()[CurrentRow()] != INVALID_UINT64) { + auto thirdArgIndex = fileSystemSampleTableObj_.ThirdArguments()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(thirdArgIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case FOURTH_ARGUMENT: { + if (fileSystemSampleTableObj_.FourthArguments()[CurrentRow()] != INVALID_UINT64) { + auto fourthArgIndex = fileSystemSampleTableObj_.FourthArguments()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(fourthArgIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ebpf/file_system_sample_table.h b/trace_streamer/src/table/ebpf/file_system_sample_table.h new file mode 100644 index 0000000000000000000000000000000000000000..e6e282ba331fb84f02588fc11281a93759289687 --- /dev/null +++ b/trace_streamer/src/table/ebpf/file_system_sample_table.h @@ -0,0 +1,49 @@ +/* + * 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 FILE_SYSTEM_SAMPLE_TABLE_H +#define FILE_SYSTEM_SAMPLE_TABLE_H + +#include "table_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +class FileSystemSampleTable : public TableBase { +public: + explicit FileSystemSampleTable(const TraceDataCache* dataCache); + ~FileSystemSampleTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const FileSystemSample& fileSystemSampleTableObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // FILE_SYSTEM_SAMPLE_TABLE_H diff --git a/trace_streamer/src/table/ftrace/BUILD.gn b/trace_streamer/src/table/ftrace/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..60c8f711b47c281386214cd7de7395d6219167ef --- /dev/null +++ b/trace_streamer/src/table/ftrace/BUILD.gn @@ -0,0 +1,95 @@ +# 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("//src/ts.gni") +ohos_source_set("ftrace_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "callstack_table.cpp", + "callstack_table.h", + "clk_event_filter_table.cpp", + "clk_event_filter_table.h", + "clock_event_filter_table.cpp", + "clock_event_filter_table.h", + "clock_snapshot_table.cpp", + "clock_snapshot_table.h", + "cpu_measure_filter_table.cpp", + "cpu_measure_filter_table.h", + "filter_table.cpp", + "filter_table.h", + "frame_maps_table.cpp", + "frame_maps_table.h", + "frame_slice_table.cpp", + "frame_slice_table.h", + "gpu_slice_table.cpp", + "gpu_slice_table.h", + "instants_table.cpp", + "instants_table.h", + "irq_table.cpp", + "irq_table.h", + "measure_filter_table.cpp", + "measure_filter_table.h", + "measure_table.cpp", + "measure_table.h", + "process_filter_table.cpp", + "process_filter_table.h", + "process_measure_filter_table.cpp", + "process_measure_filter_table.h", + "process_table.cpp", + "process_table.h", + "raw_table.cpp", + "raw_table.h", + "sched_slice_table.cpp", + "sched_slice_table.h", + "system_call_table.cpp", + "system_call_table.h", + "system_event_filter_table.cpp", + "system_event_filter_table.h", + "thread_filter_table.cpp", + "thread_filter_table.h", + "thread_state_table.cpp", + "thread_state_table.h", + "thread_table.cpp", + "thread_table.h", + ] + + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/ftrace/callstack_table.cpp b/trace_streamer/src/table/ftrace/callstack_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05a695bae19d5bb3cb69c5f98806199508bfa457 --- /dev/null +++ b/trace_streamer/src/table/ftrace/callstack_table.cpp @@ -0,0 +1,290 @@ +/* + * 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 "callstack_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + TS, + DUR, + CALL_ID, + CAT, + IDENTIFY, + NAME, + DEPTH, + COOKIE_ID, + PARENT_ID, + ARGSET, + CHAIN_ID, + SPAN_ID, + PARENT_SPAN_ID, + FLAG, + ARGS +}; +CallStackTable::CallStackTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("identify", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cookie", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("argsetid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("chainId", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("args", "TEXT")); + tablePriKey_.push_back("callid"); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("depth"); +} + +CallStackTable::~CallStackTable() {} + +void CallStackTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstInternalSlicesData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void CallStackTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool CallStackTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr CallStackTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +CallStackTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstInternalSlicesData().Size())), + slicesObj_(dataCache->GetConstInternalSlicesData()) +{ +} + +CallStackTable::Cursor::~Cursor() {} + +int32_t CallStackTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case TS: + FilterTS(c.op, argv[i], slicesObj_.TimeStampData()); + break; + case CALL_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), slicesObj_.CallIds()); + break; + case COOKIE_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), slicesObj_.Cookies()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t CallStackTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, CurrentRow()); + break; + case TS: + sqlite3_result_int64(context_, static_cast(slicesObj_.TimeStampData()[CurrentRow()])); + break; + case DUR: + sqlite3_result_int64(context_, static_cast(slicesObj_.DursData()[CurrentRow()])); + break; + case CALL_ID: + sqlite3_result_int64(context_, static_cast(slicesObj_.CallIds()[CurrentRow()])); + break; + case CAT: { + if (slicesObj_.CatsData()[CurrentRow()] != INVALID_UINT64) { + auto catsDataIndex = static_cast(slicesObj_.CatsData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(catsDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case IDENTIFY: + sqlite3_result_int(context_, slicesObj_.IdentifysData()[CurrentRow()]); + break; + case NAME: { + if (slicesObj_.NamesData()[CurrentRow()] != INVALID_UINT64) { + auto nameDataIndex = static_cast(slicesObj_.NamesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(nameDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case DEPTH: + sqlite3_result_int64(context_, static_cast(slicesObj_.Depths()[CurrentRow()])); + break; + case COOKIE_ID: + if (slicesObj_.Cookies()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(slicesObj_.Cookies()[CurrentRow()])); + } + break; + case PARENT_ID: { + if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) { + sqlite3_result_int64(context_, static_cast(slicesObj_.ParentIdData()[CurrentRow()].value())); + } + break; + } + case ARGSET: + if (slicesObj_.ArgSetIdsData()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(slicesObj_.ArgSetIdsData()[CurrentRow()])); + } + break; + case CHAIN_ID: + if (!slicesObj_.ChainIds()[CurrentRow()].empty()) { + sqlite3_result_text(context_, slicesObj_.ChainIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + } + break; + case SPAN_ID: + if (!slicesObj_.SpanIds()[CurrentRow()].empty()) { + sqlite3_result_text(context_, slicesObj_.SpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + } + break; + case PARENT_SPAN_ID: + if (!slicesObj_.ParentSpanIds()[CurrentRow()].empty()) { + sqlite3_result_text(context_, slicesObj_.ParentSpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + case FLAG: + if (!slicesObj_.Flags()[CurrentRow()].empty()) { + sqlite3_result_text(context_, slicesObj_.Flags()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + } + break; + case ARGS: + if (!slicesObj_.ArgsData()[CurrentRow()].empty()) { + sqlite3_result_text(context_, slicesObj_.ArgsData()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + } + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/callstack_table.h b/trace_streamer/src/table/ftrace/callstack_table.h new file mode 100644 index 0000000000000000000000000000000000000000..64ba32b4825aadcec8ba7ab4f5213cf378599c0f --- /dev/null +++ b/trace_streamer/src/table/ftrace/callstack_table.h @@ -0,0 +1,50 @@ +/* + * 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 CALL_STACK_TABLE_H +#define CALL_STACK_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class CallStackTable : public TableBase { +public: + explicit CallStackTable(const TraceDataCache* dataCache); + ~CallStackTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + private: + const CallStack& slicesObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // CALL_STACK_TABLE_H diff --git a/trace_streamer/src/table/ftrace/clk_event_filter_table.cpp b/trace_streamer/src/table/ftrace/clk_event_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..498761ae0afecac2c325201a423e41f0cb16c240 --- /dev/null +++ b/trace_streamer/src/table/ftrace/clk_event_filter_table.cpp @@ -0,0 +1,232 @@ +/* + * 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 "clk_event_filter_table.h" + +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, CPU }; +ClkEventFilterTable::ClkEventFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ClkEventFilterTable::~ClkEventFilterTable() {} + +void ClkEventFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstClkEventFilterData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ClkEventFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ClkEventFilterTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr ClkEventFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ClkEventFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstClkEventFilterData().Size())) +{ +} + +ClkEventFilterTable::Cursor::~Cursor() {} + +int32_t ClkEventFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterSorted(c.col, c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ClkEventFilterTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64( + context_, static_cast(dataCache_->GetConstClkEventFilterData().IdsData()[CurrentRow()])); + break; + case TYPE: { + size_t typeId = static_cast(dataCache_->GetConstClkEventFilterData().RatesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(typeId).c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case NAME: { + size_t strId = static_cast(dataCache_->GetConstClkEventFilterData().NamesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(strId).c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case CPU: + sqlite3_result_int64(context_, static_cast( + dataCache_->GetConstClkEventFilterData().CpusData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +void ClkEventFilterTable::Cursor::FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL, filter out nothing + indexMap_->Intersect(0, 0); + return; + } + + switch (col) { + case ID: { + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint32_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(dataCache_->GetConstClkEventFilterData().IdsData(), v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(dataCache_->GetConstClkEventFilterData().IdsData(), v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(dataCache_->GetConstClkEventFilterData().IdsData(), v, getValue); + break; + } + default: + break; + } // end of switch (op) + } // end of case TS + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/clk_event_filter_table.h b/trace_streamer/src/table/ftrace/clk_event_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..445baf9130fba5ec34aeabd32c46ab0e2868b015 --- /dev/null +++ b/trace_streamer/src/table/ftrace/clk_event_filter_table.h @@ -0,0 +1,49 @@ +/* + * 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 SRC_CLK_EVENT_FILTER_TABLE_H +#define SRC_CLK_EVENT_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ClkEventFilterTable : public TableBase { +public: + explicit ClkEventFilterTable(const TraceDataCache*); + ~ClkEventFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + void FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv); + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_CLK_EVENT_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/clock_event_filter_table.cpp b/trace_streamer/src/table/ftrace/clock_event_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2af886f069eb66f5d2cae10bcc6f98e6a374333a --- /dev/null +++ b/trace_streamer/src/table/ftrace/clock_event_filter_table.cpp @@ -0,0 +1,232 @@ +/* + * 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 "clock_event_filter_table.h" + +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, CPU }; +ClockEventFilterTable::ClockEventFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ClockEventFilterTable::~ClockEventFilterTable() {} + +void ClockEventFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstClockEventFilterData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ClockEventFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ClockEventFilterTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr ClockEventFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ClockEventFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstClockEventFilterData().Size())) +{ +} + +ClockEventFilterTable::Cursor::~Cursor() {} + +int32_t ClockEventFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterSorted(c.col, c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ClockEventFilterTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast( + dataCache_->GetConstClockEventFilterData().IdsData()[CurrentRow()])); + break; + case TYPE: { + size_t typeId = static_cast(dataCache_->GetConstClockEventFilterData().TypesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(typeId).c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case NAME: { + size_t strId = static_cast(dataCache_->GetConstClockEventFilterData().NamesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(strId).c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case CPU: + sqlite3_result_int64(context_, static_cast( + dataCache_->GetConstClockEventFilterData().CpusData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +void ClockEventFilterTable::Cursor::FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL, filter out nothing + indexMap_->Intersect(0, 0); + return; + } + + switch (col) { + case ID: { + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint32_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(dataCache_->GetConstClockEventFilterData().IdsData(), v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(dataCache_->GetConstClockEventFilterData().IdsData(), v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(dataCache_->GetConstClockEventFilterData().IdsData(), v, getValue); + break; + } + default: + break; + } // end of switch (op) + } // end of case TS + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/clock_event_filter_table.h b/trace_streamer/src/table/ftrace/clock_event_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..af8907814e383dcad45c9457f41e51348a4ce24f --- /dev/null +++ b/trace_streamer/src/table/ftrace/clock_event_filter_table.h @@ -0,0 +1,49 @@ +/* + * 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 SRC_CLOCK_EVENT_FILTER_TABLE_H +#define SRC_CLOCK_EVENT_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ClockEventFilterTable : public TableBase { +public: + explicit ClockEventFilterTable(const TraceDataCache* dataCache); + ~ClockEventFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + void FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv); + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_CLOCK_EVENT_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/clock_snapshot_table.cpp b/trace_streamer/src/table/ftrace/clock_snapshot_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f644d1e74097abd063669ce5c4261217d35a10fd --- /dev/null +++ b/trace_streamer/src/table/ftrace/clock_snapshot_table.cpp @@ -0,0 +1,69 @@ +/* + * 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 "clock_snapshot_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, CLOCK_ID, TS, CLOCK_NAME }; +ClockSnapShotTable::ClockSnapShotTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("clock_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("clock_name", "TEXT")); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("id"); +} + +ClockSnapShotTable::~ClockSnapShotTable() {} + +std::unique_ptr ClockSnapShotTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ClockSnapShotTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstClockSnapshotData().Size())), + snapShotData_(dataCache->GetConstClockSnapshotData()) +{ +} + +ClockSnapShotTable::Cursor::~Cursor() {} + +int32_t ClockSnapShotTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, CurrentRow()); + break; + case CLOCK_ID: + sqlite3_result_int64(context_, static_cast(snapShotData_.ClockIds()[CurrentRow()])); + break; + case TS: + sqlite3_result_int64(context_, static_cast(snapShotData_.Ts()[CurrentRow()])); + break; + case CLOCK_NAME: + sqlite3_result_text(context_, snapShotData_.Names()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/clock_snapshot_table.h b/trace_streamer/src/table/ftrace/clock_snapshot_table.h new file mode 100644 index 0000000000000000000000000000000000000000..42d34a57ad42c0888b7345217fdb7f99ff338700 --- /dev/null +++ b/trace_streamer/src/table/ftrace/clock_snapshot_table.h @@ -0,0 +1,51 @@ +/* + * 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 CLOCK_SNAPSHOT_TABLE_H +#define CLOCK_SNAPSHOT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ClockSnapShotTable : public TableBase { +public: + explicit ClockSnapShotTable(const TraceDataCache* dataCache); + ~ClockSnapShotTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t column) const override; + + private: + const ClockSnapshotData& snapShotData_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // CLOCK_SNAPSHOT_TABLE_H diff --git a/trace_streamer/src/table/ftrace/cpu_measure_filter_table.cpp b/trace_streamer/src/table/ftrace/cpu_measure_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b4f9b9c067c6d1e96ada9be14e3307b677aa0d9 --- /dev/null +++ b/trace_streamer/src/table/ftrace/cpu_measure_filter_table.cpp @@ -0,0 +1,235 @@ +/* + * 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 "cpu_measure_filter_table.h" + +#include + +#include "log.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, CPU }; +CpuMeasureFilterTable::CpuMeasureFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER")); + tablePriKey_.push_back("id"); +} + +CpuMeasureFilterTable::~CpuMeasureFilterTable() {} + +void CpuMeasureFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstCpuMeasureData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void CpuMeasureFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool CpuMeasureFilterTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr CpuMeasureFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +CpuMeasureFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstCpuMeasureData().Size())), + cpuMeasureObj_(dataCache->GetConstCpuMeasureData()) +{ +} + +CpuMeasureFilterTable::Cursor::~Cursor() {} + +int32_t CpuMeasureFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterSorted(c.col, c.op, argv[i]); + break; + case CPU: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), cpuMeasureObj_.CpuData()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t CpuMeasureFilterTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(cpuMeasureObj_.IdsData()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_text(context_, "cpu_measure_filter", STR_DEFAULT_LEN, nullptr); + break; + case NAME: { + const std::string& str = + dataCache_->GetDataFromDict(static_cast(cpuMeasureObj_.NameData()[CurrentRow()])); + sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case CPU: + sqlite3_result_int64(context_, static_cast(cpuMeasureObj_.CpuData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} + +void CpuMeasureFilterTable::Cursor::FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL, filter out nothing + indexMap_->Intersect(0, 0); + return; + } + + switch (col) { + case ID: { + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint32_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(cpuMeasureObj_.IdsData(), v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(cpuMeasureObj_.IdsData(), v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(cpuMeasureObj_.IdsData(), v, getValue); + break; + } + default: + break; + } // end of switch (op) + } // end of case TS + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/cpu_measure_filter_table.h b/trace_streamer/src/table/ftrace/cpu_measure_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..d308949439d11f5c887df20f07179b2c4203dd5a --- /dev/null +++ b/trace_streamer/src/table/ftrace/cpu_measure_filter_table.h @@ -0,0 +1,51 @@ +/* + * 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 CPU_MEASURE_FILTER_TABLE_H +#define CPU_MEASURE_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class CpuMeasureFilterTable : public TableBase { +public: + explicit CpuMeasureFilterTable(const TraceDataCache* dataCache); + ~CpuMeasureFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + void FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv); + + private: + const CpuMeasureFilter& cpuMeasureObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // CPU_MEASURE_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/filter_table.cpp b/trace_streamer/src/table/ftrace/filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e485ceaba58a1b0a49a4f7ba084cd8a036aecbd --- /dev/null +++ b/trace_streamer/src/table/ftrace/filter_table.cpp @@ -0,0 +1,186 @@ +/* + * 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 "filter_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, SOURCE_ARG_SET_ID }; +FilterTable::FilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("source_arg_set_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +FilterTable::~FilterTable() {} + +void FilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstFilterData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void FilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool FilterTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr FilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +FilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstFilterData().Size())), + filterObj_(dataCache->GetConstFilterData()) +{ +} + +FilterTable::Cursor::~Cursor() {} + +int32_t FilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t FilterTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, CurrentRow()); // IdsData() will be optimized + break; + case TYPE: + sqlite3_result_text(context_, filterObj_.TypeData()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case NAME: + sqlite3_result_text(context_, filterObj_.NameData()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case SOURCE_ARG_SET_ID: + sqlite3_result_int64(context_, static_cast(filterObj_.SourceArgSetIdData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/filter_table.h b/trace_streamer/src/table/ftrace/filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..bd0373358ea4d1fbf3081f85737ba8f70a02dd2e --- /dev/null +++ b/trace_streamer/src/table/ftrace/filter_table.h @@ -0,0 +1,51 @@ +/* + * 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 FILTER_TABLE_H +#define FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class FilterTable : public TableBase { +public: + enum Column { ID = 0, TYPE = 1, NAME = 2, ARG_ID = 3 }; + explicit FilterTable(const TraceDataCache* dataCache); + ~FilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + private: + const TraceStreamer::Filter& filterObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/frame_maps_table.cpp b/trace_streamer/src/table/ftrace/frame_maps_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c667fa92d88d4609295bdb2a3a779808fc3e4cc8 --- /dev/null +++ b/trace_streamer/src/table/ftrace/frame_maps_table.cpp @@ -0,0 +1,189 @@ +/* + * 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 "frame_maps_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, SRC_ROW, DST_ROW }; +FrameMapsTable::FrameMapsTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("src_row", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dst_row", "INTEGER")); + tablePriKey_.push_back("id"); +} + +FrameMapsTable::~FrameMapsTable() {} + +void FrameMapsTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void FrameMapsTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool FrameMapsTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr FrameMapsTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +FrameMapsTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstFameMapsData().Size())), + frameMapsObj_(dataCache->GetConstFameMapsData()) +{ +} + +FrameMapsTable::Cursor::~Cursor() {} + +int32_t FrameMapsTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case SRC_ROW: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + frameMapsObj_.SrcIndexs()); + break; + case DST_ROW: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameMapsObj_.DstIndexs()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t FrameMapsTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case SRC_ROW: + sqlite3_result_int64(context_, static_cast(frameMapsObj_.SrcIndexs()[CurrentRow()])); + break; + case DST_ROW: + sqlite3_result_int64(context_, static_cast(frameMapsObj_.DstIndexs()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/frame_maps_table.h b/trace_streamer/src/table/ftrace/frame_maps_table.h new file mode 100644 index 0000000000000000000000000000000000000000..949d58b77417dc303621b946afc2e4f2e0280d90 --- /dev/null +++ b/trace_streamer/src/table/ftrace/frame_maps_table.h @@ -0,0 +1,49 @@ +/* + * 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 FRAME_MAPS_TABLE_H +#define FRAME_MAPS_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class FrameMapsTable : public TableBase { +public: + explicit FrameMapsTable(const TraceDataCache* dataCache); + ~FrameMapsTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const FrameMaps& frameMapsObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // FRAME_MAPS_TABLE_H diff --git a/trace_streamer/src/table/ftrace/frame_slice_table.cpp b/trace_streamer/src/table/ftrace/frame_slice_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1d75d592c931099a24ae8d8b4f35c8d05359024 --- /dev/null +++ b/trace_streamer/src/table/ftrace/frame_slice_table.cpp @@ -0,0 +1,267 @@ +/* + * 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 "frame_slice_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TS, VSYNC, IPID, ITID, CALLSTACK_ID, DUR, SRC, DST, TYPE, TYPE_DESC, FLAG, DEPTH, FRAME_NO }; +FrameSliceTable::FrameSliceTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("vsync", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callstack_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("src", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("dst", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type_desc", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("flag", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("frame_no", "INTEGER")); + tablePriKey_.push_back("id"); +} + +FrameSliceTable::~FrameSliceTable() {} + +void FrameSliceTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void FrameSliceTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool FrameSliceTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr FrameSliceTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +FrameSliceTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstFameSliceData().Size())), + frameSliceObj_(dataCache->GetConstFameSliceData()) +{ +} + +FrameSliceTable::Cursor::~Cursor() {} + +int32_t FrameSliceTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case ITID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + frameSliceObj_.InternalTidsData()); + break; + case IPID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.Ipids()); + break; + case VSYNC: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.VsyncIds()); + break; + case CALLSTACK_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + frameSliceObj_.CallStackIds()); + break; + case DUR: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.Durs()); + break; + case TYPE: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.Types()); + break; + case FLAG: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.Flags()); + break; + case DEPTH: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.Depths()); + break; + case FRAME_NO: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), frameSliceObj_.FrameNos()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t FrameSliceTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TS: + sqlite3_result_int64(context_, static_cast(frameSliceObj_.TimeStampData()[CurrentRow()])); + break; + case VSYNC: + sqlite3_result_int64(context_, static_cast(frameSliceObj_.VsyncIds()[CurrentRow()])); + break; + case IPID: + sqlite3_result_int64(context_, static_cast(frameSliceObj_.Ipids()[CurrentRow()])); + break; + case ITID: + sqlite3_result_int64(context_, static_cast(frameSliceObj_.InternalTidsData()[CurrentRow()])); + break; + case CALLSTACK_ID: + sqlite3_result_int64(context_, static_cast(frameSliceObj_.CallStackIds()[CurrentRow()])); + break; + case DUR: + if (frameSliceObj_.Durs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(frameSliceObj_.Durs()[CurrentRow()])); + } + break; + case SRC: + sqlite3_result_text(context_, frameSliceObj_.Srcs()[CurrentRow()].c_str(), + frameSliceObj_.Srcs()[CurrentRow()].length(), nullptr); + break; + case DST: + if (frameSliceObj_.Dsts()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(frameSliceObj_.Dsts()[CurrentRow()])); + } + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(frameSliceObj_.Types()[CurrentRow()])); + break; + case TYPE_DESC: + sqlite3_result_text(context_, frameSliceObj_.Types()[CurrentRow()] == 0 ? "actural" : "expect", + STR_DEFAULT_LEN, nullptr); + break; + case FLAG: + if (frameSliceObj_.Flags()[CurrentRow()] != INVALID_UINT8) { + sqlite3_result_int(context_, static_cast(frameSliceObj_.Flags()[CurrentRow()])); + } + break; + case DEPTH: + if (frameSliceObj_.Depths()[CurrentRow()] != INVALID_UINT8) { + sqlite3_result_int(context_, static_cast(frameSliceObj_.Depths()[CurrentRow()])); + } + break; + case FRAME_NO: + if (frameSliceObj_.FrameNos()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int(context_, static_cast(frameSliceObj_.FrameNos()[CurrentRow()])); + } + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/frame_slice_table.h b/trace_streamer/src/table/ftrace/frame_slice_table.h new file mode 100644 index 0000000000000000000000000000000000000000..9ab595b7e76df53d0564074b61abe73748b0242b --- /dev/null +++ b/trace_streamer/src/table/ftrace/frame_slice_table.h @@ -0,0 +1,49 @@ +/* + * 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 FRAME_SLICE_TABLE_H +#define FRAME_SLICE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class FrameSliceTable : public TableBase { +public: + explicit FrameSliceTable(const TraceDataCache* dataCache); + ~FrameSliceTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const FrameSlice& frameSliceObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // FRAME_SLICE_TABLE_H diff --git a/trace_streamer/src/table/ftrace/gpu_slice_table.cpp b/trace_streamer/src/table/ftrace/gpu_slice_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4106be65b81fc92585225ab1f4ea406e67be7f4d --- /dev/null +++ b/trace_streamer/src/table/ftrace/gpu_slice_table.cpp @@ -0,0 +1,190 @@ +/* + * 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 "gpu_slice_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, FRAME_ROW, DUR }; +GPUSliceTable::GPUSliceTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("frame_row", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tablePriKey_.push_back("id"); +} + +GPUSliceTable::~GPUSliceTable() {} + +void GPUSliceTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void GPUSliceTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool GPUSliceTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr GPUSliceTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +GPUSliceTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstGPUSliceData().Size())), + gpuSliceObj_(dataCache->GetConstGPUSliceData()) +{ +} + +GPUSliceTable::Cursor::~Cursor() {} + +int32_t GPUSliceTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case FRAME_ROW: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), gpuSliceObj_.FrameRows()); + break; + case DUR: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), gpuSliceObj_.Durs()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t GPUSliceTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case FRAME_ROW: + sqlite3_result_int64(context_, static_cast(gpuSliceObj_.FrameRows()[CurrentRow()])); + break; + case DUR: + if (gpuSliceObj_.Durs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(gpuSliceObj_.Durs()[CurrentRow()])); + } + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/gpu_slice_table.h b/trace_streamer/src/table/ftrace/gpu_slice_table.h new file mode 100644 index 0000000000000000000000000000000000000000..b8f4a88249244ed7c046e18d83d2f9d6971d0737 --- /dev/null +++ b/trace_streamer/src/table/ftrace/gpu_slice_table.h @@ -0,0 +1,49 @@ +/* + * 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 GPU_SLICE_TABLE_H +#define GPU_SLICE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class GPUSliceTable : public TableBase { +public: + explicit GPUSliceTable(const TraceDataCache* dataCache); + ~GPUSliceTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const GPUSlice& gpuSliceObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // GPU_SLICE_TABLE_H diff --git a/trace_streamer/src/table/ftrace/instants_table.cpp b/trace_streamer/src/table/ftrace/instants_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18c41a97f75905f7254de0935be3aca4946a23cc --- /dev/null +++ b/trace_streamer/src/table/ftrace/instants_table.cpp @@ -0,0 +1,228 @@ +/* + * 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 "instants_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { TS = 0, NAME, REF, WAKEUP_FROM, REF_TYPE, VALUE }; +InstantsTable::InstantsTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ref", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("wakeup_from", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ref_type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "REAL")); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("ref"); +} + +InstantsTable::~InstantsTable() {} + +std::unique_ptr InstantsTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +InstantsTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstInstantsData().Size())), + InstantsObj_(dataCache->GetConstInstantsData()) +{ +} + +InstantsTable::Cursor::~Cursor() {} + +void InstantsTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstMeasureData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case TS: + break; + case NAME: + break; + case REF: + break; + case WAKEUP_FROM: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void InstantsTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case TS: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool InstantsTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +int32_t InstantsTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset + indexMap_ = std::make_unique(0, rowCount_); + if (rowCount_ <= 0) { + return SQLITE_OK; + } + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case TS: + FilterTS(c.op, argv[i], InstantsObj_.TimeStampData()); + break; + case NAME: + indexMap_->MixRange(c.op, + dataCache_->GetConstDataIndex( + std::string(reinterpret_cast(sqlite3_value_text(argv[i])))), + InstantsObj_.NameIndexsData()); + break; + case REF: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + InstantsObj_.InternalTidsData()); + break; + case WAKEUP_FROM: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + InstantsObj_.WakeupFromPidsData()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case TS: + indexMap_->SortBy(orderbys[i].desc); + break; + case NAME: + indexMap_->SortBy(orderbys[i].desc); + break; + case REF: + indexMap_->SortBy(orderbys[i].desc); + break; + case WAKEUP_FROM: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t InstantsTable::Cursor::Column(int32_t column) const +{ + size_t stringIdentity = static_cast(InstantsObj_.NameIndexsData()[CurrentRow()]); + switch (column) { + case TS: + sqlite3_result_int64(context_, static_cast(InstantsObj_.TimeStampData()[CurrentRow()])); + break; + case NAME: { + sqlite3_result_text(context_, dataCache_->GetDataFromDict(stringIdentity).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + case REF: + sqlite3_result_int64(context_, static_cast(InstantsObj_.InternalTidsData()[CurrentRow()])); + break; + case WAKEUP_FROM: + sqlite3_result_int64(context_, static_cast(InstantsObj_.WakeupFromPidsData()[CurrentRow()])); + break; + case REF_TYPE: { + sqlite3_result_text(context_, "itid", STR_DEFAULT_LEN, nullptr); + break; + } + case VALUE: { + sqlite3_result_double(context_, 0.0); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/instants_table.h b/trace_streamer/src/table/ftrace/instants_table.h new file mode 100644 index 0000000000000000000000000000000000000000..383252fb794577028ae260ebf6a085740abc60ac --- /dev/null +++ b/trace_streamer/src/table/ftrace/instants_table.h @@ -0,0 +1,48 @@ +/* + * 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 INSTANTS_TABLE_H +#define INSTANTS_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class InstantsTable : public TableBase { +public: + explicit InstantsTable(const TraceDataCache* dataCache); + ~InstantsTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + bool CanFilterSorted(const char op, size_t& rowCount) const; + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const Instants& InstantsObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // INSTANTS_TABLE_H diff --git a/trace_streamer/src/table/ftrace/irq_table.cpp b/trace_streamer/src/table/ftrace/irq_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9da49f2d7d427960877ad25e595d932a4f91bd8 --- /dev/null +++ b/trace_streamer/src/table/ftrace/irq_table.cpp @@ -0,0 +1,265 @@ +/* + * 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 "irq_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + TS, + DUR, + CALL_ID, + CAT, + NAME, + DEPTH, + COOKIE_ID, + PARENT_ID, + ARGSET, + CHAIN_ID, + SPAN_ID, + PARENT_SPAN_ID, + FLAG, + ARGS +}; +IrqTable::IrqTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cat", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cookie", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("argsetid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("chainId", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("spanId", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("parentSpanId", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("flag", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("args", "TEXT")); + tablePriKey_.push_back("callid"); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("depth"); +} + +IrqTable::~IrqTable() {} + +void IrqTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstIrqData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void IrqTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool IrqTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr IrqTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +IrqTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstIrqData().Size())), + slicesObj_(dataCache->GetConstIrqData()) +{ +} + +IrqTable::Cursor::~Cursor() {} + +int32_t IrqTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t IrqTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, CurrentRow()); + break; + case TS: + sqlite3_result_int64(context_, static_cast(slicesObj_.TimeStampData()[CurrentRow()])); + break; + case DUR: + sqlite3_result_int64(context_, static_cast(slicesObj_.DursData()[CurrentRow()])); + break; + case CALL_ID: + sqlite3_result_int64(context_, static_cast(slicesObj_.CallIds()[CurrentRow()])); + break; + case CAT: { + if (slicesObj_.CatsData()[CurrentRow()] != INVALID_UINT64) { + auto catsDataIndex = static_cast(slicesObj_.CatsData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(catsDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case NAME: { + if (slicesObj_.NamesData()[CurrentRow()] != INVALID_UINT64) { + auto nameDataIndex = static_cast(slicesObj_.NamesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(nameDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case DEPTH: + sqlite3_result_int64(context_, static_cast(slicesObj_.Depths()[CurrentRow()])); + break; + case COOKIE_ID: + if (slicesObj_.Cookies()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(slicesObj_.Cookies()[CurrentRow()])); + } + break; + case PARENT_ID: { + if (slicesObj_.ParentIdData()[CurrentRow()].has_value()) { + sqlite3_result_int64(context_, static_cast(slicesObj_.ParentIdData()[CurrentRow()].value())); + } + break; + } + case ARGSET: + if (slicesObj_.ArgSetIdsData()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(slicesObj_.ArgSetIdsData()[CurrentRow()])); + } + break; + case CHAIN_ID: + sqlite3_result_text(context_, slicesObj_.ChainIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case SPAN_ID: + sqlite3_result_text(context_, slicesObj_.SpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case PARENT_SPAN_ID: + sqlite3_result_text(context_, slicesObj_.ParentSpanIds()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case FLAG: + sqlite3_result_text(context_, slicesObj_.Flags()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case ARGS: + sqlite3_result_text(context_, slicesObj_.ArgsData()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/irq_table.h b/trace_streamer/src/table/ftrace/irq_table.h new file mode 100644 index 0000000000000000000000000000000000000000..03d10115bf689cdd9e0ad73b612e614d5598b46a --- /dev/null +++ b/trace_streamer/src/table/ftrace/irq_table.h @@ -0,0 +1,50 @@ +/* + * 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 IRQ_TABLE_H +#define IRQ_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class IrqTable : public TableBase { +public: + explicit IrqTable(const TraceDataCache* dataCache); + ~IrqTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const CallStack& slicesObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // IRQ_TABLE_H diff --git a/trace_streamer/src/table/ftrace/measure_filter_table.cpp b/trace_streamer/src/table/ftrace/measure_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff8a943b010de16fed48c00e98048082f9dfa28f --- /dev/null +++ b/trace_streamer/src/table/ftrace/measure_filter_table.cpp @@ -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. + */ + +#include "measure_filter_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, INTERNAL_TID }; +MeasureFilterTable::MeasureFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +MeasureFilterTable::~MeasureFilterTable() {} + +std::unique_ptr MeasureFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +MeasureFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstThreadMeasureFilterData().Size())) +{ +} + +MeasureFilterTable::Cursor::~Cursor() {} + +int32_t MeasureFilterTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64( + context_, + static_cast(dataCache_->GetConstThreadMeasureFilterData().FilterIdData()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_text(context_, "thread_measure_filter", STR_DEFAULT_LEN, nullptr); + break; + case NAME: { + const std::string& str = dataCache_->GetDataFromDict( + dataCache_->GetConstThreadMeasureFilterData().NameIndexData()[CurrentRow()]); + sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case INTERNAL_TID: + sqlite3_result_int64( + context_, + static_cast(dataCache_->GetConstThreadMeasureFilterData().InternalTidData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/measure_filter_table.h b/trace_streamer/src/table/ftrace/measure_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..38ec1ea446c513c0492449341e3a626888657bb6 --- /dev/null +++ b/trace_streamer/src/table/ftrace/measure_filter_table.h @@ -0,0 +1,49 @@ +/* + * 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 THREAD_MEASURE_FILTER_H +#define THREAD_MEASURE_FILTER_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class MeasureFilterTable : public TableBase { +public: + explicit MeasureFilterTable(const TraceDataCache* dataCache); + ~MeasureFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // THREAD_MEASURE_FILTER_H diff --git a/trace_streamer/src/table/ftrace/measure_table.cpp b/trace_streamer/src/table/ftrace/measure_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4c4113878a60967beaf935de309b8ca03de8ea6 --- /dev/null +++ b/trace_streamer/src/table/ftrace/measure_table.cpp @@ -0,0 +1,210 @@ +/* + * 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 "measure_table.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { TYPE = 0, TS, DUR, VALUE, FILTER_ID }; +MeasureTable::MeasureTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("value", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("filter_id", "INTEGER")); + tablePriKey_.push_back("ts"); + tablePriKey_.push_back("filter_id"); +} + +MeasureTable::~MeasureTable() {} + +std::unique_ptr MeasureTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +MeasureTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor( + dataCache, + table, + static_cast(table->name_ == "measure" || table->name_ == "_measure" + ? dataCache->GetConstMeasureData().Size() + : (table->name_ == "process_measure" || table->name_ == "_process_measure" + ? dataCache->GetConstProcessMeasureData().Size() + : dataCache->GetConstSysMemMeasureData().Size()))), + measureObj(table->name_ == "measure" || table->name_ == "_measure" + ? dataCache->GetConstMeasureData() + : (table->name_ == "process_measure" || table->name_ == "_process_measure" + ? dataCache->GetConstProcessMeasureData() + : dataCache->GetConstSysMemMeasureData())) +{ +} + +MeasureTable::Cursor::~Cursor() {} + +void MeasureTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstMeasureData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case TS: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void MeasureTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case TS: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool MeasureTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +int32_t MeasureTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case TS: + FilterTS(c.op, argv[i], measureObj.TimeStampData()); + break; + case FILTER_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), measureObj.FilterIdData()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case TS: + indexMap_->SortBy(orderbys[i].desc); + break; + case FILTER_ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t MeasureTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TYPE: + sqlite3_result_text(context_, "measure", STR_DEFAULT_LEN, nullptr); + break; + case TS: + sqlite3_result_int64(context_, static_cast(measureObj.TimeStampData()[CurrentRow()])); + break; + case DUR: + if (measureObj.DursData()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(measureObj.DursData()[CurrentRow()])); + } + break; + case VALUE: + sqlite3_result_int64(context_, static_cast(measureObj.ValuesData()[CurrentRow()])); + break; + case FILTER_ID: + sqlite3_result_int64(context_, static_cast(measureObj.FilterIdData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/measure_table.h b/trace_streamer/src/table/ftrace/measure_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6040cc393e82d636d1ab100d7179547b5310d75c --- /dev/null +++ b/trace_streamer/src/table/ftrace/measure_table.h @@ -0,0 +1,49 @@ +/* + * 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 MEASURE_TABLE_H +#define MEASURE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class MeasureTable : public TableBase { +public: + explicit MeasureTable(const TraceDataCache* dataCache); + ~MeasureTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + bool CanFilterSorted(const char op, size_t& rowCount) const; + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const Measure& measureObj; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // MEASURE_TABLE_H diff --git a/trace_streamer/src/table/ftrace/process_filter_table.cpp b/trace_streamer/src/table/ftrace/process_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de64a28979120e33d4872bd76f4cd1910ab33d77 --- /dev/null +++ b/trace_streamer/src/table/ftrace/process_filter_table.cpp @@ -0,0 +1,70 @@ +/* + * 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 "process_filter_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, INTERNAL_PID }; +ProcessFilterTable::ProcessFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ProcessFilterTable::~ProcessFilterTable() {} + +std::unique_ptr ProcessFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ProcessFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstProcessFilterData().Size())), + processFilterObj_(dataCache->GetConstProcessFilterData()) +{ +} + +ProcessFilterTable::Cursor::~Cursor() {} + +int32_t ProcessFilterTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(processFilterObj_.IdsData()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_text(context_, "process_filter", STR_DEFAULT_LEN, nullptr); + break; + case NAME: { + DataIndex stringIdentity = static_cast(processFilterObj_.NamesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(stringIdentity).c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + case INTERNAL_PID: + sqlite3_result_int64(context_, static_cast(processFilterObj_.UpidsData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/process_filter_table.h b/trace_streamer/src/table/ftrace/process_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..b247061661fe1c3060321e676c3e71ec83b13a9a --- /dev/null +++ b/trace_streamer/src/table/ftrace/process_filter_table.h @@ -0,0 +1,52 @@ +/* + * 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 PROCESS_FILTER_TABLE_H +#define PROCESS_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ProcessFilterTable : public TableBase { +public: + explicit ProcessFilterTable(const TraceDataCache* dataCache); + ~ProcessFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t col) const override; + + private: + const ProcessMeasureFilter& processFilterObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PROCESS_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/process_measure_filter_table.cpp b/trace_streamer/src/table/ftrace/process_measure_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11f3d337b561c2769942434d12aca18ee968996b --- /dev/null +++ b/trace_streamer/src/table/ftrace/process_measure_filter_table.cpp @@ -0,0 +1,204 @@ +/* + * 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 "process_measure_filter_table.h" + +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, INTERNAL_PID }; +ProcessMeasureFilterTable::ProcessMeasureFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ProcessMeasureFilterTable::~ProcessMeasureFilterTable() {} + +void ProcessMeasureFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstProcessMeasureFilterData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ProcessMeasureFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ProcessMeasureFilterTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr ProcessMeasureFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ProcessMeasureFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstProcessMeasureFilterData().Size())) +{ +} + +ProcessMeasureFilterTable::Cursor::~Cursor() {} + +int32_t ProcessMeasureFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + dataCache_->GetConstProcessMeasureFilterData().IdsData()); + break; + case INTERNAL_PID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + dataCache_->GetConstProcessMeasureFilterData().UpidsData()); + break; + case NAME: + indexMap_->MixRange(c.op, + dataCache_->GetConstDataIndex( + std::string(reinterpret_cast(sqlite3_value_text(argv[i])))), + dataCache_->GetConstProcessMeasureFilterData().NamesData()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ProcessMeasureFilterTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast( + dataCache_->GetConstProcessMeasureFilterData().IdsData()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_text(context_, "process_measure_filter", STR_DEFAULT_LEN, nullptr); + break; + case NAME: { + size_t strId = + static_cast(dataCache_->GetConstProcessMeasureFilterData().NamesData()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(strId).c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case INTERNAL_PID: + sqlite3_result_int64( + context_, + static_cast(dataCache_->GetConstProcessMeasureFilterData().UpidsData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/process_measure_filter_table.h b/trace_streamer/src/table/ftrace/process_measure_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..baffdf8c85e29df9985ebdab7be161b1b3095501 --- /dev/null +++ b/trace_streamer/src/table/ftrace/process_measure_filter_table.h @@ -0,0 +1,47 @@ +/* + * 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 SRC_PROCESS_MEASURE_FILTER_TABLE_H +#define SRC_PROCESS_MEASURE_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ProcessMeasureFilterTable : public TableBase { +public: + explicit ProcessMeasureFilterTable(const TraceDataCache* dataCache); + ~ProcessMeasureFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_PROCESS_MEASURE_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/process_table.cpp b/trace_streamer/src/table/ftrace/process_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b01342993ae498519fc7e9fcc1864d08de4245e --- /dev/null +++ b/trace_streamer/src/table/ftrace/process_table.cpp @@ -0,0 +1,355 @@ +/* + * 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 "process_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + IPID, + TYPE, + PID, + NAME, + START_TS, + SWTICH_COUNT, + SWITCH_COUNT, + THREAD_COUNT, + SLICE_COUNT, + MEM_COUNT +}; +ProcessTable::ProcessTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + // remove the 'swtich_count' after three release version + tableColumn_.push_back(TableBase::ColumnInfo("swtich_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("switch_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("thread_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("slice_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("mem_count", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ProcessTable::~ProcessTable() {} + +void ProcessTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->ProcessSize(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case IPID: + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ProcessTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case IPID: + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ProcessTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +int32_t ProcessTable::Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) +{ + if (argc <= 1) { + return SQLITE_READONLY; + } + if (sqlite3_value_type(argv[0]) == SQLITE_NULL) { + return SQLITE_READONLY; + } + auto id = sqlite3_value_int64(argv[0]); + auto process = wdataCache_->GetProcessData(static_cast(id)); + constexpr int32_t colOffset = 2; + for (auto i = colOffset; i < argc; i++) { + auto col = i - colOffset; + if (col != NAME) { + continue; + } + const char* name = reinterpret_cast(sqlite3_value_text(argv[i])); + if (name == nullptr) { + process->cmdLine_.clear(); + } else { + process->cmdLine_ = name; + } + break; + } + return SQLITE_OK; +} + +std::unique_ptr ProcessTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ProcessTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, dataCache->ProcessSize()) +{ +} + +ProcessTable::Cursor::~Cursor() {} + +int32_t ProcessTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + case IPID: + FilterId(c.op, argv[i]); + break; + case PID: + FilterIndex(c.col, c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + case IPID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ProcessTable::Cursor::Column(int32_t col) const +{ + const auto& process = dataCache_->GetConstProcessData(CurrentRow()); + switch (col) { + case ID: + case IPID: + sqlite3_result_int64(context_, CurrentRow()); + break; + case TYPE: + sqlite3_result_text(context_, "process", STR_DEFAULT_LEN, nullptr); + break; + case PID: + sqlite3_result_int64(context_, process.pid_); + break; + case NAME: + if (process.cmdLine_.size()) { + sqlite3_result_text(context_, process.cmdLine_.c_str(), static_cast(process.cmdLine_.length()), + nullptr); + } + break; + case START_TS: + if (process.startT_) { + sqlite3_result_int64(context_, static_cast(process.startT_)); + } + break; + case SWITCH_COUNT: + case SWTICH_COUNT: + sqlite3_result_int64(context_, process.switchCount_); + break; + case THREAD_COUNT: + sqlite3_result_int64(context_, process.threadCount_); + break; + case SLICE_COUNT: + sqlite3_result_int64(context_, process.sliceSize_); + break; + case MEM_COUNT: + sqlite3_result_int64(context_, process.memSize_); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +void ProcessTable::Cursor::FilterPid(unsigned char op, uint64_t value) +{ + bool remove = false; + if (indexMap_->HasData()) { + indexMap_->CovertToIndexMap(); + remove = true; + } + const auto& processQueue = dataCache_->GetConstProcessData(); + auto size = processQueue.size(); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) { + if (processQueue[*i].pid_ != value) { + i = indexMap_->rowIndex_.erase(i); + } else { + i++; + } + } + } else { + for (auto i = 0; i < size; i++) { + if (processQueue[i].pid_ == value) { + indexMap_->rowIndex_.push_back(i); + } + } + } + indexMap_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_NE: + if (remove) { + for (auto i = indexMap_->rowIndex_.begin(); i != indexMap_->rowIndex_.end();) { + if (processQueue[*i].pid_ == value) { + i = indexMap_->rowIndex_.erase(i); + } else { + i++; + } + } + } else { + for (auto i = 0; i < size; i++) { + if (processQueue[i].pid_ != value) { + indexMap_->rowIndex_.push_back(i); + } + } + } + indexMap_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: + break; + default: + break; + } // end of switch (op) +} +void ProcessTable::Cursor::FilterIndex(int32_t col, unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + switch (col) { + case PID: + /* code */ + FilterPid(op, static_cast(sqlite3_value_int64(argv))); + break; + + default: + break; + } +} +void ProcessTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/process_table.h b/trace_streamer/src/table/ftrace/process_table.h new file mode 100644 index 0000000000000000000000000000000000000000..ea2e74429f3536419c76e89b2c0eccd7f54f3239 --- /dev/null +++ b/trace_streamer/src/table/ftrace/process_table.h @@ -0,0 +1,50 @@ +/* + * 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 PROCESS_TABLE_H +#define PROCESS_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ProcessTable : public TableBase { +public: + explicit ProcessTable(const TraceDataCache* dataCache); + ~ProcessTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + int32_t Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) override; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + void FilterPid(unsigned char op, uint64_t value); + void FilterIndex(int32_t col, unsigned char op, sqlite3_value* argv); + void FilterId(unsigned char op, sqlite3_value* argv) override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PROCESS_TABLE_H diff --git a/trace_streamer/src/table/ftrace/raw_table.cpp b/trace_streamer/src/table/ftrace/raw_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fba6d44dde9a3220ae6051b6950207dc2e98a31e --- /dev/null +++ b/trace_streamer/src/table/ftrace/raw_table.cpp @@ -0,0 +1,224 @@ +/* + * 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 "raw_table.h" +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, TS, NAME, CPU, INTERNAL_TID }; +enum RawType { RAW_CPU_IDLE = 1, RAW_SCHED_WAKEUP = 2, RAW_SCHED_WAKING = 3 }; +uint32_t GetNameIndex(const std::string& name) +{ + if (name == "cpu_idle") { + return RAW_CPU_IDLE; + } else if (name == "sched_wakeup") { + return RAW_SCHED_WAKEUP; + } else if (name == "sched_waking") { + return RAW_SCHED_WAKING; + } else { + return INVALID_UINT32; + } +} +RawTable::RawTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +RawTable::~RawTable() {} + +void RawTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstRawTableData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void RawTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool RawTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr RawTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +RawTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstRawTableData().Size())), + rawObj_(dataCache->GetConstRawTableData()) +{ +} + +RawTable::Cursor::~Cursor() {} +int32_t RawTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case NAME: + indexMap_->MixRange( + c.op, GetNameIndex(std::string(reinterpret_cast(sqlite3_value_text(argv[i])))), + rawObj_.NameData()); + break; + case TS: + FilterTS(c.op, argv[i], rawObj_.TimeStampData()); + break; + case INTERNAL_TID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + rawObj_.InternalTidsData()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t RawTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TYPE: + sqlite3_result_text(context_, "raw", STR_DEFAULT_LEN, nullptr); + break; + case TS: + sqlite3_result_int64(context_, static_cast(rawObj_.TimeStampData()[CurrentRow()])); + break; + case NAME: { + if (rawObj_.NameData()[CurrentRow()] == RAW_CPU_IDLE) { + sqlite3_result_text(context_, "cpu_idle", STR_DEFAULT_LEN, nullptr); + } else if (rawObj_.NameData()[CurrentRow()] == RAW_SCHED_WAKEUP) { + sqlite3_result_text(context_, "sched_wakeup", STR_DEFAULT_LEN, nullptr); + } else if (rawObj_.NameData()[CurrentRow()] == RAW_SCHED_WAKING) { + sqlite3_result_text(context_, "sched_waking", STR_DEFAULT_LEN, nullptr); + } + break; + } + case CPU: + sqlite3_result_int64(context_, static_cast(rawObj_.CpuData()[CurrentRow()])); + break; + case INTERNAL_TID: + sqlite3_result_int64(context_, static_cast(rawObj_.InternalTidData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/raw_table.h b/trace_streamer/src/table/ftrace/raw_table.h new file mode 100644 index 0000000000000000000000000000000000000000..7128324613cf656e33681ebefcb1bee9d7462120 --- /dev/null +++ b/trace_streamer/src/table/ftrace/raw_table.h @@ -0,0 +1,49 @@ +/* + * 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 RAW_TABLE_H +#define RAW_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class RawTable : public TableBase { +public: + explicit RawTable(const TraceDataCache* dataCache); + ~RawTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const Raw& rawObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // RAW_TABLE_H diff --git a/trace_streamer/src/table/ftrace/sched_slice_table.cpp b/trace_streamer/src/table/ftrace/sched_slice_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ca1d004b9f0d84afb5aae01cb335a84b288ff8a --- /dev/null +++ b/trace_streamer/src/table/ftrace/sched_slice_table.cpp @@ -0,0 +1,270 @@ +/* + * 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 "sched_slice_table.h" + +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, TS, DUR, TS_END, CPU, INTERNAL_TID, INTERNAL_PID, END_STATE, PRIORITY, ARGSETID }; +SchedSliceTable::SchedSliceTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts_end", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_state", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("priority", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("arg_setid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +SchedSliceTable::~SchedSliceTable() {} + +void SchedSliceTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstSchedSliceData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + case TS: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void SchedSliceTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + case TS: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool SchedSliceTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +bool SchedSliceTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr SchedSliceTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SchedSliceTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSchedSliceData().Size())), + schedSliceObj_(dataCache->GetConstSchedSliceData()) +{ +} + +SchedSliceTable::Cursor::~Cursor() {} + +int32_t SchedSliceTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case TS: + FilterTS(c.op, argv[i], schedSliceObj_.TimeStampData()); + break; + case CPU: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), schedSliceObj_.CpusData()); + break; + case INTERNAL_TID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + schedSliceObj_.InternalTidsData()); + break; + case INTERNAL_PID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + schedSliceObj_.InternalPidsData()); + break; + case DUR: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + schedSliceObj_.DursData()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + case TS: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t SchedSliceTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TYPE: + sqlite3_result_text(context_, "sched_slice", STR_DEFAULT_LEN, nullptr); + break; + case TS: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.TimeStampData()[CurrentRow()])); + break; + case DUR: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.DursData()[CurrentRow()])); + break; + case TS_END: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.TsEndData()[CurrentRow()])); + break; + case CPU: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.CpusData()[CurrentRow()])); + break; + case INTERNAL_TID: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.InternalTidsData()[CurrentRow()])); + break; + case INTERNAL_PID: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.InternalPidsData()[CurrentRow()])); + break; + case END_STATE: { + const std::string& str = dataCache_->GetConstSchedStateData(schedSliceObj_.EndStatesData()[CurrentRow()]); + sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case PRIORITY: + sqlite3_result_int64(context_, static_cast(schedSliceObj_.PriorityData()[CurrentRow()])); + break; + case ARGSETID: { + const uint32_t& argSetId = schedSliceObj_.ArgSetData()[CurrentRow()]; + if (argSetId != INVALID_UINT32) { + sqlite3_result_int(context_, argSetId); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/sched_slice_table.h b/trace_streamer/src/table/ftrace/sched_slice_table.h new file mode 100644 index 0000000000000000000000000000000000000000..b6986e7a09d4492d390d434b92980410fd8b895c --- /dev/null +++ b/trace_streamer/src/table/ftrace/sched_slice_table.h @@ -0,0 +1,52 @@ +/* + * 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 SCHED_SLICE_TABLE_H +#define SCHED_SLICE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SchedSliceTable : public TableBase { +public: + explicit SchedSliceTable(const TraceDataCache* dataCache); + ~SchedSliceTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + private: + const SchedSlice& schedSliceObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SCHED_SLICE_TABLE_H diff --git a/trace_streamer/src/table/ftrace/system_call_table.cpp b/trace_streamer/src/table/ftrace/system_call_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27438d6e7bbf6a7183750ec4178a4312ee11cd59 --- /dev/null +++ b/trace_streamer/src/table/ftrace/system_call_table.cpp @@ -0,0 +1,72 @@ +/* + * 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 "system_call_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { SYSCALL_NUM = 0, TYPE, IPID, TS, RET }; +SystemCallTable::SystemCallTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("syscall_num", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ret", "INTEGER")); + tablePriKey_.push_back("syscall_num"); +} + +SystemCallTable::~SystemCallTable() {} + +std::unique_ptr SystemCallTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SystemCallTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSysCallData().Size())), + sysCallObj_(dataCache->GetConstSysCallData()) +{ +} + +SystemCallTable::Cursor::~Cursor() {} + +int32_t SystemCallTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case SYSCALL_NUM: + sqlite3_result_int64(context_, dataCache_->GetConstSysCallData().SysCallsData()[CurrentRow()]); + break; + case TYPE: + sqlite3_result_text(context_, dataCache_->GetDataFromDict(sysCallObj_.TypesData()[CurrentRow()]).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case IPID: + sqlite3_result_int64(context_, dataCache_->GetConstSysCallData().IpidsData()[CurrentRow()]); + break; + case TS: + sqlite3_result_int64(context_, dataCache_->GetConstSysCallData().TimeStampData()[CurrentRow()]); + break; + case RET: + sqlite3_result_int64(context_, dataCache_->GetConstSysCallData().RetsData()[CurrentRow()]); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/system_call_table.h b/trace_streamer/src/table/ftrace/system_call_table.h new file mode 100644 index 0000000000000000000000000000000000000000..ae9afb2e8b25a63439ee5c664cb4bea2565ffa44 --- /dev/null +++ b/trace_streamer/src/table/ftrace/system_call_table.h @@ -0,0 +1,52 @@ +/* + * 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 SYSCALL_TABLE_H +#define SYSCALL_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SystemCallTable : public TableBase { +public: + explicit SystemCallTable(const TraceDataCache*); + ~SystemCallTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const SysCall& sysCallObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PROCESS_TABLE_H diff --git a/trace_streamer/src/table/ftrace/system_event_filter_table.cpp b/trace_streamer/src/table/ftrace/system_event_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c669786d71285373c5ace71d9a4d64cd99fbedfc --- /dev/null +++ b/trace_streamer/src/table/ftrace/system_event_filter_table.cpp @@ -0,0 +1,225 @@ +/* + * 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 "system_event_filter_table.h" + +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME }; +SystemEventFilterTable::SystemEventFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tablePriKey_.push_back("id"); +} + +SystemEventFilterTable::~SystemEventFilterTable() {} + +void SystemEventFilterTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstSysMeasureFilterData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void SystemEventFilterTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool SystemEventFilterTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr SystemEventFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SystemEventFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSysMeasureFilterData().Size())), + sysEventObj_(dataCache->GetConstSysMeasureFilterData()) +{ +} + +SystemEventFilterTable::Cursor::~Cursor() {} + +int32_t SystemEventFilterTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterSorted(c.col, c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t SystemEventFilterTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, sysEventObj_.IdsData()[CurrentRow()]); + break; + case TYPE: + sqlite3_result_text(context_, dataCache_->GetDataFromDict(sysEventObj_.TypesData()[CurrentRow()]).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + case NAME: + sqlite3_result_text(context_, dataCache_->GetDataFromDict(sysEventObj_.NamesData()[CurrentRow()]).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +void SystemEventFilterTable::Cursor::FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL, filter out nothing + indexMap_->Intersect(0, 0); + return; + } + + switch (col) { + case ID: { + auto v = static_cast(sqlite3_value_int64(argv)); + auto getValue = [](const uint32_t& row) { return row; }; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->IntersectabcEqual(sysEventObj_.IdsData(), v, getValue); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + case SQLITE_INDEX_CONSTRAINT_GE: { + indexMap_->IntersectGreaterEqual(sysEventObj_.IdsData(), v, getValue); + break; + } + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + case SQLITE_INDEX_CONSTRAINT_LT: { + indexMap_->IntersectLessEqual(sysEventObj_.IdsData(), v, getValue); + break; + } + default: + break; + } // end of switch (op) + } // end of case TS + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/system_event_filter_table.h b/trace_streamer/src/table/ftrace/system_event_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..f439f9273af28a4fb1260463b2229765c7e8c433 --- /dev/null +++ b/trace_streamer/src/table/ftrace/system_event_filter_table.h @@ -0,0 +1,51 @@ +/* + * 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 SYSTEM_EVENT_FILTER_TABLE_H +#define SYSTEM_EVENT_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SystemEventFilterTable : public TableBase { +public: + explicit SystemEventFilterTable(const TraceDataCache*); + ~SystemEventFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + void FilterSorted(int32_t col, unsigned char op, sqlite3_value* argv); + + private: + const SysMeasureFilter& sysEventObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SYSTEM_EVENT_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/thread_filter_table.cpp b/trace_streamer/src/table/ftrace/thread_filter_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3698e7657a8f70b8956dc58be4523deb22500288 --- /dev/null +++ b/trace_streamer/src/table/ftrace/thread_filter_table.cpp @@ -0,0 +1,71 @@ +/* + * 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 "thread_filter_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, NAME, INTERNAL_TID }; +ThreadFilterTable::ThreadFilterTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ThreadFilterTable::~ThreadFilterTable() {} + +std::unique_ptr ThreadFilterTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ThreadFilterTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstThreadFilterData().Size())) +{ +} + +ThreadFilterTable::Cursor::~Cursor() {} + +int32_t ThreadFilterTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast( + dataCache_->GetConstThreadFilterData().FilterIdData()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_text(context_, "thread_filter", STR_DEFAULT_LEN, nullptr); + break; + case NAME: { + std::string str = + dataCache_->GetDataFromDict(dataCache_->GetConstThreadFilterData().NameIndexData()[CurrentRow()]); + sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case INTERNAL_TID: + sqlite3_result_int64(context_, static_cast( + dataCache_->GetConstThreadFilterData().InternalTidData()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/thread_filter_table.h b/trace_streamer/src/table/ftrace/thread_filter_table.h new file mode 100644 index 0000000000000000000000000000000000000000..439640da400a51a84f2c3851d5cebf63cbd80651 --- /dev/null +++ b/trace_streamer/src/table/ftrace/thread_filter_table.h @@ -0,0 +1,50 @@ +/* + * 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 THREAD_FILTER_TABLE_H +#define THREAD_FILTER_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ThreadFilterTable : public TableBase { +public: + explicit ThreadFilterTable(const TraceDataCache* dataCache); + ~ThreadFilterTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // THREAD_FILTER_TABLE_H diff --git a/trace_streamer/src/table/ftrace/thread_state_table.cpp b/trace_streamer/src/table/ftrace/thread_state_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfbc7b80fcf1bc191299704ed943a7c401eb1515 --- /dev/null +++ b/trace_streamer/src/table/ftrace/thread_state_table.cpp @@ -0,0 +1,286 @@ +/* + * 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 "thread_state_table.h" +#include "thread_state.h" + +#include + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TYPE, TS, DUR, CPU, INTERNAL_TID, TID, PID, STATE, ARGSETID }; +ThreadStateTable::ThreadStateTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("tid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("state", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("arg_setid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ThreadStateTable::~ThreadStateTable() {} + +void ThreadStateTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstThreadStateData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + case TS: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ThreadStateTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + case TS: { + auto oldRowCount = rowCount; + if (CanFilterSorted(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += log2(oldRowCount); // binary search + } else { + filterCost += oldRowCount; + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ThreadStateTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +bool ThreadStateTable::CanFilterSorted(const char op, size_t& rowCount) const +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = rowCount / log2(rowCount); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr ThreadStateTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ThreadStateTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, dataCache->GetConstThreadStateData().Size()), + threadStateObj_(dataCache->GetConstThreadStateData()) +{ +} + +ThreadStateTable::Cursor::~Cursor() {} + +int32_t ThreadStateTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset + if (rowCount_ <= 0) { + return SQLITE_OK; + } + IndexMap* indexMapBack = indexMap_.get(); + if (indexMap_->HasData()) { + indexMapBack = std::make_unique(0, rowCount_).get(); + } + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + indexMapBack->FilterId(c.op, argv[i]); + break; + case TS: + indexMapBack->FilterTS(c.op, argv[i], threadStateObj_.TimeStamsData()); + break; + case INTERNAL_TID: + indexMapBack->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + threadStateObj_.ItidsData()); + break; + case TID: + indexMapBack->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + threadStateObj_.TidsData()); + break; + case PID: + indexMapBack->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + threadStateObj_.PidsData()); + break; + case DUR: + indexMapBack->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + threadStateObj_.DursData()); + break; + case CPU: + indexMapBack->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + threadStateObj_.CpusData()); + break; + case STATE: + indexMapBack->MixRange(c.op, + static_cast(dataCache_->GetThreadStateValue( + std::string(reinterpret_cast(sqlite3_value_text(argv[i]))))), + threadStateObj_.StatesData()); + break; + case ARGSETID: + indexMapBack->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), + threadStateObj_.ArgSetsData()); + break; + default: + break; + } + } + if (indexMap_->HasData()) { + indexMap_->Merge(indexMapBack); + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + case TS: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ThreadStateTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TYPE: + sqlite3_result_text(context_, "thread_state", STR_DEFAULT_LEN, nullptr); + break; + case TS: + sqlite3_result_int64(context_, static_cast(threadStateObj_.TimeStamsData()[CurrentRow()])); + break; + case DUR: + sqlite3_result_int64(context_, static_cast(threadStateObj_.DursData()[CurrentRow()])); + break; + case CPU: + if (threadStateObj_.CpusData()[CurrentRow()] != INVALID_CPU) { + sqlite3_result_int64(context_, static_cast(threadStateObj_.CpusData()[CurrentRow()])); + } + break; + case INTERNAL_TID: + sqlite3_result_int64(context_, static_cast(threadStateObj_.ItidsData()[CurrentRow()])); + break; + case TID: + sqlite3_result_int64(context_, static_cast(threadStateObj_.TidsData()[CurrentRow()])); + break; + case PID: + sqlite3_result_int64(context_, static_cast(threadStateObj_.PidsData()[CurrentRow()])); + break; + case STATE: { + const std::string& str = dataCache_->GetConstSchedStateData(threadStateObj_.StatesData()[CurrentRow()]); + sqlite3_result_text(context_, str.c_str(), STR_DEFAULT_LEN, nullptr); + break; + } + case ARGSETID: + if (threadStateObj_.ArgSetsData()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(threadStateObj_.ArgSetsData()[CurrentRow()])); + } + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/thread_state_table.h b/trace_streamer/src/table/ftrace/thread_state_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6f8ecef06e493249439954ce92fc6ca94c7eb4d9 --- /dev/null +++ b/trace_streamer/src/table/ftrace/thread_state_table.h @@ -0,0 +1,51 @@ +/* + * 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 THREAD_STATE_TABLE_H +#define THREAD_STATE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ThreadStateTable : public TableBase { +public: + explicit ThreadStateTable(const TraceDataCache* dataCache); + ~ThreadStateTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + // the column is sorted + bool CanFilterSorted(const char op, size_t& rowCount) const; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + private: + const ThreadState& threadStateObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // THREAD_STATE_TABLE_H diff --git a/trace_streamer/src/table/ftrace/thread_table.cpp b/trace_streamer/src/table/ftrace/thread_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3776df1e58d0d25f436248f457692ece4068d10f --- /dev/null +++ b/trace_streamer/src/table/ftrace/thread_table.cpp @@ -0,0 +1,541 @@ +/* + * 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 "thread_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, ITID, TYPE, TID, NAME, START_TS, END_TS, INTERNAL_PID, IS_MAIN_THREAD, SWITCH_COUNT }; +ThreadTable::ThreadTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("tid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("is_main_thread", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("switch_count", "INTEGER")); + tablePriKey_.push_back("id"); +} + +ThreadTable::~ThreadTable() {} + +void ThreadTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->ThreadSize(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ITID: + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void ThreadTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ITID: + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool ThreadTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr ThreadTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +ThreadTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, dataCache->ThreadSize()) +{ +} + +ThreadTable::Cursor::~Cursor() {} +void ThreadTable::Cursor::FilterTid(unsigned char op, uint64_t value) +{ + bool remove = false; + if (indexMapBack_->HasData()) { + indexMapBack_->CovertToIndexMap(); + remove = true; + } + const auto& threadQueue = dataCache_->GetConstThreadData(); + auto size = threadQueue.size(); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].tid_ != value) { + i = indexMapBack_->rowIndex_.erase(i); + } else { + i++; + } + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].tid_ == value) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOT: + case SQLITE_INDEX_CONSTRAINT_NE: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].tid_ == value) { + i = indexMapBack_->rowIndex_.erase(i); + } else { + i++; + } + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].tid_ != value) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + default: + break; + } // end of switch (op) +} +void ThreadTable::Cursor::FilterIpid(unsigned char op, uint64_t value) +{ + bool remove = false; + if (indexMapBack_->HasData()) { + indexMapBack_->CovertToIndexMap(); + remove = true; + } + const auto& threadQueue = dataCache_->GetConstThreadData(); + auto size = threadQueue.size(); + rowIndexBak_.clear(); + bool changed = false; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].internalPid_ != value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + indexMapBack_->rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].internalPid_ == value) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNULL: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].internalPid_ != INVALID_UINT32) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + indexMapBack_->rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].internalPid_ == INVALID_UINT32) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].internalPid_ == INVALID_UINT32) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + indexMapBack_->rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].internalPid_ != INVALID_UINT32) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + default: + break; + } // end of switch (op) +} +void ThreadTable::Cursor::FilterSwitchCount(unsigned char op, uint64_t value) +{ + bool remove = false; + if (indexMapBack_->HasData()) { + indexMapBack_->CovertToIndexMap(); + remove = true; + } + const auto& threadQueue = dataCache_->GetConstThreadData(); + auto size = threadQueue.size(); + rowIndexBak_.clear(); + bool changed = false; + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].switchCount_ != value) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + indexMapBack_->rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].switchCount_ == value) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNULL: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].switchCount_ != INVALID_UINT32) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + indexMapBack_->rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].switchCount_ == INVALID_UINT32) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: + if (remove) { + for (auto i = indexMapBack_->rowIndex_.begin(); i != indexMapBack_->rowIndex_.end();) { + if (threadQueue[*i].switchCount_ == INVALID_UINT32) { + i++; + } else { + changed = true; + rowIndexBak_.push_back(*i); + i++; + } + } + if (changed) { + indexMapBack_->rowIndex_ = rowIndexBak_; + } + } else { + for (auto i = 0; i < size; i++) { + if (threadQueue[i].switchCount_ != INVALID_UINT32) { + indexMapBack_->rowIndex_.push_back(i); + } + } + } + indexMapBack_->FixSize(); + break; + default: + break; + } // end of switch (op) +} +void ThreadTable::Cursor::FilterIndex(int32_t col, unsigned char op, sqlite3_value* argv) +{ + switch (col) { + case INTERNAL_PID: + FilterIpid(op, static_cast(sqlite3_value_int64(argv))); + break; + case TID: + FilterTid(op, static_cast(sqlite3_value_int64(argv))); + break; + case SWITCH_COUNT: + FilterSwitchCount(op, static_cast(sqlite3_value_int64(argv))); + break; + default: + // we can't filter all rows + break; + } +} +int32_t ThreadTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMapBack_ + if (rowCount_ <= 0) { + return SQLITE_OK; + } + indexMapBack_ = indexMap_.get(); + if (indexMap_->HasData()) { + indexMapBack_ = std::make_unique(0, rowCount_).get(); + } + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + case ITID: + FilterId(c.op, argv[i]); + break; + case TID: + case INTERNAL_PID: + case SWITCH_COUNT: + FilterIndex(c.col, c.op, argv[i]); + break; + default: + break; + } + } + if (indexMap_->HasData()) { + indexMap_->Merge(indexMapBack_); + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + case ITID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t ThreadTable::Cursor::Column(int32_t col) const +{ + const auto& thread = dataCache_->GetConstThreadData(CurrentRow()); + switch (col) { + case ID: + case ITID: { + sqlite3_result_int64(context_, CurrentRow()); + break; + } + case TYPE: { + sqlite3_result_text(context_, "thread", strlen("thread"), nullptr); + break; + } + case TID: { + sqlite3_result_int64(context_, static_cast(thread.tid_)); + break; + } + case NAME: { + const auto& name = dataCache_->GetDataFromDict(thread.nameIndex_); + if (name.size()) { + sqlite3_result_text(context_, name.c_str(), static_cast(name.length()), nullptr); + } + break; + } + case START_TS: { + if (thread.startT_) { + sqlite3_result_int64(context_, static_cast(thread.startT_)); + } + break; + } + case END_TS: { + if (thread.endT_) { + sqlite3_result_int64(context_, static_cast(thread.endT_)); + } + break; + } + case INTERNAL_PID: { + if (thread.internalPid_ != INVALID_UINT32) { + sqlite3_result_int(context_, static_cast(thread.internalPid_)); + } + break; + } + case IS_MAIN_THREAD: { + // When it is not clear which process the thread belongs to, is_main_thread should be set to null + if (thread.internalPid_ == INVALID_UINT32) { + break; + } + const auto& process = dataCache_->GetConstProcessData(thread.internalPid_); + sqlite3_result_int(context_, thread.tid_ == process.pid_); + break; + } + case SWITCH_COUNT: { + // When it is not clear which process the thread belongs to, is_main_thread should be set to null + sqlite3_result_int(context_, thread.switchCount_); + break; + } + + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +int32_t ThreadTable::Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) +{ + if (argc <= 1) { + return SQLITE_READONLY; + } + if (sqlite3_value_type(argv[0]) == SQLITE_NULL) { + return SQLITE_READONLY; + } + auto id = sqlite3_value_int64(argv[0]); + auto thread = wdataCache_->GetThreadData(static_cast(id)); + constexpr int32_t colOffset = 2; + for (auto i = colOffset; i < argc; i++) { + auto col = i - colOffset; + if (col != INTERNAL_PID) { + continue; + } + auto ipid = static_cast(sqlite3_value_int(argv[i])); + if (ipid) { + thread->internalPid_ = ipid; + } + break; + } + return SQLITE_OK; +} +void ThreadTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMapBack_->Intersect(0, 0); + return; + } + + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMapBack_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMapBack_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMapBack_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMapBack_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMapBack_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/ftrace/thread_table.h b/trace_streamer/src/table/ftrace/thread_table.h new file mode 100644 index 0000000000000000000000000000000000000000..e48f9c2611f3f2d4b2555f101cbc30ad45433df1 --- /dev/null +++ b/trace_streamer/src/table/ftrace/thread_table.h @@ -0,0 +1,58 @@ +/* + * 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 SRC_THREAD_TABLE_H +#define SRC_THREAD_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class ThreadTable : public TableBase { +public: + explicit ThreadTable(const TraceDataCache* dataCache); + ~ThreadTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + int32_t Update(int32_t argc, sqlite3_value** argv, sqlite3_int64* pRowid) override; + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + void FilterIpid(unsigned char op, uint64_t value); + void FilterTid(unsigned char op, uint64_t value); + void FilterSwitchCount(unsigned char op, uint64_t value); + void FilterIndex(int32_t col, unsigned char op, sqlite3_value* argv); + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t col) const override; + + void FilterId(unsigned char op, sqlite3_value* argv) override; + + private: + std::vector rowIndexBak_; + IndexMap* indexMapBack_ = nullptr; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // SRC_THREAD_TABLE_H diff --git a/trace_streamer/src/table/hi_sysevent/BUILD.gn b/trace_streamer/src/table/hi_sysevent/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..11c4a69f66988592419e924f16de235965582394 --- /dev/null +++ b/trace_streamer/src/table/hi_sysevent/BUILD.gn @@ -0,0 +1,52 @@ +# 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("//src/ts.gni") +ohos_source_set("hi_sysevent_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "device_state_table.cpp", + "device_state_table.h", + "sysevent_measure_table.cpp", + "sysevent_measure_table.h", + ] + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/hi_sysevent/device_state_table.cpp b/trace_streamer/src/table/hi_sysevent/device_state_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..232b4d7ffef2af611dcd5332630878043bc5fa31 --- /dev/null +++ b/trace_streamer/src/table/hi_sysevent/device_state_table.cpp @@ -0,0 +1,158 @@ + +/* + * 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 "device_state_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + BRIGHTNESS, + BT_STATE, + LOCATION, + WIFI, + STREAM_DEFAULT, + VOICE_CALL, + MUSIC, + STREAM_RING, + MEDIA, + VOICE_ASSISTANT, + SYSTEM, + ALARM, + NOTIFICATION, + BT_SCO, + ENFORCED_AUDIBLE, + STREAM_DTMF, + STREAM_TTS, + ACCESSIBILITY, + RECORDING, + STREAM_ALL +}; +DeviceStateTable::DeviceStateTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("brightness", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("bt_state", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("location", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("wifi", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("stream_default", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("voice_call", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("music", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("stream_ring", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("media", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("voice_assistant", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("system", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("alarm", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("notification", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("bt_sco", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("enforced_audible", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("stream_dtmf", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("stream_tts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("accessibility", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("recording", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("stream_all", "INTEGER")); + tablePriKey_.push_back("id"); +} + +DeviceStateTable::~DeviceStateTable() {} + +std::unique_ptr DeviceStateTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +DeviceStateTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstDeviceStateData().Size())), + deviceStateData_(dataCache->GetConstDeviceStateData()) +{ +} + +DeviceStateTable::Cursor::~Cursor() {} + +int32_t DeviceStateTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, dataCache_->GetConstDeviceStateData().IdsData()[CurrentRow()]); + break; + case BRIGHTNESS: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Brightness()[CurrentRow()]); + break; + case BT_STATE: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().BtState()[CurrentRow()]); + break; + case LOCATION: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Location()[CurrentRow()]); + break; + case WIFI: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Wifi()[CurrentRow()]); + break; + case STREAM_DEFAULT: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().StreamDefault()[CurrentRow()]); + break; + case VOICE_CALL: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().VoiceCall()[CurrentRow()]); + break; + case MUSIC: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Music()[CurrentRow()]); + break; + case STREAM_RING: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().StreamRing()[CurrentRow()]); + break; + case MEDIA: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Media()[CurrentRow()]); + break; + case VOICE_ASSISTANT: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().VoiceAssistant()[CurrentRow()]); + break; + case SYSTEM: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().System()[CurrentRow()]); + break; + case ALARM: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Alarm()[CurrentRow()]); + break; + case NOTIFICATION: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Notification()[CurrentRow()]); + break; + case BT_SCO: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().BtSco()[CurrentRow()]); + break; + case ENFORCED_AUDIBLE: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().EnforcedAudible()[CurrentRow()]); + break; + case STREAM_DTMF: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().StreamDtmf()[CurrentRow()]); + break; + case STREAM_TTS: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().StreamTts()[CurrentRow()]); + break; + case ACCESSIBILITY: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Accessibility()[CurrentRow()]); + break; + case RECORDING: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().Recording()[CurrentRow()]); + break; + case STREAM_ALL: + sqlite3_result_int(context_, dataCache_->GetConstDeviceStateData().StreamAll()[CurrentRow()]); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hi_sysevent/device_state_table.h b/trace_streamer/src/table/hi_sysevent/device_state_table.h new file mode 100644 index 0000000000000000000000000000000000000000..d354464c5c2b1b0a826d2133a1e07d0b30a8e9f0 --- /dev/null +++ b/trace_streamer/src/table/hi_sysevent/device_state_table.h @@ -0,0 +1,52 @@ +/* + * 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 DEVICE_STATE_TABLE_H +#define DEVICE_STATE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class DeviceStateTable : public TableBase { +public: + explicit DeviceStateTable(const TraceDataCache*); + ~DeviceStateTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const DeviceStateData& deviceStateData_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // DEVICE_STATE__TABLE_H diff --git a/trace_streamer/src/table/hi_sysevent/sysevent_measure_table.cpp b/trace_streamer/src/table/hi_sysevent/sysevent_measure_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9db9ceffaba74fd6be99f87b37cacef7f755d69 --- /dev/null +++ b/trace_streamer/src/table/hi_sysevent/sysevent_measure_table.cpp @@ -0,0 +1,85 @@ +/* + * 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 "sysevent_measure_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, SERIAL, TS, NAME_ID, KEY_ID, TYPE, INT_VALUE, STRING_VALUE }; +SysEventMeasureTable::SysEventMeasureTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("serial", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("key_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("int_value", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("string_value", "TEXT")); + tablePriKey_.push_back("id"); +} + +SysEventMeasureTable::~SysEventMeasureTable() {} + +std::unique_ptr SysEventMeasureTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SysEventMeasureTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSyseventMeasureData().Size())), + sysEventMeasure_(dataCache->GetConstSyseventMeasureData()) +{ +} + +SysEventMeasureTable::Cursor::~Cursor() {} + +int32_t SysEventMeasureTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, dataCache_->GetConstSyseventMeasureData().IdsData()[CurrentRow()]); + break; + case SERIAL: + sqlite3_result_int64(context_, dataCache_->GetConstSyseventMeasureData().Serial()[CurrentRow()]); + break; + case TS: + sqlite3_result_int64(context_, dataCache_->GetConstSyseventMeasureData().Ts()[CurrentRow()]); + break; + case NAME_ID: + sqlite3_result_int(context_, dataCache_->GetConstSyseventMeasureData().NameFilterId()[CurrentRow()]); + break; + case KEY_ID: + sqlite3_result_int(context_, dataCache_->GetConstSyseventMeasureData().AppKeyFilterId()[CurrentRow()]); + break; + case TYPE: + sqlite3_result_int(context_, dataCache_->GetConstSyseventMeasureData().Type()[CurrentRow()]); + break; + case INT_VALUE: + sqlite3_result_double(context_, dataCache_->GetConstSyseventMeasureData().NumValue()[CurrentRow()]); + break; + case STRING_VALUE: + sqlite3_result_text(context_, + dataCache_->GetDataFromDict(sysEventMeasure_.StringValue()[CurrentRow()]).c_str(), + STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hi_sysevent/sysevent_measure_table.h b/trace_streamer/src/table/hi_sysevent/sysevent_measure_table.h new file mode 100644 index 0000000000000000000000000000000000000000..0f49f3887da502f7d4c082d3edc94ad807d7f899 --- /dev/null +++ b/trace_streamer/src/table/hi_sysevent/sysevent_measure_table.h @@ -0,0 +1,52 @@ +/* + * 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 SYSEVENT_MEASURE_TABLE_H +#define SYSEVENT_MEASURE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SysEventMeasureTable : public TableBase { +public: + explicit SysEventMeasureTable(const TraceDataCache*); + ~SysEventMeasureTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const SysEventMeasureData& sysEventMeasure_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SYSEVENT_MEASURE_TABLE_H diff --git a/trace_streamer/src/table/hiperf/BUILD.gn b/trace_streamer/src/table/hiperf/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..4f26399d62744684cf47d8669b50fee854b8da3a --- /dev/null +++ b/trace_streamer/src/table/hiperf/BUILD.gn @@ -0,0 +1,59 @@ +# 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("//src/ts.gni") +ohos_source_set("hiperf_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "perf_call_chain_table.cpp", + "perf_call_chain_table.h", + "perf_files_table.cpp", + "perf_files_table.h", + "perf_report_table.cpp", + "perf_report_table.h", + "perf_sample_table.cpp", + "perf_sample_table.h", + "perf_thread_table.cpp", + "perf_thread_table.h", + ] + + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/hiperf/perf_call_chain_table.cpp b/trace_streamer/src/table/hiperf/perf_call_chain_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e3c0d1ad2924dd2ce514b9c17c15e53181467b1 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_call_chain_table.cpp @@ -0,0 +1,210 @@ +/* + * 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 "perf_call_chain_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, CALLCHAIN_ID, DEPTH, VADDR_IN_FILE, FILE_ID, SYMBOL_ID, NAME }; +PerfCallChainTable::PerfCallChainTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("vaddr_in_file", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("symbol_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "TEXT")); + tablePriKey_.push_back("id"); +} + +PerfCallChainTable::~PerfCallChainTable() {} + +void PerfCallChainTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstPerfCallChainData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void PerfCallChainTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool PerfCallChainTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr PerfCallChainTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +PerfCallChainTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstPerfCallChainData().Size())), + perfCallChainObj_(dataCache->GetConstPerfCallChainData()) +{ +} + +PerfCallChainTable::Cursor::~Cursor() {} + +int32_t PerfCallChainTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case CALLCHAIN_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + perfCallChainObj_.SampleIds()); + break; + case FILE_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + perfCallChainObj_.FileIds()); + break; + case SYMBOL_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + perfCallChainObj_.SymbolIds()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t PerfCallChainTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(perfCallChainObj_.IdsData()[CurrentRow()])); + break; + case CALLCHAIN_ID: + sqlite3_result_int64(context_, static_cast(perfCallChainObj_.SampleIds()[CurrentRow()])); + break; + case DEPTH: + sqlite3_result_int64(context_, static_cast(perfCallChainObj_.CallChainIds()[CurrentRow()])); + break; + case VADDR_IN_FILE: + sqlite3_result_int64(context_, static_cast(perfCallChainObj_.VaddrInFiles()[CurrentRow()])); + break; + case FILE_ID: + sqlite3_result_int64(context_, static_cast(perfCallChainObj_.FileIds()[CurrentRow()])); + break; + case SYMBOL_ID: + sqlite3_result_int64(context_, static_cast(perfCallChainObj_.SymbolIds()[CurrentRow()])); + break; + case NAME: + sqlite3_result_text(context_, perfCallChainObj_.Names()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hiperf/perf_call_chain_table.h b/trace_streamer/src/table/hiperf/perf_call_chain_table.h new file mode 100644 index 0000000000000000000000000000000000000000..44c8e9957ea4096145ef5e35e384547e86d7d1d5 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_call_chain_table.h @@ -0,0 +1,49 @@ +/* + * 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 PERF_CALL_CHAIN_TABLE_H +#define PERF_CALL_CHAIN_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class PerfCallChainTable : public TableBase { +public: + explicit PerfCallChainTable(const TraceDataCache* dataCache); + ~PerfCallChainTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const PerfCallChain& perfCallChainObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PERF_CALL_CHAIN_TABLE_H diff --git a/trace_streamer/src/table/hiperf/perf_files_table.cpp b/trace_streamer/src/table/hiperf/perf_files_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1c68c0e60c19bb558c496f6a4c6ed4e17b9598e --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_files_table.cpp @@ -0,0 +1,200 @@ +/* + * 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 "perf_files_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, FILE_ID, SERIAL_ID, SYMBOL, PATH }; +PerfFilesTable::PerfFilesTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("serial_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("symbol", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("path", "TEXT")); + tablePriKey_.push_back("id"); +} + +PerfFilesTable::~PerfFilesTable() {} + +void PerfFilesTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstPerfFilesData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void PerfFilesTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool PerfFilesTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr PerfFilesTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +PerfFilesTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstPerfFilesData().Size())), + perfFilesObj_(dataCache->GetConstPerfFilesData()) +{ +} + +PerfFilesTable::Cursor::~Cursor() {} + +int32_t PerfFilesTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case FILE_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), perfFilesObj_.FileIds()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t PerfFilesTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(perfFilesObj_.IdsData()[CurrentRow()])); + break; + case FILE_ID: + sqlite3_result_int64(context_, static_cast(perfFilesObj_.FileIds()[CurrentRow()])); + break; + case SERIAL_ID: + sqlite3_result_int(context_, static_cast(perfFilesObj_.Serials()[CurrentRow()])); + break; + case SYMBOL: + if (perfFilesObj_.Symbols()[CurrentRow()] != INVALID_UINT64) { + auto symbolIndex = static_cast(perfFilesObj_.Symbols()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(symbolIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + case PATH: + if (perfFilesObj_.FilePaths()[CurrentRow()] != INVALID_UINT64) { + auto pathIndex = static_cast(perfFilesObj_.FilePaths()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(pathIndex).c_str(), STR_DEFAULT_LEN, nullptr); + } + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hiperf/perf_files_table.h b/trace_streamer/src/table/hiperf/perf_files_table.h new file mode 100644 index 0000000000000000000000000000000000000000..ff302b243e24a2ce892cd42d6a4adc527bc88cf2 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_files_table.h @@ -0,0 +1,49 @@ +/* + * 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 PERF_FILES_TABLE_H +#define PERF_FILES_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class PerfFilesTable : public TableBase { +public: + explicit PerfFilesTable(const TraceDataCache* dataCache); + ~PerfFilesTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const PerfFiles& perfFilesObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PERF_FILES_TABLE_H diff --git a/trace_streamer/src/table/hiperf/perf_report_table.cpp b/trace_streamer/src/table/hiperf/perf_report_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..565dee6c816e609c06e19cd894ea1cb412ecd6c6 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_report_table.cpp @@ -0,0 +1,74 @@ +/* + * 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 "perf_report_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + REPORT_TYPE, + REPORT_VALUE, +}; +PerfReportTable::PerfReportTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("report_type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("report_value", "TEXT")); + tablePriKey_.push_back("id"); +} + +PerfReportTable::~PerfReportTable() {} + +std::unique_ptr PerfReportTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +PerfReportTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstPerfReportData().Size())), + perfReportObj_(dataCache->GetConstPerfReportData()) +{ +} + +PerfReportTable::Cursor::~Cursor() {} + +int32_t PerfReportTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(perfReportObj_.IdsData()[CurrentRow()])); + break; + case REPORT_TYPE: + if (perfReportObj_.Types()[CurrentRow()] != INVALID_UINT64) { + auto typeIndex = static_cast(perfReportObj_.Types()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(typeIndex).c_str(), STR_DEFAULT_LEN, nullptr); + } + break; + case REPORT_VALUE: + if (perfReportObj_.Values()[CurrentRow()] != INVALID_UINT64) { + auto typeValueIndex = static_cast(perfReportObj_.Values()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(typeValueIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hiperf/perf_report_table.h b/trace_streamer/src/table/hiperf/perf_report_table.h new file mode 100644 index 0000000000000000000000000000000000000000..8a0b504bff36e7dc4a3a7bbdc91e37705602fd1b --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_report_table.h @@ -0,0 +1,51 @@ +/* + * 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 PERF_REPORT_TABLE_H +#define PERF_REPORT_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class PerfReportTable : public TableBase { +public: + explicit PerfReportTable(const TraceDataCache* dataCache); + ~PerfReportTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override{}; + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t column) const override; + + private: + const PerfReport& perfReportObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PERF_REPORT_TABLE_H diff --git a/trace_streamer/src/table/hiperf/perf_sample_table.cpp b/trace_streamer/src/table/hiperf/perf_sample_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bef531d405eb2f344547ab5fc23f84126c82c6a7 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_sample_table.cpp @@ -0,0 +1,237 @@ +/* + * 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 "perf_sample_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + CALLCHAIN_ID, + TIMESTAMP, + THREAD_ID, + EVENT_COUNT, + EVENT_TYPE_ID, + TIMESTAMP_TRACE, + CPU_ID, + THREAD_STATE +}; +PerfSampleTable::PerfSampleTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("timeStamp", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("thread_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("event_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("event_type_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("timestamp_trace", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("thread_state", "TEXT")); + tablePriKey_.push_back("id"); +} + +PerfSampleTable::~PerfSampleTable() {} + +void PerfSampleTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstPerfSampleData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void PerfSampleTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool PerfSampleTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr PerfSampleTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +PerfSampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstPerfSampleData().Size())), + perfSampleObj_(dataCache->GetConstPerfSampleData()) +{ +} + +PerfSampleTable::Cursor::~Cursor() {} + +int32_t PerfSampleTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case CALLCHAIN_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + perfSampleObj_.SampleIds()); + break; + case THREAD_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), perfSampleObj_.Tids()); + break; + case EVENT_TYPE_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + perfSampleObj_.EventTypeIds()); + break; + case CPU_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), perfSampleObj_.CpuIds()); + break; + default: + break; + } + } + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t PerfSampleTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.IdsData()[CurrentRow()])); + break; + case CALLCHAIN_ID: + if (perfSampleObj_.SampleIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(perfSampleObj_.SampleIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case TIMESTAMP: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.TimeStampData()[CurrentRow()])); + break; + case THREAD_ID: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.Tids()[CurrentRow()])); + break; + case EVENT_COUNT: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.EventCounts()[CurrentRow()])); + break; + case EVENT_TYPE_ID: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.EventTypeIds()[CurrentRow()])); + break; + case TIMESTAMP_TRACE: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.TimestampTraces()[CurrentRow()])); + break; + case CPU_ID: + sqlite3_result_int64(context_, static_cast(perfSampleObj_.CpuIds()[CurrentRow()])); + break; + case THREAD_STATE: + if (perfSampleObj_.ThreadStates()[CurrentRow()] != INVALID_UINT64) { + auto threadStateIndex = static_cast(perfSampleObj_.ThreadStates()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(threadStateIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hiperf/perf_sample_table.h b/trace_streamer/src/table/hiperf/perf_sample_table.h new file mode 100644 index 0000000000000000000000000000000000000000..6c70b20282eb7c3f63eb12913319744b652d9a44 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_sample_table.h @@ -0,0 +1,49 @@ +/* + * 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 PERF_SAMPLE_TABLE_H +#define PERF_SAMPLE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class PerfSampleTable : public TableBase { +public: + explicit PerfSampleTable(const TraceDataCache* dataCache); + ~PerfSampleTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const PerfSample& perfSampleObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PERF_SAMPLE_TABLE_H diff --git a/trace_streamer/src/table/hiperf/perf_thread_table.cpp b/trace_streamer/src/table/hiperf/perf_thread_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bbb6b624842f147ed72eb6b6add42b2f87ea0912 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_thread_table.cpp @@ -0,0 +1,199 @@ +/* + * 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 "perf_thread_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, THREAD_ID, PROCESS_ID, THREAD_NAME }; +PerfThreadTable::PerfThreadTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("thread_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("process_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("thread_name", "TEXT")); + tablePriKey_.push_back("id"); +} + +PerfThreadTable::~PerfThreadTable() {} + +void PerfThreadTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstPerfThreadData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void PerfThreadTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool PerfThreadTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr PerfThreadTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +PerfThreadTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstPerfThreadData().Size())), + perfThreadObj_(dataCache->GetConstPerfThreadData()) +{ +} + +PerfThreadTable::Cursor::~Cursor() {} + +int32_t PerfThreadTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case THREAD_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), perfThreadObj_.Tids()); + break; + case PROCESS_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), perfThreadObj_.Pids()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t PerfThreadTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(perfThreadObj_.IdsData()[CurrentRow()])); + break; + case THREAD_ID: + sqlite3_result_int64(context_, static_cast(perfThreadObj_.Tids()[CurrentRow()])); + break; + case PROCESS_ID: + sqlite3_result_int64(context_, static_cast(perfThreadObj_.Pids()[CurrentRow()])); + break; + case THREAD_NAME: + if (perfThreadObj_.ThreadNames()[CurrentRow()] != INVALID_UINT64) { + auto threadNameIndex = static_cast(perfThreadObj_.ThreadNames()[CurrentRow()]); + if (dataCache_->GetDataFromDict(threadNameIndex).empty()) { + break; + } + sqlite3_result_text(context_, dataCache_->GetDataFromDict(threadNameIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/hiperf/perf_thread_table.h b/trace_streamer/src/table/hiperf/perf_thread_table.h new file mode 100644 index 0000000000000000000000000000000000000000..f39cda03c77887d05a63e99d9580cc3194332195 --- /dev/null +++ b/trace_streamer/src/table/hiperf/perf_thread_table.h @@ -0,0 +1,49 @@ +/* + * 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 PERF_THREAD_TABLE_H +#define PERF_THREAD_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class PerfThreadTable : public TableBase { +public: + explicit PerfThreadTable(const TraceDataCache* dataCache); + ~PerfThreadTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const PerfThread& perfThreadObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // PERF_THREAD_TABLE_H diff --git a/trace_streamer/src/table/js_memory/BUILD.gn b/trace_streamer/src/table/js_memory/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e289343b9eb26c93407280d521d991ec48181ea7 --- /dev/null +++ b/trace_streamer/src/table/js_memory/BUILD.gn @@ -0,0 +1,68 @@ +# 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("//src/ts.gni") +ohos_source_set("js_memory_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "appname_table.cpp", + "appname_table.h", + "js_heap_edges_table.cpp", + "js_heap_edges_table.h", + "js_heap_files_table.cpp", + "js_heap_files_table.h", + "js_heap_info_table.cpp", + "js_heap_info_table.h", + "js_heap_location_table.cpp", + "js_heap_location_table.h", + "js_heap_nodes_table.cpp", + "js_heap_nodes_table.h", + "js_heap_sample_table.cpp", + "js_heap_sample_table.h", + "js_heap_string_table.cpp", + "js_heap_string_table.h", + "js_heap_trace_function_info_table.cpp", + "js_heap_trace_function_info_table.h", + "js_heap_trace_node_table.cpp", + "js_heap_trace_node_table.h", + ] + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/js_memory/appname_table.cpp b/trace_streamer/src/table/js_memory/appname_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b168abd7076cf871d191b1098ba96df8a9c74d0 --- /dev/null +++ b/trace_streamer/src/table/js_memory/appname_table.cpp @@ -0,0 +1,67 @@ +/* + * 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 "appname_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, FLAG, APP_NAME, APP_KEY }; +AppnameTable::AppnameTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("flag", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("app_name", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("app_key", "INTEGER")); + tablePriKey_.push_back("id"); +} + +AppnameTable::~AppnameTable() {} + +std::unique_ptr AppnameTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +AppnameTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstAppNamesData().Size())), + appName_(dataCache->GetConstAppNamesData()) +{ +} + +AppnameTable::Cursor::~Cursor() {} + +int32_t AppnameTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, dataCache_->GetConstAppNamesData().IdsData()[CurrentRow()]); + break; + case FLAG: + sqlite3_result_int(context_, dataCache_->GetConstAppNamesData().Falgs()[CurrentRow()]); + break; + case APP_NAME: + sqlite3_result_int64(context_, dataCache_->GetConstAppNamesData().EventSourceId()[CurrentRow()]); + break; + case APP_KEY: + sqlite3_result_int64(context_, dataCache_->GetConstAppNamesData().AppName()[CurrentRow()]); + break; + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/appname_table.h b/trace_streamer/src/table/js_memory/appname_table.h new file mode 100644 index 0000000000000000000000000000000000000000..ff02cf4d3ab3558d5d8d37380cc192dcd4b9c925 --- /dev/null +++ b/trace_streamer/src/table/js_memory/appname_table.h @@ -0,0 +1,52 @@ +/* + * 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 APPNAME_TABLE_H +#define APPNAME_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class AppnameTable : public TableBase { +public: + explicit AppnameTable(const TraceDataCache*); + ~AppnameTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const AppNames& appName_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // APPNAME_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_edges_table.cpp b/trace_streamer/src/table/js_memory/js_heap_edges_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a583ad92ee5ea451a9414a3b8214f7cdf01c2da4 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_edges_table.cpp @@ -0,0 +1,79 @@ +/* + * 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 "js_heap_edges_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, EDGE_INDEX, TYPE, NAME_OR_INDEX, TO_NODE, FROM_NODE_ID, TO_NODE_ID }; +JsHeapEdgesTable::JsHeapEdgesTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("edge_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name_or_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("to_node", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("from_node_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("to_node_id", "INTEGER")); + tablePriKey_.push_back("file_id"); +} + +JsHeapEdgesTable::~JsHeapEdgesTable() {} + +std::unique_ptr JsHeapEdgesTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapEdgesTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapEdgesData().Size())), + jsHeapEdges_(dataCache->GetConstJsHeapEdgesData()) +{ +} + +JsHeapEdgesTable::Cursor::~Cursor() {} + +int32_t JsHeapEdgesTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.FileIds()[CurrentRow()])); + break; + case EDGE_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.EdgeIndexs()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.Types()[CurrentRow()])); + break; + case NAME_OR_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.NameOrIndexs()[CurrentRow()])); + break; + case TO_NODE: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.ToNodes()[CurrentRow()])); + break; + case FROM_NODE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.FromNodeIds()[CurrentRow()])); + break; + case TO_NODE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapEdges_.ToNodeIds()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_edges_table.h b/trace_streamer/src/table/js_memory/js_heap_edges_table.h new file mode 100644 index 0000000000000000000000000000000000000000..a9e333b21886ef52fc745cab10dedffb03e58270 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_edges_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_EDGES_TABLE_H +#define JS_HEAP_EDGES_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapEdgesTable : public TableBase { +public: + explicit JsHeapEdgesTable(const TraceDataCache* dataCache); + ~JsHeapEdgesTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapEdges& jsHeapEdges_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_EDGES_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_files_table.cpp b/trace_streamer/src/table/js_memory/js_heap_files_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99cf460b6efe1d22dc7892b52fb671cd3c571332 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_files_table.cpp @@ -0,0 +1,71 @@ +/* + * 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 "js_heap_files_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, FILE_NAME, START_TIME, END_TIME, IPID }; +JsHeapFilesTable::JsHeapFilesTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("start_time", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_time", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +JsHeapFilesTable::~JsHeapFilesTable() {} + +std::unique_ptr JsHeapFilesTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapFilesTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapFilesData().Size())), + jsHeapFiles_(dataCache->GetConstJsHeapFilesData()) +{ +} + +JsHeapFilesTable::Cursor::~Cursor() {} + +int32_t JsHeapFilesTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, static_cast(jsHeapFiles_.IDs()[CurrentRow()])); + break; + case FILE_NAME: + sqlite3_result_text(context_, jsHeapFiles_.FilePaths()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case START_TIME: + sqlite3_result_int64(context_, static_cast(jsHeapFiles_.StartTimes()[CurrentRow()])); + break; + case END_TIME: + sqlite3_result_int64(context_, static_cast(jsHeapFiles_.EndTimes()[CurrentRow()])); + break; + case IPID: + sqlite3_result_int64(context_, static_cast(jsHeapFiles_.Pids()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_files_table.h b/trace_streamer/src/table/js_memory/js_heap_files_table.h new file mode 100644 index 0000000000000000000000000000000000000000..cb2089dc42f858f05d49fee574e9367e5fa6037a --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_files_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_FILES_TABLE_H +#define JS_HEAP_FILES_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapFilesTable : public TableBase { +public: + explicit JsHeapFilesTable(const TraceDataCache* dataCache); + ~JsHeapFilesTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapFiles& jsHeapFiles_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_FILES_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_info_table.cpp b/trace_streamer/src/table/js_memory/js_heap_info_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a52c970ff05758957e05e75ab616203d34e97a3 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_info_table.cpp @@ -0,0 +1,74 @@ +/* + * 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 "js_heap_info_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, KEY, TYPE, INT_VALUE, STR_VALUE }; +JsHeapInfoTable::JsHeapInfoTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("key", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("int_value", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("str_value", "TEXT")); + tablePriKey_.push_back("file_id"); +} + +JsHeapInfoTable::~JsHeapInfoTable() {} + +std::unique_ptr JsHeapInfoTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapInfoTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapInfoData().Size())), + jsHeapInfo_(dataCache->GetConstJsHeapInfoData()) +{ +} + +JsHeapInfoTable::Cursor::~Cursor() {} + +int32_t JsHeapInfoTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64( + context_, + static_cast(jsHeapInfo_.FileIds()[CurrentRow()])); // IdsData() will be optimized + break; + case KEY: + sqlite3_result_text(context_, jsHeapInfo_.Keys()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(jsHeapInfo_.Types()[CurrentRow()])); + break; + case INT_VALUE: + sqlite3_result_int64(context_, static_cast(jsHeapInfo_.IntValues()[CurrentRow()])); + break; + case STR_VALUE: + sqlite3_result_text(context_, jsHeapInfo_.StrValues()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_info_table.h b/trace_streamer/src/table/js_memory/js_heap_info_table.h new file mode 100644 index 0000000000000000000000000000000000000000..a0638a33c7fc5427dedca99613a75bbad97f3166 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_info_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_INFO_TABLE_H +#define JS_HEAP_INFO_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapInfoTable : public TableBase { +public: + explicit JsHeapInfoTable(const TraceDataCache* dataCache); + ~JsHeapInfoTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapInfo& jsHeapInfo_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_INFO_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_location_table.cpp b/trace_streamer/src/table/js_memory/js_heap_location_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e653ce3674e0b1f23dfe5afca629953c426ccc89 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_location_table.cpp @@ -0,0 +1,71 @@ +/* + * 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 "js_heap_location_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, OBJECT_INDEX, SCRIPT_ID, LINE, COLUMN }; +JsHeapLocationTable::JsHeapLocationTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("object_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("script_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("line", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("column", "INTEGER")); + tablePriKey_.push_back("file_id"); +} + +JsHeapLocationTable::~JsHeapLocationTable() {} + +std::unique_ptr JsHeapLocationTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapLocationTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapLocationData().Size())), + jsHeapLocation_(dataCache->GetConstJsHeapLocationData()) +{ +} + +JsHeapLocationTable::Cursor::~Cursor() {} + +int32_t JsHeapLocationTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapLocation_.FileIds()[CurrentRow()])); + break; + case OBJECT_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapLocation_.ObjectIndexs()[CurrentRow()])); + break; + case SCRIPT_ID: + sqlite3_result_int64(context_, static_cast(jsHeapLocation_.ScriptIds()[CurrentRow()])); + break; + case LINE: + sqlite3_result_int64(context_, static_cast(jsHeapLocation_.Lines()[CurrentRow()])); + break; + case COLUMN: + sqlite3_result_int64(context_, static_cast(jsHeapLocation_.Columns()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_location_table.h b/trace_streamer/src/table/js_memory/js_heap_location_table.h new file mode 100644 index 0000000000000000000000000000000000000000..9ef7d617b6a6ee887b2013c2388f2196b12002b0 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_location_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_LOCATION_TABLE_H +#define JS_HEAP_LOCATION_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapLocationTable : public TableBase { +public: + explicit JsHeapLocationTable(const TraceDataCache* dataCache); + ~JsHeapLocationTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapLocation& jsHeapLocation_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_LOCATION_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_nodes_table.cpp b/trace_streamer/src/table/js_memory/js_heap_nodes_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc2f960fb81258b4149709248c4c68f581353f67 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_nodes_table.cpp @@ -0,0 +1,87 @@ +/* + * 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 "js_heap_nodes_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, NODE_INDEX, TYPE, NAME, NODE_ID, SELF_SIZE, EDGE_COUNT, TRACE_NODE_ID, DETACHEDNESS }; +JsHeapNodesTable::JsHeapNodesTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("node_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("self_size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("edge_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("trace_node_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("detachedness", "INTEGER")); + tablePriKey_.push_back("file_id"); +} + +JsHeapNodesTable::~JsHeapNodesTable() {} + +std::unique_ptr JsHeapNodesTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapNodesTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapNodesData().Size())), + jsHeapNodes_(dataCache->GetConstJsHeapNodesData()) +{ +} + +JsHeapNodesTable::Cursor::~Cursor() {} + +int32_t JsHeapNodesTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.FileIds()[CurrentRow()])); + break; + case NODE_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.NodeIndexs()[CurrentRow()])); + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.Types()[CurrentRow()])); + break; + case NAME: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.Names()[CurrentRow()])); + break; + case NODE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.NodeIds()[CurrentRow()])); + break; + case SELF_SIZE: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.SelfSizes()[CurrentRow()])); + break; + case EDGE_COUNT: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.EdgeCounts()[CurrentRow()])); + break; + case TRACE_NODE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.TraceNodeIds()[CurrentRow()])); + break; + case DETACHEDNESS: + sqlite3_result_int64(context_, static_cast(jsHeapNodes_.DetachedNess()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_nodes_table.h b/trace_streamer/src/table/js_memory/js_heap_nodes_table.h new file mode 100644 index 0000000000000000000000000000000000000000..a48f7e00b2edf0ef6fe113ea75441a3d7ea9316d --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_nodes_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_NODES_TABLE_H +#define JS_HEAP_NODES_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapNodesTable : public TableBase { +public: + explicit JsHeapNodesTable(const TraceDataCache* dataCache); + ~JsHeapNodesTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapNodes& jsHeapNodes_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_NODES_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_sample_table.cpp b/trace_streamer/src/table/js_memory/js_heap_sample_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff24b74c793322f6143a96fa1f2f6084b71af99f --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_sample_table.cpp @@ -0,0 +1,63 @@ +/* + * 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 "js_heap_sample_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, TIMESTAMP_US, LAST_ASSIGNED_ID }; +JsHeapSampleTable::JsHeapSampleTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("timestamp_us", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("last_assigned_id", "INTEGER")); + tablePriKey_.push_back("file_id"); +} + +JsHeapSampleTable::~JsHeapSampleTable() {} + +std::unique_ptr JsHeapSampleTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapSampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapSampleData().Size())), + jsHeapSample_(dataCache->GetConstJsHeapSampleData()) +{ +} + +JsHeapSampleTable::Cursor::~Cursor() {} + +int32_t JsHeapSampleTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapSample_.FileIds()[CurrentRow()])); + break; + case TIMESTAMP_US: + sqlite3_result_int64(context_, static_cast(jsHeapSample_.TimeStampUs()[CurrentRow()])); + break; + case LAST_ASSIGNED_ID: + sqlite3_result_int64(context_, static_cast(jsHeapSample_.LastAssignedIds()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_sample_table.h b/trace_streamer/src/table/js_memory/js_heap_sample_table.h new file mode 100644 index 0000000000000000000000000000000000000000..228cc71aee5b54cd1eaf1d28f7c29e09714f4c66 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_sample_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_SAMPLE_TABLE_H +#define JS_HEAP_SAMPLE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapSampleTable : public TableBase { +public: + explicit JsHeapSampleTable(const TraceDataCache* dataCache); + ~JsHeapSampleTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapSample& jsHeapSample_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_SAMPLE_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_string_table.cpp b/trace_streamer/src/table/js_memory/js_heap_string_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01da1de3d370e4163c2c6197294bc774d1781428 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_string_table.cpp @@ -0,0 +1,64 @@ +/* + * 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 "js_heap_string_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, FILE_INDEX, STRING }; +JsHeapStringTable::JsHeapStringTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("string", "TEXT")); + tablePriKey_.push_back("file_id"); +} + +JsHeapStringTable::~JsHeapStringTable() {} + +std::unique_ptr JsHeapStringTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapStringTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapStringData().Size())), + jsHeapString_(dataCache->GetConstJsHeapStringData()) +{ +} + +JsHeapStringTable::Cursor::~Cursor() {} + +int32_t JsHeapStringTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapString_.FileIds()[CurrentRow()])); + break; + case FILE_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapString_.FileIndexs()[CurrentRow()])); + break; + case STRING: + sqlite3_result_text(context_, jsHeapString_.Strings()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_string_table.h b/trace_streamer/src/table/js_memory/js_heap_string_table.h new file mode 100644 index 0000000000000000000000000000000000000000..828b58d00d8d69810b37db39b20520f0cf80e14d --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_string_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_STRING_TABLE_H +#define JS_HEAP_STRING_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapStringTable : public TableBase { +public: + explicit JsHeapStringTable(const TraceDataCache* dataCache); + ~JsHeapStringTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapString& jsHeapString_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_STRING_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_trace_function_info_table.cpp b/trace_streamer/src/table/js_memory/js_heap_trace_function_info_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af03f74c856640862056dc5bfdf1545fff4953fc --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_trace_function_info_table.cpp @@ -0,0 +1,83 @@ +/* + * 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 "js_heap_trace_function_info_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, FUNCTION_INDEX, FUNCTION_ID, NAME, SCRIPT_NAME, SCRIPT_ID, LINE, COLUMN }; +JsHeapTraceFunctionInfoTable::JsHeapTraceFunctionInfoTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("function_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("function_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("name", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("script_name", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("script_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("line", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("column", "INTEGER")); + tablePriKey_.push_back("file_id"); +} + +JsHeapTraceFunctionInfoTable::~JsHeapTraceFunctionInfoTable() {} + +std::unique_ptr JsHeapTraceFunctionInfoTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapTraceFunctionInfoTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapTraceFuncInfoData().Size())), + jsHeapTraceFuncInfo_(dataCache->GetConstJsHeapTraceFuncInfoData()) +{ +} + +JsHeapTraceFunctionInfoTable::Cursor::~Cursor() {} + +int32_t JsHeapTraceFunctionInfoTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.FileIds()[CurrentRow()])); + break; + case FUNCTION_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.FunctionIndexs()[CurrentRow()])); + break; + case FUNCTION_ID: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.FunctionIds()[CurrentRow()])); + break; + case NAME: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.Names()[CurrentRow()])); + break; + case SCRIPT_NAME: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.ScriptNames()[CurrentRow()])); + break; + case SCRIPT_ID: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.ScriptIds()[CurrentRow()])); + break; + case LINE: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.Lines()[CurrentRow()])); + break; + case COLUMN: + sqlite3_result_int64(context_, static_cast(jsHeapTraceFuncInfo_.Columns()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_trace_function_info_table.h b/trace_streamer/src/table/js_memory/js_heap_trace_function_info_table.h new file mode 100644 index 0000000000000000000000000000000000000000..5f76e5c43e84ec14d89774a678d4dcda9e770911 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_trace_function_info_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_TRACE_FUNCTION_INFO_TABLE_H +#define JS_HEAP_TRACE_FUNCTION_INFO_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapTraceFunctionInfoTable : public TableBase { +public: + explicit JsHeapTraceFunctionInfoTable(const TraceDataCache* dataCache); + ~JsHeapTraceFunctionInfoTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapTraceFuncInfo& jsHeapTraceFuncInfo_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_TRACE_FUNCTION_INFO_TABLE_H diff --git a/trace_streamer/src/table/js_memory/js_heap_trace_node_table.cpp b/trace_streamer/src/table/js_memory/js_heap_trace_node_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba3a80c36ff338faf318cb051795d3b21ad88d01 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_trace_node_table.cpp @@ -0,0 +1,75 @@ +/* + * 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 "js_heap_trace_node_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { FILE_ID = 0, TRACE_NODE_ID, FUNCTION_INFO_INDEX, COUNT, SIZE, PARENT_ID }; +JsHeapTraceNodeTable::JsHeapTraceNodeTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("function_info_index", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("parent_id", "INTEGER")); + tablePriKey_.push_back("file_id"); +} + +JsHeapTraceNodeTable::~JsHeapTraceNodeTable() {} + +std::unique_ptr JsHeapTraceNodeTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +JsHeapTraceNodeTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstJsHeapTraceNodeData().Size())), + jsHeapTraceNode_(dataCache->GetConstJsHeapTraceNodeData()) +{ +} + +JsHeapTraceNodeTable::Cursor::~Cursor() {} + +int32_t JsHeapTraceNodeTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case FILE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapTraceNode_.FileIds()[CurrentRow()])); + break; + case TRACE_NODE_ID: + sqlite3_result_int64(context_, static_cast(jsHeapTraceNode_.TraceNodeIDs()[CurrentRow()])); + break; + case FUNCTION_INFO_INDEX: + sqlite3_result_int64(context_, static_cast(jsHeapTraceNode_.FunctionInfoIndexs()[CurrentRow()])); + break; + case COUNT: + sqlite3_result_int64(context_, static_cast(jsHeapTraceNode_.Counts()[CurrentRow()])); + break; + case SIZE: + sqlite3_result_int64(context_, static_cast(jsHeapTraceNode_.NodeSizes()[CurrentRow()])); + break; + case PARENT_ID: + sqlite3_result_int64(context_, static_cast(jsHeapTraceNode_.ParentIds()[CurrentRow()])); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/js_memory/js_heap_trace_node_table.h b/trace_streamer/src/table/js_memory/js_heap_trace_node_table.h new file mode 100644 index 0000000000000000000000000000000000000000..93689620fff845330936daf3a161a8f3acce0b55 --- /dev/null +++ b/trace_streamer/src/table/js_memory/js_heap_trace_node_table.h @@ -0,0 +1,55 @@ +/* + * 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 JS_HEAP_TRACE_NODE_TABLE_H +#define JS_HEAP_TRACE_NODE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class JsHeapTraceNodeTable : public TableBase { +public: + explicit JsHeapTraceNodeTable(const TraceDataCache* dataCache); + ~JsHeapTraceNodeTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override + { + UNUSED(fc); + UNUSED(ei); + } + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const JsHeapTraceNode& jsHeapTraceNode_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // JS_HEAP_TRACE_NODE_TABLE_H diff --git a/trace_streamer/src/table/monitor/BUILD.gn b/trace_streamer/src/table/monitor/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3e7b883da101e724b8939429c4b50052a393f02f --- /dev/null +++ b/trace_streamer/src/table/monitor/BUILD.gn @@ -0,0 +1,64 @@ +# 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("//src/ts.gni") +ohos_source_set("monitor_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "cpu_usage_info_table.cpp", + "cpu_usage_info_table.h", + "disk_io_table.cpp", + "disk_io_table.h", + "hidump_table.cpp", + "hidump_table.h", + "live_process_table.cpp", + "live_process_table.h", + "log_table.cpp", + "log_table.h", + "network_table.cpp", + "network_table.h", + "paged_memory_sample_table.cpp", + "paged_memory_sample_table.h", + "smaps_table.cpp", + "smaps_table.h", + ] + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/monitor/cpu_usage_info_table.cpp b/trace_streamer/src/table/monitor/cpu_usage_info_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7da5974efc1277c2d3cec6bf266c47d455c071f7 --- /dev/null +++ b/trace_streamer/src/table/monitor/cpu_usage_info_table.cpp @@ -0,0 +1,81 @@ +/* + * 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 "cpu_usage_info_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { TS = 0, DUR, TOTAL_LOAD, USER_LOAD, SYSTEM_LOAD, THREADS }; +CpuUsageInfoTable::CpuUsageInfoTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("total_load", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("user_load", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("system_load", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("process_num", "INTEGER")); + tablePriKey_.push_back("ts"); +} + +CpuUsageInfoTable::~CpuUsageInfoTable() {} + +std::unique_ptr CpuUsageInfoTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +CpuUsageInfoTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstCpuUsageInfoData().Size())), + cpuUsageInfoObj_(dataCache->GetConstCpuUsageInfoData()) +{ +} + +CpuUsageInfoTable::Cursor::~Cursor() {} + +int32_t CpuUsageInfoTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(cpuUsageInfoObj_.TimeStampData()[CurrentRow()])); + break; + } + case DUR: { + sqlite3_result_int64(context_, static_cast(cpuUsageInfoObj_.Durs()[CurrentRow()])); + break; + } + case TOTAL_LOAD: { + sqlite3_result_int64(context_, static_cast(cpuUsageInfoObj_.TotalLoad()[CurrentRow()])); + break; + } + case USER_LOAD: { + sqlite3_result_double(context_, cpuUsageInfoObj_.UserLoad()[CurrentRow()]); + break; + } + case SYSTEM_LOAD: { + sqlite3_result_double(context_, cpuUsageInfoObj_.SystemLoad()[CurrentRow()]); + break; + } + case THREADS: { + sqlite3_result_int(context_, static_cast(cpuUsageInfoObj_.Threads()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/cpu_usage_info_table.h b/trace_streamer/src/table/monitor/cpu_usage_info_table.h new file mode 100644 index 0000000000000000000000000000000000000000..c9ee4084a301e9b07ed3e4925eda17bee9409ec7 --- /dev/null +++ b/trace_streamer/src/table/monitor/cpu_usage_info_table.h @@ -0,0 +1,52 @@ +/* + * 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 CPU_USAGE_INFO_TABLE_H +#define CPU_USAGE_INFO_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class CpuUsageInfoTable : public TableBase { +public: + explicit CpuUsageInfoTable(const TraceDataCache* dataCache); + ~CpuUsageInfoTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const CpuUsageDetailData& cpuUsageInfoObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // NETWORK_TABLE_H diff --git a/trace_streamer/src/table/monitor/disk_io_table.cpp b/trace_streamer/src/table/monitor/disk_io_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14ca7235279e6612099f39b8895a77dacd19f56a --- /dev/null +++ b/trace_streamer/src/table/monitor/disk_io_table.cpp @@ -0,0 +1,112 @@ +/* + * 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 "disk_io_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + TS = 0, + DUR, + RD, + WR, + RD_SPEED, + WR_SPEED, + RD_COUNT, + WR_COUNT, + RD_COUNT_SPEED, + WR_COUNT_SPEED, +}; +DiskIOTable::DiskIOTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("rd", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("wr", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("rd_speed", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("wr_speed", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("rd_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("wr_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("rd_count_speed", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("wr_count_speed", "REAL")); + tablePriKey_.push_back("ts"); +} + +DiskIOTable::~DiskIOTable() {} + +std::unique_ptr DiskIOTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +DiskIOTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstDiskIOData().Size())), + diskIODataObj_(dataCache->GetConstDiskIOData()) +{ +} + +DiskIOTable::Cursor::~Cursor() {} + +int32_t DiskIOTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(diskIODataObj_.TimeStampData()[CurrentRow()])); + break; + } + case DUR: { + sqlite3_result_int64(context_, static_cast(diskIODataObj_.Durs()[CurrentRow()])); + break; + } + case RD: { + sqlite3_result_int64(context_, static_cast(diskIODataObj_.RdDatas()[CurrentRow()])); + break; + } + case WR: { + sqlite3_result_int64(context_, static_cast(diskIODataObj_.WrDatas()[CurrentRow()])); + break; + } + case RD_SPEED: { + sqlite3_result_double(context_, static_cast(diskIODataObj_.RdSpeedDatas()[CurrentRow()])); + break; + } + case WR_SPEED: { + sqlite3_result_double(context_, static_cast(diskIODataObj_.WrSpeedDatas()[CurrentRow()])); + break; + } + case RD_COUNT: { + sqlite3_result_int64(context_, static_cast(diskIODataObj_.RdCountDatas()[CurrentRow()])); + break; + } + case WR_COUNT: { + sqlite3_result_int64(context_, static_cast(diskIODataObj_.WrCountDatas()[CurrentRow()])); + break; + } + case RD_COUNT_SPEED: { + sqlite3_result_double(context_, static_cast(diskIODataObj_.RdCountPerSecDatas()[CurrentRow()])); + break; + } + case WR_COUNT_SPEED: { + sqlite3_result_double(context_, static_cast(diskIODataObj_.WrCountPerSecDatas()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/disk_io_table.h b/trace_streamer/src/table/monitor/disk_io_table.h new file mode 100644 index 0000000000000000000000000000000000000000..c2d4ca9680454b24e5cd53da1f31de5cd98b0b75 --- /dev/null +++ b/trace_streamer/src/table/monitor/disk_io_table.h @@ -0,0 +1,52 @@ +/* + * 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 DISKIO_TABLE_H +#define DISKIO_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class DiskIOTable : public TableBase { +public: + explicit DiskIOTable(const TraceDataCache* dataCache); + ~DiskIOTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const DiskIOData& diskIODataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // DISKIO_TABLE_H diff --git a/trace_streamer/src/table/monitor/hidump_table.cpp b/trace_streamer/src/table/monitor/hidump_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a7a6781658edd2f2ccf639fc2126b883b122b32 --- /dev/null +++ b/trace_streamer/src/table/monitor/hidump_table.cpp @@ -0,0 +1,190 @@ +/* + * 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 "hidump_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TS, FPS }; +HidumpTable::HidumpTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("fps", "INTEGER")); + tablePriKey_.push_back("ts"); +} + +HidumpTable::~HidumpTable() {} + +void HidumpTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void HidumpTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool HidumpTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr HidumpTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +HidumpTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstHidumpData().Size())), + hidumpObj_(dataCache->GetConstHidumpData()) +{ +} + +HidumpTable::Cursor::~Cursor() {} + +int32_t HidumpTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case TS: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + hidumpObj_.TimeStampData()); + break; + case FPS: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), hidumpObj_.Fpss()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t HidumpTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case TS: + sqlite3_result_int64(context_, static_cast(hidumpObj_.TimeStampData()[CurrentRow()])); + break; + case FPS: { + sqlite3_result_int64(context_, static_cast(hidumpObj_.Fpss()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/hidump_table.h b/trace_streamer/src/table/monitor/hidump_table.h new file mode 100644 index 0000000000000000000000000000000000000000..9efdab44bcefd7c8c4256d19c2513015c3f3abcf --- /dev/null +++ b/trace_streamer/src/table/monitor/hidump_table.h @@ -0,0 +1,49 @@ +/* + * 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 HIDUMP_TABLE_H +#define HIDUMP_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class HidumpTable : public TableBase { +public: + explicit HidumpTable(const TraceDataCache* dataCache); + ~HidumpTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const Hidump& hidumpObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // HIDUMP_TABLE_H diff --git a/trace_streamer/src/table/monitor/live_process_table.cpp b/trace_streamer/src/table/monitor/live_process_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..558dcfe89109f415e44ccb06281c3f3f9f4cac63 --- /dev/null +++ b/trace_streamer/src/table/monitor/live_process_table.cpp @@ -0,0 +1,134 @@ +/* + * 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 "live_process_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + TS = 0, + DUR, + CPU_TIME, + PROCESS_ID, + PROCESS_NAME, + PARENT_PROCESS_ID, + UID, + USER_NAME, + CPU_USAGE, + PSS_INFO, + THREAD_SUM, + DISK_WRITES, + DISK_READS +}; +LiveProcessTable::LiveProcessTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu_time", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("process_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("process_name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("parent_process_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("uid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("user_name", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("cpu_usage", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("pss_info", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("thread_num", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("disk_writes", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("disk_reads", "INTEGER")); + tablePriKey_.push_back("ts"); +} + +LiveProcessTable::~LiveProcessTable() {} + +std::unique_ptr LiveProcessTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +LiveProcessTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstLiveProcessData().Size())), + liveProcessDetailDataObj_(dataCache->GetConstLiveProcessData()) +{ +} + +LiveProcessTable::Cursor::~Cursor() {} + +int32_t LiveProcessTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, + static_cast(liveProcessDetailDataObj_.TimeStampData()[CurrentRow()])); + break; + } + case DUR: { + sqlite3_result_int64(context_, static_cast(liveProcessDetailDataObj_.Durs()[CurrentRow()])); + break; + } + case CPU_TIME: { + sqlite3_result_int64(context_, static_cast(liveProcessDetailDataObj_.CpuTimes()[CurrentRow()])); + break; + } + case PROCESS_ID: { + sqlite3_result_int(context_, static_cast(liveProcessDetailDataObj_.ProcessID()[CurrentRow()])); + break; + } + case PROCESS_NAME: { + sqlite3_result_text(context_, liveProcessDetailDataObj_.ProcessName()[CurrentRow()].c_str(), + STR_DEFAULT_LEN, nullptr); + break; + } + case PARENT_PROCESS_ID: { + sqlite3_result_int(context_, + static_cast(liveProcessDetailDataObj_.ParentProcessID()[CurrentRow()])); + break; + } + case UID: { + sqlite3_result_int(context_, static_cast(liveProcessDetailDataObj_.Uid()[CurrentRow()])); + break; + } + case USER_NAME: { + sqlite3_result_text(context_, liveProcessDetailDataObj_.UserName()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + break; + } + case CPU_USAGE: { + sqlite3_result_double(context_, liveProcessDetailDataObj_.CpuUsage()[CurrentRow()]); + break; + } + case PSS_INFO: { + sqlite3_result_int(context_, static_cast(liveProcessDetailDataObj_.PssInfo()[CurrentRow()])); + break; + } + case THREAD_SUM: { + sqlite3_result_int(context_, static_cast(liveProcessDetailDataObj_.Threads()[CurrentRow()])); + break; + } + case DISK_WRITES: { + sqlite3_result_int(context_, static_cast(liveProcessDetailDataObj_.DiskWrites()[CurrentRow()])); + break; + } + case DISK_READS: { + sqlite3_result_int(context_, static_cast(liveProcessDetailDataObj_.DiskReads()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/live_process_table.h b/trace_streamer/src/table/monitor/live_process_table.h new file mode 100644 index 0000000000000000000000000000000000000000..49f1b701a6a3490d6a73e9438195adac5d2b8be5 --- /dev/null +++ b/trace_streamer/src/table/monitor/live_process_table.h @@ -0,0 +1,52 @@ +/* + * 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 LIVE_PROCESS_TABLE_H +#define LIVE_PROCESS_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class LiveProcessTable : public TableBase { +public: + explicit LiveProcessTable(const TraceDataCache* dataCache); + ~LiveProcessTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const LiveProcessDetailData& liveProcessDetailDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // LIVE_PROCESS_TABLE_H diff --git a/trace_streamer/src/table/monitor/log_table.cpp b/trace_streamer/src/table/monitor/log_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b638acaf93e863904d08d57a1ab4214e2238b339 --- /dev/null +++ b/trace_streamer/src/table/monitor/log_table.cpp @@ -0,0 +1,100 @@ +/* + * 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 "log_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { SEQ = 0, TS, PID, TID, LEVEL, TAG, CONTEXT, ORIGINTS }; +LogTable::LogTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("seq", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("pid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("tid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("level", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("tag", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("context", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("origints", "INTEGER")); + tablePriKey_.push_back("ts"); +} + +LogTable::~LogTable() {} + +std::unique_ptr LogTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +LogTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstHilogData().Size())), + logInfoObj_(dataCache->GetConstHilogData()) +{ +} + +LogTable::Cursor::~Cursor() {} + +int32_t LogTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case SEQ: + sqlite3_result_int64(context_, static_cast(logInfoObj_.HilogLineSeqs()[CurrentRow()])); + break; + case TS: + sqlite3_result_int64(context_, static_cast(logInfoObj_.TimeStampData()[CurrentRow()])); + break; + case PID: { + sqlite3_result_int64(context_, static_cast(logInfoObj_.Pids()[CurrentRow()])); + break; + } + case TID: + sqlite3_result_int64(context_, static_cast(logInfoObj_.Tids()[CurrentRow()])); + break; + case LEVEL: { + if (logInfoObj_.Levels()[CurrentRow()] != INVALID_UINT64) { + auto levelDataIndex = static_cast(logInfoObj_.Levels()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(levelDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case TAG: { + if (logInfoObj_.Tags()[CurrentRow()] != INVALID_UINT64) { + auto tagDataIndex = static_cast(logInfoObj_.Tags()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(tagDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case CONTEXT: { + if (logInfoObj_.Contexts()[CurrentRow()] != INVALID_UINT64) { + auto contextDataIndex = static_cast(logInfoObj_.Contexts()[CurrentRow()]); + sqlite3_result_text(context_, dataCache_->GetDataFromDict(contextDataIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case ORIGINTS: { + sqlite3_result_int64(context_, static_cast(logInfoObj_.OriginTimeStamData()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/log_table.h b/trace_streamer/src/table/monitor/log_table.h new file mode 100644 index 0000000000000000000000000000000000000000..2bfa50da22ad82e133476a53eaac4272a9caf3ca --- /dev/null +++ b/trace_streamer/src/table/monitor/log_table.h @@ -0,0 +1,52 @@ +/* + * 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 LOG_TABLE_H +#define LOG_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class LogTable : public TableBase { +public: + explicit LogTable(const TraceDataCache* dataCache); + ~LogTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const LogInfo& logInfoObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // LOG_TABLE_H diff --git a/trace_streamer/src/table/monitor/network_table.cpp b/trace_streamer/src/table/monitor/network_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..52eb6d797cc7871097174dd850567fdb01dcc5f7 --- /dev/null +++ b/trace_streamer/src/table/monitor/network_table.cpp @@ -0,0 +1,124 @@ +/* + * 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 "network_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + TS = 0, + DUR, + TX, + RX, + TX_SPEED, + RX_SPEED, + PACKET_IN, + PACKET_IN_SEC, + PACKET_OUT, + PACKET_OUT_SEC, + NET_TYPE, +}; +NetworkTable::NetworkTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("tx", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("rx", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("tx_speed", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("rx_speed", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("packet_in", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("packet_in_sec", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("packet_out", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("packet_out_sec", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("net_type", "TEXT")); + tablePriKey_.push_back("ts"); +} + +NetworkTable::~NetworkTable() {} + +std::unique_ptr NetworkTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +NetworkTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstNetworkData().Size())), + networkDataObj_(dataCache->GetConstNetworkData()) +{ +} + +NetworkTable::Cursor::~Cursor() {} + +int32_t NetworkTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case TS: { + sqlite3_result_int64(context_, static_cast(networkDataObj_.TimeStampData()[CurrentRow()])); + break; + } + case TX: { + sqlite3_result_int64(context_, static_cast(networkDataObj_.TxDatas()[CurrentRow()])); + break; + } + case RX: { + sqlite3_result_int64(context_, static_cast(networkDataObj_.RxDatas()[CurrentRow()])); + break; + } + case DUR: { + sqlite3_result_int64(context_, static_cast(networkDataObj_.Durs()[CurrentRow()])); + break; + } + case TX_SPEED: { + sqlite3_result_double(context_, static_cast(networkDataObj_.TxSpeed()[CurrentRow()])); + break; + } + case RX_SPEED: { + sqlite3_result_double(context_, + static_cast(dataCache_->GetConstNetworkData().RxSpeed()[CurrentRow()])); + break; + } + case PACKET_IN: { + sqlite3_result_int64(context_, + static_cast(dataCache_->GetConstNetworkData().PacketIn()[CurrentRow()])); + break; + } + case PACKET_IN_SEC: { + sqlite3_result_double(context_, + static_cast(dataCache_->GetConstNetworkData().PacketInSec()[CurrentRow()])); + break; + } + case PACKET_OUT: { + sqlite3_result_int64(context_, + static_cast(dataCache_->GetConstNetworkData().PacketOut()[CurrentRow()])); + break; + } + case PACKET_OUT_SEC: { + sqlite3_result_double(context_, + static_cast(dataCache_->GetConstNetworkData().PacketOutSec()[CurrentRow()])); + break; + } + case NET_TYPE: { + sqlite3_result_text(context_, dataCache_->GetConstNetworkData().NetTypes()[CurrentRow()].c_str(), + STR_DEFAULT_LEN, nullptr); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/network_table.h b/trace_streamer/src/table/monitor/network_table.h new file mode 100644 index 0000000000000000000000000000000000000000..1241e393b4fc88f18452521dac974d07da12aa28 --- /dev/null +++ b/trace_streamer/src/table/monitor/network_table.h @@ -0,0 +1,52 @@ +/* + * 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 NETWORK_TABLE_H +#define NETWORK_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class NetworkTable : public TableBase { +public: + explicit NetworkTable(const TraceDataCache* dataCache); + ~NetworkTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + + int32_t Column(int32_t column) const override; + + private: + const NetDetailData& networkDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // NETWORK_TABLE_H diff --git a/trace_streamer/src/table/monitor/paged_memory_sample_table.cpp b/trace_streamer/src/table/monitor/paged_memory_sample_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b86ac772047ba56ccb25b7fac9f2c2062bbff40 --- /dev/null +++ b/trace_streamer/src/table/monitor/paged_memory_sample_table.cpp @@ -0,0 +1,255 @@ +/* + * 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 "paged_memory_sample_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, CALLCHAIN_ID, TYPE, IPID, START_TS, END_TS, DUR, SIZE, ADDR, ITID }; +PagedMemorySampleTable::PagedMemorySampleTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("addr", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tablePriKey_.push_back("id"); +} + +PagedMemorySampleTable::~PagedMemorySampleTable() {} + +void PagedMemorySampleTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstHidumpData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void PagedMemorySampleTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool PagedMemorySampleTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr PagedMemorySampleTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +PagedMemorySampleTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstPagedMemorySampleData().Size())), + PagedMemorySampleDataObj_(dataCache->GetConstPagedMemorySampleData()) +{ +} + +PagedMemorySampleTable::Cursor::~Cursor() {} + +int32_t PagedMemorySampleTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + return SQLITE_OK; +} + +int32_t PagedMemorySampleTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.IdsData()[CurrentRow()])); + break; + case CALLCHAIN_ID: + if (PagedMemorySampleDataObj_.CallChainIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, + static_cast(PagedMemorySampleDataObj_.CallChainIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case TYPE: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.Types()[CurrentRow()])); + break; + case IPID: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.Ipids()[CurrentRow()])); + break; + case ITID: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.Itids()[CurrentRow()])); + break; + case START_TS: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.StartTs()[CurrentRow()])); + break; + case END_TS: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.EndTs()[CurrentRow()])); + break; + case DUR: + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.Durs()[CurrentRow()])); + break; + case SIZE: { + if (PagedMemorySampleDataObj_.Sizes()[CurrentRow()] != MAX_SIZE_T) { + sqlite3_result_int64(context_, static_cast(PagedMemorySampleDataObj_.Sizes()[CurrentRow()])); + } + break; + } + case ADDR: { + if (PagedMemorySampleDataObj_.Addr()[CurrentRow()] != INVALID_UINT64) { + auto firstArgIndex = PagedMemorySampleDataObj_.Addr()[CurrentRow()]; + sqlite3_result_text(context_, dataCache_->GetDataFromDict(firstArgIndex).c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} + +void PagedMemorySampleTable::Cursor::FilterId(unsigned char op, sqlite3_value* argv) +{ + auto type = sqlite3_value_type(argv); + if (type != SQLITE_INTEGER) { + // other type consider it NULL + indexMap_->Intersect(0, 0); + return; + } + auto v = static_cast(sqlite3_value_int64(argv)); + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + indexMap_->Intersect(v, v + 1); + break; + case SQLITE_INDEX_CONSTRAINT_GE: + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_GT: + v++; + indexMap_->Intersect(v, rowCount_); + break; + case SQLITE_INDEX_CONSTRAINT_LE: + v++; + indexMap_->Intersect(0, v); + break; + case SQLITE_INDEX_CONSTRAINT_LT: + indexMap_->Intersect(0, v); + break; + default: + // can't filter, all rows + break; + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/paged_memory_sample_table.h b/trace_streamer/src/table/monitor/paged_memory_sample_table.h new file mode 100644 index 0000000000000000000000000000000000000000..08f1924eadbe8fa8fe8d275d1c7fa3adfd81e3e4 --- /dev/null +++ b/trace_streamer/src/table/monitor/paged_memory_sample_table.h @@ -0,0 +1,52 @@ +/* + * 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 PAGED_MEMORY_SAMPLE_TABLE_H +#define PAGED_MEMORY_SAMPLE_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class PagedMemorySampleTable : public TableBase { +public: + explicit PagedMemorySampleTable(const TraceDataCache* dataCache); + ~PagedMemorySampleTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + void FilterId(unsigned char op, sqlite3_value* argv) override; + + private: + const PagedMemorySampleData& PagedMemorySampleDataObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // PAGED_MEMORY_SAMPLE_TABLE_H diff --git a/trace_streamer/src/table/monitor/smaps_table.cpp b/trace_streamer/src/table/monitor/smaps_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e67023f5f6c1aafab31e6d8b78cf7448ac80382b --- /dev/null +++ b/trace_streamer/src/table/monitor/smaps_table.cpp @@ -0,0 +1,100 @@ +/* + * 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 "smaps_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, TIME_STAMP, START_ADDRESS, END_ADDRESS, DIRTY, SWAPPER, RSS, PSS, SIZE, RESIDE, PROTECTION, PATH }; +SmapsTable::SmapsTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("timeStamp", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start_addr", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("end_addr", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("dirty", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("swapper", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("resident_size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("pss", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("virtaul_size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("reside", "REAL")); + tableColumn_.push_back(TableBase::ColumnInfo("protection_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("path_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +SmapsTable::~SmapsTable() {} + +std::unique_ptr SmapsTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +SmapsTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstSmapsData().Size())), + smapsObj_(dataCache->GetConstSmapsData()) +{ +} + +SmapsTable::Cursor::~Cursor() {} + +int32_t SmapsTable::Cursor::Column(int32_t col) const +{ + switch (col) { + case ID: + sqlite3_result_int64(context_, smapsObj_.IdsData()[CurrentRow()]); + break; + case TIME_STAMP: + sqlite3_result_int64(context_, smapsObj_.TimeStamps()[CurrentRow()]); + break; + case START_ADDRESS: + sqlite3_result_text(context_, smapsObj_.StartAddrs()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case END_ADDRESS: + sqlite3_result_text(context_, smapsObj_.EndAddrs()[CurrentRow()].c_str(), STR_DEFAULT_LEN, nullptr); + break; + case DIRTY: + sqlite3_result_int64(context_, smapsObj_.Dirtys()[CurrentRow()]); + break; + case SWAPPER: + sqlite3_result_int64(context_, smapsObj_.Swappers()[CurrentRow()]); + break; + case RSS: + sqlite3_result_int64(context_, smapsObj_.Rss()[CurrentRow()]); + break; + case PSS: + sqlite3_result_int64(context_, smapsObj_.Pss()[CurrentRow()]); + break; + case SIZE: + sqlite3_result_int64(context_, smapsObj_.Sizes()[CurrentRow()]); + break; + case RESIDE: + sqlite3_result_double(context_, smapsObj_.Resides()[CurrentRow()]); + break; + case PROTECTION: + sqlite3_result_int64(context_, smapsObj_.ProtectionIds()[CurrentRow()]); + break; + case PATH: + sqlite3_result_int64(context_, smapsObj_.PathIds()[CurrentRow()]); + break; + default: + TS_LOGF("Unregistered column : %d", col); + break; + } + return SQLITE_OK; +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/monitor/smaps_table.h b/trace_streamer/src/table/monitor/smaps_table.h new file mode 100644 index 0000000000000000000000000000000000000000..75d3697e951534eba947d5dd8dda646f8d205c4c --- /dev/null +++ b/trace_streamer/src/table/monitor/smaps_table.h @@ -0,0 +1,51 @@ +/* + * 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 SMAPS_TABLE_H +#define SMAPS_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class SmapsTable : public TableBase { +public: + explicit SmapsTable(const TraceDataCache* dataCache); + ~SmapsTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override {} + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override + { + UNUSED(fc); + UNUSED(argv); + return 0; + } + int32_t Column(int32_t col) const override; + + private: + const SmapsData& smapsObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // SMAPS_TABLE_H diff --git a/trace_streamer/src/table/native_hook/BUILD.gn b/trace_streamer/src/table/native_hook/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3fcc9b666e588b0a18de16c7b564bbf19e3b5a1a --- /dev/null +++ b/trace_streamer/src/table/native_hook/BUILD.gn @@ -0,0 +1,55 @@ +# 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("//src/ts.gni") +ohos_source_set("native_hook_tables") { + subsystem_name = "trace_streamer" + part_name = "table" + sources = [ + "native_hook_frame_table.cpp", + "native_hook_frame_table.h", + "native_hook_statistic_table.cpp", + "native_hook_statistic_table.h", + "native_hook_table.cpp", + "native_hook_table.h", + ] + + include_dirs = [ + "../base", + "//third_party/sqlite/include", + "//src/base", + "../../parser", + "//src/trace_data", + "//src/include", + "//src", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } +} diff --git a/trace_streamer/src/table/native_hook/native_hook_frame_table.cpp b/trace_streamer/src/table/native_hook/native_hook_frame_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb6b1c19339f55a8a4f8516980ee1affbe9de9cc --- /dev/null +++ b/trace_streamer/src/table/native_hook/native_hook_frame_table.cpp @@ -0,0 +1,237 @@ +/* + * 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 "native_hook_frame_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, CALLCHAIN_ID, DEPTH, IP, SYMBOL_ID, FILE_ID, OFFSET, SYMBOL_OFFSET, VADDR }; +NativeHookFrameTable::NativeHookFrameTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("depth", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ip", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("symbol_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("file_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("offset", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("symbol_offset", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("vaddr", "TEXT")); + tablePriKey_.push_back("id"); +} + +NativeHookFrameTable::~NativeHookFrameTable() {} + +void NativeHookFrameTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstNativeHookFrameData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void NativeHookFrameTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool NativeHookFrameTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr NativeHookFrameTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +NativeHookFrameTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstNativeHookFrameData().Size())), + nativeHookFrameInfoObj_(dataCache->GetConstNativeHookFrameData()) +{ +} + +NativeHookFrameTable::Cursor::~Cursor() {} + +int32_t NativeHookFrameTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case CALLCHAIN_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + nativeHookFrameInfoObj_.CallChainIds()); + break; + case SYMBOL_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + nativeHookFrameInfoObj_.SymbolNames()); + break; + case FILE_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + nativeHookFrameInfoObj_.FilePaths()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t NativeHookFrameTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case CALLCHAIN_ID: + if (nativeHookFrameInfoObj_.CallChainIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, + static_cast(nativeHookFrameInfoObj_.CallChainIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case DEPTH: + sqlite3_result_int64(context_, static_cast(nativeHookFrameInfoObj_.Depths()[CurrentRow()])); + break; + case IP: + if (nativeHookFrameInfoObj_.Ips()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(nativeHookFrameInfoObj_.Ips()[CurrentRow()])); + } + break; + case SYMBOL_ID: + if (nativeHookFrameInfoObj_.SymbolNames()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, + static_cast(nativeHookFrameInfoObj_.SymbolNames()[CurrentRow()])); + } + break; + case FILE_ID: { + if (nativeHookFrameInfoObj_.FilePaths()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(nativeHookFrameInfoObj_.FilePaths()[CurrentRow()])); + } + break; + } + case OFFSET: { + sqlite3_result_int64(context_, static_cast(nativeHookFrameInfoObj_.Offsets()[CurrentRow()])); + break; + } + case SYMBOL_OFFSET: { + sqlite3_result_int64(context_, static_cast(nativeHookFrameInfoObj_.SymbolOffsets()[CurrentRow()])); + break; + } + case VADDR: { + if (!nativeHookFrameInfoObj_.Vaddrs()[CurrentRow()].empty()) { + sqlite3_result_text(context_, nativeHookFrameInfoObj_.Vaddrs()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/native_hook/native_hook_frame_table.h b/trace_streamer/src/table/native_hook/native_hook_frame_table.h new file mode 100644 index 0000000000000000000000000000000000000000..8bbe93ada06e8d6a97b3aa30ef5b9846df2752cd --- /dev/null +++ b/trace_streamer/src/table/native_hook/native_hook_frame_table.h @@ -0,0 +1,49 @@ +/* + * 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 NATIVE_HOOK_FRAME_TABLE_H +#define NATIVE_HOOK_FRAME_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class NativeHookFrameTable : public TableBase { +public: + explicit NativeHookFrameTable(const TraceDataCache* dataCache); + ~NativeHookFrameTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const NativeHookFrame& nativeHookFrameInfoObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // NATIVE_HOOK_FRAME_TABLE_H diff --git a/trace_streamer/src/table/native_hook/native_hook_statistic_table.cpp b/trace_streamer/src/table/native_hook/native_hook_statistic_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c372edca58d625723e61734a433f88fbd73429d --- /dev/null +++ b/trace_streamer/src/table/native_hook/native_hook_statistic_table.cpp @@ -0,0 +1,227 @@ +/* + * 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 "native_hook_statistic_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { ID = 0, CALLCHAIN_ID, IPID, TS, MEMORY_TYPE, APPLY_COUNT, RELEASE_COUNT, APPLY_SIZE, RELEASE_SIZE }; +NativeHookStatisticTable::NativeHookStatisticTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("type", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("apply_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("release_count", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("apply_size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("release_size", "INTEGER")); + tablePriKey_.push_back("id"); +} + +NativeHookStatisticTable::~NativeHookStatisticTable() {} + +void NativeHookStatisticTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstNativeHookStatisticData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void NativeHookStatisticTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool NativeHookStatisticTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr NativeHookStatisticTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +NativeHookStatisticTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstNativeHookStatisticData().Size())), + nativeHookStatisticInfoObj_(dataCache->GetConstNativeHookStatisticData()) +{ +} + +NativeHookStatisticTable::Cursor::~Cursor() {} + +int32_t NativeHookStatisticTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case CALLCHAIN_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + nativeHookStatisticInfoObj_.CallChainIds()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t NativeHookStatisticTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case CALLCHAIN_ID: + if (nativeHookStatisticInfoObj_.CallChainIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.CallChainIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case IPID: + if (nativeHookStatisticInfoObj_.Ipids()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(nativeHookStatisticInfoObj_.Ipids()[CurrentRow()])); + } + break; + case TS: + if (nativeHookStatisticInfoObj_.TimeStampData()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.TimeStampData()[CurrentRow()])); + } + break; + case MEMORY_TYPE: + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.MemoryTypes()[CurrentRow()])); + break; + case APPLY_COUNT: + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.ApplyCounts()[CurrentRow()])); + break; + case RELEASE_COUNT: + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.ReleaseCounts()[CurrentRow()])); + break; + case APPLY_SIZE: { + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.ApplySizes()[CurrentRow()])); + break; + } + case RELEASE_SIZE: { + sqlite3_result_int64(context_, + static_cast(nativeHookStatisticInfoObj_.ReleaseSizes()[CurrentRow()])); + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/native_hook/native_hook_statistic_table.h b/trace_streamer/src/table/native_hook/native_hook_statistic_table.h new file mode 100644 index 0000000000000000000000000000000000000000..dd8b4e92d48b233b6e5a5def2a749a42462349dd --- /dev/null +++ b/trace_streamer/src/table/native_hook/native_hook_statistic_table.h @@ -0,0 +1,49 @@ +/* + * 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 NATIVE_HOOK_STATISTIC_TABLE_H +#define NATIVE_HOOK_STATISTIC_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class NativeHookStatisticTable : public TableBase { +public: + explicit NativeHookStatisticTable(const TraceDataCache* dataCache); + ~NativeHookStatisticTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const NativeHookStatistic& nativeHookStatisticInfoObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // NATIVE_HOOK_STATISTIC_TABLE_H diff --git a/trace_streamer/src/table/native_hook/native_hook_table.cpp b/trace_streamer/src/table/native_hook/native_hook_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..617ef48f74d8a7f97467d25d7e6b9923499a53ec --- /dev/null +++ b/trace_streamer/src/table/native_hook/native_hook_table.cpp @@ -0,0 +1,274 @@ +/* + * 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 "native_hook_table.h" + +namespace SysTuning { +namespace TraceStreamer { +enum Index { + ID = 0, + CALLCHAIN_ID, + IPID, + ITID, + EVENT_TYPE, + SUB_TYPE_ID, + START_TS, + END_TS, + DURATION, + ADDR, + MEM_SIZE, + ALL_MEM_SIZE, + CURRENT_SIZE_DUR, + LAST_LIB_ID +}; +NativeHookTable::NativeHookTable(const TraceDataCache* dataCache) : TableBase(dataCache) +{ + tableColumn_.push_back(TableBase::ColumnInfo("id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("callchain_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("ipid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("itid", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("event_type", "TEXT")); + tableColumn_.push_back(TableBase::ColumnInfo("sub_type_id", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("start_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("end_ts", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("addr", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("heap_size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("all_heap_size", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("current_size_dur", "INTEGER")); + tableColumn_.push_back(TableBase::ColumnInfo("last_lib_id", "INTEGER")); + tablePriKey_.push_back("id"); +} + +NativeHookTable::~NativeHookTable() {} + +void NativeHookTable::EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) +{ + constexpr double filterBaseCost = 1000.0; // set-up and tear-down + constexpr double indexCost = 2.0; + ei.estimatedCost = filterBaseCost; + + auto rowCount = dataCache_->GetConstNativeHookData().Size(); + if (rowCount == 0 || rowCount == 1) { + ei.estimatedRows = rowCount; + ei.estimatedCost += indexCost * rowCount; + return; + } + + double filterCost = 0.0; + auto constraints = fc.GetConstraints(); + if (constraints.empty()) { // scan all rows + filterCost = rowCount; + } else { + FilterByConstraint(fc, filterCost, rowCount); + } + ei.estimatedCost += filterCost; + ei.estimatedRows = rowCount; + ei.estimatedCost += rowCount * indexCost; + + ei.isOrdered = true; + auto orderbys = fc.GetOrderBys(); + for (auto i = 0; i < orderbys.size(); i++) { + switch (orderbys[i].iColumn) { + case ID: + break; + default: // other columns can be sorted by SQLite + ei.isOrdered = false; + break; + } + } +} + +void NativeHookTable::FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount) +{ + auto fcConstraints = fc.GetConstraints(); + for (int32_t i = 0; i < static_cast(fcConstraints.size()); i++) { + if (rowCount <= 1) { + // only one row or nothing, needn't filter by constraint + filterCost += rowCount; + break; + } + const auto& c = fcConstraints[i]; + switch (c.col) { + case ID: { + if (CanFilterId(c.op, rowCount)) { + fc.UpdateConstraint(i, true); + filterCost += 1; // id can position by 1 step + } else { + filterCost += rowCount; // scan all rows + } + break; + } + default: // other column + filterCost += rowCount; // scan all rows + break; + } + } +} + +bool NativeHookTable::CanFilterId(const char op, size_t& rowCount) +{ + switch (op) { + case SQLITE_INDEX_CONSTRAINT_EQ: + rowCount = 1; + break; + case SQLITE_INDEX_CONSTRAINT_GT: + case SQLITE_INDEX_CONSTRAINT_GE: + case SQLITE_INDEX_CONSTRAINT_LE: + case SQLITE_INDEX_CONSTRAINT_LT: + // assume filter out a half of rows + rowCount = (rowCount >> 1); + break; + default: + return false; + } + return true; +} + +std::unique_ptr NativeHookTable::CreateCursor() +{ + return std::make_unique(dataCache_, this); +} + +NativeHookTable::Cursor::Cursor(const TraceDataCache* dataCache, TableBase* table) + : TableBase::Cursor(dataCache, table, static_cast(dataCache->GetConstNativeHookData().Size())), + nativeHookObj_(dataCache->GetConstNativeHookData()) +{ +} + +NativeHookTable::Cursor::~Cursor() {} + +int32_t NativeHookTable::Cursor::Filter(const FilterConstraints& fc, sqlite3_value** argv) +{ + // reset indexMap_ + indexMap_ = std::make_unique(0, rowCount_); + + if (rowCount_ <= 0) { + return SQLITE_OK; + } + + auto& cs = fc.GetConstraints(); + for (size_t i = 0; i < cs.size(); i++) { + const auto& c = cs[i]; + switch (c.col) { + case ID: + FilterId(c.op, argv[i]); + break; + case IPID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), nativeHookObj_.Ipids()); + break; + case ITID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int(argv[i])), nativeHookObj_.Itids()); + break; + case CALLCHAIN_ID: + indexMap_->MixRange(c.op, static_cast(sqlite3_value_int64(argv[i])), + nativeHookObj_.CallChainIds()); + break; + default: + break; + } + } + + auto orderbys = fc.GetOrderBys(); + for (auto i = orderbys.size(); i > 0;) { + i--; + switch (orderbys[i].iColumn) { + case ID: + indexMap_->SortBy(orderbys[i].desc); + break; + default: + break; + } + } + + return SQLITE_OK; +} + +int32_t NativeHookTable::Cursor::Column(int32_t column) const +{ + switch (column) { + case ID: + sqlite3_result_int64(context_, static_cast(CurrentRow())); + break; + case CALLCHAIN_ID: + if (nativeHookObj_.CallChainIds()[CurrentRow()] != INVALID_UINT32) { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.CallChainIds()[CurrentRow()])); + } else { + sqlite3_result_int64(context_, static_cast(INVALID_CALL_CHAIN_ID)); + } + break; + case IPID: + sqlite3_result_int64(context_, static_cast(nativeHookObj_.Ipids()[CurrentRow()])); + break; + case ITID: + sqlite3_result_int64(context_, static_cast(nativeHookObj_.Itids()[CurrentRow()])); + break; + case EVENT_TYPE: { + if (!nativeHookObj_.EventTypes()[CurrentRow()].empty()) { + sqlite3_result_text(context_, nativeHookObj_.EventTypes()[CurrentRow()].c_str(), STR_DEFAULT_LEN, + nullptr); + } + break; + } + case SUB_TYPE_ID: { + if (nativeHookObj_.SubTypes()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.SubTypes()[CurrentRow()])); + } + break; + } + case START_TS: + sqlite3_result_int64(context_, static_cast(nativeHookObj_.TimeStampData()[CurrentRow()])); + break; + case END_TS: + if (static_cast(nativeHookObj_.EndTimeStamps()[CurrentRow()]) != 0) { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.EndTimeStamps()[CurrentRow()])); + } + break; + case DURATION: + if (static_cast(nativeHookObj_.Durations()[CurrentRow()]) != 0) { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.Durations()[CurrentRow()])); + } + break; + case ADDR: { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.Addrs()[CurrentRow()])); + break; + } + case MEM_SIZE: { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.MemSizes()[CurrentRow()])); + break; + } + case ALL_MEM_SIZE: { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.AllMemSizes()[CurrentRow()])); + break; + } + case CURRENT_SIZE_DUR: { + sqlite3_result_int64(context_, static_cast(nativeHookObj_.CurrentSizeDurs()[CurrentRow()])); + break; + } + case LAST_LIB_ID: { + if (nativeHookObj_.LastCallerPathIndexs()[CurrentRow()] != INVALID_UINT64) { + sqlite3_result_int64(context_, + static_cast(nativeHookObj_.LastCallerPathIndexs()[CurrentRow()])); + } + break; + } + default: + TS_LOGF("Unregistered column : %d", column); + break; + } + return SQLITE_OK; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/table/native_hook/native_hook_table.h b/trace_streamer/src/table/native_hook/native_hook_table.h new file mode 100644 index 0000000000000000000000000000000000000000..556030cf070a235032747810badf3d9ede91d7a5 --- /dev/null +++ b/trace_streamer/src/table/native_hook/native_hook_table.h @@ -0,0 +1,49 @@ +/* + * 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 NATIVE_HOOK_TABLE_H +#define NATIVE_HOOK_TABLE_H + +#include "table_base.h" +#include "trace_data_cache.h" + +namespace SysTuning { +namespace TraceStreamer { +class NativeHookTable : public TableBase { +public: + explicit NativeHookTable(const TraceDataCache* dataCache); + ~NativeHookTable() override; + std::unique_ptr CreateCursor() override; + +private: + void EstimateFilterCost(FilterConstraints& fc, EstimatedIndexInfo& ei) override; + // filter out by operator[=, >, <...] from column(ID) + bool CanFilterId(const char op, size_t& rowCount); + void FilterByConstraint(FilterConstraints& fc, double& filterCost, size_t rowCount); + + class Cursor : public TableBase::Cursor { + public: + explicit Cursor(const TraceDataCache* dataCache, TableBase* table); + ~Cursor() override; + int32_t Filter(const FilterConstraints& fc, sqlite3_value** argv) override; + int32_t Column(int32_t column) const override; + + private: + const NativeHook& nativeHookObj_; + }; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif // NATIVE_HOOK_TABLE_H diff --git a/trace_streamer/src/trace_data/BUILD.gn b/trace_streamer/src/trace_data/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..88e22be0d10ea3efcf2d273d21b117c2b1894610 --- /dev/null +++ b/trace_streamer/src/trace_data/BUILD.gn @@ -0,0 +1,67 @@ +# 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("//src/ts.gni") + +ohos_source_set("trace_data") { + subsystem_name = "trace_streamer" + part_name = "trace_data" + sources = [ + "trace_data_cache.cpp", + "trace_data_cache.h", + "trace_data_cache_base.cpp", + "trace_data_cache_base.h", + "trace_data_cache_reader.cpp", + "trace_data_cache_reader.h", + "trace_data_cache_writer.cpp", + "trace_data_cache_writer.h", + "trace_data_db.cpp", + "trace_data_db.h", + "trace_stdtype.cpp", + "trace_stdtype.h", + ] + + if (enable_ts_utest && !use_wasm) { + cflags = [ + "-fprofile-arcs", + "-ftest-coverage", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + if (is_test) { + cflags += [ "-D IS_UT" ] + } + } + include_dirs = [ + "//third_party/sqlite/include", + "//src", + "//src/base", + "//src/include", + "//src/table", + "//src/table/base", + "//src/table/ebpf", + "//src/table/ftrace", + "//src/table/hiperf", + "//src/table/hi_sysevent", + "//src/table/js_memory", + "//src/table/monitor", + "//src/table/native_hook", + ".", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + ] +} diff --git a/trace_streamer/src/trace_data/trace_data_cache.cpp b/trace_streamer/src/trace_data/trace_data_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e71cf55e96e28517ec06a4b82fb86a6389ad0de --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache.cpp @@ -0,0 +1,268 @@ +/* + * 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 "trace_data_cache.h" +#include "appname_table.h" +#include "args_table.h" +#include "bio_latency_sample_table.h" +#include "callstack_table.h" +#include "clk_event_filter_table.h" +#include "clock_event_filter_table.h" +#include "clock_snapshot_table.h" +#include "cpu_measure_filter_table.h" +#include "cpu_usage_info_table.h" +#include "data_dict_table.h" +#include "data_type_table.h" +#include "datasource_clockid_table.h" +#include "device_state_table.h" +#include "disk_io_table.h" +#include "ebpf_callstack_table.h" +#if WITH_EBPF_HELP +#include "ebpf_elf_symbol_table.h" +#include "ebpf_elf_table.h" +#include "ebpf_process_maps_table.h" +#endif +#include "file_system_sample_table.h" +#include "filter_table.h" +#include "frame_maps_table.h" +#include "frame_slice_table.h" +#include "gpu_slice_table.h" +#include "js_heap_edges_table.h" +#include "js_heap_files_table.h" +#include "js_heap_info_table.h" +#include "js_heap_location_table.h" +#include "js_heap_nodes_table.h" +#include "js_heap_sample_table.h" +#include "js_heap_string_table.h" +#include "js_heap_trace_function_info_table.h" +#include "js_heap_trace_node_table.h" +#include "hidump_table.h" +#include "instants_table.h" +#include "irq_table.h" +#include "live_process_table.h" +#include "log_table.h" +#include "measure_filter_table.h" +#include "measure_table.h" +#include "meta_table.h" +#include "native_hook_frame_table.h" +#include "native_hook_statistic_table.h" +#include "native_hook_table.h" +#include "native_hook_statistic_table.h" +#include "network_table.h" +#include "paged_memory_sample_table.h" +#if WITH_PERF +#include "perf_call_chain_table.h" +#include "perf_files_table.h" +#include "perf_report_table.h" +#include "perf_sample_table.h" +#include "perf_thread_table.h" +#endif +#include "process_filter_table.h" +#include "process_measure_filter_table.h" +#include "process_table.h" +#include "range_table.h" +#include "raw_table.h" +#include "sched_slice_table.h" +#include "smaps_table.h" +#include "span_join.h" +#include "sqlite3.h" +#include "stat_table.h" +#include "symbols_table.h" +#include "sysevent_measure_table.h" +#include "system_call_table.h" +#include "system_event_filter_table.h" +#include "table_base.h" +#include "thread_filter_table.h" +#include "thread_state_table.h" +#include "thread_table.h" +#include "trace_config_table.h" + +namespace SysTuning { +namespace TraceStreamer { +TraceDataCache::TraceDataCache() +{ + InitDB(); +} + +TraceDataCache::~TraceDataCache() {} + +void TraceDataCache::InitDB() +{ + if (dbInited) { + return; + } +#ifdef USE_VTABLE + TableBase::TableDeclare(*db_, this, "process"); + TableBase::TableDeclare(*db_, this, "sched_slice"); + TableBase::TableDeclare(*db_, this, "callstack"); + TableBase::TableDeclare(*db_, this, "thread"); + TableBase::TableDeclare(*db_, this, "thread_state"); + TableBase::TableDeclare(*db_, this, "thread_filter"); + TableBase::TableDeclare(*db_, this, "process_filter"); + TableBase::TableDeclare(*db_, this, "measure_filter"); + TableBase::TableDeclare(*db_, this, "irq"); + TableBase::TableDeclare(*db_, this, "data_dict"); + TableBase::TableDeclare(*db_, this, "raw"); + TableBase::TableDeclare(*db_, this, "symbols"); + TableBase::TableDeclare(*db_, this, "data_type"); + TableBase::TableDeclare(*db_, this, "hidump"); + TableBase::TableDeclare(*db_, this, "native_hook"); + TableBase::TableDeclare(*db_, this, "native_hook_frame"); + TableBase::TableDeclare(*db_, this, "native_hook_statistic"); + TableBase::TableDeclare(*db_, this, "span_join"); + + // no id + TableBase::TableDeclare(*db_, this, "instant"); + TableBase::TableDeclare(*db_, this, "measure"); + TableBase::TableDeclare(*db_, this, "sys_mem_measure"); + TableBase::TableDeclare(*db_, this, "process_measure"); + TableBase::TableDeclare(*db_, this, "trace_range"); + TableBase::TableDeclare(*db_, this, "stat"); + TableBase::TableDeclare(*db_, this, "syscall"); + TableBase::TableDeclare(*db_, this, "meta"); + TableBase::TableDeclare(*db_, this, "log"); + TableBase::TableDeclare(*db_, this, "network"); + + // id is not real id + TableBase::TableDeclare(*db_, this, "cpu_measure_filter"); + TableBase::TableDeclare(*db_, this, "measure_filter"); + TableBase::TableDeclare(*db_, this, "process_measure_filter"); + TableBase::TableDeclare(*db_, this, "clock_event_filter"); + TableBase::TableDeclare(*db_, this, "clk_event_filter"); + TableBase::TableDeclare(*db_, this, "js_heap_files"); + TableBase::TableDeclare(*db_, this, "js_heap_edges"); + TableBase::TableDeclare(*db_, this, "js_heap_info"); + TableBase::TableDeclare(*db_, this, "js_heap_location"); + TableBase::TableDeclare(*db_, this, "js_heap_nodes"); + TableBase::TableDeclare(*db_, this, "js_heap_sample"); + TableBase::TableDeclare(*db_, this, "js_heap_string"); + TableBase::TableDeclare(*db_, this, "js_heap_trace_function_info"); + TableBase::TableDeclare(*db_, this, "js_heap_trace_node"); + TableBase::TableDeclare(*db_, this, "args"); + + TableBase::TableDeclare(*db_, this, "sys_event_filter"); + TableBase::TableDeclare(*db_, this, "diskio"); + TableBase::TableDeclare(*db_, this, "cpu_usage"); + TableBase::TableDeclare(*db_, this, "live_process"); + TableBase::TableDeclare(*db_, this, "file_system_sample"); + TableBase::TableDeclare(*db_, this, "ebpf_callstack"); + TableBase::TableDeclare(*db_, this, "paged_memory_sample"); +#if WITH_EBPF_HELP + TableBase::TableDeclare(*db_, this, "ebpf_process_maps"); + TableBase::TableDeclare(*db_, this, "ebpf_elf"); + TableBase::TableDeclare(*db_, this, "ebpf_elf_symbol"); +#endif + TableBase::TableDeclare(*db_, this, "app_name"); + TableBase::TableDeclare(*db_, this, "hisys_event_measure"); + TableBase::TableDeclare(*db_, this, "trace_config"); + TableBase::TableDeclare(*db_, this, "device_state"); + TableBase::TableDeclare(*db_, this, "smaps"); + TableBase::TableDeclare(*db_, this, "bio_latency_sample"); + TableBase::TableDeclare(*db_, this, "datasource_clockid"); + TableBase::TableDeclare(*db_, this, "clock_snapshot"); + TableBase::TableDeclare(*db_, this, "frame_slice"); + TableBase::TableDeclare(*db_, this, "frame_maps"); + TableBase::TableDeclare(*db_, this, "gpu_slice"); + +#if WITH_PERF + TableBase::TableDeclare(*db_, this, "perf_report"); + TableBase::TableDeclare(*db_, this, "perf_sample"); + TableBase::TableDeclare(*db_, this, "perf_callchain"); + TableBase::TableDeclare(*db_, this, "perf_thread"); + TableBase::TableDeclare(*db_, this, "perf_files"); +#endif +#else + TableBase::TableDeclare(*db_, this, "_process"); + TableBase::TableDeclare(*db_, this, "_sched_slice"); + TableBase::TableDeclare(*db_, this, "_callstack"); + TableBase::TableDeclare(*db_, this, "_thread"); + TableBase::TableDeclare(*db_, this, "_thread_state"); + TableBase::TableDeclare(*db_, this, "_thread_filter"); + TableBase::TableDeclare(*db_, this, "_process_filter"); + TableBase::TableDeclare(*db_, this, "_measure_filter"); + TableBase::TableDeclare(*db_, this, "_irq"); + TableBase::TableDeclare(*db_, this, "_data_dict"); + TableBase::TableDeclare(*db_, this, "_raw"); + TableBase::TableDeclare(*db_, this, "_symbols"); + TableBase::TableDeclare(*db_, this, "_data_type"); + TableBase::TableDeclare(*db_, this, "_hidump"); + TableBase::TableDeclare(*db_, this, "_native_hook"); + TableBase::TableDeclare(*db_, this, "_native_hook_frame"); + TableBase::TableDeclare(*db_, this, "_native_hook_statistic"); + TableBase::TableDeclare(*db_, this, "_span_join"); + + // no id + TableBase::TableDeclare(*db_, this, "_instant"); + TableBase::TableDeclare(*db_, this, "_measure"); + TableBase::TableDeclare(*db_, this, "_sys_mem_measure"); + TableBase::TableDeclare(*db_, this, "_process_measure"); + TableBase::TableDeclare(*db_, this, "_trace_range"); + TableBase::TableDeclare(*db_, this, "_stat"); + TableBase::TableDeclare(*db_, this, "_syscall"); + TableBase::TableDeclare(*db_, this, "_meta"); + TableBase::TableDeclare(*db_, this, "_log"); + TableBase::TableDeclare(*db_, this, "_network"); + + // id is not real id + TableBase::TableDeclare(*db_, this, "_cpu_measure_filter"); + TableBase::TableDeclare(*db_, this, "_measure_filter"); + TableBase::TableDeclare(*db_, this, "_process_measure_filter"); + TableBase::TableDeclare(*db_, this, "_clock_event_filter"); + TableBase::TableDeclare(*db_, this, "_clk_event_filter"); + TableBase::TableDeclare(*db_, this, "_js_heap_files"); + TableBase::TableDeclare(*db_, this, "_js_heap_edges"); + TableBase::TableDeclare(*db_, this, "_js_heap_info"); + TableBase::TableDeclare(*db_, this, "_js_heap_location"); + TableBase::TableDeclare(*db_, this, "_js_heap_nodes"); + TableBase::TableDeclare(*db_, this, "_js_heap_sample"); + TableBase::TableDeclare(*db_, this, "_js_heap_string"); + TableBase::TableDeclare(*db_, this, "_js_heap_trace_function_info"); + TableBase::TableDeclare(*db_, this, "_js_heap_trace_node"); + TableBase::TableDeclare(*db_, this, "_args"); + TableBase::TableDeclare(*db_, this, "_sys_event_filter"); + TableBase::TableDeclare(*db_, this, "_diskio"); + TableBase::TableDeclare(*db_, this, "_cpu_usage"); + TableBase::TableDeclare(*db_, this, "_live_process"); + TableBase::TableDeclare(*db_, this, "_file_system_sample"); + TableBase::TableDeclare(*db_, this, "_ebpf_callstack"); + TableBase::TableDeclare(*db_, this, "_paged_memory_sample"); + TableBase::TableDeclare(*db_, this, "_smaps"); + TableBase::TableDeclare(*db_, this, "_bio_latency_sample"); + TableBase::TableDeclare(*db_, this, "_datasource_clockid"); + TableBase::TableDeclare(*db_, this, "_clock_snapshot"); + TableBase::TableDeclare(*db_, this, "_frame_slice"); + TableBase::TableDeclare(*db_, this, "_frame_maps"); + TableBase::TableDeclare(*db_, this, "_gpu_slice"); +#if WITH_EBPF_HELP + TableBase::TableDeclare(*db_, this, "_ebpf_process_maps"); + TableBase::TableDeclare(*db_, this, "_ebpf_elf"); + TableBase::TableDeclare(*db_, this, "_ebpf_elf_symbol"); +#endif + TableBase::TableDeclare(*db_, this, "_app_name"); + TableBase::TableDeclare(*db_, this, "_hisys_event_measure"); + TableBase::TableDeclare(*db_, this, "_device_state"); + TableBase::TableDeclare(*db_, this, "_trace_config"); +#if WITH_PERF + TableBase::TableDeclare(*db_, this, "_perf_report"); + TableBase::TableDeclare(*db_, this, "_perf_sample"); + TableBase::TableDeclare(*db_, this, "_perf_callchain"); + TableBase::TableDeclare(*db_, this, "_perf_thread"); + TableBase::TableDeclare(*db_, this, "_perf_files"); +#endif +#endif + dbInited = true; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_data_cache.h b/trace_streamer/src/trace_data/trace_data_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..a53e2ae0a635e252cdaa42f87cc6b9edd41fc864 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache.h @@ -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. + */ + +#ifndef TRACE_DATA_CACHE_H +#define TRACE_DATA_CACHE_H + +#include +#include "trace_data_cache_reader.h" +#include "trace_data_cache_writer.h" +#include "trace_data_db.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCache : public TraceDataCacheReader, public TraceDataCacheWriter, public TraceDataDB { +public: + TraceDataCache(); + TraceDataCache(const TraceDataCache* dataCache) = delete; + TraceDataCache* operator=(const TraceDataCache* dataCache) = delete; + ~TraceDataCache() override; + +private: + void InitDB() override; + bool dbInited = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_DATA_CACHE_H diff --git a/trace_streamer/src/trace_data/trace_data_cache_base.cpp b/trace_streamer/src/trace_data/trace_data_cache_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bc4ad2d1afa5bab59e3371d807e9d0c95091caa --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache_base.cpp @@ -0,0 +1,50 @@ +/* + * 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 "trace_data_cache_base.h" +#include + +namespace SysTuning { +namespace TraceStreamer { +TraceDataCacheBase::TraceDataCacheBase() +{ + internalProcessesData_.emplace_back(0); + internalThreadsData_.emplace_back(0); + internalThreadsData_.front().internalPid_ = 0; + GetDataIndex(""); + auto it = statusString_.rbegin(); + for (it++; it != statusString_.rend(); it++) { + threadStatus2Value_[it->second] = it->first; + } +} +DataIndex TraceDataCacheBase::GetDataIndex(std::string_view str) +{ + return dataDict_.GetStringIndex(str); +} + +DataIndex TraceDataCacheBase::GetConstDataIndex(std::string_view str) const +{ + return dataDict_.GetStringIndexNoWrite(str); +} +void TraceDataCacheBase::UpdataZeroThreadInfo() +{ + const std::string ZERO_THREAD_NAME = "swapper"; + internalProcessesData_.front().cmdLine_ = ZERO_THREAD_NAME; + auto& thread = internalThreadsData_.front(); + thread.internalPid_ = 0; + thread.nameIndex_ = dataDict_.GetStringIndex(ZERO_THREAD_NAME); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_data_cache_base.h b/trace_streamer/src/trace_data/trace_data_cache_base.h new file mode 100644 index 0000000000000000000000000000000000000000..0a9fa64c168cab12fb2c6b5128d41a749a17af9f --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache_base.h @@ -0,0 +1,168 @@ +/* + * 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 TRACE_DATA_CACHE_BASE_H +#define TRACE_DATA_CACHE_BASE_H + +#include +#include +#include +#include +#include +#include +#include "trace_stdtype.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheBase { +public: + TraceDataCacheBase(); + TraceDataCacheBase(const TraceDataCacheBase&) = delete; + TraceDataCacheBase& operator=(const TraceDataCacheBase&) = delete; + virtual ~TraceDataCacheBase() = default; + +public: + size_t ThreadSize() const + { + return internalThreadsData_.size(); + } + size_t ProcessSize() const + { + return internalProcessesData_.size(); + } + + void UpdataZeroThreadInfo(); + size_t DataDictSize() const + { + return dataDict_.Size(); + } + void UpdateTraceRange() + { + metaData_.SetTraceDuration((traceEndTime_ - traceStartTime_) / SEC_TO_NS); + } + uint64_t GetThreadStateValue(const std::string& status) const + { + if (threadStatus2Value_.count(status)) { + return threadStatus2Value_.at(status); + } + return INVALID_UINT64; + } + DataIndex GetDataIndex(std::string_view str); + DataIndex GetConstDataIndex(std::string_view str) const; + std::map statusString_ = {{TASK_RUNNABLE, "R"}, + {TASK_INTERRUPTIBLE, "S"}, + {TASK_UNINTERRUPTIBLE, "D"}, + {TASK_UNINTERRUPTIBLE_IO, "D-IO"}, + {TASK_UNINTERRUPTIBLE_NIO, "D-NIO"}, + {TASK_RUNNING, "Running"}, + {TASK_INTERRUPTED, "I"}, + {TASK_TRACED, "T"}, + {TASK_EXIT_DEAD, "X"}, + {TASK_ZOMBIE, "Z"}, + {TASK_KILLED, "I"}, + {TASK_WAKEKILL, "R"}, + {TASK_PARKED, "P"}, + {TASK_INVALID, "U"}, + {TASK_CLONE, "I"}, + {TASK_DK, "DK"}, + {TASK_DK_IO, "DK-IO"}, + {TASK_DK_NIO, "DK-NIO"}, + {TASK_TRACED_KILL, "TK"}, + {TASK_FOREGROUND, "R+"}, + {TASK_MAX, "S"}}; + std::map threadStatus2Value_ = {}; + uint64_t traceStartTime_ = std::numeric_limits::max(); + uint64_t traceEndTime_ = 0; + + Raw rawData_; + ThreadState threadStateData_; + Instants instantsData_; + + Filter filterData_; + ProcessMeasureFilter processMeasureFilterData_; + ClockEventData clockEventFilterData_; + ClkEventData clkEventFilterData_; + ProcessMeasureFilter processFilterData_; + ThreadMeasureFilter threadMeasureFilterData_; + ThreadMeasureFilter threadFilterData_; + DataDict dataDict_; + + SchedSlice schedSliceData_; + CallStack callstackData_; + CallStack irqData_; + LogInfo hilogData_; + NativeHook nativeHookData_; + NativeHookFrame nativeHookFrameData_; + NativeHookStatistic nativeHookStatisticData_; + Hidump hidumpData_; + PerfSample perfSample_; + PerfCallChain perfCallChain_; + PerfThread perfThread_; + PerfFiles perfFiles_; + PerfReport perfReport_; + + std::deque internalProcessesData_ = {}; + std::deque internalThreadsData_ = {}; + + Measure measureData_; + Measure sysMemMeasureData_; + Measure processMeasureData_; + CpuMeasureFilter cpuMeasureData_; + + StatAndInfo stat_; + MetaData metaData_; + SymbolsData symbolsData_; + SysCall sysCallData_; + ArgSet argSet_; + DataType dataType_; + SysMeasureFilter sysEvent_; + NetDetailData networkData_; + NetDetailData networkDetailData_; + CpuUsageDetailData cpuUsageData_; + DiskIOData diskIOData_; + LiveProcessDetailData liveProcessDetailData_; + FileSystemSample fileSamplingTableData_; + EbpfCallStackData ebpfCallStackData_; + PagedMemorySampleData PagedMemorySampleData_; +#if WITH_EBPF_HELP + EbpfProcessMaps ebpfProcessMaps_; + EbpfElf ebpfElf_; + EbpfElfSymbol ebpfElfSymbol_; +#endif + AppNames appNames_; + SysEventMeasureData sysEventMeasureData_; + DeviceStateData deviceStateData_; + TraceConfigData traceConfigData_; + SmapsData smapsData_; + BioLatencySampleData bioLatencySampleData_; + ClockSnapshotData clockSnapshotData_; + DataSourceClockIdData dataSourceClockIdData_; + FrameSlice frameSliceData_; + FrameMaps frameMapsData_; + GPUSlice gpuSliceData_; + JsHeapFiles jsHeapFilesData_; + JsHeapEdges jsHeapEdgesData_; + JsHeapInfo jsHeapInfoData_; + JsHeapLocation jsHeapLocationData_; + JsHeapNodes jsHeapNodesData_; + JsHeapSample jsHeapSampleData_; + JsHeapString jsHeapStringData_; + JsHeapTraceFuncInfo jsHeapTraceFuncInfoData_; + JsHeapTraceNode jsHeapTraceNodeData_; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_DATA_CACHE_BASE_H diff --git a/trace_streamer/src/trace_data/trace_data_cache_reader.cpp b/trace_streamer/src/trace_data/trace_data_cache_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f1166181ac32d1159bb90080df16f828a06e560 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache_reader.cpp @@ -0,0 +1,330 @@ +/* + * 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 "trace_data_cache_reader.h" +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +TraceDataCacheReader::~TraceDataCacheReader() {} +const std::string& TraceDataCacheReader::GetDataFromDict(DataIndex id) const +{ + return dataDict_.GetDataFromDict(id); +} + +const std::deque& TraceDataCacheReader::GetConstProcessData() const +{ + return internalProcessesData_; +} +const Process& TraceDataCacheReader::GetConstProcessData(InternalPid internalPid) const +{ + TS_ASSERT(internalPid < internalProcessesData_.size()); + return internalProcessesData_[internalPid]; +} +const Thread& TraceDataCacheReader::GetConstThreadData(InternalTid internalTid) const +{ + TS_ASSERT(internalTid < internalThreadsData_.size()); + return internalThreadsData_[internalTid]; +} + +const std::deque& TraceDataCacheReader::GetConstThreadData() const +{ + return internalThreadsData_; +} +const CallStack& TraceDataCacheReader::GetConstInternalSlicesData() const +{ + return callstackData_; +} +const CallStack& TraceDataCacheReader::GetConstIrqData() const +{ + return irqData_; +} +const Filter& TraceDataCacheReader::GetConstFilterData() const +{ + return filterData_; +} +const Raw& TraceDataCacheReader::GetConstRawTableData() const +{ + return rawData_; +} +const Measure& TraceDataCacheReader::GetConstMeasureData() const +{ + return measureData_; +} +const Measure& TraceDataCacheReader::GetConstSysMemMeasureData() const +{ + return sysMemMeasureData_; +} +const Measure& TraceDataCacheReader::GetConstProcessMeasureData() const +{ + return processMeasureData_; +} + +const ThreadMeasureFilter& TraceDataCacheReader::GetConstThreadMeasureFilterData() const +{ + return threadMeasureFilterData_; +} +const ThreadState& TraceDataCacheReader::GetConstThreadStateData() const +{ + return threadStateData_; +} +const SchedSlice& TraceDataCacheReader::GetConstSchedSliceData() const +{ + return schedSliceData_; +} +const CpuMeasureFilter& TraceDataCacheReader::GetConstCpuMeasureData() const +{ + return cpuMeasureData_; +} +const ThreadMeasureFilter& TraceDataCacheReader::GetConstThreadFilterData() const +{ + return threadFilterData_; +} +const Instants& TraceDataCacheReader::GetConstInstantsData() const +{ + return instantsData_; +} +const ProcessMeasureFilter& TraceDataCacheReader::GetConstProcessFilterData() const +{ + return processFilterData_; +} +const ProcessMeasureFilter& TraceDataCacheReader::GetConstProcessMeasureFilterData() const +{ + return processMeasureFilterData_; +} + +const ClockEventData& TraceDataCacheReader::GetConstClockEventFilterData() const +{ + return clockEventFilterData_; +} +const ClkEventData& TraceDataCacheReader::GetConstClkEventFilterData() const +{ + return clkEventFilterData_; +} +const std::string& TraceDataCacheReader::GetConstSchedStateData(uint64_t rowId) const +{ + TS_ASSERT(statusString_.find(rowId) != statusString_.end()); + return statusString_.at(rowId); +} +uint64_t TraceDataCacheReader::TraceStartTime() const +{ + return traceStartTime_; +} +uint64_t TraceDataCacheReader::TraceEndTime() const +{ + return traceEndTime_; +} + +const StatAndInfo& TraceDataCacheReader::GetConstStatAndInfo() const +{ + return stat_; +} +const MetaData& TraceDataCacheReader::GetConstMetaData() const +{ + return metaData_; +} + +const SymbolsData& TraceDataCacheReader::GetConstSymbolsData() const +{ + return symbolsData_; +} + +const LogInfo& TraceDataCacheReader::GetConstHilogData() const +{ + return hilogData_; +} + +const NativeHook& TraceDataCacheReader::GetConstNativeHookData() const +{ + return nativeHookData_; +} + +const NativeHookFrame& TraceDataCacheReader::GetConstNativeHookFrameData() const +{ + return nativeHookFrameData_; +} +const NativeHookStatistic& TraceDataCacheReader::GetConstNativeHookStatisticData() const +{ + return nativeHookStatisticData_; +} +const Hidump& TraceDataCacheReader::GetConstHidumpData() const +{ + return hidumpData_; +} + +const PerfCallChain& TraceDataCacheReader::GetConstPerfCallChainData() const +{ + return perfCallChain_; +} +const PerfFiles& TraceDataCacheReader::GetConstPerfFilesData() const +{ + return perfFiles_; +} +const PerfSample& TraceDataCacheReader::GetConstPerfSampleData() const +{ + return perfSample_; +} +const PerfThread& TraceDataCacheReader::GetConstPerfThreadData() const +{ + return perfThread_; +} +const PerfReport& TraceDataCacheReader::GetConstPerfReportData() const +{ + return perfReport_; +} +const SysCall& TraceDataCacheReader::GetConstSysCallData() const +{ + return sysCallData_; +} +const ArgSet& TraceDataCacheReader::GetConstArgSetData() const +{ + return argSet_; +} +const JsHeapFiles& TraceDataCacheReader::GetConstJsHeapFilesData() const +{ + return jsHeapFilesData_; +} +const JsHeapEdges& TraceDataCacheReader::GetConstJsHeapEdgesData() const +{ + return jsHeapEdgesData_; +} +const JsHeapInfo& TraceDataCacheReader::GetConstJsHeapInfoData() const +{ + return jsHeapInfoData_; +} +const JsHeapLocation& TraceDataCacheReader::GetConstJsHeapLocationData() const +{ + return jsHeapLocationData_; +} +const JsHeapNodes& TraceDataCacheReader::GetConstJsHeapNodesData() const +{ + return jsHeapNodesData_; +} +const JsHeapSample& TraceDataCacheReader::GetConstJsHeapSampleData() const +{ + return jsHeapSampleData_; +} +const JsHeapString& TraceDataCacheReader::GetConstJsHeapStringData() const +{ + return jsHeapStringData_; +} +const JsHeapTraceFuncInfo& TraceDataCacheReader::GetConstJsHeapTraceFuncInfoData() const +{ + return jsHeapTraceFuncInfoData_; +} +const JsHeapTraceNode& TraceDataCacheReader::GetConstJsHeapTraceNodeData() const +{ + return jsHeapTraceNodeData_; +} + +const DataType& TraceDataCacheReader::GetConstDataTypeData() const +{ + return dataType_; +} + +const SysMeasureFilter& TraceDataCacheReader::GetConstSysMeasureFilterData() const +{ + return sysEvent_; +} +const NetDetailData& TraceDataCacheReader::GetConstNetworkData() const +{ + return networkData_; +} +const CpuUsageDetailData& TraceDataCacheReader::GetConstCpuUsageInfoData() const +{ + return cpuUsageData_; +} +const DiskIOData& TraceDataCacheReader::GetConstDiskIOData() const +{ + return diskIOData_; +} +const LiveProcessDetailData& TraceDataCacheReader::GetConstLiveProcessData() const +{ + return liveProcessDetailData_; +} +const FileSystemSample& TraceDataCacheReader::GetConstFileSystemSample() const +{ + return fileSamplingTableData_; +} +const EbpfCallStackData& TraceDataCacheReader::GetConstEbpfCallStackData() const +{ + return ebpfCallStackData_; +} +const PagedMemorySampleData& TraceDataCacheReader::GetConstPagedMemorySampleData() const +{ + return PagedMemorySampleData_; +} +#if WITH_EBPF_HELP +const EbpfProcessMaps& TraceDataCacheReader::GetConstEbpfProcessMaps() const +{ + return ebpfProcessMaps_; +} +const EbpfElf& TraceDataCacheReader::GetConstEbpfElf() const +{ + return ebpfElf_; +} +const EbpfElfSymbol& TraceDataCacheReader::GetConstEbpfElfSymbol() const +{ + return ebpfElfSymbol_; +} +#endif +const AppNames& TraceDataCacheReader::GetConstAppNamesData() const +{ + return appNames_; +} +const SysEventMeasureData& TraceDataCacheReader::GetConstSyseventMeasureData() const +{ + return sysEventMeasureData_; +} +const TraceConfigData& TraceDataCacheReader::GetConstTraceConfigData() const +{ + return traceConfigData_; +} +const DeviceStateData& TraceDataCacheReader::GetConstDeviceStateData() const +{ + return deviceStateData_; +} +const SmapsData& TraceDataCacheReader::GetConstSmapsData() const +{ + return smapsData_; +} +const BioLatencySampleData& TraceDataCacheReader::GetConstBioLatencySampleData() const +{ + return bioLatencySampleData_; +} + +const ClockSnapshotData& TraceDataCacheReader::GetConstClockSnapshotData() const +{ + return clockSnapshotData_; +} + +const DataSourceClockIdData& TraceDataCacheReader::GetConstDataSourceClockIdData() const +{ + return dataSourceClockIdData_; +} +const FrameSlice& TraceDataCacheReader::GetConstFameSliceData() const +{ + return frameSliceData_; +} +const FrameMaps& TraceDataCacheReader::GetConstFameMapsData() const +{ + return frameMapsData_; +} +const GPUSlice& TraceDataCacheReader::GetConstGPUSliceData() const +{ + return gpuSliceData_; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_data_cache_reader.h b/trace_streamer/src/trace_data/trace_data_cache_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..9894b31e1c4817e53adc4089b3b0931a883eabf5 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache_reader.h @@ -0,0 +1,111 @@ +/* + * 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 TRACE_DATA_CACHE_READER_H +#define TRACE_DATA_CACHE_READER_H + +#include "log.h" +#include "trace_data_cache_base.h" +#include "trace_stdtype.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheReader : virtual public TraceDataCacheBase { +public: + TraceDataCacheReader() = default; + TraceDataCacheReader(const TraceDataCacheReader&) = delete; + TraceDataCacheReader& operator=(const TraceDataCacheReader&) = delete; + ~TraceDataCacheReader() override; + +public: + const std::string& GetDataFromDict(DataIndex id) const; + const Process& GetConstProcessData(InternalPid internalPid) const; + const std::deque& GetConstProcessData() const; + const Thread& GetConstThreadData(InternalTid internalTid) const; + const std::deque& GetConstThreadData() const; + const CallStack& GetConstInternalSlicesData() const; + const CallStack& GetConstIrqData() const; + const Filter& GetConstFilterData() const; + const Raw& GetConstRawTableData() const; + const Measure& GetConstMeasureData() const; + const Measure& GetConstSysMemMeasureData() const; + const Measure& GetConstProcessMeasureData() const; + const ThreadMeasureFilter& GetConstThreadMeasureFilterData() const; + const ThreadState& GetConstThreadStateData() const; + const SchedSlice& GetConstSchedSliceData() const; + const CpuMeasureFilter& GetConstCpuMeasureData() const; + const ThreadMeasureFilter& GetConstThreadFilterData() const; + const Instants& GetConstInstantsData() const; + const ProcessMeasureFilter& GetConstProcessFilterData() const; + const ProcessMeasureFilter& GetConstProcessMeasureFilterData() const; + const ClockEventData& GetConstClockEventFilterData() const; + const ClkEventData& GetConstClkEventFilterData() const; + const std::string& GetConstSchedStateData(uint64_t rowId) const; + uint64_t TraceStartTime() const; + uint64_t TraceEndTime() const; + const StatAndInfo& GetConstStatAndInfo() const; + const MetaData& GetConstMetaData() const; + const SymbolsData& GetConstSymbolsData() const; + const SysCall& GetConstSysCallData() const; + const LogInfo& GetConstHilogData() const; + const NativeHook& GetConstNativeHookData() const; + const NativeHookFrame& GetConstNativeHookFrameData() const; + const NativeHookStatistic& GetConstNativeHookStatisticData() const; + const Hidump& GetConstHidumpData() const; + const PerfCallChain& GetConstPerfCallChainData() const; + const PerfFiles& GetConstPerfFilesData() const; + const PerfSample& GetConstPerfSampleData() const; + const PerfThread& GetConstPerfThreadData() const; + const PerfReport& GetConstPerfReportData() const; + const ArgSet& GetConstArgSetData() const; + const DataType& GetConstDataTypeData() const; + const SysMeasureFilter& GetConstSysMeasureFilterData() const; + const NetDetailData& GetConstNetworkData() const; + const CpuUsageDetailData& GetConstCpuUsageInfoData() const; + const DiskIOData& GetConstDiskIOData() const; + const LiveProcessDetailData& GetConstLiveProcessData() const; + const FileSystemSample& GetConstFileSystemSample() const; + const DeviceStateData& GetConstDeviceStateData() const; + const EbpfCallStackData& GetConstEbpfCallStackData() const; + const PagedMemorySampleData& GetConstPagedMemorySampleData() const; +#if WITH_EBPF_HELP + const EbpfProcessMaps& GetConstEbpfProcessMaps() const; + const EbpfElf& GetConstEbpfElf() const; + const EbpfElfSymbol& GetConstEbpfElfSymbol() const; +#endif + const AppNames& GetConstAppNamesData() const; + const SysEventMeasureData& GetConstSyseventMeasureData() const; + const TraceConfigData& GetConstTraceConfigData() const; + const SmapsData& GetConstSmapsData() const; + const BioLatencySampleData& GetConstBioLatencySampleData() const; + const ClockSnapshotData& GetConstClockSnapshotData() const; + const DataSourceClockIdData& GetConstDataSourceClockIdData() const; + const FrameSlice& GetConstFameSliceData() const; + const FrameMaps& GetConstFameMapsData() const; + const GPUSlice& GetConstGPUSliceData() const; + const JsHeapFiles& GetConstJsHeapFilesData() const; + const JsHeapEdges& GetConstJsHeapEdgesData() const; + const JsHeapInfo& GetConstJsHeapInfoData() const; + const JsHeapLocation& GetConstJsHeapLocationData() const; + const JsHeapNodes& GetConstJsHeapNodesData() const; + const JsHeapSample& GetConstJsHeapSampleData() const; + const JsHeapString& GetConstJsHeapStringData() const; + const JsHeapTraceFuncInfo& GetConstJsHeapTraceFuncInfoData() const; + const JsHeapTraceNode& GetConstJsHeapTraceNodeData() const; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/trace_data/trace_data_cache_writer.cpp b/trace_streamer/src/trace_data/trace_data_cache_writer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..907138ff465cc7a499ede9b795f6a4a453f03f65 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache_writer.cpp @@ -0,0 +1,436 @@ +/* + * 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 "trace_data_cache_writer.h" +#include "log.h" +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +TraceDataCacheWriter::~TraceDataCacheWriter() {} +InternalPid TraceDataCacheWriter::GetProcessInternalPid(uint32_t pid) +{ + internalProcessesData_.emplace_back(pid); + return static_cast(internalProcessesData_.size() - 1); +} +Process* TraceDataCacheWriter::GetProcessData(InternalPid internalPid) +{ + TS_ASSERT(internalPid < internalProcessesData_.size()); + return &internalProcessesData_[internalPid]; +} + +uint32_t TraceDataCacheWriter::AppendNewProcessData(uint32_t pid, const std::string& name, uint64_t startTs) +{ + internalProcessesData_.emplace_back(pid); + auto& process = internalProcessesData_.back(); + process.cmdLine_ = name; + process.startT_ = startTs; + return internalProcessesData_.size() - 1; +} + +InternalTid TraceDataCacheWriter::NewInternalThread(uint32_t tid) +{ + internalThreadsData_.emplace_back(tid); + return static_cast(internalThreadsData_.size() - 1); +} +Thread* TraceDataCacheWriter::GetThreadData(InternalTid internalTid) +{ + if (internalTid >= internalThreadsData_.size()) { + return nullptr; + } + return &internalThreadsData_[internalTid]; +} + +void TraceDataCacheWriter::UpdateTraceTime(uint64_t timeStamp) +{ + if (timeStamp) { + traceStartTime_ = std::min(traceStartTime_, timeStamp); + traceEndTime_ = std::max(traceEndTime_, timeStamp); + } +} + +void TraceDataCacheWriter::MixTraceTime(uint64_t timestampMin, uint64_t timestampMax) +{ + if (timestampMin == std::numeric_limits::max() || timestampMax == 0 || timestampMin == timestampMax) { + return; + } + if (traceStartTime_ != std::numeric_limits::max()) { + traceStartTime_ = std::max(traceStartTime_, timestampMin); + } else { + traceStartTime_ = timestampMin; + } + if (traceEndTime_) { + traceEndTime_ = std::min(traceEndTime_, timestampMax); + } else { + traceEndTime_ = timestampMax; + } +} +CallStack* TraceDataCacheWriter::GetInternalSlicesData() +{ + return &callstackData_; +} +CallStack* TraceDataCacheWriter::GetIrqData() +{ + return &irqData_; +} + +Filter* TraceDataCacheWriter::GetFilterData() +{ + return &filterData_; +} + +Raw* TraceDataCacheWriter::GetRawData() +{ + return &rawData_; +} + +Measure* TraceDataCacheWriter::GetMeasureData() +{ + return &measureData_; +} + +Measure* TraceDataCacheWriter::GetSysMemMeasureData() +{ + return &sysMemMeasureData_; +} +Measure* TraceDataCacheWriter::GetProcessMeasureData() +{ + return &processMeasureData_; +} + +ThreadState* TraceDataCacheWriter::GetThreadStateData() +{ + return &threadStateData_; +} + +SchedSlice* TraceDataCacheWriter::GetSchedSliceData() +{ + return &schedSliceData_; +} + +CpuMeasureFilter* TraceDataCacheWriter::GetCpuMeasuresData() +{ + return &cpuMeasureData_; +} + +ThreadMeasureFilter* TraceDataCacheWriter::GetThreadMeasureFilterData() +{ + return &threadMeasureFilterData_; +} + +ThreadMeasureFilter* TraceDataCacheWriter::GetThreadFilterData() +{ + return &threadFilterData_; +} + +Instants* TraceDataCacheWriter::GetInstantsData() +{ + return &instantsData_; +} + +ProcessMeasureFilter* TraceDataCacheWriter::GetProcessFilterData() +{ + return &processFilterData_; +} + +ProcessMeasureFilter* TraceDataCacheWriter::GetProcessMeasureFilterData() +{ + return &processMeasureFilterData_; +} + +ClockEventData* TraceDataCacheWriter::GetClockEventFilterData() +{ + return &clockEventFilterData_; +} + +ClkEventData* TraceDataCacheWriter::GetClkEventFilterData() +{ + return &clkEventFilterData_; +} +StatAndInfo* TraceDataCacheWriter::GetStatAndInfo() +{ + return &stat_; +} + +MetaData* TraceDataCacheWriter::GetMetaData() +{ + return &metaData_; +} + +SymbolsData* TraceDataCacheWriter::GetSymbolsData() +{ + return &symbolsData_; +} +SysCall* TraceDataCacheWriter::GetSysCallData() +{ + return &sysCallData_; +} +LogInfo* TraceDataCacheWriter::GetHilogData() +{ + return &hilogData_; +} + +NativeHook* TraceDataCacheWriter::GetNativeHookData() +{ + return &nativeHookData_; +} + +NativeHookFrame* TraceDataCacheWriter::GetNativeHookFrameData() +{ + return &nativeHookFrameData_; +} + +NativeHookStatistic* TraceDataCacheWriter::GetNativeHookStatisticsData() +{ + return &nativeHookStatisticData_; +} +Hidump* TraceDataCacheWriter::GetHidumpData() +{ + return &hidumpData_; +} +PerfCallChain* TraceDataCacheWriter::GetPerfCallChainData() +{ + return &perfCallChain_; +} +PerfFiles* TraceDataCacheWriter::GetPerfFilesData() +{ + return &perfFiles_; +} +PerfSample* TraceDataCacheWriter::GetPerfSampleData() +{ + return &perfSample_; +} +PerfThread* TraceDataCacheWriter::GetPerfThreadData() +{ + return &perfThread_; +} +PerfReport* TraceDataCacheWriter::GetPerfReportData() +{ + return &perfReport_; +} +ArgSet* TraceDataCacheWriter::GetArgSetData() +{ + return &argSet_; +} + +DataType* TraceDataCacheWriter::GetDataTypeData() +{ + return &dataType_; +} + +SysMeasureFilter* TraceDataCacheWriter::GetSysMeasureFilterData() +{ + return &sysEvent_; +} +NetDetailData* TraceDataCacheWriter::GetNetworkData() +{ + return &networkData_; +} +NetDetailData* TraceDataCacheWriter::GetNetworkDetailData() +{ + return &networkDetailData_; +} +DiskIOData* TraceDataCacheWriter::GetDiskIOData() +{ + return &diskIOData_; +} + +CpuUsageDetailData* TraceDataCacheWriter::GetCpuUsageInfoData() +{ + return &cpuUsageData_; +} +LiveProcessDetailData* TraceDataCacheWriter::GetLiveProcessData() +{ + return &liveProcessDetailData_; +} +FileSystemSample* TraceDataCacheWriter::GetFileSystemSample() +{ + return &fileSamplingTableData_; +} +EbpfCallStackData* TraceDataCacheWriter::GetEbpfCallStack() +{ + return &ebpfCallStackData_; +} +PagedMemorySampleData* TraceDataCacheWriter::GetPagedMemorySampleData() +{ + return &PagedMemorySampleData_; +} +#if WITH_EBPF_HELP +EbpfProcessMaps* TraceDataCacheWriter::GetEbpfProcessMaps() +{ + return &ebpfProcessMaps_; +} +EbpfElf* TraceDataCacheWriter::GetEbpfElf() +{ + return &ebpfElf_; +} +EbpfElfSymbol* TraceDataCacheWriter::GetEbpfElfSymbol() +{ + return &ebpfElfSymbol_; +} +#endif +AppNames* TraceDataCacheWriter::GetAppNamesData() +{ + return &appNames_; +} +SysEventMeasureData* TraceDataCacheWriter::GetSyseventMeasureData() +{ + return &sysEventMeasureData_; +} +DeviceStateData* TraceDataCacheWriter::GetDeviceStateData() +{ + return &deviceStateData_; +} +TraceConfigData* TraceDataCacheWriter::GetTraceConfigData() +{ + return &traceConfigData_; +} +SmapsData* TraceDataCacheWriter::GetSmapsData() +{ + return &smapsData_; +} +BioLatencySampleData* TraceDataCacheWriter::GetBioLatencySampleData() +{ + return &bioLatencySampleData_; +} + +ClockSnapshotData* TraceDataCacheWriter::GetClockSnapshotData() +{ + return &clockSnapshotData_; +} +DataSourceClockIdData* TraceDataCacheWriter::GetDataSourceClockIdData() +{ + return &dataSourceClockIdData_; +} +FrameSlice* TraceDataCacheWriter::GetFrameSliceData() +{ + return &frameSliceData_; +} +FrameMaps* TraceDataCacheWriter::GetFrameMapsData() +{ + return &frameMapsData_; +} + +GPUSlice* TraceDataCacheWriter::GetGPUSliceData() +{ + return &gpuSliceData_; +} + +JsHeapFiles* TraceDataCacheWriter::GetJsHeapFilesData() +{ + return &jsHeapFilesData_; +} +JsHeapEdges* TraceDataCacheWriter::GetJsHeapEdgesData() +{ + return &jsHeapEdgesData_; +} +JsHeapInfo* TraceDataCacheWriter::GetJsHeapInfoData() +{ + return &jsHeapInfoData_; +} +JsHeapLocation* TraceDataCacheWriter::GetJsHeapLocationData() +{ + return &jsHeapLocationData_; +} +JsHeapNodes* TraceDataCacheWriter::GetJsHeapNodesData() +{ + return &jsHeapNodesData_; +} +JsHeapSample* TraceDataCacheWriter::GetJsHeapSampleData() +{ + return &jsHeapSampleData_; +} +JsHeapString* TraceDataCacheWriter::GetJsHeapStringData() +{ + return &jsHeapStringData_; +} +JsHeapTraceFuncInfo* TraceDataCacheWriter::GetJsHeapTraceFuncInfoData() +{ + return &jsHeapTraceFuncInfoData_; +} +JsHeapTraceNode* TraceDataCacheWriter::GetJsHeapTraceNodeData() +{ + return &jsHeapTraceNodeData_; +} +void TraceDataCacheWriter::Clear() +{ + rawData_.Clear(); + threadStateData_.Clear(); + instantsData_.Clear(); + + filterData_.Clear(); + processMeasureFilterData_.Clear(); + clockEventFilterData_.Clear(); + clkEventFilterData_.Clear(); + processFilterData_.Clear(); + threadMeasureFilterData_.Clear(); + threadFilterData_.Clear(); + dataDict_.Clear(); + + schedSliceData_.Clear(); + callstackData_.Clear(); + irqData_.Clear(); + hilogData_.Clear(); + nativeHookData_.Clear(); + nativeHookFrameData_.Clear(); + hidumpData_.Clear(); + + internalProcessesData_.clear(); + internalThreadsData_.clear(); + + measureData_.Clear(); + cpuMeasureData_.Clear(); + + metaData_.Clear(); + symbolsData_.Clear(); + sysCallData_.Clear(); + argSet_.Clear(); + dataType_.Clear(); + sysEvent_.Clear(); + networkData_.Clear(); + networkDetailData_.Clear(); + perfSample_.Clear(); + perfCallChain_.Clear(); + perfThread_.Clear(); + perfFiles_.Clear(); + perfReport_.Clear(); + cpuUsageData_.Clear(); + diskIOData_.Clear(); + liveProcessDetailData_.Clear(); + fileSamplingTableData_.Clear(); + ebpfCallStackData_.Clear(); + PagedMemorySampleData_.Clear(); + jsHeapFilesData_.Clear(); + jsHeapEdgesData_.Clear(); + jsHeapInfoData_.Clear(); + jsHeapLocationData_.Clear(); + jsHeapNodesData_.Clear(); + jsHeapSampleData_.Clear(); + jsHeapStringData_.Clear(); + jsHeapTraceFuncInfoData_.Clear(); + jsHeapTraceNodeData_.Clear(); + +#if WITH_EBPF_HELP + ebpfProcessMaps_.Clear(); + ebpfElf_.Clear(); + ebpfElfSymbol_.Clear(); +#endif + appNames_.Clear(); + sysEventMeasureData_.Clear(); + deviceStateData_.Clear(); + smapsData_.Clear(); + bioLatencySampleData_.Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_data_cache_writer.h b/trace_streamer/src/trace_data/trace_data_cache_writer.h new file mode 100644 index 0000000000000000000000000000000000000000..bbfe38f9225cddb152ef2f0a5e841ba7f9b762d0 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_cache_writer.h @@ -0,0 +1,110 @@ +/* + * 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 TRACE_DATA_CACHE_WRITER_H +#define TRACE_DATA_CACHE_WRITER_H + +#include "trace_data_cache_reader.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace TraceStdtype; +class TraceDataCacheWriter : virtual public TraceDataCacheBase { +public: + TraceDataCacheWriter() = default; + TraceDataCacheWriter(const TraceDataCacheWriter&) = delete; + TraceDataCacheWriter& operator=(const TraceDataCacheWriter&) = delete; + ~TraceDataCacheWriter() override; + void Clear(); + +public: + InternalPid GetProcessInternalPid(uint32_t pid); + Process* GetProcessData(InternalPid internalPid); + uint32_t AppendNewProcessData(uint32_t pid, const std::string& name, uint64_t startTs); + InternalTid NewInternalThread(uint32_t tid); + Thread* GetThreadData(InternalTid internalTid); + void UpdateTraceTime(uint64_t timeStamp); + void MixTraceTime(uint64_t timestampMin, uint64_t timestampMax); + CallStack* GetInternalSlicesData(); + CallStack* GetIrqData(); + Filter* GetFilterData(); + Raw* GetRawData(); + Measure* GetMeasureData(); + Measure* GetSysMemMeasureData(); + Measure* GetProcessMeasureData(); + ThreadState* GetThreadStateData(); + SchedSlice* GetSchedSliceData(); + CpuMeasureFilter* GetCpuMeasuresData(); + ThreadMeasureFilter* GetThreadMeasureFilterData(); + ThreadMeasureFilter* GetThreadFilterData(); + Instants* GetInstantsData(); + ProcessMeasureFilter* GetProcessFilterData(); + ProcessMeasureFilter* GetProcessMeasureFilterData(); + ClockEventData* GetClockEventFilterData(); + ClkEventData* GetClkEventFilterData(); + StatAndInfo* GetStatAndInfo(); + MetaData* GetMetaData(); + SymbolsData* GetSymbolsData(); + SysCall* GetSysCallData(); + LogInfo* GetHilogData(); + NativeHook* GetNativeHookData(); + NativeHookFrame* GetNativeHookFrameData(); + NativeHookStatistic* GetNativeHookStatisticsData(); + Hidump* GetHidumpData(); + PerfCallChain* GetPerfCallChainData(); + PerfFiles* GetPerfFilesData(); + PerfSample* GetPerfSampleData(); + PerfThread* GetPerfThreadData(); + PerfReport* GetPerfReportData(); + ArgSet* GetArgSetData(); + DataType* GetDataTypeData(); + SysMeasureFilter* GetSysMeasureFilterData(); + NetDetailData* GetNetworkData(); + NetDetailData* GetNetworkDetailData(); + DiskIOData* GetDiskIOData(); + CpuUsageDetailData* GetCpuUsageInfoData(); + LiveProcessDetailData* GetLiveProcessData(); + FileSystemSample* GetFileSystemSample(); + EbpfCallStackData* GetEbpfCallStack(); + PagedMemorySampleData* GetPagedMemorySampleData(); +#if WITH_EBPF_HELP + EbpfProcessMaps* GetEbpfProcessMaps(); + EbpfElf* GetEbpfElf(); + EbpfElfSymbol* GetEbpfElfSymbol(); +#endif + AppNames* GetAppNamesData(); + SysEventMeasureData* GetSyseventMeasureData(); + DeviceStateData* GetDeviceStateData(); + TraceConfigData* GetTraceConfigData(); + SmapsData* GetSmapsData(); + BioLatencySampleData* GetBioLatencySampleData(); + ClockSnapshotData* GetClockSnapshotData(); + DataSourceClockIdData* GetDataSourceClockIdData(); + FrameSlice* GetFrameSliceData(); + FrameMaps* GetFrameMapsData(); + GPUSlice* GetGPUSliceData(); + JsHeapFiles* GetJsHeapFilesData(); + JsHeapEdges* GetJsHeapEdgesData(); + JsHeapInfo* GetJsHeapInfoData(); + JsHeapLocation* GetJsHeapLocationData(); + JsHeapNodes* GetJsHeapNodesData(); + JsHeapSample* GetJsHeapSampleData(); + JsHeapString* GetJsHeapStringData(); + JsHeapTraceFuncInfo* GetJsHeapTraceFuncInfoData(); + JsHeapTraceNode* GetJsHeapTraceNodeData(); +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/trace_data/trace_data_db.cpp b/trace_streamer/src/trace_data/trace_data_db.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79cc2cbfbcd952b90a413bdcc8c6cd11ded828c0 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_db.cpp @@ -0,0 +1,478 @@ +/* + * 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 "trace_data_db.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "codec_cov.h" +#include "ext/sqlite_ext_funcs.h" +#include "file.h" +#include "log.h" +#include "sqlite3.h" +#include "string_help.h" + +const int32_t ONCE_MAX_MB = 1024 * 1024 * 4; +namespace SysTuning { +namespace TraceStreamer { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +using namespace SysTuning::base; +TraceDataDB::TraceDataDB() : db_(nullptr) +{ + if (sqlite3_threadsafe() > 0) { + int32_t retCode = sqlite3_config(SQLITE_CONFIG_SERIALIZED); + if (retCode == SQLITE_OK) { + TS_LOGI("Can now use sqlite on multiple threads, using the same connection"); + } else { + TS_LOGE("setting sqlite thread safe mode to serialized failed!!! return code: %d", retCode); + } + } else { + TS_LOGE("Your SQLite database is not compiled to be threadsafe."); + } + if (sqlite3_open(":memory:", &db_)) { + TS_LOGF("open :memory db failed"); + } + ts_create_extend_function(db_); +} + +TraceDataDB::~TraceDataDB() +{ + sqlite3_close(db_); +} + +void TraceDataDB::AppendNewTable(std::string tableName) +{ + internalTables_.push_back(tableName); +} +void TraceDataDB::EnableMetaTable(bool enabled) +{ + exportMetaTable_ = enabled; +} + +void TraceDataDB::SendDatabase(ResultCallBack resultCallBack) +{ + int32_t fd(base::OpenFile(wasmDBName_, O_RDWR, TS_PERMISSION_RW)); + if (!fd) { + TS_LOGD("Failed to open file: %s", wasmDBName_.c_str()); + return; + } + + while (true) { + uint8_t data[DATABASE_BASE]; + auto size = base::Read(fd, data, DATABASE_BASE); + if (size == 0) { + resultCallBack(std::string((char*)data, size), SEND_FINISH); + break; + } else if (size < 0) { + TS_LOGD("Reading trace file failed (errno: %d, %s)", errno, strerror(errno)); + break; + } + resultCallBack(std::string((char*)data, DATABASE_BASE), SEND_CONTINUE); + } + close(fd); + remove(wasmDBName_.c_str()); + wasmDBName_.clear(); +} + +int32_t TraceDataDB::ExportDatabase(const std::string& outputName, ResultCallBack resultCallBack) +{ + { + int32_t fd(base::OpenFile(outputName, O_CREAT | O_RDWR, TS_PERMISSION_RW)); + if (!fd) { + fprintf(stdout, "Failed to create file: %s", outputName.c_str()); + return 1; + } + auto ret = ftruncate(fd, 0); + UNUSED(ret); + close(fd); + } + + std::string attachSql("ATTACH DATABASE '" + outputName + "' AS systuning_export"); +#ifdef _WIN32 + if (!base::GetCoding(reinterpret_cast(attachSql.c_str()), attachSql.length())) { + attachSql = base::GbkToUtf8(attachSql.c_str()); + } +#endif + ExecuteSql(attachSql); + + for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) { +#ifndef USE_VTABLE + if (*itor == "_meta" && !exportMetaTable_) { + continue; + } else { + std::string exportSql("CREATE TABLE systuning_export." + (*itor).substr(1, -1) + " AS SELECT * FROM " + + *itor); + ExecuteSql(exportSql); + } +#else + if (*itor == "meta" && !exportMetaTable_) { + continue; + } else { + std::string exportSql("CREATE TABLE systuning_export." + (*itor) + " AS SELECT * FROM " + *itor); + ExecuteSql(exportSql); + } +#endif + } + std::string createArgsView = + "create view systuning_export.args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when " + "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on (D.typeId " + "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key"; + ExecuteSql(createArgsView); + std::string updateProcessName = + "update process set name = (select name from thread t where t.ipid = process.id and t.name is not null and " + "is_main_thread = 1)"; + ExecuteSql(updateProcessName); + std::string detachSql("DETACH DATABASE systuning_export"); + ExecuteSql(detachSql); + + if (resultCallBack != nullptr) { + wasmDBName_ = outputName; + SendDatabase(resultCallBack); + } + return 0; +} + +void TraceDataDB::Prepare() +{ + if (pared_) { + return; + } + pared_ = true; +#ifndef USE_VTABLE + for (auto itor = internalTables_.begin(); itor != internalTables_.end(); itor++) { + std::string exportSql("CREATE TABLE " + (*itor).substr(1, -1) + " AS SELECT * FROM " + *itor); + ExecuteSql(exportSql); + } +#endif + ExecuteSql( + "update thread set ipid = \ + (select id from process where \ + thread.tid = process.pid) where thread.ipid is null;"); + std::string createArgsView = + "create view args_view AS select A.argset, V2.data as keyName, A.id, D.desc, (case when " + "A.datatype==1 then V.data else A.value end) as strValue from args as A left join data_type as D on " + "(D.typeId " + "= A.datatype) left join data_dict as V on V.id = A.value left join data_dict as V2 on V2.id = A.key"; + ExecuteSql(createArgsView); + + std::string updateProcessNewName = + "update process set name = (select name from thread t where t.ipid = process.id and t.name is not " + "null and " + "is_main_thread = 1)"; + ExecuteSql(updateProcessNewName); +} +void TraceDataDB::ExecuteSql(const std::string_view& sql) +{ + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.data(), static_cast(sql.size()), &stmt, nullptr); + + while (!ret) { + int32_t err = sqlite3_step(stmt); + if (err == SQLITE_ROW) { + continue; + } + if (err == SQLITE_DONE) { + break; + } + ret = err; + } + + sqlite3_finalize(stmt); +} +std::vector TraceDataDB::SearchData() +{ + std::vector values = {}; + Prepare(); + std::string line; + bool printResult = false; + for (;;) { + std::cout << "> "; + getline(std::cin, line); + if (line.empty()) { + std::cout << "If you want to quit either type -q or press CTRL-Z" << std::endl; + continue; + } + values.clear(); + std::string option = ""; + size_t pos = std::string::npos; + if ((pos = line.find(" ")) != std::string::npos) { + option = line.substr(0, pos); + auto left = line.substr(pos + 1, -1); + while ((pos = left.find(",")) != std::string::npos) { + values.push_back(left.substr(0, pos + 1)); + left = left.substr(pos + 1, -1); + } + values.push_back(left); + } + printf("option:%s\n", option.c_str()); + if (!line.compare("-q") || !line.compare("-quit")) { + break; + } else if (!line.compare("-e")) { + TS_LOGI("the db file will be at current folder, the name is default.db"); + (void)ExportDatabase("default.db"); + return values; + } else if (!line.compare("-help") || !line.compare("-h")) { + std::cout << "use info" << std::endl; + continue; + } else if (!line.compare("-p")) { + std::cout << "will print result of query" << std::endl; + printResult = true; + continue; + } else if (!option.compare("-s")) { + if (!values.empty()) { + return values; + } + continue; + } else if (!line.compare("-up")) { + std::cout << "will not print result of query" << std::endl; + printResult = false; + continue; + } else if (line.find("-c:") == 0) { + line = line.substr(strlen("-c:")); + if (OperateDatabase(line) == SQLITE_OK) { + printf("operate SQL success\n"); + } + continue; + } + + using namespace std::chrono; + const auto start = steady_clock::now(); + int32_t rowCount = SearchDatabase(line, printResult); + std::chrono::nanoseconds searchDur = duration_cast(steady_clock::now() - start); + printf("\"%s\"\n\tused %.3fms row: %d\n", line.c_str(), searchDur.count() / 1E6, rowCount); + } + return values; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, bool print) +{ + Prepare(); + int32_t rowCount = 0; + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return 0; + } + + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + TS_LOGI("sqlite3_column_count(%s) no column", sql.c_str()); + sqlite3_finalize(stmt); + return 0; + } + if (print) { + for (int32_t i = 0; i < colCount; i++) { + printf("%s\t", sqlite3_column_name(stmt, i)); + } + printf("\n"); + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + rowCount++; + for (int32_t i = 0; i < colCount; i++) { + const char* p = reinterpret_cast(sqlite3_column_text(stmt, i)); + int32_t type = sqlite3_column_type(stmt, i); + if (!print) { + continue; + } + if (p == nullptr) { + printf("null\t"); + continue; + } + if (type == SQLITE_TEXT) { + printf("\"%s\"\t", p); + } else { + printf("%s\t", p); + } + } + if (print) { + printf("\n"); + } + } + sqlite3_finalize(stmt); + return rowCount; +} +int32_t TraceDataDB::OperateDatabase(const std::string& sql) +{ + Prepare(); + char* errmsg = nullptr; + int32_t ret = sqlite3_exec(db_, sql.c_str(), NULL, NULL, &errmsg); + if (ret != SQLITE_OK && errmsg) { + TS_LOGE("sqlite3_exec(%s) failed: %d:%s", sql.c_str(), ret, errmsg); + sqlite3_free(errmsg); + } + return ret; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, ResultCallBack resultCallBack) +{ + Prepare(); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + resultCallBack("false\r\n", SEND_FINISH); + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return ret; + } + if (!resultCallBack) { + return ret; + } + + std::string res = "ok\r\n"; + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + resultCallBack(res, SEND_FINISH); + return ret; + } + res += "{\"columns\":["; + for (int32_t i = 0; i < colCount; i++) { + res += "\""; + res += sqlite3_column_name(stmt, i); + res += "\","; + } + res.pop_back(); // remove the last "," + res += "],\"values\":["; + bool hasRow = false; + constexpr int32_t defaultLenRowString = 1024; + std::string row; + row.reserve(defaultLenRowString); + while (sqlite3_step(stmt) == SQLITE_ROW) { + hasRow = true; + GetRowString(stmt, colCount, row); + res += row + ","; + if (res.size() >= ONCE_MAX_MB) { + resultCallBack(res, SEND_CONTINUE); + res = ""; + } + } + if (hasRow) { + res.pop_back(); // remove the last ',' + } + res += "]}\r\n"; + resultCallBack(res, SEND_FINISH); + + sqlite3_finalize(stmt); + return ret; +} +int32_t TraceDataDB::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen) +{ + Prepare(); + sqlite3_stmt* stmt = nullptr; + int32_t ret = sqlite3_prepare_v2(db_, sql.c_str(), static_cast(sql.size()), &stmt, nullptr); + if (ret != SQLITE_OK) { + TS_LOGE("sqlite3_prepare_v2(%s) failed: %d:%s", sql.c_str(), ret, sqlite3_errmsg(db_)); + return -1; + } + char* res = reinterpret_cast(out); + int32_t retSnprintf = snprintf_s(res, outLen, 1, "ok\r\n"); + if (retSnprintf < 0) { + return -1; + } + int32_t pos = retSnprintf; + int32_t colCount = sqlite3_column_count(stmt); + if (colCount == 0) { + return pos; + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s", "{\"columns\":["); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + for (int32_t i = 0; i < colCount; i++) { + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s%s%s", "\"", sqlite3_column_name(stmt, i), "\","); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + } + pos--; // rmove the last ',' + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "],\"values\":["); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + bool hasRow = false; + constexpr int32_t defaultLenRowString = 1024; + std::string row; + row.reserve(defaultLenRowString); + while (sqlite3_step(stmt) == SQLITE_ROW) { + hasRow = true; + GetRowString(stmt, colCount, row); + if (pos + row.size() + strlen(",]}\r\n") >= size_t(outLen)) { + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n"); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + sqlite3_finalize(stmt); + return pos; + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "%s%s", row.c_str(), ","); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + } + if (hasRow) { + pos--; // remove the last ',' + } + retSnprintf = snprintf_s(res + pos, outLen - pos, 1, "]}\r\n"); + if (retSnprintf < 0) { + return -1; + } + pos += retSnprintf; + sqlite3_finalize(stmt); + return pos; +} +void TraceDataDB::SetCancel(bool cancel) +{ + cancelQuery_ = cancel; +} +void TraceDataDB::GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr) +{ + rowStr.clear(); + rowStr = "["; + for (int32_t i = 0; i < colCount; i++) { + const char* p = reinterpret_cast(sqlite3_column_text(stmt, i)); + if (p == nullptr) { + rowStr += "null,"; + continue; + } + int32_t type = sqlite3_column_type(stmt, i); + switch (type) { + case SQLITE_TEXT: + rowStr += "\""; + rowStr += p; + rowStr += "\""; + break; + default: + rowStr += p; + break; + } + rowStr += ","; + } + rowStr.pop_back(); // remove the last ',' + rowStr += "]"; +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_data_db.h b/trace_streamer/src/trace_data/trace_data_db.h new file mode 100644 index 0000000000000000000000000000000000000000..6cf26f758887713e96ec457eb9b64c64e7c429bb --- /dev/null +++ b/trace_streamer/src/trace_data/trace_data_db.h @@ -0,0 +1,80 @@ +/* + * 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 TRACE_DATA_DB_H +#define TRACE_DATA_DB_H + +#include +#include +#include +#include +#include +#include "sqlite3.h" + +struct ElfSymbolTable { + std::string filePath; + uint64_t textVaddr; + uint32_t textOffset; + uint32_t symEntSize; + std::string strTable; + std::string symTable; +}; + +namespace SysTuning { +namespace TraceStreamer { +const int32_t SEND_CONTINUE = 0; +const int32_t SEND_FINISH = 1; +constexpr int32_t DATABASE_BASE = (1U << 20); +class TraceDataDB { +public: + TraceDataDB(); + TraceDataDB(const TraceDataDB&) = delete; + TraceDataDB& operator=(const TraceDataDB&) = delete; + virtual ~TraceDataDB(); + virtual void InitDB() = 0; + void Prepare(); + +public: + using ResultCallBack = std::function; + int32_t ExportDatabase(const std::string& outputName, ResultCallBack resultCallBack = nullptr); + std::vector SearchData(); + int32_t OperateDatabase(const std::string& sql); + int32_t SearchDatabase(const std::string& sql, ResultCallBack resultCallBack); + int32_t SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen); + void SetCancel(bool cancel); + void AppendNewTable(std::string tableName); + void EnableMetaTable(bool enabled); + bool Cancel() const + { + return cancelQuery_; + } + +public: + sqlite3* db_; + +private: + void ExecuteSql(const std::string_view& sql); + void SendDatabase(ResultCallBack resultCallBack); + static void GetRowString(sqlite3_stmt* stmt, int32_t colCount, std::string& rowStr); + int32_t SearchDatabase(const std::string& sql, bool print); + std::list internalTables_ = {}; + bool exportMetaTable_ = true; + bool pared_ = false; + bool cancelQuery_ = false; + std::string wasmDBName_; +}; +} // namespace TraceStreamer +} // namespace SysTuning +#endif diff --git a/trace_streamer/src/trace_data/trace_stdtype.cpp b/trace_streamer/src/trace_data/trace_stdtype.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31b18a4932fda45d8b9adda0a1aad7782e75fef2 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_stdtype.cpp @@ -0,0 +1,2671 @@ +/* + * 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 "trace_stdtype.h" +#include +#include +namespace SysTuning { +namespace TraceStdtype { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) +void CpuCacheBase::SetDur(uint64_t index, uint64_t dur) +{ + durs_[index] = dur; +} +TableRowId ThreadState::AppendThreadState(InternalTime ts, + InternalTime dur, + InternalCpu cpu, + InternalTid itid, + TableRowId idState) +{ + timeStamps_.emplace_back(ts); + durations_.emplace_back(dur); + itids_.emplace_back(itid); + tids_.emplace_back(INVALID_UINT32); + pids_.emplace_back(INVALID_UINT32); + states_.emplace_back(idState); + cpus_.emplace_back(cpu); + argSetIds_.emplace_back(INVALID_UINT32); + return itids_.size() - 1; +} + +void ThreadState::SetDuration(TableRowId index, InternalTime dur) +{ + durations_[index] = dur; +} +void DataDict::Finish() +{ + std::string::size_type pos(0); + for (auto i = 0; i < dataDict_.size(); i++) { + if (dataDict_[i].empty()) { + continue; + } + while ((pos = dataDict_[i].find("\"")) != std::string::npos) { + dataDict_[i].replace(pos, 1, "\'"); + } + while ((dataDict_[i].back() >= SPASCII_START && dataDict_[i].back() <= SPASCII_END) || + dataDict_[i].back() == '\r') { + dataDict_[i].pop_back(); + } + } +} +TableRowId ThreadState::UpdateDuration(TableRowId index, InternalTime ts) +{ + if (durations_[index] == INVALID_TIME) { + durations_[index] = ts - timeStamps_[index]; + } + return itids_[index]; +} + +bool ThreadState::End(TableRowId index, InternalTime ts) +{ + if (durations_[index] == INVALID_TIME) { + durations_[index] = -1; + return false; + } + return true; +} +void ThreadState::UpdateState(TableRowId index, TableRowId idState) +{ + states_[index] = idState; +} +void ThreadState::SetArgSetId(TableRowId index, uint32_t setId) +{ + argSetIds_[index] = setId; +} + +void ThreadState::UpdateDuration(TableRowId index, InternalTime ts, TableRowId idState) +{ + durations_[index] = ts - timeStamps_[index]; + states_[index] = idState; +} + +void ThreadState::UpdateTidAndPid(TableRowId index, InternalTid tid, InternalTid pid) +{ + tids_[index] = tid; + pids_[index] = pid; +} + +TableRowId ThreadState::UpdateDuration(TableRowId index, InternalTime ts, InternalCpu cpu, TableRowId idState) +{ + cpus_[index] = cpu; + durations_[index] = ts - timeStamps_[index]; + states_[index] = idState; + return itids_[index]; +} + +size_t SchedSlice::AppendSchedSlice(uint64_t ts, + uint64_t dur, + uint64_t cpu, + uint32_t internalTid, + uint64_t endState, + uint64_t priority) +{ + timeStamps_.emplace_back(ts); + durs_.emplace_back(dur); + cpus_.emplace_back(cpu); + tsEnds_.emplace_back(0); + internalTids_.emplace_back(internalTid); + endStates_.emplace_back(endState); + priority_.emplace_back(priority); + argSets_.emplace_back(INVALID_UINT32); + return Size() - 1; +} + +void SchedSlice::SetDuration(size_t index, uint64_t duration) +{ + durs_[index] = duration; + tsEnds_[index] = timeStamps_[index] + duration; +} + +void SchedSlice::Update(uint64_t index, uint64_t ts, uint64_t state) +{ + durs_[index] = ts - timeStamps_[index]; + endStates_[index] = state; +} + +void SchedSlice::UpdateArg(uint64_t index, uint32_t argsetId) +{ + argSets_[index] = argsetId; +} +size_t CallStack::AppendInternalAsyncSlice(uint64_t startT, + uint64_t durationNs, + InternalTid internalTid, + DataIndex cat, + uint16_t nameIdentify, + DataIndex name, + uint8_t depth, + uint64_t cookid, + const std::optional& parentId) +{ + AppendCommonInfo(startT, durationNs, internalTid); + AppendCallStack(cat, name, depth, parentId); + AppendDistributeInfo(); + cookies_.emplace_back(cookid); + ids_.emplace_back(ids_.size()); + identifys_.emplace_back(nameIdentify + depth); + return Size() - 1; +} +size_t CallStack::AppendInternalSlice(uint64_t startT, + uint64_t durationNs, + InternalTid internalTid, + DataIndex cat, + uint16_t nameIdentify, + DataIndex name, + uint8_t depth, + const std::optional& parentId) +{ + AppendCommonInfo(startT, durationNs, internalTid); + AppendCallStack(cat, name, depth, parentId); + identifys_.emplace_back(nameIdentify + depth); + ids_.emplace_back(ids_.size()); + cookies_.emplace_back(INVALID_UINT64); + AppendDistributeInfo(); + return Size() - 1; +} + +void CallStack::AppendCommonInfo(uint64_t startT, uint64_t durationNs, InternalTid internalTid) +{ + timeStamps_.emplace_back(startT); + durs_.emplace_back(durationNs); + callIds_.emplace_back(internalTid); +} +void CallStack::AppendCallStack(DataIndex cat, DataIndex name, uint8_t depth, std::optional parentId) +{ + parentIds_.emplace_back(parentId); + cats_.emplace_back(cat); + names_.emplace_back(name); + depths_.emplace_back(depth); +} +void CallStack::SetDistributeInfo(size_t index, + const std::string& chainId, + const std::string& spanId, + const std::string& parentSpanId, + const std::string& flag, + const std::string& args) +{ + chainIds_[index] = chainId; + spanIds_[index] = spanId; + parentSpanIds_[index] = parentSpanId; + flags_[index] = flag; + args_[index] = args; + argSet_[index] = INVALID_UINT32; +} +void CallStack::AppendDistributeInfo(const std::string& chainId, + const std::string& spanId, + const std::string& parentSpanId, + const std::string& flag, + const std::string& args) +{ + chainIds_.emplace_back(chainId); + spanIds_.emplace_back(spanId); + parentSpanIds_.emplace_back(parentSpanId); + flags_.emplace_back(flag); + args_.emplace_back(args); + argSet_.emplace_back(INVALID_UINT32); +} +void CallStack::AppendDistributeInfo() +{ + chainIds_.emplace_back(""); + spanIds_.emplace_back(""); + parentSpanIds_.emplace_back(""); + flags_.emplace_back(""); + args_.emplace_back(""); + argSet_.emplace_back(INVALID_UINT32); +} +void CallStack::SetDuration(size_t index, uint64_t timeStamp) +{ + durs_[index] = timeStamp - timeStamps_[index]; +} +void CallStack::SetDurationWithFlag(size_t index, uint64_t timeStamp) +{ + durs_[index] = timeStamp - timeStamps_[index]; + flags_[index] = "1"; +} + +void CallStack::SetFlag(size_t index, uint8_t flag) +{ + flags_[index] = std::to_string(flag); +} +void CallStack::SetDurationEx(size_t index, uint32_t dur) +{ + durs_[index] = dur; +} + +void CallStack::SetIrqDurAndArg(size_t index, uint64_t timeStamp, uint32_t argSetId) +{ + SetDuration(index, timeStamp); + argSet_[index] = argSetId; +} +void CallStack::SetTimeStamp(size_t index, uint64_t timeStamp) +{ + timeStamps_[index] = timeStamp; +} + +void CallStack::SetDepth(size_t index, uint8_t depth) +{ + depths_[index] = depth; +} +void CallStack::SetArgSetId(size_t index, uint32_t argSetId) +{ + argSet_[index] = argSetId; +} +const std::deque>& CallStack::ParentIdData() const +{ + return parentIds_; +} +const std::deque& CallStack::CatsData() const +{ + return cats_; +} +const std::deque& CallStack::IdentifysData() const +{ + return identifys_; +} +const std::deque& CallStack::NamesData() const +{ + return names_; +} +const std::deque& CallStack::Depths() const +{ + return depths_; +} +const std::deque& CallStack::Cookies() const +{ + return cookies_; +} +const std::deque& CallStack::CallIds() const +{ + return callIds_; +} +const std::deque& CallStack::ChainIds() const +{ + return chainIds_; +} +const std::deque& CallStack::SpanIds() const +{ + return spanIds_; +} +const std::deque& CallStack::ParentSpanIds() const +{ + return parentSpanIds_; +} +const std::deque& CallStack::Flags() const +{ + return flags_; +} +const std::deque& CallStack::ArgsData() const +{ + return args_; +} +const std::deque& CallStack::ArgSetIdsData() const +{ + return argSet_; +} + +size_t ArgSet::AppendNewArg(DataIndex nameId, BaseDataType dataType, int64_t value, size_t argSet) +{ + dataTypes_.emplace_back(dataType); + argset_.emplace_back(argSet); + ids_.emplace_back(Size()); + values_.emplace_back(value); + names_.emplace_back(nameId); + return Size() - 1; +} +const std::deque& ArgSet::DataTypes() const +{ + return dataTypes_; +} +const std::deque& ArgSet::ValuesData() const +{ + return values_; +} +const std::deque& ArgSet::ArgsData() const +{ + return argset_; +} +const std::deque& ArgSet::NamesData() const +{ + return names_; +} + +size_t SysMeasureFilter::AppendNewFilter(uint64_t filterId, DataIndex type, DataIndex nameId) +{ + ids_.emplace_back(filterId); + names_.emplace_back(nameId); + types_.emplace_back(type); + return ids_.size() - 1; +} +const std::deque& SysMeasureFilter::NamesData() const +{ + return names_; +} + +const std::deque& SysMeasureFilter::TypesData() const +{ + return types_; +} +size_t DataType::AppendNewDataType(BaseDataType dataType, DataIndex dataDescIndex) +{ + ids_.emplace_back(Size()); + dataTypes_.emplace_back(dataType); + descs_.emplace_back(dataDescIndex); + return Size() - 1; +} + +const std::deque& DataType::DataTypes() const +{ + return dataTypes_; +} +const std::deque& DataType::DataDesc() const +{ + return descs_; +} +size_t Filter::AppendNewFilterData(std::string type, std::string name, uint64_t sourceArgSetId) +{ + nameDeque_.emplace_back(name); + sourceArgSetId_.emplace_back(sourceArgSetId); + ids_.emplace_back(Size()); + typeDeque_.emplace_back(type); + return Size() - 1; +} + +size_t Measure::AppendMeasureData(uint32_t type, uint64_t timeStamp, int64_t value, uint32_t filterId) +{ + valuesDeque_.emplace_back(value); + filterIdDeque_.emplace_back(filterId); + typeDeque_.emplace_back(type); + timeStamps_.emplace_back(timeStamp); + durDeque_.emplace_back(INVALID_UINT64); + return Size() - 1; +} + +void Measure::SetDur(uint32_t row, uint64_t timeStamp) +{ + durDeque_[row] = timeStamp - timeStamps_[row]; +} +size_t Raw::AppendRawData(uint32_t id, uint64_t timeStamp, uint32_t name, uint32_t cpu, uint32_t internalTid) +{ + ids_.emplace_back(id); + timeStamps_.emplace_back(timeStamp); + nameDeque_.emplace_back(name); + cpuDeque_.emplace_back(cpu); + itidDeque_.emplace_back(internalTid); + return Size() - 1; +} + +size_t ThreadMeasureFilter::AppendNewFilter(uint64_t filterId, uint32_t nameIndex, uint64_t internalTid) +{ + filterId_.emplace_back(filterId); + nameIndex_.emplace_back(nameIndex); + internalTids_.emplace_back(internalTid); + return Size() - 1; +} + +size_t Instants::AppendInstantEventData(uint64_t timeStamp, + DataIndex nameIndex, + int64_t internalTid, + int64_t wakeupFromInternalPid) +{ + internalTids_.emplace_back(internalTid); + timeStamps_.emplace_back(timeStamp); + NameIndexs_.emplace_back(nameIndex); + wakeupFromInternalPids_.emplace_back(wakeupFromInternalPid); + return Size() - 1; +} +size_t LogInfo::AppendNewLogInfo(uint64_t seq, + uint64_t timeStamp, + uint32_t pid, + uint32_t tid, + DataIndex level, + DataIndex tag, + DataIndex context, + uint64_t originTs) +{ + hilogLineSeqs_.emplace_back(seq); + timeStamps_.emplace_back(timeStamp); + pids_.emplace_back(pid); + tids_.emplace_back(tid); + levels_.emplace_back(level); + tags_.emplace_back(tag); + contexts_.emplace_back(context); + originTs_.emplace_back(originTs); + return Size() - 1; +} +const std::deque& LogInfo::HilogLineSeqs() const +{ + return hilogLineSeqs_; +} +const std::deque& LogInfo::Pids() const +{ + return pids_; +} +const std::deque& LogInfo::Tids() const +{ + return tids_; +} +const std::deque& LogInfo::Levels() const +{ + return levels_; +} +const std::deque& LogInfo::Tags() const +{ + return tags_; +} +const std::deque& LogInfo::Contexts() const +{ + return contexts_; +} +const std::deque& LogInfo::OriginTimeStamData() const +{ + return originTs_; +} +void NativeHook::UpdateCallChainId(size_t row, uint32_t callChainId) +{ + if (row < Size()) { + callChainIds_[row] = callChainId; + } else { + TS_LOGE("Native hook update callChainId failed!!!"); + } +} +size_t NativeHook::AppendNewNativeHookData(uint32_t callChainId, + uint32_t ipid, + uint32_t itid, + std::string eventType, + DataIndex subType, + uint64_t timeStamp, + uint64_t endTimeStamp, + uint64_t duration, + uint64_t addr, + int64_t memSize) +{ + callChainIds_.emplace_back(callChainId); + ipids_.emplace_back(ipid); + itids_.emplace_back(itid); + eventTypes_.emplace_back(eventType); + subTypes_.emplace_back(subType); + timeStamps_.emplace_back(timeStamp); + endTimeStamps_.emplace_back(endTimeStamp); + durations_.emplace_back(duration); + addrs_.emplace_back(addr); + memSizes_.emplace_back(memSize); + if (eventType == ALLOC_EVET) { + countHeapSizes_ += memSize; + allMemSizes_.emplace_back(countHeapSizes_); + } else if (eventType == FREE_EVENT) { + countHeapSizes_ -= memSize; + allMemSizes_.emplace_back(countHeapSizes_); + } else if (eventType == MMAP_EVENT) { + countMmapSizes_ += memSize; + allMemSizes_.emplace_back(countMmapSizes_); + } else if (eventType == MUNMAP_EVENT) { + countMmapSizes_ -= memSize; + allMemSizes_.emplace_back(countMmapSizes_); + } + currentSizeDurs_.emplace_back(0); + lastCallerPathIndexs_.emplace_back(INVALID_UINT64); + return Size() - 1; +} +void NativeHook::UpdateEndTimeStampAndDuration(size_t row, uint64_t endTimeStamp) +{ + endTimeStamps_[row] = endTimeStamp; + durations_[row] = endTimeStamp - timeStamps_[row]; +} +void NativeHook::UpdateCurrentSizeDur(size_t row, uint64_t timeStamp) +{ + currentSizeDurs_[row] = timeStamp - timeStamps_[row]; +} +void NativeHook::UpdateMemMapSubType() +{ + if (addrToMmapTag_.empty()) { + return; + } + for (auto i = 0; i < Size(); ++i) { + if ((eventTypes_[i] == MMAP_EVENT || eventTypes_[i] == MUNMAP_EVENT) && subTypes_[i] == INVALID_UINT64) { + if (addrToMmapTag_.count(addrs_[i])) { + subTypes_[i] = addrToMmapTag_.at(addrs_[i]); + } + } + } +} +void NativeHook::UpdateAddrToMemMapSubType(uint64_t addr, uint64_t tagId) +{ + addrToMmapTag_.emplace(addr, tagId); +} +void NativeHook::UpdateLastCallerPathIndexs(std::unordered_map& callIdToLasLibId) +{ + if (callIdToLasLibId.empty()) { + return; + } + for (auto i = 0; i < Size(); ++i) { + auto symbolIt = callIdToLasLibId.find(callChainIds_[i]); + if (symbolIt != callIdToLasLibId.end()) { + lastCallerPathIndexs_[i] = symbolIt->second; + } else { + lastCallerPathIndexs_[i] = INVALID_UINT64; + } + } +} +const std::deque& NativeHook::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& NativeHook::Ipids() const +{ + return ipids_; +} +const std::deque& NativeHook::Itids() const +{ + return itids_; +} +const std::deque& NativeHook::EventTypes() const +{ + return eventTypes_; +} +const std::deque& NativeHook::SubTypes() const +{ + return subTypes_; +} +const std::deque& NativeHook::EndTimeStamps() const +{ + return endTimeStamps_; +} +const std::deque& NativeHook::Durations() const +{ + return durations_; +} +const std::deque& NativeHook::Addrs() const +{ + return addrs_; +} +const std::deque& NativeHook::MemSizes() const +{ + return memSizes_; +} +const std::deque& NativeHook::AllMemSizes() const +{ + return allMemSizes_; +} +const std::deque& NativeHook::CurrentSizeDurs() const +{ + return currentSizeDurs_; +} +const std::deque& NativeHook::LastCallerPathIndexs() const +{ + return lastCallerPathIndexs_; +} +size_t NativeHookFrame::AppendNewNativeHookFrame(uint32_t callChainId, + uint64_t depth, + uint64_t ip, + uint64_t sp, + DataIndex symbolName, + DataIndex filePath, + uint64_t offset, + uint64_t symbolOffset, + const std::string& vaddr) +{ + callChainIds_.emplace_back(callChainId); + ips_.emplace_back(ip); + sps_.emplace_back(sp); + depths_.emplace_back(depth); + symbolNames_.emplace_back(symbolName); + filePaths_.emplace_back(filePath); + offsets_.emplace_back(offset); + symbolOffsets_.emplace_back(symbolOffset); + vaddrs_.emplace_back(vaddr); + return Size() - 1; +} +size_t NativeHookFrame::AppendNewNativeHookFrame(uint32_t callChainId, + uint64_t depth, + uint64_t ip, + uint64_t sp, + DataIndex symbolName, + DataIndex filePath, + uint64_t offset, + uint64_t symbolOffset) +{ + callChainIds_.emplace_back(callChainId); + ips_.emplace_back(ip); + sps_.emplace_back(sp); + depths_.emplace_back(depth); + symbolNames_.emplace_back(symbolName); + filePaths_.emplace_back(filePath); + offsets_.emplace_back(offset); + symbolOffsets_.emplace_back(symbolOffset); + return Size() - 1; +} +void NativeHookFrame::UpdateSymbolIdToNameMap(uint64_t originSymbolId, uint64_t symbolId) +{ + symbolIdToSymbolName_.insert(std::make_pair(originSymbolId, symbolId)); +} +void NativeHookFrame::UpdateFrameInfo(size_t row, + DataIndex symbolIndex, + DataIndex filePathIndex, + uint64_t offset, + uint64_t symbolOffset) +{ + if (row >= Size()) { + TS_LOGE("The updated row does not exist!"); + return; + } + symbolNames_[row] = symbolIndex; + filePaths_[row] = filePathIndex; + offsets_[row] = offset; + symbolOffsets_[row] = symbolOffset; +} + +void NativeHookFrame::UpdateSymbolId() +{ + if (symbolIdToSymbolName_.empty()) { + return; + } + for (auto i = 0; i < Size(); ++i) { + auto symbolIt = symbolIdToSymbolName_.find(symbolNames_[i]); + if (symbolIt != symbolIdToSymbolName_.end()) { + symbolNames_[i] = symbolIt->second; + } + } +} +void NativeHookFrame::UpdateSymbolId(size_t index, DataIndex symbolId) +{ + if (index < Size()) { + symbolNames_[index] = symbolId; + } +} +void NativeHookFrame::UpdateFileId(std::map& filePathIdToFilePathName) +{ + if (filePathIdToFilePathName.empty()) { + return; + } + for (auto i = 0; i < Size(); ++i) { + auto symbolIt = filePathIdToFilePathName.find(filePaths_[i]); + if (symbolIt != filePathIdToFilePathName.end()) { + filePaths_[i] = symbolIt->second; + } + } +} +void NativeHookFrame::UpdateVaddrs(std::deque& vaddrs) +{ + vaddrs_.assign(vaddrs.begin(), vaddrs.end()); +} +const std::deque& NativeHookFrame::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& NativeHookFrame::Depths() const +{ + return depths_; +} +const std::deque& NativeHookFrame::Ips() const +{ + return ips_; +} +const std::deque& NativeHookFrame::Sps() const +{ + return sps_; +} +const std::deque& NativeHookFrame::SymbolNames() const +{ + return symbolNames_; +} +const std::deque& NativeHookFrame::FilePaths() const +{ + return filePaths_; +} +const std::deque& NativeHookFrame::Offsets() const +{ + return offsets_; +} +const std::deque& NativeHookFrame::SymbolOffsets() const +{ + return symbolOffsets_; +} +const std::deque& NativeHookFrame::Vaddrs() const +{ + return vaddrs_; +} + +size_t NativeHookStatistic::AppendNewNativeHookStatistic(uint32_t ipid, + uint64_t timeStamp, + uint32_t callChainId, + uint32_t memoryType, + uint64_t applyCount, + uint64_t releaseCount, + uint64_t applySize, + uint64_t releaseSize) +{ + ids_.emplace_back(Size()); + ipids_.emplace_back(ipid); + timeStamps_.emplace_back(timeStamp); + callChainIds_.emplace_back(callChainId); + memoryTypes_.emplace_back(memoryType); + applyCounts_.emplace_back(applyCount); + releaseCounts_.emplace_back(releaseCount); + applySizes_.emplace_back(applySize); + releaseSizes_.emplace_back(releaseSize); + return Size() - 1; +} +const std::deque& NativeHookStatistic::Ipids() const +{ + return ipids_; +} +const std::deque& NativeHookStatistic::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& NativeHookStatistic::MemoryTypes() const +{ + return memoryTypes_; +} +const std::deque& NativeHookStatistic::ApplyCounts() const +{ + return applyCounts_; +} +const std::deque& NativeHookStatistic::ReleaseCounts() const +{ + return releaseCounts_; +} +const std::deque& NativeHookStatistic::ApplySizes() const +{ + return applySizes_; +} +const std::deque& NativeHookStatistic::ReleaseSizes() const +{ + return releaseSizes_; +} +size_t Hidump::AppendNewHidumpInfo(uint64_t timeStamp, uint32_t fps) +{ + timeStamps_.emplace_back(timeStamp); + fpss_.emplace_back(fps); + return Size() - 1; +} +const std::deque& Hidump::Fpss() const +{ + return fpss_; +} + +size_t PerfCallChain::AppendNewPerfCallChain(uint64_t sampleId, + uint32_t callChainId, + uint64_t vaddrInFile, + uint64_t fileId, + uint64_t symbolId) +{ + ids_.emplace_back(Size()); + sampleIds_.emplace_back(sampleId); + callChainIds_.emplace_back(callChainId); + vaddrInFiles_.emplace_back(vaddrInFile); + fileIds_.emplace_back(fileId); + symbolIds_.emplace_back(symbolId); + names_.emplace_back(""); + return Size() - 1; +} +const std::deque& PerfCallChain::SampleIds() const +{ + return sampleIds_; +} +const std::deque& PerfCallChain::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& PerfCallChain::VaddrInFiles() const +{ + return vaddrInFiles_; +} +const std::deque& PerfCallChain::FileIds() const +{ + return fileIds_; +} +const std::deque& PerfCallChain::SymbolIds() const +{ + return symbolIds_; +} + +const std::deque& PerfCallChain::Names() const +{ + return names_; +} +void PerfCallChain::SetName(uint64_t index, const std::string& name) +{ + names_[index] = name; +} +void PerfCallChain::Clear() +{ + CacheBase::Clear(); + sampleIds_.clear(); + callChainIds_.clear(); + vaddrInFiles_.clear(); + fileIds_.clear(); + symbolIds_.clear(); + names_.clear(); +} +size_t PerfFiles::AppendNewPerfFiles(uint64_t fileIds, uint32_t serial, DataIndex symbols, DataIndex filePath) +{ + ids_.emplace_back(Size()); + fileIds_.emplace_back(fileIds); + serials_.emplace_back(serial); + symbols_.emplace_back(symbols); + filePaths_.emplace_back(filePath); + return Size() - 1; +} +const std::deque& PerfFiles::FileIds() const +{ + return fileIds_; +} + +const std::deque& PerfFiles::Serials() const +{ + return serials_; +} +const std::deque& PerfFiles::Symbols() const +{ + return symbols_; +} +const std::deque& PerfFiles::FilePaths() const +{ + return filePaths_; +} + +void PerfFiles::Clear() +{ + CacheBase::Clear(); + fileIds_.clear(); + serials_.clear(); + symbols_.clear(); + filePaths_.clear(); +} + +size_t PerfSample::AppendNewPerfSample(uint32_t sampleId, + uint64_t timeStamp, + uint32_t tid, + uint64_t eventCount, + uint64_t eventTypeId, + uint64_t timestampTrace, + uint64_t cpuId, + uint64_t threadState) +{ + ids_.emplace_back(Size()); + sampleIds_.emplace_back(sampleId); + timeStamps_.emplace_back(timeStamp); + tids_.emplace_back(tid); + eventCounts_.emplace_back(eventCount); + eventTypeIds_.emplace_back(eventTypeId); + timestampTraces_.emplace_back(timestampTrace); + cpuIds_.emplace_back(cpuId); + threadStates_.emplace_back(threadState); + return Size() - 1; +} +const std::deque& PerfSample::SampleIds() const +{ + return sampleIds_; +} +const std::deque& PerfSample::Tids() const +{ + return tids_; +} +const std::deque& PerfSample::EventCounts() const +{ + return eventCounts_; +} +const std::deque& PerfSample::EventTypeIds() const +{ + return eventTypeIds_; +} +const std::deque& PerfSample::TimestampTraces() const +{ + return timestampTraces_; +} +const std::deque& PerfSample::CpuIds() const +{ + return cpuIds_; +} +const std::deque& PerfSample::ThreadStates() const +{ + return threadStates_; +} + +void PerfSample::Clear() +{ + CacheBase::Clear(); + sampleIds_.clear(); + tids_.clear(); + eventCounts_.clear(); + eventTypeIds_.clear(); + timestampTraces_.clear(); + cpuIds_.clear(); + threadStates_.clear(); +} + +size_t PerfThread::AppendNewPerfThread(uint32_t pid, uint32_t tid, DataIndex threadName) +{ + ids_.emplace_back(Size()); + pids_.emplace_back(pid); + tids_.emplace_back(tid); + threadNames_.emplace_back(threadName); + return Size() - 1; +} +const std::deque& PerfThread::Pids() const +{ + return pids_; +} +const std::deque& PerfThread::Tids() const +{ + return tids_; +} +const std::deque& PerfThread::ThreadNames() const +{ + return threadNames_; +} +void PerfThread::Clear() +{ + CacheBase::Clear(); + tids_.clear(); + pids_.clear(); + threadNames_.clear(); +} +size_t PerfReport::AppendNewPerfReport(DataIndex type, DataIndex value) +{ + ids_.emplace_back(Size()); + types_.emplace_back(type); + values_.emplace_back(value); + return Size() - 1; +} +const std::deque& PerfReport::Types() const +{ + return types_; +} +const std::deque& PerfReport::Values() const +{ + return values_; +} +size_t ProcessMeasureFilter::AppendNewFilter(uint64_t id, DataIndex name, uint32_t internalPid) +{ + internalPids_.emplace_back(internalPid); + ids_.emplace_back(id); + names_.emplace_back(name); + return Size() - 1; +} +size_t ClockEventData::AppendNewFilter(uint64_t id, DataIndex type, DataIndex name, uint64_t cpu) +{ + cpus_.emplace_back(cpu); + ids_.emplace_back(id); + types_.emplace_back(type); + names_.emplace_back(name); + return Size() - 1; +} +size_t ClkEventData::AppendNewFilter(uint64_t id, uint64_t rate, DataIndex name, uint64_t cpu) +{ + ids_.emplace_back(id); + rates_.emplace_back(rate); + names_.emplace_back(name); + cpus_.emplace_back(cpu); + return Size() - 1; +} +size_t SysCall::AppendSysCallData(int64_t sysCallNum, DataIndex type, uint32_t ipid, uint64_t timeStamp, int64_t ret) +{ + sysCallNums_.emplace_back(sysCallNum); + types_.emplace_back(type); + ipids_.emplace_back(ipid); + timeStamps_.emplace_back(timeStamp); + rets_.emplace_back(ret); + return Size() - 1; +} +StatAndInfo::StatAndInfo() +{ + // sched_switch_received | sched_switch_not_match | sched_switch_not_not_supported etc. + for (int32_t i = TRACE_EVENT_START; i < TRACE_EVENT_MAX; i++) { + event_[i] = config_.eventNameMap_.at(static_cast(i)); + } + for (int32_t j = STAT_EVENT_START; j < STAT_EVENT_MAX; j++) { + stat_[j] = config_.eventErrorDescMap_.at(static_cast(j)); + } + + for (int32_t i = TRACE_EVENT_START; i < TRACE_EVENT_MAX; i++) { + for (int32_t j = STAT_EVENT_START; j < STAT_EVENT_MAX; j++) { + statSeverity_[i][j] = config_.eventParserStatSeverityDescMap_.at(static_cast(i)) + .at(static_cast(j)); + } + } + + for (int32_t i = TRACE_EVENT_START; i < TRACE_EVENT_MAX; i++) { + for (int32_t j = STAT_EVENT_START; j < STAT_EVENT_MAX; j++) { + statSeverityDesc_[i][j] = config_.serverityLevelDescMap_.at(statSeverity_[i][j]); + } + } + + for (int32_t i = TRACE_EVENT_START; i < TRACE_EVENT_MAX; i++) { + for (int32_t j = STAT_EVENT_START; j < STAT_EVENT_MAX; j++) { + statCount_[i][j] = 0; + } + } + clockid2ClockNameMap_ = { + {TS_CLOCK_UNKNOW, "unknown"}, {TS_CLOCK_BOOTTIME, "boottime"}, + {TS_CLOCK_REALTIME, "realtime"}, {TS_CLOCK_REALTIME_COARSE, "realtime_corse"}, + {TS_MONOTONIC, "monotonic"}, {TS_MONOTONIC_COARSE, "monotonic-coarse"}, + {TS_MONOTONIC_RAW, "monotonic-raw"}, + }; +} +void StatAndInfo::IncreaseStat(SupportedTraceEventType eventType, StatType type) +{ + statCount_[eventType][type]++; +} +const uint32_t& StatAndInfo::GetValue(SupportedTraceEventType eventType, StatType type) const +{ + return statCount_[eventType][type]; +} +const std::string& StatAndInfo::GetEvent(SupportedTraceEventType eventType) const +{ + return event_[eventType]; +} +const std::string& StatAndInfo::GetStat(StatType type) const +{ + return stat_[type]; +} +const std::string& StatAndInfo::GetSeverityDesc(SupportedTraceEventType eventType, StatType type) const +{ + return statSeverityDesc_[eventType][type]; +} +const StatSeverityLevel& StatAndInfo::GetSeverity(SupportedTraceEventType eventType, StatType type) const +{ + return statSeverity_[eventType][type]; +} + +uint64_t SymbolsData::Size() const +{ + return addrs_.size(); +} +void SymbolsData::InsertSymbol(const DataIndex& name, const uint64_t& addr) +{ + addrs_.emplace_back(addr); + funcName_.emplace_back(name); +} +const std::deque& SymbolsData::GetConstFuncNames() const +{ + return funcName_; +} +const std::deque& SymbolsData::GetConstAddrs() const +{ + return addrs_; +} +MetaData::MetaData() +{ + columnNames_.resize(METADATA_ITEM_MAX); + values_.resize(METADATA_ITEM_MAX); + columnNames_[METADATA_ITEM_DATASIZE] = METADATA_ITEM_DATASIZE_COLNAME; + columnNames_[METADATA_ITEM_PARSETOOL_NAME] = METADATA_ITEM_PARSETOOL_NAME_COLNAME; + columnNames_[METADATA_ITEM_PARSERTOOL_VERSION] = METADATA_ITEM_PARSERTOOL_VERSION_COLNAME; + columnNames_[METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME] = METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME_COLNAME; + columnNames_[METADATA_ITEM_SOURCE_FILENAME] = METADATA_ITEM_SOURCE_FILENAME_COLNAME; + columnNames_[METADATA_ITEM_OUTPUT_FILENAME] = METADATA_ITEM_OUTPUT_FILENAME_COLNAME; + columnNames_[METADATA_ITEM_PARSERTIME] = METADATA_ITEM_PARSERTIME_COLNAME; + columnNames_[METADATA_ITEM_TRACE_DURATION] = METADATA_ITEM_TRACE_DURATION_COLNAME; + columnNames_[METADATA_ITEM_SOURCE_DATETYPE] = METADATA_ITEM_SOURCE_DATETYPE_COLNAME; + values_[METADATA_ITEM_PARSETOOL_NAME] = "trace_streamer"; +} +void MetaData::SetTraceType(const std::string& traceType) +{ + values_[METADATA_ITEM_SOURCE_DATETYPE] = traceType; +} +void MetaData::SetSourceFileName(const std::string& fileName) +{ + MetaData::values_[METADATA_ITEM_SOURCE_FILENAME] = fileName; +} +void MetaData::SetOutputFileName(const std::string& fileName) +{ + MetaData::values_[METADATA_ITEM_OUTPUT_FILENAME] = fileName; +} +void MetaData::SetParserToolVersion(const std::string& version) +{ + values_[METADATA_ITEM_PARSERTOOL_VERSION] = version; +} +void MetaData::SetParserToolPublishDateTime(const std::string& datetime) +{ + values_[METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME] = datetime; +} +void MetaData::SetTraceDataSize(uint64_t dataSize) +{ + std::stringstream ss; + ss << dataSize; + values_[METADATA_ITEM_DATASIZE] = ss.str(); + // Function 'time' may return error. It is not allowed to do anything that might fail inside the constructor. + time_t rawtime; + struct tm* timeinfo = nullptr; + void(time(&rawtime)); + timeinfo = localtime(&rawtime); + values_[METADATA_ITEM_PARSERTIME] = asctime(timeinfo); + // sometimes there will be a extra \n at last + values_[METADATA_ITEM_PARSERTIME].pop_back(); +} +void MetaData::SetTraceDuration(uint64_t dur) +{ + values_[METADATA_ITEM_TRACE_DURATION] = std::to_string(dur) + " s"; +} +const std::string& MetaData::Value(uint64_t row) const +{ + return values_[row]; +} +const std::string& MetaData::Name(uint64_t row) const +{ + return columnNames_[row]; +} +DataIndex DataDict::GetStringIndex(std::string_view str) +{ + auto hashValue = hashFun(str); + auto itor = dataDictInnerMap_.find(hashValue); + if (itor != dataDictInnerMap_.end()) { + return itor->second; + } + mutex_.lock(); + dataDict_.emplace_back(std::string(str)); + DataIndex stringIdentity = dataDict_.size() - 1; + dataDictInnerMap_.emplace(hashValue, stringIdentity); + mutex_.unlock(); + return stringIdentity; +} +DataIndex DataDict::GetStringIndexNoWrite(std::string_view str) const +{ + auto hashValue = hashFun(str); + auto itor = dataDictInnerMap_.find(hashValue); + if (itor != dataDictInnerMap_.end()) { + return itor->second; + } + return INVALID_UINT64; +} +size_t CpuUsageDetailData::AppendNewData(uint64_t newTimeStamp, + uint64_t dur, + double totalLoad, + double userLoad, + double systemLoad, + int64_t threads) +{ + timeStamps_.emplace_back(newTimeStamp); + durs_.emplace_back(dur); + totalLoad_.emplace_back(totalLoad); + userLoad_.emplace_back(userLoad); + systemLoad_.emplace_back(systemLoad); + threads_.emplace_back(threads); + return Size() - 1; +} +const std::deque& CpuUsageDetailData::Durs() const +{ + return durs_; +} +const std::deque& CpuUsageDetailData::TotalLoad() const +{ + return totalLoad_; +} +const std::deque& CpuUsageDetailData::UserLoad() const +{ + return userLoad_; +} +const std::deque& CpuUsageDetailData::SystemLoad() const +{ + return systemLoad_; +} +const std::deque& CpuUsageDetailData::Threads() const +{ + return threads_; +} +size_t LiveProcessDetailData::AppendNewData(uint64_t newTimeStamp, + uint64_t dur, + int32_t processID, + std::string processName, + int32_t parentProcessID, + int32_t uid, + std::string userName, + double cpuUsage, + int32_t pssInfo, + uint64_t cpuTime, + int32_t threads, + int64_t diskWrites, + int64_t diskReads) +{ + timeStamps_.emplace_back(newTimeStamp); + durs_.emplace_back(dur); + processID_.emplace_back(processID); + processName_.emplace_back(processName); + parentProcessID_.emplace_back(parentProcessID); + uid_.emplace_back(uid); + userName_.emplace_back(userName); + cpuUsage_.emplace_back(cpuUsage); + pssInfo_.emplace_back(pssInfo); + threads_.emplace_back(threads); + diskWrites_.emplace_back(diskWrites); + diskReads_.emplace_back(diskReads); + cpuTimes_.emplace_back(cpuTime); + return Size() - 1; +} +const std::deque& LiveProcessDetailData::Durs() const +{ + return durs_; +} +const std::deque& LiveProcessDetailData::ProcessID() const +{ + return processID_; +} +const std::deque& LiveProcessDetailData::ProcessName() const +{ + return processName_; +} +const std::deque& LiveProcessDetailData::ParentProcessID() const +{ + return parentProcessID_; +} +const std::deque& LiveProcessDetailData::Uid() const +{ + return uid_; +} +const std::deque& LiveProcessDetailData::UserName() const +{ + return userName_; +} +const std::deque& LiveProcessDetailData::CpuUsage() const +{ + return cpuUsage_; +} +const std::deque& LiveProcessDetailData::PssInfo() const +{ + return pssInfo_; +} +const std::deque& LiveProcessDetailData::Threads() const +{ + return threads_; +} +const std::deque& LiveProcessDetailData::DiskWrites() const +{ + return diskWrites_; +} +const std::deque& LiveProcessDetailData::DiskReads() const +{ + return diskReads_; +} + +const std::deque& LiveProcessDetailData::CpuTimes() const +{ + return cpuTimes_; +} + +size_t NetDetailData::AppendNewNetData(uint64_t newTimeStamp, + uint64_t tx, + uint64_t rx, + uint64_t dur, + double rxSpeed, + double txSpeed, + uint64_t packetIn, + double packetInSec, + uint64_t packetOut, + double packetOutSec, + const std::string& netType) +{ + timeStamps_.emplace_back(newTimeStamp); + txs_.emplace_back(tx); + rxs_.emplace_back(rx); + durs_.emplace_back(dur); + txSpeeds_.emplace_back(txSpeed); + rxSpeeds_.emplace_back(rxSpeed); + netTypes_.emplace_back(netType); + packetIn_.emplace_back(packetIn); + packetInSec_.emplace_back(packetInSec); + packetOut_.emplace_back(packetOut); + packetOutSec_.emplace_back(packetOutSec); + + return Size() - 1; +} +const std::deque& NetDetailData::Durs() const +{ + return durs_; +} +const std::deque& NetDetailData::RxSpeed() const +{ + return rxSpeeds_; +} +const std::deque& NetDetailData::TxSpeed() const +{ + return txSpeeds_; +} +const std::deque& NetDetailData::NetTypes() const +{ + return netTypes_; +} +const std::deque& NetDetailData::RxDatas() const +{ + return rxs_; +} +const std::deque& NetDetailData::TxDatas() const +{ + return txs_; +} +const std::deque& NetDetailData::PacketIn() const +{ + return packetIn_; +} +const std::deque& NetDetailData::PacketInSec() const +{ + return packetInSec_; +} +const std::deque& NetDetailData::PacketOut() const +{ + return packetOut_; +} +const std::deque& NetDetailData::PacketOutSec() const +{ + return packetOutSec_; +} + +void DiskIOData::AppendNewData(uint64_t ts, + uint64_t dur, + uint64_t rd, + uint64_t wr, + uint64_t rdPerSec, + uint64_t wrPerSec, + double rdCountPerSec, + double wrCountPerSec, + uint64_t rdCount, + uint64_t wrCount) +{ + timeStamps_.emplace_back(ts); + durs_.emplace_back(dur); + rdDatas_.emplace_back(rd); + wrDatas_.emplace_back(wr); + rdPerSec_.emplace_back(rdPerSec); + wrPerSec_.emplace_back(wrPerSec); + rdCountPerSec_.emplace_back(rdCountPerSec); + wrCountPerSec_.emplace_back(wrCountPerSec); + rdCountDatas_.emplace_back(rdCount); + wrCountDatas_.emplace_back(wrCount); +} +const std::deque& DiskIOData::Durs() const +{ + return durs_; +} +const std::deque& DiskIOData::RdDatas() const +{ + return rdDatas_; +} +const std::deque& DiskIOData::WrDatas() const +{ + return wrDatas_; +} +const std::deque& DiskIOData::RdSpeedDatas() const +{ + return rdPerSec_; +} +const std::deque& DiskIOData::WrSpeedDatas() const +{ + return wrPerSec_; +} + +const std::deque& DiskIOData::RdCountPerSecDatas() const +{ + return rdCountPerSec_; +} +const std::deque& DiskIOData::WrCountPerSecDatas() const +{ + return wrCountPerSec_; +} +const std::deque& DiskIOData::RdCountDatas() const +{ + return rdCountDatas_; +} +const std::deque& DiskIOData::WrCountDatas() const +{ + return wrCountDatas_; +} + +size_t FileSystemSample::AppendNewData(uint32_t callChainId, + uint16_t type, + uint32_t ipid, + uint32_t itid, + uint64_t startTs, + uint64_t endTs, + uint64_t dur, + DataIndex returnValue, + DataIndex errorCode, + size_t size, + int32_t fd, + DataIndex fileId, + DataIndex firstArgument, + DataIndex secondArgument, + DataIndex thirdArgument, + DataIndex fourthArgument) +{ + callChainIds_.emplace_back(callChainId); + types_.emplace_back(type); + ipids_.emplace_back(ipid); + itids_.emplace_back(itid); + startTs_.emplace_back(startTs); + endTs_.emplace_back(endTs); + durs_.emplace_back(dur); + returnValues_.emplace_back(returnValue); + errorCodes_.emplace_back(errorCode); + fds_.emplace_back(fd); + fileIds_.emplace_back(fileId); + Sizes_.emplace_back(size); + firstArguments_.emplace_back(firstArgument); + secondArguments_.emplace_back(secondArgument); + thirdArguments_.emplace_back(thirdArgument); + fourthArguments_.emplace_back(fourthArgument); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& FileSystemSample::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& FileSystemSample::Types() const +{ + return types_; +} +const std::deque& FileSystemSample::Ipids() const +{ + return ipids_; +} +const std::deque& FileSystemSample::Itids() const +{ + return itids_; +} +const std::deque& FileSystemSample::StartTs() const +{ + return startTs_; +} +const std::deque& FileSystemSample::EndTs() const +{ + return endTs_; +} +const std::deque& FileSystemSample::Durs() const +{ + return durs_; +} +const std::deque& FileSystemSample::ReturnValues() const +{ + return returnValues_; +} +const std::deque& FileSystemSample::ErrorCodes() const +{ + return errorCodes_; +} +const std::deque& FileSystemSample::Fds() const +{ + return fds_; +} +const std::deque& FileSystemSample::FileIds() const +{ + return fileIds_; +} +const std::deque& FileSystemSample::Sizes() const +{ + return Sizes_; +} +const std::deque& FileSystemSample::FirstArguments() const +{ + return firstArguments_; +} +const std::deque& FileSystemSample::SecondArguments() const +{ + return secondArguments_; +} +const std::deque& FileSystemSample::ThirdArguments() const +{ + return thirdArguments_; +} +const std::deque& FileSystemSample::FourthArguments() const +{ + return fourthArguments_; +} + +size_t PagedMemorySampleData::AppendNewData(uint32_t callChainId, + uint16_t type, + uint32_t ipid, + uint64_t startTs, + uint64_t endTs, + uint64_t dur, + size_t size, + DataIndex addr, + uint32_t itid) +{ + callChainIds_.emplace_back(callChainId); + types_.emplace_back(type); + ipids_.emplace_back(ipid); + startTs_.emplace_back(startTs); + endTs_.emplace_back(endTs); + durs_.emplace_back(dur); + Sizes_.emplace_back(size); + addrs_.emplace_back(addr); + itids_.emplace_back(itid); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& PagedMemorySampleData::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& PagedMemorySampleData::Types() const +{ + return types_; +} +const std::deque& PagedMemorySampleData::Ipids() const +{ + return ipids_; +} +const std::deque& PagedMemorySampleData::Itids() const +{ + return itids_; +} +const std::deque& PagedMemorySampleData::StartTs() const +{ + return startTs_; +} +const std::deque& PagedMemorySampleData::EndTs() const +{ + return endTs_; +} +const std::deque& PagedMemorySampleData::Durs() const +{ + return durs_; +} +const std::deque& PagedMemorySampleData::Sizes() const +{ + return Sizes_; +} +const std::deque& PagedMemorySampleData::Addr() const +{ + return addrs_; +} + +size_t EbpfCallStackData::AppendNewData(uint32_t callChainId, + uint32_t depth, + DataIndex ip, + DataIndex symbolId, + DataIndex filePathId) +{ + callChainIds_.emplace_back(callChainId); + depths_.emplace_back(depth); + ips_.emplace_back(ip); + symbolIds_.emplace_back(symbolId); + filePathIds_.emplace_back(filePathId); + ids_.emplace_back(Size()); + return Size() - 1; +} +void EbpfCallStackData::UpdateSymbolAndFilePathIndex(size_t row, DataIndex symbolId, DataIndex filePathId) +{ + if (row >= Size()) { + TS_LOGE("The updated row does not exist!"); + return; + } + symbolIds_[row] = symbolId; + filePathIds_[row] = filePathId; +} +const std::deque& EbpfCallStackData::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& EbpfCallStackData::Depths() const +{ + return depths_; +} +const std::deque& EbpfCallStackData::Ips() const +{ + return ips_; +} +const std::deque& EbpfCallStackData::SymbolIds() const +{ + return symbolIds_; +} +const std::deque& EbpfCallStackData::FilePathIds() const +{ + return filePathIds_; +} +#if WITH_EBPF_HELP +size_t EbpfProcessMaps::AppendNewData(uint64_t start, + uint64_t end, + uint32_t offset, + uint32_t pid, + uint32_t fileNameLen, + uint64_t fileNameIndex) +{ + starts_.emplace_back(start); + ends_.emplace_back(end); + offsets_.emplace_back(offset); + pids_.emplace_back(pid); + fileNameLens_.emplace_back(fileNameLen); + fileNameIndexs_.emplace_back(fileNameIndex); + ids_.emplace_back(Size()); + return Size() - 1; +} + +const std::deque& EbpfProcessMaps::Starts() const +{ + return starts_; +} +const std::deque& EbpfProcessMaps::Ends() const +{ + return ends_; +} +const std::deque& EbpfProcessMaps::Offsets() const +{ + return offsets_; +} +const std::deque& EbpfProcessMaps::Pids() const +{ + return pids_; +} +const std::deque& EbpfProcessMaps::FileNameLens() const +{ + return fileNameLens_; +} +const std::deque& EbpfProcessMaps::FileNameIndexs() const +{ + return fileNameIndexs_; +} + +size_t EbpfElf::AppendNewData(uint64_t elfId, + uint64_t textVaddr, + uint32_t textOffset, + uint32_t strTabLen, + uint32_t symTabLen, + uint32_t fileNameLen, + uint32_t symEntLen, + uint64_t fileNameIndex) +{ + elfIds_.emplace_back(elfId); + textVaddrs_.emplace_back(textVaddr); + textOffsets_.emplace_back(textOffset); + strTabLens_.emplace_back(strTabLen); + symTabLens_.emplace_back(symTabLen); + fileNameLens_.emplace_back(fileNameLen); + symEntLens_.emplace_back(symEntLen); + fileNameIndexs_.emplace_back(fileNameIndex); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& EbpfElf::ElfIds() const +{ + return elfIds_; +} +const std::deque& EbpfElf::TextVaddrs() const +{ + return textVaddrs_; +} +const std::deque& EbpfElf::TextOffsets() const +{ + return textOffsets_; +} +const std::deque& EbpfElf::StrTabLens() const +{ + return strTabLens_; +} +const std::deque& EbpfElf::SymTabLens() const +{ + return symTabLens_; +} +const std::deque& EbpfElf::FileNameLens() const +{ + return fileNameLens_; +} +const std::deque& EbpfElf::SymEntLens() const +{ + return symEntLens_; +} +const std::deque& EbpfElf::FileNameIndexs() const +{ + return fileNameIndexs_; +} + +size_t EbpfElfSymbol::AppendNewData(uint64_t elfId, uint32_t stName, uint64_t stValue, uint64_t stSize) +{ + elfIds_.emplace_back(elfId); + stNames_.emplace_back(stName); + stValues_.emplace_back(stValue); + stSizes_.emplace_back(stSize); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& EbpfElfSymbol::ElfIds() const +{ + return elfIds_; +} +const std::deque& EbpfElfSymbol::StNames() const +{ + return stNames_; +} +const std::deque& EbpfElfSymbol::StValues() const +{ + return stValues_; +} +const std::deque& EbpfElfSymbol::StSizes() const +{ + return stSizes_; +} +#endif +uint32_t AppNames::AppendAppName(uint8_t flags, DataIndex eventSource, DataIndex appName) +{ + flags_.push_back(flags); + appNames_.push_back(eventSource); + keyNames_.push_back(appName); + ids_.push_back(keyNames_.size() - 1); + return Size() - 1; +} +const std::deque& AppNames::Falgs() const +{ + return flags_; +} +const std::deque& AppNames::EventSourceId() const +{ + return appNames_; +} +const std::deque& AppNames::AppName() const +{ + return keyNames_; +} + +void SysEventMeasureData::AppendData(uint64_t serial, + uint64_t ts, + uint32_t nameId, + uint32_t keyId, + int32_t type, + double numericValue, + DataIndex stringValue) +{ + serial_.emplace_back(serial); + ts_.emplace_back(ts); + nameFilterIds_.emplace_back(nameId); + appKeyFilterIds_.emplace_back(keyId); + types_.emplace_back(type); + numValues_.emplace_back(numericValue); + stringValues_.emplace_back(stringValue); + ids_.push_back(rowCount_); + rowCount_++; +} +const std::deque& SysEventMeasureData::Serial() const +{ + return serial_; +} +const std::deque& SysEventMeasureData::Ts() const +{ + return ts_; +} +const std::deque& SysEventMeasureData::NameFilterId() const +{ + return nameFilterIds_; +} +const std::deque& SysEventMeasureData::AppKeyFilterId() const +{ + return appKeyFilterIds_; +} +const std::deque& SysEventMeasureData::Type() const +{ + return types_; +} +const std::deque& SysEventMeasureData::NumValue() const +{ + return numValues_; +} +const std::deque& SysEventMeasureData::StringValue() const +{ + return stringValues_; +} +void DeviceStateData::AppendNewData(int32_t brightness, + int32_t btState, + int32_t location, + int32_t wifi, + int32_t streamDefault, + int32_t voiceCall, + int32_t music, + int32_t streamRing, + int32_t media, + int32_t voiceAssistant, + int32_t system, + int32_t alarm, + int32_t notification, + int32_t btSco, + int32_t enforcedAudible, + int32_t streamDtmf, + int32_t streamTts, + int32_t accessibility, + int32_t recording, + int32_t streamAll) +{ + brightness_.emplace_back(brightness); + btStates_.emplace_back(btState); + locations_.emplace_back(location); + wifis_.emplace_back(wifi); + streamDefaults_.emplace_back(streamDefault); + voiceCalls_.emplace_back(voiceCall); + musics_.emplace_back(music); + streamRings_.emplace_back(streamRing); + medias_.emplace_back(media); + voiceAssistants_.emplace_back(voiceAssistant); + systems_.emplace_back(system); + alarms_.emplace_back(alarm); + notifications_.emplace_back(notification); + btScos_.emplace_back(btSco); + enforcedAudibles_.emplace_back(enforcedAudible); + streamDtmfs_.emplace_back(streamDtmf); + streamTts_.emplace_back(streamTts); + accessibilitys_.emplace_back(accessibility); + recordings_.emplace_back(recording); + streamAlls_.emplace_back(streamAll); + ids_.push_back(rowCounts_); + rowCounts_++; +} +const std::deque& DeviceStateData::Brightness() const +{ + return brightness_; +} +const std::deque& DeviceStateData::BtState() const +{ + return btStates_; +} +const std::deque& DeviceStateData::Location() const +{ + return locations_; +} +const std::deque& DeviceStateData::Wifi() const +{ + return wifis_; +} +const std::deque& DeviceStateData::StreamDefault() const +{ + return streamDefaults_; +} +const std::deque& DeviceStateData::VoiceCall() const +{ + return voiceCalls_; +} +const std::deque& DeviceStateData::Music() const +{ + return musics_; +} +const std::deque& DeviceStateData::StreamRing() const +{ + return streamRings_; +} +const std::deque& DeviceStateData::Media() const +{ + return medias_; +} +const std::deque& DeviceStateData::VoiceAssistant() const +{ + return voiceAssistants_; +} +const std::deque& DeviceStateData::System() const +{ + return systems_; +} +const std::deque& DeviceStateData::Alarm() const +{ + return alarms_; +} +const std::deque& DeviceStateData::Notification() const +{ + return notifications_; +} +const std::deque& DeviceStateData::BtSco() const +{ + return btScos_; +} +const std::deque& DeviceStateData::EnforcedAudible() const +{ + return enforcedAudibles_; +} +const std::deque& DeviceStateData::StreamDtmf() const +{ + return streamDtmfs_; +} +const std::deque& DeviceStateData::StreamTts() const +{ + return streamTts_; +} +const std::deque& DeviceStateData::Accessibility() const +{ + return accessibilitys_; +} +const std::deque& DeviceStateData::Recording() const +{ + return recordings_; +} +const std::deque& DeviceStateData::StreamAll() const +{ + return streamAlls_; +} +void TraceConfigData::AppendNewData(std::string traceSource, std::string key, std::string value) +{ + traceSource_.emplace_back(traceSource); + key_.emplace_back(key); + value_.emplace_back(value); + ids_.push_back(rowCounts_); + rowCounts_++; +} +const std::deque& TraceConfigData::TraceSource() const +{ + return traceSource_; +} +const std::deque& TraceConfigData::Key() const +{ + return key_; +} +const std::deque& TraceConfigData::Value() const +{ + return value_; +} +void SmapsData::AppendNewData(uint64_t timeStamp, + std::string startAddr, + std::string endAddr, + uint64_t dirty, + uint64_t swapper, + uint64_t rss, + uint64_t pss, + uint64_t size, + double reside, + DataIndex protectionId, + DataIndex pathId) +{ + timeStamps_.emplace_back(timeStamp); + startAddrs_.emplace_back(startAddr); + endAddrs_.emplace_back(endAddr); + dirtys_.emplace_back(dirty); + swappers_.emplace_back(swapper); + rss_.emplace_back(rss); + pss_.emplace_back(pss); + sizes_.emplace_back(size); + resides_.emplace_back(reside); + protectionIds_.emplace_back(protectionId); + pathIds_.emplace_back(pathId); + ids_.push_back(rowCount_); + rowCount_++; +} +const std::deque& SmapsData::TimeStamps() const +{ + return timeStamps_; +} +const std::deque& SmapsData::StartAddrs() const +{ + return startAddrs_; +} +const std::deque& SmapsData::EndAddrs() const +{ + return endAddrs_; +} +const std::deque& SmapsData::Dirtys() const +{ + return dirtys_; +} +const std::deque& SmapsData::Swappers() const +{ + return swappers_; +} +const std::deque& SmapsData::Rss() const +{ + return rss_; +} +const std::deque& SmapsData::Pss() const +{ + return pss_; +} +const std::deque& SmapsData::Sizes() const +{ + return sizes_; +} +const std::deque& SmapsData::Resides() const +{ + return resides_; +} +const std::deque& SmapsData::ProtectionIds() const +{ + return protectionIds_; +} +const std::deque& SmapsData::PathIds() const +{ + return pathIds_; +} +void BioLatencySampleData::AppendNewData(uint32_t callChainId, + uint64_t type, + uint32_t ipid, + uint32_t itid, + uint64_t startTs, + uint64_t endTs, + uint64_t latencyDur, + uint32_t tier, + uint64_t size, + uint64_t blockNumber, + uint64_t filePathId, + uint64_t durPer4k) +{ + callChainIds_.emplace_back(callChainId); + types_.emplace_back(type); + ipids_.emplace_back(ipid); + itids_.emplace_back(itid); + startTs_.emplace_back(startTs); + endTs_.emplace_back(endTs); + latencyDurs_.emplace_back(latencyDur); + tiers_.emplace_back(tier); + sizes_.emplace_back(size); + blockNumbers_.emplace_back(blockNumber); + filePathIds_.emplace_back(filePathId); + durPer4ks_.emplace_back(durPer4k); + ids_.emplace_back(rowCount_); + rowCount_++; +} +const std::deque& BioLatencySampleData::CallChainIds() const +{ + return callChainIds_; +} +const std::deque& BioLatencySampleData::Types() const +{ + return types_; +} +const std::deque& BioLatencySampleData::Ipids() const +{ + return ipids_; +} +const std::deque& BioLatencySampleData::Itids() const +{ + return itids_; +} +const std::deque& BioLatencySampleData::StartTs() const +{ + return startTs_; +} +const std::deque& BioLatencySampleData::EndTs() const +{ + return endTs_; +} +const std::deque& BioLatencySampleData::LatencyDurs() const +{ + return latencyDurs_; +} +const std::deque& BioLatencySampleData::Tiers() const +{ + return tiers_; +} +const std::deque& BioLatencySampleData::Sizes() const +{ + return sizes_; +} +const std::deque& BioLatencySampleData::BlockNumbers() const +{ + return blockNumbers_; +} +const std::deque& BioLatencySampleData::FilePathIds() const +{ + return filePathIds_; +} +const std::deque& BioLatencySampleData::DurPer4k() const +{ + return durPer4ks_; +} +#ifndef IS_PBDECODER +DataSourceClockIdData::DataSourceClockIdData() + : dataSource2ClockIdMap_({{DATA_SOURCE_TYPE_TRACE, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_MEM, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_HILOG, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_NATIVEHOOK, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_FPS, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_NETWORK, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_DISKIO, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_CPU, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_PROCESS, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_HISYSEVENT, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_JSMEMORY, TS_CLOCK_UNKNOW}}), + dataSource2PluginNameMap_({ + {DATA_SOURCE_TYPE_TRACE, "ftrace-plugin"}, + {DATA_SOURCE_TYPE_MEM, "memory-plugin"}, + {DATA_SOURCE_TYPE_HILOG, "hilog-plugin"}, + {DATA_SOURCE_TYPE_NATIVEHOOK, "nativehook"}, + {DATA_SOURCE_TYPE_FPS, "hidump-plugin"}, + {DATA_SOURCE_TYPE_NETWORK, "network-plugin"}, + {DATA_SOURCE_TYPE_DISKIO, "diskio-plugin"}, + {DATA_SOURCE_TYPE_CPU, "cpu-plugin"}, + {DATA_SOURCE_TYPE_PROCESS, "process-plugin"}, + {DATA_SOURCE_TYPE_HISYSEVENT, "hisysevent-plugin"}, + {DATA_SOURCE_TYPE_JSMEMORY, "js-memory"}, + }) +{ +} +#else +DataSourceClockIdData::DataSourceClockIdData() + : dataSource2ClockIdMap_({{DATA_SOURCE_TYPE_TRACE, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_MEM, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_HILOG, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_ALLOCATION, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_FPS, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_NETWORK, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_DISKIO, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_CPU, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_PROCESS, TS_CLOCK_UNKNOW}, + {DATA_SOURCE_TYPE_HISYSEVENT, TS_CLOCK_UNKNOW}}), + dataSource2PluginNameMap_({{DATA_SOURCE_TYPE_TRACE, "ftrace-plugin"}, + {DATA_SOURCE_TYPE_MEM, "memory-plugin"}, + {DATA_SOURCE_TYPE_HILOG, "hilog-plugin"}, + {DATA_SOURCE_TYPE_ALLOCATION, "nativehook"}, + {DATA_SOURCE_TYPE_FPS, "hidump-plugin"}, + {DATA_SOURCE_TYPE_NETWORK, "network-plugin"}, + {DATA_SOURCE_TYPE_DISKIO, "diskio-plugin"}, + {DATA_SOURCE_TYPE_CPU, "cpu-plugin"}, + {DATA_SOURCE_TYPE_PROCESS, "process-plugin"}, + {DATA_SOURCE_TYPE_HISYSEVENT, "hisysevent-plugin"}}) + +{ +} +#endif +void DataSourceClockIdData::Finish() +{ + for (auto i = dataSource2ClockIdMap_.begin(); i != dataSource2ClockIdMap_.end(); i++) { + if (i->second) { // ignore the empty datasource, for which the clockid is default TS_CLOCK_UNKNOW 0 + dataSourceNames_.emplace_back(dataSource2PluginNameMap_.at(i->first)); + clockIds_.emplace_back(i->second); + } + } +} +void DataSourceClockIdData::SetDataSourceClockId(DataSourceType source, uint32_t id) +{ + dataSource2ClockIdMap_.at(source) = id; +} +size_t FrameSlice::AppendFrame(uint64_t ts, uint32_t ipid, uint32_t itid, uint32_t vsyncId, uint64_t callStackSliceId) +{ + timeStamps_.emplace_back(ts); + ipids_.emplace_back(ipid); + internalTids_.emplace_back(itid); + vsyncIds_.emplace_back(vsyncId); + callStackIds_.emplace_back(callStackSliceId); + endTss_.emplace_back(INVALID_UINT64); + dsts_.emplace_back(INVALID_UINT64); + ids_.emplace_back(ids_.size()); + durs_.emplace_back(INVALID_UINT64); + types_.emplace_back(0); + flags_.emplace_back(INVALID_UINT8); + srcs_.emplace_back(""); + depths_.emplace_back(0); + frameNos_.emplace_back(0); + return Size() - 1; +} +size_t FrameSlice::AppendFrame(uint64_t ts, + uint32_t ipid, + uint32_t itid, + uint32_t vsyncId, + uint64_t callStackSliceId, + uint64_t end, + uint8_t type) +{ + auto row = AppendFrame(ts, ipid, itid, vsyncId, callStackSliceId); + SetEndTime(row, end); + SetType(row, type); + depths_.emplace_back(0); + frameNos_.emplace_back(0); + durs_[row] = end - ts; + return row; +} + +void FrameSlice::SetEndTime(uint64_t row, uint64_t end) +{ + endTss_[row] = end; +} +void FrameSlice::SetType(uint64_t row, uint8_t type) +{ + types_[row] = type; +} +void FrameSlice::SetDst(uint64_t row, uint64_t dst) +{ + dsts_[row] = dst; +} + +void FrameSlice::SetSrcs(uint64_t row, const std::vector& fromSlices) +{ + std::string s = ""; + for (auto&& i : fromSlices) { + s += std::to_string(i) + ","; + } + s.pop_back(); + srcs_[row] = s; +} +const std::deque FrameSlice::Ipids() const +{ + return ipids_; +} +const std::deque FrameSlice::VsyncIds() const +{ + return vsyncIds_; +} +const std::deque FrameSlice::CallStackIds() const +{ + return callStackIds_; +} +const std::deque FrameSlice::EndTss() const +{ + return endTss_; +} +const std::deque FrameSlice::Dsts() const +{ + return dsts_; +} +const std::deque FrameSlice::Durs() const +{ + return durs_; +} +const std::deque FrameSlice::Types() const +{ + return types_; +} +const std::deque FrameSlice::Flags() const +{ + return flags_; +} + +const std::deque FrameSlice::Depths() const +{ + return depths_; +} +const std::deque FrameSlice::FrameNos() const +{ + return frameNos_; +} +const std::deque& FrameSlice::Srcs() const +{ + return srcs_; +} +void FrameSlice::UpdateCallStackSliceId(uint64_t row, uint64_t callStackSliceId) +{ + callStackIds_[row] = callStackSliceId; +} +void FrameSlice::SetEndTimeAndFlag(uint64_t row, uint64_t ts, uint64_t expectDur, uint64_t expectEnd) +{ + UNUSED(expectDur); + durs_[row] = ts - timeStamps_[row]; + flags_[row] = expectEnd >= ts ? 0 : 1; +} +void FrameSlice::Erase(uint64_t row) +{ + flags_[row] = INVALID_ROW; +} +size_t FrameMaps::AppendNew(uint64_t src, uint64_t dst) +{ + timeStamps_.emplace_back(0); + ids_.emplace_back(ids_.size()); + srcs_.push_back(src); + dsts_.push_back(dst); + return Size() - 1; +} +const std::deque& FrameMaps::SrcIndexs() const +{ + return srcs_; +} +const std::deque& FrameMaps::DstIndexs() const +{ + return dsts_; +} + +size_t GPUSlice::AppendNew(uint32_t frameRow, uint64_t dur) +{ + frameRows_.emplace_back(frameRow); + durs_.emplace_back(dur); + return Size() - 1; +} +const std::deque& GPUSlice::FrameRows() const +{ + return frameRows_; +} +const std::deque& GPUSlice::Durs() const +{ + return durs_; +} +const size_t GPUSlice::Size() const +{ + return durs_.size(); +} + +size_t + JsHeapFiles::AppendNewData(uint32_t id, std::string filePath, uint64_t startTime, uint64_t endTime, uint32_t ipid) +{ + fileIds_.emplace_back(id); + filePaths_.emplace_back(filePath); + startTimes_.emplace_back(startTime); + endTimes_.emplace_back(endTime); + ipids_.emplace_back(ipid); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapFiles::IDs() const +{ + return fileIds_; +} +const std::deque& JsHeapFiles::FilePaths() const +{ + return filePaths_; +} +const std::deque& JsHeapFiles::StartTimes() const +{ + return startTimes_; +} +const std::deque& JsHeapFiles::EndTimes() const +{ + return endTimes_; +} +const std::deque& JsHeapFiles::Pids() const +{ + return ipids_; +} + +size_t JsHeapEdges::AppendNewData(uint32_t fileId, + uint32_t edgeIndex, + uint32_t type, + uint32_t nameOrIndex, + uint32_t toNode, + uint32_t fromNodeId, + uint32_t toNodeId) +{ + fileIds_.emplace_back(fileId); + edgeIndexs_.emplace_back(edgeIndex); + types_.emplace_back(type); + nameOrIndexs_.emplace_back(nameOrIndex); + toNodes_.emplace_back(toNode); + fromNodeIds_.emplace_back(fromNodeId); + toNodeIds_.emplace_back(toNodeId); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapEdges::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapEdges::EdgeIndexs() const +{ + return edgeIndexs_; +} +const std::deque& JsHeapEdges::Types() const +{ + return types_; +} +const std::deque& JsHeapEdges::NameOrIndexs() const +{ + return nameOrIndexs_; +} +const std::deque& JsHeapEdges::ToNodes() const +{ + return toNodes_; +} +const std::deque& JsHeapEdges::FromNodeIds() const +{ + return fromNodeIds_; +} +const std::deque& JsHeapEdges::ToNodeIds() const +{ + return toNodeIds_; +} + +size_t + JsHeapInfo::AppendNewData(uint32_t fileId, std::string key, uint32_t type, int32_t intValue, std::string strValue) +{ + fileIds_.emplace_back(fileId); + keys_.emplace_back(key); + types_.emplace_back(type); + intValues_.emplace_back(intValue); + strValues_.emplace_back(strValue); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapInfo::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapInfo::Keys() const +{ + return keys_; +} +const std::deque& JsHeapInfo::Types() const +{ + return types_; +} +const std::deque& JsHeapInfo::IntValues() const +{ + return intValues_; +} +const std::deque& JsHeapInfo::StrValues() const +{ + return strValues_; +} + +size_t JsHeapLocation::AppendNewData(uint32_t fileId, + uint32_t objectIndex, + uint32_t scriptId, + uint32_t line, + uint32_t column) +{ + fileIds_.emplace_back(fileId); + objectIndexs_.emplace_back(objectIndex); + scriptIds_.emplace_back(scriptId); + lines_.emplace_back(line); + columns_.emplace_back(column); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapLocation::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapLocation::ObjectIndexs() const +{ + return objectIndexs_; +} +const std::deque& JsHeapLocation::ScriptIds() const +{ + return scriptIds_; +} +const std::deque& JsHeapLocation::Lines() const +{ + return lines_; +} +const std::deque& JsHeapLocation::Columns() const +{ + return columns_; +} + +size_t JsHeapNodes::AppendNewData(uint32_t fileId, + uint32_t nodeIndex, + uint32_t type, + uint32_t name, + uint32_t id, + uint32_t selfSize, + uint32_t edgeCount, + uint32_t traceNodeId, + uint32_t detachedNess) +{ + fileIds_.emplace_back(fileId); + nodeIndexs_.emplace_back(nodeIndex); + types_.emplace_back(type); + names_.emplace_back(name); + nodeIds_.emplace_back(id); + selfSizes_.emplace_back(selfSize); + edgeCounts_.emplace_back(edgeCount); + traceNodeIds_.emplace_back(traceNodeId); + detachedNess_.emplace_back(detachedNess); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapNodes::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapNodes::NodeIndexs() const +{ + return nodeIndexs_; +} +const std::deque& JsHeapNodes::Types() const +{ + return types_; +} +const std::deque& JsHeapNodes::Names() const +{ + return names_; +} +const std::deque& JsHeapNodes::NodeIds() const +{ + return nodeIds_; +} +const std::deque& JsHeapNodes::SelfSizes() const +{ + return selfSizes_; +} +const std::deque& JsHeapNodes::EdgeCounts() const +{ + return edgeCounts_; +} +const std::deque& JsHeapNodes::TraceNodeIds() const +{ + return traceNodeIds_; +} +const std::deque& JsHeapNodes::DetachedNess() const +{ + return detachedNess_; +} + +size_t JsHeapSample::AppendNewData(uint32_t fileId, uint64_t timeStampUs, uint32_t lastAssignedId) +{ + fileIds_.emplace_back(fileId); + timeStampUs_.emplace_back(timeStampUs); + lastAssignedIds_.emplace_back(lastAssignedId); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapSample::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapSample::TimeStampUs() const +{ + return timeStampUs_; +} +const std::deque& JsHeapSample::LastAssignedIds() const +{ + return lastAssignedIds_; +} + +size_t JsHeapString::AppendNewData(uint32_t fileId, uint32_t fileIndex, std::string string) +{ + fileIds_.emplace_back(fileId); + fileIndexs_.emplace_back(fileIndex); + strings_.emplace_back(string); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapString::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapString::FileIndexs() const +{ + return fileIndexs_; +} +const std::deque& JsHeapString::Strings() const +{ + return strings_; +} + +size_t JsHeapTraceFuncInfo::AppendNewData(uint32_t fileId, + uint32_t functionIndex, + uint32_t functionId, + uint32_t name, + uint32_t scriptName, + uint32_t scriptId, + uint32_t line, + uint32_t column) +{ + fileIds_.emplace_back(fileId); + functionIndexs_.emplace_back(functionIndex); + functionIds_.emplace_back(functionId); + names_.emplace_back(name); + scriptNames_.emplace_back(scriptName); + scriptIds_.emplace_back(scriptId); + lines_.emplace_back(line); + columns_.emplace_back(column); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapTraceFuncInfo::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapTraceFuncInfo::FunctionIndexs() const +{ + return functionIndexs_; +} +const std::deque& JsHeapTraceFuncInfo::FunctionIds() const +{ + return functionIds_; +} +const std::deque& JsHeapTraceFuncInfo::Names() const +{ + return names_; +} +const std::deque& JsHeapTraceFuncInfo::ScriptNames() const +{ + return scriptNames_; +} +const std::deque& JsHeapTraceFuncInfo::ScriptIds() const +{ + return scriptIds_; +} +const std::deque& JsHeapTraceFuncInfo::Lines() const +{ + return lines_; +} +const std::deque& JsHeapTraceFuncInfo::Columns() const +{ + return columns_; +} + +size_t JsHeapTraceNode::AppendNewData(uint32_t fileId, + uint32_t traceNodeId, + uint32_t functionInfoIndex, + uint32_t count, + uint32_t size, + int32_t parentId) +{ + fileIds_.emplace_back(fileId); + traceNodeIds_.emplace_back(traceNodeId); + functionInfoIndexs_.emplace_back(functionInfoIndex); + counts_.emplace_back(count); + sizes_.emplace_back(size); + parentIds_.emplace_back(parentId); + ids_.emplace_back(Size()); + return Size() - 1; +} +const std::deque& JsHeapTraceNode::FileIds() const +{ + return fileIds_; +} +const std::deque& JsHeapTraceNode::TraceNodeIDs() const +{ + return traceNodeIds_; +} +const std::deque& JsHeapTraceNode::FunctionInfoIndexs() const +{ + return functionInfoIndexs_; +} +const std::deque& JsHeapTraceNode::Counts() const +{ + return counts_; +} +const std::deque& JsHeapTraceNode::NodeSizes() const +{ + return sizes_; +} +const std::deque& JsHeapTraceNode::ParentIds() const +{ + return parentIds_; +} + +} // namespace TraceStdtype +} // namespace SysTuning diff --git a/trace_streamer/src/trace_data/trace_stdtype.h b/trace_streamer/src/trace_data/trace_stdtype.h new file mode 100644 index 0000000000000000000000000000000000000000..550f00cb0ad52816a3ea607ad252524d8f3a35f1 --- /dev/null +++ b/trace_streamer/src/trace_data/trace_stdtype.h @@ -0,0 +1,2226 @@ +/* + * 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 TRACE_STDTYPE_H +#define TRACE_STDTYPE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cfg/trace_streamer_config.h" +#include "double_map.h" +#include "log.h" +#include "ts_common.h" + +namespace SysTuning { +namespace TraceStdtype { +using namespace SysTuning::TraceCfg; +using namespace SysTuning::TraceStreamer; +class CacheBase { +public: + size_t Size() const + { + return std::max(timeStamps_.size(), ids_.size()); + } + const std::deque& IdsData() const + { + return ids_; + } + const std::deque& TimeStampData() const + { + return timeStamps_; + } + const std::deque& InternalTidsData() const + { + return internalTids_; + } + virtual void Clear() + { + internalTids_.clear(); + timeStamps_.clear(); + ids_.clear(); + } + +public: + std::deque internalTids_ = {}; + std::deque timeStamps_ = {}; + std::deque ids_ = {}; +}; + +class CpuCacheBase { +public: + const std::deque& DursData() const + { + return durs_; + } + + const std::deque& CpusData() const + { + return cpus_; + } + virtual void Clear() + { + durs_.clear(); + cpus_.clear(); + } + void SetDur(uint64_t index, uint64_t dur); + +public: + std::deque durs_; + std::deque cpus_; +}; +class Thread { +public: + explicit Thread(uint32_t t) : tid_(t) {} + InternalPid internalPid_ = INVALID_UINT32; + uint32_t tid_ = 0; + DataIndex nameIndex_ = 0; + InternalTime startT_ = 0; + InternalTime endT_ = 0; + uint32_t switchCount_ = 0; + uint32_t sliceSize_ = 0; + uint32_t cpuStatesCount_ = 0; +}; + +class Process { +public: + explicit Process(uint32_t p) : pid_(p) {} + std::string cmdLine_ = ""; + InternalTime startT_ = 0; + uint32_t pid_ = 0; + uint32_t memSize_ = 0; + uint32_t threadSize_ = 0; + uint32_t sliceSize_ = 0; + uint32_t switchCount_ = 0; + int32_t threadCount_ = -1; + uint32_t cpuStatesCount_ = 0; +}; + +class ThreadState { +public: + TableRowId + AppendThreadState(InternalTime ts, InternalTime dur, InternalCpu cpu, InternalTid itid, TableRowId idState); + void SetDuration(TableRowId index, InternalTime dur); + TableRowId UpdateDuration(TableRowId index, InternalTime ts); + bool End(TableRowId index, InternalTime ts); + void UpdateState(TableRowId index, TableRowId idState); + void SetArgSetId(TableRowId index, uint32_t setId); + void UpdateDuration(TableRowId index, InternalTime ts, TableRowId idState); + void UpdateTidAndPid(TableRowId index, InternalTid tid, InternalTid pid); + TableRowId UpdateDuration(TableRowId index, InternalTime ts, InternalCpu cpu, TableRowId idState); + void Clear() + { + timeStamps_.clear(); + durations_.clear(); + itids_.clear(); + tids_.clear(); + pids_.clear(); + states_.clear(); + cpus_.clear(); + } + const uint32_t Size() const + { + return itids_.size(); + } + + const std::deque& TimeStamsData() const + { + return timeStamps_; + } + const std::deque& DursData() const + { + return durations_; + } + const std::deque& ItidsData() const + { + return itids_; + } + const std::deque& TidsData() const + { + return tids_; + } + const std::deque& PidsData() const + { + return pids_; + } + const std::deque& StatesData() const + { + return states_; + } + const std::deque& CpusData() const + { + return cpus_; + } + const std::deque& ArgSetsData() const + { + return argSetIds_; + } + +private: + std::deque timeStamps_; + std::deque durations_; + std::deque itids_; + std::deque tids_; + std::deque pids_; + std::deque states_; + std::deque cpus_; + std::deque argSetIds_; +}; + +class SchedSlice : public CacheBase, public CpuCacheBase { +public: + size_t AppendSchedSlice(uint64_t ts, + uint64_t dur, + uint64_t cpu, + uint32_t internalTid, + uint64_t endState, + uint64_t priority); + void SetDuration(size_t index, uint64_t duration); + void Update(uint64_t index, uint64_t ts, uint64_t state); + void UpdateArg(uint64_t index, uint32_t argsetId); + + const std::deque& EndStatesData() const + { + return endStates_; + } + + const std::deque& PriorityData() const + { + return priority_; + } + + const std::deque& ArgSetData() const + { + return argSets_; + } + const std::deque& TsEndData() const + { + return tsEnds_; + } + const std::deque& InternalPidsData() const + { + return internalPids_; + } + void AppendInternalPid(InternalPid ipid) + { + internalPids_.emplace_back(ipid); + } + void Clear() override + { + CacheBase::Clear(); + CpuCacheBase::Clear(); + endStates_.clear(); + priority_.clear(); + internalPids_.clear(); + tsEnds_.clear(); + } + +private: + std::deque internalPids_ = {}; + std::deque tsEnds_ = {}; + std::deque endStates_ = {}; + std::deque priority_ = {}; + std::deque argSets_ = {}; +}; + +class CallStack : public CacheBase, public CpuCacheBase { +public: + size_t AppendInternalAsyncSlice(uint64_t startT, + uint64_t durationNs, + InternalTid internalTid, + DataIndex cat, + uint16_t nameIdentify, + DataIndex name, + uint8_t depth, + uint64_t cookid, + const std::optional& parentId); + size_t AppendInternalSlice(uint64_t startT, + uint64_t durationNs, + InternalTid internalTid, + DataIndex cat, + uint16_t nameIdentify, + DataIndex name, + uint8_t depth, + const std::optional& parentId); + void SetDistributeInfo(size_t index, + const std::string& chainId, + const std::string& spanId, + const std::string& parentSpanId, + const std::string& flag, + const std::string& args); + void AppendDistributeInfo(const std::string& chainId, + const std::string& spanId, + const std::string& parentSpanId, + const std::string& flag, + const std::string& args); + void AppendDistributeInfo(); + void SetDuration(size_t index, uint64_t timeStamp); + void SetDurationWithFlag(size_t index, uint64_t timeStamp); + void SetFlag(size_t index, uint8_t flag); + void SetDurationEx(size_t index, uint32_t dur); + void SetIrqDurAndArg(size_t index, uint64_t timeStamp, uint32_t argSetId); + void SetTimeStamp(size_t index, uint64_t timeStamp); + void SetDepth(size_t index, uint8_t depth); + void SetArgSetId(size_t index, uint32_t argSetId); + void Clear() override + { + CacheBase::Clear(); + CpuCacheBase::Clear(); + cats_.clear(); + cookies_.clear(); + callIds_.clear(); + names_.clear(); + depths_.clear(); + chainIds_.clear(); + spanIds_.clear(); + parentSpanIds_.clear(); + flags_.clear(); + args_.clear(); + argSet_.clear(); + } + + const std::deque>& ParentIdData() const; + const std::deque& CatsData() const; + const std::deque& NamesData() const; + const std::deque& Depths() const; + const std::deque& Cookies() const; + const std::deque& CallIds() const; + const std::deque& IdentifysData() const; + const std::deque& ChainIds() const; + const std::deque& SpanIds() const; + const std::deque& ParentSpanIds() const; + const std::deque& Flags() const; + const std::deque& ArgsData() const; + const std::deque& ArgSetIdsData() const; + +private: + void AppendCommonInfo(uint64_t startT, uint64_t durationNs, InternalTid internalTid); + void AppendCallStack(DataIndex cat, DataIndex name, uint8_t depth, std::optional parentId); + +private: + std::deque> parentIds_; + std::deque cats_ = {}; + std::deque cookies_ = {}; + std::deque callIds_ = {}; + std::deque identifys_ = {}; + std::deque names_ = {}; + std::deque depths_ = {}; + + std::deque chainIds_ = {}; + std::deque spanIds_ = {}; + std::deque parentSpanIds_ = {}; + std::deque flags_ = {}; + std::deque args_ = {}; + std::deque argSet_ = {}; +}; + +class Filter : public CacheBase { +public: + size_t AppendNewFilterData(std::string type, std::string name, uint64_t sourceArgSetId); + const std::deque& NameData() const + { + return nameDeque_; + } + const std::deque& TypeData() const + { + return typeDeque_; + } + const std::deque& SourceArgSetIdData() const + { + return sourceArgSetId_; + } + void Clear() override + { + CacheBase::Clear(); + nameDeque_.clear(); + typeDeque_.clear(); + sourceArgSetId_.clear(); + } + +private: + std::deque nameDeque_ = {}; + std::deque typeDeque_ = {}; + std::deque sourceArgSetId_ = {}; +}; + +class Measure : public CacheBase { +public: + size_t AppendMeasureData(uint32_t type, uint64_t timeStamp, int64_t value, uint32_t filterId); + const std::deque& TypeData() const + { + return typeDeque_; + } + const std::deque& ValuesData() const + { + return valuesDeque_; + } + const std::deque& DursData() const + { + return durDeque_; + } + void SetDur(uint32_t row, uint64_t timeStamp); + const std::deque& FilterIdData() const + { + return filterIdDeque_; + } + void Clear() override + { + CacheBase::Clear(); + typeDeque_.clear(); + durDeque_.clear(); + valuesDeque_.clear(); + filterIdDeque_.clear(); + } + +private: + std::deque typeDeque_ = {}; + std::deque durDeque_ = {}; + std::deque valuesDeque_ = {}; + std::deque filterIdDeque_ = {}; +}; + +class Raw : public CacheBase { +public: + size_t AppendRawData(uint32_t id, uint64_t timeStamp, uint32_t name, uint32_t cpu, uint32_t internalTid); + const std::deque& NameData() const + { + return nameDeque_; + } + const std::deque& CpuData() const + { + return cpuDeque_; + } + const std::deque& InternalTidData() const + { + return itidDeque_; + } + void Clear() override + { + CacheBase::Clear(); + nameDeque_.clear(); + cpuDeque_.clear(); + itidDeque_.clear(); + } + +private: + std::deque nameDeque_ = {}; + std::deque cpuDeque_ = {}; + std::deque itidDeque_ = {}; +}; + +class ThreadMeasureFilter { +public: + size_t AppendNewFilter(uint64_t filterId, uint32_t nameIndex, uint64_t internalTid); + size_t Size() const + { + return filterId_.size(); + } + const std::deque& FilterIdData() const + { + return filterId_; + } + const std::deque& InternalTidData() const + { + return internalTids_; + } + const std::deque& NameIndexData() const + { + return nameIndex_; + } + void Clear() + { + filterId_.clear(); + internalTids_.clear(); + nameIndex_.clear(); + } + +private: + std::deque filterId_ = {}; + std::deque internalTids_ = {}; + std::deque nameIndex_ = {}; +}; + +class CpuMeasureFilter : public CacheBase { +public: + inline size_t AppendNewFilter(uint64_t filterId, DataIndex name, uint32_t cpu) + { + ids_.emplace_back(filterId); + cpu_.emplace_back(cpu); + name_.emplace_back(name); + return Size() - 1; + } + + const std::deque& CpuData() const + { + return cpu_; + } + + const std::deque& TypeData() const + { + return type_; + } + + const std::deque& NameData() const + { + return name_; + } + void Clear() override + { + CacheBase::Clear(); + cpu_.clear(); + type_.clear(); + name_.clear(); + } + +private: + std::deque cpu_ = {}; + std::deque type_ = {}; + std::deque name_ = {}; +}; + +class Instants : public CacheBase { +public: + size_t AppendInstantEventData(uint64_t timeStamp, + DataIndex nameIndex, + int64_t internalTid, + int64_t wakeupFromInternalPid); + + const std::deque& NameIndexsData() const + { + return NameIndexs_; + } + const std::deque& WakeupFromPidsData() const + { + return wakeupFromInternalPids_; + } + void Clear() override + { + CacheBase::Clear(); + NameIndexs_.clear(); + wakeupFromInternalPids_.clear(); + } + +private: + std::deque NameIndexs_; + std::deque wakeupFromInternalPids_; +}; + +class ProcessMeasureFilter : public CacheBase { +public: + size_t AppendNewFilter(uint64_t id, DataIndex name, uint32_t internalPid); + + const std::deque& UpidsData() const + { + return internalPids_; + } + + const std::deque& NamesData() const + { + return names_; + } + void Clear() override + { + CacheBase::Clear(); + internalPids_.clear(); + names_.clear(); + } + +private: + std::deque internalPids_ = {}; + std::deque names_ = {}; +}; +class ClockEventData : public CacheBase { +public: + size_t AppendNewFilter(uint64_t id, DataIndex type, DataIndex name, uint64_t cpu); + + const std::deque& CpusData() const + { + return cpus_; + } + + const std::deque& NamesData() const + { + return names_; + } + const std::deque& TypesData() const + { + return types_; + } + void Clear() override + { + CacheBase::Clear(); + cpus_.clear(); + names_.clear(); + types_.clear(); + } + +private: + std::deque cpus_ = {}; // in clock_set_rate event, it save cpu + std::deque names_ = {}; + std::deque types_ = {}; +}; +class ClkEventData : public CacheBase { +public: + size_t AppendNewFilter(uint64_t id, uint64_t rate, DataIndex name, uint64_t cpu); + + const std::deque& NamesData() const + { + return names_; + } + const std::deque& RatesData() const + { + return rates_; + } + const std::deque& CpusData() const + { + return cpus_; + } + void Clear() override + { + CacheBase::Clear(); + names_.clear(); + rates_.clear(); + cpus_.clear(); + } + +private: + std::deque names_; + std::deque rates_; + std::deque cpus_; +}; +class SysCall : public CacheBase { +public: + size_t AppendSysCallData(int64_t sysCallNum, DataIndex type, uint32_t ipid, uint64_t timeStamp, int64_t ret); + const std::deque& SysCallsData() const + { + return sysCallNums_; + } + const std::deque& TypesData() const + { + return types_; + } + const std::deque& IpidsData() const + { + return ipids_; + } + const std::deque& RetsData() const + { + return rets_; + } + void Clear() override + { + CacheBase::Clear(); + sysCallNums_.clear(); + types_.clear(); + ipids_.clear(); + rets_.clear(); + } + +private: + std::deque sysCallNums_ = {}; + std::deque types_ = {}; + std::deque ipids_ = {}; + std::deque rets_ = {}; +}; +class ArgSet : public CacheBase { +public: + size_t AppendNewArg(DataIndex nameId, BaseDataType dataType, int64_t value, size_t argSet); + const std::deque& DataTypes() const; + const std::deque& ValuesData() const; + const std::deque& ArgsData() const; + const std::deque& NamesData() const; + + void Clear() override + { + CacheBase::Clear(); + names_.clear(); + dataTypes_.clear(); + values_.clear(); + argset_.clear(); + } + +private: + std::deque names_ = {}; + std::deque dataTypes_ = {}; + std::deque values_ = {}; + std::deque argset_ = {}; +}; +class SysMeasureFilter : public CacheBase { +public: + size_t AppendNewFilter(uint64_t filterId, DataIndex type, DataIndex nameId); + const std::deque& NamesData() const; + const std::deque& TypesData() const; + void Clear() override + { + CacheBase::Clear(); + types_.clear(); + names_.clear(); + } + +private: + std::deque types_ = {}; + std::deque names_ = {}; +}; +class DataType : public CacheBase { +public: + size_t AppendNewDataType(BaseDataType dataType, DataIndex dataDescIndex); + const std::deque& DataTypes() const; + const std::deque& DataDesc() const; + void Clear() override + { + CacheBase::Clear(); + dataTypes_.clear(); + descs_.clear(); + } + +private: + std::deque dataTypes_ = {}; + std::deque descs_ = {}; +}; +class LogInfo : public CacheBase { +public: + size_t AppendNewLogInfo(uint64_t seq, + uint64_t timeStamp, + uint32_t pid, + uint32_t tid, + DataIndex level, + DataIndex tag, + DataIndex context, + uint64_t originTs); + const std::deque& HilogLineSeqs() const; + const std::deque& Pids() const; + const std::deque& Tids() const; + const std::deque& Levels() const; + const std::deque& Tags() const; + const std::deque& Contexts() const; + const std::deque& OriginTimeStamData() const; + void Clear() override + { + CacheBase::Clear(); + hilogLineSeqs_.clear(); + pids_.clear(); + levels_.clear(); + tags_.clear(); + contexts_.clear(); + originTs_.clear(); + } + +private: + std::deque hilogLineSeqs_ = {}; + std::deque pids_ = {}; + std::deque tids_ = {}; + std::deque levels_ = {}; + std::deque tags_ = {}; + std::deque contexts_ = {}; + std::deque originTs_ = {}; +}; + +class NativeHook : public CacheBase { +public: + size_t AppendNewNativeHookData(uint32_t callChainId, + uint32_t ipid, + uint32_t itid, + std::string eventType, + DataIndex subType, + uint64_t timeStamp, + uint64_t endTimeStamp, + uint64_t duration, + uint64_t addr, + int64_t memSize); + void UpdateCallChainId(size_t row, uint32_t callChainId); + void UpdateEndTimeStampAndDuration(size_t row, uint64_t endTimeStamp); + void UpdateCurrentSizeDur(size_t row, uint64_t timeStamp); + void UpdateMemMapSubType(); + void UpdateAddrToMemMapSubType(uint64_t addr, uint64_t tagId); + void UpdateLastCallerPathIndexs(std::unordered_map& callIdToLasLibId); + const std::deque& CallChainIds() const; + const std::deque& Ipids() const; + const std::deque& Itids() const; + const std::deque& EventTypes() const; + const std::deque& SubTypes() const; + const std::deque& EndTimeStamps() const; + const std::deque& Durations() const; + const std::deque& Addrs() const; + const std::deque& MemSizes() const; + const std::deque& AllMemSizes() const; + const std::deque& CurrentSizeDurs() const; + const std::deque& LastCallerPathIndexs() const; + void Clear() override + { + CacheBase::Clear(); + callChainIds_.clear(); + ipids_.clear(); + itids_.clear(); + eventTypes_.clear(); + subTypes_.clear(); + endTimeStamps_.clear(); + durations_.clear(); + addrs_.clear(); + memSizes_.clear(); + allMemSizes_.clear(); + currentSizeDurs_.clear(); + lastCallerPathIndexs_.clear(); + } + +private: + std::deque callChainIds_ = {}; + std::deque ipids_ = {}; + std::deque itids_ = {}; + std::deque eventTypes_ = {}; + std::deque subTypes_ = {}; + std::deque endTimeStamps_ = {}; + std::deque durations_ = {}; + std::deque addrs_ = {}; + std::deque memSizes_ = {}; + std::deque allMemSizes_ = {}; + std::deque currentSizeDurs_ = {}; + std::deque lastCallerPathIndexs_ = {}; + std::unordered_map addrToMmapTag_ = {}; + int64_t countHeapSizes_ = 0; + int64_t countMmapSizes_ = 0; + const std::string ALLOC_EVET = "AllocEvent"; + const std::string FREE_EVENT = "FreeEvent"; + const std::string MMAP_EVENT = "MmapEvent"; + const std::string MUNMAP_EVENT = "MunmapEvent"; +}; + +class NativeHookFrame { +public: + size_t AppendNewNativeHookFrame(uint32_t callChainId, + uint64_t depth, + uint64_t ip, + uint64_t sp, + DataIndex symbolName, + DataIndex filePath, + uint64_t offset, + uint64_t symbolOffset); + size_t AppendNewNativeHookFrame(uint32_t callChainId, + uint64_t depth, + uint64_t ip, + uint64_t sp, + DataIndex symbolName, + DataIndex filePath, + uint64_t offset, + uint64_t symbolOffset, + const std::string& vaddr); + void UpdateFrameInfo(size_t row, + DataIndex symbolIndex, + DataIndex filePathIndex, + uint64_t offset, + uint64_t symbolOffset); + void UpdateSymbolIdToNameMap(uint64_t originSymbolId, uint64_t symbolId); + void UpdateSymbolId(); + void UpdateSymbolId(size_t index, DataIndex symbolId); + void UpdateFileId(std::map& filePathIdToFilePathName); + void UpdateVaddrs(std::deque& vaddrs); + const std::deque& CallChainIds() const; + const std::deque& Depths() const; + const std::deque& Ips() const; + const std::deque& Sps() const; + const std::deque& SymbolNames() const; + const std::deque& FilePaths() const; + const std::deque& Offsets() const; + const std::deque& SymbolOffsets() const; + const std::deque& Vaddrs() const; + size_t Size() const + { + return callChainIds_.size(); + } + void Clear() + { + callChainIds_.clear(); + depths_.clear(); + ips_.clear(); + sps_.clear(); + symbolNames_.clear(); + filePaths_.clear(); + offsets_.clear(); + symbolOffsets_.clear(); + vaddrs_.clear(); + } + +private: + std::deque callChainIds_ = {}; + std::deque depths_ = {}; + std::deque ips_ = {}; + std::deque sps_ = {}; + std::deque symbolNames_ = {}; + std::deque filePaths_ = {}; + std::deque offsets_ = {}; + std::deque symbolOffsets_ = {}; + std::deque vaddrs_ = {}; + std::map symbolIdToSymbolName_ = {}; + DataIndex libcFilePathIndex_ = INVALID_UINT64; + DataIndex muslFilePathIndex_ = INVALID_UINT64; +}; + +class NativeHookStatistic : public CacheBase { +public: + size_t AppendNewNativeHookStatistic(uint32_t ipid, + uint64_t timeStamp, + uint32_t callChainId, + uint32_t memoryType, + uint64_t applyCount, + uint64_t releaseCount, + uint64_t applySize, + uint64_t releaseSize); + + const std::deque& Ipids() const; + const std::deque& CallChainIds() const; + const std::deque& MemoryTypes() const; + const std::deque& ApplyCounts() const; + const std::deque& ReleaseCounts() const; + const std::deque& ApplySizes() const; + const std::deque& ReleaseSizes() const; + void Clear() override + { + CacheBase::Clear(); + ids_.clear(); + ipids_.clear(); + callChainIds_.clear(); + timeStamps_.clear(); + memoryTypes_.clear(); + applyCounts_.clear(); + releaseCounts_.clear(); + applySizes_.clear(); + releaseSizes_.clear(); + } + +private: + std::deque ipids_ = {}; + std::deque callChainIds_ = {}; + std::deque memoryTypes_ = {}; + std::deque applyCounts_ = {}; + std::deque releaseCounts_ = {}; + std::deque applySizes_ = {}; + std::deque releaseSizes_ = {}; +}; + +class Hidump : public CacheBase { +public: + size_t AppendNewHidumpInfo(uint64_t timeStamp, uint32_t fps); + const std::deque& Fpss() const; + +private: + std::deque fpss_ = {}; +}; + +class PerfCallChain : public CacheBase { +public: + size_t AppendNewPerfCallChain(uint64_t sampleId, + uint32_t callChainId, + uint64_t vaddrInFile, + uint64_t fileId, + uint64_t symbolId); + const std::deque& SampleIds() const; + const std::deque& CallChainIds() const; + const std::deque& VaddrInFiles() const; + const std::deque& FileIds() const; + const std::deque& SymbolIds() const; + const std::deque& Names() const; + void SetName(uint64_t index, const std::string& name); + void Clear() override; + +private: + std::deque sampleIds_ = {}; + std::deque callChainIds_ = {}; + std::deque vaddrInFiles_ = {}; + std::deque fileIds_ = {}; + std::deque symbolIds_ = {}; + std::deque names_ = {}; +}; + +class PerfFiles : public CacheBase { +public: + size_t AppendNewPerfFiles(uint64_t fileIds, uint32_t serial, DataIndex symbols, DataIndex filePath); + const std::deque& FileIds() const; + const std::deque& Symbols() const; + const std::deque& FilePaths() const; + const std::deque& Serials() const; + void Clear() override; + +private: + std::deque fileIds_ = {}; + std::deque serials_ = {}; + std::deque symbols_ = {}; + std::deque filePaths_ = {}; +}; + +class PerfSample : public CacheBase { +public: + size_t AppendNewPerfSample(uint32_t sampleId, + uint64_t timeStamp, + uint32_t tid, + uint64_t eventCount, + uint64_t eventTypeId, + uint64_t timestampTrace, + uint64_t cpuId, + uint64_t threadState); + const std::deque& SampleIds() const; + const std::deque& Tids() const; + const std::deque& EventCounts() const; + const std::deque& EventTypeIds() const; + const std::deque& TimestampTraces() const; + const std::deque& CpuIds() const; + const std::deque& ThreadStates() const; + void Clear() override; + +private: + std::deque sampleIds_ = {}; + std::deque tids_ = {}; + std::deque eventCounts_ = {}; + std::deque eventTypeIds_ = {}; + std::deque timestampTraces_ = {}; + std::deque cpuIds_ = {}; + std::deque threadStates_ = {}; +}; + +class PerfThread : public CacheBase { +public: + size_t AppendNewPerfThread(uint32_t pid, uint32_t tid, DataIndex threadName); + const std::deque& Pids() const; + const std::deque& Tids() const; + const std::deque& ThreadNames() const; + void Clear() override; + +private: + std::deque tids_ = {}; + std::deque pids_ = {}; + std::deque threadNames_ = {}; +}; + +class PerfReport : public CacheBase { +public: + size_t AppendNewPerfReport(DataIndex type, DataIndex value); + const std::deque& Types() const; + const std::deque& Values() const; + +private: + std::deque types_ = {}; + std::deque values_ = {}; +}; +class StatAndInfo { +public: + StatAndInfo(); + ~StatAndInfo() = default; + void IncreaseStat(SupportedTraceEventType eventType, StatType type); + const uint32_t& GetValue(SupportedTraceEventType eventType, StatType type) const; + const std::string& GetEvent(SupportedTraceEventType eventType) const; + const std::string& GetStat(StatType type) const; + const std::string& GetSeverityDesc(SupportedTraceEventType eventType, StatType type) const; + const StatSeverityLevel& GetSeverity(SupportedTraceEventType eventType, StatType type) const; + std::map clockid2ClockNameMap_ = {}; + +private: + uint32_t statCount_[TRACE_EVENT_MAX][STAT_EVENT_MAX]; + std::string event_[TRACE_EVENT_MAX]; + std::string stat_[STAT_EVENT_MAX]; + std::string statSeverityDesc_[TRACE_EVENT_MAX][STAT_EVENT_MAX]; + StatSeverityLevel statSeverity_[TRACE_EVENT_MAX][STAT_EVENT_MAX]; + TraceStreamerConfig config_{}; +}; +class SymbolsData { +public: + SymbolsData() = default; + ~SymbolsData() = default; + uint64_t Size() const; + void InsertSymbol(const DataIndex& name, const uint64_t& addr); + const std::deque& GetConstFuncNames() const; + const std::deque& GetConstAddrs() const; + void Clear() + { + addrs_.clear(); + funcName_.clear(); + } + +private: + std::deque addrs_ = {}; + std::deque funcName_ = {}; +}; +class DiskIOData : public CacheBase { +public: + DiskIOData() = default; + ~DiskIOData() = default; + void AppendNewData(uint64_t ts, + uint64_t dur, + uint64_t rd, + uint64_t wr, + uint64_t rdPerSec, + uint64_t wrPerSec, + double rdCountPerSec, + double wrCountPerSec, + uint64_t rdCount, + uint64_t wrCount); + const std::deque& Durs() const; + const std::deque& RdDatas() const; + const std::deque& WrDatas() const; + const std::deque& RdSpeedDatas() const; + const std::deque& WrSpeedDatas() const; + const std::deque& RdCountPerSecDatas() const; + const std::deque& WrCountPerSecDatas() const; + const std::deque& RdCountDatas() const; + const std::deque& WrCountDatas() const; + +private: + std::deque durs_ = {}; + std::deque rdDatas_ = {}; + std::deque wrDatas_ = {}; + std::deque wrPerSec_ = {}; + std::deque rdPerSec_ = {}; + std::deque wrCountPerSec_ = {}; + std::deque rdCountPerSec_ = {}; + std::deque rdCountDatas_ = {}; + std::deque wrCountDatas_ = {}; +}; +class MetaData { +public: + MetaData(); + ~MetaData() = default; + void SetTraceType(const std::string& traceType); + void SetSourceFileName(const std::string& fileName); + void SetOutputFileName(const std::string& fileName); + void SetParserToolVersion(const std::string& version); + void SetParserToolPublishDateTime(const std::string& datetime); + void SetTraceDataSize(uint64_t dataSize); + void SetTraceDuration(uint64_t dur); + const std::string& Value(uint64_t row) const; + const std::string& Name(uint64_t row) const; + void Clear() + { + columnNames_.clear(); + values_.clear(); + } + +private: + const std::string METADATA_ITEM_DATASIZE_COLNAME = "datasize"; + const std::string METADATA_ITEM_PARSETOOL_NAME_COLNAME = "parse_tool"; + const std::string METADATA_ITEM_PARSERTOOL_VERSION_COLNAME = "tool_version"; + const std::string METADATA_ITEM_PARSERTOOL_PUBLISH_DATETIME_COLNAME = "tool_publish_time"; + const std::string METADATA_ITEM_SOURCE_FILENAME_COLNAME = "source_name"; + const std::string METADATA_ITEM_OUTPUT_FILENAME_COLNAME = "output_name"; + const std::string METADATA_ITEM_PARSERTIME_COLNAME = "runtime"; + const std::string METADATA_ITEM_TRACE_DURATION_COLNAME = "trace_duration"; + const std::string METADATA_ITEM_SOURCE_DATETYPE_COLNAME = "source_type"; + + std::deque columnNames_ = {}; + std::deque values_ = {}; +}; +class DataDict { +public: + size_t Size() const + { + return dataDict_.size(); + } + DataIndex GetStringIndex(std::string_view str); + DataIndex GetStringIndexNoWrite(std::string_view str) const; + const std::string& GetDataFromDict(DataIndex id) const + { + TS_ASSERT(id < dataDict_.size()); + return dataDict_[id]; + } + void Finish(); + void Clear() + { + dataDict_.clear(); + } + +public: + std::deque dataDict_; + std::unordered_map dataDictInnerMap_; + +private: + std::hash hashFun; + std::mutex mutex_; + const int8_t SPASCII_START = 0; + const int8_t SPASCII_END = 32; +}; +class NetDetailData : public CacheBase { +public: + size_t AppendNewNetData(uint64_t newTimeStamp, + uint64_t tx, + uint64_t rx, + uint64_t dur, + double rxSpeed, + double txSpeed, + uint64_t packetIn, + double packetInSec, + uint64_t packetOut, + double packetOutSec, + const std::string& netType); + const std::deque& Durs() const; + const std::deque& RxSpeed() const; + const std::deque& TxSpeed() const; + const std::deque& NetTypes() const; + const std::deque& RxDatas() const; + const std::deque& TxDatas() const; + const std::deque& PacketIn() const; + const std::deque& PacketInSec() const; + const std::deque& PacketOut() const; + const std::deque& PacketOutSec() const; + void Clear() override + { + CacheBase::Clear(); + durs_.clear(); + rxSpeeds_.clear(); + txSpeeds_.clear(); + netTypes_.clear(); + packetIn_.clear(); + packetInSec_.clear(); + packetOut_.clear(); + packetOutSec_.clear(); + } + +private: + std::deque rxs_ = {}; + std::deque txs_ = {}; + std::deque durs_ = {}; + std::deque rxSpeeds_ = {}; + std::deque txSpeeds_ = {}; + std::deque packetIn_ = {}; + std::deque packetInSec_ = {}; + std::deque packetOut_ = {}; + std::deque packetOutSec_ = {}; + std::deque netTypes_ = {}; +}; +class LiveProcessDetailData : public CacheBase { +public: + size_t AppendNewData(uint64_t newTimeStamp, + uint64_t dur, + int32_t processID, + std::string processName, + int32_t parentProcessID, + int32_t uid, + std::string userName, + double cpuUsage, + int32_t pssInfo, + uint64_t cpuTime, + int32_t threads, + int64_t diskWrites, + int64_t diskReads); + const std::deque& Durs() const; + const std::deque& ProcessID() const; + const std::deque& ProcessName() const; + const std::deque& ParentProcessID() const; + const std::deque& Uid() const; + const std::deque& UserName() const; + const std::deque& CpuUsage() const; + const std::deque& PssInfo() const; + const std::deque& Threads() const; + const std::deque& DiskWrites() const; + const std::deque& DiskReads() const; + const std::deque& CpuTimes() const; + void Clear() override + { + CacheBase::Clear(); + durs_.clear(); + processID_.clear(); + processName_.clear(); + parentProcessID_.clear(); + uid_.clear(); + userName_.clear(); + cpuUsage_.clear(); + pssInfo_.clear(); + threads_.clear(); + diskWrites_.clear(); + diskReads_.clear(); + } + +private: + std::deque durs_ = {}; + std::deque processID_ = {}; + std::deque processName_ = {}; + std::deque parentProcessID_ = {}; + std::deque uid_ = {}; + std::deque userName_ = {}; + std::deque cpuUsage_ = {}; + std::deque pssInfo_ = {}; + std::deque threads_ = {}; + std::deque diskWrites_ = {}; + std::deque diskReads_ = {}; + std::deque cpuTimes_ = {}; +}; +class CpuUsageDetailData : public CacheBase { +public: + size_t AppendNewData(uint64_t newTimeStamp, + uint64_t dur, + double totalLoad, + double userLoad, + double systemLoad, + int64_t threads); + const std::deque& Durs() const; + const std::deque& TotalLoad() const; + const std::deque& UserLoad() const; + const std::deque& SystemLoad() const; + const std::deque& Threads() const; + void Clear() override + { + CacheBase::Clear(); + durs_.clear(); + totalLoad_.clear(); + userLoad_.clear(); + systemLoad_.clear(); + threads_.clear(); + } + +private: + std::deque durs_ = {}; + std::deque totalLoad_ = {}; + std::deque userLoad_ = {}; + std::deque systemLoad_ = {}; + std::deque threads_ = {}; +}; +class FileSystemSample : public CacheBase { +public: + size_t AppendNewData(uint32_t callChainId, + uint16_t type, + uint32_t ipid, + uint32_t itid, + uint64_t startTs, + uint64_t endTs, + uint64_t dur, + DataIndex returnValue, + DataIndex errorCode, + size_t size, + int32_t fd, + DataIndex fileId, + DataIndex firstArgument, + DataIndex secondArgument, + DataIndex thirdArgument, + DataIndex fourthArgument); + const std::deque& CallChainIds() const; + const std::deque& Types() const; + const std::deque& Ipids() const; + const std::deque& Itids() const; + const std::deque& StartTs() const; + const std::deque& EndTs() const; + const std::deque& Durs() const; + const std::deque& ReturnValues() const; + const std::deque& ErrorCodes() const; + const std::deque& Fds() const; + const std::deque& FileIds() const; + const std::deque& Sizes() const; + const std::deque& FirstArguments() const; + const std::deque& SecondArguments() const; + const std::deque& ThirdArguments() const; + const std::deque& FourthArguments() const; + void Clear() override + { + CacheBase::Clear(); + callChainIds_.clear(); + types_.clear(); + ipids_.clear(); + itids_.clear(); + startTs_.clear(); + endTs_.clear(); + durs_.clear(); + returnValues_.clear(); + errorCodes_.clear(); + fds_.clear(); + Sizes_.clear(); + firstArguments_.clear(); + secondArguments_.clear(); + thirdArguments_.clear(); + fourthArguments_.clear(); + } + +private: + std::deque callChainIds_ = {}; + std::deque types_ = {}; + std::deque ipids_ = {}; + std::deque itids_ = {}; + std::deque startTs_ = {}; + std::deque endTs_ = {}; + std::deque durs_ = {}; + std::deque returnValues_ = {}; + std::deque errorCodes_ = {}; + std::deque fds_ = {}; + std::deque fileIds_ = {}; + std::deque Sizes_ = {}; + std::deque firstArguments_ = {}; + std::deque secondArguments_ = {}; + std::deque thirdArguments_ = {}; + std::deque fourthArguments_ = {}; +}; +class EbpfCallStackData : public CacheBase { +public: + size_t AppendNewData(uint32_t callChainId, uint32_t depth, DataIndex ip, DataIndex symbolId, DataIndex filePathId); + void UpdateSymbolAndFilePathIndex(size_t row, DataIndex symbolId, DataIndex filePathId); + const std::deque& CallChainIds() const; + const std::deque& Depths() const; + const std::deque& Ips() const; + const std::deque& SymbolIds() const; + const std::deque& FilePathIds() const; + void Clear() override + { + CacheBase::Clear(); + callChainIds_.clear(); + depths_.clear(); + symbolIds_.clear(); + filePathIds_.clear(); + } + +private: + std::deque callChainIds_ = {}; + std::deque depths_ = {}; + std::deque ips_ = {}; + std::deque symbolIds_ = {}; + std::deque filePathIds_ = {}; +}; +class PagedMemorySampleData : public CacheBase { +public: + size_t AppendNewData(uint32_t callChainId, + uint16_t type, + uint32_t ipid, + uint64_t startTs, + uint64_t endTs, + uint64_t dur, + size_t size, + DataIndex addr, + uint32_t itid); + const std::deque& CallChainIds() const; + const std::deque& Types() const; + const std::deque& Ipids() const; + const std::deque& StartTs() const; + const std::deque& EndTs() const; + const std::deque& Durs() const; + const std::deque& Sizes() const; + const std::deque& Addr() const; + const std::deque& Itids() const; + void Clear() override + { + CacheBase::Clear(); + callChainIds_.clear(); + types_.clear(); + ipids_.clear(); + startTs_.clear(); + endTs_.clear(); + durs_.clear(); + Sizes_.clear(); + addrs_.clear(); + itids_.clear(); + } + +private: + std::deque callChainIds_ = {}; + std::deque types_ = {}; + std::deque ipids_ = {}; + std::deque startTs_ = {}; + std::deque endTs_ = {}; + std::deque durs_ = {}; + std::deque Sizes_ = {}; + std::deque addrs_ = {}; + std::deque itids_ = {}; +}; +#if WITH_EBPF_HELP +class EbpfProcessMaps : public CacheBase { +public: + size_t AppendNewData(uint64_t start, + uint64_t end, + uint32_t offset, + uint32_t pid, + uint32_t fileNameLen, + uint64_t fileNameIndex); + const std::deque& Starts() const; + const std::deque& Ends() const; + const std::deque& Offsets() const; + const std::deque& Pids() const; + const std::deque& FileNameLens() const; + const std::deque& FileNameIndexs() const; + void Clear() override + { + CacheBase::Clear(); + starts_.clear(); + ends_.clear(); + offsets_.clear(); + pids_.clear(); + fileNameLens_.clear(); + fileNameIndexs_.clear(); + } + +private: + std::deque starts_ = {}; + std::deque ends_ = {}; + std::deque offsets_ = {}; + std::deque pids_ = {}; + std::deque fileNameLens_ = {}; + std::deque fileNameIndexs_ = {}; +}; + +class EbpfElf : public CacheBase { +public: + size_t AppendNewData(uint64_t elfId, + uint64_t textVaddr, + uint32_t textOffset, + uint32_t strTabLen, + uint32_t symTabLen, + uint32_t fileNameLen, + uint32_t symEntLen, + uint64_t fileNameIndex); + const std::deque& ElfIds() const; + const std::deque& TextVaddrs() const; + const std::deque& TextOffsets() const; + const std::deque& StrTabLens() const; + const std::deque& SymTabLens() const; + const std::deque& FileNameLens() const; + const std::deque& SymEntLens() const; + const std::deque& FileNameIndexs() const; + + void Clear() override + { + CacheBase::Clear(); + elfIds_.clear(); + textVaddrs_.clear(); + textOffsets_.clear(); + strTabLens_.clear(); + symTabLens_.clear(); + fileNameLens_.clear(); + symEntLens_.clear(); + fileNameIndexs_.clear(); + } + +private: + std::deque elfIds_ = {}; + std::deque textVaddrs_ = {}; + std::deque textOffsets_ = {}; + std::deque strTabLens_ = {}; + std::deque symTabLens_ = {}; + std::deque fileNameLens_ = {}; + std::deque symEntLens_ = {}; + std::deque fileNameIndexs_ = {}; +}; + +class EbpfElfSymbol : public CacheBase { +public: + size_t AppendNewData(uint64_t elfId, uint32_t stName, uint64_t stValue, uint64_t stSize); + const std::deque& ElfIds() const; + const std::deque& StNames() const; + const std::deque& StValues() const; + const std::deque& StSizes() const; + + void Clear() override + { + CacheBase::Clear(); + elfIds_.clear(); + stNames_.clear(); + stValues_.clear(); + stSizes_.clear(); + } + +private: + std::deque elfIds_ = {}; + std::deque stNames_ = {}; + std::deque stValues_ = {}; + std::deque stSizes_ = {}; +}; +#endif +class AppNames : public CacheBase { +public: + uint32_t AppendAppName(uint8_t flags, DataIndex eventSource, DataIndex appName); + const std::deque& Falgs() const; + const std::deque& EventSourceId() const; + const std::deque& AppName() const; + void Clear() override + { + CacheBase::Clear(); + flags_.clear(); + appNames_.clear(); + keyNames_.clear(); + } + +private: + std::deque flags_ = {}; + std::deque appNames_ = {}; + std::deque keyNames_ = {}; + uint32_t rowCount_ = 0; +}; +class SysEventMeasureData : public CacheBase { +public: + void AppendData(uint64_t serial, + uint64_t ts, + uint32_t nameId, + uint32_t keyId, + int32_t type, + double numericValue, + DataIndex stringValue); + const std::deque& Serial() const; + const std::deque& Ts() const; + const std::deque& NameFilterId() const; + const std::deque& AppKeyFilterId() const; + const std::deque& Type() const; + const std::deque& NumValue() const; + const std::deque& StringValue() const; + void Clear() override + { + CacheBase::Clear(); + serial_.clear(); + ts_.clear(); + nameFilterIds_.clear(); + appKeyFilterIds_.clear(); + types_.clear(); + numValues_.clear(); + stringValues_.clear(); + } + +private: + std::deque serial_ = {}; + std::deque ts_ = {}; + std::deque nameFilterIds_ = {}; + std::deque appKeyFilterIds_ = {}; + std::deque types_ = {}; + std::deque numValues_ = {}; + std::deque stringValues_ = {}; + uint32_t rowCount_ = 0; +}; +class DeviceStateData : public CacheBase { +public: + void AppendNewData(int32_t brightness, + int32_t btState, + int32_t location, + int32_t wifi, + int32_t streamDefault, + int32_t voiceCall, + int32_t music, + int32_t streamRing, + int32_t media, + int32_t voiceAssistant, + int32_t system, + int32_t alarm, + int32_t notification, + int32_t btSco, + int32_t enforcedAudible, + int32_t streamDtmf, + int32_t streamTts, + int32_t accessibility, + int32_t recording, + int32_t streamAll); + const std::deque& Brightness() const; + const std::deque& BtState() const; + const std::deque& Location() const; + const std::deque& Wifi() const; + const std::deque& StreamDefault() const; + const std::deque& VoiceCall() const; + const std::deque& Music() const; + const std::deque& StreamRing() const; + const std::deque& Media() const; + const std::deque& VoiceAssistant() const; + const std::deque& System() const; + const std::deque& Alarm() const; + const std::deque& Notification() const; + const std::deque& BtSco() const; + const std::deque& EnforcedAudible() const; + const std::deque& StreamDtmf() const; + const std::deque& StreamTts() const; + const std::deque& Accessibility() const; + const std::deque& Recording() const; + const std::deque& StreamAll() const; + void Clear() override + { + CacheBase::Clear(); + brightness_.clear(); + btStates_.clear(); + locations_.clear(); + wifis_.clear(); + streamDefaults_.clear(); + voiceCalls_.clear(); + musics_.clear(); + streamRings_.clear(); + medias_.clear(); + voiceAssistants_.clear(); + systems_.clear(); + alarms_.clear(); + notifications_.clear(); + btScos_.clear(); + enforcedAudibles_.clear(); + streamDtmfs_.clear(); + streamTts_.clear(); + accessibilitys_.clear(); + recordings_.clear(); + streamAlls_.clear(); + } + +private: + std::deque stringValues_ = {}; + std::deque brightness_ = {}; + std::deque btStates_ = {}; + std::deque locations_ = {}; + std::deque wifis_ = {}; + std::deque streamDefaults_ = {}; + std::deque voiceCalls_ = {}; + std::deque musics_ = {}; + std::deque streamRings_ = {}; + std::deque medias_ = {}; + std::deque voiceAssistants_ = {}; + std::deque systems_ = {}; + std::deque alarms_ = {}; + std::deque notifications_ = {}; + std::deque btScos_ = {}; + std::deque enforcedAudibles_ = {}; + std::deque streamDtmfs_ = {}; + std::deque streamTts_ = {}; + std::deque accessibilitys_ = {}; + std::deque recordings_ = {}; + std::deque streamAlls_ = {}; + uint32_t rowCounts_ = 0; +}; +class TraceConfigData : public CacheBase { +public: + void AppendNewData(std::string traceSource, std::string key, std::string value); + const std::deque& TraceSource() const; + const std::deque& Key() const; + const std::deque& Value() const; + void Clear() override + { + CacheBase::Clear(); + traceSource_.clear(); + key_.clear(); + value_.clear(); + } + +private: + std::deque traceSource_ = {}; + std::deque key_ = {}; + std::deque value_ = {}; + uint32_t rowCounts_ = 0; +}; +class SmapsData : public CacheBase { +public: + void AppendNewData(uint64_t timeStamp, + std::string startAddr, + std::string endAddr, + uint64_t dirty, + uint64_t swapper, + uint64_t rss, + uint64_t pss, + uint64_t size, + double reside, + DataIndex protectionId, + DataIndex pathId); + const std::deque& Id() const; + const std::deque& TimeStamps() const; + const std::deque& StartAddrs() const; + const std::deque& EndAddrs() const; + const std::deque& Dirtys() const; + const std::deque& Swappers() const; + const std::deque& Rss() const; + const std::deque& Pss() const; + const std::deque& Sizes() const; + const std::deque& Resides() const; + const std::deque& ProtectionIds() const; + const std::deque& PathIds() const; + void Clear() override + { + CacheBase::Clear(); + startAddrs_.clear(); + endAddrs_.clear(); + dirtys_.clear(); + swappers_.clear(); + rss_.clear(); + pss_.clear(); + sizes_.clear(); + resides_.clear(); + protectionIds_.clear(); + pathIds_.clear(); + } + +private: + std::deque startAddrs_ = {}; + std::deque endAddrs_ = {}; + std::deque dirtys_ = {}; + std::deque swappers_ = {}; + std::deque rss_ = {}; + std::deque pss_ = {}; + std::deque sizes_ = {}; + std::deque resides_ = {}; + std::deque protectionIds_ = {}; + std::deque pathIds_ = {}; + uint32_t rowCount_ = 0; +}; +class BioLatencySampleData : public CacheBase { +public: + void AppendNewData(uint32_t callChainId, + uint64_t type, + uint32_t ipid, + uint32_t itid, + uint64_t startTs, + uint64_t endTs, + uint64_t latencyDur, + uint32_t tier, + uint64_t size, + uint64_t blockNumber, + uint64_t filePathId, + uint64_t durPer4k); + const std::deque& Id() const; + const std::deque& CallChainIds() const; + const std::deque& Types() const; + const std::deque& Ipids() const; + const std::deque& Itids() const; + const std::deque& StartTs() const; + const std::deque& EndTs() const; + const std::deque& LatencyDurs() const; + const std::deque& Tiers() const; + const std::deque& Sizes() const; + const std::deque& BlockNumbers() const; + const std::deque& FilePathIds() const; + const std::deque& DurPer4k() const; + void Clear() override + { + CacheBase::Clear(); + callChainIds_.clear(); + types_.clear(); + ipids_.clear(); + itids_.clear(); + startTs_.clear(); + endTs_.clear(); + latencyDurs_.clear(); + tiers_.clear(); + sizes_.clear(); + blockNumbers_.clear(); + filePathIds_.clear(); + durPer4ks_.clear(); + } + +private: + std::deque callChainIds_ = {}; + std::deque types_ = {}; + std::deque ipids_ = {}; + std::deque itids_ = {}; + std::deque startTs_ = {}; + std::deque endTs_ = {}; + std::deque latencyDurs_ = {}; + std::deque tiers_ = {}; + std::deque sizes_ = {}; + std::deque blockNumbers_ = {}; + std::deque filePathIds_ = {}; + std::deque durPer4ks_ = {}; + uint32_t rowCount_ = 0; +}; +class ClockSnapshotData { +public: + size_t AppendNewSnapshot(uint8_t clockId, uint64_t ts, const std::string& name) + { + clockIds_.emplace_back(clockId); + ts_.emplace_back(ts); + names_.emplace_back(name); + return ts_.size(); + } + const size_t Size() const + { + return ts_.size(); + } + const std::deque& ClockIds() const + { + return clockIds_; + } + const std::deque& Ts() const + { + return ts_; + } + const std::deque& Names() const + { + return names_; + } + +private: + std::deque clockIds_ = {}; + std::deque ts_ = {}; + std::deque names_ = {}; +}; +class DataSourceClockIdData { +public: + DataSourceClockIdData(); + size_t AppendNewDataSourceClockId(const std::string& dataSoruceName, uint8_t clockId) + { + dataSourceNames_.emplace_back(dataSoruceName); + clockIds_.emplace_back(clockId); + return dataSourceNames_.size(); + } + const size_t Size() const + { + return dataSourceNames_.size(); + } + const std::deque& ClockIds() const + { + return clockIds_; + } + const std::deque& Names() const + { + return dataSourceNames_; + } + void SetDataSourceClockId(DataSourceType source, uint32_t id); + void Finish(); + +private: + std::deque dataSourceNames_ = {}; + std::deque clockIds_ = {}; + std::map dataSource2ClockIdMap_ = {}; + std::map dataSource2PluginNameMap_ = {}; +}; + +class FrameSlice : public CacheBase { +public: + size_t AppendFrame(uint64_t ts, uint32_t ipid, uint32_t itid, uint32_t vsyncId, uint64_t callStackSliceId); + size_t AppendFrame(uint64_t ts, + uint32_t ipid, + uint32_t itid, + uint32_t vsyncId, + uint64_t callStackSliceId, + uint64_t end, + uint8_t type); + void SetEndTime(uint64_t row, uint64_t end); + void SetType(uint64_t row, uint8_t type); + void SetDst(uint64_t row, uint64_t dst); + void SetSrcs(uint64_t row, const std::vector& fromSlices); + const std::deque Ipids() const; + const std::deque VsyncIds() const; + const std::deque CallStackIds() const; + const std::deque EndTss() const; + const std::deque Dsts() const; + const std::deque Durs() const; + const std::deque Types() const; + const std::deque Flags() const; + const std::deque Depths() const; + const std::deque FrameNos() const; + const std::deque& Srcs() const; + void UpdateCallStackSliceId(uint64_t row, uint64_t callStackSliceId); + void SetEndTimeAndFlag(uint64_t row, uint64_t ts, uint64_t expectDur, uint64_t expectEnd); + void Erase(uint64_t row); + +private: + std::deque ipids_ = {}; + std::deque dsts_ = {}; + std::deque srcs_ = {}; + std::deque vsyncIds_ = {}; + std::deque callStackIds_ = {}; + std::deque endTss_ = {}; + std::deque durs_ = {}; + std::deque types_ = {}; + std::deque flags_ = {}; + std::deque depths_ = {}; + std::deque frameNos_ = {}; + const uint32_t INVALID_ROW = 2; +}; +class FrameMaps : public CacheBase { +public: + size_t AppendNew(uint64_t src, uint64_t dst); + const std::deque& SrcIndexs() const; + const std::deque& DstIndexs() const; + +private: + std::deque srcs_ = {}; + std::deque dsts_ = {}; +}; + +class JsHeapFiles : public CacheBase { +public: + size_t AppendNewData(uint32_t id, std::string filePath, uint64_t startTime, uint64_t endTime, uint32_t ipid); + const std::deque& IDs() const; + const std::deque& FilePaths() const; + const std::deque& StartTimes() const; + const std::deque& EndTimes() const; + const std::deque& Pids() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + filePaths_.clear(); + startTimes_.clear(); + endTimes_.clear(); + ipids_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque filePaths_ = {}; + std::deque startTimes_ = {}; + std::deque endTimes_ = {}; + std::deque ipids_ = {}; +}; + +class JsHeapEdges : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, + uint32_t edgeIndex, + uint32_t type, + uint32_t nameOrIndex, + uint32_t toNode, + uint32_t fromNodeId, + uint32_t toNodeId); + const std::deque& FileIds() const; + const std::deque& EdgeIndexs() const; + const std::deque& Types() const; + const std::deque& NameOrIndexs() const; + const std::deque& ToNodes() const; + const std::deque& FromNodeIds() const; + const std::deque& ToNodeIds() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + edgeIndexs_.clear(); + types_.clear(); + nameOrIndexs_.clear(); + toNodes_.clear(); + fromNodeIds_.clear(); + toNodeIds_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque edgeIndexs_ = {}; + std::deque types_ = {}; + std::deque nameOrIndexs_ = {}; + std::deque toNodes_ = {}; + std::deque fromNodeIds_ = {}; + std::deque toNodeIds_ = {}; +}; + +class JsHeapInfo : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, std::string key, uint32_t type, int32_t intValue, std::string strValue); + const std::deque& FileIds() const; + const std::deque& Keys() const; + const std::deque& Types() const; + const std::deque& IntValues() const; + const std::deque& StrValues() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + keys_.clear(); + types_.clear(); + intValues_.clear(); + strValues_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque keys_ = {}; + std::deque types_ = {}; + std::deque intValues_ = {}; + std::deque strValues_ = {}; +}; + +class JsHeapLocation : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, uint32_t objectIndex, uint32_t scriptId, uint32_t line, uint32_t column); + const std::deque& FileIds() const; + const std::deque& ObjectIndexs() const; + const std::deque& ScriptIds() const; + const std::deque& Lines() const; + const std::deque& Columns() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + objectIndexs_.clear(); + scriptIds_.clear(); + lines_.clear(); + columns_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque objectIndexs_ = {}; + std::deque scriptIds_ = {}; + std::deque lines_ = {}; + std::deque columns_ = {}; +}; + +class JsHeapNodes : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, + uint32_t nodeIndex, + uint32_t type, + uint32_t name, + uint32_t id, + uint32_t selfSize, + uint32_t edgeCount, + uint32_t traceNodeId, + uint32_t detachedNess); + const std::deque& FileIds() const; + const std::deque& NodeIndexs() const; + const std::deque& Types() const; + const std::deque& Names() const; + const std::deque& NodeIds() const; + const std::deque& SelfSizes() const; + const std::deque& EdgeCounts() const; + const std::deque& TraceNodeIds() const; + const std::deque& DetachedNess() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + nodeIndexs_.clear(); + types_.clear(); + names_.clear(); + nodeIds_.clear(); + selfSizes_.clear(); + edgeCounts_.clear(); + traceNodeIds_.clear(); + detachedNess_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque nodeIndexs_ = {}; + std::deque types_ = {}; + std::deque names_ = {}; + std::deque nodeIds_ = {}; + std::deque selfSizes_ = {}; + std::deque edgeCounts_ = {}; + std::deque traceNodeIds_ = {}; + std::deque detachedNess_ = {}; +}; + +class JsHeapSample : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, uint64_t timeStampUs, uint32_t lastAssignedId); + const std::deque& FileIds() const; + const std::deque& TimeStampUs() const; + const std::deque& LastAssignedIds() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + timeStampUs_.clear(); + lastAssignedIds_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque timeStampUs_ = {}; + std::deque lastAssignedIds_ = {}; +}; + +class JsHeapString : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, uint32_t fileIndex, std::string string); + const std::deque& FileIds() const; + const std::deque& FileIndexs() const; + const std::deque& Strings() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + fileIndexs_.clear(); + strings_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque fileIndexs_ = {}; + std::deque strings_ = {}; +}; + +class JsHeapTraceFuncInfo : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, + uint32_t functionIndex, + uint32_t functionId, + uint32_t name, + uint32_t scriptName, + uint32_t scriptId, + uint32_t line, + uint32_t column); + const std::deque& FileIds() const; + const std::deque& FunctionIndexs() const; + const std::deque& FunctionIds() const; + const std::deque& Names() const; + const std::deque& ScriptNames() const; + const std::deque& ScriptIds() const; + const std::deque& Lines() const; + const std::deque& Columns() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + functionIndexs_.clear(); + functionIds_.clear(); + names_.clear(); + scriptNames_.clear(); + scriptIds_.clear(); + lines_.clear(); + columns_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque functionIndexs_ = {}; + std::deque functionIds_ = {}; + std::deque names_ = {}; + std::deque scriptNames_ = {}; + std::deque scriptIds_ = {}; + std::deque lines_ = {}; + std::deque columns_ = {}; +}; + +class JsHeapTraceNode : public CacheBase { +public: + size_t AppendNewData(uint32_t fileId, + uint32_t traceNodeId, + uint32_t functionInfoIndex, + uint32_t count, + uint32_t size, + int32_t parentId); + const std::deque& FileIds() const; + const std::deque& TraceNodeIDs() const; + const std::deque& FunctionInfoIndexs() const; + const std::deque& Counts() const; + const std::deque& NodeSizes() const; + const std::deque& ParentIds() const; + void Clear() override + { + CacheBase::Clear(); + fileIds_.clear(); + traceNodeIds_.clear(); + functionInfoIndexs_.clear(); + counts_.clear(); + sizes_.clear(); + parentIds_.clear(); + } + +private: + std::deque fileIds_ = {}; + std::deque traceNodeIds_ = {}; + std::deque functionInfoIndexs_ = {}; + std::deque counts_ = {}; + std::deque sizes_ = {}; + std::deque parentIds_ = {}; +}; + +class GPUSlice { +public: + size_t AppendNew(uint32_t frameRow, uint64_t dur); + const std::deque& FrameRows() const; + const std::deque& Durs() const; + const size_t Size() const; + +private: + std::deque frameRows_ = {}; + std::deque durs_ = {}; +}; +} // namespace TraceStdtype +} // namespace SysTuning + +#endif // TRACE_STDTYPE_H diff --git a/trace_streamer/src/trace_streamer/trace_streamer_filters.cpp b/trace_streamer/src/trace_streamer/trace_streamer_filters.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2d1a16dd3c3bb701181ba4a5e577c543000a4d5 --- /dev/null +++ b/trace_streamer/src/trace_streamer/trace_streamer_filters.cpp @@ -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. + */ + +#include "trace_streamer_filters.h" +#include "args_filter.h" +#include "binder_filter.h" +#include "clock_filter.h" +#include "cpu_filter.h" +#include "filter_filter.h" +#include "frame_filter.h" +#include "hi_sysevent_measure_filter.h" +#include "irq_filter.h" +#include "measure_filter.h" +#include "perf_data_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "symbols_filter.h" +#include "system_event_measure_filter.h" + +namespace SysTuning { +namespace TraceStreamer { +TraceStreamerFilters::TraceStreamerFilters() = default; +TraceStreamerFilters::~TraceStreamerFilters() = default; +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_streamer/trace_streamer_filters.h b/trace_streamer/src/trace_streamer/trace_streamer_filters.h new file mode 100644 index 0000000000000000000000000000000000000000..cf07cc953443ffaed369141b64e4af61c3fca042 --- /dev/null +++ b/trace_streamer/src/trace_streamer/trace_streamer_filters.h @@ -0,0 +1,76 @@ +/* + * 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 TRACE_STREAMERTOKEN_H +#define TRACE_STREAMERTOKEN_H + +#include +namespace SysTuning { +namespace TraceStreamer { +class SliceFilter; +class ProcessFilter; +class CpuFilter; +class MeasureFilter; +class FilterFilter; +class ClockFilter; +class SymbolsFilter; +class StatFilter; +class BinderFilter; +class ArgsFilter; +class IrqFilter; +class SystemEventMeasureFilter; +class HiSysEventMeasureFilter; +class FrameFilter; +#if WITH_PERF +class PerfDataFilter; +#endif +class TraceStreamerFilters { +public: + TraceStreamerFilters(); + ~TraceStreamerFilters(); + std::unique_ptr clockFilter_; + std::unique_ptr filterFilter_; + std::unique_ptr sliceFilter_; + std::unique_ptr processFilter_; + std::unique_ptr cpuFilter_; + std::unique_ptr cpuMeasureFilter_; + std::unique_ptr threadMeasureFilter_; + std::unique_ptr threadFilter_; + std::unique_ptr processMeasureFilter_; + std::unique_ptr processFilterFilter_; + std::unique_ptr symbolsFilter_; + std::unique_ptr statFilter_; + std::unique_ptr clockRateFilter_; + std::unique_ptr clockEnableFilter_; + std::unique_ptr clockDisableFilter_; + std::unique_ptr clkRateFilter_; + std::unique_ptr clkEnableFilter_; + std::unique_ptr clkDisableFilter_; + std::unique_ptr binderFilter_; + std::unique_ptr argsFilter_; + std::unique_ptr irqFilter_; + std::unique_ptr sysEventMemMeasureFilter_; + std::unique_ptr sysEventVMemMeasureFilter_; + std::unique_ptr sysEventSourceFilter_; + std::unique_ptr hiSysEventMeasureFilter_; + std::unique_ptr frameFilter_; +#if WITH_PERF + std::unique_ptr perfDataFilter_; +#endif +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_STREAMERTOKEN_H diff --git a/trace_streamer/src/trace_streamer/trace_streamer_selector.cpp b/trace_streamer/src/trace_streamer/trace_streamer_selector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29857cc659f16e5e910933aa618796727cb7d11e --- /dev/null +++ b/trace_streamer/src/trace_streamer/trace_streamer_selector.cpp @@ -0,0 +1,290 @@ +/* + * 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 "trace_streamer_selector.h" +#include +#include +#include +#include +#include "args_filter.h" +#include "binder_filter.h" +#include "clock_filter.h" +#include "cpu_filter.h" +#include "file.h" +#include "filter_filter.h" +#include "frame_filter.h" +#include "hi_sysevent_measure_filter.h" +#include "irq_filter.h" +#include "measure_filter.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#ifndef IS_PBDECODER +#include "parser/htrace_pbreader_parser/htrace_parser.h" +#else +#include "parser/htrace_parser/htrace_parser.h" +#endif +#if WITH_PERF +#include "perf_data_filter.h" +#endif +#include "process_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "string_help.h" +#include "symbols_filter.h" +#include "system_event_measure_filter.h" + +using namespace SysTuning::base; +namespace SysTuning { +namespace TraceStreamer { +namespace { +TraceFileType GuessFileType(const uint8_t* data, size_t size) +{ + if (size == 0) { + return TRACE_FILETYPE_UN_KNOW; + } + std::string start(reinterpret_cast(data), std::min(size, 20)); + if (start.find("# tracer") != std::string::npos) { + return TRACE_FILETYPE_BY_TRACE; + } + if (start.find("# TRACE") != std::string::npos) { + return TRACE_FILETYPE_BY_TRACE; + } + if (start.find("# SYSEVENT") != std::string::npos) { + return TRACE_FILETYPE_SYSEVENT; + } + if (start.find("# sysevent") != std::string::npos) { + return TRACE_FILETYPE_SYSEVENT; + } + if ((start.compare(0, std::string("").length(), "") == 0) || + (start.compare(0, std::string("").length(), "") == 0)) { + return TRACE_FILETYPE_BY_TRACE; + } + if (start.compare(0, std::string("\x0a").length(), "\x0a") == 0) { + return TRACE_FILETYPE_UN_KNOW; + } + if (start.compare(0, std::string("OHOSPROF").length(), "OHOSPROF") == 0) { + return TRACE_FILETYPE_H_TRACE; + } + const std::regex bytraceMatcher = std::regex(R"(-(\d+)\s+\(?\s*(\d+|-+)?\)?\s?\[(\d+)\]\s*)" + R"([a-zA-Z0-9.]{0,5}\s+(\d+\.\d+):\s+(\S+):)"); + std::smatch matcheLine; + std::string bytraceMode(reinterpret_cast(data), size); + if (std::regex_search(bytraceMode, matcheLine, bytraceMatcher)) { + return TRACE_FILETYPE_BY_TRACE; + } + return TRACE_FILETYPE_UN_KNOW; +} +} // namespace + +TraceStreamerSelector::TraceStreamerSelector() + : fileType_(TRACE_FILETYPE_UN_KNOW), bytraceParser_(nullptr), htraceParser_(nullptr) +{ + InitFilter(); +} +TraceStreamerSelector::~TraceStreamerSelector() {} + +void TraceStreamerSelector::InitFilter() +{ + streamFilters_ = std::make_unique(); + traceDataCache_ = std::make_unique(); + streamFilters_->cpuFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->sliceFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + + streamFilters_->processFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->clockFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->filterFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + + streamFilters_->threadMeasureFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_THREADMEASURE_FILTER); + streamFilters_->threadFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_THREAD_FILTER); + streamFilters_->cpuMeasureFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CPU_MEASURE_FILTER); + streamFilters_->processMeasureFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_PROCESS_MEASURE_FILTER); + streamFilters_->processFilterFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_PROCESS_FILTER_FILTER); + streamFilters_->symbolsFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->statFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->binderFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->argsFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->irqFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->frameFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + streamFilters_->clockRateFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CLOCK_RATE_FILTER); + streamFilters_->clockEnableFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CLOCK_ENABLE_FILTER); + streamFilters_->clockDisableFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CLOCK_DISABLE_FILTER); + streamFilters_->clkRateFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CLK_RATE_FILTER); + streamFilters_->clkEnableFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CLK_ENABLE_FILTER); + streamFilters_->clkDisableFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_CLK_DISABLE_FILTER); + streamFilters_->sysEventMemMeasureFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get(), E_SYS_MEMORY_FILTER); + streamFilters_->sysEventVMemMeasureFilter_ = std::make_unique( + traceDataCache_.get(), streamFilters_.get(), E_SYS_VIRTUAL_MEMORY_FILTER); +#if WITH_PERF + streamFilters_->perfDataFilter_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); +#endif + streamFilters_->sysEventSourceFilter_ = std::make_unique( + traceDataCache_.get(), streamFilters_.get(), E_SYS_EVENT_SOURCE_FILTER); + streamFilters_->hiSysEventMeasureFilter_ = + std::make_unique(traceDataCache_.get(), streamFilters_.get()); +} + +void TraceStreamerSelector::WaitForParserEnd() +{ + if (fileType_ == TRACE_FILETYPE_H_TRACE) { + htraceParser_->WaitForParserEnd(); + } + if (fileType_ == TRACE_FILETYPE_BY_TRACE) { + bytraceParser_->WaitForParserEnd(); + } + traceDataCache_->UpdateTraceRange(); +} + +MetaData* TraceStreamerSelector::GetMetaData() +{ + return traceDataCache_->GetMetaData(); +} + +void TraceStreamerSelector::SetDataType(TraceFileType type) +{ + fileType_ = type; + if (fileType_ == TRACE_FILETYPE_H_TRACE) { + htraceParser_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + } else if (fileType_ == TRACE_FILETYPE_BY_TRACE) { + bytraceParser_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + } +} +bool TraceStreamerSelector::ParseTraceDataSegment(std::unique_ptr data, size_t size) +{ + if (size == 0) { + return true; + } + if (fileType_ == TRACE_FILETYPE_UN_KNOW) { + fileType_ = GuessFileType(data.get(), size); + if (fileType_ == TRACE_FILETYPE_H_TRACE) { + htraceParser_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); +#ifndef IS_PBDECODER + htraceParser_->EnableFileSeparate(enableFileSeparate_); +#endif + } else if (fileType_ == TRACE_FILETYPE_BY_TRACE || fileType_ == TRACE_FILETYPE_SYSEVENT) { + bytraceParser_ = std::make_unique(traceDataCache_.get(), streamFilters_.get()); + bytraceParser_->EnableBytrace(fileType_ == TRACE_FILETYPE_BY_TRACE); + } + if (fileType_ == TRACE_FILETYPE_UN_KNOW) { + SetAnalysisResult(TRACE_PARSER_FILE_TYPE_ERROR); + TS_LOGI( + "File type is not supported!,\nthe head content is:%s\n ---waring!!!---\n" + "File type is not supported!,\n", + data.get()); + return false; + } + } + if (fileType_ == TRACE_FILETYPE_H_TRACE) { + htraceParser_->ParseTraceDataSegment(std::move(data), size); + } else if (fileType_ == TRACE_FILETYPE_BY_TRACE || fileType_ == TRACE_FILETYPE_SYSEVENT) { + bytraceParser_->ParseTraceDataSegment(std::move(data), size); + } + SetAnalysisResult(TRACE_PARSER_NORMAL); + return true; +} +void TraceStreamerSelector::EnableMetaTable(bool enabled) +{ + traceDataCache_->EnableMetaTable(enabled); +} + +void TraceStreamerSelector::EnableFileSave(bool enabled) +{ + enableFileSeparate_ = enabled; +} + +void TraceStreamerSelector::SetCleanMode(bool cleanMode) +{ + g_cleanMode = true; +} + +int32_t TraceStreamerSelector::ExportDatabase(const std::string& outputName, TraceDataDB::ResultCallBack resultCallBack) +{ + traceDataCache_->UpdateTraceRange(); + return traceDataCache_->ExportDatabase(outputName, resultCallBack); +} + +bool TraceStreamerSelector::ReloadSymbolFiles(std::string& directory, std::vector& symbolsPaths) +{ + if (fileType_ == TRACE_FILETYPE_H_TRACE) { + TS_LOGE("directory is %s", directory.c_str()); + for (auto file : symbolsPaths) { + TS_LOGE("files is %s", file.c_str()); + } +#ifndef IS_PBDECODER + htraceParser_->ReparseSymbolFilesAndResymbolization(directory, symbolsPaths); +#endif + } + return true; +} +void TraceStreamerSelector::Clear() +{ + traceDataCache_->Prepare(); + traceDataCache_->Clear(); +} +std::vector TraceStreamerSelector::SearchData() +{ + return traceDataCache_->SearchData(); +} +int32_t TraceStreamerSelector::OperateDatabase(const std::string& sql) +{ + return traceDataCache_->OperateDatabase(sql); +} +int32_t TraceStreamerSelector::SearchDatabase(const std::string& sql, TraceDataDB::ResultCallBack resultCallBack) +{ + return traceDataCache_->SearchDatabase(sql, resultCallBack); +} +int32_t TraceStreamerSelector::SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen) +{ + return traceDataCache_->SearchDatabase(sql, out, outLen); +} +int32_t TraceStreamerSelector::UpdateTraceRangeTime(uint8_t* data, int32_t len) +{ + std::string traceRangeStr; + memcpy(&traceRangeStr, data, len); + int32_t size = traceRangeStr.size(); + std::vector vTraceRangeStr; + for (int32_t i = 0, pos = 0; i < size; i++) { + pos = traceRangeStr.find(";", i); + if (pos == std::string::npos) { + break; + } + if (pos < size) { + std::string s = traceRangeStr.substr(i, pos - i); + vTraceRangeStr.push_back(s); + i = pos; + } + } + uint64_t minTs = std::stoull(vTraceRangeStr.at(0)); + uint64_t maxTs = std::stoull(vTraceRangeStr.at(1)); + traceDataCache_->UpdateTraceTime(minTs); + traceDataCache_->UpdateTraceTime(maxTs); + return 0; +} +void TraceStreamerSelector::SetCancel(bool cancel) +{ + traceDataCache_->SetCancel(cancel); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/src/trace_streamer/trace_streamer_selector.h b/trace_streamer/src/trace_streamer/trace_streamer_selector.h new file mode 100644 index 0000000000000000000000000000000000000000..40f1deece025cbe57ddcde9fdddff19ddb4655db --- /dev/null +++ b/trace_streamer/src/trace_streamer/trace_streamer_selector.h @@ -0,0 +1,66 @@ +/* + * 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 TRACE_STREAMER_SELECTOR_H +#define TRACE_STREAMER_SELECTOR_H +#include +#include +#include "trace_data/trace_data_cache.h" +#include "trace_streamer_filters.h" + +namespace SysTuning { +namespace TraceStreamer { +class BytraceParser; +class HtraceParser; +class TraceStreamerSelector { +public: + TraceStreamerSelector(); + ~TraceStreamerSelector(); + bool ParseTraceDataSegment(std::unique_ptr data, size_t size); + void EnableMetaTable(bool enabled); + void EnableFileSave(bool enabled); + static void SetCleanMode(bool cleanMode); + int32_t ExportDatabase(const std::string& outputName, TraceDataDB::ResultCallBack resultCallBack = nullptr); + bool ReloadSymbolFiles(std::string& symbolsPath, std::vector& symbolsPaths); + std::vector SearchData(); + int32_t OperateDatabase(const std::string& sql); + int32_t SearchDatabase(const std::string& sql, TraceDataDB::ResultCallBack resultCallBack); + int32_t SearchDatabase(const std::string& sql, uint8_t* out, int32_t outLen); + int32_t UpdateTraceRangeTime(uint8_t* data, int32_t len); + void WaitForParserEnd(); + void Clear(); + MetaData* GetMetaData(); + void SetDataType(TraceFileType type); + void SetCancel(bool cancel); + TraceFileType DataType() const + { + return fileType_; + } + +private: + void InitFilter(); + void Remove_Folders(const char* dir); + TraceFileType fileType_; + std::unique_ptr streamFilters_ = {}; + std::unique_ptr traceDataCache_ = {}; + + std::unique_ptr bytraceParser_; + std::unique_ptr htraceParser_; + bool enableFileSeparate_ = false; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // TRACE_STREAMER_SELECTOR_H diff --git a/trace_streamer/src/ts.gni b/trace_streamer/src/ts.gni new file mode 100755 index 0000000000000000000000000000000000000000..3030c45f115f529c8819d5089ad75ce2e861854c --- /dev/null +++ b/trace_streamer/src/ts.gni @@ -0,0 +1,61 @@ +# 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. +OHOS_PROTO_DIR = "" + +if (target_os == "linux" || target_os == "macx" || target_os == "windows") { + # OHOS_FTRACE_PROTO_DIR="//third_party/protogen" + OHOS_FTRACE_PROTO_DIR = "//src/multi_platform" + + # OHOS_MEMORY_PROTO_DIR="//third_party/protogen" + OHOS_MEMORY_PROTO_DIR = "//src/multi_platform" + + # OHOS_HILOG_PROTO_DIR="//third_party/protogen" + OHOS_HILOG_PROTO_DIR = "//src/multi_platform" + + # OHOS_NATIVE_HOOK_PROTO_DIR="//third_party/protogen" + OHOS_NATIVE_HOOK_PROTO_DIR = "//src/multi_platform" + + # OHOS_HIDUMP_PROTO_DIR="//third_party/protogen" + OHOS_HIDUMP_PROTO_DIR = "//src/multi_platform" + + # OHOS_SERVICE_PROTO_DIR = "//third_party/protogen" + OHOS_SERVICE_PROTO_DIR = "//src/multi_platform" + OHOS_PROTO_GEN = "//third_party/protogen" + + # kernel_version = "5.10.79_aarch64" + kernel_version = "." + if (target == "test" || target == "testpb") { + enable_ts_utest = true + } else { + enable_ts_utest = false + } + is_openharmony = false +} else { + enable_ts_utest = true + use_wasm = false + kernel_version = "." + is_fuzz = false + target = "trace_streamer" + is_openharmony = true + OHOS_FTRACE_PROTO_DIR = "//developtools/profiler/protos/types/plugins/ftrace_data/${kernel_version}" + OHOS_MEMORY_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/memory_data" + OHOS_HILOG_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hilog_data" + OHOS_NATIVE_HOOK_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/native_hook" + OHOS_HIDUMP_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hidump_data" + OHOS_SERVICE_PROTO_DIR = "//developtools/profiler/protos/services" + OHOS_PROTO_GEN = "//out/ohos-arm-release/gen/cpp/developtools/profiler/protos" +} diff --git a/trace_streamer/test/BUILD.gn b/trace_streamer/test/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..4ab31b23ef17a1ef25a4ec721446955d509c4af1 --- /dev/null +++ b/trace_streamer/test/BUILD.gn @@ -0,0 +1,193 @@ +# 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("//build/test.gni") +import("test_ts.gni") + +if (is_test) { + ohos_unittest("trace_streamer_ut") { + if (is_test) { + if (is_pbdecoder) { + sources = [ + "unittest/binder_filter_test.cpp", + "unittest/bio_parser_test.cpp", + "unittest/bytrace_parser_test.cpp", + "unittest/clock_filter_test.cpp", + "unittest/cpu_filter_test.cpp", + "unittest/ebpf_file_system_test.cpp", + "unittest/ebpf_parser_test.cpp", + "unittest/event_parser_test.cpp", + "unittest/filter_filter_test.cpp", + "unittest/frame_filter_test.cpp", + "unittest/hidump_parser_test.cpp", + "unittest/hilog_parser_test.cpp", + "unittest/hisys_event_parser_test.cpp", + "unittest/htrace_binder_event_test.cpp", + "unittest/htrace_cpu_data_parser_test.cpp", + "unittest/htrace_cpu_detail_parser_test.cpp", + "unittest/htrace_diskio_parser_test.cpp", + "unittest/htrace_event_parser_test.cpp", + "unittest/htrace_irq_event_test.cpp", + "unittest/htrace_mem_parser_test.cpp", + "unittest/htrace_network_parser_test.cpp", + "unittest/htrace_process_parser_test.cpp", + "unittest/htrace_sys_mem_parser_test.cpp", + "unittest/htrace_sys_vmem_parser_test.cpp", + "unittest/http_server_test.cpp", + "unittest/irq_filter_test.cpp", + "unittest/measure_filter_test.cpp", + "unittest/native_hook_parser_test.cpp", + "unittest/paged_memory_parser_test.cpp", + "unittest/parser_test.cpp", + "unittest/process_filter_test.cpp", + "unittest/proto_reader_test.cpp", + "unittest/rpc_server_test.cpp", + "unittest/slice_filter_test.cpp", + "unittest/smaps_parser_test.cpp", + "unittest/span_join_test.cpp", + "unittest/table_test.cpp", + "unittest/wasm_func_test.cpp", + ] + } else { + sources = [ + "unittest/js_memory_test.cpp", + "unittest/parser_pbreader_test.cpp", + ] + } + } + deps = [ + "../src:trace_streamer_source", + "//prebuilts/protos:ts_proto_data_cpp", + "//third_party/googletest:gtest", + "//third_party/googletest:gtest_main", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + "//third_party/sqlite:sqlite", + ] + if (is_test) { + if (is_pbdecoder) { + deps += [ "../src/parser/htrace_parser:htrace_parser" ] + } else { + deps += [ + "../src/parser/htrace_pbreader_parser:htrace_pbreader_parser", + "../src/proto_reader:proto_reader", + ] + } + } + include_dirs = [ + "../src", + "../src/trace_data", + "../src/table", + "../src/table/base", + "../src/filter", + "../src/base", + "../src/rpc", + "../src/include", + "../src/trace_streamer", + "../src/parser/bytrace_parser", + "../src/parser", + "../src/cfg", + "../src/parser/ebpf_parser", + "../src/proto_reader", + "../src/proto_reader/include", + "../prebuilts/emsdk/emsdk/emscripten/system/include", + "..", + "//third_party/googletest/googletest/include/gtest", + "//third_party/protobuf/src", + "//third_party/hiperf/include", + "//third_party/hiperf/include/nonlinux/linux", + "//third_party/protobuf/src/google/protobuf", + "//third_party/json-master/include", + "//third_party/json-master/include/nlohmann", + "//third_party/perf_include/musl", + "${OHOS_PROTO_GEN}", + "${OHOS_FTRACE_PROTO_DIR}", + "${OHOS_MEMORY_PROTO_DIR}", + "${OHOS_HILOG_PROTO_DIR}", + "${OHOS_NATIVE_HOOK_PROTO_DIR}", + "${OHOS_HIDUMP_PROTO_DIR}", + "${OHOS_NETWORK_PROTO_DIR}", + "${OHOS_DISKIO_PROTO_DIR}", + "${OHOS_CPUDATA_PROTO_DIR}", + "${OHOS_PROCESS_PROTO_DIR}", + "${OHOS_SERVICE_PROTO_DIR}", + "${OHOS_TEST_PROTO_DIR}", + "${OHOS_JSMEMORY_PROTO_DIR}", + ] + if (is_test) { + if (is_pbdecoder) { + include_dirs += [ + "../src/parser/htrace_parser", + "../src/parser/htrace_parser/htrace_event_parser", + "../src/parser/htrace_parser/htrace_cpu_parser", + ] + } else { + include_dirs += [ + "../src/parser/htrace_pbreader_parser", + "../src/parser/htrace_pbreader_parser/htrace_event_parser", + "../src/parser/htrace_pbreader_parser/htrace_cpu_parser", + "../src/proto_reader", + "../src/proto_reader/include", + ] + } + } + + cflags = [ + "-Wno-inconsistent-missing-override", + "-Dprivate=public", #allow test code access private members + "-Dprotected=public", #allow test code access protect members + "-fprofile-arcs", + "-ftest-coverage", + "-Wno-unused-command-line-argument", + "-Wno-format", + "-Wno-unused-const-variable", + "-Wno-unused-variable", + "-Wno-used-but-marked-unused", + ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + cflags += [ + # clang coverage options: + "--coverage", + "-mllvm", + "-limited-coverage-experimental=true", + "-fno-use-cxa-atexit", + "-DIS_UT", + ] + if (is_macx) { + lib_dirs = [ "/usr/local/opt/llvm/lib" ] + } + libs = [ "LLVMCore" ] + } +} + +# this is the dest for ohos.build +if (is_test) { + group("unittest") { + testonly = true + deps = [ ":trace_streamer_ut" ] + } +} else if (target == "fuzz") { + group("fuzztest") { + testonly = true + deps = [ + "test_fuzzer/bytrace_fuzzer:fuzztest", + "test_fuzzer/htrace_fuzzer:fuzztest", + "test_fuzzer/selector_fuzzer:fuzztest", + ] + } +} diff --git a/trace_streamer/test/resource/htrace.bin b/trace_streamer/test/resource/htrace.bin new file mode 100755 index 0000000000000000000000000000000000000000..c6fa0f8d8b9d057840ae1c033aed86f649be1b29 Binary files /dev/null and b/trace_streamer/test/resource/htrace.bin differ diff --git a/trace_streamer/test/resource/htrace_ebpf.bin b/trace_streamer/test/resource/htrace_ebpf.bin new file mode 100755 index 0000000000000000000000000000000000000000..6af3c0bc0cd489a73081ce8f46cecf5bbe81ae73 Binary files /dev/null and b/trace_streamer/test/resource/htrace_ebpf.bin differ diff --git a/trace_streamer/test/resource/htrace_ebpf_gold.db b/trace_streamer/test/resource/htrace_ebpf_gold.db new file mode 100755 index 0000000000000000000000000000000000000000..164da5ebf1261950fa231636016f52024b05a4ae Binary files /dev/null and b/trace_streamer/test/resource/htrace_ebpf_gold.db differ diff --git a/trace_streamer/test/resource/htrace_gold.db b/trace_streamer/test/resource/htrace_gold.db new file mode 100755 index 0000000000000000000000000000000000000000..d3d742ac3c25298b8e849bf96b632f19952e14c8 Binary files /dev/null and b/trace_streamer/test/resource/htrace_gold.db differ diff --git a/trace_streamer/test/resource/htrace_perf.bin b/trace_streamer/test/resource/htrace_perf.bin new file mode 100755 index 0000000000000000000000000000000000000000..7e07460ebc739e896cd2f501ca97c25c78b0eb23 Binary files /dev/null and b/trace_streamer/test/resource/htrace_perf.bin differ diff --git a/trace_streamer/test/resource/htrace_perf_gold.db b/trace_streamer/test/resource/htrace_perf_gold.db new file mode 100755 index 0000000000000000000000000000000000000000..87d6c0d9d448cc9337c7573eeb2294ee01e17b87 Binary files /dev/null and b/trace_streamer/test/resource/htrace_perf_gold.db differ diff --git a/trace_streamer/test/resource/pbreader.htrace b/trace_streamer/test/resource/pbreader.htrace new file mode 100755 index 0000000000000000000000000000000000000000..4643f4c2e36d7c25b5becf52f75657486047c867 Binary files /dev/null and b/trace_streamer/test/resource/pbreader.htrace differ diff --git a/trace_streamer/test/resource/pbreaderhtrace.db b/trace_streamer/test/resource/pbreaderhtrace.db new file mode 100755 index 0000000000000000000000000000000000000000..b894047ee3b10262fc1907cc25b174812951d644 Binary files /dev/null and b/trace_streamer/test/resource/pbreaderhtrace.db differ diff --git a/trace_streamer/test/resource/ut_bytrace_input_full.txt b/trace_streamer/test/resource/ut_bytrace_input_full.txt new file mode 100755 index 0000000000000000000000000000000000000000..0a0588c4628428677936486271326d3e5f10de47 --- /dev/null +++ b/trace_streamer/test/resource/ut_bytrace_input_full.txt @@ -0,0 +1,75 @@ +# TRACE: +# tracer: nop +# +# entries-in-buffer/entries-written: 1373949/1373949 #P:4 +# +# _-----=> irqs-off +# / _----=> need-resched +# | / _---=> hardirq/softirq +# || / _--=> preempt-depth +# ||| / delay +# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION +# | | | | |||| | | + ACCS0-2716 ( 2519) [000] ...1 168758.662861: binder_transaction: transaction=25137708 dest_node=4336 dest_proc=924 dest_thread=0 reply=0 flags=0x10 code=0x3 + ACCS0-2716 ( 2519) [000] ...1 168758.662869: binder_transaction_alloc_buf: transaction=25137708 data_size=80 offsets_size=0 + ACCS0-2716 ( 2519) [000] d..5 168758.662877: sched_waking: comm=Binder:924_3 pid=1200 prio=120 target_cpu=001 + ACCS0-2716 ( 2519) [000] d..6 168758.662898: sched_wakeup: comm=Binder:924_3 pid=1200 prio=120 target_cpu=001 + ACCS0-2716 ( 2519) [000] d..3 168758.662919: sched_switch: prev_comm=ACCS0 prev_pid=2716 prev_prio=120 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + HeapTaskDaemon-2532 ( 2519) [000] ...1 168758.662947: tracing_mark_write: E|2519 + HeapTaskDaemon-2532 ( 2519) [000] ...1 168758.662957: tracing_mark_write: B|2519|VisitNonThreadRoots + atrace-8528 ( 8528) [003] ...1 168758.662972: tracing_mark_write: trace_event_clock_sync: parent_ts=20445.875000 + atrace-8528 ( 8528) [003] ...1 168758.662986: tracing_mark_write: trace_event_clock_sync: realtime_ts=1616434280685 + -0 (-----) [001] dn.2 168758.662989: ipi_entry: (Rescheduling interrupts) + -0 (-----) [001] dn.2 168758.662992: ipi_exit: (Rescheduling interrupts) + -0 (-----) [001] .n.2 168758.662996: cpu_idle: state=4294967295 cpu_id=1 + HeapTaskDaemon-2532 ( 2519) [000] ...1 168758.663011: tracing_mark_write: E|2519 + -0 (-----) [001] d..3 168758.663017: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Binder:924_3 next_pid=1200 next_prio=120 + HeapTaskDaemon-2532 ( 2519) [000] ...1 168758.663018: tracing_mark_write: B|2519|ProcessMarkStack + <...>-1200 (-----) [001] ...1 168758.663028: binder_transaction_received: transaction=25137708 + atrace-8528 ( 8528) [003] d..3 168758.663039: sched_switch: prev_comm=atrace prev_pid=8528 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + -0 (-----) [003] d..4 168758.663078: sched_waking: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] d..1 168758.663089: ipi_entry: (Rescheduling interrupts) + -0 (-----) [003] d..2 168758.663089: softirq_raise: vec=9 [action=RCU] + -0 (-----) [003] d..3 168758.663092: sched_waking: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] dnh2 168758.663097: sched_wakeup: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] dn.1 168758.663100: ipi_exit: (Rescheduling interrupts) + -0 (-----) [003] dn.4 168758.663104: sched_wakeup: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663107: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R ==> next_comm=rcu_preempt next_pid=7 next_prio=98 + rcu_preempt-7 ( 7) [000] d..3 168758.663126: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=98 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + -0 (-----) [003] d..3 168758.663126: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=29 next_prio=120 + ksoftirqd/3-29 ( 29) [003] ..s1 168758.663134: softirq_entry: vec=9 [action=RCU] + ksoftirqd/3-29 ( 29) [003] ..s1 168758.663141: softirq_exit: vec=9 [action=RCU] + ksoftirqd/3-29 ( 29) [003] d..3 168758.663159: sched_switch: prev_comm=ksoftirqd/3 prev_pid=29 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + -0 (-----) [003] d..4 168758.663181: sched_waking: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + -0 (-----) [003] d..2 168758.663188: softirq_raise: vec=9 [action=RCU] + HeapTaskDaemon-2532 ( 2519) [000] d..1 168758.663190: ipi_entry: (Rescheduling interrupts) + -0 (-----) [003] d..3 168758.663190: sched_waking: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] dnh2 168758.663194: sched_wakeup: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] dn.1 168758.663195: ipi_exit: (Rescheduling interrupts) + -0 (-----) [003] dn.4 168758.663198: sched_wakeup: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663199: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R+ ==> next_comm=rcu_preempt next_pid=7 next_prio=98 + rcu_preempt-7 ( 7) [000] d..3 168758.663209: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=98 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + -0 (-----) [003] d..3 168758.663212: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=29 next_prio=120 + ksoftirqd/3-29 ( 29) [003] ..s1 168758.663218: softirq_entry: vec=9 [action=RCU] + ksoftirqd/3-29 ( 29) [003] ..s1 168758.663222: softirq_exit: vec=9 [action=RCU] + ksoftirqd/3-29 ( 29) [003] d..3 168758.663239: sched_switch: prev_comm=ksoftirqd/3 prev_pid=29 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + -0 (-----) [003] d..4 168758.663261: sched_waking: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] d..1 168758.663270: ipi_entry: (Rescheduling interrupts) + -0 (-----) [003] d..2 168758.663270: softirq_raise: vec=9 [action=RCU] + -0 (-----) [003] d..3 168758.663272: sched_waking: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] dnh2 168758.663274: sched_wakeup: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] dn.1 168758.663276: ipi_exit: (Rescheduling interrupts) + -0 (-----) [003] dn.4 168758.663279: sched_wakeup: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663280: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R ==> next_comm=rcu_preempt next_pid=7 next_prio=98 + rcu_preempt-7 ( 7) [000] d..3 168758.663290: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=98 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + -0 (-----) [003] d..3 168758.663294: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=29 next_prio=120 + ksoftirqd/3-29 ( 29) [003] ..s1 168758.663298: softirq_entry: vec=9 [action=RCU] + ksoftirqd/3-29 ( 29) [003] ..s1 168758.663301: softirq_exit: vec=9 [action=RCU] + <...>-1200 (-----) [001] ...1 168758.663302: binder_transaction: transaction=25137709 dest_node=0 dest_proc=2519 dest_thread=2716 reply=1 flags=0x0 code=0x0 + <...>-1200 (-----) [001] ...1 168758.663307: binder_transaction_alloc_buf: transaction=25137709 data_size=8 offsets_size=0 + <...>-1200 (-----) [001] d..3 168758.663312: sched_waking: comm=ACCS0 pid=2716 prio=120 target_cpu=000 + ksoftirqd/3-29 ( 29) [003] d..3 168758.663316: sched_switch: prev_comm=ksoftirqd/3 prev_pid=29 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + HeapTaskDaemon-2532 ( 2519) [000] dn.1 168758.663324: ipi_entry: (Rescheduling interrupts) + <...>-1200 (-----) [001] d..4 168758.663324: sched_wakeup: comm=ACCS0 pid=2716 prio=120 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] dn.1 168758.663325: ipi_exit: (Rescheduling interrupts) + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663329: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R ==> next_comm=ACCS0 next_pid=2716 next_prio=120 \ No newline at end of file diff --git a/trace_streamer/test/resource/ut_bytrace_input_full_gold.db b/trace_streamer/test/resource/ut_bytrace_input_full_gold.db new file mode 100755 index 0000000000000000000000000000000000000000..105e8073e5e89805dc1660b46c48c51122156572 Binary files /dev/null and b/trace_streamer/test/resource/ut_bytrace_input_full_gold.db differ diff --git a/trace_streamer/test/resource/ut_bytrace_input_thread.txt b/trace_streamer/test/resource/ut_bytrace_input_thread.txt new file mode 100755 index 0000000000000000000000000000000000000000..1e6486754a3c12a68f1ad5e2f35641a47cf69ba7 --- /dev/null +++ b/trace_streamer/test/resource/ut_bytrace_input_thread.txt @@ -0,0 +1,43 @@ +# TRACE: +# tracer: nop +# +# entries-in-buffer/entries-written: 1373949/1373949 #P:4 +# +# _-----=> irqs-off +# / _----=> need-resched +# | / _---=> hardirq/softirq +# || / _--=> preempt-depth +# ||| / delay +# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION +# | | | | |||| | | + ACCS0-2716 ( 2519) [000] d..5 168758.662877: sched_waking: comm=Binder:924_3 pid=1200 prio=120 target_cpu=001 + ACCS0-2716 ( 2519) [000] d..6 168758.662898: sched_wakeup: comm=Binder:924_3 pid=1200 prio=120 target_cpu=001 + -0 (-----) [001] d..3 168758.663017: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Binder:924_3 next_pid=1200 next_prio=120 + atrace-8528 ( 8528) [003] d..3 168758.663039: sched_switch: prev_comm=atrace prev_pid=8528 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + -0 (-----) [003] d..3 168758.663092: sched_waking: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] dnh2 168758.663097: sched_wakeup: comm=rcu_preempt pid=7 prio=98 target_cpu=000) + -0 (-----) [003] dn.4 168758.663104: sched_wakeup: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663107: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R ==> next_comm=rcu_preempt next_pid=7 next_prio=98 + rcu_preempt-7 ( 7) [000] d..3 168758.663126: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=98 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + -0 (-----) [003] d..3 168758.663126: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=29 next_prio=120 + ksoftirqd/3-29 ( 29) [003] d..3 168758.663159: sched_switch: prev_comm=ksoftirqd/3 prev_pid=29 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + -0 (-----) [003] d..4 168758.663181: sched_waking: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + -0 (-----) [003] d..3 168758.663190: sched_waking: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] dnh2 168758.663194: sched_wakeup: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + -0 (-----) [003] dn.4 168758.663198: sched_wakeup: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663199: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R+ ==> next_comm=rcu_preempt next_pid=7 next_prio=98 + rcu_preempt-7 ( 7) [000] d..3 168758.663209: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=98 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + -0 (-----) [003] d..3 168758.663212: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=29 next_prio=120 + ksoftirqd/3-29 ( 29) [003] d..3 168758.663239: sched_switch: prev_comm=ksoftirqd/3 prev_pid=29 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + -0 (-----) [003] d..4 168758.663261: sched_waking: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + -0 (-----) [003] d..3 168758.663272: sched_waking: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] dnh2 168758.663274: sched_wakeup: comm=rcu_preempt pid=7 prio=98 target_cpu=000 + -0 (-----) [003] dn.4 168758.663279: sched_wakeup: comm=ksoftirqd/3 pid=29 prio=120 target_cpu=003 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663280: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R ==> next_comm=rcu_preempt next_pid=7 next_prio=98 + rcu_preempt-7 ( 7) [000] d..3 168758.663290: sched_switch: prev_comm=rcu_preempt prev_pid=7 prev_prio=98 prev_state=S ==> next_comm=HeapTaskDaemon next_pid=2532 next_prio=124 + -0 (-----) [003] d..3 168758.663294: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/3 next_pid=29 next_prio=120 + <...>-1200 (-----) [001] d..3 168758.663312: sched_waking: comm=ACCS0 pid=2716 prio=120 target_cpu=000 + ksoftirqd/3-29 ( 29) [003] d..3 168758.663316: sched_switch: prev_comm=ksoftirqd/3 prev_pid=29 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120 + <...>-1200 (-----) [001] d..4 168758.663324: sched_wakeup: comm=ACCS0 pid=2716 prio=120 target_cpu=000 + HeapTaskDaemon-2532 ( 2519) [000] d..3 168758.663329: sched_switch: prev_comm=HeapTaskDaemon prev_pid=2532 prev_prio=124 prev_state=R ==> next_comm=ACCS0 next_pid=2716 next_prio=120 + \ No newline at end of file diff --git a/trace_streamer/test/resource/ut_bytrace_input_thread_gold.db b/trace_streamer/test/resource/ut_bytrace_input_thread_gold.db new file mode 100755 index 0000000000000000000000000000000000000000..8e429972480b4b1b1c5574afe868ef32f30ff9f6 Binary files /dev/null and b/trace_streamer/test/resource/ut_bytrace_input_thread_gold.db differ diff --git a/trace_streamer/test/test_fuzzer/README.md b/trace_streamer/test/test_fuzzer/README.md new file mode 100644 index 0000000000000000000000000000000000000000..bbb57beec4db2bdf6f6b52c9271cd32f5f9d381e --- /dev/null +++ b/trace_streamer/test/test_fuzzer/README.md @@ -0,0 +1,49 @@ +# Hi3516烧录OH2代码 + 1. 连接串口线, USB和网线。 + 2. 使用HiTool工具加载并烧写OH2代码编译镜像。 + 镜像路径: OH2_TOOL\out\ohos-arm-release\packages\phone\images\Hi3516DV300-emmc.xml + 3. 在新烧录好的开发板配置网络信息。 + 配置IP: ifconfig eth0 xxx.xxx.xxx.xxx + 配置子网掩码: ifconfig eth0 xxx.xxx.xxx.xxx netmask 255.255.255.0 + 分配hdcd端口: hdcd -t & + 查看端口: netstat -nat + +# 编译FUZZ测试二进制文件 + 1. 修改OH2_TOOL/developtools/profiler/ohos.build + 在testlist中添加:"//developtools/profiler/trace_analyzer/test:fuzztest" + 2. 启动测试shell。 + cd OH2_TOOL + ./test/developertest/start.sh 根据输出提示选择 hi3516DV300对应的数字。 + 3. 编译可执行程序。 + run -t FUZZ -ss developtools -ts hiprofiler_ts_bytrace_fuzz_test + run -t FUZZ -ss developtools -ts hiprofiler_ts_htrace_fuzz_test + run -t FUZZ -ss developtools -ts hiprofiler_ts_selector_fuzz_test + 生成可执行文件路径: OH2_TOOL/out/ohos-arm-release/packages/phone/tests/fuzztest/hiprofiler/ts_fuzz/ + +# 准备FUZZ测试环境 + 1. 使用hdc工具将上一步生成的可执行程序上传到开发板指定目录。 + 例如: hdc_std file send hiprofiler_ts_htrace_fuzz_test /data/local/tmp/FuzzTest + 添加执行权限 chmod +x hiprofiler_ts_htrace_fuzz_test + 2. 上传动态库。 + 代码目录下查询以下动态库, 并上传到开发板/system/lib目录。 + libsqlite.z.so + libcrypto.so + libssl.z.so + libcrypto.z.so + libgrpc.z.so + +# 执行FUZZ测试用例 + cd /data/local/tmp/FuzzTest + ./hiprofiler_ts_bytrace_fuzz_test -max_total_time=20 + ./hiprofiler_ts_htrace_fuzz_test -max_total_time=20 + ./hiprofiler_ts_selector_fuzz_test -max_total_time=20 + +# 可能遇到的问题 + 1. 开发板启动失败,重启开发板,进入uboot中配置启动参数。 + setenv bootargs 'mem=640M console=ttyAMA0,115200 mmz=anonymous,0,0xA8000000,384M clk_ignore_unused androidboot.selinux=permissive skip_initramfs rootdelay=10 init=/init root=/dev/mmcblk0p5 rootfstype=ext4 rw blkdevparts=mmcblk0:1M(boot),15M(kernel),20M(updater),1M(misc),3307M(system),256M(vendor),-(userdata)' + setenv bootcmd "mmc read 0x0 0x80000000 0x800 0x4800; bootm 0x80000000"; + save + reset + 2. 执行测试用例过程中报“cannot merge previous GCDA ”。 + 在开发板上进入OH2_TOOL目录,执行以下命令: + find . -name "*.gcda" -print0 | xargs -0 rm diff --git a/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..4c4eaaad9120de23772d75901dc512e16f9a35c9 --- /dev/null +++ b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/BUILD.gn @@ -0,0 +1,80 @@ +# 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. + +#####################hydra-fuzz################### +import("//build/ohos.gni") +import("//build/test.gni") +import("../../test_ts.gni") + +##############################fuzztest########################################## +ohos_fuzztest("ts_bytrace_fuzz_test") { + include_dirs = [ + "../../../src", + "../../../src/base", + "../../../src/table", + "../../../src/filter", + "../../../src/trace_data", + "../../../src/parser", + "../../../src/trace_streamer", + "../../../src/include", + "../../../src/parser/bytrace_parser", + "../../../src/cfg", + "../../../src/parser/htrace_parser", + "../../../src/parser/htrace_parser/htrace_event_parser", + "../../../src/parser/htrace_parser/htrace_cpu_parser", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "bytrace_fuzzer.cpp" ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + deps = [ + "../../../src:trace_streamer_source", + "//prebuilts/protos:ts_proto_data_cpp", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + "//third_party/sqlite:sqlite", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":ts_bytrace_fuzz_test", + ] +} +############################################################################### diff --git a/trace_streamer/test/test_fuzzer/bytrace_fuzzer/bytrace_fuzzer.cpp b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/bytrace_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32bec6b19e3f0693c49f075bee939f2a25eaec89 --- /dev/null +++ b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/bytrace_fuzzer.cpp @@ -0,0 +1,53 @@ +/* + * 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_fuzzer.h" +#include +#include +#include +#include "common_types.h" +#include "string_help.h" +#include "trace_streamer_selector.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +bool BytraceParserFuzzTest(const uint8_t* data, size_t size) +{ + if (!size) { + return true; + } + TS_LOGI("size:%u", size); + TraceStreamerSelector stream_ = {}; + stream_.SetDataType(TRACE_FILETYPE_BY_TRACE); + std::unique_ptr buf = std::make_unique(size); + if (memcpy_s(buf.get(), size, data, size)) { + return false; + } + stream_.SetCleanMode(true); + stream_.ParseTraceDataSegment(std::move(buf), size); + stream_.WaitForParserEnd(); + return true; +} +} // namespace TraceStreamer +} // namespace SysTuning + +/* Fuzzer entry point */ +extern "C" int32_t LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + /* Run your code on data */ + SysTuning::TraceStreamer::BytraceParserFuzzTest(data, size); + return 0; +} diff --git a/trace_streamer/test/test_fuzzer/bytrace_fuzzer/bytrace_fuzzer.h b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/bytrace_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..39b435f1c56eaf1de1c0c58c3b3cd866876eecee --- /dev/null +++ b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/bytrace_fuzzer.h @@ -0,0 +1,19 @@ +/* + * 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 BYTRACE_FUZZER_H +#define BYTRACE_FUZZER_H +#define FUZZ_PROJECT_NAME "bytrace_fuzzer" +#endif diff --git a/trace_streamer/test/test_fuzzer/bytrace_fuzzer/project.xml b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..85e7ef2c1cc6471e288306f6e3dcea5287a78b0e --- /dev/null +++ b/trace_streamer/test/test_fuzzer/bytrace_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn b/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d9522852aa6da649ccf06e1d0b85992528aa740b --- /dev/null +++ b/trace_streamer/test/test_fuzzer/htrace_fuzzer/BUILD.gn @@ -0,0 +1,80 @@ +# 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. + +#####################hydra-fuzz################### +import("//build/ohos.gni") +import("//build/test.gni") +import("../../test_ts.gni") + +##############################fuzztest########################################## +ohos_fuzztest("ts_htrace_fuzz_test") { + include_dirs = [ + "../../../src", + "../../../src/base", + "../../../src/table", + "../../../src/filter", + "../../../src/trace_data", + "../../../src/parser", + "../../../src/trace_streamer", + "../../../src/include", + "../../../src/parser/bytrace_parser", + "../../../src/cfg", + "../../../src/parser/htrace_parser", + "../../../src/parser/htrace_parser/htrace_event_parser", + "../../../src/parser/htrace_parser/htrace_cpu_parser", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "htrace_fuzzer.cpp" ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + deps = [ + "../../../src:trace_streamer_source", + "//prebuilts/protos:ts_proto_data_cpp", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + "//third_party/sqlite:sqlite", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":ts_htrace_fuzz_test", + ] +} +############################################################################### diff --git a/trace_streamer/test/test_fuzzer/htrace_fuzzer/htrace_fuzzer.cpp b/trace_streamer/test/test_fuzzer/htrace_fuzzer/htrace_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b15c0b75163f4cd581878919f1d58c046843065b --- /dev/null +++ b/trace_streamer/test/test_fuzzer/htrace_fuzzer/htrace_fuzzer.cpp @@ -0,0 +1,49 @@ +/* + * 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 "htrace_fuzzer.h" +#include +#include +#include +#include "common_types.h" +#include "string_help.h" +#include "trace_streamer_selector.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +bool HtraceParserFuzzTest(const uint8_t* data, size_t size) +{ + TraceStreamerSelector stream_ = {}; + stream_.SetDataType(TRACE_FILETYPE_H_TRACE); + std::unique_ptr buf = std::make_unique(size); + if (memcpy_s(buf.get(), size, data, size)) { + return false; + } + stream_.SetCleanMode(true); + stream_.ParseTraceDataSegment(std::move(buf), size); + stream_.WaitForParserEnd(); + return true; +} +} // namespace TraceStreamer +} // namespace SysTuning + +/* Fuzzer entry point */ +extern "C" int32_t LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + /* Run your code on data */ + SysTuning::TraceStreamer::HtraceParserFuzzTest(data, size); + return 0; +} diff --git a/trace_streamer/test/test_fuzzer/htrace_fuzzer/htrace_fuzzer.h b/trace_streamer/test/test_fuzzer/htrace_fuzzer/htrace_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..534420bf9655aab17c1799b3610489cfd6bee577 --- /dev/null +++ b/trace_streamer/test/test_fuzzer/htrace_fuzzer/htrace_fuzzer.h @@ -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. + */ +#ifndef HTRACE_FUZZER_H +#define HTRACE_FUZZER_H +#define FUZZ_PROJECT_NAME "htrace_fuzzer" +#endif diff --git a/trace_streamer/test/test_fuzzer/htrace_fuzzer/project.xml b/trace_streamer/test/test_fuzzer/htrace_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..85e7ef2c1cc6471e288306f6e3dcea5287a78b0e --- /dev/null +++ b/trace_streamer/test/test_fuzzer/htrace_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn b/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..35b9aaf37325769f9e694c9d2ad812dd1a399d64 --- /dev/null +++ b/trace_streamer/test/test_fuzzer/selector_fuzzer/BUILD.gn @@ -0,0 +1,80 @@ +# 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. + +#####################hydra-fuzz################### +import("//build/ohos.gni") +import("//build/test.gni") +import("../../test_ts.gni") + +##############################fuzztest########################################## +ohos_fuzztest("ts_selector_fuzz_test") { + include_dirs = [ + "../../../src", + "../../../src/base", + "../../../src/table", + "../../../src/filter", + "../../../src/trace_data", + "../../../src/parser", + "../../../src/trace_streamer", + "../../../src/include", + "../../../src/parser/bytrace_parser", + "../../../src/cfg", + "../../../src/parser/htrace_parser", + "../../../src/parser/htrace_parser/htrace_event_parser", + "../../../src/parser/htrace_parser/htrace_cpu_parser", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", + "${OHOS_PROTO_GEN}/types/plugins/hilog_data", + "${OHOS_PROTO_GEN}/types/plugins/native_hook", + "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", + "${OHOS_PROTO_GEN}/types/plugins/hisysevent_data", + "${OHOS_PROTO_GEN}/types/plugins/js_memory", + "${OHOS_PROTO_GEN}", + "//third_party/protobuf/src", + ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "selector_fuzzer.cpp" ] + ldflags = [ + "-fprofile-arcs", + "-ftest-coverage", + "--coverage", + ] + deps = [ + "../../../src:trace_streamer_source", + "//prebuilts/protos:ts_proto_data_cpp", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + "//third_party/sqlite:sqlite", + ] +} + +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + # deps file + ":ts_selector_fuzz_test", + ] +} +############################################################################### diff --git a/trace_streamer/test/test_fuzzer/selector_fuzzer/project.xml b/trace_streamer/test/test_fuzzer/selector_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..85e7ef2c1cc6471e288306f6e3dcea5287a78b0e --- /dev/null +++ b/trace_streamer/test/test_fuzzer/selector_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/trace_streamer/test/test_fuzzer/selector_fuzzer/selector_fuzzer.cpp b/trace_streamer/test/test_fuzzer/selector_fuzzer/selector_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a50605929f00a6389cd59cb8420ecc7096b8d01 --- /dev/null +++ b/trace_streamer/test/test_fuzzer/selector_fuzzer/selector_fuzzer.cpp @@ -0,0 +1,48 @@ +/* + * 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 "selector_fuzzer.h" +#include +#include +#include +#include "common_types.h" +#include "string_help.h" +#include "trace_streamer_selector.h" + +namespace SysTuning { +namespace TraceStreamer { +using namespace SysTuning::base; +bool TraceStreamerSelectorFuzzTest(const uint8_t* data, size_t size) +{ + TraceStreamerSelector stream_ = {}; + std::unique_ptr buf = std::make_unique(size); + if (memcpy_s(buf.get(), size, data, size)) { + return false; + } + stream_.SetCleanMode(true); + stream_.ParseTraceDataSegment(std::move(buf), size); + stream_.WaitForParserEnd(); + return true; +} +} // namespace TraceStreamer +} // namespace SysTuning + +/* Fuzzer entry point */ +extern "C" int32_t LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + /* Run your code on data */ + SysTuning::TraceStreamer::TraceStreamerSelectorFuzzTest(data, size); + return 0; +} diff --git a/trace_streamer/test/test_fuzzer/selector_fuzzer/selector_fuzzer.h b/trace_streamer/test/test_fuzzer/selector_fuzzer/selector_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..cf572ff388f80b369cabf76845ae6ee535b7cd98 --- /dev/null +++ b/trace_streamer/test/test_fuzzer/selector_fuzzer/selector_fuzzer.h @@ -0,0 +1,19 @@ +/* + * 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 SELECTOR_FUZZER_H +#define SELECTOR_FUZZER_H +#define FUZZ_PROJECT_NAME "selector_fuzzer" +#endif diff --git a/trace_streamer/test/test_ts.gni b/trace_streamer/test/test_ts.gni new file mode 100755 index 0000000000000000000000000000000000000000..642cb4243b50649cdd5ff46c129fde7cf2012dc7 --- /dev/null +++ b/trace_streamer/test/test_ts.gni @@ -0,0 +1,50 @@ +# 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. +OHOS_PROTO_DIR = "" +kernel_version = "." +if (target_os == "linux" || target_os == "windows" || target_os == "macx") { + OHOS_FTRACE_PROTO_DIR = "//src/multi_platform" + OHOS_MEMORY_PROTO_DIR = "//src/multi_platform" + OHOS_SERVICE_PROTO_DIR = "//src/multi_platform" + OHOS_PROTO_GEN = "//third_party/protogen" + if (is_test) { + OHOS_MEMORY_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/memory_data" + OHOS_NETWORK_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/network_data" + OHOS_DISKIO_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/diskio_data" + OHOS_CPUDATA_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/cpu_data" + OHOS_PROCESS_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/process_data" + OHOS_HISYSEVENT_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/hisysevent_data" + OHOS_TEST_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/test_data" + OHOS_JSMEMORY_PROTO_DIR = "$OHOS_PROTO_GEN/types/plugins/js_memory" + enable_ts_utest = true + OHOS_HILOG_PROTO_DIR = "//src/multi_platform" + OHOS_NATIVE_HOOK_PROTO_DIR = "//src/multi_platform" + OHOS_HIDUMP_PROTO_DIR = "//src/multi_platform" + } +} else { + use_wasm = false + OHOS_FTRACE_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/ftrace_data" + OHOS_MEMORY_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/memory_data" + OHOS_HILOG_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hilog_data" + OHOS_NATIVE_HOOK_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/native_hook" + OHOS_HIDUMP_PROTO_DIR = + "//developtools/profiler/protos/types/plugins/hidump_data" + OHOS_SERVICE_PROTO_DIR = "//developtools/profiler/protos/services" + OHOS_PROTO_GEN = + "//developtools/profiler/trace_analyzer/third_party/protogen/" + enable_ts_utest = true +} diff --git a/trace_streamer/test/unittest/README.md b/trace_streamer/test/unittest/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4bb1a397f53544e67aecb79a14bb54aadf99df8b --- /dev/null +++ b/trace_streamer/test/unittest/README.md @@ -0,0 +1,53 @@ +# 准备测试的硬件环境 + 1. 测试依赖hi3516DV300设备。 + 2. 烧录OHOS_STD代码。 + 3. 通过直连方式,使用USB线将设备连接到存储测试代码的主机。 + +# 准备测试的软件环境 + 1. 设置UT环境变量 + 在代码根目录执行:export BUILD_UT=true + 2. 连接设备 + 在代码根目录执行: root + remount + 3. 准备UT依赖的动态库 + 通过push 把测试依赖的libsqlite.z.so等动态库推到hi3516DV300设备的system/lib文件夹下。 + 4. 准备UT依赖的资源文件 + 将OHOS_STD/test/resource目录push到hi3516DV300设备的/data目录 + 在代码根目录执行: push ./test/resource/ /data/ + 5. 环境清理 + (a) 执行之前先清理OHOS_STD/out/xxx-arm-release/obj/developtools 临时文件。 + rm -rf ~/OHOS_STD/out/xxx-arm-release/obj/developtools + (b) 清理hi3516DV300设备上生成的中间文件/home/XXX/OHOS_STD/out。 + rm -rf /home/ohos/OHOS_STD/out* + (c) 清理UT环境残留的覆盖率报告。 + rm -rf ~/OHOS_STD/developtools/profiler/build/html + +# 测试步骤 + 1. 启动UT执行环境, 启动后根据提示信息输入hi3516DV300对应的设备编号。 + 在代码根目录执行:./test/developertest/start.sh + 2. 编译并执行hiprofiler_ts_ut。 + 在start.sh启动的交互式窗口执行:run -t ut -ss developtools -ts hiprofiler_ts_ut + +# 生成测试报告 + 1. pull设备上生成的gcda + 进入设备环境后: 执行cd /home/XXX/OHOS_STD + tar -cvf out.tar out + exit + 退出shell后:pull /home/XXX/OHOS_STD/out.tar ~/OHOS_STD/ + tar -xvf out.tar + pull /home/ohos/OHOS_STD/out/* /home/ohos/OHOS_STD/out/ + cd /home/ohos/OHOS_STD/developtools/profiler/build + 2. 生成UT覆盖率报告 + 在代码根目录执行:./developtools/profiler/build/lcov.sh + pull /data/test/hiprofiler_ts_ut.xml ~/OHOS_STD/developtools/profiler/build/html/ + 报告位置:~/OHOS_STD/developtools/profiler/build/html/index.html + +# 可能遇到的问题 + 1. gcno文件不存在问题 + gcno文件是在编译阶段生成,编译时如果out目录存在.o临时文件,则不会编译源码,需要删除out/ obj/developtools/目录的编译中间文件后重新编译 + 2. 运行时报缺少依赖库libsqlite.z.so + 需要把libsqlite.z.so push到设备的system/lib目录,在developtools/profiler/device/ohos_test.xml文件增加push命令 + 3. UT所有步骤执行完之后,html中没有生成覆盖率信息 + 权限问题,从设备中pull出来gcov文件后,需要关注文件权限 + 4. UT输出覆盖率世间点不是当前最新时间 + 清理掉原来的html文件,重新执行lcov.sh,生成新的html覆盖率报告 \ No newline at end of file diff --git a/trace_streamer/test/unittest/binder_filter_test.cpp b/trace_streamer/test/unittest/binder_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e57f4ffc1f48dedd6d6e173d85e34af19402d8d --- /dev/null +++ b/trace_streamer/test/unittest/binder_filter_test.cpp @@ -0,0 +1,291 @@ +/* + * 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 +#include + +#include "args_filter.h" +#include "binder_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "trace_plugin_result.pb.h" +#include "ts_common.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class BinderFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.processFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.argsFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.binderFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.statFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.sliceFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + TraceStreamerFilters streamFilters_; + TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: BinderSenderfilterNeedReply + * @tc.desc: Binder event needs reply to + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderfilterNeedReply, TestSize.Level1) +{ + TS_LOGI("test1-1"); + uint64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_); 0x01 + int32_t code = 0; // not important + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 7); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().TimeStampData()[0] == ts1); +} + +/** + * @tc.name: BinderSenderfilterNeedReplyAndReceive + * @tc.desc: Complete event, Binder event needs reply to + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderfilterNeedReplyAndReceive, TestSize.Level1) +{ + TS_LOGI("test1-2"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not importent + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 7); + ts1 = 200; + uint32_t pid1 = 1; + streamFilters_.binderFilter_->ReceiveTraction(ts1, pid1, transactionId1); // receive binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[1] == 1); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 11); + auto len = traceDataCache_.GetConstArgSetData().Size(); + for (uint64_t i = 0; i < len; i++) { + if (traceDataCache_.GetConstArgSetData().names_[i] == streamFilters_.binderFilter_->isReplayId_) { + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[i] == static_cast(isReply)); + } else if (traceDataCache_.GetConstArgSetData().names_[i] == streamFilters_.binderFilter_->destNodeId_) { + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[i] == static_cast(destNode1)); + } else if (traceDataCache_.GetConstArgSetData().names_[i] == streamFilters_.binderFilter_->destThreadId_) { + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[i] == static_cast(pid1)); + } else if (traceDataCache_.GetConstArgSetData().names_[i] == streamFilters_.binderFilter_->callingTid_) { + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[i] == static_cast(tid1)); + } else if (traceDataCache_.GetConstArgSetData().names_[i] == streamFilters_.binderFilter_->transId_) { + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[i] == static_cast(transactionId1)); + } + } +} + +/** + * @tc.name: BinderSenderfilterNeedReplyAndReceiveWithAlloc + * @tc.desc: The binder test that needs to be replied and there is an allock event + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderfilterNeedReplyAndReceiveWithAlloc, TestSize.Level1) +{ + TS_LOGI("test1-3"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not importent + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, + code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 7); + + ts1 = 150; + uint64_t dataSize = 100; + uint64_t offsetSize = 200; + streamFilters_.binderFilter_->TransactionAllocBuf(ts1, tid1, dataSize, offsetSize); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 9); + + ts1 = 200; + uint32_t pid1 = 1; + streamFilters_.binderFilter_->ReceiveTraction(ts1, pid1, transactionId1); // receive binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[1] == 1); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 13); +} + +/** + * @tc.name: BinderSenderfilterNeedReplyAndReceiveNotmatch + * @tc.desc: The binder test that needs to be replied but not match + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderfilterNeedReplyAndReceiveNotmatch, TestSize.Level1) +{ + TS_LOGI("test1-4"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not importent + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, + code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + ts1 = 200; + uint32_t pid1 = 1; + uint64_t transactionId2 = 2; + streamFilters_.binderFilter_->ReceiveTraction(ts1, pid1, transactionId2); // receive binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); +} + +/** + * @tc.name: BinderSenderfilterNoNeedReply + * @tc.desc: The binder test that donot needs to be replied + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderfilterNoNeedReply, TestSize.Level1) +{ + TS_LOGI("test1-5"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not importent + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); +} + +/** + * @tc.name: BinderSenderNoneedReplyAndReceivefilter + * @tc.desc: Complete event, The binder test that donot needs to be replied + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderNoneedReplyAndReceivefilter, TestSize.Level1) +{ + TS_LOGI("test1-6"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not importent + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, + code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + + ts1 = 200; + uint32_t pid1 = 1; + streamFilters_.binderFilter_->ReceiveTraction(ts1, pid1, transactionId1); // receive binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[1] == 0); +} + +/** + * @tc.name: BinderSenderNoneedReplyAndReceivefilterNotmatch + * @tc.desc: Not Match, The binder test that donot needs to be replied + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderNoneedReplyAndReceivefilterNotmatch, TestSize.Level1) +{ + TS_LOGI("test1-7"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + int32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not importent + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, + code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + + ts1 = 200; + uint32_t pid1 = 1; + uint64_t transactionId2 = 2; + streamFilters_.binderFilter_->ReceiveTraction(ts1, pid1, transactionId2); // receive binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); +} + +/** + * @tc.name: BinderSenderfilterWrongReply + * @tc.desc: The binder test with wrong replie + * @tc.type: FUNC + */ +HWTEST_F(BinderFilterTest, BinderSenderfilterWrongReply, TestSize.Level1) +{ + TS_LOGI("test1-8"); + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = true; + int32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + int32_t code = 0; // not important + streamFilters_.binderFilter_->SendTraction(ts1, tid1, transactionId1, destNode1, destTgid1, destTid1, isReply, + flags, + code); // start binder + EXPECT_TRUE(traceDataCache_.GetConstInternalSlicesData().Size() == 0); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 0); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/bio_parser_test.cpp b/trace_streamer/test/unittest/bio_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e2fef42c72b0235516876d722a4f37b896dbad3e --- /dev/null +++ b/trace_streamer/test/unittest/bio_parser_test.cpp @@ -0,0 +1,317 @@ + +/* + * 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 +#include +#include "bio_latency_data_parser.h" +#include "cpu_filter.h" +#include "ebpf_data_parser.h" +#include "ebpf_stdtype.h" +#include "process_filter.h" +#include "trace_streamer_selector.h" +#include "ts_common.h" +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::EbpfStdtype; +namespace SysTuning ::TraceStreamer { +const std::string COMMAND_LINE = "hiebpf --events ptrace --duration 50"; +const uint64_t EPBF_ERROR_MAGIC = 0x12345678; +const uint32_t EPBF_ERROR_HEAD_SIZE = 0; +class EbpfBioParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; +}; +const char PROCESS_NAME_01[MAX_PROCESS_NAME_SZIE] = "process01"; +const uint64_t START_TIME = 1725645867369; +const uint64_t END_TIME = 1725645967369; +const uint64_t BLKCNT = 7829248; +const uint64_t IPS_01 = 548606407208; +const uint64_t IPS_02 = 548607407208; +const uint64_t EBPF_COMMAND_MAX_SIZE = 1000; +const uint32_t DURPER4K = 4096; +/** + * @tc.name: EbpfBioParserCorrectWithoutCallback + * @tc.desc: Test parse BIO data without callback + * @tc.type: FUNC + */ +HWTEST_F(EbpfBioParserTest, EbpfBioParserCorrectWithoutCallback, TestSize.Level1) +{ + TS_LOGI("test32-1"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + strcpy(ebpfHeader.cmdline, COMMAND_LINE.c_str()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(BIOFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_BIO; + BIOFixedHeader bioFixedHeader; + bioFixedHeader.pid = 32; + bioFixedHeader.tid = 32; + memcpy_s(bioFixedHeader.processName, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + bioFixedHeader.startTime = START_TIME; + bioFixedHeader.endTime = END_TIME; + bioFixedHeader.prio = 0; + bioFixedHeader.size = DURPER4K; + bioFixedHeader.blkcnt = BLKCNT; + bioFixedHeader.nips = 0; + bioFixedHeader.type = 2; + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&ebpfTypeAndLength))[0], + &(reinterpret_cast(&ebpfTypeAndLength))[sizeof(EbpfTypeAndLength)]); + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&bioFixedHeader))[0], + &(reinterpret_cast(&bioFixedHeader))[sizeof(BIOFixedHeader)]); + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetBIOSampleMap().size()); + ebpfDataParser->ParseBioLatencyEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstBioLatencySampleData().CallChainIds()[0]; + EXPECT_EQ(callChainId, INVALID_UINT32); + auto type = stream_.traceDataCache_->GetConstBioLatencySampleData().Types()[0]; + EXPECT_EQ(type, 2); + auto startTs = stream_.traceDataCache_->GetConstBioLatencySampleData().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME); + auto endTs = stream_.traceDataCache_->GetConstBioLatencySampleData().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME); + auto dur = stream_.traceDataCache_->GetConstBioLatencySampleData().LatencyDurs()[0]; + EXPECT_EQ(dur, END_TIME - START_TIME); + auto tier = stream_.traceDataCache_->GetConstBioLatencySampleData().Tiers()[0]; + EXPECT_EQ(tier, 0); + auto size = stream_.traceDataCache_->GetConstBioLatencySampleData().Sizes()[0]; + EXPECT_EQ(size, DURPER4K); + auto Expectblk = ebpfDataParser->ConvertToHexTextIndex(BLKCNT); + auto blk = stream_.traceDataCache_->GetConstBioLatencySampleData().BlockNumbers()[0]; + EXPECT_EQ(blk, Expectblk); + auto durPer4K = stream_.traceDataCache_->GetConstBioLatencySampleData().DurPer4k()[0]; + EXPECT_EQ(durPer4K, dur / (size / DURPER4K)); +} + +/** + * @tc.name: EbpfBioParserwrongWithoutCallback + * @tc.desc: Test parse BIO data without callback and startTs > endTs + * @tc.type: FUNC + */ +HWTEST_F(EbpfBioParserTest, EbpfBioParserwrongWithoutCallback, TestSize.Level1) +{ + TS_LOGI("test32-2"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + strcpy(ebpfHeader.cmdline, COMMAND_LINE.c_str()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(BIOFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_BIO; + BIOFixedHeader bioFixedHeader; + bioFixedHeader.pid = 32; + bioFixedHeader.tid = 32; + memcpy_s(bioFixedHeader.processName, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + bioFixedHeader.startTime = END_TIME; + bioFixedHeader.endTime = START_TIME; + bioFixedHeader.prio = 0; + bioFixedHeader.size = DURPER4K; + bioFixedHeader.blkcnt = BLKCNT; + bioFixedHeader.nips = 0; + bioFixedHeader.type = 2; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&bioFixedHeader), + reinterpret_cast(&bioFixedHeader + 1)); + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetBIOSampleMap().size()); + ebpfDataParser->ParseBioLatencyEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstBioLatencySampleData().CallChainIds()[0]; + EXPECT_FALSE(callChainId == INVALID_UINT64); + auto type = stream_.traceDataCache_->GetConstBioLatencySampleData().Types()[0]; + EXPECT_FALSE(type == 2); + auto startTs = stream_.traceDataCache_->GetConstBioLatencySampleData().StartTs()[0]; + EXPECT_FALSE(startTs == END_TIME); + auto endTs = stream_.traceDataCache_->GetConstBioLatencySampleData().EndTs()[0]; + EXPECT_FALSE(endTs == START_TIME); + auto dur = stream_.traceDataCache_->GetConstBioLatencySampleData().LatencyDurs()[0]; + EXPECT_FALSE(dur == endTs - startTs); + auto tier = stream_.traceDataCache_->GetConstBioLatencySampleData().Tiers()[0]; + EXPECT_FALSE(tier == 0); + auto size = stream_.traceDataCache_->GetConstBioLatencySampleData().Sizes()[0]; + EXPECT_FALSE(size == DURPER4K); + auto Expectblk = ebpfDataParser->ConvertToHexTextIndex(BLKCNT); + auto blk = stream_.traceDataCache_->GetConstBioLatencySampleData().BlockNumbers()[0]; + EXPECT_FALSE(blk == Expectblk); + auto durPer4K = stream_.traceDataCache_->GetConstBioLatencySampleData().DurPer4k()[0]; + EXPECT_FALSE(durPer4K == dur / (size / DURPER4K)); +} + +/** + * @tc.name: EbpfBioParserCorrectWithOneCallback + * @tc.desc: Test parse BIO data with one callback + * @tc.type: FUNC + */ +HWTEST_F(EbpfBioParserTest, EbpfBioParserCorrectWithOneCallback, TestSize.Level1) +{ + TS_LOGI("test32-3"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + memcpy_s(ebpfHeader.cmdline, EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), COMMAND_LINE.length()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(BIOFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_BIO; + BIOFixedHeader bioFixedHeader; + bioFixedHeader.pid = 32; + bioFixedHeader.tid = 32; + memcpy_s(bioFixedHeader.processName, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + bioFixedHeader.startTime = START_TIME; + bioFixedHeader.endTime = END_TIME; + bioFixedHeader.prio = 0; + bioFixedHeader.size = DURPER4K; + bioFixedHeader.blkcnt = BLKCNT; + bioFixedHeader.nips = 1; + bioFixedHeader.type = 2; + const uint64_t ips[1] = {IPS_01}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&bioFixedHeader), + reinterpret_cast(&bioFixedHeader + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(ips), + reinterpret_cast(&ips + 1)); + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetBIOSampleMap().size()); + ebpfDataParser->ParseBioLatencyEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstBioLatencySampleData().CallChainIds()[0]; + EXPECT_EQ(callChainId, 0); + auto type = stream_.traceDataCache_->GetConstBioLatencySampleData().Types()[0]; + EXPECT_EQ(type, 2); + auto ipid = stream_.traceDataCache_->GetConstBioLatencySampleData().Ipids()[0]; + EXPECT_EQ(ipid, 1); + auto itid = stream_.traceDataCache_->GetConstBioLatencySampleData().Itids()[0]; + EXPECT_EQ(itid, 1); + auto startTs = stream_.traceDataCache_->GetConstBioLatencySampleData().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME); + auto endTs = stream_.traceDataCache_->GetConstBioLatencySampleData().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME); + auto dur = stream_.traceDataCache_->GetConstBioLatencySampleData().LatencyDurs()[0]; + EXPECT_EQ(dur, END_TIME - START_TIME); + auto tier = stream_.traceDataCache_->GetConstBioLatencySampleData().Tiers()[0]; + EXPECT_EQ(tier, 0); + auto size = stream_.traceDataCache_->GetConstBioLatencySampleData().Sizes()[0]; + EXPECT_EQ(size, DURPER4K); + auto Expectblk = ebpfDataParser->ConvertToHexTextIndex(BLKCNT); + auto blk = stream_.traceDataCache_->GetConstBioLatencySampleData().BlockNumbers()[0]; + EXPECT_EQ(blk, Expectblk); + auto durPer4K = stream_.traceDataCache_->GetConstBioLatencySampleData().DurPer4k()[0]; + EXPECT_EQ(durPer4K, dur / (size / DURPER4K)); + auto ExpectIps0 = ebpfDataParser->ConvertToHexTextIndex(ips[0]); + auto ips0 = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[0]; + EXPECT_EQ(ips0, ExpectIps0); +} + +/** + * @tc.name: EbpfBioParserCorrectWithMultipleCallback + * @tc.desc: Test parse BIO data with multiple callback + * @tc.type: FUNC + */ +HWTEST_F(EbpfBioParserTest, EbpfBioParserCorrectWithMultipleCallback, TestSize.Level1) +{ + TS_LOGI("test32-4"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + memcpy_s(ebpfHeader.cmdline, EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), COMMAND_LINE.length()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&ebpfHeader))[0], + &(reinterpret_cast(&ebpfHeader))[EbpfDataHeader::EBPF_DATA_HEADER_SIZE]); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(BIOFixedHeader) + 2 * sizeof(uint64_t); + ebpfTypeAndLength.type = ITEM_EVENT_BIO; + BIOFixedHeader bioFixedHeader; + bioFixedHeader.pid = 32; + bioFixedHeader.tid = 32; + memcpy_s(bioFixedHeader.processName, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + bioFixedHeader.startTime = START_TIME; + bioFixedHeader.endTime = END_TIME; + bioFixedHeader.prio = 0; + bioFixedHeader.size = DURPER4K; + bioFixedHeader.blkcnt = BLKCNT; + bioFixedHeader.nips = 2; + bioFixedHeader.type = 2; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&bioFixedHeader), + reinterpret_cast(&bioFixedHeader + 1)); + const uint64_t ips[2] = {IPS_01, IPS_02}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(ips), + reinterpret_cast(&ips + 1)); + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetBIOSampleMap().size()); + ebpfDataParser->ParseBioLatencyEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstBioLatencySampleData().CallChainIds()[0]; + EXPECT_EQ(callChainId, 0); + auto type = stream_.traceDataCache_->GetConstBioLatencySampleData().Types()[0]; + EXPECT_EQ(type, 2); + auto ipid = stream_.traceDataCache_->GetConstBioLatencySampleData().Ipids()[0]; + EXPECT_EQ(ipid, 1); + auto itid = stream_.traceDataCache_->GetConstBioLatencySampleData().Itids()[0]; + EXPECT_EQ(itid, 1); + auto startTs = stream_.traceDataCache_->GetConstBioLatencySampleData().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME); + auto endTs = stream_.traceDataCache_->GetConstBioLatencySampleData().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME); + auto dur = stream_.traceDataCache_->GetConstBioLatencySampleData().LatencyDurs()[0]; + EXPECT_EQ(dur, END_TIME - START_TIME); + auto tier = stream_.traceDataCache_->GetConstBioLatencySampleData().Tiers()[0]; + EXPECT_EQ(tier, 0); + auto size = stream_.traceDataCache_->GetConstBioLatencySampleData().Sizes()[0]; + EXPECT_EQ(size, DURPER4K); + auto Expectblk = ebpfDataParser->ConvertToHexTextIndex(BLKCNT); + auto blk = stream_.traceDataCache_->GetConstBioLatencySampleData().BlockNumbers()[0]; + EXPECT_EQ(blk, Expectblk); + auto durPer4K = stream_.traceDataCache_->GetConstBioLatencySampleData().DurPer4k()[0]; + EXPECT_EQ(durPer4K, dur / (size / DURPER4K)); + auto ExpectIps0 = ebpfDataParser->ConvertToHexTextIndex(ips[0]); + auto ips0 = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[1]; + EXPECT_EQ(ips0, ExpectIps0); + auto ExpectIps1 = ebpfDataParser->ConvertToHexTextIndex(ips[1]); + auto ips1 = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[0]; + EXPECT_EQ(ips1, ExpectIps1); +} +} // namespace SysTuning::TraceStreamer diff --git a/trace_streamer/test/unittest/bytrace_parser_test.cpp b/trace_streamer/test/unittest/bytrace_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70bcfa68e325f6d695c4ad762df9e41f943b001a --- /dev/null +++ b/trace_streamer/test/unittest/bytrace_parser_test.cpp @@ -0,0 +1,244 @@ +/* + * 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 +#include +#include +#include +#include + +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "string_help.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::base; + +namespace SysTuning { +namespace TraceStreamer { +class BytraceParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; + +/** + * @tc.name: ParseNoData + * @tc.desc: Test ParseTraceDataSegment interface Parse empty memory + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, ParseNoData, TestSize.Level1) +{ + TS_LOGI("test2-1"); + auto buf = std::make_unique(1); + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), 1); + bytraceParser.WaitForParserEnd(); + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 0); +} + +/** + * @tc.name: ParseNoDataWhithLineFlag + * @tc.desc: Test ParseTraceDataSegment interface Parse "\n" + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, ParseNoDataWhithLineFlag, TestSize.Level1) +{ + TS_LOGI("test2-2"); + constexpr uint32_t bufSize = 1024; + auto buf = std::make_unique(bufSize); + auto realBufSize = strlen(" \n"); + if (memcpy_s(buf.get(), bufSize, " \n", realBufSize)) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), realBufSize); + bytraceParser.WaitForParserEnd(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 1); +} + +/** + * @tc.name: ParseInvalidData + * @tc.desc: Test ParseTraceDataSegment interface Parse invalid string + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, ParseInvalidData, TestSize.Level1) +{ + TS_LOGI("test2-3"); + constexpr uint32_t bufSize = 1024; + auto buf = std::make_unique(bufSize); + auto realBufSize = strlen("0123456789\n"); + if (memcpy_s(buf.get(), bufSize, "0123456789\n", realBufSize)) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), realBufSize); + bytraceParser.WaitForParserEnd(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 1); +} + +/** + * @tc.name: ParseComment + * @tc.desc: Test ParseTraceDataSegment interface Parse Multiline data + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, ParseComment, TestSize.Level1) +{ + TS_LOGI("test2-4"); + constexpr uint32_t bufSize = 1024; + auto buf = std::make_unique(bufSize); + auto realBufSize = strlen("TRACE: \n# tracer: nop \n# \n"); + if (memcpy_s(buf.get(), bufSize, "TRACE: \n# tracer: nop \n# \n", realBufSize)) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), realBufSize); + bytraceParser.WaitForParserEnd(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 2); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 1); +} + +/** + * @tc.name: ParseInvalidLines + * @tc.desc: Test ParseTraceDataSegment interface Parse Multiline Invalid data + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, ParseInvalidLines, TestSize.Level1) +{ + TS_LOGI("test2-5"); + constexpr uint32_t bufSize = 1024; + auto buf = std::make_unique(bufSize); + auto realBufSize = strlen(" \nafafda\n"); + if (memcpy_s(buf.get(), bufSize, " \nafafda\n", realBufSize)) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), realBufSize); + bytraceParser.WaitForParserEnd(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 2); +} + +/** + * @tc.name: ParseNormal + * @tc.desc: Test ParseTraceDataItem interface Parse normal data + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, ParseNormal, TestSize.Level1) +{ + TS_LOGI("test2-6"); + std::string str( + "ACCS0-2716 ( 2519) [000] ...1 168758.662861: binder_transaction: \ + transaction=25137708 dest_node=4336 dest_proc=924 dest_thread=0 reply=0 flags=0x10 code=0x3 \n"); + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataItem(str); + bytraceParser.WaitForParserEnd(); + + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 1); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 0); +} + +/** + * @tc.name: LineParser_abnormal_pid_err + * @tc.desc: Test ParseTraceDataItem interface Parse data with error pid + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, LineParser_abnormal_pid_err, TestSize.Level1) +{ + TS_LOGI("test2-7"); + std::string str( + "ACCS0-27X6 ( 2519) [000] ...1 168758.662861: binder_transaction: \ + transaction=25137708 dest_node=4336 dest_proc=924 dest_thread=0 reply=0 flags=0x10 code=0x3 \n"); + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataItem(str); + bytraceParser.WaitForParserEnd(); + + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 1); +} + +/** + * @tc.name: LineParserWithInvalidCpu + * @tc.desc: Test ParseTraceDataItem interface Parse data with invalid cpu + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, LineParserWithInvalidCpu, TestSize.Level1) +{ + TS_LOGI("test2-8"); + std::string str( + "ACCS0-2716 ( 2519) [00X] ...1 168758.662861: binder_transaction: \ + transaction=25137708 dest_node=4336 dest_proc=924 dest_thread=0 reply=0 flags=0x10 code=0x3 \n"); + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataItem(str); + bytraceParser.WaitForParserEnd(); + + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 1); +} + +/** + * @tc.name: LineParserWithInvalidTs + * @tc.desc: Test ParseTraceDataItem interface Parse data with invalid ts + * @tc.type: FUNC + */ +HWTEST_F(BytraceParserTest, LineParserWithInvalidTs, TestSize.Level1) +{ + TS_LOGI("test2-9"); + std::string str( + "ACCS0-2716 ( 2519) [000] ...1 168758.662X61: binder_transaction: \ + transaction=25137708 dest_node=4336 dest_proc=924 dest_thread=0 reply=0 flags=0x10 code=0x3 \n"); + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataItem(str); + bytraceParser.WaitForParserEnd(); + + EXPECT_TRUE(bytraceParser.TraceCommentLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceValidLines() == 0); + EXPECT_TRUE(bytraceParser.ParsedTraceInvalidLines() == 1); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/clock_filter_test.cpp b/trace_streamer/test/unittest/clock_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccf2af61290cd3ecb9728ec250ea60c0b6dc158b --- /dev/null +++ b/trace_streamer/test/unittest/clock_filter_test.cpp @@ -0,0 +1,507 @@ +/* + * 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 +#include + +#include "clock_filter.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class ClockFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.clockFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerFilters streamFilters_; + SysTuning::TraceStreamer::TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: ConvertBoottimeToMonitonicTime + * @tc.desc: convert Boottime to MonitonicTime + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertBoottimeToMonitonicTime, TestSize.Level1) +{ + TS_LOGI("test3-1"); + uint64_t tsBoottime = 100; + uint64_t tsMonotonicTime = 200; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + uint64_t time1 = 150; + uint64_t expectTime1 = 250; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time1, TS_MONOTONIC), expectTime1); +} + +/** + * @tc.name: ConvertBoottimeToMonitonicTimeTwice + * @tc.desc: convert twice Boottime to MonitonicTime + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertBoottimeToMonitonicTimeTwice, TestSize.Level1) +{ + TS_LOGI("test3-2"); + uint64_t tsBoottime = 100; + uint64_t tsMonotonicTime = 200; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + uint64_t time1 = 150; + uint64_t expectTime1 = 250; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time1, TS_MONOTONIC), expectTime1); + uint64_t time2 = 200; + uint64_t expectTime2 = 300; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time2, TS_MONOTONIC), expectTime2); +} + +/** + * @tc.name: ConvertTimestampInvalid + * @tc.desc: Convert timeStamp invalid + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertTimestampInvalid, TestSize.Level1) +{ + TS_LOGI("test3-3"); + uint64_t tsBoottime = 100; + uint64_t tsMonotonicTime = 200; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsMonotonicTime2 = 350; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_MONOTONIC, tsMonotonicTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + uint64_t time2 = 200; + uint64_t expectTime2 = 200; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time2, TS_CLOCK_REALTIME), expectTime2); +} + +/** + * @tc.name: ConvertTimestampBoottimeToRealtime + * @tc.desc: convert Boottime to Realtime + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertTimestampBoottimeToRealtime, TestSize.Level1) +{ + TS_LOGI("test3-4"); + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsRealTime2 = 400; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + uint64_t time3 = 101; + uint64_t expectTime3 = 301; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time3, TS_CLOCK_REALTIME), expectTime3); +} + +/** + * @tc.name: ConvertBoottimeToRealtimeTwiceWithTwoSnapShot + * @tc.desc: convert Boottime to Realtime twice with two snapShot + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertBoottimeToRealtimeTwiceWithTwoSnapShot, TestSize.Level1) +{ + TS_LOGI("test3-5"); + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsRealTime2 = 400; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + uint64_t time3 = 101; + uint64_t expectTime3 = 301; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time3, TS_CLOCK_REALTIME), expectTime3); + time3 = 201; + expectTime3 = 401; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time3, TS_CLOCK_REALTIME), expectTime3); +} + +/** + * @tc.name: ConvertBoottimeToRealtimeWithSingleSnapShot + * @tc.desc: convert Boottime to Realtime twice with single snapShot + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertBoottimeToRealtimeWithSingleSnapShot, TestSize.Level1) +{ + TS_LOGI("test3-6"); + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + uint64_t time3 = 101; + uint64_t expectTime3 = 301; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time3, TS_CLOCK_REALTIME), expectTime3); + time3 = 201; + expectTime3 = 401; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time3, TS_CLOCK_REALTIME), expectTime3); +} + +/** + * @tc.name: ConvertRealtimeToBoottime + * @tc.desc: convert Realtime to Boottime with single snapShot + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertRealtimeToBoottime, TestSize.Level1) +{ + TS_LOGI("test3-7"); + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + uint64_t time7 = 301; + uint64_t expectTime7 = 101; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time7, TS_CLOCK_BOOTTIME), expectTime7); +} + +/** + * @tc.name: ConvertRealtimeToBoottimeTwice + * @tc.desc: convert Realtime to Boottime twice with single snapShot + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertRealtimeToBoottimeTwice, TestSize.Level1) +{ + TS_LOGI("test3-8"); + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + uint64_t time7 = 301; + uint64_t expectTime7 = 101; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time7, TS_CLOCK_BOOTTIME), expectTime7); + time7 = 501; + expectTime7 = 301; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time7, TS_CLOCK_BOOTTIME), expectTime7); +} + +/** + * @tc.name: ConvertRealtimeToBoottimeTwiceWithTwoSnapshot + * @tc.desc: convert Realtime to Boottime twice with two snapShot + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertRealtimeToBoottimeTwiceWithTwoSnapshot, TestSize.Level1) +{ + TS_LOGI("test3-9"); + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsRealTime2 = 400; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + uint64_t time7 = 401; + uint64_t expectTime7 = 201; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time7, TS_CLOCK_BOOTTIME), expectTime7); + time7 = 301; + expectTime7 = 101; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time7, TS_CLOCK_BOOTTIME), expectTime7); +} + +/** + * @tc.name: ConvertTimestamp + * @tc.desc: muti type timeStamp convert + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertTimestamp, TestSize.Level1) +{ + TS_LOGI("test3-10"); + uint64_t tsBoottime = 100; + uint64_t tsMonotonicTime = 200; + uint64_t tsRealTime = 300; + uint64_t tsRealTimeCoarseTime = 400; + std::vector snapShot0; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + snapShot0.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsMonotonicTime2 = 350; + uint64_t tsRealTime2 = 400; + uint64_t tsRealTimeCoarseTime2 = 800; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_MONOTONIC, tsMonotonicTime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + snapShot1.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + uint64_t time1 = 150; + uint64_t expectTime1 = 250; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time1, TS_MONOTONIC), expectTime1); + uint64_t time2 = 200; + uint64_t expectTime2 = 350; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time2, TS_MONOTONIC), expectTime2); + uint64_t time3 = 101; + uint64_t expectTime3 = 301; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time3, TS_CLOCK_REALTIME), expectTime3); + uint64_t time4 = 102; + uint64_t expectTime4 = 402; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_BOOTTIME, time4, TS_CLOCK_REALTIME_COARSE), expectTime4); + uint64_t time5 = 102; + uint64_t expectTime5 = 202; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_MONOTONIC, time5, TS_CLOCK_REALTIME), expectTime5); + uint64_t time6 = 351; + uint64_t expectTime6 = 251; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time6, TS_MONOTONIC), expectTime6); + uint64_t time7 = 401; + uint64_t expectTime7 = 351; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_CLOCK_REALTIME, time7, TS_MONOTONIC), expectTime7); + uint64_t time8 = 150; + uint64_t expectTime8 = 50; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_MONOTONIC, time8, TS_CLOCK_BOOTTIME), expectTime8); + uint64_t time9 = 250; + uint64_t expectTime9 = 150; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_MONOTONIC, time9, TS_CLOCK_BOOTTIME), expectTime9); + uint64_t time10 = 351; + uint64_t expectTime10 = 201; + EXPECT_EQ(streamFilters_.clockFilter_->Convert(TS_MONOTONIC, time10, TS_CLOCK_BOOTTIME), expectTime10); +} + +/** + * @tc.name: ConvertToPrimary + * @tc.desc: set realtime as primary time type, and convert boottime to Primary time type + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertToPrimary, TestSize.Level1) +{ + TS_LOGI("test3-11"); + std::vector snapShot0; + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsRealTime2 = 400; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + + streamFilters_.clockFilter_->SetPrimaryClock(TS_CLOCK_REALTIME); + uint64_t time1 = 150; + uint64_t expectTime1 = 350; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_BOOTTIME, time1), expectTime1); +} + +/** + * @tc.name: ConvertToPrimaryTwice + * @tc.desc: set realtime as primary time type, and convert boottime to Primary time type twice + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertToPrimaryTwice, TestSize.Level1) +{ + TS_LOGI("test3-12"); + std::vector snapShot0; + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsRealTime2 = 400; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + + streamFilters_.clockFilter_->SetPrimaryClock(TS_CLOCK_BOOTTIME); + uint64_t time1 = 350; + uint64_t expectTime1 = 150; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, time1), expectTime1); +} + +/** + * @tc.name: ConvertToPrimaryTimestampLessThanSnapShop + * @tc.desc: convert realtime to primary time type, and timeStamp less than snapshop + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertToPrimaryTimestampLessThanSnapShop, TestSize.Level1) +{ + TS_LOGI("test3-13"); + std::vector snapShot0; + uint64_t tsBoottime = 100; + uint64_t tsRealTime = 300; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + streamFilters_.clockFilter_->SetPrimaryClock(TS_CLOCK_BOOTTIME); + uint64_t time1 = 250; + uint64_t expectTime1 = 50; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, time1), expectTime1); +} + +/** + * @tc.name: ConvertMonotonicTimeToPrimaryTwice + * @tc.desc: convert TS_MONOTONIC to primary time type with single snapshop + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertMonotonicTimeToPrimaryTwice, TestSize.Level1) +{ + TS_LOGI("test3-14"); + std::vector snapShot0; + uint64_t tsMonotonicTime = 200; + uint64_t tsRealTimeCoarseTime = 400; + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + snapShot0.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + streamFilters_.clockFilter_->SetPrimaryClock(TS_CLOCK_REALTIME_COARSE); + uint64_t time1 = 250; + uint64_t expectTime1 = 450; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, time1), expectTime1); + time1 = 550; + expectTime1 = 750; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, time1), expectTime1); +} + +/** + * @tc.name: ConvertToPrimaryTwiceWithTwoSnapshop + * @tc.desc: convert TS_MONOTONIC & TS_CLOCK_BOOTTIME to primary time type with two snapshop + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, ConvertToPrimaryTwiceWithTwoSnapshop, TestSize.Level1) +{ + TS_LOGI("test3-15"); + std::vector snapShot0; + uint64_t tsMonotonicTime = 200; + uint64_t tsRealTimeCoarseTime = 400; + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + snapShot0.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBootTime2 = 350; + uint64_t tsRealTimeCoarseTime2 = 800; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBootTime2}); + snapShot1.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + + streamFilters_.clockFilter_->SetPrimaryClock(TS_CLOCK_REALTIME_COARSE); + + uint64_t time1 = 250; + uint64_t expectTime1 = 450; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_MONOTONIC, time1), expectTime1); + + uint64_t time2 = 450; + uint64_t expectTime2 = 900; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_BOOTTIME, time2), expectTime2); +} + +/** + * @tc.name: MutiTimeTypeConvertWithMutiSnapshop + * @tc.desc: convert muti time type to primary time type with muti snapshop + * @tc.type: FUNC + */ +HWTEST_F(ClockFilterTest, MutiTimeTypeConvertWithMutiSnapshop, TestSize.Level1) +{ + TS_LOGI("test3-16"); + std::vector snapShot0; + uint64_t tsBoottime = 100; + uint64_t tsMonotonicTime = 200; + uint64_t tsRealTime = 300; + uint64_t tsRealTimeCoarseTime = 400; + snapShot0.push_back({TS_CLOCK_BOOTTIME, tsBoottime}); + snapShot0.push_back({TS_MONOTONIC, tsMonotonicTime}); + snapShot0.push_back({TS_CLOCK_REALTIME, tsRealTime}); + snapShot0.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot0); + + std::vector snapShot1; + uint64_t tsBoottime2 = 200; + uint64_t tsMonotonicTime2 = 350; + uint64_t tsRealTime2 = 400; + uint64_t tsRealTimeCoarseTime2 = 800; + snapShot1.push_back({TS_CLOCK_BOOTTIME, tsBoottime2}); + snapShot1.push_back({TS_MONOTONIC, tsMonotonicTime2}); + snapShot1.push_back({TS_CLOCK_REALTIME, tsRealTime2}); + snapShot1.push_back({TS_CLOCK_REALTIME_COARSE, tsRealTimeCoarseTime2}); + streamFilters_.clockFilter_->AddClockSnapshot(snapShot1); + + streamFilters_.clockFilter_->SetPrimaryClock(TS_CLOCK_REALTIME); + uint64_t time1 = 150; + uint64_t expectTime1 = 350; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_BOOTTIME, time1), expectTime1); + uint64_t time2 = 101; + uint64_t expectTime2 = 301; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_BOOTTIME, time2), expectTime2); + uint64_t time3 = 101; + uint64_t expectTime3 = 101; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, time3), expectTime3); + uint64_t time4 = 351; + uint64_t expectTime4 = 351; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME, time4), expectTime4); + uint64_t time5 = 350; + uint64_t expectTime5 = 250; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME_COARSE, time5), expectTime5); + uint64_t time6 = 420; + uint64_t expectTime6 = 320; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME_COARSE, time6), expectTime6); + uint64_t time7 = 801; + uint64_t expectTime7 = 401; + EXPECT_EQ(streamFilters_.clockFilter_->ToPrimaryTraceTime(TS_CLOCK_REALTIME_COARSE, time7), expectTime7); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/cpu_filter_test.cpp b/trace_streamer/test/unittest/cpu_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18d784f6fbfd74c55a52367de72e2ada2bc56965 --- /dev/null +++ b/trace_streamer/test/unittest/cpu_filter_test.cpp @@ -0,0 +1,355 @@ +/* + * 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 +#include + +#include "cpu_filter.h" +#include "process_filter.h" +#include "ts_common.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class CpuFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.cpuFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.processFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + TraceStreamerFilters streamFilters_; + TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: CpufilterInsertWakeupTest + * @tc.desc: Test CpuFilter insert WakeupEvent + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertWakeupTest, TestSize.Level1) +{ + TS_LOGI("test4-1"); + /* InsertWakeupEvent ts, internalTid */ + uint64_t ts1 = 168758662877000; + uint64_t itid = 1; + streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); // 1st waking + + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state only +} + +/** + * @tc.name: CpufilterInsertSwitchTest + * @tc.desc: Test CpuFilter insert SwitchEvent + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTest, TestSize.Level1) +{ + TS_LOGI("test4-2"); + uint64_t ts1 = 168758662919000; + uint64_t itidPre = 2; + uint64_t prePior = 120; + uint64_t cpu = 0; + uint64_t itidNext = 3; + uint64_t nextPior = 124; + + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 1st switch + printf("state of pre itid: %llu\n", streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre)); + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state +} + +/** + * @tc.name: CpufilterInsertSwitchFromZeroThread + * @tc.desc: Test CpuFilter insert SwitchEvent switch from zero thread + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchFromZeroThread, TestSize.Level1) +{ + TS_LOGI("test4-3"); + uint64_t ts1 = 168758662919000; + uint64_t itidPre = 0; + uint64_t prePior = 120; + uint64_t cpu = 0; + uint64_t itidNext = 3; + uint64_t nextPior = 124; + + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 1st switch + printf("state of pre itid: %llu\n", streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre)); + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INVALID); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 1); // 1 thread state +} + +/** + * @tc.name: CpufilterInsertSwitchToZeroThread + * @tc.desc: Test CpuFilter insert SwitchEvent switch to zero thread + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchToZeroThread, TestSize.Level1) +{ + TS_LOGI("test4-4"); + uint64_t ts1 = 168758662919000; + uint64_t itidPre = 2; + uint64_t prePior = 120; + uint64_t cpu = 0; + uint64_t itidNext = 0; + uint64_t nextPior = 124; + + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 1st switch + printf("state of pre itid: %llu\n", streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre)); + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_INVALID); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == INVALID_UINT64); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 1); // 1 thread state +} + +/** + * @tc.name: CpufilterInsertSwitchDoubleThread + * @tc.desc: Test CpuFilter insert SwitchEvent, A switch to B and B switch to A + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchDoubleThread, TestSize.Level1) +{ + TS_LOGI("test4-5"); + uint64_t ts1 = 168758662919000; + uint64_t itidPre = 2; + uint64_t prePior = 120; + uint64_t cpu = 0; + uint64_t itidNext = 3; + uint64_t nextPior = 124; + + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 1st switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + + ts1 = 168758663017000; + itidPre = 3; + prePior = 120; + cpu = 0; + itidNext = 4; + nextPior = 120; + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 2nd switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidPre) == 3); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 4); // 4 thread state +} + +/** + * @tc.name: CpufilterInsertSwitchThreeThread + * @tc.desc: Test CpuFilter insert SwitchEvent, A switch to B and B switch to C + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchThreeThread, TestSize.Level1) +{ + TS_LOGI("test4-6"); + uint64_t ts1 = 168758662919000; + uint64_t itidPre = 2; + uint64_t prePior = 120; + uint64_t cpu = 0; + uint64_t itidNext = 3; + uint64_t nextPior = 124; + + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 1st switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + + ts1 = 168758663017000; + itidPre = 3; + prePior = 120; + cpu = 0; + itidNext = 2; + nextPior = 120; + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_RUNNABLE, itidNext, nextPior, + INVALID_DATAINDEX); // 2nd switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidPre) == 3); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 4); // 4 thread state +} + +/** + * @tc.name: CpufilterInsertSwitchTestZero + * @tc.desc: Test CpuFilter insert SwitchEvent, A switch to B and B switch to zero thread + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTestZero, TestSize.Level1) +{ + TS_LOGI("test4-7"); + uint64_t ts1 = 168758662919000; + uint64_t itidPre = 2; + uint64_t prePior = 120; + uint64_t cpu = 0; + uint64_t itidNext = 3; + uint64_t nextPior = 124; + + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_INTERRUPTIBLE, itidNext, nextPior, + INVALID_DATAINDEX); // 1st switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidPre) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 0); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); // 2 thread state + + ts1 = 168758663017000; + itidPre = 0; + prePior = 120; + cpu = 0; + itidNext = 4; + nextPior = 120; + streamFilters_.cpuFilter_->InsertSwitchEvent(ts1, cpu, itidPre, prePior, TASK_RUNNABLE, itidNext, nextPior, + INVALID_DATAINDEX); // 2nd switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itidNext) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itidNext) == 2); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 3); // 4 thread state +} + +/** + * @tc.name: CpufiltertWakeingTest + * @tc.desc: Test CpuFilter insert Waking Event + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufiltertWakeingTest, TestSize.Level1) +{ + TS_LOGI("test4-8"); + uint64_t ts1 = 168758662919000; + uint64_t itid = 2; + + streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state +} + +/** + * @tc.name: CpufiltertWakingTwice + * @tc.desc: Test CpuFilter insert Waking Event, one thread waking twice + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufiltertWakingTwice, TestSize.Level1) +{ + TS_LOGI("test4-9"); + uint64_t ts1 = 168758662919000; + uint64_t itid = 2; + + streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); + ts1 = 168758662929000; + itid = 4; + streamFilters_.cpuFilter_->InsertWakeupEvent(ts1, itid); + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(itid) == TASK_INVALID); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(itid) == INVALID_UINT64); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state +} + +/** + * @tc.name: CpufilterInsertSwitchTestFull + * @tc.desc: Parsing multiple switch and wakeup alternates + * @tc.type: FUNC + */ +HWTEST_F(CpuFilterTest, CpufilterInsertSwitchTestFull, TestSize.Level1) +{ + TS_LOGI("test4-10"); + /* InsertWakeupEvent ts, internalTid */ + /* InsertSwitchEvent ts, cpu, prevPid, prevPior, prevState, nextPid, nextPior */ + streamFilters_.cpuFilter_->InsertWakeupEvent(168758662877000, 1); // 1st waking + + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(1) == INVALID_UINT64); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(1) == TASK_INVALID); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 0); // 0 thread state only + + streamFilters_.cpuFilter_->InsertSwitchEvent(168758662919000, 0, 1, 120, TASK_INTERRUPTIBLE, 2, 124, + INVALID_DATAINDEX); // 1st switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(1) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(2) == 0); + // 2 thread state, the waking event add a runnable state + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 2); + streamFilters_.cpuFilter_->InsertSwitchEvent(168758663017000, 0, 0, 120, TASK_RUNNABLE, 4, 120, + INVALID_DATAINDEX); // 2nd switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(4) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(4) == 2); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 3); // 4 thread state + + streamFilters_.cpuFilter_->InsertWakeupEvent(168758663078000, 0); // 2nd waking + + streamFilters_.cpuFilter_->InsertWakeupEvent(168758663092000, 0); // 3rd waking + + streamFilters_.cpuFilter_->InsertSwitchEvent(168758663107000, 0, 2, 124, TASK_RUNNABLE, 5, 98, + INVALID_DATAINDEX); // 3rd switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(5) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNABLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(5) == 3); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(2) == 4); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 5); // 6 thread state + + streamFilters_.cpuFilter_->InsertSwitchEvent(168758663126000, 0, 5, 98, TASK_INTERRUPTIBLE, 2, 124, + INVALID_DATAINDEX); // 4th switch + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(2) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(5) == TASK_INTERRUPTIBLE); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(2) == 5); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(5) == 6); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 7); // 8 thread state + + streamFilters_.cpuFilter_->InsertSwitchEvent(168758663136000, 3, 5, 120, TASK_RUNNABLE, 6, 120, + INVALID_DATAINDEX); // 5th switch + + EXPECT_TRUE(streamFilters_.cpuFilter_->StateOfInternalTidInStateTable(6) == TASK_RUNNING); + EXPECT_TRUE(streamFilters_.cpuFilter_->RowOfInternalTidInStateTable(6) == 7); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->Size() == 9); // 10 thread state + + // after 3rd switch + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->DursData()[1] == INVALID_UINT64); + // after 4th switch + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->DursData()[6] == 168758663136000 - 168758663126000); + EXPECT_TRUE(traceDataCache_.GetThreadStateData()->DursData()[7] == INVALID_UINT64); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/ebpf_file_system_test.cpp b/trace_streamer/test/unittest/ebpf_file_system_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..748a3f9c6487fcf189e9a0698957a27393962008 --- /dev/null +++ b/trace_streamer/test/unittest/ebpf_file_system_test.cpp @@ -0,0 +1,510 @@ +/* + * 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 +#include + +#include "ebpf_data_parser.h" +#include "ebpf_stdtype.h" +#include "process_filter.h" +#include "trace_streamer_selector.h" +#include "ts_common.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::EbpfStdtype; +namespace SysTuning { +namespace TraceStreamer { +class EbpfFileSystemTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +const uint32_t PID_01 = 32; +const uint32_t TID_01 = 12; +const uint32_t PID_02 = 33; +const uint32_t TID_02 = 13; +const uint64_t START_TIME_01 = 1725645867369; +const uint64_t END_TIME_01 = 1725645967369; +const uint64_t START_TIME_02 = 1725645867369; +const uint64_t END_TIME_02 = 1725645967369; +const int32_t RET_01 = 8; +const int32_t RET_02 = -1; +const uint16_t IPS_NUM_00 = 0; +const uint16_t IPS_NUM_01 = 1; +const uint16_t IPS_NUM_02 = 2; +const uint64_t ARGS_01[ARGS_MAX] = {101, 102, 103, 104}; +const uint64_t ARGS_02[ARGS_MAX] = {201, 202, 203, 204}; +const char PROCESS_NAME_01[MAX_PROCESS_NAME_SZIE] = "process01"; +const char PROCESS_NAME_02[MAX_PROCESS_NAME_SZIE] = "process02"; +const uint64_t IPS_01[IPS_NUM_01] = {0x100000000}; +const uint64_t IPS_02[IPS_NUM_02] = {0x100000000, 0x100000001}; + +/** + * @tc.name: ParseFileSystemWithTypeOpen + * @tc.desc: Test parse Ebpf data has one file system data with type open and no ips + * @tc.type: FUNC + */ +HWTEST_F(EbpfFileSystemTest, ParseFileSystemWithTypeOpen, TestSize.Level1) +{ + TS_LOGI("test30-1"); + + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + + FsFixedHeader fsFixedHeader; + fsFixedHeader.pid = PID_01; + fsFixedHeader.tid = TID_01; + fsFixedHeader.startTime = START_TIME_01; + fsFixedHeader.endTime = END_TIME_01; + fsFixedHeader.ret = RET_01; + fsFixedHeader.nrUserIPs = IPS_NUM_00; + fsFixedHeader.type = SYS_OPENAT2; + for (auto i = 0; i < ARGS_MAX; i++) { + fsFixedHeader.args[i] = ARGS_01[i]; + } + strncpy_s(fsFixedHeader.processName, MAX_PROCESS_NAME_SZIE, PROCESS_NAME_01, MAX_PROCESS_NAME_SZIE); + + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(fsFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_FS; + + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&fsFixedHeader), + reinterpret_cast(&fsFixedHeader + 1)); + + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(parser->reader_->GetFileSystemEventMap().size()); + parser->ParseFileSystemEvent(); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstFileSystemSample().CallChainIds()[0]; + EXPECT_EQ(callChainId, INVALID_UINT32); + auto type = stream_.traceDataCache_->GetConstFileSystemSample().Types()[0]; + EXPECT_EQ(type, OPEN); + auto startTs = stream_.traceDataCache_->GetConstFileSystemSample().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME_01); + auto endTs = stream_.traceDataCache_->GetConstFileSystemSample().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME_01); + auto dur = stream_.traceDataCache_->GetConstFileSystemSample().Durs()[0]; + EXPECT_EQ(dur, END_TIME_01 - START_TIME_01); + auto ExpectReturnValue = parser->ConvertToHexTextIndex(RET_01); + auto returnValue = stream_.traceDataCache_->GetConstFileSystemSample().ReturnValues()[0]; + EXPECT_EQ(returnValue, ExpectReturnValue); + auto errorCode = stream_.traceDataCache_->GetConstFileSystemSample().ErrorCodes()[0]; + EXPECT_EQ(errorCode, INVALID_UINT64); + auto fd = stream_.traceDataCache_->GetConstFileSystemSample().Fds()[0]; + EXPECT_EQ(fd, RET_01); + auto fileId = stream_.traceDataCache_->GetConstFileSystemSample().FileIds()[0]; + EXPECT_EQ(fileId, INVALID_UINT64); + auto size = stream_.traceDataCache_->GetConstFileSystemSample().Sizes()[0]; + EXPECT_EQ(size, MAX_SIZE_T); + auto i = 0; + auto ExpectFirstArg = parser->ConvertToHexTextIndex(ARGS_01[i++]); + auto firstArg = stream_.traceDataCache_->GetConstFileSystemSample().FirstArguments()[0]; + EXPECT_EQ(firstArg, ExpectFirstArg); + auto ExpectSecondArg = parser->ConvertToHexTextIndex(ARGS_01[i++]); + auto secondArg = stream_.traceDataCache_->GetConstFileSystemSample().SecondArguments()[0]; + EXPECT_EQ(secondArg, ExpectSecondArg); + auto ExpectThirdArg = parser->ConvertToHexTextIndex(ARGS_01[i++]); + auto thirdArg = stream_.traceDataCache_->GetConstFileSystemSample().ThirdArguments()[0]; + EXPECT_EQ(thirdArg, ExpectThirdArg); + auto ExpectFourthArg = parser->ConvertToHexTextIndex(ARGS_01[i]); + auto fourthArg = stream_.traceDataCache_->GetConstFileSystemSample().FourthArguments()[0]; + EXPECT_EQ(fourthArg, ExpectFourthArg); +} + +/** + * @tc.name: ParseFileSystemWithTypeClose + * @tc.desc: Test parse Ebpf data has one file system data with type close and no ips and return value little to zero + * @tc.type: FUNC + */ +HWTEST_F(EbpfFileSystemTest, ParseFileSystemWithTypeClose, TestSize.Level1) +{ + TS_LOGI("test30-2"); + + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + + FsFixedHeader fsFixedHeader; + fsFixedHeader.pid = PID_02; + fsFixedHeader.tid = TID_02; + fsFixedHeader.startTime = START_TIME_02; + fsFixedHeader.endTime = END_TIME_02; + fsFixedHeader.ret = RET_02; + fsFixedHeader.nrUserIPs = IPS_NUM_00; + fsFixedHeader.type = SYS_CLOSE; + for (auto i = 0; i < ARGS_MAX; i++) { + fsFixedHeader.args[i] = ARGS_02[i]; + } + strncpy_s(fsFixedHeader.processName, MAX_PROCESS_NAME_SZIE, PROCESS_NAME_02, MAX_PROCESS_NAME_SZIE); + + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(fsFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_FS; + + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&fsFixedHeader), + reinterpret_cast(&fsFixedHeader + 1)); + + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(parser->reader_->GetFileSystemEventMap().size()); + parser->ParseFileSystemEvent(); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstFileSystemSample().CallChainIds()[0]; + EXPECT_EQ(callChainId, INVALID_UINT32); + auto type = stream_.traceDataCache_->GetConstFileSystemSample().Types()[0]; + EXPECT_EQ(type, CLOSE); + auto startTs = stream_.traceDataCache_->GetConstFileSystemSample().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME_02); + auto endTs = stream_.traceDataCache_->GetConstFileSystemSample().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME_02); + auto dur = stream_.traceDataCache_->GetConstFileSystemSample().Durs()[0]; + EXPECT_EQ(dur, END_TIME_02 - START_TIME_02); + auto ExpectReturnValue = parser->ConvertToHexTextIndex(0); + auto returnValue = stream_.traceDataCache_->GetConstFileSystemSample().ReturnValues()[0]; + EXPECT_EQ(returnValue, ExpectReturnValue); + auto ExpectErrorValue = parser->ConvertToHexTextIndex(-RET_02); + auto errorCode = stream_.traceDataCache_->GetConstFileSystemSample().ErrorCodes()[0]; + EXPECT_EQ(errorCode, ExpectErrorValue); + auto fd = stream_.traceDataCache_->GetConstFileSystemSample().Fds()[0]; + EXPECT_EQ(fd, ARGS_02[1]); + auto fileId = stream_.traceDataCache_->GetConstFileSystemSample().FileIds()[0]; + EXPECT_EQ(fileId, INVALID_UINT64); + auto size = stream_.traceDataCache_->GetConstFileSystemSample().Sizes()[0]; + EXPECT_EQ(size, MAX_SIZE_T); + auto i = 0; + auto ExpectFirstArg = parser->ConvertToHexTextIndex(ARGS_02[i++]); + auto firstArg = stream_.traceDataCache_->GetConstFileSystemSample().FirstArguments()[0]; + EXPECT_EQ(firstArg, ExpectFirstArg); + auto ExpectSecondArg = parser->ConvertToHexTextIndex(ARGS_02[i++]); + auto secondArg = stream_.traceDataCache_->GetConstFileSystemSample().SecondArguments()[0]; + EXPECT_EQ(secondArg, ExpectSecondArg); + auto ExpectThirdArg = parser->ConvertToHexTextIndex(ARGS_02[i++]); + auto thirdArg = stream_.traceDataCache_->GetConstFileSystemSample().ThirdArguments()[0]; + EXPECT_EQ(thirdArg, ExpectThirdArg); + auto ExpectFourthArg = parser->ConvertToHexTextIndex(ARGS_02[i]); + auto fourthArg = stream_.traceDataCache_->GetConstFileSystemSample().FourthArguments()[0]; + EXPECT_EQ(fourthArg, ExpectFourthArg); +} + +/** + * @tc.name: ParseFileSystemWithTypeRead + * @tc.desc: Test parse Ebpf data has one file system data with type read and no ips + * @tc.type: FUNC + */ +HWTEST_F(EbpfFileSystemTest, ParseFileSystemWithTypeRead, TestSize.Level1) +{ + TS_LOGI("test30-3"); + + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + + FsFixedHeader fsFixedHeader; + fsFixedHeader.pid = PID_01; + fsFixedHeader.tid = TID_01; + fsFixedHeader.startTime = START_TIME_01; + fsFixedHeader.endTime = END_TIME_01; + fsFixedHeader.ret = RET_01; + fsFixedHeader.nrUserIPs = IPS_NUM_00; + fsFixedHeader.type = SYS_READ; + for (auto i = 0; i < ARGS_MAX; i++) { + fsFixedHeader.args[i] = ARGS_01[i]; + } + strncpy_s(fsFixedHeader.processName, MAX_PROCESS_NAME_SZIE, PROCESS_NAME_01, MAX_PROCESS_NAME_SZIE); + + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(fsFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_FS; + + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&fsFixedHeader), + reinterpret_cast(&fsFixedHeader + 1)); + + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(parser->reader_->GetFileSystemEventMap().size()); + parser->ParseFileSystemEvent(); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstFileSystemSample().CallChainIds()[0]; + EXPECT_EQ(callChainId, INVALID_UINT32); + auto type = stream_.traceDataCache_->GetConstFileSystemSample().Types()[0]; + EXPECT_EQ(type, READ); + auto startTs = stream_.traceDataCache_->GetConstFileSystemSample().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME_01); + auto endTs = stream_.traceDataCache_->GetConstFileSystemSample().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME_01); + auto dur = stream_.traceDataCache_->GetConstFileSystemSample().Durs()[0]; + EXPECT_EQ(dur, END_TIME_01 - START_TIME_01); + auto ExpectReturnValue = parser->ConvertToHexTextIndex(RET_01); + auto returnValue = stream_.traceDataCache_->GetConstFileSystemSample().ReturnValues()[0]; + EXPECT_EQ(returnValue, ExpectReturnValue); + auto errorCode = stream_.traceDataCache_->GetConstFileSystemSample().ErrorCodes()[0]; + EXPECT_EQ(errorCode, INVALID_UINT64); + auto fd = stream_.traceDataCache_->GetConstFileSystemSample().Fds()[0]; + EXPECT_EQ(fd, ARGS_01[0]); + auto fileId = stream_.traceDataCache_->GetConstFileSystemSample().FileIds()[0]; + EXPECT_EQ(fileId, INVALID_UINT64); + auto size = stream_.traceDataCache_->GetConstFileSystemSample().Sizes()[0]; + EXPECT_EQ(size, RET_01); + auto i = 0; + auto ExpectFirstArg = parser->ConvertToHexTextIndex(ARGS_01[i++]); + auto firstArg = stream_.traceDataCache_->GetConstFileSystemSample().FirstArguments()[0]; + EXPECT_EQ(firstArg, ExpectFirstArg); + auto ExpectSecondArg = parser->ConvertToHexTextIndex(ARGS_01[i++]); + auto secondArg = stream_.traceDataCache_->GetConstFileSystemSample().SecondArguments()[0]; + EXPECT_EQ(secondArg, ExpectSecondArg); + auto ExpectThirdArg = parser->ConvertToHexTextIndex(ARGS_01[i++]); + auto thirdArg = stream_.traceDataCache_->GetConstFileSystemSample().ThirdArguments()[0]; + EXPECT_EQ(thirdArg, ExpectThirdArg); + auto ExpectFourthArg = parser->ConvertToHexTextIndex(ARGS_01[i]); + auto fourthArg = stream_.traceDataCache_->GetConstFileSystemSample().FourthArguments()[0]; + EXPECT_EQ(fourthArg, ExpectFourthArg); +} + +/** + * @tc.name: ParseFileSystemWithTypeWrite + * @tc.desc: Test parse Ebpf data has one file system data with type read and no ips + * @tc.type: FUNC + */ +HWTEST_F(EbpfFileSystemTest, ParseFileSystemWithTypeWrite, TestSize.Level1) +{ + TS_LOGI("test30-4"); + + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + + FsFixedHeader fsFixedHeader; + fsFixedHeader.pid = PID_02; + fsFixedHeader.tid = TID_02; + fsFixedHeader.startTime = START_TIME_02; + fsFixedHeader.endTime = END_TIME_02; + fsFixedHeader.ret = RET_02; + fsFixedHeader.nrUserIPs = IPS_NUM_00; + fsFixedHeader.type = SYS_WRITE; + for (auto i = 0; i < ARGS_MAX; i++) { + fsFixedHeader.args[i] = ARGS_02[i]; + } + strncpy_s(fsFixedHeader.processName, MAX_PROCESS_NAME_SZIE, PROCESS_NAME_02, MAX_PROCESS_NAME_SZIE); + + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(fsFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_FS; + + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&fsFixedHeader), + reinterpret_cast(&fsFixedHeader + 1)); + + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(parser->reader_->GetFileSystemEventMap().size()); + parser->ParseFileSystemEvent(); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstFileSystemSample().CallChainIds()[0]; + EXPECT_EQ(callChainId, INVALID_UINT32); + auto type = stream_.traceDataCache_->GetConstFileSystemSample().Types()[0]; + EXPECT_EQ(type, WRITE); + auto startTs = stream_.traceDataCache_->GetConstFileSystemSample().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME_02); + auto endTs = stream_.traceDataCache_->GetConstFileSystemSample().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME_02); + auto dur = stream_.traceDataCache_->GetConstFileSystemSample().Durs()[0]; + EXPECT_EQ(dur, END_TIME_02 - START_TIME_02); + auto ExpectReturnValue = parser->ConvertToHexTextIndex(0); + auto returnValue = stream_.traceDataCache_->GetConstFileSystemSample().ReturnValues()[0]; + EXPECT_EQ(returnValue, ExpectReturnValue); + auto errorCode = stream_.traceDataCache_->GetConstFileSystemSample().ErrorCodes()[0]; + auto ExpectErrorValue = parser->ConvertToHexTextIndex(-RET_02); + EXPECT_EQ(errorCode, ExpectErrorValue); + auto fd = stream_.traceDataCache_->GetConstFileSystemSample().Fds()[0]; + EXPECT_EQ(fd, ARGS_02[0]); + auto fileId = stream_.traceDataCache_->GetConstFileSystemSample().FileIds()[0]; + EXPECT_EQ(fileId, INVALID_UINT64); + auto size = stream_.traceDataCache_->GetConstFileSystemSample().Sizes()[0]; + EXPECT_EQ(size, MAX_SIZE_T); + auto i = 0; + auto ExpectFirstArg = parser->ConvertToHexTextIndex(ARGS_02[i++]); + auto firstArg = stream_.traceDataCache_->GetConstFileSystemSample().FirstArguments()[0]; + EXPECT_EQ(firstArg, ExpectFirstArg); + auto ExpectSecondArg = parser->ConvertToHexTextIndex(ARGS_02[i++]); + auto secondArg = stream_.traceDataCache_->GetConstFileSystemSample().SecondArguments()[0]; + EXPECT_EQ(secondArg, ExpectSecondArg); + auto ExpectThirdArg = parser->ConvertToHexTextIndex(ARGS_02[i++]); + auto thirdArg = stream_.traceDataCache_->GetConstFileSystemSample().ThirdArguments()[0]; + EXPECT_EQ(thirdArg, ExpectThirdArg); + auto ExpectFourthArg = parser->ConvertToHexTextIndex(ARGS_02[i]); + auto fourthArg = stream_.traceDataCache_->GetConstFileSystemSample().FourthArguments()[0]; + EXPECT_EQ(fourthArg, ExpectFourthArg); +} + +/** + * @tc.name: ParseFileSystemWithErrorType + * @tc.desc: Test parse Ebpf data has one file system data with error type and no ips + * @tc.type: FUNC + */ +HWTEST_F(EbpfFileSystemTest, ParseFileSystemWithErrorType, TestSize.Level1) +{ + TS_LOGI("test30-5"); + + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + + FsFixedHeader fsFixedHeader; + fsFixedHeader.pid = PID_01; + fsFixedHeader.tid = TID_01; + fsFixedHeader.startTime = START_TIME_01; + fsFixedHeader.endTime = END_TIME_01; + fsFixedHeader.ret = RET_01; + fsFixedHeader.nrUserIPs = IPS_NUM_00; + fsFixedHeader.type = 0; + for (auto i = 0; i < ARGS_MAX; i++) { + fsFixedHeader.args[i] = ARGS_01[i]; + } + strncpy_s(fsFixedHeader.processName, MAX_PROCESS_NAME_SZIE, PROCESS_NAME_01, MAX_PROCESS_NAME_SZIE); + + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(fsFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_FS; + + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&fsFixedHeader), + reinterpret_cast(&fsFixedHeader + 1)); + + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(parser->reader_->GetFileSystemEventMap().size()); + parser->ParseFileSystemEvent(); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + EXPECT_FALSE(stream_.traceDataCache_->GetConstFileSystemSample().Size()); +} + +/** + * @tc.name: ParseFileSystemWithIPsButNoSymTable + * @tc.desc: Test parse Ebpf data has one file system data with ips but no maps + * @tc.type: FUNC + */ +HWTEST_F(EbpfFileSystemTest, ParseFileSystemWithIPsButNoMaps, TestSize.Level1) +{ + TS_LOGI("test30-6"); + + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + + FsFixedHeader fsFixedHeader; + fsFixedHeader.pid = PID_01; + fsFixedHeader.tid = TID_01; + fsFixedHeader.startTime = START_TIME_01; + fsFixedHeader.endTime = END_TIME_01; + fsFixedHeader.ret = RET_01; + fsFixedHeader.nrUserIPs = IPS_NUM_02; + fsFixedHeader.type = SYS_OPENAT2; + for (auto i = 0; i < ARGS_MAX; i++) { + fsFixedHeader.args[i] = ARGS_01[i]; + } + strncpy_s(fsFixedHeader.processName, MAX_PROCESS_NAME_SZIE, PROCESS_NAME_01, MAX_PROCESS_NAME_SZIE); + + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(fsFixedHeader) + IPS_NUM_02 * sizeof(uint64_t); + ebpfTypeAndLength.type = ITEM_EVENT_FS; + + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&fsFixedHeader), + reinterpret_cast(&fsFixedHeader + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(IPS_02), + reinterpret_cast(&IPS_02 + 1)); + + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(parser->reader_->GetFileSystemEventMap().size()); + parser->ParseFileSystemEvent(); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstFileSystemSample().CallChainIds()[0]; + EXPECT_EQ(callChainId, 0); + auto callStackFirstLevelCallChainId = stream_.traceDataCache_->GetConstEbpfCallStackData().CallChainIds()[0]; + EXPECT_EQ(callStackFirstLevelCallChainId, 0); + auto callStackSecondLevelCallChainId = stream_.traceDataCache_->GetConstEbpfCallStackData().CallChainIds()[1]; + EXPECT_EQ(callStackSecondLevelCallChainId, 0); + auto callStackFirstLevelDepth = stream_.traceDataCache_->GetConstEbpfCallStackData().Depths()[0]; + EXPECT_EQ(callStackFirstLevelDepth, 0); + auto callStackSecondLevelDepth = stream_.traceDataCache_->GetConstEbpfCallStackData().Depths()[1]; + EXPECT_EQ(callStackSecondLevelDepth, 1); + auto ExpectCallStackFirstLevelIp = parser->ConvertToHexTextIndex(IPS_02[1]); + auto callStackFirstLevelIp = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[0]; + EXPECT_EQ(callStackFirstLevelIp, ExpectCallStackFirstLevelIp); + auto ExpectCallStackSecondLevelIp = parser->ConvertToHexTextIndex(IPS_02[0]); + auto callStackSecondLevelIp = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[1]; + EXPECT_EQ(callStackSecondLevelIp, ExpectCallStackSecondLevelIp); + auto callStackFirstLevelSymbolId = stream_.traceDataCache_->GetConstEbpfCallStackData().SymbolIds()[0]; + EXPECT_EQ(callStackFirstLevelSymbolId, INVALID_UINT64); + auto callStackSecondLevelSymbolId = stream_.traceDataCache_->GetConstEbpfCallStackData().SymbolIds()[1]; + EXPECT_EQ(callStackSecondLevelSymbolId, INVALID_UINT64); + auto callStackFirstLevelFilePathIds = stream_.traceDataCache_->GetConstEbpfCallStackData().FilePathIds()[0]; + EXPECT_EQ(callStackFirstLevelFilePathIds, INVALID_UINT64); + auto callStackSecondLevelFilePathIds = stream_.traceDataCache_->GetConstEbpfCallStackData().FilePathIds()[1]; + EXPECT_EQ(callStackSecondLevelFilePathIds, INVALID_UINT64); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/ebpf_parser_test.cpp b/trace_streamer/test/unittest/ebpf_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f53250add0d7b97eb60565f6500a73a106fcf976 --- /dev/null +++ b/trace_streamer/test/unittest/ebpf_parser_test.cpp @@ -0,0 +1,159 @@ +/* + * 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 +#include + +#include "ebpf_data_parser.h" +#include "ebpf_stdtype.h" +#include "htrace_file_header.h" +#include "process_filter.h" +#include "trace_streamer_selector.h" +#include "ts_common.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::EbpfStdtype; +namespace SysTuning { +namespace TraceStreamer { +const std::string COMMAND_LINE = "hiebpf --events ptrace --duration 50"; +const uint64_t EPBF_ERROR_MAGIC = 0x12345678; +const uint32_t EPBF_ERROR_HEAD_SIZE = 0; +class EbpfParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: EbpfDataOnlyEbpfHeadWithErrorMagic + * @tc.desc: Test parse Ebpf data with only ebpf head but no command line + * @tc.type: FUNC + */ +HWTEST_F(EbpfParserTest, EbpfDataOnlyEbpfHeadWithErrorMagic, TestSize.Level1) +{ + TS_LOGI("test29-1"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.magic = EPBF_ERROR_MAGIC; + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_FALSE(parser->Init(dequeBuffer, dequeBuffer.size())); +} + +/** + * @tc.name: EbpfDataOnlyEbpfHeadWithErrorSize + * @tc.desc: Test parse Ebpf data with only ebpf head but no command line + * @tc.type: FUNC + */ +HWTEST_F(EbpfParserTest, EbpfDataOnlyEbpfHeadWithErrorSize, TestSize.Level1) +{ + TS_LOGI("test29-2"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.headSize = EPBF_ERROR_HEAD_SIZE; + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_FALSE(parser->Init(dequeBuffer, dequeBuffer.size())); +} + +/** + * @tc.name: EbpfDataEbpfHeadWithNormalData + * @tc.desc: Test parse Ebpf data with normal data + * @tc.type: FUNC + */ +HWTEST_F(EbpfParserTest, EbpfDataEbpfHeadWithNormalData, TestSize.Level1) +{ + TS_LOGI("test29-3"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = 0; + ebpfHeader.header.headSize = EbpfDataHeader::EBPF_DATA_HEADER_SIZE; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + parser->Finish(); + EXPECT_EQ(parser->reader_->ebpfDataHeader_->header.clock, EBPF_CLOCK_BOOTTIME); + EXPECT_EQ(parser->reader_->ebpfDataHeader_->header.cmdLineLen, 0); + EXPECT_EQ(parser->reader_->ebpfDataHeader_->header.headSize, EbpfDataHeader::EBPF_DATA_HEADER_SIZE); +} + +/** + * @tc.name: EbpfDataWithOnlyEbpfHeadNoCommandLine + * @tc.desc: Test parse Ebpf data with only ebpf head but no command line + * @tc.type: FUNC + */ +HWTEST_F(EbpfParserTest, EbpfDataWithOnlyEbpfHeadNoCommandLine, TestSize.Level1) +{ + TS_LOGI("test29-4"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = 0; + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); +} + +/** + * @tc.name: EbpfDataEbpfHeadHasProcessName + * @tc.desc: Test parse Ebpf data with only ebpf head + * @tc.type: FUNC + */ +HWTEST_F(EbpfParserTest, EbpfDataEbpfHeadHasProcessName, TestSize.Level1) +{ + TS_LOGI("test29-5"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + strncpy_s(ebpfHeader.cmdline, EbpfDataHeader::EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), + EbpfDataHeader::EBPF_COMMAND_MAX_SIZE); + + std::deque dequeBuffer = {}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + std::unique_ptr parser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + EXPECT_TRUE(parser->Init(dequeBuffer, dequeBuffer.size())); + parser->Finish(); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + EXPECT_TRUE(parser->reader_->ebpfDataHeader_->header.cmdLineLen == COMMAND_LINE.length()); + EXPECT_STREQ(parser->reader_->ebpfDataHeader_->cmdline, COMMAND_LINE.c_str()); +} + +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/event_parser_test.cpp b/trace_streamer/test/unittest/event_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0051afb1e284ef162896c5d365b36f156d7867bb --- /dev/null +++ b/trace_streamer/test/unittest/event_parser_test.cpp @@ -0,0 +1,1203 @@ +/* + * 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 +#include +#include +#include +#include + +#include "cpu_filter.h" +#include "parser/bytrace_parser/bytrace_event_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "string_help.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::base; + +namespace SysTuning { +namespace TraceStreamer { +const uint32_t G_BUF_SIZE = 1024; +// TestSuite: +class EventParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() + { + if (access(dbPath_.c_str(), F_OK) == 0) { + remove(dbPath_.c_str()); + } + } + +public: + TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; + +/** + * @tc.name: ParseLine + * @tc.desc: Parse a complete sched_switch event in bytrace format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseLine, TestSize.Level1) +{ + TS_LOGI("test5-1"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.cpu = 0; + bytraceLine.task = "ACCS0-2716"; + bytraceLine.pidStr = "12"; + bytraceLine.tGidStr = "12"; + bytraceLine.eventName = "sched_switch"; + bytraceLine.argsStr = + "prev_comm=ACCS0 prev_pid=2716 prev_prio=120 \ + prev_state=R ==> next_comm=kworker/0:0 next_pid=8326 next_prio=120"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(bytraceLine); + eventParser.FilterAllEvents(); + EXPECT_EQ(0, + stream_.traceDataCache_->GetStatAndInfo()->GetValue(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID)); + auto readStatIndex = stream_.traceDataCache_->GetConstSchedSliceData().EndStatesData()[0]; + EXPECT_EQ(TASK_RUNNABLE, readStatIndex); + auto realTimeStamp = stream_.traceDataCache_->GetConstSchedSliceData().TimeStampData()[0]; + EXPECT_TRUE(bytraceLine.ts == realTimeStamp); + auto realCpu = stream_.traceDataCache_->GetConstSchedSliceData().CpusData()[0]; + EXPECT_TRUE(bytraceLine.cpu == realCpu); +} + +/** + * @tc.name: ParseLineNotEnoughArgs + * @tc.desc: Parse a sched_switch event which has not enough args in bytrace format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseLineNotEnoughArgs, TestSize.Level1) +{ + TS_LOGI("test5-2"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.cpu = 0; + bytraceLine.task = "ACCS0-2716"; + bytraceLine.pidStr = "12"; + bytraceLine.tGidStr = "12"; + bytraceLine.eventName = "sched_switch"; + bytraceLine.argsStr = "prev_state=R ==> next_comm=kworker/0:0 next_pid=8326 next_prio=120"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(bytraceLine); + eventParser.FilterAllEvents(); + EXPECT_EQ(1, + stream_.traceDataCache_->GetStatAndInfo()->GetValue(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID)); +} +/** + * @tc.name: ParseLineUnCognizableEventname + * @tc.desc: Parse a UnCognizable Eventname event in bytrace format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseLineUnCognizableEventname, TestSize.Level1) +{ + TS_LOGI("test5-3"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.cpu = 0; + bytraceLine.task = "ACCS0-2716"; + bytraceLine.pidStr = "12"; + bytraceLine.tGidStr = "12"; + bytraceLine.eventName = "ThisEventNameDoNotExist"; // UnRecognizable event name + bytraceLine.argsStr = + "prev_comm=ACCS0 prev_pid=2716 prev_prio=120 \ + prev_state=R ==> next_comm=kworker/0:0 next_pid=8326 next_prio=120"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(bytraceLine); + eventParser.FilterAllEvents(); + EXPECT_EQ(1, stream_.traceDataCache_->GetStatAndInfo()->GetValue(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED)); +} + +/** + * @tc.name: ParseSchedSwitchNoArgs + * @tc.desc: Parse a SchedSwitch event which has no args in bytrace format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedSwitchNoArgs, TestSize.Level1) +{ + TS_LOGI("test5-4"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.cpu = 0; + bytraceLine.task = "ACCS0-2716"; + bytraceLine.pidStr = "12"; + bytraceLine.tGidStr = "12"; + bytraceLine.eventName = "sched_switch"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(bytraceLine); + eventParser.FilterAllEvents(); + EXPECT_EQ(1, + stream_.traceDataCache_->GetStatAndInfo()->GetValue(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID)); +} + +/** + * @tc.name: ParseSchedWakeupNoArgs + * @tc.desc: Parse a SchedWakeup event which has no args in bytrace format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWakeupNoArgs, TestSize.Level1) +{ + TS_LOGI("test5-5"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.cpu = 0; + bytraceLine.task = "ACCS0-2716"; + bytraceLine.pidStr = "12"; + bytraceLine.tGidStr = "12"; + bytraceLine.eventName = "sched_wakeup"; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(bytraceLine); + eventParser.FilterAllEvents(); + EXPECT_EQ(1, + stream_.traceDataCache_->GetStatAndInfo()->GetValue(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID)); +} + +/** + * @tc.name: ParseTracingMarkWriteC + * @tc.desc: Parse a TracingMarkWrite C event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTracingMarkWriteC, TestSize.Level1) +{ + TS_LOGI("test5-6"); + + const uint8_t str[] = + "ACCS0-2716 ( 2519) [000] ...1 174330.284808: tracing_mark_write: C|2519|Heap size (KB)|2906\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseTracingMarkWriteBE + * @tc.desc: Parse a TracingMarkWrite BE event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTracingMarkWriteBE, TestSize.Level1) +{ + TS_LOGI("test5-7"); + const uint8_t str[] = + "system-1298 ( 1298) [001] ...1 174330.287420: tracing_mark_write: B|1298|Choreographer#doFrame\n \ + system - 1298(1298)[001]... 1 174330.287622 : tracing_mark_write : E | 1298\n"; // E | 1298 wrong format + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + EXPECT_EQ(bytraceParser.ParsedTraceInvalidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseTracingMarkWriteSF + * @tc.desc: Parse a TracingMarkWrite SF event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTracingMarkWriteSF, TestSize.Level1) +{ + TS_LOGI("test5-8"); + + const uint8_t str[] = + "system-1298 ( 1298) [001] ...1 174330.287478: tracing_mark_write: S|1298|animator:\ + translateX|18888109\n system-1298(1298)[001]... 1 174330.287514 : tracing_mark_write : \ + F | 1298 | animator : translateX | 18888109\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + EXPECT_EQ(bytraceParser.ParsedTraceInvalidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseTracingMarkWriteErrorPoint + * @tc.desc: Parse a TracingMarkWrite event with error point info + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTracingMarkWriteErrorPoint, TestSize.Level1) +{ + TS_LOGI("test5-9"); + const uint8_t str[] = + "system-1298 ( 1298) [001] ...1 174330.287478: tracing_mark_write: G|1298|animator: \ + translateX|18888109\n system-1298(1298)[001]... 1 174330.287514 : tracing_mark_write : \ + F | 1298 | animator : translateX | 18888109\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + EXPECT_EQ(bytraceParser.ParsedTraceInvalidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseCpuIdle + * @tc.desc: Parse a CpuIdle event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseCpuIdle, TestSize.Level1) +{ + TS_LOGI("test5-10"); + const uint8_t str[] = "-0 (-----) [003] d..2 174330.280761: cpu_idle: state=2 cpu_id=3\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseIrqHandlerEntry + * @tc.desc: Parse a IrqHandlerEntry event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseIrqHandlerEntry, TestSize.Level1) +{ + TS_LOGI("test5-11"); + const uint8_t str[] = + "ACCS0-2716 ( 2519) [000] d.h1 174330.280362: irq_handler_entry: irq=19 name=408000.qcom,cpu-bwmon\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseIrqHandlerExit + * @tc.desc: Parse a IrqHandlerExit event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseIrqHandlerExit, TestSize.Level1) +{ + TS_LOGI("test5-12"); + const uint8_t str[] = "ACCS0-2716 ( 2519) [000] d.h1 174330.280382: irq_handler_exit: irq=19 ret=handled\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseSchedWaking + * @tc.desc: Parse a SchedWaking event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWaking, TestSize.Level1) +{ + TS_LOGI("test5-13"); + const uint8_t str[] = + "ACCS0-2716 ( 2519) [000] d..5 174330.280567: sched_waking: \ + comm=Binder:924_6 pid=1332 prio=120 target_cpu=000\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseSchedWakeup + * @tc.desc: Parse a SchedWakeup event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWakeup, TestSize.Level1) +{ + TS_LOGI("test5-14"); + const uint8_t str[] = + "ACCS0-2716 ( 2519) [000] d..6 174330.280575: sched_wakeup: \ + comm=Binder:924_6 pid=1332 prio=120 target_cpu=000\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseTraceEventClockSync + * @tc.desc: Parse a TraceEventClockSync event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTraceEventClockSync, TestSize.Level1) +{ + TS_LOGI("test5-15"); + const uint8_t str[] = + "sampletrace-12728 (12728) [003] ...1 174330.280300: tracing_mark_write: \ + trace_event_clock_sync:parent_ts=23139.998047\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseSchedSwitch + * @tc.desc: Parse a SchedSwitch event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedSwitch, TestSize.Level1) +{ + TS_LOGI("test5-16"); + const uint8_t str[] = + "ACCS0-2716 ( 2519) [000] d..3 174330.289220: sched_switch: prev_comm=ACCS0 prev_pid=2716 prev_prio=120 \ + prev_state=R+ ==> next_comm=Binder:924_6 next_pid=1332 next_prio=120\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseTaskRename + * @tc.desc: Parse a TaskRename event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTaskRename, TestSize.Level1) +{ + TS_LOGI("test5-17"); + const uint8_t str[] = + "<...>-2093 (-----) [001] ...2 174332.792290: task_rename: pid=12729 oldcomm=perfd \ + newcomm=POSIX timer 249 oom_score_adj=-1000\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseTaskNewtask + * @tc.desc: Parse a TaskNewtask event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTaskNewtask, TestSize.Level1) +{ + TS_LOGI("test5-18"); + const uint8_t str[] = + "<...>-2 (-----) [003] ...1 174332.825588: task_newtask: pid=12730 \ + comm=kthreadd clone_flags=800711 oom_score_adj=0\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_EQ(access(dbPath_.c_str(), F_OK), 0); +} + +/** + * @tc.name: ParseWorkqueueExecuteStart + * @tc.desc: Parse a WorkqueueExecuteStart event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseWorkqueueExecuteStart, TestSize.Level1) +{ + TS_LOGI("test5-19"); + const uint8_t str[] = + "<...>-12180 (-----) [001] ...1 174332.827595: workqueue_execute_start: \ + work struct 0000000000000000: function pm_runtime_work\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParseWorkqueueExecuteEnd + * @tc.desc: Parse a WorkqueueExecuteEnd event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseWorkqueueExecuteEnd, TestSize.Level1) +{ + TS_LOGI("test5-20"); + const uint8_t str[] = + "<...>-12180 (-----) [001] ...1 174332.828056: workqueue_execute_end: work struct 0000000000000000\n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); +} + +/** + * @tc.name: ParsDistribute + * @tc.desc: Parse a Distribute event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParsDistribute, TestSize.Level1) +{ + TS_LOGI("test5-21"); + const uint8_t str[] = + "system-1298 ( 1298) [001] ...1 174330.287420: tracing_mark_write: B|1298|[8b00e96b2,2,1]:C$#decodeFrame$#" + "{\"Process\":\"DecodeVideoFrame\",\"frameTimestamp\":37313484466}\n \ + system - 1298(1298)[001]... 1 174330.287622 : tracing_mark_write : E | 1298 \n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ChainIds()[0] == "8b00e96b2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().SpanIds()[0] == "2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ParentSpanIds()[0] == "1"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Flags()[0] == "C"); +} + +/** + * @tc.name: ParsPairsOfDistributeEvent + * @tc.desc: Parse a pair of Distribute event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParsPairsOfDistributeEvent, TestSize.Level1) +{ + TS_LOGI("test5-22"); + const uint8_t str[] = + "system-1298 ( 1298) [001] ...1 174330.287420: tracing_mark_write: B|1298|[8b00e96b2,2,1]:C$#decodeFrame$#" + "{\"Process\":\"DecodeVideoFrame\",\"frameTimestamp\":37313484466} \ + system - 1298(1298)[001]... 1 174330.287622 : tracing_mark_write : E | 1298 \n" + "startVC-7601 ( 7601) [002] ...1 174330.387420: tracing_mark_write: B|7601|[8b00e96b2,2,1]:S$#startVCFrame$#" + "{\"Process\":\"DecodeVideoFrame\",\"frameTimestamp\":37313484466} \ + startVC-7601 (7601)[002]... 1 174330.487622 : tracing_mark_write : E | 7601 \n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(2)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ChainIds()[0] == "8b00e96b2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().SpanIds()[0] == "2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ParentSpanIds()[0] == "1"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Flags()[0] == "C"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ChainIds()[1] == "8b00e96b2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().SpanIds()[1] == "2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ParentSpanIds()[1] == "1"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Flags()[1] == "S"); +} + +/** + * @tc.name: ParsDistributeWithNoFlag + * @tc.desc: Parse a Distribute event with no flag + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParsDistributeWithNoFlag, TestSize.Level1) +{ + TS_LOGI("test5-23"); + const uint8_t str[] = + "system-1298 ( 1298) [001] ...1 174330.287420: tracing_mark_write: B|1298|[8b00e96b2,2,1]$#decodeFrame$#" + "{\"Process\":\"DecodeVideoFrame\",\"frameTimestamp\":37313484466} \ + system - 1298(1298)[001]... 1 174330.287622 : tracing_mark_write : E | 1298 \n"; + auto buf = std::make_unique(G_BUF_SIZE); + if (memcpy_s(buf.get(), G_BUF_SIZE, str, sizeof(str))) { + EXPECT_TRUE(false); + return; + } + BytraceParser bytraceParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + bytraceParser.ParseTraceDataSegment(std::move(buf), G_BUF_SIZE); + bytraceParser.WaitForParserEnd(); + + EXPECT_EQ(bytraceParser.ParsedTraceValidLines(), static_cast(1)); + stream_.traceDataCache_->ExportDatabase(dbPath_); + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ChainIds()[0] == "8b00e96b2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().SpanIds()[0] == "2"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ParentSpanIds()[0] == "1"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Flags()[0] == ""); +} + +/** + * @tc.name: ParseSchedSwitchByInitParam + * @tc.desc: Parse a SchedSwitch event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedSwitchByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-24"); + BytraceLine bytraceLine; + static std::unordered_map args{{"prev_comm", "ACCS0"}, {"next_comm", "HeapTaskDaemon"}, + {"prev_prio", "120"}, {"next_prio", "124"}, + {"prev_pid", "2716"}, {"next_pid", "2532"}, + {"prev_state", "S"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SchedSwitchEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseSchedSwitchByAbnormalInitParam + * @tc.desc: Parse a SchedSwitch event with some Null parameter + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedSwitchByAbnormalInitParam, TestSize.Level1) +{ + TS_LOGI("test5-25"); + BytraceLine bytraceLine; + static std::unordered_map args{{"prev_comm", "ACCS0"}, {"next_comm", "HeapTaskDaemon"}, + {"prev_prio", ""}, {"next_prio", ""}, + {"prev_pid", ""}, {"next_pid", ""}, + {"prev_state", "S"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SchedSwitchEvent(args, bytraceLine); + + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ParseTaskRenameEventByInitParam + * @tc.desc: Parse a TaskRename event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTaskRenameEventByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-26"); + BytraceLine bytraceLine; + static std::unordered_map args{{"newcomm", "POSIX"}, {"pid", "8542"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.TaskRenameEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseTaskNewtaskByInitParam + * @tc.desc: Parse a TaskNew event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTaskNewtaskByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-27"); + BytraceLine bytraceLine; + bytraceLine.tGidStr = "12"; + static std::unordered_map args{{"comm", "POSIX"}, {"pid", "8542"}, {"clone_flags", "1"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.TaskNewtaskEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseTracingMarkWriteByInitParam + * @tc.desc: Parse a TracingMarkWriteEvent event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseTracingMarkWriteByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-28"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + bytraceLine.argsStr = "B|924|FullSuspendCheck"; + static std::unordered_map args{}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.TracingMarkWriteOrPrintEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseSchedWakeupByInitParam + * @tc.desc: Parse a SchedWakeup event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWakeupByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-29"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + static std::unordered_map args{{"pid", "1200"}, {"target_cpu", "1"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SchedWakeupEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseSchedWakeupByAbromalInitParam + * @tc.desc: Parse a SchedWakeup event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWakeupByAbromalInitParam, TestSize.Level1) +{ + TS_LOGI("test5-30"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + static std::unordered_map args{{"pid", ""}, {"target_cpu", "1"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SchedWakeupEvent(args, bytraceLine); + + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ParseSchedWakingByInitParam + * @tc.desc: Parse a SchedWaking event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWakingByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-31"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + static std::unordered_map args{ + {"prio", "120"}, {"comm", "thread1"}, {"pid", "1200"}, {"target_cpu", "1"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SchedWakingEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseSchedWakingByAbnormalInitParam + * @tc.desc: Parse a SchedWaking event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseSchedWakingByAbnormalInitParam, TestSize.Level1) +{ + TS_LOGI("test5-32"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1; + static std::unordered_map args{ + {"prio", "120"}, {"comm", "thread1"}, {"pid", ""}, {"target_cpu", "1"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.SchedWakingEvent(args, bytraceLine); + + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ParseCpuIdleByInitParam + * @tc.desc: Parse a CpuIdle event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseCpuIdleByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-33"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.eventName = "POSIX"; + static std::unordered_map args{{"cpu_id", "3"}, {"state", "4294967295"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.CpuIdleEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseCpuIdleByAbnormalInitParam + * @tc.desc: Parse a CpuIdle event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseCpuIdleByAbnormalInitParam, TestSize.Level1) +{ + TS_LOGI("test5-34"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.eventName = "POSIX"; + static std::unordered_map args{{"cpu_id", ""}, {"state", "4294967295"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.CpuIdleEvent(args, bytraceLine); + + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ParseCpuFrequencyNormal + * @tc.desc: Parse a CpuFrequency event normally + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseCpuFrequencyNormal, TestSize.Level1) +{ + TS_LOGI("test5-35"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.eventName = "POSIX"; + static std::unordered_map args{{"cpu_id", "3"}, {"state", "4294967295"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.CpuFrequencyEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseCpuFrequencyByAbnormalInitEmptyCpuId + * @tc.desc: Parse a CpuFrequency event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseCpuFrequencyByAbnormalInitEmptyCpuId, TestSize.Level1) +{ + TS_LOGI("test5-36"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.eventName = "POSIX"; + static std::unordered_map args{{"cpu_id", ""}, {"state", "4294967295"}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.CpuFrequencyEvent(args, bytraceLine); + + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ParseCpuFrequencyByAbnormalInitEmptyStateValue + * @tc.desc: Parse a CpuFrequency event, empty state value + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseCpuFrequencyByAbnormalInitEmptyStateValue, TestSize.Level1) +{ + TS_LOGI("test5-37"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.eventName = "POSIX"; + static std::unordered_map args{{"cpu_id", "3"}, {"state", ""}}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.CpuFrequencyEvent(args, bytraceLine); + + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ParseWorkqueueExecuteStartByInitParam + * @tc.desc: Parse a WorkqueueExecuteStart event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseWorkqueueExecuteStartByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-38"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1355; + bytraceLine.argsStr = "vec=9 [action=RCU]"; + static std::unordered_map args{}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.WorkqueueExecuteStartEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: ParseWorkqueueExecuteEndByInitParam + * @tc.desc: Parse a WorkqueueExecuteEnd event + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, ParseWorkqueueExecuteEndByInitParam, TestSize.Level1) +{ + TS_LOGI("test5-39"); + BytraceLine bytraceLine; + bytraceLine.ts = 1616439852302; + bytraceLine.pid = 1355; + static std::unordered_map args{}; + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.WorkqueueExecuteEndEvent(args, bytraceLine); + + EXPECT_EQ(result, true); +} + +/** + * @tc.name: CheckTracePoint + * @tc.desc: Judge whether the "tracepoint information conforming to the specification" in a text format conforms to the + * tracepoint specification + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, CheckTracePoint, TestSize.Level1) +{ + TS_LOGI("test5-40"); + std::string str("B|924|FullSuspendCheck"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.CheckTracePoint(str); + + EXPECT_TRUE(result == PARSE_SUCCESS); +} + +/** + * @tc.name: CheckTracePointEmptyString + * @tc.desc: Judge whether the Empty string conforms to the tracepoint specification + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, CheckTracePointEmptyString, TestSize.Level1) +{ + TS_LOGI("test5-41"); + std::string str(""); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.CheckTracePoint(str); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: CheckTracePointNoSplit + * @tc.desc: Judge whether the string No Split conforms to the tracepoint specification + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, CheckTracePointNoSplit, TestSize.Level1) +{ + TS_LOGI("test5-42"); + std::string str("trace_event_clock_sync"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.CheckTracePoint(str); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: CheckTracePointMultiType + * @tc.desc: Judge whether the string has multipul Case type conforms to the tracepoint specification + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, CheckTracePointMultiType, TestSize.Level1) +{ + TS_LOGI("test5-43"); + std::string str("BECSF|924|FullSuspendCheck"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.CheckTracePoint(str); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: CheckTracePointCheckSingleCharacter + * @tc.desc: Check whether a single character conforms to tracepoint format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, CheckTracePointCheckSingleCharacter, TestSize.Level1) +{ + TS_LOGI("test5-44"); + std::string str("X"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.CheckTracePoint(str); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: CheckTracePointCheckErrorSplit + * @tc.desc: Check error split + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, CheckTracePointCheckErrorSplit, TestSize.Level1) +{ + TS_LOGI("test5-45"); + std::string str("B&924|FullSuspendCheck"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.CheckTracePoint(str); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: GetTracePoint + * @tc.desc: Test GetTracePoint interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, GetTracePoint, TestSize.Level1) +{ + TS_LOGI("test5-46"); + TracePoint point; + std::string str("B|924|SuspendThreadByThreadId suspended Binder:924_8 id=39"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.GetTracePoint(str, point); + + EXPECT_TRUE(result == PARSE_SUCCESS); +} + +/** + * @tc.name: GetTracePointParseEmptyString + * @tc.desc: Test GetTracePoint interface parse empty string + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, GetTracePointParseEmptyString, TestSize.Level1) +{ + TS_LOGI("test5-47"); + TracePoint point; + std::string str(""); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.GetTracePoint(str, point); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: GetTracePointParseErrorSubEventType + * @tc.desc: Test GetTracePoint interface parse error Sub event type + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, GetTracePointParseErrorSubEventType, TestSize.Level1) +{ + TS_LOGI("test5-48"); + TracePoint point; + std::string str("X|924|SuspendThreadByThreadId suspended Binder:924_8 id=39"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.GetTracePoint(str, point); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: GetThreadGroupId + * @tc.desc: Test GetThreadGroupId interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, GetThreadGroupId, TestSize.Level1) +{ + TS_LOGI("test5-49"); + size_t length{0}; + std::string str("E|924"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.GetThreadGroupId(str, length); + + EXPECT_TRUE(result == 924); +} + +/** + * @tc.name: GetThreadGroupIdParseErrorPid + * @tc.desc: Test GetThreadGroupId interface parse error pid + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, GetThreadGroupIdParseErrorPid, TestSize.Level1) +{ + TS_LOGI("test5-50"); + size_t length{0}; + std::string str("E|abc"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.GetThreadGroupId(str, length); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: HandlerB + * @tc.desc: Test HandlerB interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerB, TestSize.Level1) +{ + TS_LOGI("test5-51"); + size_t length{3}; + TracePoint outPoint; + std::string str("B|924|HID::ISensors::batch::client"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerB(str, outPoint, length); + + EXPECT_TRUE(result == PARSE_SUCCESS); +} + +/** + * @tc.name: HandlerBAbnormal + * @tc.desc: Test HandlerBAbnormal interface using Abnormal format + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerBAbnormal, TestSize.Level1) +{ + TS_LOGI("test5-52"); + size_t length{3}; + TracePoint outPoint; + std::string str("B|924|"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerB(str, outPoint, length); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: HandlerCsf + * @tc.desc: Test HandlerCSF interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerCsf, TestSize.Level1) +{ + TS_LOGI("test5-53"); + size_t length{4}; + TracePoint outPoint; + std::string str("C|2519|Heap size (KB)|2363"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerCSF(str, outPoint, length); + + EXPECT_TRUE(result == PARSE_SUCCESS); +} + +/** + * @tc.name: HandlerCsfParseEmptyString + * @tc.desc: Parse empty string using HandlerCSF interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerCsfParseEmptyString, TestSize.Level1) +{ + TS_LOGI("test5-54"); + size_t length{4}; + TracePoint outPoint; + std::string str(""); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerCSF(str, outPoint, length); + + EXPECT_TRUE(result == PARSE_ERROR); +} + +/** + * @tc.name: HandlerCsfParseErrorFormate + * @tc.desc: Parse "C|2519|Heap size (KB)|" using HandlerCSF interface + * @tc.type: FUNC + */ +HWTEST_F(EventParserTest, HandlerCsfParseErrorFormate, TestSize.Level1) +{ + TS_LOGI("test5-55"); + size_t length{4}; + TracePoint outPoint; + std::string str("C|2519|Heap size (KB)|"); + BytraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + int32_t result = eventParser.printEventParser_.HandlerCSF(str, outPoint, length); + + EXPECT_TRUE(result == PARSE_ERROR); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/filter_filter_test.cpp b/trace_streamer/test/unittest/filter_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a311c254c6e6b763f87b0179cff8fbcd161863b --- /dev/null +++ b/trace_streamer/test/unittest/filter_filter_test.cpp @@ -0,0 +1,85 @@ +/* + * 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 +#include + +#include "filter_filter.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class FilterFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.filterFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + TraceStreamerFilters streamFilters_; + TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: AddCpuCounterFilter + * @tc.desc: Add cpu_counter_filter through AddFilter interface + * @tc.type: FUNC + */ +HWTEST_F(FilterFilterTest, AddCpuCounterFilter, TestSize.Level1) +{ + TS_LOGI("test6-1"); + uint32_t filterId = streamFilters_.filterFilter_->AddFilter("cpu_counter_filter", "cpu1", 1); + EXPECT_EQ(filterId, static_cast(0)); + + filterId = streamFilters_.filterFilter_->AddFilter("cpu_counter_filter", "cpu2", 2); + EXPECT_EQ(filterId, static_cast(1)); + + Filter* filterTable = traceDataCache_.GetFilterData(); + EXPECT_EQ(filterTable->Size(), static_cast(2)); +} + +/** + * @tc.name: AddThreadFilter + * @tc.desc: Add thread_counter_filter & thread_filter through AddFilter interface + * @tc.type: FUNC + */ +HWTEST_F(FilterFilterTest, AddThreadFilter, TestSize.Level1) +{ + TS_LOGI("test6-2"); + uint32_t threadFilterId = streamFilters_.filterFilter_->AddFilter("thread_counter_filter", "threadCount1", 1); + EXPECT_EQ(threadFilterId, static_cast(0)); + + threadFilterId = streamFilters_.filterFilter_->AddFilter("thread_counter_filter", "threadCount2", 2); + EXPECT_EQ(threadFilterId, static_cast(1)); + + Filter* filterTable = traceDataCache_.GetFilterData(); + EXPECT_EQ(filterTable->Size(), static_cast(2)); + + threadFilterId = streamFilters_.filterFilter_->AddFilter("thread_filter", "thread1", 1); + EXPECT_EQ(threadFilterId, static_cast(2)); + + threadFilterId = streamFilters_.filterFilter_->AddFilter("thread_filter", "thread2", 2); + EXPECT_EQ(threadFilterId, static_cast(3)); + + EXPECT_EQ(filterTable->Size(), static_cast(4)); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/frame_filter_test.cpp b/trace_streamer/test/unittest/frame_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b65c62e3a2c224257bc48124072a05ede865dd5 --- /dev/null +++ b/trace_streamer/test/unittest/frame_filter_test.cpp @@ -0,0 +1,389 @@ +/* + * 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 +#include + +#include "frame_filter.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class FrameFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.frameFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + TraceStreamerFilters streamFilters_; + TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: AppVsyncNoFrameNum + * @tc.desc: app's vsync event no frameNum + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, AppVsyncNoFrameNum, TestSize.Level1) +{ + TS_LOGI("test6-1"); + // ut 1 no frameNum + // app ---------------VSYNCStart------------------End---uint64_t ts, + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t END_TS = 10; + auto res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_FALSE(res); + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Flags()[0], 2); // actural frame, no frameNum + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Flags()[1], 2); // expect frame, no frameNum + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->TimeStampData()[0], START_TS); // actural frame + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->TimeStampData()[1], EXPECTED_START); // expect frame + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Durs()[0], END_TS - START_TS); // actural frame + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Durs()[1], EXPECTED_END - EXPECTED_START); // expect frame +} + +/** + * @tc.name: AppVsyncHasFrameNum + * @tc.desc: app's vsync event has frameNum + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, AppVsyncHasFrameNum, TestSize.Level1) +{ + TS_LOGI("test6-2"); + // ut 2 has frameNum + // app -----VSYNCStart------------------End--- + // -----------------frameNum-------------- + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t FRAME_TS = 5; + const uint32_t FRAME_NUM = 1; + bool res = streamFilters_.frameFilter_->BeginRSTransactionData(FRAME_TS, ITID, FRAME_NUM); + EXPECT_TRUE(res); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Flags()[0], 0); // actural frame, no frameNum + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Flags()[1], 255); // expect frame, no frameNum + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->TimeStampData()[0], START_TS); // actural frame + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->TimeStampData()[1], EXPECTED_START); // expect frame + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Durs()[0], END_TS - START_TS); // actural frame + EXPECT_EQ(traceDataCache_.GetFrameSliceData()->Durs()[1], EXPECTED_END - EXPECTED_START); // expect frame + EXPECT_EQ(streamFilters_.frameFilter_->dstRenderSlice_[ITID][FRAME_NUM].get()->startTs_, START_TS); +} +/** + * @tc.name: RSVsyncHasFrameNum + * @tc.desc: RS's vsync event has no frameNum + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, RSVsyncHasNoFrameNum, TestSize.Level1) +{ + TS_LOGI("test6-3"); + // ut3 RS no frame + // RS ---------------VSYNCStart------------------End--- + + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS = 2; + auto res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS, ITID); + EXPECT_TRUE(res); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + EXPECT_TRUE(streamFilters_.frameFilter_->vsyncRenderSlice_[ITID].begin()->get()->isRsMainThread_ == true); +} + +/** + * @tc.name: RSVsyncHasFrameNumNotMatched + * @tc.desc: RS's vsync event has frameNum,but not matched + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, RSVsyncHasFrameNumNotMatched, TestSize.Level1) +{ + TS_LOGI("test6-4"); + // ut4 RS has frame, bu not matched + // RS -----VSYNCStart------------------End--- + // -----------frameNum------------------- + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS = 2; + auto res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS, ITID); + EXPECT_TRUE(res); + + const uint32_t SOURCE_ITID1 = 2; + const uint32_t SOURCE_FRAME_NUM = 1; + const uint64_t UNI_TS = 3; + std::vector frames; + frames.push_back({SOURCE_ITID1, SOURCE_FRAME_NUM}); + streamFilters_.frameFilter_->BeginProcessCommandUni(UNI_TS, ITID, frames, 0); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + EXPECT_TRUE(streamFilters_.frameFilter_->vsyncRenderSlice_[ITID].begin()->get()->isRsMainThread_ == true); + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Srcs()[0].empty() == true); +} + +/** + * @tc.name: RSVsyncHasGpu + * @tc.desc: RS's vsync event has gpu + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, RSVsyncHasGpu, TestSize.Level1) +{ + TS_LOGI("test6-5"); + // ut5 RS has gpu inner + // RS -----VSYNCStart------------------End--- + // --------------gpuStart----gpuEnd---------- + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS = 2; + auto res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS, ITID); + EXPECT_TRUE(res); + + const uint32_t SOURCE_ITID1 = 2; + const uint32_t SOURCE_FRAME_NUM = 1; + const uint64_t UNI_TS = 3; + std::vector frames; + frames.push_back({SOURCE_ITID1, SOURCE_FRAME_NUM}); + streamFilters_.frameFilter_->BeginProcessCommandUni(UNI_TS, ITID, frames, 0); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + EXPECT_TRUE((streamFilters_.frameFilter_->vsyncRenderSlice_[ITID].begin()->get()->isRsMainThread_ == true)); + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Srcs()[0].empty() == true); +} + +/** + * @tc.name: RSVsyncHasGpuCross + * @tc.desc: RS's vsync event has gpu + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, RSVsyncHasGpuCross, TestSize.Level1) +{ + TS_LOGI("test6-6"); + // ut6 RS has gpu later + // RS -----VSYNCStart------------------End------------ + // ------------------------------gpuStart----gpuEnd--- + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS = 2; + auto res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS, ITID); + EXPECT_TRUE(res); + const uint64_t GPU_START_TS = 3; + streamFilters_.frameFilter_->StartFrameQueue(GPU_START_TS, ITID); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + + const uint64_t GPU_END_TS = 15; + res = streamFilters_.frameFilter_->EndFrameQueue(GPU_END_TS, ITID); + + EXPECT_TRUE(res); + EXPECT_TRUE((streamFilters_.frameFilter_->vsyncRenderSlice_[ITID].begin()->get()->isRsMainThread_ == true)); + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Durs()[0] == GPU_END_TS - START_TS); +} + +/** + * @tc.name: RSVsyncHasGpu2Slices + * @tc.desc: RS's vsync event has gpu, two slice across + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, RSVsyncHasGpu2Slices, TestSize.Level1) +{ + TS_LOGI("test6-7"); + // ut7 RS two slice across + // RS -----VSYNCStart------------------End-----VSYNCStart------------------End-------- + // --------------gpuStart------------------------------gpuEnd---------gpuStart----gpuEnd------ + + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS = 2; + auto res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS, ITID); + EXPECT_TRUE(res); + const uint64_t GPU_START_TS = 3; + streamFilters_.frameFilter_->StartFrameQueue(GPU_START_TS, ITID); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + + const uint64_t START_TS2 = 4; + const uint64_t EXPECTED_START2 = 6; + const uint64_t EXPECTED_END2 = 11; + const uint32_t VSYNC_ID2 = 2; + const uint32_t CALLSTACK_SLICE_ID2 = 2; + + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS2, IPID, ITID, EXPECTED_START2, EXPECTED_END2, VSYNC_ID2, + CALLSTACK_SLICE_ID2); + const uint64_t ONVSYNC_TS2 = 5; + res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS2, ITID); + EXPECT_TRUE(res); + + const uint64_t GPU_END_TS = 15; + res = streamFilters_.frameFilter_->EndFrameQueue(GPU_END_TS, ITID); + + const uint64_t GPU_START_TS2 = 16; + streamFilters_.frameFilter_->StartFrameQueue(GPU_START_TS2, ITID); + const uint64_t END_TS2 = 18; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS2, ITID); + + const uint64_t GPU_END_TS2 = 20; + res = streamFilters_.frameFilter_->EndFrameQueue(GPU_END_TS2, ITID); + + EXPECT_TRUE(res); + EXPECT_TRUE((streamFilters_.frameFilter_->vsyncRenderSlice_[ITID].begin()->get()->isRsMainThread_ == true)); + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Durs()[0] == GPU_END_TS - START_TS); + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Durs()[2] == GPU_END_TS2 - START_TS2); + EXPECT_TRUE(streamFilters_.frameFilter_->vsyncRenderSlice_.size() == 1); +} + +/** + * @tc.name: RSVsyncHasGpu2Slices + * @tc.desc: RS's vsync event has gpu, two slice across + * @tc.type: FUNC + */ +HWTEST_F(FrameFilterTest, SliceFromAppToRS, TestSize.Level1) +{ + TS_LOGI("test6-8"); + // ut8 + // slice from app to RS + // app -----VSYNCStart------------------End--- + // -----------------frameNum-------------- + // RS -------------------------VSYNCStart------------------End-----VSYNCStart------------------End----------------- + // -----------------------------------gpuStart------------------------------gpuEnd---------gpuStart----gpuEnd------ + const uint64_t START_TS = 1; + const uint32_t IPID = 1; + const uint32_t ITID = 1; + const uint64_t EXPECTED_START = 5; + const uint64_t EXPECTED_END = 10; + const uint32_t VSYNC_ID = 1; + const uint32_t CALLSTACK_SLICE_ID = 1; + uint64_t vsyncStartTs = 1; + streamFilters_.frameFilter_->BeginVsyncEvent(START_TS, IPID, ITID, EXPECTED_START, EXPECTED_END, VSYNC_ID, + CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS = 2; + const uint32_t FRAME_NUM = 1; + auto res = streamFilters_.frameFilter_->BeginRSTransactionData(ONVSYNC_TS, ITID, FRAME_NUM); + EXPECT_TRUE(res); + + const uint64_t RS_START_TS = 5; + const uint32_t RS_IPID = 2; + const uint32_t RS_ITID = 2; + const uint64_t RS_EXPECTED_START = 6; + const uint64_t RS_EXPECTED_END = 11; + const uint32_t RS_VSYNC_ID = 2; + const uint32_t RS_CALLSTACK_SLICE_ID = 2; + streamFilters_.frameFilter_->BeginVsyncEvent(RS_START_TS, RS_IPID, RS_ITID, RS_EXPECTED_START, RS_EXPECTED_END, + RS_VSYNC_ID, RS_CALLSTACK_SLICE_ID); + const uint64_t ONVSYNC_TS2 = 7; + res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS2, RS_ITID); + const uint64_t GPU_START_TS2 = 7; + streamFilters_.frameFilter_->StartFrameQueue(GPU_START_TS2, RS_ITID); + const uint64_t END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS, ITID); + EXPECT_TRUE(res); + + const uint64_t RS_END_TS = 10; + res = streamFilters_.frameFilter_->EndVsyncEvent(RS_END_TS, RS_ITID); + + const uint64_t RS_START_TS2 = 11; + const uint64_t RS_EXPECTED_START2 = 11; + const uint64_t RS_EXPECTED_END2 = 25; + const uint32_t RS_VSYNC_ID2 = 3; + const uint32_t RS_CALLSTACK_SLICE_ID2 = 3; + streamFilters_.frameFilter_->BeginVsyncEvent(RS_START_TS2, RS_IPID, RS_ITID, RS_EXPECTED_START2, RS_EXPECTED_END2, + RS_VSYNC_ID2, RS_CALLSTACK_SLICE_ID2); + const uint64_t ONVSYNC_TS3 = 12; + res = streamFilters_.frameFilter_->MarkRSOnvsyncEvent(ONVSYNC_TS3, RS_ITID); + + const uint64_t GPU_END_TS = 15; + res = streamFilters_.frameFilter_->EndFrameQueue(GPU_END_TS, RS_ITID); + + const uint64_t GPU_START_TS3 = 16; + streamFilters_.frameFilter_->StartFrameQueue(GPU_START_TS3, RS_ITID); + const uint64_t END_TS3 = 20; + res = streamFilters_.frameFilter_->EndVsyncEvent(END_TS3, RS_ITID); + + const uint64_t GPU_END_TS3 = 25; + res = streamFilters_.frameFilter_->EndFrameQueue(GPU_END_TS3, RS_ITID); + + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Durs()[0] == END_TS - START_TS); + EXPECT_TRUE(traceDataCache_.GetFrameSliceData()->Durs()[2] == GPU_END_TS - RS_START_TS); + EXPECT_TRUE(atoi(traceDataCache_.GetFrameSliceData()->Srcs()[2].c_str()) == + traceDataCache_.GetFrameSliceData()->IdsData()[0]); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/hidump_parser_test.cpp b/trace_streamer/test/unittest/hidump_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8b51931a70fe144aaf9b80ecf68107dfebf3032 --- /dev/null +++ b/trace_streamer/test/unittest/hidump_parser_test.cpp @@ -0,0 +1,160 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_hidump_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HidumpParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() + { + if (access(dbPath_.c_str(), F_OK) == 0) { + remove(dbPath_.c_str()); + } + } + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; + +/** + * @tc.name: ParseEmptyHidumpInfo + * @tc.desc: Parse an empty HidumpInfo + * @tc.type: FUNC + */ +HWTEST_F(HidumpParserTest, ParseEmptyHidumpInfo, TestSize.Level1) +{ + TS_LOGI("test7-1"); + HidumpInfo hidumpInfo; + HtraceHidumpParser htraceHidumpParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHidumpParser.Parse(hidumpInfo); + auto size = stream_.traceDataCache_->GetConstHidumpData().Size(); + EXPECT_EQ(0, size); +} + +/** + * @tc.name: ParseLegalHidumpInfo + * @tc.desc: Parse a legal HidumpInfo + * @tc.type: FUNC + */ +HWTEST_F(HidumpParserTest, ParseLegalHidumpInfo, TestSize.Level1) +{ + TS_LOGI("test7-2"); + const uint32_t FPS = 120; + const uint32_t TV_SEC = 16326755; + const uint32_t TV_NSEC = 39656070; + + FpsData_TimeSpec timeSpec; + timeSpec.set_tv_nsec(TV_NSEC); + timeSpec.set_tv_sec(TV_SEC); + + HidumpInfo* hidumpInfo = new HidumpInfo(); + auto fpsData = hidumpInfo->add_fps_event(); + fpsData->set_fps(FPS); + fpsData->set_allocated_time(&timeSpec); + + HtraceHidumpParser htraceHidumpParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHidumpParser.Parse(*hidumpInfo); + + auto Fps = stream_.traceDataCache_->GetConstHidumpData().Fpss()[0]; + EXPECT_EQ(FPS, Fps); + auto TimeSpec = stream_.traceDataCache_->GetConstHidumpData().TimeStampData()[0]; + EXPECT_EQ((TV_NSEC + TV_SEC * SEC_TO_NS), TimeSpec); + auto Size = stream_.traceDataCache_->GetConstHidumpData().Size(); + EXPECT_EQ(1, Size); +} + +/** + * @tc.name: ParseMultipleReasonableHidumpInfo + * @tc.desc: parse multiple reasonable HidumpInfo + * @tc.type: FUNC + */ +HWTEST_F(HidumpParserTest, ParseMultipleReasonableHidumpInfo, TestSize.Level1) +{ + TS_LOGI("test7-3"); + const uint32_t FPS_00 = 120; + const uint32_t TV_SEC_00 = 1632675525; + const uint32_t TV_NSEC_00 = 996560700; + FpsData_TimeSpec timeSpecFirst; + timeSpecFirst.set_tv_nsec(TV_NSEC_00); + timeSpecFirst.set_tv_sec(TV_SEC_00); + + const uint32_t FPS_01 = 60; + const uint32_t TV_SEC_01 = 1632675525; + const uint32_t TV_NSEC_01 = 996560700; + FpsData_TimeSpec timeSpecSecond; + timeSpecSecond.set_tv_nsec(TV_NSEC_01); + timeSpecSecond.set_tv_sec(TV_SEC_01); + + const uint32_t FPS_02 = 90; + const uint32_t TV_SEC_02 = 1632688888; + const uint32_t TV_NSEC_02 = 996588888; + FpsData_TimeSpec timeSpecThird; + timeSpecThird.set_tv_nsec(TV_NSEC_02); + timeSpecThird.set_tv_sec(TV_SEC_02); + + HidumpInfo* hidumpInfo = new HidumpInfo(); + auto fpsDataFirst = hidumpInfo->add_fps_event(); + fpsDataFirst->set_fps(FPS_00); + fpsDataFirst->set_allocated_time(&timeSpecFirst); + + auto fpsDataSecond = hidumpInfo->add_fps_event(); + fpsDataSecond->set_fps(FPS_01); + fpsDataSecond->set_allocated_time(&timeSpecSecond); + + auto fpsDataThird = hidumpInfo->add_fps_event(); + fpsDataThird->set_fps(FPS_02); + fpsDataThird->set_allocated_time(&timeSpecThird); + + HtraceHidumpParser htraceHidumpParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHidumpParser.Parse(*hidumpInfo); + + auto Fps_00 = stream_.traceDataCache_->GetConstHidumpData().Fpss()[0]; + auto Fps_01 = stream_.traceDataCache_->GetConstHidumpData().Fpss()[1]; + auto Fps_02 = stream_.traceDataCache_->GetConstHidumpData().Fpss()[2]; + EXPECT_EQ(FPS_00, Fps_00); + EXPECT_EQ(FPS_01, Fps_01); + EXPECT_EQ(FPS_02, Fps_02); + + auto TimeSpec_00 = stream_.traceDataCache_->GetConstHidumpData().TimeStampData()[0]; + auto TimeSpec_01 = stream_.traceDataCache_->GetConstHidumpData().TimeStampData()[1]; + auto TimeSpec_02 = stream_.traceDataCache_->GetConstHidumpData().TimeStampData()[2]; + EXPECT_EQ((TV_NSEC_00 + TV_SEC_00 * SEC_TO_NS), TimeSpec_00); + EXPECT_EQ((TV_NSEC_01 + TV_SEC_01 * SEC_TO_NS), TimeSpec_01); + EXPECT_EQ((TV_NSEC_02 + TV_SEC_02 * SEC_TO_NS), TimeSpec_02); + + auto Size = stream_.traceDataCache_->GetConstHidumpData().Size(); + EXPECT_EQ(3, Size); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/hilog_parser_test.cpp b/trace_streamer/test/unittest/hilog_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aafa4b115da21dd4bcbacf654670e651ea4f580f --- /dev/null +++ b/trace_streamer/test/unittest/hilog_parser_test.cpp @@ -0,0 +1,359 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_hilog_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HilogParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseHilogInfoWithoutHilogLine + * @tc.desc: Parse a HilogInfo that does not contain any hiloglines + * @tc.type: FUNC + */ +HWTEST_F(HilogParserTest, ParseHilogInfoWithoutHilogLine, TestSize.Level1) +{ + TS_LOGI("test8-1"); + HilogInfo* hilogInfo = new HilogInfo(); + HtraceHiLogParser htraceHiLogParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHiLogParser.Parse(*hilogInfo); + auto size = stream_.traceDataCache_->GetConstHilogData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHilogInfoWithOneHilogLine + * @tc.desc: Parse a HilogInfo with only one Hilogline + * @tc.type: FUNC + */ +HWTEST_F(HilogParserTest, ParseHilogInfoWithOneHilogLine, TestSize.Level1) +{ + TS_LOGI("test8-2"); + const uint64_t TV_SEC = 1632675525; + const uint64_t TV_NSEC = 996560700; + const std::string LOG_TAG = "HwMSDPMovementService"; + const std::string LOG_CONTEXT = "handleGetSupportedModule"; + const uint32_t LOG_LEVEL_D = 68; + const uint32_t PID = 2716; + const uint32_t TID = 1532; + const uint64_t LOG_ID = 1; + + HilogDetails* hilogDetails = new HilogDetails(); + hilogDetails->set_tv_sec(TV_SEC); + hilogDetails->set_tv_nsec(TV_NSEC); + hilogDetails->set_pid(PID); + hilogDetails->set_tid(TID); + hilogDetails->set_level(LOG_LEVEL_D); + hilogDetails->set_tag(LOG_TAG); + + HilogInfo* hilogInfo = new HilogInfo(); + auto hilogLine = hilogInfo->add_info(); + hilogLine->set_allocated_detail(hilogDetails); + hilogLine->set_context(LOG_CONTEXT); + hilogLine->set_id(LOG_ID); + + HtraceHiLogParser htraceHiLogParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHiLogParser.Parse(*hilogInfo); + + auto seq = stream_.traceDataCache_->GetConstHilogData().HilogLineSeqs()[0]; + EXPECT_EQ(seq, LOG_ID); + + auto timeStamp = stream_.traceDataCache_->GetConstHilogData().TimeStampData()[0]; + EXPECT_EQ(timeStamp, (TV_NSEC + TV_SEC * SEC_TO_NS)); + + auto pid = stream_.traceDataCache_->GetConstHilogData().Pids()[0]; + EXPECT_EQ(pid, PID); + + auto tid = stream_.traceDataCache_->GetConstHilogData().Tids()[0]; + EXPECT_EQ(tid, TID); + + auto level = stream_.traceDataCache_->GetConstHilogData().Levels()[0]; + auto iter = htraceHiLogParser.logLevelString_.find(LOG_LEVEL_D); + if (iter == htraceHiLogParser.logLevelString_.end()) { + EXPECT_FALSE(0); + } + DataIndex levelDIndex = stream_.traceDataCache_->dataDict_.GetStringIndex(iter->second.c_str()); + EXPECT_EQ(level, levelDIndex); + + auto readTagIndex = stream_.traceDataCache_->GetConstHilogData().Tags()[0]; + DataIndex writeTagIndex = stream_.traceDataCache_->dataDict_.GetStringIndex(LOG_TAG); + EXPECT_EQ(readTagIndex, writeTagIndex); + + auto readContextIndex = stream_.traceDataCache_->GetConstHilogData().Contexts()[0]; + DataIndex writeContextIndex = stream_.traceDataCache_->dataDict_.GetStringIndex(LOG_CONTEXT); + EXPECT_EQ(readContextIndex, writeContextIndex); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseHilogInfoWithMultipleHilogLine + * @tc.desc: Parse a HilogInfo with multiple Hiloglines + * @tc.type: FUNC + */ +HWTEST_F(HilogParserTest, ParseHilogInfoWithMultipleHilogLine, TestSize.Level1) +{ + TS_LOGI("test8-3"); + const uint64_t TV_SEC_01 = 1632675525; + const uint64_t TV_NSEC_01 = 996560700; + const uint32_t PID_01 = 2716; + const uint32_t TID_01 = 1532; + const uint32_t LOG_LEVEL_D = 68; + const std::string LOG_TAG_01 = "HwMSDPMovementService"; + const std::string LOG_CONTEXT_01 = "handleGetSupportedModule"; + const uint64_t LOG_ID_01 = 1; + + HilogDetails* hilogDetailsFirst = new HilogDetails(); + hilogDetailsFirst->set_tv_sec(TV_SEC_01); + hilogDetailsFirst->set_tv_nsec(TV_NSEC_01); + hilogDetailsFirst->set_pid(PID_01); + hilogDetailsFirst->set_tid(TID_01); + hilogDetailsFirst->set_level(LOG_LEVEL_D); + hilogDetailsFirst->set_tag(LOG_TAG_01); + + const uint64_t TV_SEC_02 = 1632688888; + const uint64_t TV_NSEC_02 = 996588888; + const uint32_t PID_02 = 2532; + const uint32_t TID_02 = 1716; + const uint32_t LOG_LEVEL_E = 69; + const std::string LOG_TAG_02 = "ProfilerService"; + const std::string LOG_CONTEXT_02 = "POST_RECV_MESSAGE method: /IProfilerService/CreateSession"; + const uint64_t LOG_ID_02 = 2; + + HilogDetails* hilogDetailsSecond = new HilogDetails(); + hilogDetailsSecond->set_tv_sec(TV_SEC_02); + hilogDetailsSecond->set_tv_nsec(TV_NSEC_02); + hilogDetailsSecond->set_pid(PID_02); + hilogDetailsSecond->set_tid(TID_02); + hilogDetailsSecond->set_level(LOG_LEVEL_E); + hilogDetailsSecond->set_tag(LOG_TAG_02); + + HilogInfo* hilogInfo = new HilogInfo(); + auto hilogLineFirst = hilogInfo->add_info(); + hilogLineFirst->set_allocated_detail(hilogDetailsFirst); + hilogLineFirst->set_context(LOG_CONTEXT_01); + hilogLineFirst->set_id(LOG_ID_01); + + auto hilogLineSecond = hilogInfo->add_info(); + hilogLineSecond->set_allocated_detail(hilogDetailsSecond); + hilogLineSecond->set_context(LOG_CONTEXT_02); + hilogLineSecond->set_id(LOG_ID_02); + + HtraceHiLogParser htraceHiLogParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHiLogParser.Parse(*hilogInfo); + + auto seqFirst = stream_.traceDataCache_->GetConstHilogData().HilogLineSeqs()[0]; + auto seqSecond = stream_.traceDataCache_->GetConstHilogData().HilogLineSeqs()[1]; + EXPECT_EQ(seqFirst, LOG_ID_01); + EXPECT_EQ(seqSecond, LOG_ID_02); + + auto timestampFirst = stream_.traceDataCache_->GetConstHilogData().TimeStampData()[0]; + auto timestampSecond = stream_.traceDataCache_->GetConstHilogData().TimeStampData()[1]; + EXPECT_EQ(timestampFirst, (TV_NSEC_01 + TV_SEC_01 * SEC_TO_NS)); + EXPECT_EQ(timestampSecond, (TV_NSEC_02 + TV_SEC_02 * SEC_TO_NS)); + + auto pidFirst = stream_.traceDataCache_->GetConstHilogData().Pids()[0]; + auto pidSecond = stream_.traceDataCache_->GetConstHilogData().Pids()[1]; + EXPECT_EQ(pidFirst, PID_01); + EXPECT_EQ(pidSecond, PID_02); + + auto tidFirst = stream_.traceDataCache_->GetConstHilogData().Tids()[0]; + auto tidSecond = stream_.traceDataCache_->GetConstHilogData().Tids()[1]; + EXPECT_EQ(tidFirst, TID_01); + EXPECT_EQ(tidSecond, TID_02); + + auto levelFirst = stream_.traceDataCache_->GetConstHilogData().Levels()[0]; + auto iterFirst = htraceHiLogParser.logLevelString_.find(LOG_LEVEL_D); + if (iterFirst == htraceHiLogParser.logLevelString_.end()) { + EXPECT_FALSE(0); + } + DataIndex levelDIndex = stream_.traceDataCache_->dataDict_.GetStringIndex(iterFirst->second.c_str()); + EXPECT_EQ(levelFirst, levelDIndex); + + auto levelSecond = stream_.traceDataCache_->GetConstHilogData().Levels()[1]; + auto iterSecond = htraceHiLogParser.logLevelString_.find(LOG_LEVEL_E); + if (iterSecond == htraceHiLogParser.logLevelString_.end()) { + EXPECT_FALSE(0); + } + DataIndex levelEIndex = stream_.traceDataCache_->dataDict_.GetStringIndex(iterSecond->second.c_str()); + EXPECT_EQ(levelSecond, levelEIndex); + + auto readTagIndexFirst = stream_.traceDataCache_->GetConstHilogData().Tags()[0]; + auto readTagIndexSecond = stream_.traceDataCache_->GetConstHilogData().Tags()[1]; + DataIndex writeTagIndexFirst = stream_.traceDataCache_->dataDict_.GetStringIndex(LOG_TAG_01); + DataIndex writeTagIndexSecond = stream_.traceDataCache_->dataDict_.GetStringIndex(LOG_TAG_02); + EXPECT_EQ(readTagIndexFirst, writeTagIndexFirst); + EXPECT_EQ(readTagIndexSecond, writeTagIndexSecond); + + auto readContextIndexFirst = stream_.traceDataCache_->GetConstHilogData().Contexts()[0]; + auto readContextIndexSecond = stream_.traceDataCache_->GetConstHilogData().Contexts()[1]; + DataIndex writeContextIndexFirst = stream_.traceDataCache_->dataDict_.GetStringIndex(LOG_CONTEXT_01); + DataIndex writeContextIndexSecond = stream_.traceDataCache_->dataDict_.GetStringIndex(LOG_CONTEXT_02); + EXPECT_EQ(readContextIndexFirst, writeContextIndexFirst); + EXPECT_EQ(readContextIndexSecond, writeContextIndexSecond); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseHilogInfoWithErrLevelHilogLine + * @tc.desc: Parse a HilogInfo with error level Hiloglines + * @tc.type: FUNC + */ +HWTEST_F(HilogParserTest, ParseHilogInfoWithErrLevelHilogLine, TestSize.Level1) +{ + TS_LOGI("test8-4"); + const uint64_t TV_SEC = 1632675525; + const uint64_t TV_NSEC = 996560700; + const std::string LOG_TAG = "HwMSDPMovementService"; + const std::string LOG_CONTEXT = "handleGetSupportedModule"; + const uint32_t LOG_LEVEL_ILLEGAL = 0; + const uint32_t PID = 2716; + const uint32_t TID = 1532; + const uint64_t LOG_ID = 1; + + HilogDetails* hilogDetails = new HilogDetails(); + hilogDetails->set_tv_sec(TV_SEC); + hilogDetails->set_tv_nsec(TV_NSEC); + hilogDetails->set_pid(PID); + hilogDetails->set_tid(TID); + hilogDetails->set_level(LOG_LEVEL_ILLEGAL); + hilogDetails->set_tag(LOG_TAG); + + HilogInfo* hilogInfo = new HilogInfo(); + auto hilogLine = hilogInfo->add_info(); + hilogLine->set_allocated_detail(hilogDetails); + hilogLine->set_context(LOG_CONTEXT); + hilogLine->set_id(LOG_ID); + + HtraceHiLogParser htraceHiLogParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHiLogParser.Parse(*hilogInfo); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_DATA_INVALID); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseHilogInfoLostHilogLine + * @tc.desc: Parse a HilogInfo that lost a Hiloglines + * @tc.type: FUNC + */ +HWTEST_F(HilogParserTest, ParseHilogInfoLostHilogLine, TestSize.Level1) +{ + TS_LOGI("test8-5"); + const uint64_t TV_SEC = 1632675525; + const uint64_t TV_NSEC = 996560700; + const std::string LOG_TAG = "HwMSDPMovementService"; + const std::string LOG_CONTEXT = "handleGetSupportedModule"; + const uint32_t LOG_LEVEL_D = 68; + const uint32_t PID = 2716; + const uint32_t TID = 1532; + const uint64_t LOG_ID = 2; + + HilogDetails* hilogDetails = new HilogDetails(); + hilogDetails->set_tv_sec(TV_SEC); + hilogDetails->set_tv_nsec(TV_NSEC); + hilogDetails->set_pid(PID); + hilogDetails->set_tid(TID); + hilogDetails->set_level(LOG_LEVEL_D); + hilogDetails->set_tag(LOG_TAG); + + HilogInfo* hilogInfo = new HilogInfo(); + auto hilogLine = hilogInfo->add_info(); + hilogLine->set_allocated_detail(hilogDetails); + hilogLine->set_context(LOG_CONTEXT); + hilogLine->set_id(LOG_ID); + + HtraceHiLogParser htraceHiLogParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHiLogParser.Parse(*hilogInfo); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_DATA_LOST); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseHilogInfoHasDuplicateHilogLine + * @tc.desc: Parse a HilogInfo has duplicate HilogLine + * @tc.type: FUNC + */ +HWTEST_F(HilogParserTest, ParseHilogInfoHasDuplicateHilogLine, TestSize.Level1) +{ + TS_LOGI("test8-6"); + const uint64_t TV_SEC = 1632675525; + const uint64_t TV_NSEC = 996560700; + const std::string LOG_TAG = "HwMSDPMovementService"; + const std::string LOG_CONTEXT = "handleGetSupportedModule"; + const uint32_t LOG_LEVEL_D = 68; + const uint32_t PID = 2716; + const uint32_t TID = 1532; + const uint64_t LOG_ID = 1; + + HilogDetails* hilogDetails = new HilogDetails(); + hilogDetails->set_tv_sec(TV_SEC); + hilogDetails->set_tv_nsec(TV_NSEC); + hilogDetails->set_pid(PID); + hilogDetails->set_tid(TID); + hilogDetails->set_level(LOG_LEVEL_D); + hilogDetails->set_tag(LOG_TAG); + + HilogInfo* hilogInfo = new HilogInfo(); + auto hilogLineFirst = hilogInfo->add_info(); + hilogLineFirst->set_allocated_detail(hilogDetails); + hilogLineFirst->set_context(LOG_CONTEXT); + hilogLineFirst->set_id(LOG_ID); + auto hilogLineSecond = hilogInfo->add_info(); + hilogLineSecond->set_allocated_detail(hilogDetails); + hilogLineSecond->set_context(LOG_CONTEXT); + hilogLineSecond->set_id(LOG_ID); + + HtraceHiLogParser htraceHiLogParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceHiLogParser.Parse(*hilogInfo); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_HILOG, STAT_EVENT_NOTMATCH); + EXPECT_TRUE(1 == eventCount); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test/unittest/hisys_event_parser_test.cpp b/trace_streamer/test/unittest/hisys_event_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..32faf5598d70387d0fcfe884aab641439306f34d --- /dev/null +++ b/trace_streamer/test/unittest/hisys_event_parser_test.cpp @@ -0,0 +1,184 @@ +/* + * 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 +#include + +#include "htrace_hisysevent_parser.h" +#include "string_to_numerical.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class HtraceHisysEventParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; +namespace base { +auto num0 = SysTuning::base::number(15, SysTuning::base::INTEGER_RADIX_TYPE_DEC); +auto num1 = SysTuning::base::number(15, SysTuning::base::INTEGER_RADIX_TYPE_HEX); +} // namespace base +/** + * @tc.name: ParseNoArray + * @tc.desc: Parse a piece of data without array + * @tc.type: FUNC + */ +HWTEST_F(HtraceHisysEventParserTest, ParseNoArray, TestSize.Level1) +{ + TS_LOGI("test9-1"); + std::string jsMessage = + "{\"domain_\":\"POWERTHERMAL\",\"name_\":\"POWER_IDE_BATTERY\",\"type_\":1,\"time_\":22611696002,\"tz_\":\"+" + "0000\",\"pid_\":722,\"tid_\":3462,\"uid_\":1201,\"START_TIME\":22611696002,\"END_TIME\":23617705010,\"GAS_" + "GAUGE\":124,\"LEVEL\":33,\"SCREEN\":11,\"CHARGE\":21,\"CURRENT\":-404,\"CAPACITY\":9898,\"level_\":\"MINOR\"," + "\"id_\":\"16494176919818340149\",\"info_\":\"\"}"; + HtraceHisyseventParser::json jMessage; + HtraceHisyseventParser::JsonData jData; + size_t maxArraySize = 0; + uint64_t serial = 1; + std::vector noArrayIndex; + std::vector arrayIndex; + std::stringstream ss; + ss << jsMessage; + ss >> jMessage; + HtraceHisyseventParser HisysEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + HisysEvent.JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex); + EXPECT_TRUE(jData.eventSource == "POWER_IDE_BATTERY"); + EXPECT_EQ(jData.timeStamp, 22611696002); + EXPECT_EQ(maxArraySize, 0); + EXPECT_EQ(noArrayIndex.size(), 17); + EXPECT_EQ(arrayIndex.size(), 0); + DataIndex eventSourceIndex = stream_.traceDataCache_->GetDataIndex(jData.eventSource); + HisysEvent.CommonDataParser(jData, eventSourceIndex, serial); + auto size = stream_.traceDataCache_->GetConstSyseventMeasureData().Size(); + EXPECT_EQ(size, 17); + auto anticipate = stream_.traceDataCache_->GetConstSyseventMeasureData().Serial()[0]; + EXPECT_EQ(anticipate, serial); + EXPECT_TRUE(base::num0 == "15"); + EXPECT_TRUE(base::num1 == "f"); +} +/** + * @tc.name: ParseHaveArrayData + * @tc.desc: Parse a piece of data with array + * @tc.type: FUNC + */ +HWTEST_F(HtraceHisysEventParserTest, ParseHaveArrayData, TestSize.Level1) +{ + TS_LOGI("test9-2"); + std::string jsMessage = + "{\"domain_\":\"POWERTHERMAL\",\"name_\":\"POWER_IDE_WIFISCAN\",\"type_\":2,\"time_\":16611696002,\"tz_\":\"+" + "0000\",\"pid_\":722,\"tid_\":17827,\"uid_\":1201,\"START_TIME\":1661783047454,\"END_TIME\":1661783050455," + "\"COUNT\":1,\"APPNAME\":[\"com.ohos.settings\",\"com.ohos.settings_js\",\"com.ohos.settings_app\"]," + "\"FOREGROUND_COUNT\":[43,41,65],\"FOREGROUND_ENERGY\":[120,134,532],\"BACKGROUND_COUNT\":[27,856,378]," + "\"BACKGROUND_ENERGY\":[638,65,12],\"SCREEN_ON_COUNT\":[23,558,75],\"SCREEN_ON_ENERGY\":[552,142,120],\"SCREEN_" + "OFF_COUNT\":[78,354,21],\"SCREEN_OFF_ENERGY\":[352,65,436],\"level_\":\"MINOR\",\"id_\":" + "\"17560016619580787102\",\"info_\":\"\"}"; + HtraceHisyseventParser::json jMessage; + HtraceHisyseventParser::JsonData jData; + size_t maxArraySize = 0; + uint64_t serial = 1; + std::vector noArrayIndex; + std::vector arrayIndex; + std::stringstream ss; + ss << jsMessage; + ss >> jMessage; + HtraceHisyseventParser HisysEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + HisysEvent.JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex); + EXPECT_TRUE(jData.eventSource == "POWER_IDE_WIFISCAN"); + EXPECT_EQ(jData.timeStamp, 16611696002); + EXPECT_EQ(maxArraySize, 3); + EXPECT_EQ(noArrayIndex.size(), 12); + EXPECT_EQ(arrayIndex.size(), 9); + DataIndex eventSourceIndex = stream_.traceDataCache_->GetDataIndex(jData.eventSource); + HisysEvent.NoArrayDataParse(jData, noArrayIndex, eventSourceIndex, serial); + HisysEvent.ArrayDataParse(jData, arrayIndex, eventSourceIndex, maxArraySize, serial); + auto size = stream_.traceDataCache_->GetConstSyseventMeasureData().Size(); + EXPECT_EQ(size, (9 * 3 + 12)); + auto anticipate = stream_.traceDataCache_->GetConstSyseventMeasureData().Serial()[0]; + EXPECT_EQ(anticipate, serial); +} +/** + * @tc.name: MixedDataAnalysis + * @tc.desc: Mixed data analysis + * @tc.type: FUNC + */ +HWTEST_F(HtraceHisysEventParserTest, MixedDataAnalysis, TestSize.Level1) +{ + TS_LOGI("test9-3"); + std::string jsMessage1 = + "{\"domain_\":\"POWERTHERMAL\",\"name_\":\"POWER_IDE_BATTERY\",\"type_\":1,\"time_\":22611696002,\"tz_\":\"+" + "0000\",\"pid_\":722,\"tid_\":3462,\"uid_\":1201,\"START_TIME\":22611696002,\"END_TIME\":23617705010,\"GAS_" + "GAUGE\":124,\"LEVEL\":33,\"SCREEN\":11,\"CHARGE\":21,\"CURRENT\":-404,\"CAPACITY\":9898,\"level_\":\"MINOR\"," + "\"id_\":\"16494176919818340149\",\"info_\":\"\"}"; + std::string jsMessage2 = + "{\"domain_\":\"POWERTHERMAL\",\"name_\":\"POWER_IDE_WIFISCAN\",\"type_\":2,\"time_\":16611696002,\"tz_\":\"+" + "0000\",\"pid_\":722,\"tid_\":17827,\"uid_\":1201,\"START_TIME\":1661783047454,\"END_TIME\":1661783050455," + "\"COUNT\":1,\"APPNAME\":[\"com.ohos.settings\",\"com.ohos.settings_js\",\"com.ohos.settings_app\"]," + "\"FOREGROUND_COUNT\":[43,41,65],\"FOREGROUND_ENERGY\":[120,134,532],\"BACKGROUND_COUNT\":[27,856,378]," + "\"BACKGROUND_ENERGY\":[638,65,12],\"SCREEN_ON_COUNT\":[23,558,75],\"SCREEN_ON_ENERGY\":[552,142,120],\"SCREEN_" + "OFF_COUNT\":[78,354,21],\"SCREEN_OFF_ENERGY\":[352,65,436],\"level_\":\"MINOR\",\"id_\":" + "\"17560016619580787102\",\"info_\":\"\"}"; + std::vector jsMessage; + jsMessage.push_back(jsMessage1); + jsMessage.push_back(jsMessage2); + uint64_t serial = 1; + for (auto i = jsMessage.begin(); i != jsMessage.end(); i++) { + HtraceHisyseventParser::json jMessage; + HtraceHisyseventParser::JsonData jData; + size_t maxArraySize = 0; + std::vector noArrayIndex; + std::vector arrayIndex; + std::stringstream ss; + ss << *i; + ss >> jMessage; + HtraceHisyseventParser HisysEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + HisysEvent.JGetData(jMessage, jData, maxArraySize, noArrayIndex, arrayIndex); + if (jData.eventSource == "POWER_IDE_WIFISCAN") { + EXPECT_TRUE(jData.eventSource == "POWER_IDE_WIFISCAN"); + EXPECT_EQ(jData.timeStamp, 16611696002); + EXPECT_EQ(maxArraySize, 3); + EXPECT_EQ(noArrayIndex.size(), 12); + EXPECT_EQ(arrayIndex.size(), 9); + } else { + EXPECT_TRUE(jData.eventSource == "POWER_IDE_BATTERY"); + EXPECT_EQ(jData.timeStamp, 22611696002); + EXPECT_EQ(maxArraySize, 0); + EXPECT_EQ(noArrayIndex.size(), 17); + EXPECT_EQ(arrayIndex.size(), 0); + } + DataIndex eventSourceIndex = stream_.traceDataCache_->GetDataIndex(jData.eventSource); + if (maxArraySize) { + HisysEvent.NoArrayDataParse(jData, noArrayIndex, eventSourceIndex, serial); + HisysEvent.ArrayDataParse(jData, arrayIndex, eventSourceIndex, maxArraySize, serial); + } else { + HisysEvent.CommonDataParser(jData, eventSourceIndex, serial); + } + } + auto size = stream_.traceDataCache_->GetConstSyseventMeasureData().Size(); + EXPECT_EQ(size, 17 + (9 * 3 + 12)); + auto anticipate = stream_.traceDataCache_->GetConstSyseventMeasureData().Serial()[0]; + EXPECT_EQ(anticipate, serial); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_binder_event_test.cpp b/trace_streamer/test/unittest/htrace_binder_event_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d496226d614e714232053be570eca88a8aeb8343 --- /dev/null +++ b/trace_streamer/test/unittest/htrace_binder_event_test.cpp @@ -0,0 +1,514 @@ +/* + * 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 +#include + +#include "binder_filter.h" +#include "htrace_cpu_detail_parser.h" +#include "htrace_event_parser.h" +#include "trace_plugin_result.pb.h" +#include "trace_streamer_selector.h" +#include "ts_common.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class HtraceBinderEventTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: BinderSenderfilterNeedReply + * @tc.desc: Binary formate binder event test, The binder event needs reply + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderfilterNeedReply, TestSize.Level1) +{ + TS_LOGI("test10-1"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_); 0x01 + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 7); +} + +/** + * @tc.name: BinderSenderfilterNeedReplyAndReceive + * @tc.desc: Binary formate binder event test, The binder event needs reply and received reply + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderfilterNeedReplyAndReceive, TestSize.Level1) +{ + TS_LOGI("test10-2"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_); 0x01 + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 7); + + ts1 = 200; + uint32_t pid1 = 1; + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(0); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(pid1); + std::string appName2 = "app2"; + ftraceEvent2->set_comm(appName2); + BinderTransactionReceivedFormat* binderReceivedEvent = new BinderTransactionReceivedFormat(); + binderReceivedEvent->set_debug_id(transactionId1); + ftraceEvent2->set_allocated_binder_transaction_received_format(binderReceivedEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[1] == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 11); +} + +/** + * @tc.name: BinderSenderfilterNeedReplyAndReceiveWithAlloc + * @tc.desc: Binary formate BinderTransactionAllocBuf event test, The binder event needs reply and received reply + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderfilterNeedReplyAndReceiveWithAlloc, TestSize.Level1) +{ + TS_LOGI("test10-3"); + int64_t ts1 = 100; + std::string appName = "app1"; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 7); + + ts1 = 150; + uint64_t dataSize = 100; + uint64_t offsetSize = 200; + BinderTransactionAllocBufFormat* binderAllocEvent = new BinderTransactionAllocBufFormat(); + binderAllocEvent->set_data_size(dataSize); + binderAllocEvent->set_offsets_size(offsetSize); + + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(0); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_binder_transaction_alloc_buf_format(binderAllocEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 9); + + ts1 = 200; + uint32_t pid1 = 1; + FtraceCpuDetailMsg ftraceCpuDetail3; + ftraceCpuDetail3.set_cpu(0); + ftraceCpuDetail3.set_overwrite(0); + auto ftraceEvent3 = ftraceCpuDetail3.add_event(); + + ftraceEvent3->set_timestamp(ts1); + ftraceEvent3->set_tgid(pid1); + std::string appName2 = "app2"; + ftraceEvent3->set_comm(appName2); + BinderTransactionReceivedFormat* binderReceivedEvent = new BinderTransactionReceivedFormat(); + binderReceivedEvent->set_debug_id(transactionId1); + ftraceEvent3->set_allocated_binder_transaction_received_format(binderReceivedEvent); + eventParser.ParseDataItem(&ftraceCpuDetail3, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[1] == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 13); +} + +/** + * @tc.name: BinderSenderfilterNeedReplyAndReceiveNotmatch + * @tc.desc: Binary formate BinderTransaction event test, The binder event needs reply but received not match + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderfilterNeedReplyAndReceiveNotmatch, TestSize.Level1) +{ + TS_LOGI("test10-4"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x02; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + + ts1 = 200; + uint32_t pid1 = 1; + uint64_t transactionId2 = 2; + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(0); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(pid1); + std::string appName2 = "app2"; + ftraceEvent2->set_comm(appName2); + BinderTransactionReceivedFormat* binderReceivedEvent = new BinderTransactionReceivedFormat(); + binderReceivedEvent->set_debug_id(transactionId2); + ftraceEvent2->set_allocated_binder_transaction_received_format(binderReceivedEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); +} + +/** + * @tc.name: BinderSenderfilterNoNeedReply + * @tc.desc: Binary formate binder event test, The binder event needs no reply + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderfilterNoNeedReply, TestSize.Level1) +{ + TS_LOGI("test10-5"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); +} + +/** + * @tc.name: BinderSenderNoneedReplyAndReceivefilter + * @tc.desc: Binary formate binder event test, other party received and no need reply。 + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderNoneedReplyAndReceivefilter, TestSize.Level1) +{ + TS_LOGI("test10-6"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + + ts1 = 200; + uint32_t pid1 = 1; + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(0); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(pid1); + std::string appName2 = "app2"; + ftraceEvent2->set_comm(appName2); + BinderTransactionReceivedFormat* binderReceivedEvent = new BinderTransactionReceivedFormat(); + binderReceivedEvent->set_debug_id(transactionId1); + ftraceEvent2->set_allocated_binder_transaction_received_format(binderReceivedEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[1] == 0); +} + +/** + * @tc.name: BinderSenderNoneedReplyAndReceivefilterNotmatch + * @tc.desc: Binary formate binder event test, other party received but not match + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderNoneedReplyAndReceivefilterNotmatch, TestSize.Level1) +{ + TS_LOGI("test10-7"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = false; + uint32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + uint32_t code = 0; // not importent + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + + ts1 = 200; + uint32_t pid1 = 1; + uint64_t transactionId2 = 2; + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(0); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(pid1); + std::string appName2 = "app2"; + ftraceEvent2->set_comm(appName2); + BinderTransactionReceivedFormat* binderReceivedEvent = new BinderTransactionReceivedFormat(); + binderReceivedEvent->set_debug_id(transactionId2); + ftraceEvent2->set_allocated_binder_transaction_received_format(binderReceivedEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().ArgSetIdsData()[0] == 0); +} + +/** + * @tc.name: BinderSenderfilterWrongReply + * @tc.desc: Binary formate binder event test, other party replyed wrong Info + * @tc.type: FUNC + */ +HWTEST_F(HtraceBinderEventTest, BinderSenderfilterWrongReply, TestSize.Level1) +{ + TS_LOGI("test10-8"); + std::string appName = "app1"; + int64_t ts1 = 100; + uint32_t tid1 = 1; + uint64_t transactionId1 = 1; + int32_t destNode1 = 1; + int32_t destTgid1 = 2; + int32_t destTid1 = 3; + bool isReply = true; + uint32_t flags = 0x01; // if need reply bool needReply = !isReply && !(flags & noReturnMsgFlag_) + uint32_t code = 0; // not important + BinderTransactionFormat* binderEvent = new BinderTransactionFormat(); + binderEvent->set_to_proc(destTgid1); + binderEvent->set_target_node(destNode1); + binderEvent->set_to_thread(destTid1); + binderEvent->set_debug_id(transactionId1); + binderEvent->set_reply(static_cast(isReply)); + binderEvent->set_code(code); + binderEvent->set_flags(flags); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_binder_transaction_format(binderEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstInternalSlicesData().Size() == 0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstArgSetData().Size() == 0); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_cpu_data_parser_test.cpp b/trace_streamer/test/unittest/htrace_cpu_data_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3439ba6a0551da541d9ec030031d84d15e3fd7ac --- /dev/null +++ b/trace_streamer/test/unittest/htrace_cpu_data_parser_test.cpp @@ -0,0 +1,312 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_cpu_data_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceCpuDataParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() const {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseHtraceWithoutCpuDataData + * @tc.desc: Parse a cpu that does not contain any cpudata + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDataParserTest, ParseHtraceWithoutCpuData, TestSize.Level1) +{ + TS_LOGI("test11-1"); + uint64_t ts = 100; + auto cpuData = std::make_unique(); + HtraceCpuDataParser htraceCpuDataParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDataParser.Parse(*cpuData, ts); + auto size = stream_.traceDataCache_->GetConstCpuUsageInfoData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtraceWithOneCpuData + * @tc.desc: Parse a cpu with one cpudata + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDataParserTest, ParseHtraceWithOneCpuData, TestSize.Level1) +{ + TS_LOGI("test11-2"); + uint64_t ts = 102; + const uint64_t TOTAL_LOAD = 2; + const uint64_t USER_LOAD = 42; + const uint64_t SYSTEM_LOAD = 32; + const uint64_t PROCESS_NUM = 202; + + auto cpuDataInfo(std::make_unique()); + cpuDataInfo->set_total_load(TOTAL_LOAD); + cpuDataInfo->set_user_load(USER_LOAD); + cpuDataInfo->set_sys_load(SYSTEM_LOAD); + cpuDataInfo->set_process_num(PROCESS_NUM); + + HtraceCpuDataParser htraceCpuDataParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDataParser.Parse(*cpuDataInfo, ts); + htraceCpuDataParser.Finish(); + auto size = stream_.traceDataCache_->GetConstCpuUsageInfoData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtraceWithTwoCpuData + * @tc.desc: Parse a cpu with two cpudata + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDataParserTest, ParseHtraceWithTwoCpuData, TestSize.Level1) +{ + TS_LOGI("test11-3"); + uint64_t ts = 103; + const uint64_t TOTALLOAD_01 = 2; + const uint64_t USERLOAD_01 = 42; + const uint64_t SYSTEMLOAD_01 = 32; + const uint64_t PROCESS_NUM_01 = 202; + + const uint64_t TOTALLOAD_02 = 3; + const uint64_t USERLOAD_02 = 43; + const uint64_t SYSTEMLOAD_02 = 33; + const uint64_t PROCESS_NUM_02 = 203; + + CpuUsageInfo* cpuUsageInfo01 = new CpuUsageInfo(); + auto cpuDataInfo01(std::make_unique()); + cpuDataInfo01->set_allocated_cpu_usage_info(cpuUsageInfo01); + cpuDataInfo01->set_total_load(TOTALLOAD_01); + cpuDataInfo01->set_user_load(USERLOAD_01); + cpuDataInfo01->set_sys_load(SYSTEMLOAD_01); + cpuDataInfo01->set_process_num(PROCESS_NUM_01); + + HtraceCpuDataParser htraceCpuDataParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDataParser.Parse(*cpuDataInfo01, ts); + + CpuUsageInfo* cpuUsageInfo02 = new CpuUsageInfo(); + auto cpuDataInfo02(std::make_unique()); + cpuDataInfo02->set_allocated_cpu_usage_info(cpuUsageInfo02); + cpuDataInfo02->set_total_load(TOTALLOAD_02); + cpuDataInfo02->set_user_load(USERLOAD_02); + cpuDataInfo02->set_sys_load(SYSTEMLOAD_02); + cpuDataInfo02->set_process_num(PROCESS_NUM_02); + + htraceCpuDataParser.Parse(*cpuDataInfo02, ts); + htraceCpuDataParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstCpuUsageInfoData().Size(); + EXPECT_EQ(1, size); + + auto totalLoad = stream_.traceDataCache_->GetConstCpuUsageInfoData().TotalLoad()[0]; + EXPECT_EQ(totalLoad, TOTALLOAD_02); + + auto userLoad = stream_.traceDataCache_->GetConstCpuUsageInfoData().UserLoad()[0]; + EXPECT_EQ(userLoad, USERLOAD_02); + + auto systemLoad = stream_.traceDataCache_->GetConstCpuUsageInfoData().SystemLoad()[0]; + EXPECT_EQ(systemLoad, SYSTEMLOAD_02); +} + +/** + * @tc.name: ParseHtraceWithThreeCpuData + * @tc.desc: Parse a cpu with Three cpudata + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDataParserTest, ParseHtraceWithThreeCpuData, TestSize.Level1) +{ + TS_LOGI("test11-4"); + uint64_t ts = 104; + const uint64_t TOTALLOAD_01 = 4; + const uint64_t USERLOAD_01 = 44; + const uint64_t SYSTEMLOAD_01 = 34; + const uint64_t PROCESS_NUM_01 = 204; + + const uint64_t TOTALLOAD_02 = 5; + const uint64_t USERLOAD_02 = 45; + const uint64_t SYSTEMLOAD_02 = 35; + const uint64_t PROCESS_NUM_02 = 205; + + const uint64_t TOTALLOAD_03 = 6; + const uint64_t USERLOAD_03 = 46; + const uint64_t SYSTEMLOAD_03 = 36; + const uint64_t PROCESS_NUM_03 = 206; + + CpuUsageInfo* cpuUsageInfo01 = new CpuUsageInfo(); + auto cpuDataInfo01(std::make_unique()); + cpuDataInfo01->set_allocated_cpu_usage_info(cpuUsageInfo01); + cpuDataInfo01->set_total_load(TOTALLOAD_01); + cpuDataInfo01->set_user_load(USERLOAD_01); + cpuDataInfo01->set_sys_load(SYSTEMLOAD_01); + cpuDataInfo01->set_process_num(PROCESS_NUM_01); + + HtraceCpuDataParser htraceCpuDataParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDataParser.Parse(*cpuDataInfo01, ts); + + CpuUsageInfo* cpuUsageInfo02 = new CpuUsageInfo(); + auto cpuDataInfo02(std::make_unique()); + cpuDataInfo02->set_allocated_cpu_usage_info(cpuUsageInfo02); + cpuDataInfo02->set_total_load(TOTALLOAD_02); + cpuDataInfo02->set_user_load(USERLOAD_02); + cpuDataInfo02->set_sys_load(SYSTEMLOAD_02); + cpuDataInfo02->set_process_num(PROCESS_NUM_02); + + htraceCpuDataParser.Parse(*cpuDataInfo02, ts); + + CpuUsageInfo* cpuUsageInfo03 = new CpuUsageInfo(); + auto cpuDataInfo03(std::make_unique()); + cpuDataInfo03->set_allocated_cpu_usage_info(cpuUsageInfo03); + cpuDataInfo03->set_total_load(TOTALLOAD_03); + cpuDataInfo03->set_user_load(USERLOAD_03); + cpuDataInfo03->set_sys_load(SYSTEMLOAD_03); + cpuDataInfo03->set_process_num(PROCESS_NUM_03); + + htraceCpuDataParser.Parse(*cpuDataInfo03, ts); + htraceCpuDataParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstCpuUsageInfoData().Size(); + EXPECT_EQ(2, size); + + auto totalLoadFirst = stream_.traceDataCache_->GetConstCpuUsageInfoData().TotalLoad()[0]; + auto totalLoadSecond = stream_.traceDataCache_->GetConstCpuUsageInfoData().TotalLoad()[1]; + EXPECT_EQ(totalLoadFirst, TOTALLOAD_02); + EXPECT_EQ(totalLoadSecond, TOTALLOAD_03); + + auto userLoadFirst = stream_.traceDataCache_->GetConstCpuUsageInfoData().UserLoad()[0]; + auto userLoadSecond = stream_.traceDataCache_->GetConstCpuUsageInfoData().UserLoad()[1]; + EXPECT_EQ(userLoadFirst, USERLOAD_02); + EXPECT_EQ(userLoadSecond, USERLOAD_03); + + auto systemLoadFirst = stream_.traceDataCache_->GetConstCpuUsageInfoData().SystemLoad()[0]; + auto systemLoadSecond = stream_.traceDataCache_->GetConstCpuUsageInfoData().SystemLoad()[1]; + EXPECT_EQ(systemLoadFirst, SYSTEMLOAD_02); + EXPECT_EQ(systemLoadSecond, SYSTEMLOAD_03); +} + +/** + * @tc.name: ParseHtraceWithMultipleCpuData + * @tc.desc: Parse a CpuData with Multiple CpuData + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDataParserTest, ParseHtraceWithMultipleCpuData, TestSize.Level1) +{ + TS_LOGI("test11-5"); + uint64_t ts = 104; + const uint64_t TOTALLOAD_01 = 4; + const uint64_t USERLOAD_01 = 44; + const uint64_t SYSTEMLOAD_01 = 34; + const uint64_t PROCESS_NUM_01 = 204; + + const uint64_t TOTALLOAD_02 = 5; + const uint64_t USERLOAD_02 = 45; + const uint64_t SYSTEMLOAD_02 = 35; + const uint64_t PROCESS_NUM_02 = 205; + + const uint64_t TOTALLOAD_03 = 6; + const uint64_t USERLOAD_03 = 46; + const uint64_t SYSTEMLOAD_03 = 36; + const uint64_t PROCESS_NUM_03 = 206; + + const uint64_t TOTALLOAD_04 = 6; + const uint64_t USERLOAD_04 = 46; + const uint64_t SYSTEMLOAD_04 = 36; + const uint64_t PROCESS_NUM_04 = 206; + + CpuUsageInfo* cpuUsageInfo01 = new CpuUsageInfo(); + auto cpuDataInfo01(std::make_unique()); + cpuDataInfo01->set_allocated_cpu_usage_info(cpuUsageInfo01); + cpuDataInfo01->set_total_load(TOTALLOAD_01); + cpuDataInfo01->set_user_load(USERLOAD_01); + cpuDataInfo01->set_sys_load(SYSTEMLOAD_01); + cpuDataInfo01->set_process_num(PROCESS_NUM_01); + + HtraceCpuDataParser htraceCpuDataParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDataParser.Parse(*cpuDataInfo01, ts); + + CpuUsageInfo* cpuUsageInfo02 = new CpuUsageInfo(); + auto cpuDataInfo02(std::make_unique()); + cpuDataInfo02->set_allocated_cpu_usage_info(cpuUsageInfo02); + cpuDataInfo02->set_total_load(TOTALLOAD_02); + cpuDataInfo02->set_user_load(USERLOAD_02); + cpuDataInfo02->set_sys_load(SYSTEMLOAD_02); + cpuDataInfo02->set_process_num(PROCESS_NUM_02); + + htraceCpuDataParser.Parse(*cpuDataInfo02, ts); + + CpuUsageInfo* cpuUsageInfo03 = new CpuUsageInfo(); + auto cpuDataInfo03(std::make_unique()); + cpuDataInfo03->set_allocated_cpu_usage_info(cpuUsageInfo03); + cpuDataInfo03->set_total_load(TOTALLOAD_03); + cpuDataInfo03->set_user_load(USERLOAD_03); + cpuDataInfo03->set_sys_load(SYSTEMLOAD_03); + cpuDataInfo03->set_process_num(PROCESS_NUM_03); + + htraceCpuDataParser.Parse(*cpuDataInfo03, ts); + + CpuUsageInfo* cpuUsageInfo04 = new CpuUsageInfo(); + auto cpuDataInfo04(std::make_unique()); + cpuDataInfo04->set_allocated_cpu_usage_info(cpuUsageInfo04); + cpuDataInfo04->set_total_load(TOTALLOAD_04); + cpuDataInfo04->set_user_load(USERLOAD_04); + cpuDataInfo04->set_sys_load(SYSTEMLOAD_04); + cpuDataInfo04->set_process_num(PROCESS_NUM_04); + + htraceCpuDataParser.Parse(*cpuDataInfo04, ts); + htraceCpuDataParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstCpuUsageInfoData().Size(); + EXPECT_EQ(3, size); + + auto totalLoadFirst = stream_.traceDataCache_->GetConstCpuUsageInfoData().TotalLoad()[0]; + auto totalLoadSecond = stream_.traceDataCache_->GetConstCpuUsageInfoData().TotalLoad()[1]; + auto totalLoadThird = stream_.traceDataCache_->GetConstCpuUsageInfoData().TotalLoad()[2]; + EXPECT_EQ(totalLoadFirst, TOTALLOAD_02); + EXPECT_EQ(totalLoadSecond, TOTALLOAD_03); + EXPECT_EQ(totalLoadThird, TOTALLOAD_04); + + auto userLoadFirst = stream_.traceDataCache_->GetConstCpuUsageInfoData().UserLoad()[0]; + auto userLoadSecond = stream_.traceDataCache_->GetConstCpuUsageInfoData().UserLoad()[1]; + auto userLoadThird = stream_.traceDataCache_->GetConstCpuUsageInfoData().UserLoad()[2]; + EXPECT_EQ(userLoadFirst, USERLOAD_02); + EXPECT_EQ(userLoadSecond, USERLOAD_03); + EXPECT_EQ(userLoadThird, USERLOAD_04); + + auto systemLoadFirst = stream_.traceDataCache_->GetConstCpuUsageInfoData().SystemLoad()[0]; + auto systemLoadSecond = stream_.traceDataCache_->GetConstCpuUsageInfoData().SystemLoad()[1]; + auto systemLoadThird = stream_.traceDataCache_->GetConstCpuUsageInfoData().SystemLoad()[2]; + EXPECT_EQ(systemLoadFirst, SYSTEMLOAD_02); + EXPECT_EQ(systemLoadSecond, SYSTEMLOAD_03); + EXPECT_EQ(systemLoadThird, SYSTEMLOAD_04); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_cpu_detail_parser_test.cpp b/trace_streamer/test/unittest/htrace_cpu_detail_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d7b697cdeeb1a0b596c52b6b99262381c7104dc --- /dev/null +++ b/trace_streamer/test/unittest/htrace_cpu_detail_parser_test.cpp @@ -0,0 +1,155 @@ +/* + * 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 +#include + +#include "htrace_cpu_detail_parser.h" +#include "htrace_event_parser.h" +#include "power.pb.h" +#include "stat_filter.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceCpuDetailParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() const {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseCpudetaulNoEvents + * @tc.desc: Parse a cpudetaul with no events + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDetailParserTest, ParseCpudetaulNoEvents, TestSize.Level1) +{ + TS_LOGI("test12-1"); + TracePluginResult tracePacket; + FtraceCpuDetailMsg* cpuDetail = tracePacket.add_ftrace_cpu_detail(); + + HtraceCpuDetailParser htraceCpuDetailParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDetailParser.Parse(&tracePacket, TS_CLOCK_REALTIME); + htraceCpuDetailParser.FilterAllEvents(); + auto size = tracePacket.ftrace_cpu_detail_size(); + auto eventSize = cpuDetail->event_size(); + EXPECT_EQ(size, 1); + EXPECT_EQ(eventSize, 0); +} +/** + * @tc.name: ParseHtraceWithoutCpuDetailData + * @tc.desc: Parse a cpu that does not contain any cpudetail + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDetailParserTest, ParseHtraceWithoutCpuDetailData, TestSize.Level1) +{ + TS_LOGI("test12-2"); + TracePluginResult tracePacket; + FtraceCpuDetailMsg* cpuDetail = tracePacket.add_ftrace_cpu_detail(); + auto event = cpuDetail->add_event(); + + HtraceCpuDetailParser htraceCpuDetailParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDetailParser.Parse(&tracePacket, TS_CLOCK_REALTIME); + htraceCpuDetailParser.FilterAllEvents(); + auto size = tracePacket.ftrace_cpu_detail_size(); + auto eventSize = cpuDetail->event_size(); + EXPECT_EQ(size, 1); + EXPECT_EQ(eventSize, 1); +} +/** + * @tc.name: ParseHtraceCpuDetailData + * @tc.desc: Parse a cpudetail data + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDetailParserTest, ParseHtraceCpuDetailData, TestSize.Level1) +{ + TS_LOGI("test12-3"); + TracePluginResult tracePacket; + FtraceCpuDetailMsg* cpuDetail = tracePacket.add_ftrace_cpu_detail(); + auto event = cpuDetail->add_event(); + cpuDetail->set_cpu(1); + event->set_timestamp(1501983446213000000); + event->set_tgid(1); + CpuFrequencyFormat* freq = new CpuFrequencyFormat(); + freq->set_cpu_id(1); + freq->set_state(1500); + event->set_allocated_cpu_frequency_format(freq); + + HtraceCpuDetailParser htraceCpuDetailParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDetailParser.Parse(&tracePacket, TS_CLOCK_REALTIME); + htraceCpuDetailParser.FilterAllEvents(); + auto size = tracePacket.ftrace_cpu_detail_size(); + auto eventSize = cpuDetail->event_size(); + auto state = stream_.traceDataCache_->GetConstMeasureData().ValuesData()[0]; + EXPECT_EQ(size, 1); + EXPECT_EQ(eventSize, 1); + EXPECT_EQ(state, 1500); +} +/** + * @tc.name: ParseMultipleCpuDetailData + * @tc.desc: Parse multiple cpudetail data + * @tc.type: FUNC + */ +HWTEST_F(HtraceCpuDetailParserTest, ParseMultipleCpuDetailData, TestSize.Level1) +{ + TS_LOGI("test12-4"); + TracePluginResult tracePacket; + FtraceCpuDetailMsg* cpuDetail = tracePacket.add_ftrace_cpu_detail(); + auto event = cpuDetail->add_event(); + cpuDetail->set_cpu(1); + event->set_timestamp(1501983446213000000); + event->set_tgid(1); + CpuFrequencyFormat* freq0 = new CpuFrequencyFormat(); + freq0->set_cpu_id(1); + freq0->set_state(1500); + event->set_allocated_cpu_frequency_format(freq0); + + cpuDetail = tracePacket.add_ftrace_cpu_detail(); + event = cpuDetail->add_event(); + cpuDetail->set_cpu(1); + event->set_timestamp(1501983446213000000); + event->set_tgid(1); + CpuFrequencyFormat* freq1 = new CpuFrequencyFormat(); + freq1->set_cpu_id(2); + freq1->set_state(3000); + event->set_allocated_cpu_frequency_format(freq1); + + HtraceCpuDetailParser htraceCpuDetailParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceCpuDetailParser.Parse(&tracePacket, TS_CLOCK_REALTIME); + htraceCpuDetailParser.FilterAllEvents(); + auto size = tracePacket.ftrace_cpu_detail_size(); + auto eventSize = cpuDetail->event_size(); + auto state0 = stream_.traceDataCache_->GetConstMeasureData().ValuesData()[0]; + auto cpuId0 = stream_.traceDataCache_->GetConstMeasureData().FilterIdData()[0]; + auto state1 = stream_.traceDataCache_->GetConstMeasureData().ValuesData()[1]; + auto cpuId1 = stream_.traceDataCache_->GetConstMeasureData().FilterIdData()[1]; + EXPECT_EQ(size, 2); + EXPECT_EQ(eventSize, 1); + EXPECT_EQ(state0, 1500); + EXPECT_EQ(state1, 3000); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_diskio_parser_test.cpp b/trace_streamer/test/unittest/htrace_diskio_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1050e85a25db42eb9b573c3b8d93cf213858916b --- /dev/null +++ b/trace_streamer/test/unittest/htrace_diskio_parser_test.cpp @@ -0,0 +1,330 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_disk_io_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtracediskioParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseHtracediskioWithoutDiskioData + * @tc.desc: Parse a diskio that does not contain any DiskioData + * @tc.type: FUNC + */ +HWTEST_F(HtracediskioParserTest, ParseHtracediskioWithoutDiskioData, TestSize.Level1) +{ + TS_LOGI("test13-1"); + uint64_t ts = 100; + auto diskioData = std::make_unique(); + HtraceDiskIOParser htraceDiskIOParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceDiskIOParser.Parse(*diskioData, ts); + auto size = stream_.traceDataCache_->GetConstDiskIOData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtracediskioWithOneDiskioData + * @tc.desc: Parse a diskio with one DiskioData + * @tc.type: FUNC + */ +HWTEST_F(HtracediskioParserTest, ParseHtracediskioWithOneDiskioData, TestSize.Level1) +{ + TS_LOGI("test13-2"); + uint64_t ts = 100; + const uint64_t RD = 100; + const uint64_t WR = 101; + const uint64_t RDPERSEC = 102; + const uint64_t WRPERSEC = 103; + StatsData* statsData = new StatsData(); + auto ioStatData = statsData->add_statsinfo(); + ioStatData->set_rd_kb(RD); + ioStatData->set_wr_kb(WR); + ioStatData->set_rd_per_sec(RDPERSEC); + ioStatData->set_wr_per_sec(WRPERSEC); + + auto diskioData(std::make_unique()); + diskioData->set_allocated_statsdata(statsData); + + HtraceDiskIOParser htraceDiskioParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceDiskioParser.Parse(*diskioData, ts); + htraceDiskioParser.Finish(); + auto size = stream_.traceDataCache_->GetConstDiskIOData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtracediskioWithTwoDiskioData + * @tc.desc: Parse a diskio with two DiskioData + * @tc.type: FUNC + */ +HWTEST_F(HtracediskioParserTest, ParseHtracediskioWithTwoDiskioData, TestSize.Level1) +{ + TS_LOGI("test13-3"); + uint64_t ts = 100; + const uint64_t RD_01 = 100; + const uint64_t WR_01 = 101; + const uint64_t RDPERSEC_01 = 102; + const uint64_t WRPERSEC_01 = 103; + + const uint64_t RD_02 = 104; + const uint64_t WR_02 = 105; + const uint64_t RDPERSEC_02 = 106; + const uint64_t WRPERSEC_02 = 107; + + StatsData* statsDataFirst = new StatsData(); + auto ioStatDatafirst = statsDataFirst->add_statsinfo(); + ioStatDatafirst->set_rd_kb(RD_01); + ioStatDatafirst->set_wr_kb(WR_01); + ioStatDatafirst->set_rd_per_sec(RDPERSEC_01); + ioStatDatafirst->set_wr_per_sec(WRPERSEC_01); + + auto diskioData = std::make_unique(); + diskioData->set_allocated_statsdata(statsDataFirst); + + HtraceDiskIOParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*diskioData, ts); + + StatsData* statsDataSecond = new StatsData(); + auto ioStatDataSecond = statsDataSecond->add_statsinfo(); + ioStatDataSecond->set_rd_kb(RD_02); + ioStatDataSecond->set_wr_kb(WR_02); + ioStatDataSecond->set_rd_per_sec(RDPERSEC_02); + ioStatDataSecond->set_wr_per_sec(WRPERSEC_02); + diskioData->set_allocated_statsdata(statsDataSecond); + + htraceProcessParser.Parse(*diskioData, ts); + htraceProcessParser.Finish(); + auto size = stream_.traceDataCache_->GetConstDiskIOData().Size(); + EXPECT_EQ(1, size); + + auto rdCountPerSecFirst = stream_.traceDataCache_->GetConstDiskIOData().RdCountPerSecDatas()[0]; + EXPECT_EQ(rdCountPerSecFirst, RDPERSEC_02); + + auto wrCountPerSecFirst = stream_.traceDataCache_->GetConstDiskIOData().WrCountPerSecDatas()[0]; + EXPECT_EQ(wrCountPerSecFirst, WRPERSEC_02); + + auto rdCountDatasFirst = stream_.traceDataCache_->GetConstDiskIOData().RdCountDatas()[0]; + EXPECT_EQ(rdCountDatasFirst, RD_02); + + auto wrCountDatasFirst = stream_.traceDataCache_->GetConstDiskIOData().WrCountDatas()[0]; + EXPECT_EQ(wrCountDatasFirst, WR_02); +} + +/** + * @tc.name: ParseHtracediskioWithThreeDiskioData + * @tc.desc: Parse a diskio with Three DiskioData + * @tc.type: FUNC + */ +HWTEST_F(HtracediskioParserTest, ParseHtracediskioWithThreeDiskioData, TestSize.Level1) +{ + TS_LOGI("test13-4"); + uint64_t ts = 100; + const uint64_t RD_01 = 100; + const uint64_t WR_01 = 101; + const uint64_t RDPERSEC_01 = 102; + const uint64_t WRPERSEC_01 = 103; + + const uint64_t RD_02 = 104; + const uint64_t WR_02 = 105; + const uint64_t RDPERSEC_02 = 106; + const uint64_t WRPERSEC_02 = 107; + + const uint64_t RD_03 = 108; + const uint64_t WR_03 = 109; + const uint64_t RDPERSEC_03 = 110; + const uint64_t WRPERSEC_03 = 111; + + StatsData* statsDataFirst = new StatsData(); + auto ioStatDatafirst = statsDataFirst->add_statsinfo(); + ioStatDatafirst->set_rd_kb(RD_01); + ioStatDatafirst->set_wr_kb(WR_01); + ioStatDatafirst->set_rd_per_sec(RDPERSEC_01); + ioStatDatafirst->set_wr_per_sec(WRPERSEC_01); + + auto diskioData = std::make_unique(); + diskioData->set_allocated_statsdata(statsDataFirst); + + HtraceDiskIOParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*diskioData, ts); + + StatsData* statsDataSecond = new StatsData(); + auto ioStatDataSecond = statsDataSecond->add_statsinfo(); + ioStatDataSecond->set_rd_kb(RD_02); + ioStatDataSecond->set_wr_kb(WR_02); + ioStatDataSecond->set_rd_per_sec(RDPERSEC_02); + ioStatDataSecond->set_wr_per_sec(WRPERSEC_02); + diskioData->set_allocated_statsdata(statsDataSecond); + + htraceProcessParser.Parse(*diskioData, ts); + + StatsData* statsDataThird = new StatsData(); + auto ioStatDataThird = statsDataThird->add_statsinfo(); + ioStatDataThird->set_rd_kb(RD_03); + ioStatDataThird->set_wr_kb(WR_03); + ioStatDataThird->set_rd_per_sec(RDPERSEC_03); + ioStatDataThird->set_wr_per_sec(WRPERSEC_03); + diskioData->set_allocated_statsdata(statsDataThird); + htraceProcessParser.Parse(*diskioData, ts); + htraceProcessParser.Finish(); + auto size = stream_.traceDataCache_->GetConstDiskIOData().Size(); + EXPECT_EQ(2, size); + + auto rdCountPerSecFirst = stream_.traceDataCache_->GetConstDiskIOData().RdCountPerSecDatas()[0]; + auto rdCountPerSecSecond = stream_.traceDataCache_->GetConstDiskIOData().RdCountPerSecDatas()[1]; + EXPECT_EQ(rdCountPerSecFirst, RDPERSEC_02); + EXPECT_EQ(rdCountPerSecSecond, RDPERSEC_03); + + auto wrCountPerSecFirst = stream_.traceDataCache_->GetConstDiskIOData().WrCountPerSecDatas()[0]; + auto wrCountPerSecSecond = stream_.traceDataCache_->GetConstDiskIOData().WrCountPerSecDatas()[1]; + EXPECT_EQ(wrCountPerSecFirst, WRPERSEC_02); + EXPECT_EQ(wrCountPerSecSecond, WRPERSEC_03); + + auto rdCountDatasFirst = stream_.traceDataCache_->GetConstDiskIOData().RdCountDatas()[0]; + auto rdCountDatasSecond = stream_.traceDataCache_->GetConstDiskIOData().RdCountDatas()[1]; + EXPECT_EQ(rdCountDatasFirst, RD_02); + EXPECT_EQ(rdCountDatasSecond, RD_03); + + auto wrCountDatasFirst = stream_.traceDataCache_->GetConstDiskIOData().WrCountDatas()[0]; + auto wrCountDatasSecond = stream_.traceDataCache_->GetConstDiskIOData().WrCountDatas()[1]; + EXPECT_EQ(wrCountDatasFirst, WR_02); + EXPECT_EQ(wrCountDatasSecond, WR_03); +} + +/** + * @tc.name: ParseHtracediskioWithMultipleDiskioData + * @tc.desc: Parse a diskio with Multiple DiskioData + * @tc.type: FUNC + */ +HWTEST_F(HtracediskioParserTest, ParseHtracediskioWithMultipleDiskioData, TestSize.Level1) +{ + TS_LOGI("test13-5"); + uint64_t ts = 100; + const uint64_t RD_01 = 100; + const uint64_t WR_01 = 101; + const uint64_t RDPERSEC_01 = 102; + const uint64_t WRPERSEC_01 = 103; + + const uint64_t RD_02 = 104; + const uint64_t WR_02 = 105; + const uint64_t RDPERSEC_02 = 106; + const uint64_t WRPERSEC_02 = 107; + + const uint64_t RD_03 = 108; + const uint64_t WR_03 = 109; + const uint64_t RDPERSEC_03 = 110; + const uint64_t WRPERSEC_03 = 111; + + const uint64_t RD_04 = 112; + const uint64_t WR_04 = 113; + const uint64_t RDPERSEC_04 = 114; + const uint64_t WRPERSEC_04 = 115; + + StatsData* statsDataFirst = new StatsData(); + auto ioStatDatafirst = statsDataFirst->add_statsinfo(); + ioStatDatafirst->set_rd_kb(RD_01); + ioStatDatafirst->set_wr_kb(WR_01); + ioStatDatafirst->set_rd_per_sec(RDPERSEC_01); + ioStatDatafirst->set_wr_per_sec(WRPERSEC_01); + + auto diskioData = std::make_unique(); + diskioData->set_allocated_statsdata(statsDataFirst); + + HtraceDiskIOParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*diskioData, ts); + + StatsData* statsDataSecond = new StatsData(); + auto ioStatDataSecond = statsDataSecond->add_statsinfo(); + ioStatDataSecond->set_rd_kb(RD_02); + ioStatDataSecond->set_wr_kb(WR_02); + ioStatDataSecond->set_rd_per_sec(RDPERSEC_02); + ioStatDataSecond->set_wr_per_sec(WRPERSEC_02); + diskioData->set_allocated_statsdata(statsDataSecond); + htraceProcessParser.Parse(*diskioData, ts); + + StatsData* statsDataThird = new StatsData(); + auto ioStatDataThird = statsDataThird->add_statsinfo(); + ioStatDataThird->set_rd_kb(RD_03); + ioStatDataThird->set_wr_kb(WR_03); + ioStatDataThird->set_rd_per_sec(RDPERSEC_03); + ioStatDataThird->set_wr_per_sec(WRPERSEC_03); + diskioData->set_allocated_statsdata(statsDataThird); + htraceProcessParser.Parse(*diskioData, ts); + + StatsData* statsDataForth = new StatsData(); + auto ioStatDataForth = statsDataForth->add_statsinfo(); + ioStatDataForth->set_rd_kb(RD_04); + ioStatDataForth->set_wr_kb(WR_04); + ioStatDataForth->set_rd_per_sec(RDPERSEC_04); + ioStatDataForth->set_wr_per_sec(WRPERSEC_04); + diskioData->set_allocated_statsdata(statsDataForth); + htraceProcessParser.Parse(*diskioData, ts); + htraceProcessParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstDiskIOData().Size(); + EXPECT_EQ(3, size); + + auto rdCountPerSecFirst = stream_.traceDataCache_->GetConstDiskIOData().RdCountPerSecDatas()[0]; + auto rdCountPerSecSecond = stream_.traceDataCache_->GetConstDiskIOData().RdCountPerSecDatas()[1]; + auto rdCountPerSecThird = stream_.traceDataCache_->GetConstDiskIOData().RdCountPerSecDatas()[2]; + EXPECT_EQ(rdCountPerSecFirst, RDPERSEC_02); + EXPECT_EQ(rdCountPerSecSecond, RDPERSEC_03); + EXPECT_EQ(rdCountPerSecThird, RDPERSEC_04); + + auto wrCountPerSecFirst = stream_.traceDataCache_->GetConstDiskIOData().WrCountPerSecDatas()[0]; + auto wrCountPerSecSecond = stream_.traceDataCache_->GetConstDiskIOData().WrCountPerSecDatas()[1]; + auto wrCountPerSecThird = stream_.traceDataCache_->GetConstDiskIOData().WrCountPerSecDatas()[2]; + EXPECT_EQ(wrCountPerSecFirst, WRPERSEC_02); + EXPECT_EQ(wrCountPerSecSecond, WRPERSEC_03); + EXPECT_EQ(wrCountPerSecThird, WRPERSEC_04); + + auto rdCountDatasFirst = stream_.traceDataCache_->GetConstDiskIOData().RdCountDatas()[0]; + auto rdCountDatasSecond = stream_.traceDataCache_->GetConstDiskIOData().RdCountDatas()[1]; + auto rdCountDatasThird = stream_.traceDataCache_->GetConstDiskIOData().RdCountDatas()[2]; + EXPECT_EQ(rdCountDatasFirst, RD_02); + EXPECT_EQ(rdCountDatasSecond, RD_03); + EXPECT_EQ(rdCountDatasThird, RD_04); + + auto wrCountDatasFirst = stream_.traceDataCache_->GetConstDiskIOData().WrCountDatas()[0]; + auto wrCountDatasSecond = stream_.traceDataCache_->GetConstDiskIOData().WrCountDatas()[1]; + auto wrCountDatasThird = stream_.traceDataCache_->GetConstDiskIOData().WrCountDatas()[2]; + EXPECT_EQ(wrCountDatasFirst, WR_02); + EXPECT_EQ(wrCountDatasSecond, WR_03); + EXPECT_EQ(wrCountDatasThird, WR_04); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test/unittest/htrace_event_parser_test.cpp b/trace_streamer/test/unittest/htrace_event_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4fd4b0705ca30d961dd91037e914b2271c299c4 --- /dev/null +++ b/trace_streamer/test/unittest/htrace_event_parser_test.cpp @@ -0,0 +1,632 @@ +/* + * 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 +#include +#include +#include + +#include "cpu_filter.h" +#include "htrace_cpu_detail_parser.h" +#include "parser/common_types.h" +#include "src/filter/symbols_filter.h" +#include "trace_streamer_filters.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +const uint64_t TIMESTAMP = 1616439852302; +const std::string THREAD_NAME_01 = "ACCS0"; +const std::string THREAD_NAME_02 = "HeapTaskDaemon"; +const uint32_t PRIORITY_01 = 120; +const uint32_t PRIORITY_02 = 124; +const uint32_t PID_01 = 2716; +const uint32_t PID_02 = 2532; +class HtraceEventParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseSchedSwitchEvent + * @tc.desc: Parse a schedswitch event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseSchedSwitchEvent, TestSize.Level1) +{ + TS_LOGI("test14-1"); + SchedSwitchFormat* event = new SchedSwitchFormat(); + event->set_prev_prio(PRIORITY_01); + event->set_next_prio(PRIORITY_02); + event->set_prev_pid(PID_01); + event->set_next_pid(PID_02); + event->set_prev_comm(THREAD_NAME_01); + event->set_next_comm(THREAD_NAME_02); + event->set_prev_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->unsafe_arena_set_allocated_sched_switch_format(event); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(1); + auto realTimeStamp = stream_.traceDataCache_->GetConstSchedSliceData().TimeStampData()[0]; + EXPECT_TRUE(TIMESTAMP == realTimeStamp); + auto realCpu = stream_.traceDataCache_->GetConstSchedSliceData().CpusData()[0]; + EXPECT_TRUE(0 == realCpu); +} + +/** + * @tc.name: ParseFtraceCpuDetailMsgHasNoEvent + * @tc.desc: FtraceCpuDetailMsg has no ftrace event + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseFtraceCpuDetailMsgHasNoEvent, TestSize.Level1) +{ + TS_LOGI("test14-2"); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_OTHER, STAT_EVENT_DATA_LOST); + EXPECT_TRUE(0 == eventCount); +} + +/** + * @tc.name: ParseFtraceCpuDetailMsgOverwriteTrue + * @tc.desc: FtraceCpuDetailMsg overwrit is true + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseFtraceCpuDetailMsgOverwriteTrue, TestSize.Level1) +{ + TS_LOGI("test14-3"); + SchedSwitchFormat* event = new SchedSwitchFormat(); + event->set_prev_prio(PRIORITY_01); + event->set_next_prio(PRIORITY_02); + event->set_prev_pid(PID_01); + event->set_next_pid(PID_02); + event->set_prev_comm(THREAD_NAME_01); + event->set_next_comm(THREAD_NAME_02); + event->set_prev_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(1); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_sched_switch_format(event); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_OTHER, STAT_EVENT_DATA_LOST); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseTaskRenameEvent + * @tc.desc: Parse a task_rename event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseTaskRenameEvent, TestSize.Level1) +{ + TS_LOGI("test14-4"); + TaskRenameFormat* taskRenameEvent = new TaskRenameFormat(); + taskRenameEvent->set_pid(PID_01); + taskRenameEvent->set_oldcomm(THREAD_NAME_01); + taskRenameEvent->set_newcomm(THREAD_NAME_02); + taskRenameEvent->set_oom_score_adj(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_task_rename_format(taskRenameEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_TASK_RENAME, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseTaskNewtaskEvent + * @tc.desc: Parse a task_newtask event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseTaskNewtaskEvent, TestSize.Level1) +{ + TS_LOGI("test14-5"); + TaskNewtaskFormat* newTaskEvent = new TaskNewtaskFormat(); + newTaskEvent->set_pid(PID_01); + newTaskEvent->set_comm(THREAD_NAME_01); + newTaskEvent->set_clone_flags(0); + newTaskEvent->set_oom_score_adj(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_task_newtask_format(newTaskEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_TASK_NEWTASK, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseSchedWakeupEvent + * @tc.desc: Parse a sched_wakeup event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseSchedWakeupEvent, TestSize.Level1) +{ + TS_LOGI("test14-6"); + SchedWakeupFormat* wakeupEvent = new SchedWakeupFormat(); + wakeupEvent->set_comm(THREAD_NAME_01); + wakeupEvent->set_pid(PRIORITY_02); + wakeupEvent->set_prio(PID_01); + wakeupEvent->set_target_cpu(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_sched_wakeup_format(wakeupEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseSchedWakingEvent + * @tc.desc: Parse a sched_waking event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseSchedWakingEvent, TestSize.Level1) +{ + TS_LOGI("test14-7"); + SchedWakingFormat* wakingEvent = new SchedWakingFormat(); + wakingEvent->set_comm(THREAD_NAME_01); + wakingEvent->set_pid(PRIORITY_02); + wakingEvent->set_prio(PID_01); + wakingEvent->set_target_cpu(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_sched_waking_format(wakingEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseCpuIdleEvent + * @tc.desc: Parse a cpuIdle event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseCpuIdleEvent, TestSize.Level1) +{ + TS_LOGI("test14-8"); + CpuIdleFormat* cpuIdleEvent = new CpuIdleFormat(); + cpuIdleEvent->set_cpu_id(0); + cpuIdleEvent->set_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_cpu_idle_format(cpuIdleEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CPU_IDLE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseCpuFrequencyEvent + * @tc.desc: Parse a CpuFrequency event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseCpuFrequencyEvent, TestSize.Level1) +{ + TS_LOGI("test14-9"); + CpuFrequencyFormat* cpuFrequencyEvent = new CpuFrequencyFormat(); + cpuFrequencyEvent->set_cpu_id(0); + cpuFrequencyEvent->set_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_cpu_frequency_format(cpuFrequencyEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseWorkqueueExecuteStartEvent + * @tc.desc: Parse a WorkqueueExecuteStart event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseWorkqueueExecuteStartEvent, TestSize.Level1) +{ + TS_LOGI("test14-10"); + stream_.streamFilters_->symbolsFilter_->RegisterFunc(1, 1); + auto funcNum = stream_.streamFilters_->symbolsFilter_->GetFunc(1); + WorkqueueExecuteStartFormat* workqueueExecuteStartEvent = new WorkqueueExecuteStartFormat(); + workqueueExecuteStartEvent->set_work(0); + workqueueExecuteStartEvent->set_function(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_workqueue_execute_start_format(workqueueExecuteStartEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_WORKQUEUE_EXECUTE_START, + STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseWorkqueueExecuteEndEvent + * @tc.desc: Parse a WorkqueueExecuteEnd event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseWorkqueueExecuteEndEvent, TestSize.Level1) +{ + TS_LOGI("test14-11"); + WorkqueueExecuteEndFormat* workqueueExecuteEndEvent = new WorkqueueExecuteEndFormat(); + workqueueExecuteEndEvent->set_work(0); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(1); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_workqueue_execute_end_format(workqueueExecuteEndEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_WORKQUEUE_EXECUTE_END, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseClockDisableEvent + * @tc.desc: Parse a clock_Disable event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseClockDisableEvent, TestSize.Level1) +{ + TS_LOGI("test14-12"); + ClockDisableFormat* clockDisableEvent = new ClockDisableFormat(); + clockDisableEvent->set_name(THREAD_NAME_02); + clockDisableEvent->set_cpu_id(0); + clockDisableEvent->set_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_clock_disable_format(clockDisableEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseClockEnableEvent + * @tc.desc: Parse a clock_Enable event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseClockEnableEvent, TestSize.Level1) +{ + TS_LOGI("test14-13"); + ClockEnableFormat* clockEnableEvent = new ClockEnableFormat(); + clockEnableEvent->set_name(THREAD_NAME_02); + clockEnableEvent->set_cpu_id(0); + clockEnableEvent->set_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_clock_enable_format(clockEnableEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseClockSetRateEvent + * @tc.desc: Parse a clock_set_rate event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseClockSetRateEvent, TestSize.Level1) +{ + TS_LOGI("test14-14"); + ClockSetRateFormat* clockSetRateEvent = new ClockSetRateFormat(); + clockSetRateEvent->set_name(THREAD_NAME_02); + clockSetRateEvent->set_cpu_id(0); + clockSetRateEvent->set_state(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_clock_set_rate_format(clockSetRateEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseClkDisableEvent + * @tc.desc: Parse a clk_Disable event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseClkDisableEvent, TestSize.Level1) +{ + TS_LOGI("test14-15"); + ClkDisableFormat* clkDisableEvent = new ClkDisableFormat(); + clkDisableEvent->set_name(THREAD_NAME_02); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_clk_disable_format(clkDisableEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CLK_DISABLE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseClkEnableEvent + * @tc.desc: Parse a clk_Enable event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseClkEnableEvent, TestSize.Level1) +{ + TS_LOGI("test14-16"); + ClkEnableFormat* clkEnableEvent = new ClkEnableFormat(); + clkEnableEvent->set_name(THREAD_NAME_02); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_clk_enable_format(clkEnableEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CLK_ENABLE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseClkSetRateEvent + * @tc.desc: Parse a clk_set_rate event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseClkSetRateEvent, TestSize.Level1) +{ + TS_LOGI("test14-17"); + ClkSetRateFormat* clkSetRateEvent = new ClkSetRateFormat(); + clkSetRateEvent->set_name(THREAD_NAME_02); + clkSetRateEvent->set_rate(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_clk_set_rate_format(clkSetRateEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_CLK_SET_RATE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseSysEnterEvent + * @tc.desc: Parse a sysEnter event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseSysEnterEvent, TestSize.Level1) +{ + TS_LOGI("test14-18"); + SysEnterFormat* sysEnterEvent = new SysEnterFormat(); + sysEnterEvent->set_id(1); + sysEnterEvent->set_args(THREAD_NAME_02); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_sys_enter_format(sysEnterEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SYS_ENTRY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} +/** + * @tc.name: ParseSystemExitEvent + * @tc.desc: Parse a system_exit event in htrace format + * @tc.type: FUNC + */ +HWTEST_F(HtraceEventParserTest, ParseSystemExitEvent, TestSize.Level1) +{ + TS_LOGI("test14-19"); + SysExitFormat* sysExitEvent = new SysExitFormat(); + sysExitEvent->set_id(1); + sysExitEvent->set_ret(1); + + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(0); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(TIMESTAMP); + ftraceEvent->set_tgid(2); + ftraceEvent->set_comm(THREAD_NAME_02); + ftraceEvent->set_allocated_sys_exit_format(sysExitEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SYS_EXIT, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_irq_event_test.cpp b/trace_streamer/test/unittest/htrace_irq_event_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d091c49558575e5d26db5d17c7808badf65f9721 --- /dev/null +++ b/trace_streamer/test/unittest/htrace_irq_event_test.cpp @@ -0,0 +1,512 @@ +/* + * 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 +#include + +#include "htrace_cpu_detail_parser.h" +#include "htrace_event_parser.h" +#include "irq_filter.h" +#include "trace_streamer_selector.h" +#include "ts_common.h" +#include "types/plugins/ftrace_data/trace_plugin_result.pb.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class HtraceIrqEventTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: IrqHandlerEntryTest + * @tc.desc: Binary formate IrqHandlerEntry Normal TEST + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, IrqHandlerEntryTest, TestSize.Level1) +{ + TS_LOGI("test15-1"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + int32_t irq = 12; + IrqHandlerEntryFormat* irqHandlerEvent = new IrqHandlerEntryFormat(); + irqHandlerEvent->set_irq(irq); + irqHandlerEvent->set_name("user_irq"); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_irq_handler_entry_format(irqHandlerEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + eventParser.Clear(); +} + +/** + * @tc.name: IrqHandlerEntryTestNotMatch + * @tc.desc: Binary formate IrqHandlerEntry, only start, no end + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, IrqHandlerEntryTestNotMatch, TestSize.Level1) +{ + TS_LOGI("test15-2"); + int64_t ts1 = 120; + uint32_t cpu1 = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + int32_t irq = 12; + IrqHandlerEntryFormat* irqHandlerEvent = new IrqHandlerEntryFormat(); + irqHandlerEvent->set_irq(irq); + irqHandlerEvent->set_name("user_irq"); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_irq_handler_entry_format(irqHandlerEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + ts1 = 110; + IrqHandlerEntryFormat* irqHandlerEvent2 = new IrqHandlerEntryFormat(); + irqHandlerEvent2->set_irq(irq); + irqHandlerEvent2->set_name("user_irq"); + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(cpu1); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_irq_handler_entry_format(irqHandlerEvent2); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 2); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_LOST); + EXPECT_TRUE(1 == eventCount); + eventParser.Clear(); +} + +/** + * @tc.name: IrqHandlerExitTestEmpty + * @tc.desc: Binary formate IrqHandlerExit, Interrupt only ends, not starts + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, IrqHandlerExitTestEmpty, TestSize.Level1) +{ + TS_LOGI("test15-3"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t ret = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + int32_t irq = 12; // 1 for handled, else for unhandled + + IrqHandlerExitFormat* irqHandlerExitEvent = new IrqHandlerExitFormat(); + irqHandlerExitEvent->set_irq(irq); + irqHandlerExitEvent->set_ret(ret); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_irq_handler_exit_format(irqHandlerExitEvent); + + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 0); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_NOTMATCH); + EXPECT_TRUE(1 == eventCount); + eventParser.Clear(); +} + +/** + * @tc.name: IrqHandlerEnterAndExitTest + * @tc.desc: Binary formate IrqHandlerEnter, Interrupt normal start and end + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, IrqHandlerEnterAndExitTest, TestSize.Level1) +{ + TS_LOGI("test15-4"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + int32_t irq = 12; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + IrqHandlerEntryFormat* irqHandlerEvent = new IrqHandlerEntryFormat(); + irqHandlerEvent->set_irq(irq); + irqHandlerEvent->set_name("user_irq"); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_irq_handler_entry_format(irqHandlerEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + uint32_t ret = 1; // 1 for handled, else for unhandled + + IrqHandlerExitFormat* irqHandlerExitEvent = new IrqHandlerExitFormat(); + irqHandlerExitEvent->set_irq(irq); + irqHandlerExitEvent->set_ret(ret); + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(cpu1); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_irq_handler_exit_format(irqHandlerExitEvent); + + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().ArgSetIdsData()[0] == 0); + eventParser.Clear(); +} + +/** + * @tc.name: IrqHandlerEnterAndExitTestTwice + * @tc.desc: Binary formate IrqHandlerEnter and Exit, Interrupt normal start and end Twice + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, IrqHandlerEnterAndExitTestTwice, TestSize.Level1) +{ + TS_LOGI("test15-5"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + int32_t irq = 12; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + IrqHandlerEntryFormat* irqHandlerEvent = new IrqHandlerEntryFormat(); + irqHandlerEvent->set_irq(irq); + irqHandlerEvent->set_name("user_irq"); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_irq_handler_entry_format(irqHandlerEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + uint32_t ret = 1; // 1 for handled, else for unhandled + cpu1 = 2; + ts1 = 150; + + IrqHandlerExitFormat* irqHandlerExitEvent = new IrqHandlerExitFormat(); + irqHandlerExitEvent->set_irq(irq); + irqHandlerExitEvent->set_ret(ret); + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(cpu1); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_irq_handler_exit_format(irqHandlerExitEvent); + + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_IRQ_HANDLER_EXIT, + STAT_EVENT_NOTMATCH) == 1); + cpu1 = 1; + ts1 = 200; + + IrqHandlerExitFormat* irqHandlerExitEvent2 = new IrqHandlerExitFormat(); + irqHandlerExitEvent2->set_irq(irq); + irqHandlerExitEvent2->set_ret(ret); + FtraceCpuDetailMsg ftraceCpuDetail3; + ftraceCpuDetail3.set_cpu(cpu1); + ftraceCpuDetail3.set_overwrite(0); + auto ftraceEvent3 = ftraceCpuDetail3.add_event(); + + ftraceEvent3->set_timestamp(ts1); + ftraceEvent3->set_tgid(tid1); + ftraceEvent3->set_comm(appName); + ftraceEvent3->set_allocated_irq_handler_exit_format(irqHandlerExitEvent2); + + eventParser.ParseDataItem(&ftraceCpuDetail3, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().ArgSetIdsData()[0] == 0); + eventParser.Clear(); +} + +/** + * @tc.name: SoftIrqEntryTest + * @tc.desc: Binary format Soft interrupt normal test + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, SoftIrqEntryTest, TestSize.Level1) +{ + TS_LOGI("test15-6"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + SoftirqEntryFormat* softirqEntryEvent = new SoftirqEntryFormat(); + softirqEntryEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_softirq_entry_format(softirqEntryEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + eventParser.Clear(); +} + +/** + * @tc.name: SoftIrqEntryNotMatch + * @tc.desc: The binary format soft interrupts do not match. The two interrupts have only the beginning and no end + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, SoftIrqEntryNotMatch, TestSize.Level1) +{ + TS_LOGI("test15-7"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + SoftirqEntryFormat* softirqEntryEvent = new SoftirqEntryFormat(); + softirqEntryEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_softirq_entry_format(softirqEntryEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + ts1 = 150; + + SoftirqEntryFormat* softirqEntryEvent2 = new SoftirqEntryFormat(); + softirqEntryEvent2->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(cpu1); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_softirq_entry_format(softirqEntryEvent2); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 2); + EXPECT_TRUE( + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_LOST) == 1); + eventParser.Clear(); +} + +/** + * @tc.name: SoftIrqExitEmptyTest + * @tc.desc: The binary format soft interrupt only ends without starting + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, SoftIrqExitEmptyTest, TestSize.Level1) +{ + TS_LOGI("test15-8"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + SoftirqExitFormat* softirqExitEvent = new SoftirqExitFormat(); + softirqExitEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_softirq_exit_format(softirqExitEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 0); + EXPECT_TRUE( + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); + eventParser.Clear(); +} + +/** + * @tc.name: SoftIrqTest + * @tc.desc: The binary format soft interrupt normal test + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, SoftIrqTest, TestSize.Level1) +{ + TS_LOGI("test15-9"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + SoftirqEntryFormat* softirqEntryEvent = new SoftirqEntryFormat(); + softirqEntryEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_softirq_entry_format(softirqEntryEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + eventParser.Clear(); + ts1 = 150; + SoftirqExitFormat* softirqExitEvent = new SoftirqExitFormat(); + softirqExitEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(cpu1); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_softirq_exit_format(softirqExitEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + eventParser.Clear(); +} + +/** + * @tc.name: SoftIrqTestNotMatch + * @tc.desc: The binary soft interrupt test not match + * @tc.type: FUNC + */ +HWTEST_F(HtraceIrqEventTest, SoftIrqTestNotMatch, TestSize.Level1) +{ + TS_LOGI("test15-10"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + std::string appName = "app1"; + uint32_t tid1 = 1; + HtraceEventParser eventParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + SoftirqEntryFormat* softirqEntryEvent = new SoftirqEntryFormat(); + softirqEntryEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail; + ftraceCpuDetail.set_cpu(cpu1); + ftraceCpuDetail.set_overwrite(0); + auto ftraceEvent = ftraceCpuDetail.add_event(); + + ftraceEvent->set_timestamp(ts1); + ftraceEvent->set_tgid(tid1); + ftraceEvent->set_comm(appName); + ftraceEvent->set_allocated_softirq_entry_format(softirqEntryEvent); + eventParser.ParseDataItem(&ftraceCpuDetail, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + eventParser.Clear(); + ts1 = 150; + cpu1 = 2; + + SoftirqExitFormat* softirqExitEvent = new SoftirqExitFormat(); + softirqExitEvent->set_vec(vec); + FtraceCpuDetailMsg ftraceCpuDetail2; + ftraceCpuDetail2.set_cpu(cpu1); + ftraceCpuDetail2.set_overwrite(0); + auto ftraceEvent2 = ftraceCpuDetail2.add_event(); + + ftraceEvent2->set_timestamp(ts1); + ftraceEvent2->set_tgid(tid1); + ftraceEvent2->set_comm(appName); + ftraceEvent2->set_allocated_softirq_exit_format(softirqExitEvent); + eventParser.ParseDataItem(&ftraceCpuDetail2, TS_CLOCK_BOOTTIME); + eventParser.FilterAllEvents(); + EXPECT_TRUE(stream_.traceDataCache_->GetConstIrqData().Size() == 1); + EXPECT_TRUE( + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); + eventParser.Clear(); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_mem_parser_test.cpp b/trace_streamer/test/unittest/htrace_mem_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdccd1c78ab861a7e4ff586fc0bb61278f54d5ba --- /dev/null +++ b/trace_streamer/test/unittest/htrace_mem_parser_test.cpp @@ -0,0 +1,255 @@ +/* + * 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 +#include +#include +#include +#include + +#include "htrace_mem_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceMemParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() + { + if (access(dbPath_.c_str(), F_OK) == 0) { + remove(dbPath_.c_str()); + } + } + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; + +/** + * @tc.name: ParseMemParse + * @tc.desc: Parse MemoryData object and export database + * @tc.type: FUNC + */ +HWTEST_F(HtraceMemParserTest, ParseMemParse, TestSize.Level1) +{ + TS_LOGI("test16-1"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memoryInfo = tracePacket.add_processesinfo(); + EXPECT_TRUE(memoryInfo != nullptr); + int32_t size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + memParser->Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_processesinfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseMemParseTestMeasureDataSize + * @tc.desc: Parse MemoryData object and count StatInfo + * @tc.type: FUNC + */ +HWTEST_F(HtraceMemParserTest, ParseMemParseTestMeasureDataSize, TestSize.Level1) +{ + TS_LOGI("test16-2"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memoryInfo = tracePacket.add_processesinfo(); + EXPECT_TRUE(memoryInfo != nullptr); + int32_t size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + uint32_t pid = 12; + int64_t memKb = 1024; + int64_t memRssKb = 512; + int64_t memAnonKb = 128; + int64_t memFileKb = 2048; + memoryInfo->set_pid(pid); + memoryInfo->set_name("Process1"); + memoryInfo->set_vm_size_kb(memKb); + memoryInfo->set_vm_rss_kb(memRssKb); + memoryInfo->set_rss_anon_kb(memAnonKb); + memoryInfo->set_rss_file_kb(memFileKb); + + memParser->Parse(tracePacket, timeStamp, clock); + memParser->Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_processesinfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessData(1).pid_ == pid); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == MEM_MAX * 1); + EXPECT_EQ(stream_.traceDataCache_->GetConstProcessData().size(), 2); + + for (auto i = 0; i < MEM_MAX; i++) { + if (stream_.traceDataCache_->GetConstProcessMeasureData().filterIdDeque_[i] == + memParser->memNameDictMap_.at(MEM_VM_SIZE)) { + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().valuesDeque_[i] == memKb); + } else if (stream_.traceDataCache_->GetConstProcessMeasureData().filterIdDeque_[i] == + memParser->memNameDictMap_.at(MEM_VM_RSS)) { + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().valuesDeque_[i] == memRssKb); + } else if (stream_.traceDataCache_->GetConstProcessMeasureData().filterIdDeque_[i] == + memParser->memNameDictMap_.at(MEM_VM_ANON)) { + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().valuesDeque_[i] == memAnonKb); + } else if (stream_.traceDataCache_->GetConstProcessMeasureData().filterIdDeque_[i] == + memParser->memNameDictMap_.at(MEM_RSS_FILE)) { + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().valuesDeque_[i] == memFileKb); + } + } +} + +/** + * @tc.name: ParseMemParseTestMutiMeasureData + * @tc.desc: Parse muti MemoryData object and count StatInfo + * @tc.type: FUNC + */ +HWTEST_F(HtraceMemParserTest, ParseMemParseTestMutiMeasureData, TestSize.Level1) +{ + TS_LOGI("test16-3"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memoryInfo = tracePacket.add_processesinfo(); + EXPECT_TRUE(memoryInfo != nullptr); + int32_t size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + uint32_t pid = 12; + memoryInfo->set_pid(12); + memoryInfo->set_name("Process1"); + memoryInfo->set_vm_size_kb(1024); + memoryInfo->set_vm_rss_kb(512); + memoryInfo->set_rss_anon_kb(128); + memoryInfo->set_rss_file_kb(128); + + ProcessMemoryInfo* memoryInfo2 = tracePacket.add_processesinfo(); + EXPECT_TRUE(memoryInfo2 != nullptr); + size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 2); + timeStamp = 1616439852402; + uint32_t pid2 = 13; + memoryInfo2->set_pid(pid2); + memoryInfo2->set_name("Process2"); + memoryInfo2->set_vm_size_kb(1024); + memoryInfo2->set_vm_rss_kb(512); + memoryInfo2->set_rss_anon_kb(128); + memoryInfo2->set_rss_file_kb(128); + + memParser->Parse(tracePacket, timeStamp, clock); + memParser->Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_processesinfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessData(1).pid_ == pid); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessData(2).pid_ == pid2); +} + +/** + * @tc.name: ParseMultiEmptyProcessMemoryInfo + * @tc.desc: Parse muti Empty ProcessMemoryInfo object and count StatInfo + * @tc.type: FUNC + */ +HWTEST_F(HtraceMemParserTest, ParseMultiEmptyProcessMemoryInfo, TestSize.Level1) +{ + TS_LOGI("test16-4"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memoryInfo = tracePacket.add_processesinfo(); + EXPECT_TRUE(memoryInfo != nullptr); + int32_t size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + ProcessMemoryInfo* memoryInfo2 = tracePacket.add_processesinfo(); + EXPECT_TRUE(memoryInfo2 != nullptr); + size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 2); + + memParser->Parse(tracePacket, timeStamp, clock); + memParser->Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_processesinfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == MEM_MAX * 2); +} + +/** + * @tc.name: ParseEmptyMemoryData + * @tc.desc: Parse Empty MemoryData + * @tc.type: FUNC + */ +HWTEST_F(HtraceMemParserTest, ParseEmptyMemoryData, TestSize.Level1) +{ + TS_LOGI("test16-5"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + int32_t size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 0); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + memParser->Finish(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(0 == eventCount); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_network_parser_test.cpp b/trace_streamer/test/unittest/htrace_network_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9d62420c12e67b79f0e3fca6760ec07e3a71643 --- /dev/null +++ b/trace_streamer/test/unittest/htrace_network_parser_test.cpp @@ -0,0 +1,300 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_network_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceNetworkParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseHtraceNetworkWithoutNetworkData + * @tc.desc: Parse a Process that does not contain any ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceNetworkParserTest, ParseHtraceNetworkWithoutNetworkData, TestSize.Level1) +{ + TS_LOGI("test17-1"); + uint64_t ts = 100; + auto networkDatas = std::make_unique(); + HtraceNetworkParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*networkDatas, ts); + auto size = stream_.traceDataCache_->GetConstNetworkData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtraceNetworkWithNetworkData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceNetworkParserTest, ParseHtraceNetworkWithNetworkData, TestSize.Level1) +{ + TS_LOGI("test17-2"); + uint64_t ts = 100; + const uint64_t DURS = 1999632780; + const uint64_t TX = 712924; + const uint64_t RX = 13535014; + const uint64_t PACKETIN = 11431; + const uint64_t PACKETOUT = 7373; + + auto networkDatas = std::make_unique(); + NetworkSystemData* networkSystemData = new NetworkSystemData(); + networkSystemData->set_rx_bytes(RX); + networkSystemData->set_tx_bytes(TX); + networkSystemData->set_rx_packets(PACKETIN); + networkSystemData->set_tx_packets(PACKETOUT); + networkDatas->set_allocated_network_system_info(networkSystemData); + + HtraceNetworkParser htraceNetworkParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNetworkParser.Parse(*networkDatas, ts); + htraceNetworkParser.Finish(); + auto size = stream_.traceDataCache_->GetConstNetworkData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtraceNetworkWithTwoNetworkData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceNetworkParserTest, ParseHtraceNetworkWithTwoNetworkData, TestSize.Level1) +{ + TS_LOGI("test17-3"); + uint64_t ts = 100; + auto networkDatas = std::make_unique(); + + const uint64_t DURS_01 = 1999632781; + const uint64_t TX_01 = 712921; + const uint64_t RX_01 = 13535011; + const uint64_t PACKETIN_01 = 11431; + const uint64_t PACKETOUT_01 = 7371; + NetworkSystemData* networkSystemDataFirst = new NetworkSystemData(); + networkSystemDataFirst->set_rx_bytes(RX_01); + networkSystemDataFirst->set_tx_bytes(TX_01); + networkSystemDataFirst->set_rx_packets(PACKETIN_01); + networkSystemDataFirst->set_tx_packets(PACKETOUT_01); + networkDatas->set_allocated_network_system_info(networkSystemDataFirst); + HtraceNetworkParser htraceNetworkParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNetworkParser.Parse(*networkDatas, ts); + + const uint64_t DURS_02 = 1999632782; + const uint64_t TX_02 = 712922; + const uint64_t RX_02 = 13535012; + const uint64_t PACKETIN_02 = 11432; + const uint64_t PACKETOUT_02 = 7372; + NetworkSystemData* networkSystemDataSecond = new NetworkSystemData(); + networkSystemDataSecond->set_rx_bytes(RX_02); + networkSystemDataSecond->set_tx_bytes(TX_02); + networkSystemDataSecond->set_rx_packets(PACKETIN_02); + networkSystemDataSecond->set_tx_packets(PACKETOUT_02); + networkDatas->set_allocated_network_system_info(networkSystemDataSecond); + htraceNetworkParser.Parse(*networkDatas, ts); + htraceNetworkParser.Finish(); + + auto tx = stream_.traceDataCache_->GetConstNetworkData().TxDatas()[0]; + EXPECT_EQ(tx, TX_02); + auto rx = stream_.traceDataCache_->GetConstNetworkData().RxDatas()[0]; + EXPECT_EQ(rx, RX_02); + auto packetIn = stream_.traceDataCache_->GetConstNetworkData().PacketIn()[0]; + EXPECT_EQ(packetIn, PACKETIN_02); + auto packetOut = stream_.traceDataCache_->GetConstNetworkData().PacketOut()[0]; + EXPECT_EQ(packetOut, PACKETOUT_02); +} + +/** + * @tc.name: ParseHtraceNetworkWithThreeNetworkData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceNetworkParserTest, ParseHtraceNetworkWithThreeNetworkData, TestSize.Level1) +{ + TS_LOGI("test17-4"); + uint64_t ts = 100; + auto networkDatas = std::make_unique(); + + const uint64_t DURS_01 = 1999632781; + const uint64_t TX_01 = 712921; + const uint64_t RX_01 = 13535011; + const uint64_t PACKETIN_01 = 11431; + const uint64_t PACKETOUT_01 = 7371; + NetworkSystemData* networkSystemDataFirst = new NetworkSystemData(); + networkSystemDataFirst->set_rx_bytes(RX_01); + networkSystemDataFirst->set_tx_bytes(TX_01); + networkSystemDataFirst->set_rx_packets(PACKETIN_01); + networkSystemDataFirst->set_tx_packets(PACKETOUT_01); + networkDatas->set_allocated_network_system_info(networkSystemDataFirst); + HtraceNetworkParser htraceNetworkParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNetworkParser.Parse(*networkDatas, ts); + + const uint64_t DURS_02 = 1999632782; + const uint64_t TX_02 = 712922; + const uint64_t RX_02 = 13535012; + const uint64_t PACKETIN_02 = 11432; + const uint64_t PACKETOUT_02 = 7372; + NetworkSystemData* networkSystemDataSecond = new NetworkSystemData(); + networkSystemDataSecond->set_rx_bytes(RX_02); + networkSystemDataSecond->set_tx_bytes(TX_02); + networkSystemDataSecond->set_rx_packets(PACKETIN_02); + networkSystemDataSecond->set_tx_packets(PACKETOUT_02); + networkDatas->set_allocated_network_system_info(networkSystemDataSecond); + htraceNetworkParser.Parse(*networkDatas, ts); + + const uint64_t DURS_03 = 1999632783; + const uint64_t TX_03 = 712923; + const uint64_t RX_03 = 13535013; + const uint64_t PACKETIN_03 = 11433; + const uint64_t PACKETOUT_03 = 7373; + NetworkSystemData* networkSystemDataThird = new NetworkSystemData(); + networkSystemDataThird->set_rx_bytes(RX_03); + networkSystemDataThird->set_tx_bytes(TX_03); + networkSystemDataThird->set_rx_packets(PACKETIN_03); + networkSystemDataThird->set_tx_packets(PACKETOUT_03); + networkDatas->set_allocated_network_system_info(networkSystemDataThird); + htraceNetworkParser.Parse(*networkDatas, ts); + htraceNetworkParser.Finish(); + + auto txFirst = stream_.traceDataCache_->GetConstNetworkData().TxDatas()[0]; + auto txSecond = stream_.traceDataCache_->GetConstNetworkData().TxDatas()[1]; + EXPECT_EQ(txFirst, TX_02); + EXPECT_EQ(txSecond, TX_03); + auto rxFirst = stream_.traceDataCache_->GetConstNetworkData().RxDatas()[0]; + auto rxSecond = stream_.traceDataCache_->GetConstNetworkData().RxDatas()[1]; + EXPECT_EQ(rxFirst, RX_02); + EXPECT_EQ(rxSecond, RX_03); + auto packetInFirst = stream_.traceDataCache_->GetConstNetworkData().PacketIn()[0]; + auto packetInSecond = stream_.traceDataCache_->GetConstNetworkData().PacketIn()[1]; + EXPECT_EQ(packetInFirst, PACKETIN_02); + EXPECT_EQ(packetInSecond, PACKETIN_03); + auto packetOutFirst = stream_.traceDataCache_->GetConstNetworkData().PacketOut()[0]; + auto packetOutSecond = stream_.traceDataCache_->GetConstNetworkData().PacketOut()[1]; + EXPECT_EQ(packetOutFirst, PACKETOUT_02); + EXPECT_EQ(packetOutSecond, PACKETOUT_03); +} + +/** + * @tc.name: ParseHtraceNetworkWithMultipleNetworkData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceNetworkParserTest, ParseHtraceNetworkWithMultipleNetworkData, TestSize.Level1) +{ + TS_LOGI("test17-5"); + uint64_t ts = 100; + auto networkDatas = std::make_unique(); + + const uint64_t DURS_01 = 1999632781; + const uint64_t TX_01 = 712921; + const uint64_t RX_01 = 13535011; + const uint64_t PACKETIN_01 = 11431; + const uint64_t PACKETOUT_01 = 7371; + NetworkSystemData* networkSystemDataFirst = new NetworkSystemData(); + networkSystemDataFirst->set_rx_bytes(RX_01); + networkSystemDataFirst->set_tx_bytes(TX_01); + networkSystemDataFirst->set_rx_packets(PACKETIN_01); + networkSystemDataFirst->set_tx_packets(PACKETOUT_01); + networkDatas->set_allocated_network_system_info(networkSystemDataFirst); + HtraceNetworkParser htraceNetworkParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNetworkParser.Parse(*networkDatas, ts); + + const uint64_t DURS_02 = 1999632782; + const uint64_t TX_02 = 712922; + const uint64_t RX_02 = 13535012; + const uint64_t PACKETIN_02 = 11432; + const uint64_t PACKETOUT_02 = 7372; + NetworkSystemData* networkSystemDataSecond = new NetworkSystemData(); + networkSystemDataSecond->set_rx_bytes(RX_02); + networkSystemDataSecond->set_tx_bytes(TX_02); + networkSystemDataSecond->set_rx_packets(PACKETIN_02); + networkSystemDataSecond->set_tx_packets(PACKETOUT_02); + networkDatas->set_allocated_network_system_info(networkSystemDataSecond); + htraceNetworkParser.Parse(*networkDatas, ts); + + const uint64_t DURS_03 = 1999632783; + const uint64_t TX_03 = 712923; + const uint64_t RX_03 = 13535013; + const uint64_t PACKETIN_03 = 11433; + const uint64_t PACKETOUT_03 = 7373; + NetworkSystemData* networkSystemDataThird = new NetworkSystemData(); + networkSystemDataThird->set_rx_bytes(RX_03); + networkSystemDataThird->set_tx_bytes(TX_03); + networkSystemDataThird->set_rx_packets(PACKETIN_03); + networkSystemDataThird->set_tx_packets(PACKETOUT_03); + networkDatas->set_allocated_network_system_info(networkSystemDataThird); + htraceNetworkParser.Parse(*networkDatas, ts); + + const uint64_t DURS_04 = 1999632784; + const uint64_t TX_04 = 712924; + const uint64_t RX_04 = 13535014; + const uint64_t PACKETIN_04 = 11434; + const uint64_t PACKETOUT_04 = 7374; + NetworkSystemData* networkSystemDataForth = new NetworkSystemData(); + networkSystemDataForth->set_rx_bytes(RX_04); + networkSystemDataForth->set_tx_bytes(TX_04); + networkSystemDataForth->set_rx_packets(PACKETIN_04); + networkSystemDataForth->set_tx_packets(PACKETOUT_04); + networkDatas->set_allocated_network_system_info(networkSystemDataForth); + htraceNetworkParser.Parse(*networkDatas, ts); + htraceNetworkParser.Finish(); + + auto txFirst = stream_.traceDataCache_->GetConstNetworkData().TxDatas()[0]; + auto txSecond = stream_.traceDataCache_->GetConstNetworkData().TxDatas()[1]; + auto txThird = stream_.traceDataCache_->GetConstNetworkData().TxDatas()[2]; + EXPECT_EQ(txFirst, TX_02); + EXPECT_EQ(txSecond, TX_03); + EXPECT_EQ(txThird, TX_04); + auto rxFirst = stream_.traceDataCache_->GetConstNetworkData().RxDatas()[0]; + auto rxSecond = stream_.traceDataCache_->GetConstNetworkData().RxDatas()[1]; + auto rxThird = stream_.traceDataCache_->GetConstNetworkData().RxDatas()[2]; + EXPECT_EQ(rxFirst, RX_02); + EXPECT_EQ(rxSecond, RX_03); + EXPECT_EQ(rxThird, RX_04); + auto packetInFirst = stream_.traceDataCache_->GetConstNetworkData().PacketIn()[0]; + auto packetInSecond = stream_.traceDataCache_->GetConstNetworkData().PacketIn()[1]; + auto packetInThird = stream_.traceDataCache_->GetConstNetworkData().PacketIn()[2]; + EXPECT_EQ(packetInFirst, PACKETIN_02); + EXPECT_EQ(packetInSecond, PACKETIN_03); + EXPECT_EQ(packetInThird, PACKETIN_04); + auto packetOutFirst = stream_.traceDataCache_->GetConstNetworkData().PacketOut()[0]; + auto packetOutSecond = stream_.traceDataCache_->GetConstNetworkData().PacketOut()[1]; + auto packetOutThird = stream_.traceDataCache_->GetConstNetworkData().PacketOut()[2]; + EXPECT_EQ(packetOutFirst, PACKETOUT_02); + EXPECT_EQ(packetOutSecond, PACKETOUT_03); + EXPECT_EQ(packetOutThird, PACKETOUT_04); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test/unittest/htrace_process_parser_test.cpp b/trace_streamer/test/unittest/htrace_process_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f241229a87d0eba51067dab94812def01c86a2b --- /dev/null +++ b/trace_streamer/test/unittest/htrace_process_parser_test.cpp @@ -0,0 +1,299 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_process_parser.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceProcessParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ParseHtraceProcessWithoutProcessData + * @tc.desc: Parse a Process that does not contain any ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceProcessParserTest, ParseHtraceProcessWithoutProcessData, TestSize.Level1) +{ + TS_LOGI("test18-1"); + auto processData = std::make_unique(); + uint64_t ts = 100; + HtraceProcessParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*processData, ts); + auto size = stream_.traceDataCache_->GetConstLiveProcessData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtraceProcessWithProcessData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceProcessParserTest, ParseHtraceProcessWithProcessData, TestSize.Level1) +{ + TS_LOGI("test18-2"); + uint64_t ts = 100; + const uint32_t PID = 312; + const string NAME = "resource_schedu"; + const int32_t PPID = 22; + const int32_t UID = 23; + + auto processData = std::make_unique(); + ProcessInfo* processInfo = processData->add_processesinfo(); + processInfo->set_pid(PID); + processInfo->set_name(NAME); + processInfo->set_ppid(PPID); + processInfo->set_uid(UID); + + HtraceProcessParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*processData, ts); + htraceProcessParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstLiveProcessData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseHtraceProcessWithTwoProcessData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceProcessParserTest, ParseHtraceProcessWithTwoProcessData, TestSize.Level1) +{ + TS_LOGI("test18-3"); + uint64_t ts = 100; + const uint32_t PID_01 = 311; + const string NAME_01 = "resource_schedu01"; + const int32_t PPID_01 = 21; + const int32_t UID_01 = 1; + + const uint32_t PID_02 = 312; + const string NAME_02 = "resource_schedu02"; + const int32_t PPID_02 = 22; + const int32_t UID_02 = 2; + + auto processData = std::make_unique(); + ProcessInfo* processInfoFirst = processData->add_processesinfo(); + processInfoFirst->set_pid(PID_01); + processInfoFirst->set_name(NAME_01); + processInfoFirst->set_ppid(PPID_01); + processInfoFirst->set_uid(UID_01); + + ProcessInfo* processInfoSecond = processData->add_processesinfo(); + processInfoSecond->set_pid(PID_02); + processInfoSecond->set_name(NAME_02); + processInfoSecond->set_ppid(PPID_02); + processInfoSecond->set_uid(UID_02); + + HtraceProcessParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*processData, ts); + htraceProcessParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstLiveProcessData().Size(); + EXPECT_EQ(1, size); + + auto pidFirst = stream_.traceDataCache_->GetConstLiveProcessData().ProcessID()[0]; + EXPECT_EQ(pidFirst, PID_02); + auto processNameFirst = stream_.traceDataCache_->GetConstLiveProcessData().ProcessName()[0]; + EXPECT_EQ(processNameFirst, NAME_02); + auto parentProcessIDFirst = stream_.traceDataCache_->GetConstLiveProcessData().ParentProcessID()[0]; + EXPECT_EQ(parentProcessIDFirst, PPID_02); + auto uidFirst = stream_.traceDataCache_->GetConstLiveProcessData().Uid()[0]; + EXPECT_EQ(uidFirst, UID_02); + auto userNameFirst = stream_.traceDataCache_->GetConstLiveProcessData().UserName()[0]; + EXPECT_EQ(userNameFirst, std::to_string(UID_02)); +} + +/** + * @tc.name: ParseHtraceProcessWithThreeProcessData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceProcessParserTest, ParseHtraceProcessWithThreeProcessData, TestSize.Level1) +{ + TS_LOGI("test18-4"); + uint64_t ts = 100; + const uint32_t PID_01 = 311; + const string NAME_01 = "resource_schedu01"; + const int32_t PPID_01 = 21; + const int32_t UID_01 = 1; + + const uint32_t PID_02 = 312; + const string NAME_02 = "resource_schedu02"; + const int32_t PPID_02 = 22; + const int32_t UID_02 = 2; + + const uint32_t PID_03 = 313; + const string NAME_03 = "resource_schedu03"; + const int32_t PPID_03 = 23; + const int32_t UID_03 = 3; + + auto processData = std::make_unique(); + ProcessInfo* processInfoFirst = processData->add_processesinfo(); + processInfoFirst->set_pid(PID_01); + processInfoFirst->set_name(NAME_01); + processInfoFirst->set_ppid(PPID_01); + processInfoFirst->set_uid(UID_01); + + ProcessInfo* processInfoSecond = processData->add_processesinfo(); + processInfoSecond->set_pid(PID_02); + processInfoSecond->set_name(NAME_02); + processInfoSecond->set_ppid(PPID_02); + processInfoSecond->set_uid(UID_02); + + ProcessInfo* processInfoThird = processData->add_processesinfo(); + processInfoThird->set_pid(PID_03); + processInfoThird->set_name(NAME_03); + processInfoThird->set_ppid(PPID_03); + processInfoThird->set_uid(UID_03); + + HtraceProcessParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*processData, ts); + htraceProcessParser.Finish(); + + auto pidFirst = stream_.traceDataCache_->GetConstLiveProcessData().ProcessID()[0]; + auto pidSecond = stream_.traceDataCache_->GetConstLiveProcessData().ProcessID()[1]; + EXPECT_EQ(pidFirst, PID_02); + EXPECT_EQ(pidSecond, PID_03); + auto processNameFirst = stream_.traceDataCache_->GetConstLiveProcessData().ProcessName()[0]; + auto processNameSecond = stream_.traceDataCache_->GetConstLiveProcessData().ProcessName()[1]; + EXPECT_EQ(processNameFirst, NAME_02); + EXPECT_EQ(processNameSecond, NAME_03); + auto parentProcessIDFirst = stream_.traceDataCache_->GetConstLiveProcessData().ParentProcessID()[0]; + auto parentProcessIDSecond = stream_.traceDataCache_->GetConstLiveProcessData().ParentProcessID()[1]; + EXPECT_EQ(parentProcessIDFirst, PPID_02); + EXPECT_EQ(parentProcessIDSecond, PPID_03); + auto uidFirst = stream_.traceDataCache_->GetConstLiveProcessData().Uid()[0]; + auto uidSecond = stream_.traceDataCache_->GetConstLiveProcessData().Uid()[1]; + EXPECT_EQ(uidFirst, UID_02); + EXPECT_EQ(uidSecond, UID_03); + auto userNameFirst = stream_.traceDataCache_->GetConstLiveProcessData().UserName()[0]; + auto userNameSecond = stream_.traceDataCache_->GetConstLiveProcessData().UserName()[1]; + EXPECT_EQ(userNameFirst, std::to_string(UID_02)); + EXPECT_EQ(userNameSecond, std::to_string(UID_03)); +} + +/** + * @tc.name: ParseHtraceProcessWithMultipleProcessData + * @tc.desc: Parse a Process with ProcessData + * @tc.type: FUNC + */ +HWTEST_F(HtraceProcessParserTest, ParseHtraceProcessWithMultipleProcessData, TestSize.Level1) +{ + TS_LOGI("test18-5"); + uint64_t ts = 100; + const uint32_t PID_01 = 311; + const string NAME_01 = "resource_schedu01"; + const int32_t PPID_01 = 21; + const int32_t UID_01 = 1; + + const uint32_t PID_02 = 312; + const string NAME_02 = "resource_schedu02"; + const int32_t PPID_02 = 22; + const int32_t UID_02 = 2; + + const uint32_t PID_03 = 313; + const string NAME_03 = "resource_schedu03"; + const int32_t PPID_03 = 23; + const int32_t UID_03 = 3; + + const uint32_t PID_04 = 313; + const string NAME_04 = "resource_schedu03"; + const int32_t PPID_04 = 23; + const int32_t UID_04 = 3; + + auto processData = std::make_unique(); + ProcessInfo* processInfoFirst = processData->add_processesinfo(); + processInfoFirst->set_pid(PID_01); + processInfoFirst->set_name(NAME_01); + processInfoFirst->set_ppid(PPID_01); + processInfoFirst->set_uid(UID_01); + + ProcessInfo* processInfoSecond = processData->add_processesinfo(); + processInfoSecond->set_pid(PID_02); + processInfoSecond->set_name(NAME_02); + processInfoSecond->set_ppid(PPID_02); + processInfoSecond->set_uid(UID_02); + + ProcessInfo* processInfoThird = processData->add_processesinfo(); + processInfoThird->set_pid(PID_03); + processInfoThird->set_name(NAME_03); + processInfoThird->set_ppid(PPID_03); + processInfoThird->set_uid(UID_03); + + ProcessInfo* processInfoFour = processData->add_processesinfo(); + processInfoFour->set_pid(PID_04); + processInfoFour->set_name(NAME_04); + processInfoFour->set_ppid(PPID_04); + processInfoFour->set_uid(UID_04); + + HtraceProcessParser htraceProcessParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceProcessParser.Parse(*processData, ts); + htraceProcessParser.Finish(); + + auto pidFirst = stream_.traceDataCache_->GetConstLiveProcessData().ProcessID()[0]; + auto pidSecond = stream_.traceDataCache_->GetConstLiveProcessData().ProcessID()[1]; + auto pidThird = stream_.traceDataCache_->GetConstLiveProcessData().ProcessID()[2]; + EXPECT_EQ(pidFirst, PID_02); + EXPECT_EQ(pidSecond, PID_03); + EXPECT_EQ(pidThird, PID_04); + auto processNameFirst = stream_.traceDataCache_->GetConstLiveProcessData().ProcessName()[0]; + auto processNameSecond = stream_.traceDataCache_->GetConstLiveProcessData().ProcessName()[1]; + auto processNameThird = stream_.traceDataCache_->GetConstLiveProcessData().ProcessName()[2]; + EXPECT_EQ(processNameFirst, NAME_02); + EXPECT_EQ(processNameSecond, NAME_03); + EXPECT_EQ(processNameThird, NAME_04); + auto parentProcessIDFirst = stream_.traceDataCache_->GetConstLiveProcessData().ParentProcessID()[0]; + auto parentProcessIDSecond = stream_.traceDataCache_->GetConstLiveProcessData().ParentProcessID()[1]; + auto parentProcessIDThird = stream_.traceDataCache_->GetConstLiveProcessData().ParentProcessID()[2]; + EXPECT_EQ(parentProcessIDFirst, PPID_02); + EXPECT_EQ(parentProcessIDSecond, PPID_03); + EXPECT_EQ(parentProcessIDThird, PPID_04); + auto uidFirst = stream_.traceDataCache_->GetConstLiveProcessData().Uid()[0]; + auto uidSecond = stream_.traceDataCache_->GetConstLiveProcessData().Uid()[1]; + auto uidThird = stream_.traceDataCache_->GetConstLiveProcessData().Uid()[2]; + EXPECT_EQ(uidFirst, UID_02); + EXPECT_EQ(uidSecond, UID_03); + EXPECT_EQ(uidThird, UID_04); + auto userNameFirst = stream_.traceDataCache_->GetConstLiveProcessData().UserName()[0]; + auto userNameSecond = stream_.traceDataCache_->GetConstLiveProcessData().UserName()[1]; + auto userNameThird = stream_.traceDataCache_->GetConstLiveProcessData().UserName()[2]; + EXPECT_EQ(userNameFirst, std::to_string(UID_02)); + EXPECT_EQ(userNameSecond, std::to_string(UID_03)); + EXPECT_EQ(userNameThird, std::to_string(UID_04)); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test/unittest/htrace_sys_mem_parser_test.cpp b/trace_streamer/test/unittest/htrace_sys_mem_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8013864aebcb01c631a9e3eb29daeaff01b6886 --- /dev/null +++ b/trace_streamer/test/unittest/htrace_sys_mem_parser_test.cpp @@ -0,0 +1,276 @@ +/* + * 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 +#include +#include +#include +#include + +#include "htrace_mem_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceSysMemParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() + { + if (access(dbPath_.c_str(), F_OK) == 0) { + remove(dbPath_.c_str()); + } + } + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; + +/** + * @tc.name: ParseSysMemParseInputEmpty + * @tc.desc: Kernel memory parsing test, input empty + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysMemParserTest, ParseSysMemParseInputEmpty, TestSize.Level1) +{ + TS_LOGI("test19-1"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + MemoryData tracePacket; + SysMeminfo* mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + int32_t size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 1); + mem->set_key(SysMeminfoType::PMEM_MEM_TOTAL); + uint64_t value = random(); + mem->set_value(value); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + uint64_t zarm = 100; + tracePacket.set_zram(zarm); + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_EQ(2, stream_.traceDataCache_->GetConstSysMeasureFilterData().Size()); + EXPECT_EQ(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0], static_cast(value)); +} + +/** + * @tc.name: ParseSysMemParseNormal + * @tc.desc: Kernel memory parsing test normal + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysMemParserTest, ParseSysMemParseNormal, TestSize.Level1) +{ + TS_LOGI("test19-2"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysMeminfo* mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + int32_t size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 1); + mem->set_key(SysMeminfoType::PMEM_MEM_TOTAL); + uint64_t value = random(); + mem->set_value(value); + + mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 2); + mem->set_key(SysMeminfoType::PMEM_MEM_FREE); + uint64_t value2 = random(); + mem->set_value(value2); + uint64_t zarm = 100; + tracePacket.set_zram(zarm); + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_EQ(3, stream_.traceDataCache_->GetConstSysMemMeasureData().Size()); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[1] == static_cast(value2)); +} + +/** + * @tc.name: ParseSysMemParseAbnomal + * @tc.desc: Kernel memory parsing test abnomal + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysMemParserTest, ParseSysMemParseAbnomal, TestSize.Level1) +{ + TS_LOGI("test19-3"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysMeminfo* mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + int32_t size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 1); + mem->set_key(SysMeminfoType::PMEM_MEM_TOTAL); + uint64_t value = random(); + mem->set_value(value); + + mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 2); + mem->set_key(static_cast(199999)); // invalid data + uint64_t value2 = random(); + mem->set_value(value2); + uint64_t zarm = 100; + tracePacket.set_zram(zarm); + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_DATA_INVALID); + EXPECT_TRUE(1 == eventCount); + EXPECT_EQ(2, stream_.traceDataCache_->GetConstSysMemMeasureData().Size()); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); +} + +/** + * @tc.name: ParseSysMemParseMutiNomal + * @tc.desc: Kernel memory parsing test with muti nomal + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysMemParserTest, ParseSysMemParseMutiNomal, TestSize.Level1) +{ + TS_LOGI("test19-4"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysMeminfo* mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + int32_t size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 1); + mem->set_key(SysMeminfoType::PMEM_KERNEL_RECLAIMABLE); + uint64_t value = random(); + mem->set_value(value); + + mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 2); + mem->set_key(SysMeminfoType::SysMeminfoType_INT_MIN_SENTINEL_DO_NOT_USE_); + uint64_t value2 = random(); + mem->set_value(value2); + + mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == 3); + mem->set_key(SysMeminfoType::SysMeminfoType_INT_MAX_SENTINEL_DO_NOT_USE_); + uint64_t value3 = random(); + mem->set_value(value3); + uint64_t zarm = 100; + tracePacket.set_zram(zarm); + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_DATA_INVALID); + EXPECT_TRUE(2 == eventCount); + EXPECT_EQ(2, stream_.traceDataCache_->GetConstSysMemMeasureData().Size()); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); +} + +/** + * @tc.name: ParseSysMemParseWithRandomValue + * @tc.desc: Kernel memory parsing test, input a random reasonable value + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysMemParserTest, ParseSysMemParseWithRandomValue, TestSize.Level1) +{ + TS_LOGI("test19-5"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + + std::map sysMemValueMap_ = {}; + for (auto i = 0; i < SysMeminfoType::PMEM_KERNEL_RECLAIMABLE + 1; i++) { + uint64_t value = random(); + sysMemValueMap_.insert(std::make_pair(static_cast(i), value)); + SysMeminfo* mem = tracePacket.add_meminfo(); + EXPECT_TRUE(mem != nullptr); + mem->set_key(static_cast(i)); + mem->set_value(value); + int32_t size = tracePacket.meminfo_size(); + EXPECT_TRUE(size == i + 1); + } + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + + for (auto i = 0; i < SysMeminfoType::PMEM_KERNEL_RECLAIMABLE + 1; i++) { + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[i] == + sysMemValueMap_.at(static_cast(i))); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/htrace_sys_vmem_parser_test.cpp b/trace_streamer/test/unittest/htrace_sys_vmem_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d261f9cbff1cd829c9177c3f7903556d31a0323b --- /dev/null +++ b/trace_streamer/test/unittest/htrace_sys_vmem_parser_test.cpp @@ -0,0 +1,275 @@ +/* + * 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 +#include +#include +#include +#include + +#include "htrace_mem_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +class HtraceSysVMemParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() + { + if (access(dbPath_.c_str(), F_OK) == 0) { + remove(dbPath_.c_str()); + } + } + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; + +/** + * @tc.name: ParseSysVMemParse + * @tc.desc: Virtual memory parsing test, input a random reasonable value + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysVMemParserTest, ParseSysVMemParse, TestSize.Level1) +{ + TS_LOGI("test20-1"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysVMeminfo* vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + int32_t size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 1); + vmem->set_key(SysVMeminfoType::VMEMINFO_UNSPECIFIED); + uint64_t value = random(); + vmem->set_value(value); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); +} + +/** + * @tc.name: ParseSysVMemNomal + * @tc.desc: Virtual memory parsing test nomal + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysVMemParserTest, ParseSysVMemNomal, TestSize.Level1) +{ + TS_LOGI("test20-2"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysVMeminfo* vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + int32_t size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 1); + vmem->set_key(SysVMeminfoType::VMEMINFO_NR_FREE_PAGES); + uint64_t value = random(); + vmem->set_value(value); + + vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 2); + vmem->set_key(SysVMeminfoType::VMEMINFO_NR_ALLOC_BATCH); + uint64_t value2 = random(); + vmem->set_value(value2); + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[1] == static_cast(value2)); +} + +/** + * @tc.name: ParseSysVMemAbnomal + * @tc.desc: Virtual memory parsing test abnomal + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysVMemParserTest, ParseSysVMemAbnomal, TestSize.Level1) +{ + TS_LOGI("test20-3"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysVMeminfo* vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + int32_t size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 1); + vmem->set_key(SysVMeminfoType::VMEMINFO_NR_FREE_PAGES); + uint64_t value = random(); + vmem->set_value(value); + + vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 2); + uint64_t value2 = random(); + vmem->set_value(value2); + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_meminfo(); + delete memParser; + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_DATA_INVALID); + EXPECT_TRUE(0 == eventCount); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); +} + +/** + * @tc.name: ParseSysVMemWithMutiNomal + * @tc.desc: Virtual memory parsing test with muti nomal + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysVMemParserTest, ParseSysVMemWithMutiNomal, TestSize.Level1) +{ + TS_LOGI("test20-4"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + SysVMeminfo* vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + int32_t size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 1); + vmem->set_key(SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE); + uint64_t value = random(); + vmem->set_value(value); + + vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 2); + vmem->set_key(SysVMeminfoType::SysVMeminfoType_INT_MIN_SENTINEL_DO_NOT_USE_); + uint64_t value2 = random(); + vmem->set_value(value2); + + vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == 3); + vmem->set_key(SysVMeminfoType::SysVMeminfoType_INT_MAX_SENTINEL_DO_NOT_USE_); + uint64_t value3 = random(); + vmem->set_value(value3); + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_vmeminfo(); + delete memParser; + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_DATA_INVALID); + EXPECT_TRUE(2 == eventCount); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[0] == static_cast(value)); +} + +/** + * @tc.name: ParseSysVMemWithRandomValue + * @tc.desc: Virtual memory parsing test, input a random reasonable value + * @tc.type: FUNC + */ +HWTEST_F(HtraceSysVMemParserTest, ParseSysVMemWithRandomValue, TestSize.Level1) +{ + TS_LOGI("test20-5"); + HtraceMemParser* memParser = new HtraceMemParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + + std::map sysVMemValueMap_ = {}; + for (auto i = 0; i < SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE + 1; i++) { + uint64_t value = random(); + sysVMemValueMap_.insert(std::make_pair(static_cast(i), value)); + SysVMeminfo* vmem = tracePacket.add_vmeminfo(); + EXPECT_TRUE(vmem != nullptr); + vmem->set_key(static_cast(i)); + vmem->set_value(value); + int32_t size = tracePacket.vmeminfo_size(); + EXPECT_TRUE(size == i + 1); + } + + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_REALTIME; + + memParser->Parse(tracePacket, timeStamp, clock); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_vmeminfo(); + delete memParser; + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SYS_VIRTUAL_MEMORY, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + + for (auto i = 0; i < SysVMeminfoType::VMEMINFO_WORKINGSET_RESTORE + 1; i++) { + EXPECT_TRUE(stream_.traceDataCache_->GetConstSysMemMeasureData().ValuesData()[i] == + sysVMemValueMap_.at(static_cast(i))); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/http_server_test.cpp b/trace_streamer/test/unittest/http_server_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67c686faff21166624f2ed2c9fb67c056924dcec --- /dev/null +++ b/trace_streamer/test/unittest/http_server_test.cpp @@ -0,0 +1,346 @@ +/* + * 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 +#include +#include +#include + +#include "http_server.h" +#include "http_socket.h" +#include "rpc/rpc_server.h" +#include "string_help.h" + +using namespace testing::ext; +namespace SysTuning { +namespace TraceStreamer { +#define UNUSED(expr) \ + do { \ + static_cast(expr); \ + } while (0) + +const uint32_t MAX_TESET_BUF_SIZE = 1024; +std::string g_parserData = "sugov:0-178 ( 178) [001] .... 28462.257501: cpu_frequency: state=816000 cpu_id=0 \n"; +std::string g_sqlQuery("select * from measure;"); +char g_clientRecvBuf[MAX_TESET_BUF_SIZE] = {0}; +class HttpServerTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; +}; + +void ResultCallbackFunc(const std::string result, int32_t num) +{ + // unused + UNUSED(result); +} + +void* HttpServerThread(void* arg) +{ + HttpServer* httpServer = static_cast(arg); + httpServer->Run(); + TS_LOGI("Server thread end"); + pthread_exit(nullptr); +} + +int32_t HttpClient(const char* buf) +{ + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htons(INADDR_ANY); + const uint16_t listenPort = 9001; + addr.sin_port = htons(listenPort); + struct timeval recvTimeout = {1, 100000}; + + int32_t sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + TS_LOGI("CreateSocket socket error"); + return -1; + } + + int32_t ret = connect(sockfd, (struct sockaddr*)(&addr), sizeof(struct sockaddr)); + if (ret < 0) { + TS_LOGE("Connect error"); + return -1; + } + + ret = send(sockfd, buf, strlen(buf), 0); + if (ret < 0) { + TS_LOGE("Send error"); + return -1; + } + + if (!memset_s(g_clientRecvBuf, strlen(g_clientRecvBuf), 0, strlen(g_clientRecvBuf))) { + TS_LOGE("memset_s error"); + return -1; + } + int32_t index = 0; + ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)(&recvTimeout), sizeof(recvTimeout)); + if (ret != 0) { + TS_LOGE("set recv time out error"); + return -1; + } + while (1) { + ret = recv(sockfd, g_clientRecvBuf + index, MAX_TESET_BUF_SIZE, 0); + if (ret < 0) { + TS_LOGE("Recv timeout"); + break; + } + index += ret; + } + return 0; +} + +/** + * @tc.name: HttpCorrectRequest + * @tc.desc: HTTP correct request + * @tc.type: FUNC + */ +HWTEST_F(HttpServerTest, HttpCorrectRequest, TestSize.Level1) +{ + TS_LOGI("test21-1"); + HttpServer httpServer; + RpcServer rpcServer; + pthread_t pthreadId = 0; + int32_t ret = 0; + + ret = rpcServer.ParseData((const uint8_t*)g_parserData.c_str(), g_parserData.length(), ResultCallbackFunc); + ret = rpcServer.ParseDataOver(nullptr, 0, ResultCallbackFunc); + ret = rpcServer.SqlQuery((const uint8_t*)g_sqlQuery.c_str(), g_sqlQuery.length(), ResultCallbackFunc); + + httpServer.RegisterRpcFunction(&rpcServer); + ret = pthread_create(&pthreadId, nullptr, HttpServerThread, &httpServer); + if (ret != 0) { + TS_LOGE("Server pthread create fail"); + pthread_exit(nullptr); + } + + sleep(1); + std::string bufToSend = + "GET /sqlquery HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length:\ + 23\r\n\r\nselect * from measure\r\n"; + + ret = HttpClient(bufToSend.c_str()); + if (ret < 0) { + TS_LOGE("Client fail"); + } + httpServer.Exit(); + ret = pthread_join(pthreadId, nullptr); + if (ret != 0) { + TS_LOGE("Server pthread jion fail"); + } + char targetStr[MAX_TESET_BUF_SIZE] = { + "HTTP/1.1 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: application/json\r\nTransfer-Encoding: " + "chunked\r\n\r\n6d\r\nok\r\n{\"columns\":[\"type\",\"ts\",\"dur\",\"value\",\"filter_id\"],\"values\":[[" + "\"measure\",28462257501000,null,816000,0]]}\r\n\r\n0\r\n\r\n"}; + + EXPECT_STREQ(targetStr, g_clientRecvBuf); +} +/** + * @tc.name: OthreAgreement + * @tc.desc: Use http1 1. Agreements other than agreements + * @tc.type: FUNC + */ +HWTEST_F(HttpServerTest, OthreAgreement, TestSize.Level1) +{ + TS_LOGI("test21-2"); + HttpServer httpServer; + RpcServer rpcServer; + pthread_t pthreadId = 0; + int32_t ret = 0; + + httpServer.RegisterRpcFunction(&rpcServer); + ret = pthread_create(&pthreadId, nullptr, HttpServerThread, &httpServer); + if (ret != 0) { + TS_LOGE("Server pthread create fail"); + pthread_exit(nullptr); + } + + sleep(1); + std::string bufToSend = + "GET /sqlquery HTTP/0.9\r\nHost: 127.0.0.1\r\nContent-Length:\ + 23\r\n\r\nselect * from measure\r\n"; + + ret = HttpClient(bufToSend.c_str()); + if (ret < 0) { + TS_LOGE("Client fail"); + } + httpServer.Exit(); + ret = pthread_join(pthreadId, nullptr); + if (ret != 0) { + TS_LOGE("Server pthread jion fail"); + } + char targetStr[MAX_TESET_BUF_SIZE] = {"HTTP/1.1 400 Bad Request\r\nConnection: Keep-Alive\r\n\r\n"}; + EXPECT_STREQ(targetStr, g_clientRecvBuf); +} + +/** + * @tc.name: OthreProtocols + * @tc.desc: Use protocols other than GET and POST + * @tc.type: FUNC + */ +HWTEST_F(HttpServerTest, OthreProtocols, TestSize.Level1) +{ + TS_LOGI("test21-3"); + HttpServer httpServer; + RpcServer rpcServer; + pthread_t pthreadId = 0; + int32_t ret = 0; + + httpServer.RegisterRpcFunction(&rpcServer); + ret = pthread_create(&pthreadId, nullptr, HttpServerThread, &httpServer); + if (ret != 0) { + TS_LOGE("Server pthread create fail"); + pthread_exit(nullptr); + } + + sleep(1); + std::string bufToSend = + "HEAD /sqlquery HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length:\ + 23\r\n\r\nselect * from measure\r\n"; + + ret = HttpClient(bufToSend.c_str()); + if (ret < 0) { + TS_LOGE("Client fail"); + } + httpServer.Exit(); + ret = pthread_join(pthreadId, nullptr); + if (ret != 0) { + TS_LOGE("Server pthread jion fail"); + } + char targetStr[MAX_TESET_BUF_SIZE] = {"HTTP/1.1 405 Method Not Allowed\r\nConnection: Keep-Alive\r\n\r\n"}; + EXPECT_STREQ(targetStr, g_clientRecvBuf); +} + +/** + * @tc.name: RequestLineFormatError + * @tc.desc: Request line format error + * @tc.type: FUNC + */ +HWTEST_F(HttpServerTest, RequestLineFormatError, TestSize.Level1) +{ + TS_LOGI("test21-4"); + HttpServer httpServer; + RpcServer rpcServer; + pthread_t pthreadId = 0; + int32_t ret = 0; + + httpServer.RegisterRpcFunction(&rpcServer); + ret = pthread_create(&pthreadId, nullptr, HttpServerThread, &httpServer); + if (ret != 0) { + TS_LOGE("Server pthread create fail"); + pthread_exit(nullptr); + } + + sleep(1); + std::string bufToSend = + "POST /sqlqueryHTTP/0.9\r\nHost: 127.0.0.1\r\nContent-Length:\ + 20\r\n\r\nselect * from meta\r\n"; + + ret = HttpClient(bufToSend.c_str()); + if (ret < 0) { + TS_LOGE("Client fail"); + } + httpServer.Exit(); + ret = pthread_join(pthreadId, nullptr); + if (ret != 0) { + TS_LOGE("Server pthread jion fail"); + } + char targetStr[MAX_TESET_BUF_SIZE] = {"HTTP/1.1 400 Bad Request\r\nConnection: Keep-Alive\r\n\r\n"}; + EXPECT_STREQ(targetStr, g_clientRecvBuf); +} + +/** + * @tc.name: RequestIsNotRPC + * @tc.desc: The URI of HTTP request is not the method of RPC + * @tc.type: FUNC + */ +HWTEST_F(HttpServerTest, RequestIsNotRPC, TestSize.Level1) +{ + TS_LOGI("test21-5"); + HttpServer httpServer; + RpcServer rpcServer; + pthread_t pthreadId = 0; + int32_t ret = 0; + + httpServer.RegisterRpcFunction(&rpcServer); + ret = pthread_create(&pthreadId, nullptr, HttpServerThread, &httpServer); + if (ret != 0) { + TS_LOGE("Server pthread create fail"); + pthread_exit(nullptr); + } + + sleep(1); + std::string bufToSend = + "POST /query HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length:20\r\n\r\n\ + select * from meta\r\n"; + + ret = HttpClient(bufToSend.c_str()); + if (ret < 0) { + TS_LOGE("Client fail"); + } + httpServer.Exit(); + ret = pthread_join(pthreadId, nullptr); + if (ret != 0) { + TS_LOGE("Server pthread jion fail"); + } + char targetStr[MAX_TESET_BUF_SIZE] = {"HTTP/1.1 404 Not Found\r\nConnection: Keep-Alive\r\n\r\n"}; + EXPECT_STREQ(targetStr, g_clientRecvBuf); +} +/** + * @tc.name: RequestTimeout + * @tc.desc: Incomplete request content data + * @tc.type: FUNC + */ +HWTEST_F(HttpServerTest, RequestTimeout, TestSize.Level1) +{ + TS_LOGI("test21-6"); + HttpServer httpServer; + RpcServer rpcServer; + pthread_t pthreadId = 0; + int32_t ret = 0; + + httpServer.RegisterRpcFunction(&rpcServer); + ret = pthread_create(&pthreadId, nullptr, HttpServerThread, &httpServer); + if (ret != 0) { + TS_LOGE("Server pthread create fail"); + pthread_exit(nullptr); + } + + sleep(1); + std::string buf = + "GET /sqlquery HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Length:\ + 28\r\n\r\nselect * from measure\r\n"; + + ret = HttpClient(buf.c_str()); + if (ret < 0) { + TS_LOGE("Client fail"); + } + httpServer.Exit(); + ret = pthread_join(pthreadId, nullptr); + if (ret != 0) { + TS_LOGE("Server pthread jion fail"); + } + char targetStr[MAX_TESET_BUF_SIZE] = {"HTTP/1.1 408 Request Time-out\r\nConnection: Keep-Alive\r\n\r\n"}; + EXPECT_STREQ(targetStr, g_clientRecvBuf); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test/unittest/irq_filter_test.cpp b/trace_streamer/test/unittest/irq_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..043dca67c0f376aca9c206066cbebfda7d211302 --- /dev/null +++ b/trace_streamer/test/unittest/irq_filter_test.cpp @@ -0,0 +1,333 @@ +/* + * 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 +#include + +#include "args_filter.h" +#include "irq_filter.h" +#include "slice_filter.h" +#include "stat_filter.h" +#include "ts_common.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class IrqFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.argsFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.irqFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.sliceFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.statFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + streamFilters_.statFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + TraceStreamerFilters streamFilters_; + TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: IrqHandlerEntryTest + * @tc.desc: IrqHandlerEntry Normal TEST + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, IrqHandlerEntryTest, TestSize.Level1) +{ + TS_LOGI("test22-1"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + DataIndex nameId1 = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, nameId1); // IrqHandlerEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); +} + +/** + * @tc.name: IrqHandlerEntryTestNotMatch + * @tc.desc: Test two interrupts, only start, no end + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, IrqHandlerEntryTestNotMatch, TestSize.Level1) +{ + TS_LOGI("test22-2"); + int64_t ts1 = 120; + uint32_t cpu1 = 1; + DataIndex nameId1 = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, nameId1); // IrqHandlerEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + ts1 = 110; + uint32_t irqRet = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, irqRet); // IrqHandlerEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 2); + // TRACE_EVENT_IRQ_HANDLER_ENTRY STAT_EVENT_DATA_LOST + auto eventCount = + traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_LOST); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: IrqHandlerExitTestEmpty + * @tc.desc:Interrupt only ends, not starts + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, IrqHandlerExitTestEmpty, TestSize.Level1) +{ + TS_LOGI("test22-3"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t ret = 1; // 1 for handled, else for unhandled + streamFilters_.irqFilter_->IrqHandlerExit(ts1, cpu1, ret, ret); // IrqHandlerExit + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 0); + // TRACE_EVENT_IRQ_HANDLER_EXIT STAT_EVENT_NOTMATCH + auto eventCount = traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_NOTMATCH); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: IrqHandlerEnterAndExitTest + * @tc.desc: Interrupt normal start and end + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, IrqHandlerEnterAndExitTest, TestSize.Level1) +{ + TS_LOGI("test22-4"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + DataIndex nameId1 = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, nameId1); // IrqHandlerEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + uint32_t irqRet = 1; // 1 for handled, else for unhandled + streamFilters_.irqFilter_->IrqHandlerExit(ts1, cpu1, irqRet, irqRet); // IrqHandlerExit + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 2); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[0] == + static_cast(streamFilters_.irqFilter_->irqHandled_)); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().names_[0] == streamFilters_.irqFilter_->irqRet_); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().argset_[0] == 0); +} + +/** + * @tc.name: IrqHandlerDoubleEnterAndExitTest + * @tc.desc: Interrupt normal test, 2 interrupts and exits + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, IrqHandlerDoubleEnterAndExitTest, TestSize.Level1) +{ + TS_LOGI("test22-5"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + DataIndex nameId1 = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, nameId1); // IrqHandlerEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + uint32_t ret = 1; // 1 for handled, else for unhandled + cpu1 = 2; + ts1 = 150; + streamFilters_.irqFilter_->IrqHandlerExit(ts1, cpu1, ret, ret); // IrqHandlerExit + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_NOTMATCH) == 1); + cpu1 = 1; + ts1 = 200; + streamFilters_.irqFilter_->IrqHandlerExit(ts1, cpu1, ret, ret); // IrqHandlerExit + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().ArgSetIdsData()[0] == 0); +} + +/** + * @tc.name: IrqHandlerTripleEnterAndExitTest + * @tc.desc: Interrupt normal test, 3 interrupts and exits + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, IrqHandlerTripleEnterAndExitTest, TestSize.Level1) +{ + TS_LOGI("test22-6"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + DataIndex nameId1 = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, nameId1); // IrqHandlerEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + uint32_t ret = 1; // 1 for handled, else for unhandled + ts1 = 150; + streamFilters_.irqFilter_->IrqHandlerExit(ts1, cpu1, ret, ret); // IrqHandlerExit + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + // check args + EXPECT_TRUE(traceDataCache_.GetConstIrqData().ArgSetIdsData()[0] == 0); + + ts1 = 200; + cpu1 = 1; + nameId1 = 1; + streamFilters_.irqFilter_->IrqHandlerEntry(ts1, cpu1, nameId1); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 2); + ret = 1; // 1 for handled, else for unhandled + ts1 = 250; + streamFilters_.irqFilter_->IrqHandlerExit(ts1, cpu1, ret, ret); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 2); + // check args + EXPECT_TRUE(traceDataCache_.GetConstIrqData().ArgSetIdsData()[1] == 1); +} + +/** + * @tc.name: SoftIrqEntryTest + * @tc.desc: Soft interrupt normal test + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqEntryTest, TestSize.Level1) +{ + TS_LOGI("test22-7"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); +} + +/** + * @tc.name: SoftIrqEntryNotMatch + * @tc.desc: The soft interrupts do not match. The two interrupts have only the beginning and no end + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqEntryNotMatch, TestSize.Level1) +{ + TS_LOGI("test22-8"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); // SoftIrqEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + ts1 = 150; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); // SoftIrqEntry + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 2); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_LOST) == 1); +} + +/** + * @tc.name: SoftIrqExitEmptyTest + * @tc.desc: The soft interrupt only ends without starting + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqExitEmptyTest, TestSize.Level1) +{ + TS_LOGI("test22-9"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 0); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); +} + +/** + * @tc.name: SoftIrqTest + * @tc.desc: The soft interrupt normal test + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqTest, TestSize.Level1) +{ + TS_LOGI("test22-10"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + ts1 = 150; + uint32_t irqRet = 1; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, irqRet); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().ArgSetIdsData()[0] == 0); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().Size() == 2); + printf("%ld\n", traceDataCache_.GetConstArgSetData().values_[0]); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().values_[0] == + static_cast(streamFilters_.irqFilter_->irqActionNameIds_[irqRet])); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().names_[0] == streamFilters_.irqFilter_->irqRet_); + EXPECT_TRUE(traceDataCache_.GetConstArgSetData().argset_[0] == 0); +} + +/** + * @tc.name: SoftIrqTestWithIrqEntryAndExit + * @tc.desc: The soft interrupt normal test + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqTestWithIrqEntryAndExit, TestSize.Level1) +{ + TS_LOGI("test22-11"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + ts1 = 150; + cpu1 = 2; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); +} + +/** + * @tc.name: SoftIrqTestOneEntryTwoNotMatchExit + * @tc.desc: The soft interrupt test with onece entry and twice Not Match exit + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqTestOneEntryTwoNotMatchExit, TestSize.Level1) +{ + TS_LOGI("test22-12"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + ts1 = 150; + cpu1 = 2; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); + ts1 = 200; + cpu1 = 3; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 2); +} + +/** + * @tc.name: SoftIrqTestWithSingleNotMatchExit + * @tc.desc: The soft interrupt test with single not Match Exit + * @tc.type: FUNC + */ +HWTEST_F(IrqFilterTest, SoftIrqTestWithSingleNotMatchExit, TestSize.Level1) +{ + TS_LOGI("test22-13"); + int64_t ts1 = 100; + uint32_t cpu1 = 1; + uint32_t vec = 1; + streamFilters_.irqFilter_->SoftIrqEntry(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + ts1 = 150; + cpu1 = 2; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); + ts1 = 200; + cpu1 = 1; + streamFilters_.irqFilter_->SoftIrqExit(ts1, cpu1, vec); + EXPECT_TRUE(traceDataCache_.GetConstIrqData().Size() == 1); + EXPECT_TRUE(traceDataCache_.GetConstStatAndInfo().GetValue(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_LOST) == 1); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/js_memory_test.cpp b/trace_streamer/test/unittest/js_memory_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..253224f3b7df6843fd52e69be9410f286b70df0a --- /dev/null +++ b/trace_streamer/test/unittest/js_memory_test.cpp @@ -0,0 +1,770 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include "file.h" +#include "htrace_js_memory_parser.h" +#include "js_heap_config.pb.h" +#include "js_heap_config.pb.cc" +#include "js_heap_config.pbreader.h" +#include "js_heap_result.pb.h" +#include "js_heap_result.pb.cc" +#include "js_heap_result.pbreader.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class JsMemoryTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; +/** + * @tc.name: snapshotParserNodesbyJsmemory + * @tc.desc: snapshot parser nodes + * @tc.type: FUNC + */ +HWTEST_F(JsMemoryTest, snapshotParserNodesByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-1"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(0)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = + "{\"method\":\"HeapProfiler.reportHeapSnapshotProgress\",\"params\":{\"done\":0,\"total\":21288}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,3575,0,0\\n,1,3,3,432,52,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":1,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstJsHeapFilesData().Size(); + EXPECT_EQ(1, size); + auto filePath = stream_.traceDataCache_->GetConstJsHeapFilesData().FilePaths()[0]; + EXPECT_EQ("Snapshot0", filePath); + auto startTime = stream_.traceDataCache_->GetConstJsHeapFilesData().StartTimes()[0]; + EXPECT_EQ(11000, startTime); + auto endTime = stream_.traceDataCache_->GetConstJsHeapFilesData().EndTimes()[0]; + EXPECT_EQ(13000, endTime); + auto pidFiles = stream_.traceDataCache_->GetConstJsHeapFilesData().Pids()[0]; + EXPECT_EQ(1734, pidFiles); + auto type = stream_.traceDataCache_->GetConstJsHeapNodesData().Types()[0]; + EXPECT_EQ(9, type); + auto name = stream_.traceDataCache_->GetConstJsHeapNodesData().Names()[0]; + EXPECT_EQ(25571, name); + auto nodeId = stream_.traceDataCache_->GetConstJsHeapNodesData().NodeIds()[0]; + EXPECT_EQ(1, nodeId); + auto selfSize = stream_.traceDataCache_->GetConstJsHeapNodesData().SelfSizes()[0]; + EXPECT_EQ(0, selfSize); + auto edgeCount = stream_.traceDataCache_->GetConstJsHeapNodesData().EdgeCounts()[0]; + EXPECT_EQ(3575, edgeCount); + auto traceNodeId = stream_.traceDataCache_->GetConstJsHeapNodesData().TraceNodeIds()[0]; + EXPECT_EQ(0, traceNodeId); + auto detachedNess = stream_.traceDataCache_->GetConstJsHeapNodesData().DetachedNess()[0]; + EXPECT_EQ(0, detachedNess); +} + +HWTEST_F(JsMemoryTest, snapshotParserEdgesByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-2"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(0)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = + "{\"method\":\"HeapProfiler.reportHeapSnapshotProgress\",\"params\":{\"done\":0,\"total\":21288}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,1,0,0\\n,1,3,3,432,3,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[5,25572," + "142919\\n,5,25572,144361\\n,5,25572,42455\\n,5,25572,42462\\n,5,25572,42469\\n]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":1,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto edgeType = stream_.traceDataCache_->GetConstJsHeapEdgesData().Types()[0]; + EXPECT_EQ(5, edgeType); + auto nameOrIndex = stream_.traceDataCache_->GetConstJsHeapEdgesData().NameOrIndexs()[0]; + EXPECT_EQ(25572, nameOrIndex); + auto toNodes = stream_.traceDataCache_->GetConstJsHeapEdgesData().ToNodes()[0]; + EXPECT_EQ(142919, toNodes); + auto fromNodeId = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[0]; + EXPECT_EQ(1, fromNodeId); + auto fromNodeId1 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[1]; + EXPECT_EQ(1, fromNodeId1); + auto fromNodeId2 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[2]; + EXPECT_EQ(1, fromNodeId2); + auto fromNodeId3 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[3]; + EXPECT_EQ(1, fromNodeId3); + auto fromNodeId4 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[4]; + EXPECT_EQ(1, fromNodeId4); + auto fromNodeId5 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[5]; + EXPECT_EQ(0, fromNodeId5); +} + +HWTEST_F(JsMemoryTest, timelineParserNodesByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-3"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(1)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = "{\"id\":1,\"result\":{}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,3575,0,0\\n,1,3,3,432,52,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":2,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto size = stream_.traceDataCache_->GetConstJsHeapFilesData().Size(); + EXPECT_EQ(1, size); + auto filePath = stream_.traceDataCache_->GetConstJsHeapFilesData().FilePaths()[0]; + EXPECT_EQ("Timeline", filePath); + auto startTime = stream_.traceDataCache_->GetConstJsHeapFilesData().StartTimes()[0]; + EXPECT_EQ(10000, startTime); + auto endTime = stream_.traceDataCache_->GetConstJsHeapFilesData().EndTimes()[0]; + EXPECT_EQ(13000, endTime); + auto pidFiles = stream_.traceDataCache_->GetConstJsHeapFilesData().Pids()[0]; + EXPECT_EQ(1734, pidFiles); + auto type = stream_.traceDataCache_->GetConstJsHeapNodesData().Types()[0]; + EXPECT_EQ(9, type); + auto name = stream_.traceDataCache_->GetConstJsHeapNodesData().Names()[0]; + EXPECT_EQ(25571, name); + auto nodeId = stream_.traceDataCache_->GetConstJsHeapNodesData().NodeIds()[0]; + EXPECT_EQ(1, nodeId); + auto selfSize = stream_.traceDataCache_->GetConstJsHeapNodesData().SelfSizes()[0]; + EXPECT_EQ(0, selfSize); + auto edgeCount = stream_.traceDataCache_->GetConstJsHeapNodesData().EdgeCounts()[0]; + EXPECT_EQ(3575, edgeCount); + auto traceNodeId = stream_.traceDataCache_->GetConstJsHeapNodesData().TraceNodeIds()[0]; + EXPECT_EQ(0, traceNodeId); + auto detachedNess = stream_.traceDataCache_->GetConstJsHeapNodesData().DetachedNess()[0]; + EXPECT_EQ(0, detachedNess); +} + +HWTEST_F(JsMemoryTest, timelineParserEdgesByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-4"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(1)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = "{\"id\":1,\"result\":{}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,1,0,0\\n,1,3,3,432,3,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[5,25572," + "142919\\n,5,25572,144361\\n,5,25572,42455\\n,5,25572,42462\\n,5,25572,42469\\n]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":2,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto edgeType = stream_.traceDataCache_->GetConstJsHeapEdgesData().Types()[0]; + EXPECT_EQ(5, edgeType); + auto nameOrIndex = stream_.traceDataCache_->GetConstJsHeapEdgesData().NameOrIndexs()[0]; + EXPECT_EQ(25572, nameOrIndex); + auto toNodes = stream_.traceDataCache_->GetConstJsHeapEdgesData().ToNodes()[0]; + EXPECT_EQ(142919, toNodes); + auto fromNodeId = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[0]; + EXPECT_EQ(1, fromNodeId); + auto fromNodeId1 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[1]; + EXPECT_EQ(1, fromNodeId1); + auto fromNodeId2 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[2]; + EXPECT_EQ(1, fromNodeId2); + auto fromNodeId3 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[3]; + EXPECT_EQ(1, fromNodeId3); + auto fromNodeId4 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[4]; + EXPECT_EQ(1, fromNodeId4); + auto fromNodeId5 = stream_.traceDataCache_->GetConstJsHeapEdgesData().FromNodeIds()[5]; + EXPECT_EQ(0, fromNodeId5); +} + +HWTEST_F(JsMemoryTest, timelineParserSamplesByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-5"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(1)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = "{\"id\":1,\"result\":{}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,1,0,0\\n,1,3,3,432,3,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[5,25572," + "142919\\n,5,25572,144361\\n,5,25572,42455\\n,5,25572,42462\\n,5,25572,42469\\n]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[0, 42570\\n, 200631, 42571\\n, 401040, 42572\\n, 601899, " + "42573\\n, 804764, 42574\\n, 1006866, 42575\\n, 1207797, " + "42576\\n],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":2,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto timeStampUs = stream_.traceDataCache_->GetConstJsHeapSampleData().TimeStampUs()[0]; + EXPECT_EQ(0, timeStampUs); + auto lastAssignedIds = stream_.traceDataCache_->GetConstJsHeapSampleData().LastAssignedIds()[0]; + EXPECT_EQ(42570, lastAssignedIds); + auto timeStampUs1 = stream_.traceDataCache_->GetConstJsHeapSampleData().TimeStampUs()[1]; + EXPECT_EQ(200631, timeStampUs1); + auto lastAssignedIds1 = stream_.traceDataCache_->GetConstJsHeapSampleData().LastAssignedIds()[1]; + EXPECT_EQ(42571, lastAssignedIds1); + auto timeStampUs2 = stream_.traceDataCache_->GetConstJsHeapSampleData().TimeStampUs()[2]; + EXPECT_EQ(401040, timeStampUs2); + auto lastAssignedIds2 = stream_.traceDataCache_->GetConstJsHeapSampleData().LastAssignedIds()[2]; + EXPECT_EQ(42572, lastAssignedIds2); + auto timeStampUs3 = stream_.traceDataCache_->GetConstJsHeapSampleData().TimeStampUs()[3]; + EXPECT_EQ(601899, timeStampUs3); + auto lastAssignedIds3 = stream_.traceDataCache_->GetConstJsHeapSampleData().LastAssignedIds()[3]; + EXPECT_EQ(42573, lastAssignedIds3); +} + +HWTEST_F(JsMemoryTest, timelineParserStringsByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-6"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(1)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = "{\"id\":1,\"result\":{}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,1,0,0\\n,1,3,3,432,3,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[5,25572," + "142919\\n,5,25572,144361\\n,5,25572,42455\\n,5,25572,42462\\n,5,25572,42469\\n]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[0, 42570\\n, 200631, 42571\\n, 401040, 42572\\n, 601899, " + "42573\\n, 804764, 42574\\n, 1006866, 42575\\n, 1207797, " + "42576\\n],\\n\\\"strings\\\":[\\\"\\\",\\n\\\"\\\",\\n\\\"GC " + "roots\\\",\\n\\\"TaggedDict[52]\\\",\\n\\\"JSFunction\\\"],\\n\\\"trace_function_infos\\\":[]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":2,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto string = stream_.traceDataCache_->GetConstJsHeapStringData().Strings()[0]; + EXPECT_EQ("", string); + auto string1 = stream_.traceDataCache_->GetConstJsHeapStringData().Strings()[1]; + EXPECT_EQ("", string1); + auto string2 = stream_.traceDataCache_->GetConstJsHeapStringData().Strings()[2]; + EXPECT_EQ("GC roots", string2); + auto string3 = stream_.traceDataCache_->GetConstJsHeapStringData().Strings()[3]; + EXPECT_EQ("TaggedDict[52]", string3); + auto string4 = stream_.traceDataCache_->GetConstJsHeapStringData().Strings()[4]; + EXPECT_EQ("JSFunction", string4); +} + +HWTEST_F(JsMemoryTest, timelineParserTraceFuncInfoByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-7"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(1)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = "{\"id\":1,\"result\":{}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,1,0,0\\n,1,3,3,432,3,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[5,25572," + "142919\\n,5,25572,144361\\n,5,25572,42455\\n,5,25572,42462\\n,5,25572,42469\\n]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[0,181," + "1601,0,0," + "0\\n]," + "\\n\\\"trace_tree\\\":[]}\\n\"}}"; + const char* result4 = "{\"id\":2,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto functionId = stream_.traceDataCache_->GetConstJsHeapTraceFuncInfoData().FunctionIds()[0]; + EXPECT_EQ(0, functionId); + auto name = stream_.traceDataCache_->GetConstJsHeapTraceFuncInfoData().Names()[0]; + EXPECT_EQ(181, name); + auto scriptName = stream_.traceDataCache_->GetConstJsHeapTraceFuncInfoData().ScriptNames()[0]; + EXPECT_EQ(1601, scriptName); + auto scriptId = stream_.traceDataCache_->GetConstJsHeapTraceFuncInfoData().ScriptIds()[0]; + EXPECT_EQ(0, scriptId); + auto line = stream_.traceDataCache_->GetConstJsHeapTraceFuncInfoData().Lines()[0]; + EXPECT_EQ(0, line); + auto column = stream_.traceDataCache_->GetConstJsHeapTraceFuncInfoData().Columns()[0]; + EXPECT_EQ(0, column); +} + +HWTEST_F(JsMemoryTest, timelineParserTraceTreeByJsmemory, TestSize.Level1) +{ + TS_LOGI("test35-8"); + const int32_t pid = 1734; + JsHeapConfig jsHeapConfig; + jsHeapConfig.set_pid(pid); + jsHeapConfig.set_type(::JsHeapConfig_HeapType(1)); + std::string strConfig = ""; + jsHeapConfig.SerializeToString(&strConfig); + + HtraceJSMemoryParser htraceJSMemoryParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + ProtoReader::BytesView tracePacket(reinterpret_cast(strConfig.data()), strConfig.size()); + htraceJSMemoryParser.ParseJSMemoryConfig(tracePacket); + + const char* result1 = "{\"id\":1,\"result\":{}}"; + const char* result2 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"{\\\"snapshot\\\":\\n{\\\"meta\\\":" + "\\n{\\\"node_fields\\\":[\\\"type\\\",\\\"name\\\",\\\"id\\\",\\\"self_size\\\",\\\"edge_count\\\",\\\"trace_" + "node_id\\\",\\\"detachedness\\\"],\\n\\\"node_types\\\":[[\\\"hidden\\\",\\\"array\\\",\\\"string\\\"," + "\\\"object\\\",\\\"code\\\",\\\"closure\\\",\\\"regexp\\\",\\\"number\\\",\\\"native\\\",\\\"synthetic\\\"," + "\\\"concatenated " + "string\\\",\\\"slicedstring\\\",\\\"symbol\\\",\\\"bigint\\\"],\\\"string\\\",\\\"number\\\",\\\"number\\\"," + "\\\"number\\\",\\\"number\\\",\\\"number\\\"],\\n\\\"edge_fields\\\":[\\\"type\\\",\\\"name_or_index\\\"," + "\\\"to_node\\\"],\\n\\\"edge_types\\\":[[\\\"context\\\",\\\"element\\\",\\\"property\\\",\\\"internal\\\"," + "\\\"hidden\\\",\\\"shortcut\\\",\\\"weak\\\"],\\\"string_or_number\\\",\\\"node\\\"],\\n\\\"trace_function_" + "info_fields\\\":[\\\"function_id\\\",\\\"name\\\",\\\"script_name\\\",\\\"script_id\\\",\\\"line\\\"," + "\\\"column\\\"],\\n\\\"trace_node_fields\\\":[\\\"id\\\",\\\"function_info_index\\\",\\\"count\\\"," + "\\\"size\\\",\\\"children\\\"],\\n\\\"sample_fields\\\":[\\\"timestamp_us\\\",\\\"last_assigned_id\\\"]," + "\\n\\\"location_fields\\\":[\\\"object_index\\\",\\\"script_id\\\",\\\"line\\\",\\\"column\\\"]},\\n\\\"node_" + "count\\\":32837,\\n\\\"edge_count\\\":152856,\\n\\\"trace_function_count\\\":0\\n},\\n\\\"nodes\\\":[9,25571," + "1,0,1,0,0\\n,1,3,3,432,3,0,0\\n,8,9,9949,40,\"}}"; + const char* result3 = + "{\"method\":\"HeapProfiler.addHeapSnapshotChunk\",\"params\":{\"chunk\":\"1,0,0],\\n\\\"edges\\\":[5,25572," + "142919\\n,5,25572,144361\\n,5,25572,42455\\n,5,25572,42462\\n,5,25572,42469\\n]," + "\\n\\\"locations\\\":[],\\n\\\"samples\\\":[],\\n\\\"strings\\\":[],\\n\\\"trace_function_infos\\\":[0,181," + "1601,0,0," + "0\\n]," + "\\n\\\"trace_tree\\\":[1,0,53,996,[2,1,571,26580,[],3,2,5,248,[4,3,27,2684,[5,4,1352,68984,[6,5,20,920,[]],7," + "6,5,144,[],8,7,18,636,[9,8,5,120,[10,9,1,28,[]]]]],11,10,10,348,[12,11,11,576,[13,12,21,632,[14,14,0,0,[15,13," + "2,28,[]],16,15,5,188,[17,16,7,196,[]]]]],18,17,10,560,[19,9,2,28,[],20,18,172,7896,[21,19,4,3196,[]]]]]}\\n\"}" + "}"; + const char* result4 = "{\"id\":2,\"result\":{}}"; + JsHeapResult jsHeapResult1; + jsHeapResult1.set_result(result1); + std::string strResult1 = ""; + jsHeapResult1.SerializeToString(&strResult1); + ProtoReader::BytesView tracePacket1(reinterpret_cast(strResult1.data()), strResult1.size()); + htraceJSMemoryParser.Parse(tracePacket1, 10000); + + JsHeapResult jsHeapResult2; + jsHeapResult2.set_result(result2); + std::string strResult2 = ""; + jsHeapResult2.SerializeToString(&strResult2); + ProtoReader::BytesView tracePacket2(reinterpret_cast(strResult2.data()), strResult2.size()); + htraceJSMemoryParser.Parse(tracePacket2, 11000); + + JsHeapResult jsHeapResult3; + jsHeapResult3.set_result(result3); + std::string strResult3 = ""; + jsHeapResult3.SerializeToString(&strResult3); + ProtoReader::BytesView tracePacket3(reinterpret_cast(strResult3.data()), strResult3.size()); + htraceJSMemoryParser.Parse(tracePacket3, 12000); + + JsHeapResult jsHeapResult4; + jsHeapResult4.set_result(result4); + std::string strResult4 = ""; + jsHeapResult4.SerializeToString(&strResult4); + ProtoReader::BytesView tracePacket4(reinterpret_cast(strResult4.data()), strResult4.size()); + htraceJSMemoryParser.Parse(tracePacket4, 13000); + htraceJSMemoryParser.Finish(); + + auto functionInfoIndex = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().FunctionInfoIndexs()[0]; + EXPECT_EQ(0, functionInfoIndex); + auto count = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().Counts()[0]; + EXPECT_EQ(53, count); + auto nodeSize = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().NodeSizes()[0]; + EXPECT_EQ(996, nodeSize); + auto parentId = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().ParentIds()[0]; + EXPECT_EQ(-1, parentId); + auto functionInfoIndex1 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().FunctionInfoIndexs()[1]; + EXPECT_EQ(1, functionInfoIndex1); + auto count1 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().Counts()[1]; + EXPECT_EQ(571, count1); + auto nodeSize1 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().NodeSizes()[1]; + EXPECT_EQ(26580, nodeSize1); + auto parentId1 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().ParentIds()[1]; + EXPECT_EQ(1, parentId1); + auto functionInfoIndex2 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().FunctionInfoIndexs()[2]; + EXPECT_EQ(2, functionInfoIndex2); + auto count2 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().Counts()[2]; + EXPECT_EQ(5, count2); + auto nodeSize2 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().NodeSizes()[2]; + EXPECT_EQ(248, nodeSize2); + auto parentId2 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().ParentIds()[2]; + EXPECT_EQ(1, parentId2); + auto parentId3 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().ParentIds()[3]; + EXPECT_EQ(3, parentId3); + auto parentId4 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().ParentIds()[4]; + EXPECT_EQ(4, parentId4); + auto functionInfoIndex10 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().FunctionInfoIndexs()[10]; + EXPECT_EQ(10, functionInfoIndex10); + auto count10 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().Counts()[10]; + EXPECT_EQ(10, count10); + auto nodeSize10 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().NodeSizes()[10]; + EXPECT_EQ(348, nodeSize10); + auto parentId10 = stream_.traceDataCache_->GetConstJsHeapTraceNodeData().ParentIds()[10]; + EXPECT_EQ(1, parentId10); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/measure_filter_test.cpp b/trace_streamer/test/unittest/measure_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f1f9cd78cca30585fa2d3bbd3647ab3f957117c --- /dev/null +++ b/trace_streamer/test/unittest/measure_filter_test.cpp @@ -0,0 +1,333 @@ +/* + * 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 +#include + +#include "filter_filter.h" +#include "measure_filter.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +constexpr int32_t CPU_ID_0 = 0; +constexpr int32_t CPU_ID_1 = 1; +constexpr std::string_view CPU_TYPE_0 = "cpu_idle"; +constexpr std::string_view CPU_TYPE_1 = "cpu_frequency"; +constexpr int32_t INTERNAL_THREAD_ID_0 = 1; +constexpr int32_t INTERNAL_THREAD_ID_1 = 2; +constexpr int32_t INTERNAL_PROCESS_ID_0 = 1; +constexpr int32_t INTERNAL_PROCESS_ID_1 = 2; +constexpr std::string_view TASK_NAME_0 = "softbus_server"; +constexpr std::string_view TASK_NAME_1 = "hiprofilerd"; + +class MeasureFilterTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: ThreadMeasureFilter + * @tc.desc: Test whether the GetOrCreateFilterId interface generated filterid and threadmeasure Info is correct + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, ThreadMeasureFilter, TestSize.Level1) +{ + TS_LOGI("test23-1"); + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_0); + uint32_t filterId = + stream_.streamFilters_->threadMeasureFilter_->GetOrCreateFilterId(INTERNAL_THREAD_ID_0, nameIndex0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex1 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_1); + filterId = stream_.streamFilters_->threadMeasureFilter_->GetOrCreateFilterId(INTERNAL_THREAD_ID_1, nameIndex1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + ThreadMeasureFilter* threadMeasureTable = stream_.traceDataCache_->GetThreadMeasureFilterData(); + EXPECT_TRUE(threadMeasureTable->Size() == 2); + EXPECT_TRUE(threadMeasureTable->FilterIdData()[0] == 0); + EXPECT_TRUE(threadMeasureTable->FilterIdData()[1] == 1); + EXPECT_TRUE(threadMeasureTable->InternalTidData()[0] == INTERNAL_THREAD_ID_0); + EXPECT_TRUE(threadMeasureTable->InternalTidData()[1] == INTERNAL_THREAD_ID_1); +} + +/** + * @tc.name: ThreadFilter + * @tc.desc: Test whether the GetOrCreateFilterId interface generated filterid and thread Info is correct + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, ThreadFilter, TestSize.Level1) +{ + TS_LOGI("test23-2"); + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_0); + uint32_t filterId = stream_.streamFilters_->threadFilter_->GetOrCreateFilterId(INTERNAL_THREAD_ID_0, nameIndex0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex1 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_1); + filterId = stream_.streamFilters_->threadFilter_->GetOrCreateFilterId(INTERNAL_THREAD_ID_1, nameIndex1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + ThreadMeasureFilter* threadTable = stream_.traceDataCache_->GetThreadFilterData(); + EXPECT_TRUE(threadTable->Size() == 2); + EXPECT_TRUE(threadTable->FilterIdData()[0] == 0); + EXPECT_TRUE(threadTable->FilterIdData()[1] == 1); + EXPECT_TRUE(threadTable->InternalTidData()[0] == INTERNAL_THREAD_ID_0); + EXPECT_TRUE(threadTable->InternalTidData()[1] == INTERNAL_THREAD_ID_1); +} + +/** + * @tc.name: CpuFilter + * @tc.desc: Test GetOrCreateFilterId interface of class CpuFilter + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, CpuFilter, TestSize.Level1) +{ + TS_LOGI("test23-3"); + auto nameIndex_0 = stream_.traceDataCache_->GetDataIndex(CPU_TYPE_0); + uint32_t filterId = stream_.streamFilters_->cpuMeasureFilter_->GetOrCreateFilterId(CPU_ID_0, nameIndex_0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex_1 = stream_.traceDataCache_->GetDataIndex(CPU_TYPE_1); + filterId = stream_.streamFilters_->cpuMeasureFilter_->GetOrCreateFilterId(CPU_ID_1, nameIndex_1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + CpuMeasureFilter* cpuMeasureTable = stream_.traceDataCache_->GetCpuMeasuresData(); + EXPECT_TRUE(cpuMeasureTable->Size() == 2); + EXPECT_TRUE(cpuMeasureTable->IdsData()[0] == 0); + EXPECT_TRUE(cpuMeasureTable->IdsData()[1] == 1); + EXPECT_TRUE(cpuMeasureTable->CpuData()[0] == CPU_ID_0); + EXPECT_TRUE(cpuMeasureTable->CpuData()[1] == CPU_ID_1); +} + +/** + * @tc.name: ProcessFilter + * @tc.desc: Test GetOrCreateFilterId interface of class ProcessFilter + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, ProcessFilter, TestSize.Level1) +{ + TS_LOGI("test23-4"); + auto nameIndex_0 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_0); + uint32_t filterId = + stream_.streamFilters_->processFilterFilter_->GetOrCreateFilterId(INTERNAL_PROCESS_ID_0, nameIndex_0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex_1 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_1); + filterId = stream_.streamFilters_->processFilterFilter_->GetOrCreateFilterId(INTERNAL_PROCESS_ID_1, nameIndex_1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + ProcessMeasureFilter* processFilterTable = stream_.traceDataCache_->GetProcessFilterData(); + EXPECT_TRUE(processFilterTable->Size() == 2); +} + +/** + * @tc.name: ClockRateFilter + * @tc.desc: Test GetOrCreateFilterId interface of class ClockRateFilter + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, ClockRateFilter, TestSize.Level1) +{ + TS_LOGI("test23-5"); + auto nameIndex_0 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_0); + uint32_t filterId = stream_.streamFilters_->clockRateFilter_->GetOrCreateFilterId(CPU_ID_0, nameIndex_0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex_1 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_1); + filterId = stream_.streamFilters_->clockRateFilter_->GetOrCreateFilterId(CPU_ID_1, nameIndex_1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + ClockEventData* clockEventTable = stream_.traceDataCache_->GetClockEventFilterData(); + EXPECT_TRUE(clockEventTable->Size() == 2); + EXPECT_TRUE(clockEventTable->CpusData()[0] == CPU_ID_0); + EXPECT_TRUE(clockEventTable->CpusData()[1] == CPU_ID_1); + EXPECT_TRUE(clockEventTable->NamesData()[0] == nameIndex_0); + EXPECT_TRUE(clockEventTable->NamesData()[1] == nameIndex_1); +} + +/** + * @tc.name: ClockEnableFilter + * @tc.desc: Test GetOrCreateFilterId interface of class ClockEnableFilter + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, ClockEnableFilter, TestSize.Level1) +{ + TS_LOGI("test23-6"); + auto nameIndex_0 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_0); + uint32_t filterId = stream_.streamFilters_->clockEnableFilter_->GetOrCreateFilterId(CPU_ID_0, nameIndex_0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex_1 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_1); + filterId = stream_.streamFilters_->clockEnableFilter_->GetOrCreateFilterId(CPU_ID_1, nameIndex_1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + ClockEventData* clockEventTable = stream_.traceDataCache_->GetClockEventFilterData(); + EXPECT_TRUE(clockEventTable->Size() == 2); + EXPECT_TRUE(clockEventTable->CpusData()[0] == CPU_ID_0); + EXPECT_TRUE(clockEventTable->CpusData()[1] == CPU_ID_1); + EXPECT_TRUE(clockEventTable->NamesData()[0] == nameIndex_0); + EXPECT_TRUE(clockEventTable->NamesData()[1] == nameIndex_1); +} + +/** + * @tc.name: ClockDisableFilter + * @tc.desc: Test GetOrCreateFilterId interface of class ClockDisableFilter + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, ClockDisableFilter, TestSize.Level1) +{ + TS_LOGI("test23-7"); + auto nameIndex_0 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_0); + uint32_t filterId = stream_.streamFilters_->clockDisableFilter_->GetOrCreateFilterId(CPU_ID_0, nameIndex_0); + EXPECT_TRUE(filterId == 0); + + auto nameIndex_1 = stream_.traceDataCache_->GetDataIndex(TASK_NAME_1); + filterId = stream_.streamFilters_->clockDisableFilter_->GetOrCreateFilterId(CPU_ID_1, nameIndex_1); + EXPECT_TRUE(filterId == 1); + + Filter* filterTable = stream_.traceDataCache_->GetFilterData(); + EXPECT_TRUE(filterTable->Size() == 2); + + ClockEventData* clockEventTable = stream_.traceDataCache_->GetClockEventFilterData(); + EXPECT_TRUE(clockEventTable->Size() == 2); + EXPECT_TRUE(clockEventTable->CpusData()[0] == CPU_ID_0); + EXPECT_TRUE(clockEventTable->CpusData()[1] == CPU_ID_1); + EXPECT_TRUE(clockEventTable->NamesData()[0] == nameIndex_0); + EXPECT_TRUE(clockEventTable->NamesData()[1] == nameIndex_1); +} + +/** + * @tc.name: MeasureFilterTest + * @tc.desc: Test GetOrCreateFilterId interface of class MeasureFilterTest + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, MeasureFilterTest, TestSize.Level1) +{ + TS_LOGI("test23-8"); + uint64_t itid = 1; + const std::string_view MEASURE_ITEM_NAME = "mem_rss"; + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME); + auto threadMeasureFilter = stream_.streamFilters_->processMeasureFilter_.get(); + threadMeasureFilter->AppendNewMeasureData(itid, nameIndex0, 168758682476000, 1200); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == 1); +} + +/** + * @tc.name: MeasureFilterAddMultiMemToSingleThread + * @tc.desc: Test GetOrCreateFilterId interface of class MeasureFilterTest, Adding multiple memory information tests to + * the same thread + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, MeasureFilterAddMultiMemToSingleThread, TestSize.Level1) +{ + TS_LOGI("test23-9"); + uint64_t itid = 1; + auto threadMeasureFilter = stream_.streamFilters_->processMeasureFilter_.get(); + const std::string_view MEASURE_ITEM_NAME = "mem_rss"; + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME); + threadMeasureFilter->AppendNewMeasureData(itid, nameIndex0, 168758682476000, 1200); + const std::string_view MEASURE_ITEM_NAME2 = "mem_vm"; + auto nameIndex1 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME2); + threadMeasureFilter->AppendNewMeasureData(itid, nameIndex1, 168758682477000, 9200); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == 2); +} + +/** + * @tc.name: MeasureFilterAddMultiMemToMultiThread + * @tc.desc: Test GetOrCreateFilterId interface of class MeasureFilterTest, Adding multiple memory information to multi + * thread + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, MeasureFilterAddMultiMemToMultiThread, TestSize.Level1) +{ + TS_LOGI("test23-10"); + uint64_t itid = 1; + uint64_t itid2 = 2; + auto threadMeasureFilter = stream_.streamFilters_->processMeasureFilter_.get(); + const std::string_view MEASURE_ITEM_NAME = "mem_rss"; + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME); + threadMeasureFilter->AppendNewMeasureData(itid, nameIndex0, 168758682476000, 1200); + const std::string_view MEASURE_ITEM_NAME2 = "mem_vm"; + auto nameIndex1 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME2); + threadMeasureFilter->AppendNewMeasureData(itid2, nameIndex1, 168758682477000, 9200); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == 2); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().ValuesData()[0] == 1200); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().ValuesData()[1] == 9200); +} + +/** + * @tc.name: MeasureFilterAddPerfclLfMux + * @tc.desc: Add perfcl_ lf_mux status test + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, MeasureFilterAddPerfclLfMux, TestSize.Level1) +{ + TS_LOGI("test23-11"); + uint64_t cpuId = 1; + int64_t state = 0; + auto threadMeasureFilter = stream_.streamFilters_->clockDisableFilter_.get(); + const std::string_view MEASURE_ITEM_NAME = "perfcl_lf_mux"; + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME); + threadMeasureFilter->AppendNewMeasureData(cpuId, nameIndex0, 168758682476000, state); + EXPECT_TRUE(stream_.traceDataCache_->GetConstMeasureData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstMeasureData().ValuesData()[0] == state); +} + +/** + * @tc.name: MeasureFilterAddPerfclPll + * @tc.desc: Add perfcl_pll status test + * @tc.type: FUNC + */ +HWTEST_F(MeasureFilterTest, MeasureFilterAddPerfclPll, TestSize.Level1) +{ + TS_LOGI("test23-12"); + uint64_t cpuId = 1; + int64_t state = 1747200000; + auto threadMeasureFilter = stream_.streamFilters_->clockRateFilter_.get(); + const std::string_view MEASURE_ITEM_NAME = "perfcl_pll"; + auto nameIndex0 = stream_.traceDataCache_->GetDataIndex(MEASURE_ITEM_NAME); + threadMeasureFilter->AppendNewMeasureData(cpuId, nameIndex0, 168758682476000, state); + EXPECT_TRUE(stream_.traceDataCache_->GetConstMeasureData().Size() == 1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstMeasureData().ValuesData()[0] == state); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/native_hook_parser_test.cpp b/trace_streamer/test/unittest/native_hook_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a88aaaec706350ed7b715e84288fb4ab7cef2b99 --- /dev/null +++ b/trace_streamer/test/unittest/native_hook_parser_test.cpp @@ -0,0 +1,1915 @@ +/* + * 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 +#include +#include +#include + +#include "htrace_native_hook_parser.h" +#include "native_hook_result.pb.h" +#include "parser/bytrace_parser/bytrace_parser.h" +#include "parser/common_types.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; + +namespace SysTuning { +namespace TraceStreamer { +const uint64_t TV_SEC_01 = 1632675525; +const uint64_t TV_SEC_02 = 1632675526; +const uint64_t TV_SEC_03 = 1632675527; +const uint64_t TV_SEC_04 = 1632675528; +const uint64_t TV_NSEC_01 = 996560701; +const uint64_t TV_NSEC_02 = 999560702; +const uint64_t TV_NSEC_03 = 996560703; +const uint64_t TV_NSEC_04 = 999560704; +const uint64_t TIMESTAMP_01 = TV_NSEC_01 + TV_SEC_01 * SEC_TO_NS; +const uint64_t TIMESTAMP_02 = TV_NSEC_02 + TV_SEC_02 * SEC_TO_NS; +const uint64_t TIMESTAMP_03 = TV_NSEC_03 + TV_SEC_03 * SEC_TO_NS; +const uint64_t TIMESTAMP_04 = TV_NSEC_04 + TV_SEC_04 * SEC_TO_NS; +const int32_t PID = 2716; +const int32_t TID_01 = 1532; +const int32_t TID_02 = 1532; +const uint64_t MEM_ADDR_01 = 10453088; +const uint64_t MEM_ADDR_02 = 10453089; +const uint64_t MEM_ADDR_03 = 10453090; +const int64_t MEM_SIZE_01 = 4096; +const int64_t MEM_SIZE_02 = 2048; +const uint64_t CALL_STACK_IP_01 = 4154215627; +const uint64_t CALL_STACK_IP_02 = 4154215630; +const uint64_t CALL_STACK_SP_01 = 4146449696; +const uint64_t CALL_STACK_SP_02 = 4146449698; +const std::string SYMBOL_NAME_01 = "__aeabi_read_tp"; +const std::string SYMBOL_NAME_02 = "ThreadMmap"; +const std::string FILE_PATH_01 = "/system/lib/ld-musl-arm.so.1"; +const std::string FILE_PATH_02 = "/system/bin/nativetest_c"; +const uint64_t OFFSET_01 = 359372; +const uint64_t OFFSET_02 = 17865; +const uint64_t SYMBOL_OFFSET_01 = 255; +const uint64_t SYMBOL_OFFSET_02 = 33; +const std::string ALLOCEVENT = "AllocEvent"; +const std::string FREEEVENT = "FreeEvent"; +const std::string MMAPEVENT = "MmapEvent"; +const std::string MUNMAPEVENT = "MunmapEvent"; +const std::string MMAP_SUB_TYPE_01 = "mmapType1"; +const std::string MMAP_SUB_TYPE_02 = "mmapType2"; +class NativeHookParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; +}; + +class NativeHookCache { +public: + NativeHookCache(const uint64_t callChainId, + const uint32_t ipid, + const uint32_t itid, + const std::string eventType, + const uint64_t subType, + const uint64_t startTimeStamp, + const uint64_t endTimeStamp, + const uint64_t duration, + const uint64_t address, + const int64_t memSize, + const int64_t allMemSize, + const uint64_t currentSizeDurations) + : callChainId_(callChainId), + ipid_(ipid), + itid_(itid), + eventType_(eventType), + subType_(subType), + startTimeStamp_(startTimeStamp), + endTimeStamp_(endTimeStamp), + duration_(duration), + address_(address), + memSize_(memSize), + allMemSize_(allMemSize), + currentSizeDurations_(currentSizeDurations) + { + } + + NativeHookCache(const NativeHook& nativeHook, uint64_t index) + { + if (nativeHook.Size() <= index) { + TS_LOGE("index out of deque bounds! nativeHook.Size() = %lu, index = %lu", nativeHook.Size(), index); + return; + } + callChainId_ = nativeHook.CallChainIds()[index]; + ipid_ = nativeHook.Ipids()[index]; + itid_ = nativeHook.Itids()[index]; + eventType_ = nativeHook.EventTypes()[index]; + subType_ = nativeHook.SubTypes()[index]; + startTimeStamp_ = nativeHook.TimeStampData()[index]; + endTimeStamp_ = nativeHook.EndTimeStamps()[index]; + duration_ = nativeHook.Durations()[index]; + address_ = nativeHook.Addrs()[index]; + memSize_ = nativeHook.MemSizes()[index]; + allMemSize_ = nativeHook.AllMemSizes()[index]; + currentSizeDurations_ = nativeHook.CurrentSizeDurs()[index]; + } + ~NativeHookCache() = default; + NativeHookCache(const NativeHookCache&) = delete; + NativeHookCache& operator=(const NativeHookCache&) = delete; + bool operator==(const NativeHookCache& nativeHookCache) const + { + if (nativeHookCache.GetCallChainId() != callChainId_) { + TS_LOGE("callChainId_ = %lu, nativeHookCache.GetCallChainId() = %lu", callChainId_, + nativeHookCache.GetCallChainId()); + return false; + } + if (nativeHookCache.GetPid() != ipid_) { + TS_LOGE("ipid_ = %u, nativeHookCache.GetPid() = %u", ipid_, nativeHookCache.GetPid()); + return false; + } + if (nativeHookCache.GetTid() != itid_) { + TS_LOGE("itid_ = %u, nativeHookCache.GetTid() = %u", nativeHookCache.GetTid(), itid_); + return false; + } + if (nativeHookCache.GetEventType() != eventType_) { + TS_LOGE("eventType_ = %s, nativeHookCache.GetEventType() = %s", eventType_.c_str(), + nativeHookCache.GetEventType().c_str()); + return false; + } + if (nativeHookCache.GetSubType() != subType_) { + TS_LOGE("subType_ = %lu, nativeHookCache.GetSubType() = %lu", subType_, nativeHookCache.GetSubType()); + return false; + } + if (nativeHookCache.GetStartTimeStamp() != startTimeStamp_) { + TS_LOGE("startTimeStamp_ = %lu, nativeHookCache.GetStartTimeStamp() = %lu", startTimeStamp_, + nativeHookCache.GetStartTimeStamp()); + return false; + } + if (nativeHookCache.GetEndTimeStamp() != endTimeStamp_) { + TS_LOGE(" endTimeStamp_ = %lu, nativeHookCache.GetEndTimeStamp() = %lu", endTimeStamp_, + nativeHookCache.GetEndTimeStamp()); + return false; + } + if (nativeHookCache.GetDuration() != duration_) { + TS_LOGE("duration_ = %lu, nativeHookCache.GetDuration() = %lu", duration_, nativeHookCache.GetDuration()); + return false; + } + if (nativeHookCache.GetEndTimeStamp() != endTimeStamp_) { + TS_LOGE("address_ = %lu, nativeHookCache.GetAddress() = %lu", address_, nativeHookCache.GetAddress()); + return false; + } + if (nativeHookCache.GetMemSize() != memSize_) { + TS_LOGE("memSize_ = %ld, nativeHookCache.GetMemSize() = %ld", memSize_, nativeHookCache.GetMemSize()); + return false; + } + if (nativeHookCache.GetAllMemSize() != allMemSize_) { + TS_LOGE("allMemSize_ = %lu, nativeHookCache.GetAllMemSize() = %lu", allMemSize_, + nativeHookCache.GetAllMemSize()); + return false; + } + if (nativeHookCache.GetCurrentSizeDuration() != currentSizeDurations_) { + TS_LOGE("currentSizeDurations_ = %lu, nativeHookCache.GetCurrentSizeDuration() = %lu", + currentSizeDurations_, nativeHookCache.GetCurrentSizeDuration()); + return false; + } + return true; + } + inline uint64_t GetCallChainId() const + { + return callChainId_; + } + inline uint32_t GetPid() const + { + return ipid_; + } + inline uint32_t GetTid() const + { + return itid_; + } + inline std::string GetEventType() const + { + return eventType_; + } + inline uint64_t GetSubType() const + { + return subType_; + } + inline uint64_t GetStartTimeStamp() const + { + return startTimeStamp_; + } + inline uint64_t GetEndTimeStamp() const + { + return endTimeStamp_; + } + inline uint64_t GetDuration() const + { + return duration_; + } + inline uint64_t GetAddress() const + { + return address_; + } + inline int64_t GetMemSize() const + { + return memSize_; + } + inline int64_t GetAllMemSize() const + { + return allMemSize_; + } + inline uint64_t GetCurrentSizeDuration() const + { + return currentSizeDurations_; + } + +private: + uint64_t callChainId_; + uint32_t ipid_; + uint32_t itid_; + std::string eventType_; + uint64_t subType_; + uint64_t startTimeStamp_; + uint64_t endTimeStamp_; + uint64_t duration_; + uint64_t address_; + int64_t memSize_; + int64_t allMemSize_; + uint64_t currentSizeDurations_; +}; + +class NativeHookFrameCache { +public: + NativeHookFrameCache(const uint64_t callChainId, + const uint64_t depth, + const uint64_t ip, + const uint64_t sp, + const uint64_t symbolName, + const uint64_t filePath, + const uint64_t offset, + const uint64_t symbolOffset) + : callChainId_(callChainId), + depth_(depth), + ip_(ip), + sp_(sp), + symbolName_(symbolName), + filePath_(filePath), + offset_(offset), + symbolOffset_(symbolOffset) + { + } + + NativeHookFrameCache(const NativeHookFrame& nativeHookFrame, const uint64_t index) + { + if (nativeHookFrame.Size() <= index) { + TS_LOGE("index out of deque bounds! nativeHookFrame.Size() = %lu, index = %lu", nativeHookFrame.Size(), + index); + return; + } + callChainId_ = nativeHookFrame.CallChainIds()[index]; + depth_ = nativeHookFrame.Depths()[index]; + ip_ = nativeHookFrame.Ips()[index]; + sp_ = nativeHookFrame.Sps()[index]; + symbolName_ = nativeHookFrame.SymbolNames()[index]; + filePath_ = nativeHookFrame.FilePaths()[index]; + offset_ = nativeHookFrame.Offsets()[index]; + symbolOffset_ = nativeHookFrame.SymbolOffsets()[index]; + } + + ~NativeHookFrameCache() = default; + NativeHookFrameCache(const NativeHookFrameCache&) = delete; + NativeHookFrameCache& operator=(const NativeHookFrameCache&) = delete; + bool operator==(const NativeHookFrameCache& frameCache) const + { + if (frameCache.GetCallChainId() != callChainId_) { + TS_LOGE("callChainId_ = %lu, frameCache.GetCallChainId() = %lu", callChainId_, frameCache.GetCallChainId()); + return false; + } + if (frameCache.GetDepth() != depth_) { + TS_LOGE("depth_ = %lu, frameCache.GetDepth() = %lu", depth_, frameCache.GetDepth()); + return false; + } + if (frameCache.GetIp() != ip_) { + TS_LOGE("ip_ = %lu, frameCache.GetIp() = %lu", ip_, frameCache.GetIp()); + return false; + } + if (frameCache.GetSp() != sp_) { + TS_LOGE("sp_ = %lu, frameCache.GetSp() = %lu", sp_, frameCache.GetSp()); + return false; + } + if (frameCache.GetSymbolName() != symbolName_) { + TS_LOGE("symbolName_ = %lu, frameCache.GetSymbolName() = %lu", symbolName_, frameCache.GetSymbolName()); + return false; + } + if (frameCache.GetFilePath() != filePath_) { + TS_LOGE("filePath_ = %lu, frameCache.GetFilePath() = %lu", filePath_, frameCache.GetFilePath()); + return false; + } + if (frameCache.GetOffset() != offset_) { + TS_LOGE("offset_ = %lu, frameCache.GetOffset() = %lu", offset_, frameCache.GetOffset()); + return false; + } + if (frameCache.GetSymbolOffset() != symbolOffset_) { + TS_LOGE("symbolOffset_ = %lu, frameCache.GetSymbolName() = %lu", symbolOffset_, frameCache.GetSymbolName()); + return false; + } + return true; + } + inline uint64_t GetCallChainId() const + { + return callChainId_; + } + inline uint64_t GetDepth() const + { + return depth_; + } + inline uint64_t GetIp() const + { + return ip_; + } + inline uint64_t GetSp() const + { + return sp_; + } + inline uint64_t GetSymbolName() const + { + return symbolName_; + } + inline uint64_t GetFilePath() const + { + return filePath_; + } + inline uint64_t GetOffset() const + { + return offset_; + } + inline uint64_t GetSymbolOffset() const + { + return symbolOffset_; + } + +private: + uint64_t callChainId_; + uint64_t depth_; + uint64_t ip_; + uint64_t sp_; + uint64_t symbolName_; + uint64_t filePath_; + uint64_t offset_; + uint64_t symbolOffset_; +}; + +/** + * @tc.name: ParseBatchNativeHookWithOutNativeHookData + * @tc.desc: Parse a BatchNativeHookData that does not contain any NativeHookData + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithOutNativeHookData, TestSize.Level1) +{ + TS_LOGI("test24-1"); + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + auto size = stream_.traceDataCache_->GetConstHilogData().Size(); + EXPECT_FALSE(size); +} + +/** + * @tc.name: ParseBatchNativeHookWithOneMalloc + * @tc.desc: Parse a BatchNativeHookData with only one Malloc + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithOneMalloc, TestSize.Level1) +{ + TS_LOGI("test24-2"); + // construct AllocEvent + AllocEvent* allocEvent = new AllocEvent(); + allocEvent->set_pid(PID); + allocEvent->set_tid(TID_01); + allocEvent->set_addr(MEM_ADDR_01); + allocEvent->set_size(MEM_SIZE_01); + // construct AllocEvent's Frame + auto frame = allocEvent->add_frame_info(); + frame->set_ip(CALL_STACK_IP_01); + frame->set_sp(CALL_STACK_SP_01); + frame->set_symbol_name(SYMBOL_NAME_01); + frame->set_file_path(FILE_PATH_01); + frame->set_offset(OFFSET_01); + frame->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookData = batchNativeHookData->add_events(); + nativeHookData->set_tv_sec(TV_SEC_01); + nativeHookData->set_tv_nsec(TV_NSEC_01); + nativeHookData->set_allocated_alloc_event(allocEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + NativeHookCache expectNativeHookCache(1, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, TIMESTAMP_01, + 0, 0, MEM_ADDR_01, MEM_SIZE_01, MEM_SIZE_01, 0); + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + NativeHookCache resultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(expectNativeHookCache == resultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(1, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache expectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache resultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(expectFrameCache == resultFrameCache); + + size = nativeHookFrame.Size(); + EXPECT_EQ(1, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithMultipleMalloc + * @tc.desc: Parse a NativeHook with multiple Malloc and Frame + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithMultipleMalloc, TestSize.Level1) +{ + TS_LOGI("test24-3"); + // constructs first AllocEvent with two Frame + AllocEvent* firstAllocEvent = new AllocEvent(); + firstAllocEvent->set_pid(PID); + firstAllocEvent->set_tid(TID_01); + firstAllocEvent->set_addr(MEM_ADDR_01); + firstAllocEvent->set_size(MEM_SIZE_01); + // construct first AllocEvent's first Frame + auto firstAllocFirstFrame = firstAllocEvent->add_frame_info(); + firstAllocFirstFrame->set_ip(CALL_STACK_IP_01); + firstAllocFirstFrame->set_sp(CALL_STACK_SP_01); + firstAllocFirstFrame->set_symbol_name(SYMBOL_NAME_01); + firstAllocFirstFrame->set_file_path(FILE_PATH_01); + firstAllocFirstFrame->set_offset(OFFSET_01); + firstAllocFirstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + // construct first AllocEvent's second Frame + auto firstAllocSecondFrame = firstAllocEvent->add_frame_info(); + firstAllocSecondFrame->set_ip(CALL_STACK_IP_02); + firstAllocSecondFrame->set_sp(CALL_STACK_SP_02); + firstAllocSecondFrame->set_symbol_name(SYMBOL_NAME_02); + firstAllocSecondFrame->set_file_path(FILE_PATH_02); + firstAllocSecondFrame->set_offset(OFFSET_02); + firstAllocSecondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // constructs second AllocEvent with two Frame + AllocEvent* secondAllocEvent = new AllocEvent(); + secondAllocEvent->set_pid(PID); + secondAllocEvent->set_tid(TID_02); + secondAllocEvent->set_addr(MEM_ADDR_02); + secondAllocEvent->set_size(MEM_SIZE_02); + // construct second AllocEvent's first Frame + auto secondAllocFirstFrame = secondAllocEvent->add_frame_info(); + secondAllocFirstFrame->set_ip(CALL_STACK_IP_01); + secondAllocFirstFrame->set_sp(CALL_STACK_SP_01); + secondAllocFirstFrame->set_symbol_name(SYMBOL_NAME_01); + secondAllocFirstFrame->set_file_path(FILE_PATH_01); + secondAllocFirstFrame->set_offset(OFFSET_01); + secondAllocFirstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + // construct second AllocEvent's second Frame + auto secondAllocSecondFrame = secondAllocEvent->add_frame_info(); + secondAllocSecondFrame->set_ip(CALL_STACK_IP_02); + secondAllocSecondFrame->set_sp(CALL_STACK_SP_02); + secondAllocSecondFrame->set_symbol_name(SYMBOL_NAME_02); + secondAllocSecondFrame->set_file_path(FILE_PATH_02); + secondAllocSecondFrame->set_offset(OFFSET_02); + secondAllocSecondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add first NativeHookData + auto firstNativeHookData = batchNativeHookData->add_events(); + firstNativeHookData->set_tv_sec(TV_SEC_01); + firstNativeHookData->set_tv_nsec(TV_NSEC_01); + firstNativeHookData->set_allocated_alloc_event(firstAllocEvent); + // add second NativeHookData + auto secondNativeHookData = batchNativeHookData->add_events(); + secondNativeHookData->set_tv_sec(TV_SEC_02); + secondNativeHookData->set_tv_nsec(TV_NSEC_02); + secondNativeHookData->set_allocated_alloc_event(secondAllocEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + // Calculate partial expectations + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + EXPECT_TRUE(MEM_SIZE_01 == nativeHook.AllMemSizes()[0]); + EXPECT_TRUE(nativeHook.CurrentSizeDurs()[0] == TIMESTAMP_02 - TIMESTAMP_01); + + // Construct the nativehookcache object using the element with subscript 0 in nativehook and compare it with the + // expected value + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_01, 0, 0, MEM_ADDR_01, MEM_SIZE_01, MEM_SIZE_01, + TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + // construct first Malloc event's first frame expect value. + // Note: the nativehookframe data is parsed in reverse order + auto firstExpectSymbol = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_02); + auto firstExpectFilePath = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_02); + auto secondExpectSymbol = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + auto secondExpectFilePath = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache firstMallocExpectFirstFrame(1, 0, 0, 0, firstExpectSymbol, firstExpectFilePath, OFFSET_02, + SYMBOL_OFFSET_02); + // Construct the NativeHookFrameCache object using the element with subscript 0 in NativeHookFrame and compare it + // with the expected value + NativeHookFrameCache firstMallocResultFirstFrame(nativeHookFrame, 0); + EXPECT_TRUE(firstMallocExpectFirstFrame == firstMallocResultFirstFrame); + + // construct first Malloc event's second frame expect value. + NativeHookFrameCache firstMallocExpectSecondFrame(1, 1, 0, 0, secondExpectSymbol, secondExpectFilePath, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache firstMallocResultSecondFrame(nativeHookFrame, 1); + EXPECT_TRUE(firstMallocExpectSecondFrame == firstMallocResultSecondFrame); + + // Construct the nativehookcache object using the element with subscript 1 in nativehook and compare it with the + // expected value + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + NativeHookCache secondExpectNativeHookCache(1, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_02, 0, 0, MEM_ADDR_02, MEM_SIZE_02, MEM_SIZE_01 + MEM_SIZE_02, + 0); + NativeHookCache secondResultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + // construct second Malloc event's first frame expect value. + // Note: the nativehookframe data is parsed in reverse order + NativeHookFrameCache secondMallocExpectFirstFrame(1, 0, 0, 0, firstExpectSymbol, firstExpectFilePath, OFFSET_02, + SYMBOL_OFFSET_02); + // Construct the NativeHookFrameCache object using the element with subscript 2 in NativeHookFrame and compare it + // Verify the compression algorithm here= + EXPECT_EQ(nativeHookFrame.CallChainIds()[1], 1); + EXPECT_EQ(nativeHookFrame.Depths()[1], 1); + EXPECT_EQ(nativeHookFrame.Ips()[1], 0); + EXPECT_EQ(nativeHookFrame.Sps()[1], 0); + EXPECT_EQ(nativeHookFrame.SymbolNames()[1], secondExpectSymbol); + EXPECT_EQ(nativeHookFrame.FilePaths()[1], secondExpectFilePath); + EXPECT_EQ(nativeHookFrame.Offsets()[1], OFFSET_01); + EXPECT_EQ(nativeHookFrame.SymbolOffsets()[1], SYMBOL_OFFSET_01); +} + +/** + * @tc.name: ParseBatchNativeHookWithOneFree + * @tc.desc: Parse a BatchNativeHookData with only one Free + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithOneFree, TestSize.Level1) +{ + TS_LOGI("test24-4"); + // construct FreeEvent + FreeEvent* freeEvent = new FreeEvent(); + freeEvent->set_pid(PID); + freeEvent->set_tid(TID_01); + freeEvent->set_addr(MEM_ADDR_01); + // construct FreeEvent's Frame + auto frame = freeEvent->add_frame_info(); + frame->set_ip(CALL_STACK_IP_01); + frame->set_sp(CALL_STACK_SP_01); + frame->set_symbol_name(SYMBOL_NAME_01); + frame->set_file_path(FILE_PATH_01); + frame->set_offset(OFFSET_01); + frame->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookData = batchNativeHookData->add_events(); + nativeHookData->set_tv_sec(TV_SEC_01); + nativeHookData->set_tv_nsec(TV_NSEC_01); + nativeHookData->set_allocated_free_event(freeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(0, size); + size = stream_.traceDataCache_->GetConstNativeHookFrameData().Size(); + EXPECT_EQ(0, size); + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithMultipleFree + * @tc.desc: Parse a NativeHook with multiple Free and Frame + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithMultipleFree, TestSize.Level1) +{ + TS_LOGI("test24-5"); + // constructs first FreeEvent with two Frame + FreeEvent* firstFreeEvent = new FreeEvent(); + firstFreeEvent->set_pid(PID); + firstFreeEvent->set_tid(TID_01); + firstFreeEvent->set_addr(MEM_ADDR_01); + // construct first FreeEvent's first Frame + auto firstFreeFirstFrame = firstFreeEvent->add_frame_info(); + firstFreeFirstFrame->set_ip(CALL_STACK_IP_01); + firstFreeFirstFrame->set_sp(CALL_STACK_SP_01); + firstFreeFirstFrame->set_symbol_name(SYMBOL_NAME_01); + firstFreeFirstFrame->set_file_path(FILE_PATH_01); + firstFreeFirstFrame->set_offset(OFFSET_01); + firstFreeFirstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + // construct first FreeEvent's second Frame + auto firstFreeSecondFrame = firstFreeEvent->add_frame_info(); + firstFreeSecondFrame->set_ip(CALL_STACK_IP_02); + firstFreeSecondFrame->set_sp(CALL_STACK_SP_02); + firstFreeSecondFrame->set_symbol_name(SYMBOL_NAME_02); + firstFreeSecondFrame->set_file_path(FILE_PATH_02); + firstFreeSecondFrame->set_offset(OFFSET_02); + firstFreeSecondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // constructs second FreeEvent with two Frame + FreeEvent* secondFreeEvent = new FreeEvent(); + secondFreeEvent->set_pid(PID); + secondFreeEvent->set_tid(TID_02); + secondFreeEvent->set_addr(MEM_ADDR_02); + // construct second FreeEvent's first Frame + auto secondFreeFirstFrame = secondFreeEvent->add_frame_info(); + secondFreeFirstFrame->set_ip(CALL_STACK_IP_01); + secondFreeFirstFrame->set_sp(CALL_STACK_SP_01); + secondFreeFirstFrame->set_symbol_name(SYMBOL_NAME_01); + secondFreeFirstFrame->set_file_path(FILE_PATH_01); + secondFreeFirstFrame->set_offset(OFFSET_01); + secondFreeFirstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + // construct second FreeEvent's second Frame + auto secondFreeSecondFrame = secondFreeEvent->add_frame_info(); + secondFreeSecondFrame->set_ip(CALL_STACK_IP_02); + secondFreeSecondFrame->set_sp(CALL_STACK_SP_02); + secondFreeSecondFrame->set_symbol_name(SYMBOL_NAME_02); + secondFreeSecondFrame->set_file_path(FILE_PATH_02); + secondFreeSecondFrame->set_offset(OFFSET_02); + secondFreeSecondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add first NativeHookData + auto firstNativeHookData = batchNativeHookData->add_events(); + firstNativeHookData->set_tv_sec(TV_SEC_01); + firstNativeHookData->set_tv_nsec(TV_NSEC_01); + firstNativeHookData->set_allocated_free_event(firstFreeEvent); + // add second NativeHookData + auto secondNativeHookData = batchNativeHookData->add_events(); + secondNativeHookData->set_tv_sec(TV_SEC_02); + secondNativeHookData->set_tv_nsec(TV_NSEC_02); + secondNativeHookData->set_allocated_free_event(secondFreeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + // Calculate partial expectations + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + EXPECT_TRUE(0 == nativeHook.Size()); + EXPECT_TRUE(0 == nativeHookFrame.Size()); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithOnePairsMallocAndFree + * @tc.desc: Parse a BatchNativeHookData with a pair of matching Malloc and Free Event + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithOnePairsMallocAndFree, TestSize.Level1) +{ + TS_LOGI("test24-6"); + // construct AllocEvent + AllocEvent* allocEvent = new AllocEvent(); + allocEvent->set_pid(PID); + allocEvent->set_tid(TID_01); + allocEvent->set_addr(MEM_ADDR_01); + allocEvent->set_size(MEM_SIZE_01); + // construct AllocEvent's Frame + auto allocframe = allocEvent->add_frame_info(); + allocframe->set_ip(CALL_STACK_IP_01); + allocframe->set_sp(CALL_STACK_SP_01); + allocframe->set_symbol_name(SYMBOL_NAME_01); + allocframe->set_file_path(FILE_PATH_01); + allocframe->set_offset(OFFSET_01); + allocframe->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct FreeEvent + FreeEvent* freeEvent = new FreeEvent(); + freeEvent->set_pid(PID); + freeEvent->set_tid(TID_02); + freeEvent->set_addr(MEM_ADDR_01); + // construct FreeEvent's Frame + auto freeframe = freeEvent->add_frame_info(); + freeframe->set_ip(CALL_STACK_IP_02); + freeframe->set_sp(CALL_STACK_SP_02); + freeframe->set_symbol_name(SYMBOL_NAME_02); + freeframe->set_file_path(FILE_PATH_02); + freeframe->set_offset(OFFSET_02); + freeframe->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookMallocData = batchNativeHookData->add_events(); + nativeHookMallocData->set_tv_sec(TV_SEC_01); + nativeHookMallocData->set_tv_nsec(TV_NSEC_01); + nativeHookMallocData->set_allocated_alloc_event(allocEvent); + auto nativeHookFreeData = batchNativeHookData->add_events(); + nativeHookFreeData->set_tv_sec(TV_SEC_02); + nativeHookFreeData->set_tv_nsec(TV_NSEC_02); + nativeHookFreeData->set_allocated_free_event(freeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse Malloc event results + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + // Verification parse Malloc Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache secondExpectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache secondResultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(secondExpectFrameCache == secondResultFrameCache); + + // Verification parse Free event results + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + NativeHookCache expectNativeHookCache(2, expect_ipid, expect_itid, FREEEVENT.c_str(), INVALID_UINT64, TIMESTAMP_02, + 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, 0); + NativeHookCache resultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(expectNativeHookCache == resultNativeHookCache); + + // Verification parse Free Event Frame results + expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_02); + expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_02); + NativeHookFrameCache expectFrameCache(2, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_02, + SYMBOL_OFFSET_02); + NativeHookFrameCache resultFrameCache(nativeHookFrame, 1); + EXPECT_TRUE(expectFrameCache == resultFrameCache); + + auto size = nativeHookFrame.Size(); + EXPECT_EQ(2, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithNotMatchMallocAndFree + * @tc.desc: Parse a BatchNativeHookData with Not Match Malloc and Free Event + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithNotMatchMallocAndFree, TestSize.Level1) +{ + TS_LOGI("test24-7"); + // construct AllocEvent + AllocEvent* allocEvent = new AllocEvent(); + allocEvent->set_pid(PID); + allocEvent->set_tid(TID_01); + allocEvent->set_addr(MEM_ADDR_01); + allocEvent->set_size(MEM_SIZE_01); + // construct AllocEvent's Frame + auto allocframe = allocEvent->add_frame_info(); + allocframe->set_ip(CALL_STACK_IP_01); + allocframe->set_sp(CALL_STACK_SP_01); + allocframe->set_symbol_name(SYMBOL_NAME_01); + allocframe->set_file_path(FILE_PATH_01); + allocframe->set_offset(OFFSET_01); + allocframe->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct FreeEvent + FreeEvent* freeEvent = new FreeEvent(); + freeEvent->set_pid(PID); + freeEvent->set_tid(TID_02); + freeEvent->set_addr(MEM_ADDR_02); + auto freeframe = freeEvent->add_frame_info(); + // construct FreeEvent's Frame + freeframe->set_ip(CALL_STACK_IP_02); + freeframe->set_sp(CALL_STACK_SP_02); + freeframe->set_symbol_name(SYMBOL_NAME_02); + freeframe->set_file_path(FILE_PATH_02); + freeframe->set_offset(OFFSET_02); + freeframe->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookMallocData = batchNativeHookData->add_events(); + nativeHookMallocData->set_tv_sec(TV_SEC_01); + nativeHookMallocData->set_tv_nsec(TV_NSEC_01); + nativeHookMallocData->set_allocated_alloc_event(allocEvent); + auto nativeHookFreeData = batchNativeHookData->add_events(); + nativeHookFreeData->set_tv_sec(TV_SEC_02); + nativeHookFreeData->set_tv_nsec(TV_NSEC_02); + nativeHookFreeData->set_allocated_free_event(freeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse Malloc event results + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_01, 0, 0, MEM_ADDR_01, MEM_SIZE_01, MEM_SIZE_01, 0); + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + // Verification parse Malloc Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache firstExpectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache firstResultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(firstExpectFrameCache == firstResultFrameCache); + + auto size = nativeHookFrame.Size(); + EXPECT_EQ(1, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseTwoMallocAndFreeEventMatched + * @tc.desc: Parse a BatchNativeHookData with two Malloc and two Free Event, that Malloc and Free was matched. + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseTwoMallocAndFreeEventMatched, TestSize.Level1) +{ + TS_LOGI("test24-8"); + // construct first AllocEvent + AllocEvent* firstAllocEvent = new AllocEvent(); + firstAllocEvent->set_pid(PID); + firstAllocEvent->set_tid(TID_01); + firstAllocEvent->set_addr(MEM_ADDR_01); + firstAllocEvent->set_size(MEM_SIZE_01); + + // construct second AllocEvent + AllocEvent* secondAllocEvent = new AllocEvent(); + secondAllocEvent->set_pid(PID); + secondAllocEvent->set_tid(TID_02); + secondAllocEvent->set_addr(MEM_ADDR_02); + secondAllocEvent->set_size(MEM_SIZE_02); + + // construct first FreeEvent + FreeEvent* firstFreeEvent = new FreeEvent(); + firstFreeEvent->set_pid(PID); + firstFreeEvent->set_tid(TID_01); + firstFreeEvent->set_addr(MEM_ADDR_01); + + // construct second FreeEvent + FreeEvent* secondFreeEvent = new FreeEvent(); + secondFreeEvent->set_pid(PID); + secondFreeEvent->set_tid(TID_02); + secondFreeEvent->set_addr(MEM_ADDR_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto firstMallocData = batchNativeHookData->add_events(); + firstMallocData->set_tv_sec(TV_SEC_01); + firstMallocData->set_tv_nsec(TV_NSEC_01); + firstMallocData->set_allocated_alloc_event(firstAllocEvent); + auto firstFreeData = batchNativeHookData->add_events(); + firstFreeData->set_tv_sec(TV_SEC_02); + firstFreeData->set_tv_nsec(TV_NSEC_02); + firstFreeData->set_allocated_free_event(firstFreeEvent); + auto secondMallocData = batchNativeHookData->add_events(); + secondMallocData->set_tv_sec(TV_SEC_03); + secondMallocData->set_tv_nsec(TV_NSEC_03); + secondMallocData->set_allocated_alloc_event(secondAllocEvent); + auto secondFreeData = batchNativeHookData->add_events(); + secondFreeData->set_tv_sec(TV_SEC_04); + secondFreeData->set_tv_nsec(TV_NSEC_04); + secondFreeData->set_allocated_free_event(secondFreeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse first Malloc event results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + NativeHookCache firstExpectMallocCache(INVALID_UINT32, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultMallocCache(nativeHook, 0); + EXPECT_TRUE(firstExpectMallocCache == firstResultMallocCache); + + // Verification parse first Free event results + NativeHookCache firstExpectFreeCache(INVALID_UINT32, expect_ipid, expect_itid, FREEEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_02, 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, TIMESTAMP_03 - TIMESTAMP_02); + NativeHookCache firstResultFreeCache(nativeHook, 1); + EXPECT_TRUE(firstExpectFreeCache == firstResultFreeCache); + + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + NativeHookCache secondExpectMallocCache(INVALID_UINT32, expect_ipid, expect_itid, ALLOCEVENT.c_str(), + INVALID_UINT64, TIMESTAMP_03, TIMESTAMP_04, TIMESTAMP_04 - TIMESTAMP_03, + MEM_ADDR_02, MEM_SIZE_02, MEM_SIZE_02, TIMESTAMP_04 - TIMESTAMP_03); + NativeHookCache secondResultMallocCache(nativeHook, 2); + EXPECT_TRUE(secondExpectMallocCache == secondResultMallocCache); + + // Verification parse first Free event results + NativeHookCache secondExpectFreeCache(INVALID_UINT32, expect_ipid, expect_itid, FREEEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_04, 0, 0, MEM_ADDR_02, MEM_SIZE_02, 0, 0); + NativeHookCache secondResultFreeCache(nativeHook, 3); + EXPECT_TRUE(secondExpectFreeCache == secondResultFreeCache); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseTwoMallocAndFreeEventPartialMatched + * @tc.desc: Parse a BatchNativeHookData with two Malloc and two Free Event, that Malloc and Free was partial matched. + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseTwoMallocAndFreeEventPartialMatched, TestSize.Level1) +{ + TS_LOGI("test24-9"); + // construct first AllocEvent + AllocEvent* firstAllocEvent = new AllocEvent(); + firstAllocEvent->set_pid(PID); + firstAllocEvent->set_tid(TID_01); + firstAllocEvent->set_addr(MEM_ADDR_01); + firstAllocEvent->set_size(MEM_SIZE_01); + + // construct second AllocEvent + AllocEvent* secondAllocEvent = new AllocEvent(); + secondAllocEvent->set_pid(PID); + secondAllocEvent->set_tid(TID_02); + secondAllocEvent->set_addr(MEM_ADDR_02); + secondAllocEvent->set_size(MEM_SIZE_02); + + // construct first FreeEvent + FreeEvent* firstFreeEvent = new FreeEvent(); + firstFreeEvent->set_pid(PID); + firstFreeEvent->set_tid(TID_01); + firstFreeEvent->set_addr(MEM_ADDR_01); + + // construct second FreeEvent + FreeEvent* secondFreeEvent = new FreeEvent(); + secondFreeEvent->set_pid(PID); + secondFreeEvent->set_tid(TID_02); + secondFreeEvent->set_addr(MEM_ADDR_03); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto firstMallocData = batchNativeHookData->add_events(); + firstMallocData->set_tv_sec(TV_SEC_01); + firstMallocData->set_tv_nsec(TV_NSEC_01); + firstMallocData->set_allocated_alloc_event(firstAllocEvent); + auto firstFreeData = batchNativeHookData->add_events(); + firstFreeData->set_tv_sec(TV_SEC_02); + firstFreeData->set_tv_nsec(TV_NSEC_02); + firstFreeData->set_allocated_free_event(firstFreeEvent); + auto secondMallocData = batchNativeHookData->add_events(); + secondMallocData->set_tv_sec(TV_SEC_03); + secondMallocData->set_tv_nsec(TV_NSEC_03); + secondMallocData->set_allocated_alloc_event(secondAllocEvent); + auto secondFreeData = batchNativeHookData->add_events(); + secondFreeData->set_tv_sec(TV_SEC_04); + secondFreeData->set_tv_nsec(TV_NSEC_04); + secondFreeData->set_allocated_free_event(secondFreeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse first Malloc event results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + NativeHookCache firstExpectMallocCache(INVALID_UINT32, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultMallocCache(nativeHook, 0); + EXPECT_TRUE(firstExpectMallocCache == firstResultMallocCache); + + // Verification parse first Free event results + NativeHookCache firstExpectFreeCache(INVALID_UINT32, expect_ipid, expect_itid, FREEEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_02, 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, TIMESTAMP_03 - TIMESTAMP_02); + NativeHookCache firstResultFreeCache(nativeHook, 1); + EXPECT_TRUE(firstExpectFreeCache == firstResultFreeCache); + + // Verification parse second Malloc event results + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + NativeHookCache secondExpectMallocCache(INVALID_UINT32, expect_ipid, expect_itid, ALLOCEVENT.c_str(), + INVALID_UINT64, TIMESTAMP_03, 0, 0, MEM_ADDR_02, MEM_SIZE_02, MEM_SIZE_02, + 0); + NativeHookCache secondResultMallocCache(nativeHook, 2); + EXPECT_TRUE(secondExpectMallocCache == secondResultMallocCache); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithOneMmap + * @tc.desc: Parse a BatchNativeHookData with only one MMAP + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithOneMmap, TestSize.Level1) +{ + TS_LOGI("test24-10"); + // construct MmapEvent + MmapEvent* mmapEvent = new MmapEvent(); + mmapEvent->set_pid(PID); + mmapEvent->set_tid(TID_01); + mmapEvent->set_addr(MEM_ADDR_01); + mmapEvent->set_size(MEM_SIZE_01); + mmapEvent->set_type(MMAP_SUB_TYPE_01); + // construct MmapEvent's Frame + auto frame = mmapEvent->add_frame_info(); + frame->set_ip(CALL_STACK_IP_01); + frame->set_sp(CALL_STACK_SP_01); + frame->set_symbol_name(SYMBOL_NAME_01); + frame->set_file_path(FILE_PATH_01); + frame->set_offset(OFFSET_01); + frame->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookData = batchNativeHookData->add_events(); + nativeHookData->set_tv_sec(TV_SEC_01); + nativeHookData->set_tv_nsec(TV_NSEC_01); + nativeHookData->set_allocated_mmap_event(mmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + NativeHookCache expectNativeHookCache(1, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, TIMESTAMP_01, 0, + 0, MEM_ADDR_01, MEM_SIZE_01, MEM_SIZE_01, 0); + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + NativeHookCache resultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(expectNativeHookCache == resultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(1, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache expectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache resultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(expectFrameCache == resultFrameCache); + + size = nativeHookFrame.Size(); + EXPECT_EQ(1, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithOneMunmap + * @tc.desc: Parse a BatchNativeHookData with only one MMAP + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithOneMunmap, TestSize.Level1) +{ + TS_LOGI("test24-11"); + // construct MunmapEvent + MunmapEvent* munmapEvent = new MunmapEvent(); + munmapEvent->set_pid(PID); + munmapEvent->set_tid(TID_01); + munmapEvent->set_addr(MEM_ADDR_01); + munmapEvent->set_size(MEM_SIZE_01); + // construct MunmapEvent's Frame + auto frame = munmapEvent->add_frame_info(); + frame->set_ip(CALL_STACK_IP_01); + frame->set_sp(CALL_STACK_SP_01); + frame->set_symbol_name(SYMBOL_NAME_01); + frame->set_file_path(FILE_PATH_01); + frame->set_offset(OFFSET_01); + frame->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookData = batchNativeHookData->add_events(); + nativeHookData->set_tv_sec(TV_SEC_01); + nativeHookData->set_tv_nsec(TV_NSEC_01); + nativeHookData->set_allocated_munmap_event(munmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(0, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + + size = nativeHookFrame.Size(); + EXPECT_EQ(0, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithMultipleMmap + * @tc.desc: Parse a BatchNativeHookData with multiple MMAP + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithMultipleMmap, TestSize.Level1) +{ + TS_LOGI("test24-12"); + // construct first MmapEvent + MmapEvent* firstMmapEvent = new MmapEvent(); + firstMmapEvent->set_pid(PID); + firstMmapEvent->set_tid(TID_01); + firstMmapEvent->set_addr(MEM_ADDR_01); + firstMmapEvent->set_size(MEM_SIZE_01); + firstMmapEvent->set_type(MMAP_SUB_TYPE_01); + // construct first MmapEvent's Frame + auto firstFrame = firstMmapEvent->add_frame_info(); + firstFrame->set_ip(CALL_STACK_IP_01); + firstFrame->set_sp(CALL_STACK_SP_01); + firstFrame->set_symbol_name(SYMBOL_NAME_01); + firstFrame->set_file_path(FILE_PATH_01); + firstFrame->set_offset(OFFSET_01); + firstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct second MmapEvent + MmapEvent* secondMmapEvent = new MmapEvent(); + secondMmapEvent->set_pid(PID); + secondMmapEvent->set_tid(TID_02); + secondMmapEvent->set_addr(MEM_ADDR_02); + secondMmapEvent->set_size(MEM_SIZE_02); + secondMmapEvent->set_type(MMAP_SUB_TYPE_02); + // construct second MmapEvent's Frame + auto secondFrame = secondMmapEvent->add_frame_info(); + secondFrame->set_ip(CALL_STACK_IP_02); + secondFrame->set_sp(CALL_STACK_SP_02); + secondFrame->set_symbol_name(SYMBOL_NAME_02); + secondFrame->set_file_path(FILE_PATH_02); + secondFrame->set_offset(OFFSET_02); + secondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto firstNativeHookData = batchNativeHookData->add_events(); + firstNativeHookData->set_tv_sec(TV_SEC_01); + firstNativeHookData->set_tv_nsec(TV_NSEC_01); + firstNativeHookData->set_allocated_mmap_event(firstMmapEvent); + auto secondNativeHookData = batchNativeHookData->add_events(); + secondNativeHookData->set_tv_sec(TV_SEC_02); + secondNativeHookData->set_tv_nsec(TV_NSEC_02); + secondNativeHookData->set_allocated_mmap_event(secondMmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_01, 0, 0, MEM_ADDR_01, MEM_SIZE_01, MEM_SIZE_01, + TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_02); + NativeHookCache secondExpectNativeHookCache(2, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_02, 0, 0, MEM_ADDR_02, MEM_SIZE_02, MEM_SIZE_01 + MEM_SIZE_02, + 0); + NativeHookCache secondResultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(2, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache firstExpectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache firstResultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(firstExpectFrameCache == firstResultFrameCache); + + expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_02); + expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_02); + NativeHookFrameCache expectFrameCache(2, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_02, + SYMBOL_OFFSET_02); + NativeHookFrameCache resultFrameCache(nativeHookFrame, 1); + EXPECT_TRUE(expectFrameCache == resultFrameCache); + + size = nativeHookFrame.Size(); + EXPECT_EQ(2, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithMultipleMunmap + * @tc.desc: Parse a BatchNativeHookData with multiple munmap + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithMultipleMunmap, TestSize.Level1) +{ + TS_LOGI("test24-13"); + // construct first MunmapEvent + MunmapEvent* firstMunmapEvent = new MunmapEvent(); + firstMunmapEvent->set_pid(PID); + firstMunmapEvent->set_tid(TID_01); + firstMunmapEvent->set_addr(MEM_ADDR_01); + firstMunmapEvent->set_size(MEM_SIZE_01); + // construct MunmapEvent's Frame + auto firstFrame = firstMunmapEvent->add_frame_info(); + firstFrame->set_ip(CALL_STACK_IP_01); + firstFrame->set_sp(CALL_STACK_SP_01); + firstFrame->set_symbol_name(SYMBOL_NAME_01); + firstFrame->set_file_path(FILE_PATH_01); + firstFrame->set_offset(OFFSET_01); + firstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct second MunmapEvent + MunmapEvent* secondMunmapEvent = new MunmapEvent(); + secondMunmapEvent->set_pid(PID); + secondMunmapEvent->set_tid(TID_02); + secondMunmapEvent->set_addr(MEM_ADDR_02); + secondMunmapEvent->set_size(MEM_SIZE_02); + // construct MunmapEvent's Frame + auto secondFrame = secondMunmapEvent->add_frame_info(); + secondFrame->set_ip(CALL_STACK_IP_02); + secondFrame->set_sp(CALL_STACK_SP_02); + secondFrame->set_symbol_name(SYMBOL_NAME_02); + secondFrame->set_file_path(FILE_PATH_02); + secondFrame->set_offset(OFFSET_02); + secondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto firstNativeHookData = batchNativeHookData->add_events(); + firstNativeHookData->set_tv_sec(TV_SEC_01); + firstNativeHookData->set_tv_nsec(TV_NSEC_01); + firstNativeHookData->set_allocated_munmap_event(firstMunmapEvent); + auto secondNativeHookData = batchNativeHookData->add_events(); + secondNativeHookData->set_tv_sec(TV_SEC_02); + secondNativeHookData->set_tv_nsec(TV_NSEC_02); + secondNativeHookData->set_allocated_munmap_event(secondMunmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(0, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + + size = nativeHookFrame.Size(); + EXPECT_EQ(0, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseOnePairsMmapAndMunmapEvent + * @tc.desc: Parse a BatchNativeHookData with one pairs Mmap and MunmapEvent + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseOnePairsMmapAndMunmapEvent, TestSize.Level1) +{ + TS_LOGI("test24-14"); + // construct MmapEvent + MmapEvent* mmapEvent = new MmapEvent(); + mmapEvent->set_pid(PID); + mmapEvent->set_tid(TID_01); + mmapEvent->set_addr(MEM_ADDR_01); + mmapEvent->set_size(MEM_SIZE_01); + mmapEvent->set_type(MMAP_SUB_TYPE_01); + // construct MmapEvent's Frame + auto firstFrame = mmapEvent->add_frame_info(); + firstFrame->set_ip(CALL_STACK_IP_01); + firstFrame->set_sp(CALL_STACK_SP_01); + firstFrame->set_symbol_name(SYMBOL_NAME_01); + firstFrame->set_file_path(FILE_PATH_01); + firstFrame->set_offset(OFFSET_01); + firstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + auto secondFrame = mmapEvent->add_frame_info(); + secondFrame->set_ip(CALL_STACK_IP_02); + secondFrame->set_sp(CALL_STACK_SP_02); + secondFrame->set_symbol_name(SYMBOL_NAME_02); + secondFrame->set_file_path(FILE_PATH_02); + secondFrame->set_offset(OFFSET_02); + secondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct first MunmapEvent + MunmapEvent* munmapEvent = new MunmapEvent(); + munmapEvent->set_pid(PID); + munmapEvent->set_tid(TID_01); + munmapEvent->set_addr(MEM_ADDR_01); + munmapEvent->set_size(MEM_SIZE_01); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookMmapData = batchNativeHookData->add_events(); + nativeHookMmapData->set_tv_sec(TV_SEC_01); + nativeHookMmapData->set_tv_nsec(TV_NSEC_01); + nativeHookMmapData->set_allocated_mmap_event(mmapEvent); + auto nativeHookMunmapData = batchNativeHookData->add_events(); + nativeHookMunmapData->set_tv_sec(TV_SEC_02); + nativeHookMunmapData->set_tv_nsec(TV_NSEC_02); + nativeHookMunmapData->set_allocated_munmap_event(munmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + NativeHookCache secondExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MUNMAPEVENT.c_str(), + mmapSubType, TIMESTAMP_02, 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, 0); + NativeHookCache secondResultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(2, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_02); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_02); + NativeHookFrameCache firstExpectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_02, + SYMBOL_OFFSET_02); + NativeHookFrameCache firstResultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(firstExpectFrameCache == firstResultFrameCache); + + expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache secondExpectFrameCache(1, 1, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache secondResultFrameCache(nativeHookFrame, 1); + EXPECT_TRUE(secondExpectFrameCache == secondResultFrameCache); + + size = nativeHookFrame.Size(); + EXPECT_EQ(2, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseNotMatchMmapAndMunmapEvent + * @tc.desc: Parse a BatchNativeHookData with not match Mmap and MunmapEvent + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseNotMatchMmapAndMunmapEvent, TestSize.Level1) +{ + TS_LOGI("test24-15"); + // construct MmapEvent + MmapEvent* mmapEvent = new MmapEvent(); + mmapEvent->set_pid(PID); + mmapEvent->set_tid(TID_01); + mmapEvent->set_addr(MEM_ADDR_01); + mmapEvent->set_size(MEM_SIZE_01); + mmapEvent->set_type(MMAP_SUB_TYPE_01); + // construct MmapEvent's Frame + auto firstFrame = mmapEvent->add_frame_info(); + firstFrame->set_ip(CALL_STACK_IP_01); + firstFrame->set_sp(CALL_STACK_SP_01); + firstFrame->set_symbol_name(SYMBOL_NAME_01); + firstFrame->set_file_path(FILE_PATH_01); + firstFrame->set_offset(OFFSET_01); + firstFrame->set_symbol_offset(SYMBOL_OFFSET_01); + auto secondFrame = mmapEvent->add_frame_info(); + secondFrame->set_ip(CALL_STACK_IP_02); + secondFrame->set_sp(CALL_STACK_SP_02); + secondFrame->set_symbol_name(SYMBOL_NAME_02); + secondFrame->set_file_path(FILE_PATH_02); + secondFrame->set_offset(OFFSET_02); + secondFrame->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct MunmapEvent + MunmapEvent* munmapEvent = new MunmapEvent(); + munmapEvent->set_pid(PID); + munmapEvent->set_tid(TID_01); + munmapEvent->set_addr(MEM_ADDR_02); + munmapEvent->set_size(MEM_SIZE_01); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookMmapData = batchNativeHookData->add_events(); + nativeHookMmapData->set_tv_sec(TV_SEC_01); + nativeHookMmapData->set_tv_nsec(TV_NSEC_01); + nativeHookMmapData->set_allocated_mmap_event(mmapEvent); + auto nativeHookMunmapData = batchNativeHookData->add_events(); + nativeHookMunmapData->set_tv_sec(TV_SEC_02); + nativeHookMunmapData->set_tv_nsec(TV_NSEC_02); + nativeHookMunmapData->set_allocated_munmap_event(munmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_01, 0, 0, MEM_ADDR_01, MEM_SIZE_01, MEM_SIZE_01, 0); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(1, size); + + // Verification parse NativeHook Frame results + const NativeHookFrame& nativeHookFrame = stream_.traceDataCache_->GetConstNativeHookFrameData(); + auto expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_02); + auto expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_02); + NativeHookFrameCache firstExpectFrameCache(1, 0, 0, 0, expectSymbolData, expectFilePathData, OFFSET_02, + SYMBOL_OFFSET_02); + NativeHookFrameCache firstResultFrameCache(nativeHookFrame, 0); + EXPECT_TRUE(firstExpectFrameCache == firstResultFrameCache); + + expectSymbolData = stream_.traceDataCache_->dataDict_.GetStringIndex(SYMBOL_NAME_01); + expectFilePathData = stream_.traceDataCache_->dataDict_.GetStringIndex(FILE_PATH_01); + NativeHookFrameCache secondExpectFrameCache(1, 1, 0, 0, expectSymbolData, expectFilePathData, OFFSET_01, + SYMBOL_OFFSET_01); + NativeHookFrameCache secondResultFrameCache(nativeHookFrame, 1); + EXPECT_TRUE(secondExpectFrameCache == secondResultFrameCache); + + size = nativeHookFrame.Size(); + EXPECT_EQ(2, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} + +/** + * @tc.name: ParseTwoPairsMatchedMmapAndMunmapEvent + * @tc.desc: Parse a BatchNativeHookData with two pairs matched Mmap and MunmapEvent + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseTwoPairsMatchedMmapAndMunmapEvent, TestSize.Level1) +{ + TS_LOGI("test24-16"); + // construct first MmapEvent + MmapEvent* firstMmapEvent = new MmapEvent(); + firstMmapEvent->set_pid(PID); + firstMmapEvent->set_tid(TID_01); + firstMmapEvent->set_addr(MEM_ADDR_01); + firstMmapEvent->set_size(MEM_SIZE_01); + firstMmapEvent->set_type(MMAP_SUB_TYPE_01); + // construct second MmapEvent + MmapEvent* secondMmapEvent = new MmapEvent(); + secondMmapEvent->set_pid(PID); + secondMmapEvent->set_tid(TID_02); + secondMmapEvent->set_addr(MEM_ADDR_02); + secondMmapEvent->set_size(MEM_SIZE_02); + secondMmapEvent->set_type(MMAP_SUB_TYPE_02); + + // construct first MunmapEvent + MunmapEvent* firstMunmapEvent = new MunmapEvent(); + firstMunmapEvent->set_pid(PID); + firstMunmapEvent->set_tid(TID_01); + firstMunmapEvent->set_addr(MEM_ADDR_01); + firstMunmapEvent->set_size(MEM_SIZE_01); + // construct second MunmapEvent + MunmapEvent* secondMunmapEvent = new MunmapEvent(); + secondMunmapEvent->set_pid(PID); + secondMunmapEvent->set_tid(TID_02); + secondMunmapEvent->set_addr(MEM_ADDR_02); + secondMunmapEvent->set_size(MEM_SIZE_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto firstNativeHookMmapData = batchNativeHookData->add_events(); + firstNativeHookMmapData->set_tv_sec(TV_SEC_01); + firstNativeHookMmapData->set_tv_nsec(TV_NSEC_01); + firstNativeHookMmapData->set_allocated_mmap_event(firstMmapEvent); + auto firstNativeHookMunmapData = batchNativeHookData->add_events(); + firstNativeHookMunmapData->set_tv_sec(TV_SEC_02); + firstNativeHookMunmapData->set_tv_nsec(TV_NSEC_02); + firstNativeHookMunmapData->set_allocated_munmap_event(firstMunmapEvent); + auto secondNativeHookMmapData = batchNativeHookData->add_events(); + secondNativeHookMmapData->set_tv_sec(TV_SEC_03); + secondNativeHookMmapData->set_tv_nsec(TV_NSEC_03); + secondNativeHookMmapData->set_allocated_mmap_event(secondMmapEvent); + auto secondNativeHookMunmapData = batchNativeHookData->add_events(); + secondNativeHookMunmapData->set_tv_sec(TV_SEC_04); + secondNativeHookMunmapData->set_tv_nsec(TV_NSEC_04); + secondNativeHookMunmapData->set_allocated_munmap_event(secondMunmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + NativeHookCache firstExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + NativeHookCache secondExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MUNMAPEVENT.c_str(), + mmapSubType, TIMESTAMP_02, 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, + TIMESTAMP_03 - TIMESTAMP_02); + NativeHookCache secondResultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_02); + NativeHookCache thirdExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_03, TIMESTAMP_04, TIMESTAMP_04 - TIMESTAMP_03, MEM_ADDR_02, + MEM_SIZE_02, MEM_SIZE_02, TIMESTAMP_04 - TIMESTAMP_03); + NativeHookCache thirdResultNativeHookCache(nativeHook, 2); + EXPECT_TRUE(thirdExpectNativeHookCache == thirdResultNativeHookCache); + + NativeHookCache fourthExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MUNMAPEVENT.c_str(), + mmapSubType, TIMESTAMP_04, 0, 0, MEM_ADDR_02, MEM_SIZE_02, 0, 0); + NativeHookCache fourthResultNativeHookCache(nativeHook, 3); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(4, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParsePartialMatchedMmapAndMunmapEvent + * @tc.desc: Parse a BatchNativeHookData with partial matched Mmap and MunmapEvent + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParsePartialMatchedMmapAndMunmapEvent, TestSize.Level1) +{ + TS_LOGI("test24-17"); + // construct AllocEvent + MmapEvent* firstMmapEvent = new MmapEvent(); + firstMmapEvent->set_pid(PID); + firstMmapEvent->set_tid(TID_01); + firstMmapEvent->set_addr(MEM_ADDR_01); + firstMmapEvent->set_size(MEM_SIZE_01); + firstMmapEvent->set_type(MMAP_SUB_TYPE_01); + MmapEvent* secondMmapEvent = new MmapEvent(); + secondMmapEvent->set_pid(PID); + secondMmapEvent->set_tid(TID_02); + secondMmapEvent->set_addr(MEM_ADDR_02); + secondMmapEvent->set_size(MEM_SIZE_02); + secondMmapEvent->set_type(MMAP_SUB_TYPE_02); + + // construct first MunmapEvent + MunmapEvent* firstMunmapEvent = new MunmapEvent(); + firstMunmapEvent->set_pid(PID); + firstMunmapEvent->set_tid(TID_01); + firstMunmapEvent->set_addr(MEM_ADDR_01); + firstMunmapEvent->set_size(MEM_SIZE_01); + MunmapEvent* secondMunmapEvent = new MunmapEvent(); + secondMunmapEvent->set_pid(PID); + secondMunmapEvent->set_tid(TID_02); + secondMunmapEvent->set_addr(MEM_ADDR_03); + secondMunmapEvent->set_size(MEM_SIZE_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto firstNativeHookMmapData = batchNativeHookData->add_events(); + firstNativeHookMmapData->set_tv_sec(TV_SEC_01); + firstNativeHookMmapData->set_tv_nsec(TV_NSEC_01); + firstNativeHookMmapData->set_allocated_mmap_event(firstMmapEvent); + auto firstNativeHookMunmapData = batchNativeHookData->add_events(); + firstNativeHookMunmapData->set_tv_sec(TV_SEC_02); + firstNativeHookMunmapData->set_tv_nsec(TV_NSEC_02); + firstNativeHookMunmapData->set_allocated_munmap_event(firstMunmapEvent); + auto secondNativeHookMmapData = batchNativeHookData->add_events(); + secondNativeHookMmapData->set_tv_sec(TV_SEC_03); + secondNativeHookMmapData->set_tv_nsec(TV_NSEC_03); + secondNativeHookMmapData->set_allocated_mmap_event(secondMmapEvent); + auto secondNativeHookMunmapData = batchNativeHookData->add_events(); + secondNativeHookMunmapData->set_tv_sec(TV_SEC_04); + secondNativeHookMunmapData->set_tv_nsec(TV_NSEC_04); + secondNativeHookMunmapData->set_allocated_munmap_event(secondMunmapEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + NativeHookCache firstExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + NativeHookCache secondExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MUNMAPEVENT.c_str(), + mmapSubType, TIMESTAMP_02, 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, + TIMESTAMP_03 - TIMESTAMP_02); + NativeHookCache secondResultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_02); + NativeHookCache thirdExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_03, 0, 0, MEM_ADDR_02, MEM_SIZE_02, MEM_SIZE_02, 0); + NativeHookCache thirdResultNativeHookCache(nativeHook, 2); + EXPECT_TRUE(thirdExpectNativeHookCache == thirdResultNativeHookCache); + + NativeHookCache fourthExpectNativeHookCache(INVALID_UINT32, expect_ipid, expect_itid, MUNMAPEVENT.c_str(), + mmapSubType, TIMESTAMP_04, 0, 0, MEM_ADDR_03, MEM_SIZE_02, MEM_SIZE_02, + 0); + NativeHookCache fourthResultNativeHookCache(nativeHook, 3); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(3, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(2 == eventCount); +} + +/** + * @tc.name: ParseBatchNativeHookWithAllTypesEvents + * @tc.desc: Parse a BatchNativeHookData with one pairs Mmap and MunmapEvent and one pairs Malloc and Free + * @tc.type: FUNC + */ +HWTEST_F(NativeHookParserTest, ParseBatchNativeHookWithAllTypesEvents, TestSize.Level1) +{ + TS_LOGI("test24-18"); + // construct MmapEvent + MmapEvent* mmapEvent = new MmapEvent(); + mmapEvent->set_pid(PID); + mmapEvent->set_tid(TID_01); + mmapEvent->set_addr(MEM_ADDR_01); + mmapEvent->set_size(MEM_SIZE_01); + mmapEvent->set_type(MMAP_SUB_TYPE_01); + // construct MmapEvent's Frame + auto mmapframe = mmapEvent->add_frame_info(); + mmapframe->set_ip(CALL_STACK_IP_01); + mmapframe->set_sp(CALL_STACK_SP_01); + mmapframe->set_symbol_name(SYMBOL_NAME_01); + mmapframe->set_file_path(FILE_PATH_01); + mmapframe->set_offset(OFFSET_01); + mmapframe->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct MunmapEvent + MunmapEvent* munmapEvent = new MunmapEvent(); + munmapEvent->set_pid(PID); + munmapEvent->set_tid(TID_01); + munmapEvent->set_addr(MEM_ADDR_01); + munmapEvent->set_size(MEM_SIZE_01); + // construct MunmapEvent's Frame + auto munmapframe = munmapEvent->add_frame_info(); + munmapframe->set_ip(CALL_STACK_IP_01); + munmapframe->set_sp(CALL_STACK_SP_01); + munmapframe->set_symbol_name(SYMBOL_NAME_01); + munmapframe->set_file_path(FILE_PATH_01); + munmapframe->set_offset(OFFSET_01); + munmapframe->set_symbol_offset(SYMBOL_OFFSET_01); + + // construct AllocEvent + AllocEvent* allocEvent = new AllocEvent(); + allocEvent->set_pid(PID); + allocEvent->set_tid(TID_02); + allocEvent->set_addr(MEM_ADDR_02); + allocEvent->set_size(MEM_SIZE_02); + // construct AllocEvent's Frame + auto allocframe = allocEvent->add_frame_info(); + allocframe->set_ip(CALL_STACK_IP_02); + allocframe->set_sp(CALL_STACK_SP_02); + allocframe->set_symbol_name(SYMBOL_NAME_02); + allocframe->set_file_path(FILE_PATH_02); + allocframe->set_offset(OFFSET_02); + allocframe->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct FreeEvent + FreeEvent* freeEvent = new FreeEvent(); + freeEvent->set_pid(PID); + freeEvent->set_tid(TID_02); + freeEvent->set_addr(MEM_ADDR_02); + // construct FreeEvent's Frame + auto freeframe = freeEvent->add_frame_info(); + freeframe->set_ip(CALL_STACK_IP_02); + freeframe->set_sp(CALL_STACK_SP_02); + freeframe->set_symbol_name(SYMBOL_NAME_02); + freeframe->set_file_path(FILE_PATH_02); + freeframe->set_offset(OFFSET_02); + freeframe->set_symbol_offset(SYMBOL_OFFSET_02); + + // construct BatchNativeHookData + BatchNativeHookData* batchNativeHookData = new BatchNativeHookData(); + + // add NativeHookData + auto nativeHookMmapData = batchNativeHookData->add_events(); + nativeHookMmapData->set_tv_sec(TV_SEC_01); + nativeHookMmapData->set_tv_nsec(TV_NSEC_01); + nativeHookMmapData->set_allocated_mmap_event(mmapEvent); + auto nativeHookMunmapData = batchNativeHookData->add_events(); + nativeHookMunmapData->set_tv_sec(TV_SEC_02); + nativeHookMunmapData->set_tv_nsec(TV_NSEC_02); + nativeHookMunmapData->set_allocated_munmap_event(munmapEvent); + auto nativeHookAllocData = batchNativeHookData->add_events(); + nativeHookAllocData->set_tv_sec(TV_SEC_03); + nativeHookAllocData->set_tv_nsec(TV_NSEC_03); + nativeHookAllocData->set_allocated_alloc_event(allocEvent); + auto nativeHookFreeData = batchNativeHookData->add_events(); + nativeHookFreeData->set_tv_sec(TV_SEC_04); + nativeHookFreeData->set_tv_nsec(TV_NSEC_04); + nativeHookFreeData->set_allocated_free_event(freeEvent); + + // start parse + HtraceNativeHookParser htraceNativeHookParser(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + htraceNativeHookParser.Parse(*batchNativeHookData); + htraceNativeHookParser.FinishParseNativeHookData(); + + // Verification parse NativeHook results + const NativeHook& nativeHook = stream_.traceDataCache_->GetConstNativeHookData(); + auto expect_ipid = stream_.streamFilters_->processFilter_->GetInternalPid(PID); + auto expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_01); + auto mmapSubType = stream_.traceDataCache_->dataDict_.GetStringIndex(MMAP_SUB_TYPE_01); + NativeHookCache firstExpectNativeHookCache(1, expect_ipid, expect_itid, MMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_01, TIMESTAMP_02, TIMESTAMP_02 - TIMESTAMP_01, MEM_ADDR_01, + MEM_SIZE_01, MEM_SIZE_01, TIMESTAMP_02 - TIMESTAMP_01); + NativeHookCache firstResultNativeHookCache(nativeHook, 0); + EXPECT_TRUE(firstExpectNativeHookCache == firstResultNativeHookCache); + + NativeHookCache secondExpectNativeHookCache(1, expect_ipid, expect_itid, MUNMAPEVENT.c_str(), mmapSubType, + TIMESTAMP_02, 0, 0, MEM_ADDR_01, MEM_SIZE_01, 0, 0); + NativeHookCache secondResultNativeHookCache(nativeHook, 1); + EXPECT_TRUE(secondExpectNativeHookCache == secondResultNativeHookCache); + + expect_itid = stream_.streamFilters_->processFilter_->GetInternalTid(TID_02); + NativeHookCache thirdExpectNativeHookCache(2, expect_ipid, expect_itid, ALLOCEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_03, TIMESTAMP_04, TIMESTAMP_04 - TIMESTAMP_03, MEM_ADDR_02, + MEM_SIZE_02, MEM_SIZE_02, TIMESTAMP_04 - TIMESTAMP_03); + NativeHookCache thirdResultNativeHookCache(nativeHook, 2); + EXPECT_TRUE(thirdExpectNativeHookCache == thirdResultNativeHookCache); + + NativeHookCache fourthExpectNativeHookCache(2, expect_ipid, expect_itid, FREEEVENT.c_str(), INVALID_UINT64, + TIMESTAMP_04, 0, 0, MEM_ADDR_02, MEM_SIZE_02, 0, 0); + NativeHookCache fourthResultNativeHookCache(nativeHook, 3); + EXPECT_TRUE(fourthExpectNativeHookCache == fourthResultNativeHookCache); + + auto size = stream_.traceDataCache_->GetConstNativeHookData().Size(); + EXPECT_EQ(4, size); + + auto eventCount = + stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MUNMAP, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_MALLOC, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_NATIVE_HOOK_FREE, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test/unittest/paged_memory_parser_test.cpp b/trace_streamer/test/unittest/paged_memory_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..611a02872ba3c5d09763841fbc5f3a4883e0a334 --- /dev/null +++ b/trace_streamer/test/unittest/paged_memory_parser_test.cpp @@ -0,0 +1,289 @@ + +/* + * 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 +#include +#include "paged_memory_data_parser.h" +#include "cpu_filter.h" +#include "ebpf_data_parser.h" +#include "ebpf_stdtype.h" +#include "process_filter.h" +#include "trace_streamer_selector.h" +#include "ts_common.h" +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::EbpfStdtype; +namespace SysTuning ::TraceStreamer { +const std::string COMMAND_LINE = "hiebpf --events ptrace --duration 50"; +class EbpfPagedMemoryParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; +}; +const uint64_t START_TIME = 1725645867369; +const uint64_t END_TIME = 1725645967369; +const uint64_t PAGEED_MEM_ADDR = 46549876; +const uint64_t IPS_01 = 548606407208; +const uint64_t IPS_02 = 548607407208; +const uint64_t EBPF_COMMAND_MAX_SIZE = 1000; +/** + * @tc.name: EbpfPagedMemoryParserCorrectWithoutCallback + * @tc.desc: Test parse PagedMem data without callback + * @tc.type: FUNC + */ +HWTEST_F(EbpfPagedMemoryParserTest, EbpfPagedMemoryParserCorrectWithoutCallback, TestSize.Level1) +{ + TS_LOGI("test31-1"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + memcpy_s(ebpfHeader.cmdline, EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), COMMAND_LINE.length()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&ebpfHeader))[0], + &(reinterpret_cast(&ebpfHeader))[EbpfDataHeader::EBPF_DATA_HEADER_SIZE]); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(PagedMemoryFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_VM; + PagedMemoryFixedHeader pagedMemoryFixedHeader; + pagedMemoryFixedHeader.pid = 32; + pagedMemoryFixedHeader.tid = 32; + memcpy_s(pagedMemoryFixedHeader.comm, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + pagedMemoryFixedHeader.startTime = START_TIME; + pagedMemoryFixedHeader.endTime = END_TIME; + pagedMemoryFixedHeader.addr = PAGEED_MEM_ADDR; + pagedMemoryFixedHeader.size = 1; + pagedMemoryFixedHeader.nips = 0; + pagedMemoryFixedHeader.type = 2; + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&ebpfTypeAndLength))[0], + &(reinterpret_cast(&ebpfTypeAndLength))[sizeof(EbpfTypeAndLength)]); + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&pagedMemoryFixedHeader))[0], + &(reinterpret_cast(&pagedMemoryFixedHeader))[sizeof(PagedMemoryFixedHeader)]); + + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetPagedMemoryMap().size()); + ebpfDataParser->ParsePagedMemoryEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstPagedMemorySampleData().CallChainIds()[0]; + EXPECT_EQ(callChainId, INVALID_UINT32); + auto type = stream_.traceDataCache_->GetConstPagedMemorySampleData().Types()[0]; + EXPECT_EQ(type, 2); + + auto startTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME); + auto endTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME); + auto dur = stream_.traceDataCache_->GetConstPagedMemorySampleData().Durs()[0]; + EXPECT_EQ(dur, END_TIME - START_TIME); + auto size = stream_.traceDataCache_->GetConstPagedMemorySampleData().Sizes()[0]; + EXPECT_EQ(size, 1); + auto ExpectAddr = ebpfDataParser->ConvertToHexTextIndex(pagedMemoryFixedHeader.addr); + auto addr = stream_.traceDataCache_->GetConstPagedMemorySampleData().Addr()[0]; + EXPECT_EQ(addr, ExpectAddr); +} + +/** + * @tc.name: EbpfPagedMemoryParserwrongWithoutCallback + * @tc.desc: Test parse pagedMem data without callback and startTs > endTs + * @tc.type: FUNC + */ +HWTEST_F(EbpfPagedMemoryParserTest, EbpfPagedMemoryParserwrongWithoutCallback, TestSize.Level1) +{ + TS_LOGI("test31-2"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + memcpy_s(ebpfHeader.cmdline, EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), COMMAND_LINE.length()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&ebpfHeader))[0], + &(reinterpret_cast(&ebpfHeader))[EbpfDataHeader::EBPF_DATA_HEADER_SIZE]); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(PagedMemoryFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_VM; + PagedMemoryFixedHeader pagedMemoryFixedHeader; + pagedMemoryFixedHeader.pid = 32; + pagedMemoryFixedHeader.tid = 32; + memcpy_s(pagedMemoryFixedHeader.comm, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + pagedMemoryFixedHeader.startTime = END_TIME; + pagedMemoryFixedHeader.endTime = START_TIME; + pagedMemoryFixedHeader.addr = PAGEED_MEM_ADDR; + pagedMemoryFixedHeader.size = 1; + pagedMemoryFixedHeader.nips = 0; + pagedMemoryFixedHeader.type = 2; + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&ebpfTypeAndLength))[0], + &(reinterpret_cast(&ebpfTypeAndLength))[sizeof(EbpfTypeAndLength)]); + dequeBuffer.insert(dequeBuffer.end(), &(reinterpret_cast(&pagedMemoryFixedHeader))[0], + &(reinterpret_cast(&pagedMemoryFixedHeader))[sizeof(PagedMemoryFixedHeader)]); + + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetPagedMemoryMap().size()); + ebpfDataParser->ParsePagedMemoryEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstPagedMemorySampleData().CallChainIds()[0]; + EXPECT_FALSE(callChainId == INVALID_UINT64); + auto type = stream_.traceDataCache_->GetConstPagedMemorySampleData().Types()[0]; + EXPECT_FALSE(type == 2); + + auto startTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().StartTs()[0]; + EXPECT_FALSE(startTs == pagedMemoryFixedHeader.startTime); + auto endTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().EndTs()[0]; + EXPECT_FALSE(endTs == pagedMemoryFixedHeader.endTime); + auto dur = stream_.traceDataCache_->GetConstPagedMemorySampleData().Durs()[0]; + EXPECT_FALSE(dur == endTs - startTs); + auto size = stream_.traceDataCache_->GetConstPagedMemorySampleData().Sizes()[0]; + EXPECT_FALSE(size == 1); + auto ExpectAddr = ebpfDataParser->ConvertToHexTextIndex(pagedMemoryFixedHeader.addr); + auto addr = stream_.traceDataCache_->GetConstPagedMemorySampleData().Addr()[0]; + EXPECT_FALSE(addr == ExpectAddr); +} + +/** + * @tc.name: EbpfPagedMemoryParserCorrectWithOneCallback + * @tc.desc: Test parse PagedMem data with one callback + * @tc.type: FUNC + */ +HWTEST_F(EbpfPagedMemoryParserTest, EbpfPagedMemoryParserCorrectWithOneCallback, TestSize.Level1) +{ + TS_LOGI("test31-3"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + memcpy_s(ebpfHeader.cmdline, EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), COMMAND_LINE.length()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(PagedMemoryFixedHeader); + ebpfTypeAndLength.type = ITEM_EVENT_VM; + PagedMemoryFixedHeader pagedMemoryFixedHeader; + pagedMemoryFixedHeader.pid = 32; + pagedMemoryFixedHeader.tid = 32; + memcpy_s(pagedMemoryFixedHeader.comm, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + pagedMemoryFixedHeader.startTime = START_TIME; + pagedMemoryFixedHeader.endTime = END_TIME; + pagedMemoryFixedHeader.addr = PAGEED_MEM_ADDR; + pagedMemoryFixedHeader.size = 1; + pagedMemoryFixedHeader.nips = 1; + pagedMemoryFixedHeader.type = 2; + const uint64_t ips[1] = {IPS_01}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&pagedMemoryFixedHeader), + reinterpret_cast(&pagedMemoryFixedHeader + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(ips), + reinterpret_cast(&ips + 1)); + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetPagedMemoryMap().size()); + ebpfDataParser->ParsePagedMemoryEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstPagedMemorySampleData().CallChainIds()[0]; + EXPECT_EQ(callChainId, 0); + auto type = stream_.traceDataCache_->GetConstPagedMemorySampleData().Types()[0]; + EXPECT_EQ(type, 2); + auto startTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME); + auto endTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME); + auto dur = stream_.traceDataCache_->GetConstPagedMemorySampleData().Durs()[0]; + EXPECT_EQ(dur, END_TIME - START_TIME); + auto size = stream_.traceDataCache_->GetConstPagedMemorySampleData().Sizes()[0]; + EXPECT_EQ(size, 1); + auto ExpectAddr = ebpfDataParser->ConvertToHexTextIndex(pagedMemoryFixedHeader.addr); + auto addr = stream_.traceDataCache_->GetConstPagedMemorySampleData().Addr()[0]; + EXPECT_EQ(addr, ExpectAddr); + auto ExpectIps0 = ebpfDataParser->ConvertToHexTextIndex(ips[0]); + auto ips0 = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[0]; + EXPECT_EQ(ips0, ExpectIps0); +} + +/** + * @tc.name: EbpfPagedMemoryParserCorrectWithMultipleCallback + * @tc.desc: Test parse PagedMem data with Multiple callback + * @tc.type: FUNC + */ +HWTEST_F(EbpfPagedMemoryParserTest, EbpfPagedMemoryParserCorrectWithMultipleCallback, TestSize.Level1) +{ + TS_LOGI("test31-4"); + EbpfDataHeader ebpfHeader; + ebpfHeader.header.clock = EBPF_CLOCK_BOOTTIME; + ebpfHeader.header.cmdLineLen = COMMAND_LINE.length(); + memcpy_s(ebpfHeader.cmdline, EBPF_COMMAND_MAX_SIZE, COMMAND_LINE.c_str(), COMMAND_LINE.length()); + std::deque dequeBuffer; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfHeader), + reinterpret_cast(&ebpfHeader + 1)); + EbpfTypeAndLength ebpfTypeAndLength; + ebpfTypeAndLength.length = sizeof(PagedMemoryFixedHeader) + 2 * sizeof(uint64_t); + ebpfTypeAndLength.type = ITEM_EVENT_VM; + PagedMemoryFixedHeader pagedMemoryFixedHeader; + pagedMemoryFixedHeader.pid = 32; + pagedMemoryFixedHeader.tid = 32; + memcpy_s(pagedMemoryFixedHeader.comm, MAX_PROCESS_NAME_SZIE, "process", MAX_PROCESS_NAME_SZIE); + pagedMemoryFixedHeader.startTime = START_TIME; + pagedMemoryFixedHeader.endTime = END_TIME; + pagedMemoryFixedHeader.addr = PAGEED_MEM_ADDR; + pagedMemoryFixedHeader.size = 1; + pagedMemoryFixedHeader.nips = 2; + pagedMemoryFixedHeader.type = 2; + const uint64_t ips[2] = {IPS_01, IPS_02}; + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&ebpfTypeAndLength), + reinterpret_cast(&ebpfTypeAndLength + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(&pagedMemoryFixedHeader), + reinterpret_cast(&pagedMemoryFixedHeader + 1)); + dequeBuffer.insert(dequeBuffer.end(), reinterpret_cast(ips), + reinterpret_cast(&ips + 1)); + std::unique_ptr ebpfDataParser = + std::make_unique(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + EXPECT_TRUE(ebpfDataParser->Init(dequeBuffer, dequeBuffer.size())); + EXPECT_TRUE(ebpfDataParser->reader_->GetPagedMemoryMap().size()); + ebpfDataParser->ParsePagedMemoryEvent(); + ebpfDataParser->Finish(); + EXPECT_TRUE(ebpfDataParser->reader_->ebpfDataHeader_->header.clock == EBPF_CLOCK_BOOTTIME); + auto callChainId = stream_.traceDataCache_->GetConstPagedMemorySampleData().CallChainIds()[0]; + EXPECT_EQ(callChainId, 0); + auto type = stream_.traceDataCache_->GetConstPagedMemorySampleData().Types()[0]; + EXPECT_EQ(type, 2); + auto startTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().StartTs()[0]; + EXPECT_EQ(startTs, START_TIME); + auto endTs = stream_.traceDataCache_->GetConstPagedMemorySampleData().EndTs()[0]; + EXPECT_EQ(endTs, END_TIME); + auto dur = stream_.traceDataCache_->GetConstPagedMemorySampleData().Durs()[0]; + EXPECT_EQ(dur, END_TIME - START_TIME); + auto size = stream_.traceDataCache_->GetConstPagedMemorySampleData().Sizes()[0]; + EXPECT_EQ(size, 1); + auto ExpectAddr = ebpfDataParser->ConvertToHexTextIndex(pagedMemoryFixedHeader.addr); + auto addr = stream_.traceDataCache_->GetConstPagedMemorySampleData().Addr()[0]; + EXPECT_EQ(addr, ExpectAddr); + auto ExpectIps0 = ebpfDataParser->ConvertToHexTextIndex(ips[0]); + auto ips0 = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[1]; + EXPECT_EQ(ips0, ExpectIps0); + auto ExpectIps1 = ebpfDataParser->ConvertToHexTextIndex(ips[1]); + auto ips1 = stream_.traceDataCache_->GetConstEbpfCallStackData().Ips()[0]; + EXPECT_EQ(ips1, ExpectIps1); +} +} // namespace SysTuning::TraceStreamer diff --git a/trace_streamer/test/unittest/parser_pbreader_test.cpp b/trace_streamer/test/unittest/parser_pbreader_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b36f37e3ad73beb4e9fdca762fbeda89632c35af --- /dev/null +++ b/trace_streamer/test/unittest/parser_pbreader_test.cpp @@ -0,0 +1,109 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "file.h" +#include "trace_streamer_selector.h" +constexpr size_t G_FILE_PERMISSION = 664; + +using namespace testing::ext; +using namespace SysTuning; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class ParserPbreaderTest : public testing::Test { +protected: + static void SetUpTestCase() {} + static void TearDownTestCase() {} +}; + +/** + * @tc.name: HtracePbreaderParserTest + * @tc.desc: Test htrace parsing binary file export database + * @tc.type: FUNC + */ +HWTEST_F(ParserPbreaderTest, HtracePbreaderParserTest, TestSize.Level1) +{ + TS_LOGI("test34-1"); + const std::string tracePath = "data/resource/pbreader.htrace"; + const std::string utGoldDb = "data/resource/pbreaderhtrace.db"; + const std::string dbPath = "data/resource/out_db2.db"; + constexpr size_t readSize = 1024; + constexpr uint32_t lineLength = 256; + + if (access(tracePath.c_str(), F_OK) == 0) { + std::unique_ptr ta = + std::make_unique(); + ta->EnableMetaTable(false); + ta->SetCleanMode(false); + int32_t fd(base::OpenFile(tracePath, O_RDONLY, G_FILE_PERMISSION)); + while (true) { + std::unique_ptr buf = std::make_unique(readSize); + auto rsize = base::Read(fd, buf.get(), readSize); + + if (rsize == 0) { + break; + } + if (rsize < 0) { + TS_LOGD("Reading trace file over (errno: %d, %s)", errno, strerror(errno)); + break; + } + if (!ta->ParseTraceDataSegment(std::move(buf), rsize)) { + break; + }; + } + ta->WaitForParserEnd(); + close(fd); + ta->ExportDatabase(dbPath); + ta->Clear(); + EXPECT_TRUE(access(dbPath.c_str(), F_OK) == 0); + } else { + EXPECT_TRUE(false); + } + + if (access(utGoldDb.c_str(), F_OK) == 0) { + FILE* file1 = nullptr; + FILE* file2 = nullptr; + char line1[lineLength]; + char line2[lineLength]; + const std::string command1 = "md5sum data/resource/pbreaderhtrace.db"; + const std::string md5DbPath = "md5sum " + dbPath; + file1 = popen(command1.c_str(), "r"); + file2 = popen(md5DbPath.c_str(), "r"); + if (file1 && file2) { + if (fgets(line1, lineLength, file1) != nullptr && fgets(line2, lineLength, file2) != nullptr) { + std::string str1(line1); + std::string str2(line2); + str1 = str1.substr(0, str1.find_first_of(' ')); + str2 = str2.substr(0, str2.find_first_of(' ')); + EXPECT_TRUE(str1.compare(str2) == 0); + } + } + } else { + EXPECT_TRUE(false); + } + + if (access(dbPath.c_str(), F_OK) == 0) { + remove(dbPath.c_str()); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/parser_test.cpp b/trace_streamer/test/unittest/parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dc530772baba41b42b80c5aa0b31e691fecca12 --- /dev/null +++ b/trace_streamer/test/unittest/parser_test.cpp @@ -0,0 +1,321 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include "file.h" +#include "trace_streamer_selector.h" +constexpr size_t G_FILE_PERMISSION = 664; + +using namespace testing::ext; +using namespace SysTuning; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class ParserTest : public testing::Test { +protected: + static void SetUpTestCase() {} + static void TearDownTestCase() {} +}; + +/** + * @tc.name: BytraceParserTest + * @tc.desc: Test bytrace parsing TXT file to export database + * @tc.type: FUNC + */ +HWTEST_F(ParserTest, BytraceParserTest, TestSize.Level1) +{ + TS_LOGI("test25-1"); + const std::string tracePath = "data/resource/ut_bytrace_input_full.txt"; + const std::string utGoldDb = "data/resource/ut_bytrace_input_full_gold.db"; + const std::string dbPath = "data/resource/out_db1.db"; + constexpr size_t readSize = 1024 * 1024; + constexpr uint32_t lineLength = 256; + + if (access(tracePath.c_str(), F_OK) == 0) { + std::unique_ptr ta = + std::make_unique(); + ta->EnableMetaTable(false); + ta->SetCleanMode(false); + int32_t fd(base::OpenFile(tracePath, O_RDONLY, G_FILE_PERMISSION)); + while (true) { + std::unique_ptr buf = std::make_unique(readSize); + auto rsize = base::Read(fd, buf.get(), readSize); + if (rsize == 0) { + break; + } + if (rsize < 0) { + TS_LOGD("Reading trace file failed (errno: %d, %s)", errno, strerror(errno)); + break; + } + if (!ta->ParseTraceDataSegment(std::move(buf), rsize)) { + break; + }; + } + ta->WaitForParserEnd(); + close(fd); + ta->ExportDatabase(dbPath); + ta->Clear(); + EXPECT_TRUE(access(dbPath.c_str(), F_OK) == 0); + } else { + EXPECT_TRUE(false); + } + + if (access(utGoldDb.c_str(), F_OK) == 0) { + FILE* file1 = nullptr; + FILE* file2 = nullptr; + char line1[lineLength]; + char line2[lineLength]; + const std::string command1 = "md5sum data/resource/ut_bytrace_input_full_gold.db"; + const std::string md5DbPath = "md5sum " + dbPath; + file1 = popen(command1.c_str(), "r"); + file2 = popen(md5DbPath.c_str(), "r"); + if (file1 && file2) { + if (fgets(line1, lineLength, file1) != nullptr && fgets(line2, lineLength, file2) != nullptr) { + std::string str1(line1); + std::string str2(line2); + str1 = str1.substr(0, str1.find_first_of(' ')); + str2 = str2.substr(0, str2.find_first_of(' ')); + EXPECT_TRUE(str1.compare(str2) == 0); + } + } + } else { + EXPECT_TRUE(false); + } + + if (access(dbPath.c_str(), F_OK) == 0) { + remove(dbPath.c_str()); + } +} + +/** + * @tc.name: HtraceParserTest + * @tc.desc: Test htrace parsing binary file export database + * @tc.type: FUNC + */ +HWTEST_F(ParserTest, HtraceParserTest, TestSize.Level1) +{ + TS_LOGI("test25-2"); + const std::string tracePath = "data/resource/htrace.bin"; + const std::string utGoldDb = "data/resource/htrace_gold.db"; + const std::string dbPath = "data/resource/out_db2.db"; + constexpr size_t readSize = 1024; + constexpr uint32_t lineLength = 256; + + if (access(tracePath.c_str(), F_OK) == 0) { + std::unique_ptr ta = + std::make_unique(); + ta->EnableMetaTable(false); + ta->SetCleanMode(false); + int32_t fd(base::OpenFile(tracePath, O_RDONLY, G_FILE_PERMISSION)); + while (true) { + std::unique_ptr buf = std::make_unique(readSize); + auto rsize = base::Read(fd, buf.get(), readSize); + + if (rsize == 0) { + break; + } + if (rsize < 0) { + TS_LOGD("Reading trace file over (errno: %d, %s)", errno, strerror(errno)); + break; + } + if (!ta->ParseTraceDataSegment(std::move(buf), rsize)) { + break; + }; + } + ta->WaitForParserEnd(); + close(fd); + ta->ExportDatabase(dbPath); + ta->Clear(); + EXPECT_TRUE(access(dbPath.c_str(), F_OK) == 0); + } else { + EXPECT_TRUE(false); + } + + if (access(utGoldDb.c_str(), F_OK) == 0) { + FILE* file1 = nullptr; + FILE* file2 = nullptr; + char line1[lineLength]; + char line2[lineLength]; + const std::string command1 = "md5sum data/resource/htrace_gold.db"; + const std::string md5DbPath = "md5sum " + dbPath; + file1 = popen(command1.c_str(), "r"); + file2 = popen(md5DbPath.c_str(), "r"); + if (file1 && file2) { + if (fgets(line1, lineLength, file1) != nullptr && fgets(line2, lineLength, file2) != nullptr) { + std::string str1(line1); + std::string str2(line2); + str1 = str1.substr(0, str1.find_first_of(' ')); + str2 = str2.substr(0, str2.find_first_of(' ')); + EXPECT_TRUE(str1.compare(str2) == 0); + } + } + } else { + EXPECT_TRUE(false); + } + + if (access(dbPath.c_str(), F_OK) == 0) { + remove(dbPath.c_str()); + } +} + +/** + * @tc.name: HtraceAndPerfParserTest + * @tc.desc: Test parsing htrace and perf binary file export database + * @tc.type: FUNC + */ +HWTEST_F(ParserTest, HtraceAndPerfParserTest, TestSize.Level1) +{ + TS_LOGI("test25-3"); + const std::string tracePath = "data/resource/htrace_perf.bin"; + const std::string utGoldDb = "data/resource/htrace_perf_gold.db"; + const std::string dbPath = "data/resource/out_db3.db"; + constexpr size_t readSize = 1024; + constexpr uint32_t lineLength = 256; + + if (access(tracePath.c_str(), F_OK) == 0) { + std::unique_ptr ta = + std::make_unique(); + ta->EnableMetaTable(false); + ta->SetCleanMode(false); + int32_t fd(base::OpenFile(tracePath, O_RDONLY, G_FILE_PERMISSION)); + while (true) { + std::unique_ptr buf = std::make_unique(readSize); + auto rsize = base::Read(fd, buf.get(), readSize); + + if (rsize == 0) { + break; + } + if (rsize < 0) { + TS_LOGD("Reading trace file over (errno: %d, %s)", errno, strerror(errno)); + break; + } + if (!ta->ParseTraceDataSegment(std::move(buf), rsize)) { + break; + }; + } + ta->WaitForParserEnd(); + close(fd); + ta->ExportDatabase(dbPath); + ta->Clear(); + EXPECT_TRUE(access(dbPath.c_str(), F_OK) == 0); + } else { + EXPECT_TRUE(false); + } + + if (access(utGoldDb.c_str(), F_OK) == 0) { + FILE* file1 = nullptr; + FILE* file2 = nullptr; + char line1[lineLength]; + char line2[lineLength]; + const std::string command1 = "md5sum data/resource/htrace_perf_gold.db"; + const std::string md5DbPath = "md5sum " + dbPath; + file1 = popen(command1.c_str(), "r"); + file2 = popen(md5DbPath.c_str(), "r"); + if (file1 && file2) { + if (fgets(line1, lineLength, file1) != nullptr && fgets(line2, lineLength, file2) != nullptr) { + std::string str1(line1); + std::string str2(line2); + str1 = str1.substr(0, str1.find_first_of(' ')); + str2 = str2.substr(0, str2.find_first_of(' ')); + EXPECT_TRUE(str1.compare(str2) == 0); + } + } + } else { + EXPECT_TRUE(false); + } + + if (access(dbPath.c_str(), F_OK) == 0) { + remove(dbPath.c_str()); + } +} + +/** + * @tc.name: HtraceAndEbpfParserTest + * @tc.desc: Test parsing htrace and ebpf binary file export database + * @tc.type: FUNC + */ +HWTEST_F(ParserTest, HtraceAndEbpfParserTest, TestSize.Level1) +{ + TS_LOGI("test25-4"); + const std::string tracePath = "data/resource/htrace_ebpf.bin"; + const std::string utGoldDb = "data/resource/htrace_ebpf_gold.db"; + const std::string dbPath = "data/resource/out_db4.db"; + constexpr size_t readSize = 1024; + constexpr uint32_t lineLength = 256; + + if (access(tracePath.c_str(), F_OK) == 0) { + std::unique_ptr ta = + std::make_unique(); + ta->EnableMetaTable(false); + ta->SetCleanMode(false); + int32_t fd(base::OpenFile(tracePath, O_RDONLY, G_FILE_PERMISSION)); + while (true) { + std::unique_ptr buf = std::make_unique(readSize); + auto rsize = base::Read(fd, buf.get(), readSize); + + if (rsize == 0) { + break; + } + if (rsize < 0) { + TS_LOGD("Reading trace file over (errno: %d, %s)", errno, strerror(errno)); + break; + } + if (!ta->ParseTraceDataSegment(std::move(buf), rsize)) { + break; + }; + } + ta->WaitForParserEnd(); + close(fd); + ta->ExportDatabase(dbPath); + ta->Clear(); + EXPECT_TRUE(access(dbPath.c_str(), F_OK) == 0); + } else { + EXPECT_TRUE(false); + } + + if (access(utGoldDb.c_str(), F_OK) == 0) { + FILE* file1 = nullptr; + FILE* file2 = nullptr; + char line1[lineLength]; + char line2[lineLength]; + const std::string command1 = "md5sum data/resource/htrace_ebpf_gold.db"; + const std::string md5DbPath = "md5sum " + dbPath; + file1 = popen(command1.c_str(), "r"); + file2 = popen(md5DbPath.c_str(), "r"); + if (file1 && file2) { + if (fgets(line1, lineLength, file1) != nullptr && fgets(line2, lineLength, file2) != nullptr) { + std::string str1(line1); + std::string str2(line2); + str1 = str1.substr(0, str1.find_first_of(' ')); + str2 = str2.substr(0, str2.find_first_of(' ')); + EXPECT_TRUE(str1.compare(str2) == 0); + } + } + } else { + EXPECT_TRUE(false); + } + + if (access(dbPath.c_str(), F_OK) == 0) { + remove(dbPath.c_str()); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/process_filter_test.cpp b/trace_streamer/test/unittest/process_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..08ea18eeb45c09fc6207ac3a2542dd20d19f8f5d --- /dev/null +++ b/trace_streamer/test/unittest/process_filter_test.cpp @@ -0,0 +1,385 @@ +/* + * 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 +#include + +#include "process_filter.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class ProcessFilterTest : public ::testing::Test { +public: + void SetUp() + { + streamFilters_.processFilter_ = std::make_unique(&traceDataCache_, &streamFilters_); + } + + void TearDown() {} + +public: + TraceStreamerFilters streamFilters_; + TraceDataCache traceDataCache_; +}; + +/** + * @tc.name: UpdateOrCreateThread + * @tc.desc: Test UpdateOrCreateThread interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThread, TestSize.Level1) +{ + TS_LOGI("test26-1"); + uint64_t ts = 168758662877000; + uint32_t tid0 = 2716; + uint32_t iTid0 = streamFilters_.processFilter_->UpdateOrCreateThread(ts, tid0); + EXPECT_TRUE(iTid0 == 1); + + uint32_t tid1 = 2519; + uint32_t iTid1 = streamFilters_.processFilter_->UpdateOrCreateThread(0, tid1); + EXPECT_TRUE(iTid1 == 2); + + Thread* thread = traceDataCache_.GetThreadData(iTid0); + EXPECT_TRUE(thread->tid_ == tid0); + + thread = traceDataCache_.GetThreadData(iTid1); + EXPECT_TRUE(thread->tid_ == tid1); +} + +/** + * @tc.name: UpdateOrCreateProcessWithName + * @tc.desc: Test UpdateOrCreateProcessWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateProcessWithName, TestSize.Level1) +{ + TS_LOGI("test26-2"); + uint32_t pid0 = 8629; + std::string_view processName = "RenderThread"; + uint32_t iPid0 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid0, processName); + EXPECT_TRUE(iPid0 == 1); + + uint32_t pid1 = 8709; + uint32_t iPid1 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid1, processName); + EXPECT_TRUE(iPid1 == 2); + + Process* process = traceDataCache_.GetProcessData(iPid0); + EXPECT_TRUE(process->pid_ == pid0); + + process = traceDataCache_.GetProcessData(iPid1); + EXPECT_TRUE(process->pid_ == pid1); +} + +/** + * @tc.name: UpdateOrCreateProcessWithNameSingleIpid + * @tc.desc: Test whether the internal PID of the generated single process is as expected. + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateProcessWithNameSingleIpid, TestSize.Level1) +{ + TS_LOGI("test26-3"); + uint32_t pid = 8629; + std::string_view processName = "RenderThread"; + uint32_t iPid0 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid, processName); + EXPECT_TRUE(iPid0 == 1); +} + +/** + * @tc.name: UpdateOrCreateProcessWithNameMultiIpid + * @tc.desc: Test genarated multi ipid with UpdateOrCreateProcessWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateProcessWithNameMultiIpid, TestSize.Level1) +{ + TS_LOGI("test26-4"); + uint32_t pid0 = 8629; + std::string_view processName = "RenderThread"; + uint32_t iPid0 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid0, processName); + EXPECT_TRUE(iPid0 == 1); + + uint32_t pid1 = 8709; + uint32_t iPid1 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid1, processName); + EXPECT_TRUE(iPid1 == 2); +} + +/** + * @tc.name: UpdateOrCreateProcessWithNameSinglePid + * @tc.desc: Test genarated single pid with UpdateOrCreateProcessWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateProcessWithNameSinglePid, TestSize.Level1) +{ + TS_LOGI("test26-5"); + uint32_t pid = 8629; + std::string_view processName = "RenderThread"; + uint32_t iPid0 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid, processName); + EXPECT_TRUE(iPid0 == 1); + + Process* process = traceDataCache_.GetProcessData(iPid0); + EXPECT_TRUE(process->pid_ == pid); +} + +/** + * @tc.name: UpdateOrCreateProcessWithNameMultiPid + * @tc.desc: est genarated multi pid with UpdateOrCreateProcessWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateProcessWithNameMultiPid, TestSize.Level1) +{ + TS_LOGI("test26-6"); + uint32_t pid0 = 8629; + std::string_view processName = "RenderThread"; + uint32_t iPid0 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid0, processName); + EXPECT_TRUE(iPid0 == 1); + + uint32_t pid1 = 8709; + uint32_t iPid1 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid1, processName); + EXPECT_TRUE(iPid1 == 2); + + uint32_t pid3 = 87091; + uint32_t iPid2 = streamFilters_.processFilter_->UpdateOrCreateProcessWithName(87091, processName); + EXPECT_TRUE(iPid2 == 3); + + Process* process = traceDataCache_.GetProcessData(iPid0); + EXPECT_TRUE(process->pid_ == pid0); + + process = traceDataCache_.GetProcessData(iPid1); + EXPECT_TRUE(process->pid_ == pid1); + + process = traceDataCache_.GetProcessData(iPid2); + EXPECT_TRUE(process->pid_ == pid3); +} + +/** + * @tc.name: UpdateOrCreateThreadWithName + * @tc.desc: Test UpdateOrCreateThreadWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithName, TestSize.Level1) +{ + TS_LOGI("test26-7"); + uint64_t ts = 168758662957020; + uint32_t tid = 123; + std::string_view threadName = "RenderThread"; + uint32_t iTid0 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts, tid, threadName); + EXPECT_TRUE(iTid0 == 1); + uint64_t ts2 = 168758663957020; + uint32_t tid2 = 2519; + std::string_view threadName2 = "RenderThread2"; + uint32_t iTid1 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts2, tid2, threadName2); + EXPECT_TRUE(iTid1 == 2); + + Thread* thread = traceDataCache_.GetThreadData(iTid0); + EXPECT_TRUE(thread->tid_ == tid); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName)); + + thread = traceDataCache_.GetThreadData(iTid1); + EXPECT_TRUE(thread->tid_ == tid2); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName2)); +} + +/** + * @tc.name: UpdateOrCreateThreadWithNameSingleItid + * @tc.desc: Test genarated single itid with UpdateOrCreateThreadWithName + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithNameSingleItid, TestSize.Level1) +{ + TS_LOGI("test26-8"); + uint64_t ts = 168758662957020; + uint32_t tid = 123; + std::string_view threadName = "RenderThread"; + uint32_t iTid0 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts, tid, threadName); + EXPECT_TRUE(iTid0 == 1); +} + +/** + * @tc.name: UpdateOrCreateThreadWithNameGenarateTidAndItid + * @tc.desc: Test genarated single itid and tid with UpdateOrCreateThreadWithName + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithNameGenarateTidAndItid, TestSize.Level1) +{ + TS_LOGI("test26-9"); + uint64_t ts = 168758662957020; + uint32_t tid = 123; + std::string_view threadName = "RenderThread2"; + uint32_t iTid0 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts, tid, threadName); + EXPECT_TRUE(iTid0 == 1); + Thread* thread = traceDataCache_.GetThreadData(iTid0); + EXPECT_TRUE(thread->tid_ == tid); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName)); +} + +/** + * @tc.name: UpdateOrCreateThreadWithNameDoubleItid + * @tc.desc: Test genarate double itid with UpdateOrCreateThreadWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithNameDoubleItid, TestSize.Level1) +{ + TS_LOGI("test26-10"); + uint64_t ts = 168758662957020; + uint32_t tid = 123; + std::string_view threadName = "RenderThread"; + uint32_t iTid0 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts, tid, threadName); + EXPECT_TRUE(iTid0 == 1); + uint64_t ts2 = 168758663957020; + uint32_t tid2 = 2519; + std::string_view threadName2 = "RenderThread2"; + uint32_t iTid1 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts2, tid2, threadName2); + EXPECT_TRUE(iTid1 == 2); + auto thread = traceDataCache_.GetThreadData(iTid1); + EXPECT_TRUE(thread->tid_ == tid2); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName2)); +} + +/** + * @tc.name: UpdateOrCreateThreadWithNameTripleItid + * @tc.desc: Test genarate triple itid with UpdateOrCreateThreadWithName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithNameTripleItid, TestSize.Level1) +{ + TS_LOGI("test26-11"); + uint64_t ts = 168758662957020; + uint32_t tid = 123; + std::string_view threadName = "RenderThread"; + uint32_t iTid0 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts, tid, threadName); + EXPECT_TRUE(iTid0 == 1); + uint64_t ts2 = 168758663957020; + uint32_t tid2 = 2519; + std::string_view threadName2 = "RenderThread2"; + uint32_t iTid1 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts2, tid2, threadName2); + EXPECT_TRUE(iTid1 == 2); + uint64_t ts3 = 168758663957020; + uint32_t tid3 = 25191; + std::string_view threadName3 = "RenderThread3"; + uint32_t iTid2 = streamFilters_.processFilter_->UpdateOrCreateThreadWithName(ts3, tid3, threadName3); + EXPECT_TRUE(iTid2 == 3); + auto thread = traceDataCache_.GetThreadData(iTid2); + EXPECT_TRUE(thread->tid_ == tid3); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName3)); +} + +/** + * @tc.name: UpdateOrCreateThreadWithPidAndName + * @tc.desc: Test UpdateOrCreateThreadWithPidAndName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithPidAndName, TestSize.Level1) +{ + TS_LOGI("test26-12"); + uint32_t tid = 869; + uint32_t pid = 123; + std::string_view threadName = "RenderThread"; + streamFilters_.processFilter_->UpdateOrCreateThreadWithPidAndName(tid, pid, threadName); + auto itid = streamFilters_.processFilter_->GetInternalTid(tid); + EXPECT_TRUE(itid != INVALID_ID); + + Thread* thread = traceDataCache_.GetThreadData(itid); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName)); +} + +/** + * @tc.name: UpdateOrCreateThreadWithPidAndNameAbnomal + * @tc.desc: Test UpdateOrCreateThreadWithPidAndName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithPidAndNameAbnomal, TestSize.Level1) +{ + TS_LOGI("test26-13"); + uint32_t tid = 869; + uint32_t pid = 123; + std::string_view threadName = "RenderThread"; + streamFilters_.processFilter_->UpdateOrCreateThreadWithPidAndName(tid, pid, threadName); + uint32_t tid2 = 969; + auto itid = streamFilters_.processFilter_->GetInternalTid(tid2); + EXPECT_TRUE(itid == INVALID_ID); +} + +/** + * @tc.name: UpdateOrCreateThreadWithPidAndNameSingleItid + * @tc.desc: Test UpdateOrCreateThreadWithPidAndName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithPidAndNameSingleItid, TestSize.Level1) +{ + TS_LOGI("test26-14"); + uint32_t tid = 869; + uint32_t pid = 123; + std::string_view threadName = "RenderThread"; + streamFilters_.processFilter_->UpdateOrCreateThreadWithPidAndName(tid, pid, threadName); + auto itid = streamFilters_.processFilter_->GetInternalPid(pid); + EXPECT_TRUE(itid != INVALID_ID); +} + +/** + * @tc.name: UpdateOrCreateThreadWithPidAndNameAbnomalPid + * @tc.desc: Test UpdateOrCreateThreadWithPidAndName interface + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateOrCreateThreadWithPidAndNameAbnomalPid, TestSize.Level1) +{ + TS_LOGI("test26-15"); + uint32_t tid = 869; + uint32_t pid0 = 123; + std::string_view threadName = "RenderThread"; + streamFilters_.processFilter_->UpdateOrCreateThreadWithPidAndName(tid, pid0, threadName); + uint32_t pid1 = 124; + auto itid = streamFilters_.processFilter_->GetInternalPid(pid1); + EXPECT_TRUE(itid == INVALID_ID); +} + +/** + * @tc.name: UpdateThreadWithName + * @tc.desc: Test update thread name + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateThreadWithName, TestSize.Level1) +{ + TS_LOGI("test26-16"); + uint32_t tid = 869; + uint64_t timeStamp = 168758662957020; + std::string_view threadName = "RenderThread"; + streamFilters_.processFilter_->UpdateOrCreateThread(timeStamp, tid); + streamFilters_.processFilter_->UpdateOrCreateThreadWithName(timeStamp, tid, threadName); + auto itid = streamFilters_.processFilter_->GetInternalTid(tid); + EXPECT_TRUE(itid != INVALID_ID); + Thread* thread = traceDataCache_.GetThreadData(itid); + EXPECT_TRUE(thread->nameIndex_ == traceDataCache_.GetDataIndex(threadName)); +} + +/** + * @tc.name: UpdateProcessWithName + * @tc.desc: Test update process name + * @tc.type: FUNC + */ +HWTEST_F(ProcessFilterTest, UpdateProcessWithName, TestSize.Level1) +{ + TS_LOGI("test26-17"); + uint32_t pid = 869; + uint64_t timeStamp = 168758662957020; + std::string_view processName = "RenderProcess"; + auto ipid = streamFilters_.processFilter_->GetOrCreateInternalPid(timeStamp, pid); + EXPECT_TRUE(ipid != INVALID_ID); + streamFilters_.processFilter_->UpdateOrCreateProcessWithName(pid, processName); + Process* process = traceDataCache_.GetProcessData(ipid); + EXPECT_TRUE(process->cmdLine_ == processName); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/proto_reader_test.cpp b/trace_streamer/test/unittest/proto_reader_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7626992d07a3fbd30703144112ea5a4c537116c --- /dev/null +++ b/trace_streamer/test/unittest/proto_reader_test.cpp @@ -0,0 +1,1030 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include "file.h" +#include "proto_reader.cpp" +#include "test.pb.h" +#include "test.pb.cc" +#include "test.pbreader.h" +#include "trace_streamer_selector.h" + +class ProtoReader; +using namespace testing::ext; +using namespace SysTuning; +using namespace SysTuning::TraceStreamer; +using namespace SysTuning::ProtoReader; +namespace SysTuning { +namespace TraceStreamer { +class ProtoReaderTest : public ::testing::Test { +protected: + static void SetUpTestCase() {} + static void TearDownTestCase() {} +}; +/** + * @tc.name: ParserDataByPBReader + * @tc.desc: ParserData by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-1"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER = 100; + const uint64_t TVNSEC = 1000000; + const std::string NAME = "1000"; + const int32_t ALLOCEVENT = 10000; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test = cores->add_test(); + test->set_number(NUMBER); + test->set_tv_nsec(TVNSEC); + test->set_name(NAME); + test->set_is_test(true); + test->set_state(::Test_State(0)); + test->set_alloc_event(ALLOCEVENT); + testParser.set_allocated_cores(cores); + + std::string str = ""; + testParser.SerializeToString(&str); + + TestParser_Reader testParserReader(str); + EXPECT_EQ(COUNT, testParserReader.count()); + auto core = testParserReader.cores(); + CpuInfoTest_Reader cpuInfoTest(core.data_, core.size_); + + auto itor = cpuInfoTest.test(); + Test_Reader cpuInfoReader1(itor->ToBytes()); + EXPECT_EQ(NUMBER, cpuInfoReader1.number()); + EXPECT_EQ(TVNSEC, cpuInfoReader1.tv_nsec()); + EXPECT_EQ(NAME, cpuInfoReader1.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader1.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader1.state()); + EXPECT_EQ(ALLOCEVENT, cpuInfoReader1.alloc_event()); +} + +/** + * @tc.name: ParserRepeatedDataByPBReader + * @tc.desc: ParserRepeatedData by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserRepeatedDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-2"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER1 = 100; + const uint64_t TVNSEC1 = 1000000; + const std::string NAME1 = "1000"; + const int32_t ALLOCEVENT1 = 10000; + const int32_t NUMBER2 = 200; + const uint64_t TVNSEC2 = 2000000; + const std::string NAME2 = "2000"; + const int32_t ALLOCEVENT2 = 20000; + const int32_t NUMBER3 = 300; + const uint64_t TVNSEC3 = 3000000; + const std::string NAME3 = "3000"; + const int32_t ALLOCEVENT3 = 30000; + std::string str = ""; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test1 = cores->add_test(); + test1->set_number(NUMBER1); + test1->set_tv_nsec(TVNSEC1); + test1->set_name(NAME1); + test1->set_is_test(true); + test1->set_state(::Test_State(0)); + test1->set_alloc_event(ALLOCEVENT1); + + auto test2 = cores->add_test(); + test2->set_number(NUMBER2); + test2->set_tv_nsec(TVNSEC2); + test2->set_name(NAME2); + test2->set_is_test(false); + test2->set_state(::Test_State(1)); + test2->set_alloc_event(ALLOCEVENT2); + + auto test3 = cores->add_test(); + test3->set_number(NUMBER3); + test3->set_tv_nsec(TVNSEC3); + test3->set_name(NAME3); + test3->set_is_test(true); + test3->set_state(::Test_State(0)); + test3->set_alloc_event(ALLOCEVENT3); + testParser.set_allocated_cores(cores); + testParser.SerializeToString(&str); + + TestParser_Reader testParserReader(str); + EXPECT_EQ(COUNT, testParserReader.count()); + auto core = testParserReader.cores(); + CpuInfoTest_Reader cpuInfoTest(core.data_, core.size_); + auto itor = cpuInfoTest.test(); + Test_Reader cpuInfoReader1(itor->ToBytes()); + EXPECT_EQ(NUMBER1, cpuInfoReader1.number()); + EXPECT_EQ(TVNSEC1, cpuInfoReader1.tv_nsec()); + EXPECT_EQ(NAME1, cpuInfoReader1.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader1.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader1.state()); + EXPECT_EQ(ALLOCEVENT1, cpuInfoReader1.alloc_event()); + itor++; + Test_Reader cpuInfoReader2(itor->ToBytes()); + EXPECT_EQ(NUMBER2, cpuInfoReader2.number()); + EXPECT_EQ(TVNSEC2, cpuInfoReader2.tv_nsec()); + EXPECT_EQ(NAME2, cpuInfoReader2.name().ToStdString()); + EXPECT_EQ(false, cpuInfoReader2.is_test()); + EXPECT_EQ(::Test_State(1), cpuInfoReader2.state()); + EXPECT_EQ(ALLOCEVENT2, cpuInfoReader2.alloc_event()); + itor++; + Test_Reader cpuInfoReader3(itor->ToBytes()); + EXPECT_EQ(NUMBER3, cpuInfoReader3.number()); + EXPECT_EQ(TVNSEC3, cpuInfoReader3.tv_nsec()); + EXPECT_EQ(NAME3, cpuInfoReader3.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader3.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader3.state()); + EXPECT_EQ(ALLOCEVENT3, cpuInfoReader3.alloc_event()); +} + +/** + * @tc.name: NoDataByPBReader + * @tc.desc: ParserNoData by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, NoDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-3"); + TestParser testParser; + + std::string str = ""; + testParser.SerializeToString(&str); + + TestParser_Reader testParserReader(str); + EXPECT_EQ(0, testParserReader.count()); + auto core = testParserReader.cores(); + CpuInfoTest_Reader cpuInfoTest(core.data_, core.size_); + + auto itor = cpuInfoTest.test(); + Test_Reader cpuInfoReader1(itor->ToBytes()); + EXPECT_EQ(0, cpuInfoReader1.number()); + EXPECT_EQ(0, cpuInfoReader1.tv_nsec()); + EXPECT_EQ("", cpuInfoReader1.name().ToStdString()); + EXPECT_EQ(false, cpuInfoReader1.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader1.state()); + EXPECT_EQ(0, cpuInfoReader1.alloc_event()); +} + +/** + * @tc.name: ParserOneofForMutiDataByPBReader + * @tc.desc: ParserOneofForMutiData by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserOneofForMutiDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-4"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER1 = 100; + const uint64_t TVNSEC1 = 1000000; + const std::string NAME1 = "1000"; + const int32_t ALLOCEVENT1 = 10000; + const int32_t NUMBER2 = 200; + const uint64_t TVNSEC2 = 2000000; + const std::string NAME2 = "2000"; + const std::string FREEEVENT = "20000"; + const int32_t NUMBER3 = 300; + const uint64_t TVNSEC3 = 3000000; + const std::string NAME3 = "3000"; + const int32_t ALLOCEVENT3 = 30000; + std::string str = ""; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test1 = cores->add_test(); + test1->set_number(NUMBER1); + test1->set_tv_nsec(TVNSEC1); + test1->set_name(NAME1); + test1->set_is_test(true); + test1->set_state(::Test_State(0)); + test1->set_alloc_event(ALLOCEVENT1); + + auto test2 = cores->add_test(); + test2->set_number(NUMBER2); + test2->set_tv_nsec(TVNSEC2); + test2->set_name(NAME2); + test2->set_is_test(false); + test2->set_state(::Test_State(1)); + test2->set_free_event(FREEEVENT); + + auto test3 = cores->add_test(); + test3->set_number(NUMBER3); + test3->set_tv_nsec(TVNSEC3); + test3->set_name(NAME3); + test3->set_is_test(true); + test3->set_state(::Test_State(0)); + test3->set_alloc_event(ALLOCEVENT3); + testParser.set_allocated_cores(cores); + testParser.SerializeToString(&str); + + TestParser_Reader testParserReader(str); + EXPECT_EQ(COUNT, testParserReader.count()); + auto core = testParserReader.cores(); + CpuInfoTest_Reader cpuInfoTest(core.data_, core.size_); + auto itor = cpuInfoTest.test(); + Test_Reader cpuInfoReader1(itor->ToBytes()); + EXPECT_EQ(NUMBER1, cpuInfoReader1.number()); + EXPECT_EQ(TVNSEC1, cpuInfoReader1.tv_nsec()); + EXPECT_EQ(NAME1, cpuInfoReader1.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader1.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader1.state()); + EXPECT_EQ(ALLOCEVENT1, cpuInfoReader1.alloc_event()); + itor++; + Test_Reader cpuInfoReader2(itor->ToBytes()); + EXPECT_EQ(NUMBER2, cpuInfoReader2.number()); + EXPECT_EQ(TVNSEC2, cpuInfoReader2.tv_nsec()); + EXPECT_EQ(NAME2, cpuInfoReader2.name().ToStdString()); + EXPECT_EQ(false, cpuInfoReader2.is_test()); + EXPECT_EQ(::Test_State(1), cpuInfoReader2.state()); + EXPECT_EQ(FREEEVENT, cpuInfoReader2.free_event().ToStdString()); + itor++; + Test_Reader cpuInfoReader3(itor->ToBytes()); + EXPECT_EQ(NUMBER3, cpuInfoReader3.number()); + EXPECT_EQ(TVNSEC3, cpuInfoReader3.tv_nsec()); + EXPECT_EQ(NAME3, cpuInfoReader3.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader3.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader3.state()); + EXPECT_EQ(ALLOCEVENT3, cpuInfoReader3.alloc_event()); +} + +/** + * @tc.name: Parser One of Data For alloc event By PBReader + * @tc.desc: ParserOneofData by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserOneofDataForAllocEventByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-5"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER1 = 100; + const uint64_t TVNSEC1 = 1000000; + const std::string NAME1 = "1000"; + const int32_t ALLOCEVENT = 10000; + std::string str = ""; + testParser.set_count(COUNT); + + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test1 = cores->add_test(); + test1->set_number(NUMBER1); + test1->set_tv_nsec(TVNSEC1); + test1->set_name(NAME1); + test1->set_is_test(true); + test1->set_state(::Test_State(0)); + test1->set_alloc_event(ALLOCEVENT); + + testParser.set_allocated_cores(cores); + testParser.SerializeToString(&str); + + TestParser_Reader testParserReader(str); + EXPECT_EQ(COUNT, testParserReader.count()); + auto core = testParserReader.cores(); + CpuInfoTest_Reader cpuInfoTest(core.data_, core.size_); + auto itor = cpuInfoTest.test(); + Test_Reader cpuInfoReader1(itor->ToBytes()); + EXPECT_EQ(NUMBER1, cpuInfoReader1.number()); + EXPECT_EQ(TVNSEC1, cpuInfoReader1.tv_nsec()); + EXPECT_EQ(NAME1, cpuInfoReader1.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader1.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader1.state()); + EXPECT_EQ(ALLOCEVENT, cpuInfoReader1.alloc_event()); +} + +/** + * @tc.name: Parser One of Data For Free event By PBReader + * @tc.desc: ParserOneofData by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserOneofDataForFreeEventByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-6"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER1 = 100; + const uint64_t TVNSEC1 = 1000000; + const std::string NAME1 = "1000"; + const int32_t FREEEVENT = 10000; + std::string str = ""; + testParser.set_count(COUNT); + + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test1 = cores->add_test(); + test1->set_number(NUMBER1); + test1->set_tv_nsec(TVNSEC1); + test1->set_name(NAME1); + test1->set_is_test(true); + test1->set_state(::Test_State(0)); + test1->set_alloc_event(FREEEVENT); + + testParser.set_allocated_cores(cores); + testParser.SerializeToString(&str); + + TestParser_Reader testParserReader(str); + EXPECT_EQ(COUNT, testParserReader.count()); + auto core = testParserReader.cores(); + CpuInfoTest_Reader cpuInfoTest(core.data_, core.size_); + auto itor = cpuInfoTest.test(); + Test_Reader cpuInfoReader1(itor->ToBytes()); + EXPECT_EQ(NUMBER1, cpuInfoReader1.number()); + EXPECT_EQ(TVNSEC1, cpuInfoReader1.tv_nsec()); + EXPECT_EQ(NAME1, cpuInfoReader1.name().ToStdString()); + EXPECT_EQ(true, cpuInfoReader1.is_test()); + EXPECT_EQ(::Test_State(0), cpuInfoReader1.state()); + EXPECT_EQ(FREEEVENT, cpuInfoReader1.alloc_event()); +} + +/** + * @tc.name: ParserNoDataByVarInt + * @tc.desc: ParserNoData by VarInt + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserNoDataByVarInt, TestSize.Level1) +{ + TS_LOGI("test33-7"); + TestParser testParser; + + std::string str = ""; + testParser.SerializeToString(&str); + + auto kCountFieldNumber = TestParser_Reader::kCountDataAreaNumber; + uint64_t count = 0; + auto tsTag = CreateTagVarInt(kCountFieldNumber); + if (str.size() > 10 && str.data()[0] == tsTag) { + const uint8_t* nextData = VarIntDecode(reinterpret_cast(str.data() + 1), + reinterpret_cast(str.data() + 11), &count); + } + EXPECT_EQ(0, count); +} + +/** + * @tc.name: ParserDataByVarInt + * @tc.desc: ParserData by VarInt + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserDataByVarInt, TestSize.Level1) +{ + TS_LOGI("test33-8"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER = 100; + const uint64_t TVNSEC = 1000000; + const std::string NAME = "1000"; + const int32_t ALLOCEVENT = 10000; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test = cores->add_test(); + test->set_number(NUMBER); + test->set_tv_nsec(TVNSEC); + test->set_name(NAME); + test->set_is_test(true); + test->set_state(::Test_State(0)); + test->set_alloc_event(ALLOCEVENT); + testParser.set_allocated_cores(cores); + + std::string str = ""; + testParser.SerializeToString(&str); + + auto kCountFieldNumber = TestParser_Reader::kCountDataAreaNumber; + uint64_t count = 0; + auto tsTag = CreateTagVarInt(kCountFieldNumber); + if (str.size() > 10 && str.data()[0] == tsTag) { + const uint8_t* nextData = VarIntDecode(reinterpret_cast(str.data() + 1), + reinterpret_cast(str.data() + 11), &count); + } + EXPECT_EQ(COUNT, count); +} + +/** + * @tc.name: ParserDataByPBReaderBase + * @tc.desc: ParserData by pbreader Base + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserDataByPBReaderBase, TestSize.Level1) +{ + TS_LOGI("test33-9"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER = 100; + const uint64_t TVNSEC = 1000000; + const std::string NAME = "1000"; + const int32_t ALLOCEVENT = 10000; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test = cores->add_test(); + test->set_number(NUMBER); + test->set_tv_nsec(TVNSEC); + test->set_name(NAME); + test->set_is_test(true); + test->set_state(::Test_State(0)); + test->set_alloc_event(ALLOCEVENT); + testParser.set_allocated_cores(cores); + + std::string str = ""; + testParser.SerializeToString(&str); + + TypedProtoReader<2> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.FindDataArea(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto core = typedProtoTest.FindDataArea(TestParser_Reader::kCoresDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(core.data_), core.size_); + auto typtest = typedProtoCpuInfoTest.FindDataArea(CpuInfoTest_Reader::kTestDataAreaNumber).ToBytes(); + TypedProtoReader<7> typedProtoTestReader(reinterpret_cast(typtest.data_), typtest.size_); + auto number = typedProtoTestReader.FindDataArea(Test_Reader::kNumberDataAreaNumber).ToInt32(); + auto tvNsec = typedProtoTestReader.FindDataArea(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + auto name = typedProtoTestReader.FindDataArea(Test_Reader::kNameDataAreaNumber).ToStdString(); + auto isTest = typedProtoTestReader.FindDataArea(Test_Reader::kIsTestDataAreaNumber).ToBool(); + auto state = typedProtoTestReader.FindDataArea(Test_Reader::kStateDataAreaNumber).ToInt32(); + auto allocEvent = typedProtoTestReader.FindDataArea(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + + EXPECT_EQ(NUMBER, number); + EXPECT_EQ(TVNSEC, tvNsec); + EXPECT_EQ(NAME, name); + EXPECT_EQ(true, isTest); + EXPECT_EQ(::Test_State(0), state); + EXPECT_EQ(ALLOCEVENT, allocEvent); +} + +/** + * @tc.name: ParserMutiDataByPBReaderBase + * @tc.desc: ParserMutiData by pbreader Base + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserMutiDataByPBReaderBase, TestSize.Level1) +{ + TS_LOGI("test33-10"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER1 = 100; + const uint64_t TVNSEC1 = 1000000; + const std::string NAME1 = "1000"; + const int32_t ALLOCEVENT1 = 10000; + const int32_t NUMBER2 = 200; + const uint64_t TVNSEC2 = 2000000; + const std::string NAME2 = "2000"; + const int32_t ALLOCEVENT2 = 20000; + const int32_t NUMBER3 = 300; + const uint64_t TVNSEC3 = 3000000; + const std::string NAME3 = "3000"; + const int32_t ALLOCEVENT3 = 30000; + std::string str = ""; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test1 = cores->add_test(); + test1->set_number(NUMBER1); + test1->set_tv_nsec(TVNSEC1); + test1->set_name(NAME1); + test1->set_is_test(true); + test1->set_state(::Test_State(0)); + test1->set_alloc_event(ALLOCEVENT1); + + auto test2 = cores->add_test(); + test2->set_number(NUMBER2); + test2->set_tv_nsec(TVNSEC2); + test2->set_name(NAME2); + test2->set_is_test(false); + test2->set_state(::Test_State(1)); + test2->set_alloc_event(ALLOCEVENT2); + + auto test3 = cores->add_test(); + test3->set_number(NUMBER3); + test3->set_tv_nsec(TVNSEC3); + test3->set_name(NAME3); + test3->set_is_test(true); + test3->set_state(::Test_State(0)); + test3->set_alloc_event(ALLOCEVENT3); + + testParser.set_allocated_cores(cores); + testParser.SerializeToString(&str); + + TypedProtoReader<2> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.FindDataArea(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto core = typedProtoTest.FindDataArea(TestParser_Reader::kCoresDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(core.data_), core.size_); + auto repeate = typedProtoCpuInfoTest.GetRepeated(CpuInfoTest_Reader::kTestDataAreaNumber); + + TypedProtoReader<7> typedProtoTestReader1(repeate->ToBytes().data_, repeate->ToBytes().size_); + auto number1 = typedProtoTestReader1.FindDataArea(Test_Reader::kNumberDataAreaNumber).ToInt32(); + EXPECT_EQ(NUMBER1, number1); + auto tvNsec1 = typedProtoTestReader1.FindDataArea(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + EXPECT_EQ(TVNSEC1, tvNsec1); + auto name1 = typedProtoTestReader1.FindDataArea(Test_Reader::kNameDataAreaNumber).ToStdString(); + EXPECT_EQ(NAME1, name1); + auto isTest1 = typedProtoTestReader1.FindDataArea(Test_Reader::kIsTestDataAreaNumber).ToBool(); + EXPECT_EQ(true, isTest1); + auto state1 = typedProtoTestReader1.FindDataArea(Test_Reader::kStateDataAreaNumber).ToInt32(); + EXPECT_EQ(::Test_State(0), state1); + auto allocEvent1 = typedProtoTestReader1.FindDataArea(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + EXPECT_EQ(ALLOCEVENT1, allocEvent1); + + repeate++; + TypedProtoReader<7> typedProtoTestReader2(repeate->ToBytes().data_, repeate->ToBytes().size_); + auto number2 = typedProtoTestReader2.FindDataArea(Test_Reader::kNumberDataAreaNumber).ToInt32(); + EXPECT_EQ(NUMBER2, number2); + auto tvNsec2 = typedProtoTestReader2.FindDataArea(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + EXPECT_EQ(TVNSEC2, tvNsec2); + auto name2 = typedProtoTestReader2.FindDataArea(Test_Reader::kNameDataAreaNumber).ToStdString(); + EXPECT_EQ(NAME2, name2); + auto isTest2 = typedProtoTestReader2.FindDataArea(Test_Reader::kIsTestDataAreaNumber).ToBool(); + EXPECT_EQ(false, isTest2); + auto state2 = typedProtoTestReader2.FindDataArea(Test_Reader::kStateDataAreaNumber).ToInt32(); + EXPECT_EQ(::Test_State(1), state2); + auto allocEvent2 = typedProtoTestReader2.FindDataArea(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + EXPECT_EQ(ALLOCEVENT2, allocEvent2); + + repeate++; + TypedProtoReader<7> typedProtoTestReader3(repeate->ToBytes().data_, repeate->ToBytes().size_); + auto number3 = typedProtoTestReader3.FindDataArea(Test_Reader::kNumberDataAreaNumber).ToInt32(); + EXPECT_EQ(NUMBER3, number3); + auto tvNsec3 = typedProtoTestReader3.FindDataArea(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + EXPECT_EQ(TVNSEC3, tvNsec3); + auto name3 = typedProtoTestReader3.FindDataArea(Test_Reader::kNameDataAreaNumber).ToStdString(); + EXPECT_EQ(NAME3, name3); + auto isTest3 = typedProtoTestReader3.FindDataArea(Test_Reader::kIsTestDataAreaNumber).ToBool(); + EXPECT_EQ(true, isTest3); + auto state3 = typedProtoTestReader3.FindDataArea(Test_Reader::kStateDataAreaNumber).ToInt32(); + EXPECT_EQ(::Test_State(0), state3); + auto allocEvent3 = typedProtoTestReader3.FindDataArea(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + EXPECT_EQ(ALLOCEVENT3, allocEvent3); +} + +/** + * @tc.name: ParserNoDataByPBReaderBase + * @tc.desc: ParserNoData by pbreader Base + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserNoDataByPBReaderBase, TestSize.Level1) +{ + TS_LOGI("test33-11"); + TestParser testParser; + + std::string str = ""; + testParser.SerializeToString(&str); + + TypedProtoReader<2> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.FindDataArea(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(0, count); + auto core = typedProtoTest.FindDataArea(TestParser_Reader::kCoresDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(core.data_), core.size_); + auto typtest = typedProtoCpuInfoTest.FindDataArea(CpuInfoTest_Reader::kTestDataAreaNumber).ToBytes(); + TypedProtoReader<7> typedProtoTestReader(reinterpret_cast(typtest.data_), typtest.size_); + auto number = typedProtoTestReader.FindDataArea(Test_Reader::kNumberDataAreaNumber).ToInt32(); + auto tvNsec = typedProtoTestReader.FindDataArea(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + auto name = typedProtoTestReader.FindDataArea(Test_Reader::kNameDataAreaNumber).ToStdString(); + auto isTest = typedProtoTestReader.FindDataArea(Test_Reader::kIsTestDataAreaNumber).ToBool(); + auto state = typedProtoTestReader.FindDataArea(Test_Reader::kStateDataAreaNumber).ToInt32(); + auto allocEvent = typedProtoTestReader.FindDataArea(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + + EXPECT_EQ(0, number); + EXPECT_EQ(0, tvNsec); + EXPECT_EQ("", name); + EXPECT_EQ(false, isTest); + EXPECT_EQ(::Test_State(0), state); + EXPECT_EQ(0, allocEvent); +} + +/** + * @tc.name: ParserDataByGet + * @tc.desc: ParserData by Get + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserDataByGet, TestSize.Level1) +{ + TS_LOGI("test33-12"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER = 100; + const uint64_t TVNSEC = 1000000; + const std::string NAME = "1000"; + const int32_t ALLOCEVENT = 10000; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test = cores->add_test(); + test->set_number(NUMBER); + test->set_tv_nsec(TVNSEC); + test->set_name(NAME); + test->set_is_test(true); + test->set_state(::Test_State(0)); + test->set_alloc_event(ALLOCEVENT); + testParser.set_allocated_cores(cores); + + std::string str = ""; + testParser.SerializeToString(&str); + + TypedProtoReader<2> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto core = typedProtoTest.Get(TestParser_Reader::kCoresDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(core.data_), core.size_); + auto typtest = typedProtoCpuInfoTest.Get(CpuInfoTest_Reader::kTestDataAreaNumber).ToBytes(); + TypedProtoReader<7> typedProtoTestReader(reinterpret_cast(typtest.data_), typtest.size_); + auto number = typedProtoTestReader.Get(Test_Reader::kNumberDataAreaNumber).ToInt32(); + auto tvNsec = typedProtoTestReader.Get(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + auto name = typedProtoTestReader.Get(Test_Reader::kNameDataAreaNumber).ToStdString(); + auto isTest = typedProtoTestReader.Get(Test_Reader::kIsTestDataAreaNumber).ToBool(); + auto state = typedProtoTestReader.Get(Test_Reader::kStateDataAreaNumber).ToInt32(); + auto allocEvent = typedProtoTestReader.Get(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + + EXPECT_EQ(NUMBER, number); + EXPECT_EQ(TVNSEC, tvNsec); + EXPECT_EQ(NAME, name); + EXPECT_EQ(true, isTest); + EXPECT_EQ(::Test_State(0), state); + EXPECT_EQ(ALLOCEVENT, allocEvent); +} + +/** + * @tc.name: ParserMutiDataByGet + * @tc.desc: ParserMutiData by Get + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserMutiDataByGet, TestSize.Level1) +{ + TS_LOGI("test33-13"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER1 = 100; + const uint64_t TVNSEC1 = 1000000; + const std::string NAME1 = "1000"; + const int32_t ALLOCEVENT1 = 10000; + const int32_t NUMBER2 = 200; + const uint64_t TVNSEC2 = 2000000; + const std::string NAME2 = "2000"; + const int32_t ALLOCEVENT2 = 20000; + const int32_t NUMBER3 = 300; + const uint64_t TVNSEC3 = 3000000; + const std::string NAME3 = "3000"; + const int32_t ALLOCEVENT3 = 30000; + std::string str = ""; + testParser.set_count(COUNT); + ::CpuInfoTest* cores = new ::CpuInfoTest(); + auto test1 = cores->add_test(); + test1->set_number(NUMBER1); + test1->set_tv_nsec(TVNSEC1); + test1->set_name(NAME1); + test1->set_is_test(true); + test1->set_state(::Test_State(0)); + test1->set_alloc_event(ALLOCEVENT1); + + auto test2 = cores->add_test(); + test2->set_number(NUMBER2); + test2->set_tv_nsec(TVNSEC2); + test2->set_name(NAME2); + test2->set_is_test(false); + test2->set_state(::Test_State(1)); + test2->set_alloc_event(ALLOCEVENT2); + + auto test3 = cores->add_test(); + test3->set_number(NUMBER3); + test3->set_tv_nsec(TVNSEC3); + test3->set_name(NAME3); + test3->set_is_test(true); + test3->set_state(::Test_State(0)); + test3->set_alloc_event(ALLOCEVENT3); + + testParser.set_allocated_cores(cores); + testParser.SerializeToString(&str); + + TypedProtoReader<2> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto core = typedProtoTest.Get(TestParser_Reader::kCoresDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(core.data_), core.size_); + auto repeate = typedProtoCpuInfoTest.GetRepeated(CpuInfoTest_Reader::kTestDataAreaNumber); + + TypedProtoReader<7> typedProtoTestReader1(repeate->ToBytes().data_, repeate->ToBytes().size_); + auto number1 = typedProtoTestReader1.Get(Test_Reader::kNumberDataAreaNumber).ToInt32(); + EXPECT_EQ(NUMBER1, number1); + auto tvNsec1 = typedProtoTestReader1.Get(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + EXPECT_EQ(TVNSEC1, tvNsec1); + auto name1 = typedProtoTestReader1.Get(Test_Reader::kNameDataAreaNumber).ToStdString(); + EXPECT_EQ(NAME1, name1); + auto isTest1 = typedProtoTestReader1.Get(Test_Reader::kIsTestDataAreaNumber).ToBool(); + EXPECT_EQ(true, isTest1); + auto state1 = typedProtoTestReader1.Get(Test_Reader::kStateDataAreaNumber).ToInt32(); + EXPECT_EQ(::Test_State(0), state1); + auto allocEvent1 = typedProtoTestReader1.Get(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + EXPECT_EQ(ALLOCEVENT1, allocEvent1); + + repeate++; + TypedProtoReader<7> typedProtoTestReader2(repeate->ToBytes().data_, repeate->ToBytes().size_); + auto number2 = typedProtoTestReader2.Get(Test_Reader::kNumberDataAreaNumber).ToInt32(); + EXPECT_EQ(NUMBER2, number2); + auto tvNsec2 = typedProtoTestReader2.Get(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + EXPECT_EQ(TVNSEC2, tvNsec2); + auto name2 = typedProtoTestReader2.Get(Test_Reader::kNameDataAreaNumber).ToStdString(); + EXPECT_EQ(NAME2, name2); + auto isTest2 = typedProtoTestReader2.Get(Test_Reader::kIsTestDataAreaNumber).ToBool(); + EXPECT_EQ(false, isTest2); + auto state2 = typedProtoTestReader2.Get(Test_Reader::kStateDataAreaNumber).ToInt32(); + EXPECT_EQ(::Test_State(1), state2); + auto allocEvent2 = typedProtoTestReader2.Get(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + EXPECT_EQ(ALLOCEVENT2, allocEvent2); + + repeate++; + TypedProtoReader<7> typedProtoTestReader3(repeate->ToBytes().data_, repeate->ToBytes().size_); + auto number3 = typedProtoTestReader3.Get(Test_Reader::kNumberDataAreaNumber).ToInt32(); + EXPECT_EQ(NUMBER3, number3); + auto tvNsec3 = typedProtoTestReader3.Get(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + EXPECT_EQ(TVNSEC3, tvNsec3); + auto name3 = typedProtoTestReader3.Get(Test_Reader::kNameDataAreaNumber).ToStdString(); + EXPECT_EQ(NAME3, name3); + auto isTest3 = typedProtoTestReader3.Get(Test_Reader::kIsTestDataAreaNumber).ToBool(); + EXPECT_EQ(true, isTest3); + auto state3 = typedProtoTestReader3.Get(Test_Reader::kStateDataAreaNumber).ToInt32(); + EXPECT_EQ(::Test_State(0), state3); + auto allocEvent3 = typedProtoTestReader3.Get(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + EXPECT_EQ(ALLOCEVENT3, allocEvent3); +} + +/** + * @tc.name: ParserNoDataByGet + * @tc.desc: ParserNoData by Get + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserNoDataByGet, TestSize.Level1) +{ + TS_LOGI("test33-14"); + TestParser testParser; + + std::string str = ""; + testParser.SerializeToString(&str); + + TypedProtoReader<2> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(0, count); + auto core = typedProtoTest.Get(TestParser_Reader::kCoresDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(core.data_), core.size_); + auto typtest = typedProtoCpuInfoTest.Get(CpuInfoTest_Reader::kTestDataAreaNumber).ToBytes(); + TypedProtoReader<7> typedProtoTestReader(reinterpret_cast(typtest.data_), typtest.size_); + auto number = typedProtoTestReader.Get(Test_Reader::kNumberDataAreaNumber).ToInt32(); + auto tvNsec = typedProtoTestReader.Get(Test_Reader::kTvNsecDataAreaNumber).ToUint64(); + auto name = typedProtoTestReader.Get(Test_Reader::kNameDataAreaNumber).ToStdString(); + auto isTest = typedProtoTestReader.Get(Test_Reader::kIsTestDataAreaNumber).ToBool(); + auto state = typedProtoTestReader.Get(Test_Reader::kStateDataAreaNumber).ToInt32(); + auto allocEvent = typedProtoTestReader.Get(Test_Reader::kAllocEventDataAreaNumber).ToInt32(); + + EXPECT_EQ(0, number); + EXPECT_EQ(0, tvNsec); + EXPECT_EQ("", name); + EXPECT_EQ(false, isTest); + EXPECT_EQ(::Test_State(0), state); + EXPECT_EQ(0, allocEvent); +} + +/** + * @tc.name: ParserPackedRepeatedInt32DataByPBReader + * @tc.desc: ParserPackedRepeatedInt32Data by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserPackedRepeatedInt32DataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-15"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER = 1000; + const int32_t NUMBER1 = 1001; + const int32_t NUMBER2 = 1002; + const int32_t NUMBER3 = 1003; + std::string str = ""; + testParser.set_count(COUNT); + ::NumberTest* numberTest = new ::NumberTest(); + numberTest->add_numbertext(NUMBER); + numberTest->add_numbertext(NUMBER1); + numberTest->add_numbertext(NUMBER2); + numberTest->add_numbertext(NUMBER3); + + testParser.set_allocated_numbertest(numberTest); + testParser.SerializeToString(&str); + bool parserError = true; + + TypedProtoReader<3> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto numberType = typedProtoTest.Get(TestParser_Reader::kNumberTestDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(numberType.data_), numberType.size_); + auto packedRepeate = typedProtoCpuInfoTest.GetPackedRepeated( + NumberTest_Reader::kNumberTextDataAreaNumber, &parserError); + auto numberValue = *packedRepeate; + EXPECT_EQ(NUMBER, numberValue); + packedRepeate++; + auto numberValue1 = *packedRepeate; + EXPECT_EQ(NUMBER1, numberValue1); + packedRepeate++; + auto numberValue2 = *packedRepeate; + EXPECT_EQ(NUMBER2, numberValue2); + packedRepeate++; + auto numberValue3 = *packedRepeate; + EXPECT_EQ(NUMBER3, numberValue3); +} + +/** + * @tc.name: ParserPackedRepeatedFixed64DataByPBReader + * @tc.desc: ParserPackedRepeatedFixed64Data by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserPackedRepeatedFixed64DataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-16"); + TestParser testParser; + const int32_t COUNT = 100; + const double NUMBER = 1000.01; + const double NUMBER1 = 1001.01; + const double NUMBER2 = 1002.01; + const double NUMBER3 = 1003.01; + std::string str = ""; + testParser.set_count(COUNT); + ::Fixed64Test* fixed64Test = new ::Fixed64Test(); + fixed64Test->add_fixed64numbertext(NUMBER); + fixed64Test->add_fixed64numbertext(NUMBER1); + fixed64Test->add_fixed64numbertext(NUMBER2); + fixed64Test->add_fixed64numbertext(NUMBER3); + + testParser.set_allocated_fixed64test(fixed64Test); + testParser.SerializeToString(&str); + bool parserError = true; + + TypedProtoReader<5> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto fix64Type = typedProtoTest.Get(TestParser_Reader::kFixed64TestDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(fix64Type.data_), fix64Type.size_); + auto packedRepeate = typedProtoCpuInfoTest.GetPackedRepeated( + Fixed64Test_Reader::kFixed64NumberTextDataAreaNumber, &parserError); + auto numberValue = *packedRepeate; + EXPECT_EQ(NUMBER, numberValue); + packedRepeate++; + auto numberValue1 = *packedRepeate; + EXPECT_EQ(NUMBER1, numberValue1); + packedRepeate++; + auto numberValue2 = *packedRepeate; + EXPECT_EQ(NUMBER2, numberValue2); + packedRepeate++; + auto numberValue3 = *packedRepeate; + EXPECT_EQ(NUMBER3, numberValue3); +} + +/** + * @tc.name: ParserPackedRepeatedFixed32DataByPBReader + * @tc.desc: ParserPackedRepeatedFixed32Data by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserPackedRepeatedFixed32DataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-17"); + TestParser testParser; + const int32_t COUNT = 100; + const float NUMBER = 1000.01; + const float NUMBER1 = 1001.01; + const float NUMBER2 = 1002.01; + const float NUMBER3 = 1003.01; + std::string str = ""; + testParser.set_count(COUNT); + ::Fixed32Test* fixed32Test = new ::Fixed32Test(); + fixed32Test->add_fixed32numbertext(NUMBER); + fixed32Test->add_fixed32numbertext(NUMBER1); + fixed32Test->add_fixed32numbertext(NUMBER2); + fixed32Test->add_fixed32numbertext(NUMBER3); + + testParser.set_allocated_fixed32test(fixed32Test); + testParser.SerializeToString(&str); + bool parserError = true; + + TypedProtoReader<5> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto fix32Type = typedProtoTest.Get(TestParser_Reader::kFixed32TestDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(fix32Type.data_), fix32Type.size_); + auto packedRepeate = typedProtoCpuInfoTest.GetPackedRepeated( + Fixed32Test_Reader::kFixed32NumberTextDataAreaNumber, &parserError); + auto numberValue = *packedRepeate; + EXPECT_EQ(NUMBER, numberValue); + packedRepeate++; + auto numberValue1 = *packedRepeate; + EXPECT_EQ(NUMBER1, numberValue1); + packedRepeate++; + auto numberValue2 = *packedRepeate; + EXPECT_EQ(NUMBER2, numberValue2); + packedRepeate++; + auto numberValue3 = *packedRepeate; + EXPECT_EQ(NUMBER3, numberValue3); +} + +/** + * @tc.name: ParserPackedRepeatedInt32OneDataByPBReader + * @tc.desc: ParserPackedRepeatedInt32 with one set of Data by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserPackedRepeatedInt32OneDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-18"); + TestParser testParser; + const int32_t COUNT = 100; + const int32_t NUMBER = 1000; + std::string str = ""; + testParser.set_count(COUNT); + ::NumberTest* numberTest = new ::NumberTest(); + numberTest->add_numbertext(NUMBER); + + testParser.set_allocated_numbertest(numberTest); + testParser.SerializeToString(&str); + bool parserError = true; + + TypedProtoReader<3> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto numberType = typedProtoTest.Get(TestParser_Reader::kNumberTestDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(numberType.data_), numberType.size_); + auto packedRepeate = typedProtoCpuInfoTest.GetPackedRepeated( + NumberTest_Reader::kNumberTextDataAreaNumber, &parserError); + auto numberValue = *packedRepeate; + EXPECT_EQ(NUMBER, numberValue); +} + +/** + * @tc.name: ParserPackedRepeatedFixed64OneDataByPBReader + * @tc.desc: ParserPackedRepeatedFixed64 with one set of Data by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserPackedRepeatedFixed64OneDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-19"); + TestParser testParser; + const int32_t COUNT = 100; + const double NUMBER = 1000.01; + std::string str = ""; + testParser.set_count(COUNT); + ::Fixed64Test* fixed64Test = new ::Fixed64Test(); + fixed64Test->add_fixed64numbertext(NUMBER); + testParser.set_allocated_fixed64test(fixed64Test); + testParser.SerializeToString(&str); + bool parserError = true; + + TypedProtoReader<5> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto fix64Type = typedProtoTest.Get(TestParser_Reader::kFixed64TestDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(fix64Type.data_), fix64Type.size_); + auto packedRepeate = typedProtoCpuInfoTest.GetPackedRepeated( + Fixed64Test_Reader::kFixed64NumberTextDataAreaNumber, &parserError); + auto numberValue = *packedRepeate; + EXPECT_EQ(NUMBER, numberValue); +} + +/** + * @tc.name: ParserPackedRepeatedFixed32OneDataByPBReader + * @tc.desc: ParserPackedRepeatedFixed32 with one set of Data by pbreader + * @tc.type: FUNC + */ +HWTEST_F(ProtoReaderTest, ParserPackedRepeatedFixed32OneDataByPBReader, TestSize.Level1) +{ + TS_LOGI("test33-20"); + TestParser testParser; + const int32_t COUNT = 100; + const float NUMBER = 1000.01; + std::string str = ""; + testParser.set_count(COUNT); + ::Fixed32Test* fixed32Test = new ::Fixed32Test(); + fixed32Test->add_fixed32numbertext(NUMBER); + testParser.set_allocated_fixed32test(fixed32Test); + testParser.SerializeToString(&str); + bool parserError = true; + + TypedProtoReader<5> typedProtoTest(reinterpret_cast(str.data()), str.size()); + auto count = typedProtoTest.Get(TestParser_Reader::kCountDataAreaNumber).ToInt32(); + EXPECT_EQ(COUNT, count); + auto fix32Type = typedProtoTest.Get(TestParser_Reader::kFixed32TestDataAreaNumber).ToBytes(); + TypedProtoReader<1> typedProtoCpuInfoTest(reinterpret_cast(fix32Type.data_), fix32Type.size_); + auto packedRepeate = typedProtoCpuInfoTest.GetPackedRepeated( + Fixed32Test_Reader::kFixed32NumberTextDataAreaNumber, &parserError); + auto numberValue = *packedRepeate; + EXPECT_EQ(NUMBER, numberValue); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/rpc_server_test.cpp b/trace_streamer/test/unittest/rpc_server_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eeb03f891f35353302f1ee351f8de3dda7ec1b7e --- /dev/null +++ b/trace_streamer/test/unittest/rpc_server_test.cpp @@ -0,0 +1,88 @@ +/* + * 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 +#include + +#include "rpc/rpc_server.h" + +using namespace testing::ext; +namespace SysTuning { +namespace TraceStreamer { +class RpcServerTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; +}; +std::string g_result; +void res(const std::string result, int32_t finish) +{ + TS_LOGI("%s", result.c_str()); + g_result = result; +} + +/** + * @tc.name: CorrectTraceData + * @tc.desc: Upload correct trace file data + * @tc.type: FUNC + */ +HWTEST_F(RpcServerTest, CorrectTraceData, TestSize.Level1) +{ + TS_LOGI("test27-1"); + std::string PARSERDATA("sugov:0-178 ( 178) [001] .... 28462.257501: cpu_frequency: state=816000 cpu_id=0 \n"); + std::string SQLQUERY("select * from measure;"); + + RpcServer rpcServer; + auto ret = rpcServer.ParseData((const uint8_t*)PARSERDATA.c_str(), PARSERDATA.length(), res); + EXPECT_TRUE(res); + EXPECT_TRUE(ret); + ret = rpcServer.ParseDataOver((const uint8_t*)PARSERDATA.c_str(), PARSERDATA.length(), res); + EXPECT_TRUE(res); + EXPECT_TRUE(ret); + ret = rpcServer.SqlQuery((const uint8_t*)SQLQUERY.c_str(), SQLQUERY.length(), res); + EXPECT_TRUE(res); + EXPECT_TRUE(ret); +} + +/** + * @tc.name: WrongTraceData + * @tc.desc: Upload wrong tracking file data + * @tc.type: FUNC + */ +HWTEST_F(RpcServerTest, WrongTraceData, TestSize.Level1) +{ + TS_LOGI("test27-2"); + std::string PARSERDATA("sugov:0-178 ( 178) [001] .... 28462.277458: cpu_frequency: state=600000 cpu_id=2 \n"); + std::string SQLQUERY("select * from measure_e;"); + + RpcServer rpcServer; + auto ret = rpcServer.ParseData((const uint8_t*)PARSERDATA.c_str(), PARSERDATA.length(), res); + EXPECT_TRUE(res); + EXPECT_TRUE(ret); + ret = rpcServer.ParseDataOver((const uint8_t*)PARSERDATA.c_str(), PARSERDATA.length(), res); + EXPECT_TRUE(res); + EXPECT_TRUE(ret); + ret = rpcServer.SqlQuery((const uint8_t*)SQLQUERY.c_str(), SQLQUERY.length(), res); + EXPECT_TRUE(g_result == "dberror\r\n"); + EXPECT_FALSE(ret); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/slice_filter_test.cpp b/trace_streamer/test/unittest/slice_filter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de37e3e365d8b1f112c1181f4305e9a48465180a --- /dev/null +++ b/trace_streamer/test/unittest/slice_filter_test.cpp @@ -0,0 +1,414 @@ +/* + * 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 +#include + +#include "filter_filter.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class SliceFilterTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() {} + +public: + TraceStreamerSelector stream_; +}; + +/** + * @tc.name: SliceTestOnceCall + * @tc.desc: Parse once method call stack + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, SliceTestOnceCall, TestSize.Level1) +{ + TS_LOGI("test28-1"); + uint64_t ts = 168758662957000; + uint64_t ts2 = 168758663011000; + + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("call_function_one"); + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts, pid1, threadGroupId1, cat, splitStrIndex); + stream_.streamFilters_->sliceFilter_->EndSlice(ts2, pid1, threadGroupId1); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 1); + EXPECT_TRUE(slices->DursData()[0] == ts2 - ts); +} + +/** + * @tc.name: SliceTestNestedTwoMethod + * @tc.desc: Parse Nested call stack of two methods + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, SliceTestNestedTwoMethod, TestSize.Level1) +{ + TS_LOGI("test28-2"); + uint64_t ts1 = 168758670506000; + uint32_t pid1 = 1298; + uint32_t threadGroupId1 = 1298; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("call_function_one"); + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts1, pid1, threadGroupId1, cat, splitStrIndex); + splitStrIndex = stream_.traceDataCache_->GetDataIndex("call_function_two"); + uint64_t ts2 = 168758670523000; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts2, pid1, threadGroupId1, cat, splitStrIndex); + uint64_t ts3 = 168758670720000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts3, pid1, threadGroupId1); + uint64_t ts4 = 168758670732000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts4, pid1, threadGroupId1); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 2); + EXPECT_TRUE(slices->DursData()[0] == ts4 - ts1); + EXPECT_TRUE(slices->DursData()[1] == ts3 - ts2); + EXPECT_TRUE(slices->Depths()[1] == 1); +} + +/** + * @tc.name: SliceTestNestedTwoMethodStackAndOneMethodStack + * @tc.desc: Parse Nested call stack of two methods and one method call stack + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, SliceTestNestedTwoMethodStackAndOneMethodStack, TestSize.Level1) +{ + TS_LOGI("test28-3"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_one"); + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts1, pid1, threadGroupId1, cat, splitStrIndex); // slice 0 + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_one"); + uint64_t ts2 = 168758663028000; + uint32_t pid2 = 2533; + uint32_t threadGroupId2 = 2529; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts2, pid2, threadGroupId2, cat, splitStrIndex); + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_two"); + uint64_t ts3 = 168758679303000; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts3, pid1, threadGroupId1, cat, splitStrIndex); // slice 2 + // end thread_one_call_function_two + uint64_t ts4 = 168758682466000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts4, pid1, threadGroupId1); + // end thread_one_call_function_one + uint64_t ts5 = 168758682476000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts5, pid1, threadGroupId1); + // end thread_two_call_function_one slice 1 + uint64_t ts6 = 168758689323000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts6, pid2, threadGroupId2); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 3); + EXPECT_TRUE(slices->DursData()[0] == ts5 - ts1); // slice 0 + EXPECT_TRUE(slices->Depths()[0] == 0); + EXPECT_TRUE(slices->DursData()[1] == ts6 - ts2); // slice 1 + EXPECT_TRUE(slices->Depths()[1] == 0); + EXPECT_TRUE(slices->DursData()[2] == ts4 - ts3); // slice 2 + EXPECT_TRUE(slices->Depths()[2] == 1); +} + +/** + * @tc.name: SliceTestWithoutBeginSlice + * @tc.desc: Test EndSlice without BeginSlice + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, SliceTestWithoutBeginSlice, TestSize.Level1) +{ + TS_LOGI("test28-4"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + stream_.streamFilters_->sliceFilter_->EndSlice(ts1, pid1, threadGroupId1); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 0); +} + +/** + * @tc.name: SliceTestWithMultiNestedCall + * @tc.desc: Parse multi nested call stack + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, SliceTestWithMultiNestedCall, TestSize.Level1) +{ + TS_LOGI("test28-5"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_one"); + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts1, pid1, threadGroupId1, cat, splitStrIndex); // slice 0 + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_one"); + uint64_t ts2 = 168758663028000; + uint32_t pid2 = 2533; + uint32_t threadGroupId2 = 2529; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts2, pid2, threadGroupId2, cat, splitStrIndex); + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_two"); + uint64_t ts3 = 168758679303000; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts3, pid1, threadGroupId1, cat, splitStrIndex); // slice 2 + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_two"); + uint64_t ts4 = 168758679312000; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts4, pid2, threadGroupId2, cat, splitStrIndex); + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_three"); + uint64_t ts5 = 168758679313000; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts5, pid1, threadGroupId1, cat, splitStrIndex); // slice 4 + splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_three"); + uint64_t ts6 = 168758679323000; + stream_.streamFilters_->sliceFilter_->BeginSlice("comm", ts6, pid2, threadGroupId2, cat, splitStrIndex); + // end thread_one_call_function_three + uint64_t ts7 = 168758682456000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts7, pid1, threadGroupId1); + // end thread_one_call_function_two + uint64_t ts8 = 168758682466000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts8, pid1, threadGroupId1); + // end thread_one_call_function_one + uint64_t ts9 = 168758682476000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts9, pid1, threadGroupId1); + // end thread_two_call_function_three slice 5 + uint64_t ts10 = 168758679343000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts10, pid2, threadGroupId2); + // end thread_two_call_function_two slice 3 + uint64_t ts11 = 168758679344000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts11, pid2, threadGroupId2); + // end thread_two_call_function_one slice 1 + uint64_t ts12 = 168758689323000; + stream_.streamFilters_->sliceFilter_->EndSlice(ts12, pid2, threadGroupId2); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 6); + EXPECT_TRUE(slices->DursData()[0] == ts9 - ts1); // slice 0 + EXPECT_TRUE(slices->Depths()[0] == 0); + EXPECT_TRUE(slices->DursData()[1] == ts12 - ts2); // slice 1 + EXPECT_TRUE(slices->Depths()[1] == 0); + EXPECT_TRUE(slices->DursData()[2] == ts8 - ts3); // slice 2 + EXPECT_TRUE(slices->Depths()[2] == 1); + EXPECT_TRUE(slices->DursData()[3] == ts11 - ts4); // slice 3 + EXPECT_TRUE(slices->Depths()[3] == 1); + EXPECT_TRUE(slices->DursData()[4] == ts7 - ts5); // slice 4 + EXPECT_TRUE(slices->DursData()[5] == ts10 - ts6); // slice 5 +} + +/** + * @tc.name: AsyncTest + * @tc.desc: Test once asynchronous method call stack + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, AsyncTest, TestSize.Level1) +{ + TS_LOGI("test28-6"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("async_call_function_one"); + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts1, pid1, threadGroupId1, cat, splitStrIndex); // slice 0 + splitStrIndex = stream_.traceDataCache_->GetDataIndex("async_call_function_one"); + // end thread_one_call_function_three + uint64_t ts2 = 168758682456000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts2, pid1, threadGroupId1, cat, splitStrIndex); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 1); + EXPECT_TRUE(slices->DursData()[0] == ts2 - ts1); // slice 0 +} + +/** + * @tc.name: FinishAsyncSliceWithoutStart + * @tc.desc: Finish async slice without start + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, FinishAsyncSliceWithoutStart, TestSize.Level1) +{ + TS_LOGI("test28-7"); + uint64_t ts = 100; + uint32_t pid = 2532; + uint32_t threadGroupId = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("async_call_function_one"); + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts, pid, threadGroupId, cat, splitStrIndex); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 0); +} + +/** + * @tc.name: AsyncTestTwiceCallStack + * @tc.desc: Test Twice asynchronous call stack + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, AsyncTestTwiceCallStack, TestSize.Level1) +{ + TS_LOGI("test28-8"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_one"); + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts1, pid1, threadGroupId1, cat, splitStrIndex); // slice 0 + DataIndex splitStrIndex2 = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_one"); + uint64_t ts2 = 168758663028000; + uint32_t pid2 = 2533; + uint32_t threadGroupId2 = 2529; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts2, pid2, threadGroupId2, cat, splitStrIndex2); + // end thread_one_call_function_three + uint64_t ts3 = 168758682456000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts3, pid1, threadGroupId1, cat, splitStrIndex); + // end thread_two_call_function_three slice 5 + uint64_t ts4 = 168758679343000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts4, pid2, threadGroupId2, cat, splitStrIndex2); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 2); + EXPECT_TRUE(slices->DursData()[0] == ts3 - ts1); // slice 0 + EXPECT_TRUE(slices->Depths()[0] == 0); + EXPECT_TRUE(slices->DursData()[1] == ts4 - ts2); // slice 1 +} + +/** + * @tc.name: BeginAsyncSliceThreeTimes + * @tc.desc: Test asynchronous call three times + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, BeginAsyncSliceThreeTimes, TestSize.Level1) +{ + TS_LOGI("test28-9"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_one"); + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts1, pid1, threadGroupId1, cat, splitStrIndex); // slice 0 + DataIndex splitStrIndex2 = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_one"); + uint64_t ts2 = 168758663028000; + uint32_t pid2 = 2533; + uint32_t threadGroupId2 = 2529; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts2, pid2, threadGroupId2, cat, splitStrIndex2); + DataIndex splitStrIndex3 = stream_.traceDataCache_->GetDataIndex("thread_three_call_function_two"); + DataIndex cat2 = stream_.traceDataCache_->GetDataIndex("Catalog2"); + uint64_t ts3 = 168758679303000; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts3, pid1, threadGroupId1, cat2, splitStrIndex3); // slice 2 + // end thread_one_call_function_three + uint64_t ts4 = 168758682456000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts4, pid1, threadGroupId1, cat, splitStrIndex); + // end thread_one_call_function_two + uint64_t ts5 = 168758682466000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts5, pid1, threadGroupId1, cat2, splitStrIndex3); + // end thread_two_call_function_three slice 5 + uint64_t ts6 = 168758679343000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts6, pid2, threadGroupId2, cat, splitStrIndex2); + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 3); + EXPECT_TRUE(slices->DursData()[0] == ts4 - ts1); // slice 0 + EXPECT_TRUE(slices->Depths()[0] == 0); + EXPECT_TRUE(slices->DursData()[1] == ts6 - ts2); // slice 1 + EXPECT_TRUE(slices->Depths()[1] == 0); + EXPECT_TRUE(slices->DursData()[2] == ts5 - ts3); // slice 2 +} + +/** + * @tc.name: BeginSliceMultiTimes + * @tc.desc: Test asynchronous call muti times + * @tc.type: FUNC + */ +HWTEST_F(SliceFilterTest, BeginSliceMultiTimes, TestSize.Level1) +{ + TS_LOGI("test28-10"); + uint64_t ts1 = 168758663018000; + uint32_t pid1 = 2532; + uint32_t threadGroupId1 = 2519; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("Catalog"); + DataIndex splitStrIndex = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_one"); + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts1, pid1, threadGroupId1, cat, splitStrIndex); // slice 0 + + DataIndex splitStrIndex2 = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_one"); + uint64_t ts2 = 168758663028000; + uint32_t pid2 = 2533; + uint32_t threadGroupId2 = 2529; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts2, pid2, threadGroupId2, cat, splitStrIndex2); // slice 1 + + DataIndex splitStrIndex3 = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_two"); + DataIndex cat2 = stream_.traceDataCache_->GetDataIndex("Catalog2"); + uint64_t ts3 = 168758679303000; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts3, pid1, threadGroupId1, cat2, splitStrIndex3); // slice 2 + + DataIndex splitStrIndex4 = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_two"); + uint64_t ts4 = 168758679312000; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts4, pid2, threadGroupId2, cat2, splitStrIndex4); // slice 3 + + DataIndex splitStrIndex5 = stream_.traceDataCache_->GetDataIndex("thread_one_call_function_three"); + uint64_t ts5 = 168758679313000; + DataIndex cat3 = stream_.traceDataCache_->GetDataIndex("Catalog3"); + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts5, pid1, threadGroupId1, cat3, splitStrIndex5); // slice 4 + + DataIndex splitStrIndex6 = stream_.traceDataCache_->GetDataIndex("thread_two_call_function_three"); + uint64_t ts6 = 168758679323000; + stream_.streamFilters_->sliceFilter_->StartAsyncSlice(ts6, pid2, threadGroupId2, cat3, splitStrIndex6); // slice 5 + + // end thread_one_call_function_three + uint64_t ts7 = 168758682456000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts7, pid1, threadGroupId1, cat, + splitStrIndex); // end slice 0 + + // end thread_one_call_function_two + uint64_t ts8 = 168758682466000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts8, pid2, threadGroupId2, cat, + splitStrIndex2); // end slice 1 + + // end thread_one_call_function_one + uint64_t ts9 = 168758682476000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts9, pid1, threadGroupId1, cat2, + splitStrIndex3); // end slice 2 + + // end thread_two_call_function_three slice 5 + uint64_t ts10 = 168758679343000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts10, pid2, threadGroupId2, cat2, + splitStrIndex4); // end slice 3 + + // end thread_two_call_function_two slice 3 + uint64_t ts11 = 168758679344000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts11, pid1, threadGroupId1, cat3, + splitStrIndex5); // end slice 4 + + // end thread_two_call_function_one slice 1 + uint64_t ts12 = 168758689323000; + stream_.streamFilters_->sliceFilter_->FinishAsyncSlice(ts12, pid2, threadGroupId2, cat3, + splitStrIndex6); // end slice 5 + + auto slices = stream_.traceDataCache_->GetInternalSlicesData(); + EXPECT_TRUE(slices->Size() == 6); + EXPECT_TRUE(slices->DursData()[0] == ts7 - ts1); // slice 0 + EXPECT_TRUE(slices->Depths()[0] == 0); + + EXPECT_TRUE(slices->DursData()[1] == ts8 - ts2); // slice 1 + EXPECT_TRUE(slices->Depths()[1] == 0); + + EXPECT_TRUE(slices->DursData()[2] == ts9 - ts3); // slice 2 + EXPECT_TRUE(slices->Depths()[2] == 0); + + EXPECT_TRUE(slices->DursData()[3] == ts10 - ts4); // slice 3 + EXPECT_TRUE(slices->Depths()[3] == 0); + + EXPECT_TRUE(slices->DursData()[4] == ts11 - ts5); // slice 4 + + EXPECT_TRUE(slices->DursData()[5] == ts12 - ts6); // slice 5 +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/smaps_parser_test.cpp b/trace_streamer/test/unittest/smaps_parser_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..16b07acd70eb445a7ec13a136a632d31671d0773 --- /dev/null +++ b/trace_streamer/test/unittest/smaps_parser_test.cpp @@ -0,0 +1,287 @@ +/* + * 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 +#include + +#include "htrace_mem_parser.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class SmapsParserTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + + void TearDown() + { + if (access(dbPath_.c_str(), F_OK) == 0) { + remove(dbPath_.c_str()); + } + } + +public: + SysTuning::TraceStreamer::TraceStreamerSelector stream_ = {}; + const std::string dbPath_ = "data/resource/out.db"; +}; +/** + * @tc.name: ParseSmapsParse + * @tc.desc: Parse SmapsData object and export database + * @tc.type: FUNC + */ +HWTEST_F(SmapsParserTest, ParseSmapsParse, TestSize.Level1) +{ + TS_LOGI("test29-1"); + HtraceMemParser SmapsEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memInfo = tracePacket.add_processesinfo(); + SmapsInfo* smapsInfo = memInfo->add_smapinfo(); + EXPECT_TRUE(smapsInfo != nullptr); + int32_t size = memInfo->smapinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_BOOTTIME; + + SmapsEvent.ParseProcessInfo(tracePacket, timeStamp); + SmapsEvent.Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + memInfo->clear_smapinfo(); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SMAPS, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == MEM_MAX * 1); + EXPECT_EQ(stream_.traceDataCache_->GetConstProcessData().size(), 1); +} +/** + * @tc.name: ParseSmapsParseTestMeasureDataSize + * @tc.desc: Parse SmapsData object and count StatInfo + * @tc.type: FUNC + */ +HWTEST_F(SmapsParserTest, ParseSmapsParseTestMeasureDataSize, TestSize.Level1) +{ + TS_LOGI("test29-2"); + HtraceMemParser SmapsEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memInfo = tracePacket.add_processesinfo(); + SmapsInfo* SmapsInfo = memInfo->add_smapinfo(); + EXPECT_TRUE(SmapsInfo != nullptr); + int32_t size = memInfo->smapinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_BOOTTIME; + std::string startAddr = "5589523000"; + std::string endAddr = "5589543000"; + std::string permission = "r--p"; + std::string path = "/system/bin/hiprofilerd"; + uint64_t vartualSize = 128; + uint64_t rss = 112; + uint64_t pss = 112; + uint64_t reside = 87.5; + SmapsInfo->set_start_addr(startAddr); + SmapsInfo->set_end_addr(endAddr); + SmapsInfo->set_permission(permission); + SmapsInfo->set_path(path); + SmapsInfo->set_size(vartualSize); + SmapsInfo->set_rss(rss); + SmapsInfo->set_pss(pss); + SmapsInfo->set_reside(reside); + + SmapsEvent.ParseProcessInfo(tracePacket, timeStamp); + SmapsEvent.Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + memInfo->clear_smapinfo(); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SMAPS, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_TRUE(stream_.traceDataCache_->GetConstProcessMeasureData().Size() == MEM_MAX * 1); + EXPECT_EQ(stream_.traceDataCache_->GetConstProcessData().size(), 1); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().StartAddrs()[0] == "0x5589523000"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().EndAddrs()[0] == "0x5589543000"); + uint64_t protection = stream_.traceDataCache_->GetDataIndex(permission); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().ProtectionIds()[0] == protection); + uint64_t pat = stream_.traceDataCache_->GetDataIndex(path); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().PathIds()[0] == pat); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Sizes()[0] == vartualSize); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Rss()[0] == rss); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Pss()[0] == pss); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Resides()[0] == reside); + EXPECT_EQ(stream_.traceDataCache_->GetConstProcessData().size(), 1); +} +/** + * @tc.name: ParseSmapsParseTestMutiMeasureData + * @tc.desc: Parse muti SmapsData object and count StatInfo + * @tc.type: FUNC + */ +HWTEST_F(SmapsParserTest, ParseSmapsParseTestMutiMeasureData, TestSize.Level1) +{ + TS_LOGI("test29-3"); + HtraceMemParser SmapsEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memInfo = tracePacket.add_processesinfo(); + SmapsInfo* smapsInfo0 = memInfo->add_smapinfo(); + EXPECT_TRUE(smapsInfo0 != nullptr); + int32_t size = memInfo->smapinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock0 = TS_CLOCK_BOOTTIME; + std::string startAddr0 = "5589523000"; + std::string endAddr0 = "5589543000"; + std::string permission0 = "r--p"; + std::string path0 = "/system/bin/hiprofilerd"; + uint64_t vartualSize0 = 128; + uint64_t rss0 = 112; + uint64_t pss0 = 112; + uint64_t reside0 = 87.5; + smapsInfo0->set_start_addr(startAddr0); + smapsInfo0->set_end_addr(endAddr0); + smapsInfo0->set_permission(permission0); + smapsInfo0->set_path(path0); + smapsInfo0->set_size(vartualSize0); + smapsInfo0->set_rss(rss0); + smapsInfo0->set_pss(pss0); + smapsInfo0->set_reside(reside0); + + SmapsInfo* smapsInfo1 = memInfo->add_smapinfo(); + EXPECT_TRUE(smapsInfo1 != nullptr); + size = memInfo->smapinfo_size(); + EXPECT_TRUE(size == 2); + timeStamp = 1616439852302; + BuiltinClocks clock1 = TS_CLOCK_BOOTTIME; + std::string startAddr1 = "5589543000"; + std::string endAddr1 = "5589589000"; + std::string permission1 = "r-xp"; + std::string path1 = "/system/bin/hiprofilerd"; + uint64_t vartualSize1 = 280; + uint64_t rss1 = 280; + uint64_t pss1 = 280; + uint64_t reside1 = 100; + smapsInfo1->set_start_addr(startAddr1); + smapsInfo1->set_end_addr(endAddr1); + smapsInfo1->set_permission(permission1); + smapsInfo1->set_path(path1); + smapsInfo1->set_size(vartualSize1); + smapsInfo1->set_rss(rss1); + smapsInfo1->set_pss(pss1); + smapsInfo1->set_reside(reside1); + + SmapsEvent.ParseProcessInfo(tracePacket, timeStamp); + SmapsEvent.Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + memInfo->clear_smapinfo(); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SMAPS, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().StartAddrs()[0] == "0x5589523000"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().EndAddrs()[0] == "0x5589543000"); + uint64_t protection = stream_.traceDataCache_->GetDataIndex(permission0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().ProtectionIds()[0] == protection); + uint64_t pathId = stream_.traceDataCache_->GetDataIndex(path0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().PathIds()[0] == pathId); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Sizes()[0] == vartualSize0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Rss()[0] == rss0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Pss()[0] == pss0); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Resides()[0] == reside0); + + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().StartAddrs()[1] == "0x5589543000"); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().EndAddrs()[1] == "0x5589589000"); + protection = stream_.traceDataCache_->GetDataIndex(permission1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().ProtectionIds()[1] == protection); + pathId = stream_.traceDataCache_->GetDataIndex(path1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().PathIds()[1] == pathId); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Sizes()[1] == vartualSize1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Rss()[1] == rss1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Pss()[1] == pss1); + EXPECT_TRUE(stream_.traceDataCache_->GetConstSmapsData().Resides()[1] == reside1); +} +/** + * @tc.name: ParseMutiEmptySmapsDataAndCountStatInfo + * @tc.desc: Parse muti Empty SmapsData object and count StatInfo + * @tc.type: FUNC + */ +HWTEST_F(SmapsParserTest, ParseMutiEmptySmapsDataAndCountStatInfo, TestSize.Level1) +{ + TS_LOGI("test29-4"); + HtraceMemParser SmapsEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + ProcessMemoryInfo* memInfo = tracePacket.add_processesinfo(); + SmapsInfo* smapsInfo0 = memInfo->add_smapinfo(); + EXPECT_TRUE(smapsInfo0 != nullptr); + int32_t size = memInfo->smapinfo_size(); + EXPECT_TRUE(size == 1); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_BOOTTIME; + + SmapsInfo* smapsInfo1 = memInfo->add_smapinfo(); + EXPECT_TRUE(smapsInfo1 != nullptr); + size = memInfo->smapinfo_size(); + EXPECT_TRUE(size == 2); + + SmapsEvent.ParseProcessInfo(tracePacket, timeStamp); + SmapsEvent.Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + memInfo->clear_smapinfo(); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SMAPS, STAT_EVENT_RECEIVED); + EXPECT_TRUE(1 == eventCount); + EXPECT_EQ(stream_.traceDataCache_->GetConstProcessData().size(), 1); +} +/** + * @tc.name: ParseEmptySmapsData + * @tc.desc: Parse Empty SmapsData + * @tc.type: FUNC + */ +HWTEST_F(SmapsParserTest, ParseEmptySmapsData, TestSize.Level1) +{ + TS_LOGI("test29-5"); + HtraceMemParser SmapsEvent(stream_.traceDataCache_.get(), stream_.streamFilters_.get()); + + MemoryData tracePacket; + int32_t size = tracePacket.processesinfo_size(); + EXPECT_TRUE(size == 0); + uint64_t timeStamp = 1616439852302; + BuiltinClocks clock = TS_CLOCK_BOOTTIME; + + SmapsEvent.ParseProcessInfo(tracePacket, timeStamp); + SmapsEvent.Finish(); + stream_.traceDataCache_->ExportDatabase(dbPath_); + + EXPECT_TRUE(access(dbPath_.c_str(), F_OK) == 0); + tracePacket.clear_processesinfo(); + + auto eventCount = stream_.traceDataCache_->GetConstStatAndInfo().GetValue(TRACE_SMAPS, STAT_EVENT_RECEIVED); + // EXPECT_TRUE(0 == eventCount); + EXPECT_EQ(0, eventCount); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/span_join_test.cpp b/trace_streamer/test/unittest/span_join_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a20571f72556fd798667d31c3bce0f8e41d7f26d --- /dev/null +++ b/trace_streamer/test/unittest/span_join_test.cpp @@ -0,0 +1,245 @@ +/* + * 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 +#include + +#include "span_join.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +namespace SysTuning { +namespace TraceStreamer { +class SpanJoinTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + void Prepare(const std::string& sql) + { + int32_t size = static_cast(sql.size()); + sqlite3_prepare_v2(stream_.traceDataCache_->db_, sql.c_str(), size, &stmt_, nullptr); + } + + void Step(const std::string& sql) + { + Prepare(sql); + sqlite3_step(stmt_); + } + + void Next(const std::vector column) + { + sqlite3_step(stmt_); + for (size_t i = 0; i < column.size(); ++i) { + sqlite3_column_int64(stmt_, static_cast(i)); + } + } + sqlite3_stmt* stmt_; + TraceStreamerSelector stream_ = {}; +}; +/** + * @tc.name: SpanjoinTwoTable + * @tc.desc: SpanjoinTwoTable with ts,dur,and partitioned cpu + * @tc.type: FUNC + */ +HWTEST_F(SpanJoinTest, SpanjoinTwoTable, TestSize.Level1) +{ + TS_LOGI("test30-1"); + Step("CREATE TABLE FirstTable(ts UNSIGNED INT PRIMARY KEY, dur UNSIGNED INT, cpu UNSIGNED INT);"); + Step("CREATE TABLE SecondTable(ts UNSIGNED INT PRIMARY KEY, dur UNSIGNED INT, cpu UNSIGNED INT);"); + Step( + "CREATE VIRTUAL TABLE SpanjoinTable using span_join(FirstTable partitioned cpu, SecondTable partitioned cpu);"); + Step("INSERT INTO FirstTable VALUES(100, 10, 5);"); + Step("INSERT INTO FirstTable VALUES(110, 50, 5);"); + Step("INSERT INTO FirstTable VALUES(120, 100, 2);"); + Step("INSERT INTO FirstTable VALUES(160, 10, 5);"); + Step("INSERT INTO SecondTable VALUES(100, 5, 5);"); + Step("INSERT INTO SecondTable VALUES(105, 100, 5);"); + Step("INSERT INTO SecondTable VALUES(110, 50, 2);"); + Step("INSERT INTO SecondTable VALUES(160, 100, 2);"); + Prepare("SELECT * FROM SpanjoinTable"); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_ROW); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 120); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 40); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 2); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_ROW); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 160); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 60); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 2); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_ROW); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 100); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 5); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 5); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_ROW); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 105); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 5); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 5); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_ROW); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 110); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 50); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 5); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_ROW); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 160); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 10); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 5); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); +} +/** + * @tc.name: SpanjoinTwoTableWithoutPartitioned + * @tc.desc: SpanjoinTwoTable with ts,dur,and without partitioned cpu + * @tc.type: FUNC + */ +HWTEST_F(SpanJoinTest, SpanjoinTwoTableWithoutPartitioned, TestSize.Level2) +{ + TS_LOGI("test30-2"); + Step("CREATE TABLE FirstTable(ts UNSIGNED INT PRIMARY KEY, dur UNSIGNED INT);"); + Step("CREATE TABLE SecondTable(ts UNSIGNED INT PRIMARY KEY, dur UNSIGNED INT);"); + Step( + "CREATE VIRTUAL TABLE SpanjoinTable using span_join(FirstTable partitioned cpu, SecondTable partitioned cpu);"); + Step("INSERT INTO FirstTable VALUES(100, 10);"); + Step("INSERT INTO FirstTable VALUES(110, 50);"); + Step("INSERT INTO FirstTable VALUES(120, 100);"); + Step("INSERT INTO FirstTable VALUES(160, 10);"); + Step("INSERT INTO SecondTable VALUES(100, 5);"); + Step("INSERT INTO SecondTable VALUES(105, 100);"); + Step("INSERT INTO SecondTable VALUES(110, 50);"); + Step("INSERT INTO SecondTable VALUES(160, 100);"); + Prepare("SELECT * FROM SpanjoinTable"); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_DONE); +} +/** + * @tc.name: SpanjoinTwoTableWithoutTs + * @tc.desc: SpanjoinTwoTableWithoutTs with dur, partitioned cpu and without ts + * @tc.type: FUNC + */ +HWTEST_F(SpanJoinTest, SpanjoinTwoTableWithoutTs, TestSize.Level3) +{ + TS_LOGI("test30-3"); + Step("CREATE TABLE FirstTable(dur UNSIGNED INT, cpu UNSIGNED INT);"); + Step("CREATE TABLE SecondTable(dur UNSIGNED INT, cpu UNSIGNED INT);"); + Step( + "CREATE VIRTUAL TABLE SpanjoinTable using span_join(FirstTable partitioned cpu, SecondTable partitioned cpu);"); + Step("INSERT INTO FirstTable VALUES(10, 5);"); + Step("INSERT INTO FirstTable VALUES(50, 5);"); + Step("INSERT INTO FirstTable VALUES(100, 2);"); + Step("INSERT INTO FirstTable VALUES(10, 5);"); + Step("INSERT INTO SecondTable VALUES(5, 5);"); + Step("INSERT INTO SecondTable VALUES(100, 5);"); + Step("INSERT INTO SecondTable VALUES(50, 2);"); + Step("INSERT INTO SecondTable VALUES(100, 2);"); + Prepare("SELECT * FROM SpanjoinTable"); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); +} +/** + * @tc.name: SpanjoinTwoTableWithoutDur + * @tc.desc: SpanjoinTwoTableWithoutTs with ts, partitioned cpu and without dur + * @tc.type: FUNC + */ +HWTEST_F(SpanJoinTest, SpanjoinTwoTableWithoutDur, TestSize.Level4) +{ + TS_LOGI("test30-4"); + Step("CREATE TABLE FirstTable(ts UNSIGNED INT PRIMARY KEY, cpu UNSIGNED INT);"); + Step("CREATE TABLE SecondTable(ts UNSIGNED INT PRIMARY KEY, cpu UNSIGNED INT);"); + Step( + "CREATE VIRTUAL TABLE SpanjoinTable using span_join(FirstTable partitioned cpu, SecondTable partitioned cpu);"); + Step("INSERT INTO FirstTable VALUES(100, 5);"); + Step("INSERT INTO FirstTable VALUES(110, 5);"); + Step("INSERT INTO FirstTable VALUES(120, 2);"); + Step("INSERT INTO FirstTable VALUES(160, 5);"); + Step("INSERT INTO SecondTable VALUES(100, 5);"); + Step("INSERT INTO SecondTable VALUES(105, 5);"); + Step("INSERT INTO SecondTable VALUES(110, 2);"); + Step("INSERT INTO SecondTable VALUES(160, 2);"); + Prepare("SELECT * FROM SpanjoinTable"); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); + EXPECT_EQ(sqlite3_column_int64(stmt_, 0), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 1), 0); + EXPECT_EQ(sqlite3_column_int64(stmt_, 2), 0); + EXPECT_EQ(sqlite3_step(stmt_), SQLITE_MISUSE); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/table_test.cpp b/trace_streamer/test/unittest/table_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14295ecaa8f3a40ac563092803a6cf8920448ef5 --- /dev/null +++ b/trace_streamer/test/unittest/table_test.cpp @@ -0,0 +1,1495 @@ +/* + * 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 +#include + +#include "htrace_mem_parser.h" +#include "rpc_server.h" +#include "trace_data_cache.h" +#include "trace_streamer_selector.h" + +using namespace testing::ext; +using namespace SysTuning::TraceStreamer; +namespace SysTuning { +namespace TraceStreamer { +class TableTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; +}; + +/** + * @tc.name: AppnameTableTest + * @tc.desc: Appname Table Test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, AppnameTableTest, TestSize.Level1) +{ + TS_LOGI("test31-1"); + std::string sqlSelect = "select * from app_name"; + uint8_t flags = 0; + DataIndex eventSource = stream_.traceDataCache_->GetDataIndex("eventSource"); + DataIndex appName = stream_.traceDataCache_->GetDataIndex("app1"); + stream_.traceDataCache_->GetAppNamesData()->AppendAppName(flags, eventSource, appName); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: ArgsTableTest + * @tc.desc: Args Table Test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ArgsTableTest, TestSize.Level1) +{ + TS_LOGI("test31-2"); + std::string sqlSelect = "select * from args"; + std::string sqlSelect1 = "select * from args where id = 1"; + std::string sqlSelect2 = "select * from args where key > 1"; + std::string sqlSelect3 = "select * from args where id < 1"; + std::string sqlSelect4 = "select * from args where id >= 1"; + std::string sqlSelect5 = "select * from args where id <= 1"; + DataIndex nameId0 = stream_.traceDataCache_->GetDataIndex("args0"); + DataIndex nameId1 = stream_.traceDataCache_->GetDataIndex("args1"); + BaseDataType dataType0 = BASE_DATA_TYPE_INT; + BaseDataType dataType1 = BASE_DATA_TYPE_STRING; + int64_t value0 = 123; + int64_t value1 = 456; + size_t argSet0 = 321; + size_t argSet1 = 654; + stream_.traceDataCache_->InitDB(); + stream_.traceDataCache_->GetArgSetData()->AppendNewArg(nameId0, dataType0, value0, argSet0); + stream_.traceDataCache_->GetArgSetData()->AppendNewArg(nameId1, dataType1, value1, argSet1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: CallstackTableTest + * @tc.desc: Callstack Table Test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, CallstackTableTest, TestSize.Level1) +{ + TS_LOGI("test31-3"); + std::string sqlSelect = "select * from callstack"; + std::string sqlSelect1 = "select * from callstack where id = 1"; + std::string sqlSelect2 = "select * from callstack where ts > 1"; + std::string sqlSelect3 = "select * from callstack where callid < 1"; + std::string sqlSelect4 = "select * from callstack where cookie >= 1"; + std::string sqlSelect5 = "select * from callstack where cookie <= 1"; + uint64_t startT = 1; + uint64_t durationNs = 1; + InternalTid internalTid = 1; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("callstack"); + uint16_t nameIdentify = 1; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint8_t depth = 1; + uint64_t cookid = stream_.traceDataCache_->GetDataIndex("cook"); + const std::optional& parentId = 1; + + uint64_t startT1 = 1; + uint64_t durationNs1 = 1; + InternalTid internalTid1 = 1; + DataIndex cat1 = stream_.traceDataCache_->GetDataIndex("callstack1"); + uint16_t nameIdentify1 = 1; + DataIndex name1 = stream_.traceDataCache_->GetDataIndex("name1"); + uint8_t depth1 = 1; + uint64_t cookid1 = stream_.traceDataCache_->GetDataIndex("cook1"); + const std::optional& parentId1 = 1; + + stream_.traceDataCache_->InitDB(); + stream_.traceDataCache_->GetInternalSlicesData()->AppendInternalAsyncSlice( + startT, durationNs, internalTid, cat, nameIdentify, name, depth, cookid, parentId); + stream_.traceDataCache_->GetInternalSlicesData()->AppendInternalAsyncSlice( + startT1, durationNs1, internalTid1, cat1, nameIdentify1, name1, depth1, cookid1, parentId1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: ClkEventFilterTableTest + * @tc.desc: ClkEvent filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ClkEventFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-4"); + std::string sqlSelect = "select * from clk_event_filter"; + std::string sqlSelect1 = "select * from clk_event_filter where id = 1"; + std::string sqlSelect2 = "select * from clk_event_filter where name < 0"; + std::string sqlSelect3 = "select * from clk_event_filter where id > 0"; + std::string sqlSelect4 = "select * from clk_event_filter where id >= 0"; + std::string sqlSelect5 = "select * from clk_event_filter where id <= 0"; + uint64_t id = 1; + uint64_t rate = 1; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint64_t cpu = 1; + + uint64_t id1 = 1; + uint64_t rate1 = 0; + DataIndex name1 = stream_.traceDataCache_->GetDataIndex("name1"); + uint64_t cpu1 = 1; + stream_.traceDataCache_->GetClkEventFilterData()->AppendNewFilter(id, rate, name, cpu); + stream_.traceDataCache_->GetClkEventFilterData()->AppendNewFilter(id1, rate1, name1, cpu1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: ClockEventFilterTableTest + * @tc.desc: ClockEvent filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ClockEventFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-5"); + std::string sqlSelect = "select * from clock_event_filter"; + std::string sqlSelect1 = "select * from clock_event_filter where id = 1"; + std::string sqlSelect2 = "select * from clock_event_filter where type > 1"; + std::string sqlSelect3 = "select * from clock_event_filter where name < 1"; + std::string sqlSelect4 = "select * from clock_event_filter where cpu >= 1"; + std::string sqlSelect5 = "select * from clock_event_filter where id <= 1"; + uint64_t id = 1; + uint64_t type = 1; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint64_t cpu = 1; + + uint64_t id1 = 1; + uint64_t type1 = 0; + DataIndex name1 = stream_.traceDataCache_->GetDataIndex("name1"); + uint64_t cpu1 = 1; + stream_.traceDataCache_->GetClockEventFilterData()->AppendNewFilter(id, type, name, cpu); + stream_.traceDataCache_->GetClockEventFilterData()->AppendNewFilter(id1, type1, name1, cpu1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: CpuMeasureFilterTableTest + * @tc.desc: Cpu measure filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, CpuMeasureFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-6"); + std::string sqlSelect = "select * from cpu_measure_filter"; + std::string sqlSelect1 = "select * from cpu_measure_filter where id = 1"; + std::string sqlSelect2 = "select * from cpu_measure_filter where id > 1"; + std::string sqlSelect3 = "select * from cpu_measure_filter where type < 1"; + std::string sqlSelect4 = "select * from cpu_measure_filter where name >= 1"; + std::string sqlSelect5 = "select * from cpu_measure_filter where cpu <= 1"; + uint64_t filterId = 2; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint32_t cpu = 1; + + uint64_t filterId1 = 1; + DataIndex name1 = stream_.traceDataCache_->GetDataIndex("name1"); + uint32_t cpu1 = 2; + + stream_.traceDataCache_->GetCpuMeasuresData()->AppendNewFilter(filterId, name, cpu); + stream_.traceDataCache_->GetCpuMeasuresData()->AppendNewFilter(filterId1, name1, cpu1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: CpuUsageFilterTableTest + * @tc.desc: Cpu usage filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, CpuUsageFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-7"); + std::string sqlSelect = "select * from cpu_usage"; + uint64_t newTimeStamp = 1663869124160; + uint64_t dur = 560; + double totalLoad = 2; + double userLoad = 2; + double systemLoad = 2; + int64_t thread = 2; + + uint64_t newTimeStamp1 = 1663869224160; + uint64_t dur1 = 550; + double totalLoad1 = 1; + double userLoad1 = 1; + double systemLoad1 = 1; + int64_t thread1 = 1; + + stream_.traceDataCache_->GetCpuUsageInfoData()->AppendNewData(newTimeStamp, dur, totalLoad, userLoad, userLoad, + thread); + stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + stream_.traceDataCache_->GetCpuUsageInfoData()->AppendNewData(newTimeStamp1, dur1, totalLoad1, userLoad1, userLoad1, + thread1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: DataDictTableTest + * @tc.desc: Data dict table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, DataDictTableTest, TestSize.Level1) +{ + TS_LOGI("test31-8"); + std::string sqlSelect = "select * from data_dict"; + std::string sqlSelect1 = "select * from data_dict where id = 1"; + std::string sqlSelect2 = "select * from data_dict where id > 1"; + std::string sqlSelect3 = "select * from data_dict where id < 1"; + std::string sqlSelect4 = "select * from data_dict where id >= 1"; + std::string sqlSelect5 = "select * from data_dict where data <= 1"; + stream_.traceDataCache_->GetDataFromDict(1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 58); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 56); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 57); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: DataTypeTableTest + * @tc.desc: Data type table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, DataTypeTableTest, TestSize.Level1) +{ + TS_LOGI("test31-9"); + std::string sqlSelect = "select * from data_type"; + std::string sqlSelect1 = "select * from data_type where id = 1"; + std::string sqlSelect2 = "select * from data_type where id > 1"; + std::string sqlSelect3 = "select * from data_type where id < 1"; + std::string sqlSelect4 = "select * from data_type where typeId >= 1"; + std::string sqlSelect5 = "select * from data_type where id <= 1"; + BaseDataType dataType = BASE_DATA_TYPE_INT; + DataIndex dataDescIndex = stream_.traceDataCache_->GetDataIndex("dataDescIndex"); + BaseDataType dataType1 = BASE_DATA_TYPE_STRING; + DataIndex dataDescIndex1 = stream_.traceDataCache_->GetDataIndex("dataDescIndex1"); + + stream_.traceDataCache_->GetDataTypeData()->AppendNewDataType(dataType, dataDescIndex); + stream_.traceDataCache_->GetDataTypeData()->AppendNewDataType(dataType1, dataDescIndex1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 6); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 4); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 4); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: DiskIoTableTest + * @tc.desc: Disk io table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, DiskIoTableTest, TestSize.Level1) +{ + TS_LOGI("test31-10"); + std::string sqlSelect = "select * from diskio"; + uint64_t ts = 1663869124160; + uint64_t dur = 540; + uint64_t rd = 5; + uint64_t wr = 5; + uint64_t rdPerSec = 6; + uint64_t wrPerSec = 6; + double rdCountPerSec = 2; + double wrCountPerSec = 2; + uint64_t rdCount = 2; + uint64_t wrCount = 2; + + stream_.traceDataCache_->GetDiskIOData()->AppendNewData(ts, dur, rd, wr, rdPerSec, wrPerSec, rdCountPerSec, + wrCountPerSec, rdCount, wrCount); + stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); +} +/** + * @tc.name: EbpfCallstackTableTest + * @tc.desc: Ebpf callstack table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, EbpfCallstackTableTest, TestSize.Level1) +{ + TS_LOGI("test31-11"); + std::string sqlSelect = "select * from ebpf_callstack"; + std::string sqlSelect1 = "select * from ebpf_callstack where id = 1"; + std::string sqlSelect2 = "select * from ebpf_callstack where id > 1"; + std::string sqlSelect3 = "select * from ebpf_callstack where id < 1"; + std::string sqlSelect4 = "select * from ebpf_callstack where id >= 1"; + std::string sqlSelect5 = "select * from ebpf_callstack where id <= 1"; + std::string sqlSelect6 = "select * from hidump"; + uint64_t callChainId = 1; + uint32_t depth = 1; + uint64_t ip = 1; + uint64_t symbolId = 1; + uint64_t filePathId = 1; + + uint64_t callChainId1 = 2; + uint32_t depth1 = 2; + uint64_t ip1 = 2; + uint64_t symbolId1 = 2; + uint64_t filePathId1 = 2; + + uint64_t timeStamp = 1663869124160; + uint32_t fps = 1; + + uint64_t timestamp1 = 1663869224160; + uint32_t fps1 = 2; + + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timeStamp, fps); + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timestamp1, fps1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect6.c_str(), false); + EXPECT_EQ(row, 2); + + stream_.traceDataCache_->GetEbpfCallStack()->AppendNewData(callChainId, depth, ip, symbolId, filePathId); + stream_.traceDataCache_->GetEbpfCallStack()->AppendNewData(callChainId1, depth1, ip1, symbolId1, filePathId1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: FileSystemSampleTableTest + * @tc.desc: File system sample table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, FileSystemSampleTableTest, TestSize.Level1) +{ + TS_LOGI("test31-12"); + std::string sqlSelect = "select * from file_system_sample"; + std::string sqlSelect1 = "select * from file_system_sample where id = 1"; + std::string sqlSelect2 = "select * from file_system_sample where type > 1"; + std::string sqlSelect3 = "select * from hidump"; + std::string sqlSelect4 = "select * from hidump where id = 1"; + std::string sqlSelect5 = "select * from hidump where ts < 1663869124160"; + // std::string sqlSelect6 = "select * from hidump"; + uint64_t callChainId = 1; + uint16_t type = 1; + uint32_t ipid = 1; + uint32_t itid = 1; + uint64_t startTs = 1663869124160; + uint64_t endTs = 1663869124260; + uint64_t dur = 100; + DataIndex returnValue = stream_.traceDataCache_->GetDataIndex("returnValue"); + DataIndex errorCode = stream_.traceDataCache_->GetDataIndex("errorCode"); + size_t size = 1; + int32_t fd = 0; + DataIndex fileId = stream_.traceDataCache_->GetDataIndex("fileId"); + DataIndex firstArgument = stream_.traceDataCache_->GetDataIndex("firstArgument"); + DataIndex secondArgument = stream_.traceDataCache_->GetDataIndex("secondArgument"); + DataIndex thirdArgument = stream_.traceDataCache_->GetDataIndex("thirdArgument"); + DataIndex fourthArgument = stream_.traceDataCache_->GetDataIndex("fourthArgument"); + + uint64_t callChainId1 = 2; + uint16_t type1 = 2; + uint32_t ipid1 = 2; + uint32_t itid1 = 2; + uint64_t startTs1 = 1663869124161; + uint64_t endTs1 = 1663869124261; + uint64_t dur1 = 200; + DataIndex returnValue1 = stream_.traceDataCache_->GetDataIndex("returnValue1"); + DataIndex errorCode1 = stream_.traceDataCache_->GetDataIndex("errorCode1"); + size_t size1 = 2; + int32_t fd1 = 1; + DataIndex fileId1 = stream_.traceDataCache_->GetDataIndex("fileId1"); + DataIndex firstArgument1 = stream_.traceDataCache_->GetDataIndex("firstArgument1"); + DataIndex secondArgument1 = stream_.traceDataCache_->GetDataIndex("secondArgument1"); + DataIndex thirdArgument1 = stream_.traceDataCache_->GetDataIndex("thirdArgument1"); + DataIndex fourthArgument1 = stream_.traceDataCache_->GetDataIndex("fourthArgument1"); + + uint64_t timeStamp = 1663869124160; + uint32_t fps = 1; + + uint64_t timestamp1 = 1663869224160; + uint32_t fps1 = 2; + + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timeStamp, fps); + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timestamp1, fps1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 0); + + stream_.traceDataCache_->GetFileSystemSample()->AppendNewData( + callChainId, type, ipid, itid, startTs, endTs, dur, returnValue, errorCode, size, fd, fileId, firstArgument, + secondArgument, thirdArgument, fourthArgument); + stream_.traceDataCache_->GetFileSystemSample()->AppendNewData( + callChainId1, type1, ipid1, itid1, startTs1, endTs1, dur1, returnValue1, errorCode1, size1, fd1, fileId1, + firstArgument1, secondArgument1, thirdArgument1, fourthArgument1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: HidumpTableTest + * @tc.desc: Hidump table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, HidumpTableTest, TestSize.Level1) +{ + TS_LOGI("test31-13"); + std::string sqlSelect = "select * from hidump"; + uint64_t timeStamp = 1663869124160; + uint32_t fps = 1; + + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timeStamp, fps); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: HisysEventMeasureTableTest + * @tc.desc: Hisys event measure table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, HisysEventMeasureTableTest, TestSize.Level1) +{ + TS_LOGI("test31-14"); + std::string sqlSelect = "select * from hisys_event_measure"; + uint64_t serial = 1; + uint64_t ts = 1663869124160; + uint32_t nameId = stream_.traceDataCache_->GetDataIndex("event"); + uint32_t keyId = stream_.traceDataCache_->GetDataIndex("data"); + int32_t type = 1; + double numericValue = 0; + DataIndex stringValue = stream_.traceDataCache_->GetDataIndex("stringValue"); + + stream_.traceDataCache_->GetSyseventMeasureData()->AppendData(ts, nameId, keyId, type, numericValue, stringValue, + serial); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: InstantTableTest + * @tc.desc: Instant table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, InstantTableTest, TestSize.Level1) +{ + TS_LOGI("test31-15"); + std::string sqlSelect = "select * from instant"; + std::string sqlSelect2 = "select * from instant where name = \"name\""; + std::string sqlSelect3 = "select * from instant where ts < 1663869124160"; + std::string sqlSelect4 = "select * from instant where ref > 1"; + std::string sqlSelect5 = "select * from instant where wakeup_from >= 1"; + uint64_t timeStamp = 1663869124160; + DataIndex nameIndex = stream_.traceDataCache_->GetDataIndex("name"); + int64_t internalTid = 1; + int64_t wakeupFromInternalPid = 1; + + DataIndex nameIndex1 = stream_.traceDataCache_->GetDataIndex("name1"); + int64_t internalTid1 = 2; + int64_t wakeupFromInternalPid1 = 2; + + std::string sqlSelect1 = "select * from measure"; + uint32_t type = 1; + int64_t value = 1; + uint32_t filterId = 1; + + uint32_t type1 = 2; + uint64_t timestamp1 = 1663869124160; + int64_t value1 = 2; + uint32_t filterId1 = 2; + + stream_.traceDataCache_->GetMeasureData()->AppendMeasureData(type, timeStamp, value, filterId); + stream_.traceDataCache_->GetMeasureData()->AppendMeasureData(type1, timestamp1, value1, filterId1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); + + stream_.traceDataCache_->GetInstantsData()->AppendInstantEventData(timeStamp, nameIndex, internalTid, + wakeupFromInternalPid); + stream_.traceDataCache_->GetInstantsData()->AppendInstantEventData(timestamp1, nameIndex1, internalTid1, + wakeupFromInternalPid1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: IoLatencySampleTableTest + * @tc.desc: Io latency sample table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, IoLatencySampleTableTest, TestSize.Level1) +{ + TS_LOGI("test31-16"); + std::string sqlSelect = "select * from bio_latency_sample"; + std::string sqlSelect1 = "select * from hidump"; + std::string sqlSelect2 = "select * from bio_latency_sample where id = 1"; + uint64_t callChainId = 1; + uint64_t type = 1; + uint64_t ipid = 1; + uint64_t itid = 1; + uint64_t startTs = 1663869124160; + uint64_t endTs = 1663869224160; + uint64_t latencyDur = 200; + uint32_t tier = 1; + uint64_t size = 1; + uint64_t blockNumber = 1; + uint64_t filePathId = stream_.traceDataCache_->GetDataIndex("filePathId"); + uint64_t durPer4k = 1; + + uint64_t callChainId1 = 2; + uint64_t type1 = 2; + uint64_t ipid1 = 2; + uint64_t itid1 = 2; + uint64_t startTs1 = 1663869224160; + uint64_t endTs1 = 1663869424160; + uint64_t latencyDur1 = 200; + uint32_t tier1 = 2; + uint64_t size1 = 2; + uint64_t blockNumber1 = 2; + uint64_t filePathId1 = stream_.traceDataCache_->GetDataIndex("filePathId1"); + uint64_t durPer4k1 = 2; + + uint64_t timeStamp = 1663869124160; + uint32_t fps = 1; + + uint64_t timestamp1 = 1663869224160; + uint32_t fps1 = 2; + + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timeStamp, fps); + stream_.traceDataCache_->GetHidumpData()->AppendNewHidumpInfo(timestamp1, fps1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); + + stream_.traceDataCache_->GetBioLatencySampleData()->AppendNewData( + callChainId, type, ipid, itid, startTs, endTs, latencyDur, tier, size, blockNumber, filePathId, durPer4k); + stream_.traceDataCache_->GetBioLatencySampleData()->AppendNewData(callChainId1, type1, ipid1, itid1, startTs1, + endTs1, latencyDur1, tier1, size1, blockNumber1, + filePathId1, durPer4k1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: IrqTableTest + * @tc.desc: Irq table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, IrqTableTest, TestSize.Level1) +{ + TS_LOGI("test31-17"); + std::string sqlSelect = "select * from irq"; + std::string sqlSelect1 = "select * from irq where id < 2"; + uint64_t startT = 1663869124160; + uint64_t durationNs = 200; + InternalTid internalTid = 1; + DataIndex cat = stream_.traceDataCache_->GetDataIndex("cat"); + uint16_t nameIdentify = 1; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint8_t depth = 1; + const std::optional& parentId = 1; + + uint64_t startT1 = 1663869224160; + uint64_t durationNs1 = 200; + InternalTid internalTid1 = 2; + DataIndex cat1 = stream_.traceDataCache_->GetDataIndex("cat1"); + uint16_t nameIdentify1 = 2; + DataIndex name1 = stream_.traceDataCache_->GetDataIndex("name1"); + uint8_t depth1 = 2; + const std::optional& parentId1 = 2; + + stream_.traceDataCache_->GetIrqData()->AppendInternalSlice(startT, durationNs, internalTid, cat, nameIdentify, name, + depth, parentId); + stream_.traceDataCache_->GetIrqData()->AppendInternalSlice(startT1, durationNs1, internalTid1, cat1, nameIdentify1, + name1, depth1, parentId1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: LiveProcessTableTest + * @tc.desc: Live Process table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, LiveProcessTableTest, TestSize.Level1) +{ + TS_LOGI("test31-18"); + std::string sqlSelect = "select * from live_process"; + uint64_t newTimeStamp = 1663869124160; + uint64_t dur = 200; + int32_t processID = 1; + std::string processName = "processName"; + int32_t parentProcessID = 1; + int32_t uid = 1; + std::string userName = "userName"; + double cpuUsage = 1; + int32_t pssInfo = 1; + uint64_t cpuTime = 1663888624160; + int32_t threads = 1; + int64_t diskWrites = 1; + int64_t diskReads = 1; + + stream_.traceDataCache_->GetLiveProcessData()->AppendNewData(newTimeStamp, dur, processID, processName, + parentProcessID, uid, userName, cpuUsage, pssInfo, + cpuTime, threads, diskWrites, diskReads); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: LogTableTest + * @tc.desc: Log table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, LogTableTest, TestSize.Level1) +{ + TS_LOGI("test31-19"); + std::string sqlSelect = "select * from log"; + uint64_t seq = 1; + uint64_t timeStamp = 1663869124160; + uint32_t pid = 1; + uint32_t tid = 1; + DataIndex level = stream_.traceDataCache_->GetDataIndex("leve"); + DataIndex tag = stream_.traceDataCache_->GetDataIndex("tag"); + DataIndex context = stream_.traceDataCache_->GetDataIndex("context"); + uint64_t originTs = 1; + + stream_.traceDataCache_->GetHilogData()->AppendNewLogInfo(seq, timeStamp, pid, tid, level, tag, context, originTs); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: MeasureTableTest + * @tc.desc: Measure table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, MeasureTableTest, TestSize.Level1) +{ + TS_LOGI("test31-20"); + std::string sqlSelect = "select * from measure"; + std::string sqlSelect1 = "select * from measure where ts = 1663869124160"; + uint32_t type = 1; + uint64_t timeStamp = 1663869124160; + int64_t value = 1; + uint32_t filterId = 1; + + uint32_t type1 = 2; + uint64_t timestamp1 = 1663869224160; + int64_t value1 = 2; + uint32_t filterId1 = 2; + + stream_.traceDataCache_->GetMeasureData()->AppendMeasureData(type, timeStamp, value, filterId); + stream_.traceDataCache_->GetMeasureData()->AppendMeasureData(type1, timestamp1, value1, filterId1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: MeasureFilterTableTest + * @tc.desc: Measure Filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, MeasureFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-21"); + std::string sqlSelect = "select * from measure_filter"; + uint64_t filterId = stream_.traceDataCache_->GetDataIndex("filter"); + ; + uint32_t nameIndex = stream_.traceDataCache_->GetDataIndex("name"); + uint64_t internalTid = 1; + + stream_.traceDataCache_->GetThreadMeasureFilterData()->AppendNewFilter(filterId, nameIndex, internalTid); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: MetaTableTest + * @tc.desc: Meta table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, MetaTableTest, TestSize.Level1) +{ + TS_LOGI("test31-22"); + std::string sqlSelect = "select * from meta"; + + stream_.traceDataCache_->GetMetaData(); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 9); +} +/** + * @tc.name: NativeHookTableTest + * @tc.desc: Native hook table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, NativeHookTableTest, TestSize.Level1) +{ + TS_LOGI("test31-23"); + std::string sqlSelect = "select * from native_hook"; + std::string sqlSelect1 = "select * from native_hook where id = 1"; + std::string sqlSelect2 = "select * from native_hook where ipid > 1"; + std::string sqlSelect3 = "select * from native_hook where itid >= 1"; + std::string sqlSelect4 = "select * from native_hook where callchain_id < 1"; + uint64_t callChainId = 1; + uint32_t ipid = 1; + uint32_t itid = 1; + std::string eventType = "eventType"; + DataIndex subType = stream_.traceDataCache_->GetDataIndex("subType"); + uint64_t timeStamp = 1663869124160; + uint64_t endTimestamp = 1663869124360; + uint64_t duration = 200; + uint64_t addr = 1; + int64_t memSize = 1; + int64_t curMemSize = 1; + + uint64_t callChainId1 = 2; + uint32_t ipid1 = 2; + uint32_t itid1 = 2; + std::string eventType1 = "eventType1"; + DataIndex subType1 = stream_.traceDataCache_->GetDataIndex("subType1"); + uint64_t timestamp1 = 1663869224160; + uint64_t endTimestamp1 = 1663869224360; + uint64_t duration1 = 200; + uint64_t addr1 = 2; + int64_t memSize1 = 2; + int64_t curMemSize1 = 2; + + stream_.traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId, ipid, itid, eventType, subType, timeStamp, endTimestamp, duration, addr, memSize); + stream_.traceDataCache_->GetNativeHookData()->AppendNewNativeHookData( + callChainId1, ipid1, itid1, eventType1, subType1, timestamp1, endTimestamp1, duration1, addr1, memSize1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: NativeHookFrameTableTest + * @tc.desc: Native hook Frame table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, NativeHookFrameTableTest, TestSize.Level1) +{ + TS_LOGI("test31-24"); + std::string sqlSelect = "select * from native_hook_frame"; + std::string sqlSelect1 = "select * from native_hook_frame where id = 1"; + std::string sqlSelect2 = "select * from native_hook_frame where callchain_id > 1"; + std::string sqlSelect3 = "select * from native_hook_frame where symbol_id >= 1"; + std::string sqlSelect4 = "select * from native_hook_frame where file_id < 2"; + uint64_t callChainId = 1; + uint64_t depth = 1; + uint64_t ip = 1; + uint64_t sp = 1; + DataIndex symbolName = stream_.traceDataCache_->GetDataIndex("symbolName"); + DataIndex filePath = stream_.traceDataCache_->GetDataIndex("filePath"); + uint64_t offset = 1; + uint64_t symbolOffset = 1; + const std::string vaddr = "addr"; + + uint64_t callChainId1 = 2; + uint64_t depth1 = 2; + uint64_t ip1 = 2; + uint64_t sp1 = 2; + DataIndex symbolName1 = stream_.traceDataCache_->GetDataIndex("symbolName1"); + DataIndex filePath1 = stream_.traceDataCache_->GetDataIndex("filePath1"); + uint64_t offset1 = 2; + uint64_t symbolOffset1 = 2; + const std::string vaddr1 = "addr1"; + + stream_.traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame(callChainId, depth, ip, sp, symbolName, + filePath, offset, symbolOffset, vaddr); + stream_.traceDataCache_->GetNativeHookFrameData()->AppendNewNativeHookFrame( + callChainId1, depth1, ip1, sp1, symbolName1, filePath1, offset1, symbolOffset1, vaddr1); + + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: NetworkTableTest + * @tc.desc: Network table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, NetworkTableTest, TestSize.Level1) +{ + TS_LOGI("test31-25"); + std::string sqlSelect = "select * from network"; + uint64_t newTimeStamp = 1663869124160; + uint64_t tx = 1; + uint64_t rx = 1; + uint64_t dur = 200; + double rxSpeed = 1; + double txSpeed = 1; + uint64_t packetIn = 1; + double packetInSec = 1; + uint64_t packetOut = 1; + double packetOutSec = 1; + const std::string& netType = "nettype"; + + stream_.traceDataCache_->GetNetworkData()->AppendNewNetData(newTimeStamp, tx, rx, dur, rxSpeed, txSpeed, packetIn, + packetInSec, packetOut, packetOutSec, netType); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: PerfCallchainTableTest + * @tc.desc: Perf callchain table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, PerfCallchainTableTest, TestSize.Level1) +{ + TS_LOGI("test31-26"); + std::string sqlSelect = "select * from perf_callchain"; + std::string sqlSelect1 = "select * from perf_callchain where id = 1"; + std::string sqlSelect2 = "select * from perf_callchain where callchain_id > 1"; + std::string sqlSelect3 = "select * from perf_callchain where file_id < 1"; + std::string sqlSelect4 = "select * from perf_callchain where symbol_id >= 1"; + uint64_t sampleId = stream_.traceDataCache_->GetDataIndex("sample"); + uint64_t callChainId = stream_.traceDataCache_->GetDataIndex("callChain"); + uint64_t vaddrInFile = 1; + uint64_t fileId = stream_.traceDataCache_->GetDataIndex("file"); + uint64_t symbolId = stream_.traceDataCache_->GetDataIndex("symbolId"); + + uint64_t sampleId1 = stream_.traceDataCache_->GetDataIndex("sample1"); + uint64_t callChainId1 = stream_.traceDataCache_->GetDataIndex("callChain1"); + uint64_t vaddrInFile1 = 2; + uint64_t fileId1 = stream_.traceDataCache_->GetDataIndex("file1"); + uint64_t symbolId1 = stream_.traceDataCache_->GetDataIndex("symbolId1"); + + stream_.traceDataCache_->GetPerfCallChainData()->AppendNewPerfCallChain(sampleId, callChainId, vaddrInFile, fileId, + symbolId); + + stream_.traceDataCache_->GetPerfCallChainData()->AppendNewPerfCallChain(sampleId1, callChainId1, vaddrInFile1, + fileId1, symbolId1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: PerfFilesTableTest + * @tc.desc: Perf files table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, PerfFilesTableTest, TestSize.Level1) +{ + TS_LOGI("test31-27"); + std::string sqlSelect = "select * from perf_files"; + std::string sqlSelect1 = "select * from perf_files where id = 1"; + std::string sqlSelect2 = "select * from perf_files where file_id < 1"; + uint64_t fileIds = stream_.traceDataCache_->GetDataIndex("file"); + uint32_t serial = 1; + DataIndex symbols = stream_.traceDataCache_->GetDataIndex("symbol"); + DataIndex filePath = stream_.traceDataCache_->GetDataIndex("filePath"); + + uint64_t fileIds1 = stream_.traceDataCache_->GetDataIndex("file1"); + uint32_t serial1 = 1; + DataIndex symbols1 = stream_.traceDataCache_->GetDataIndex("symbol1"); + DataIndex filePath1 = stream_.traceDataCache_->GetDataIndex("filePath1"); + + stream_.traceDataCache_->GetPerfFilesData()->AppendNewPerfFiles(fileIds, serial, symbols, filePath); + stream_.traceDataCache_->GetPerfFilesData()->AppendNewPerfFiles(fileIds1, serial1, symbols1, filePath1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: PerfReportTableTest + * @tc.desc: Perf report table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, PerfReportTableTest, TestSize.Level1) +{ + TS_LOGI("test31-28"); + std::string sqlSelect = "select * from perf_report"; + DataIndex type = stream_.traceDataCache_->GetDataIndex("type"); + DataIndex value = stream_.traceDataCache_->GetDataIndex("value"); + + stream_.traceDataCache_->GetPerfReportData()->AppendNewPerfReport(type, value); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: PerfSampleTableTest + * @tc.desc: Perf sample table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, PerfSampleTableTest, TestSize.Level1) +{ + TS_LOGI("test31-29"); + std::string sqlSelect = "select * from perf_sample"; + std::string sqlSelect1 = "select * from perf_sample where id = 1"; + std::string sqlSelect2 = "select * from perf_sample where callchain_id > 1"; + std::string sqlSelect3 = "select * from perf_sample where thread_id < 1"; + std::string sqlSelect4 = "select * from perf_sample where event_type_id >= 1"; + std::string sqlSelect5 = "select * from perf_sample where cpu_id <= 1"; + uint64_t sampleId = stream_.traceDataCache_->GetDataIndex("type"); + uint64_t timeStamp = 1663869124160; + uint64_t tid = 1; + uint64_t eventCount = 2; + uint64_t eventTypeId = 1; + uint64_t timestampTrace = 1; + uint64_t cpuId = 1; + uint64_t threadState = stream_.traceDataCache_->GetDataIndex("threadState"); + + uint64_t sampleId1 = stream_.traceDataCache_->GetDataIndex("type1"); + uint64_t timestamp1 = 1663869124160; + uint64_t tid1 = 2; + uint64_t eventCount1 = 3; + uint64_t eventTypeId1 = 2; + uint64_t timestampTrace1 = 2; + uint64_t cpuId1 = 2; + uint64_t threadState1 = stream_.traceDataCache_->GetDataIndex("threadState1"); + + stream_.traceDataCache_->GetPerfSampleData()->AppendNewPerfSample(sampleId, timeStamp, tid, eventCount, eventTypeId, + timestampTrace, cpuId, threadState); + stream_.traceDataCache_->GetPerfSampleData()->AppendNewPerfSample( + sampleId1, timestamp1, tid1, eventCount1, eventTypeId1, timestampTrace1, cpuId1, threadState1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: PerfThreadTableTest + * @tc.desc: Perf Thread table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, PerfThreadTableTest, TestSize.Level1) +{ + TS_LOGI("test31-30"); + std::string sqlSelect = "select * from perf_thread"; + std::string sqlSelect1 = "select * from perf_thread where id = 1"; + std::string sqlSelect2 = "select * from perf_thread where thread_id > 1"; + std::string sqlSelect3 = "select * from perf_thread where process_id < 1"; + uint64_t pid = 1; + uint64_t tid = 1; + DataIndex threadName = stream_.traceDataCache_->GetDataIndex("threadState"); + + uint64_t pid1 = 2; + uint64_t tid1 = 2; + DataIndex threadName1 = stream_.traceDataCache_->GetDataIndex("threadState1"); + + stream_.traceDataCache_->GetPerfThreadData()->AppendNewPerfThread(pid, tid, threadName); + stream_.traceDataCache_->GetPerfThreadData()->AppendNewPerfThread(pid1, tid1, threadName1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: ProcessTableTest + * @tc.desc: Process table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ProcessTableTest, TestSize.Level1) +{ + TS_LOGI("test31-31"); + std::string sqlSelect = "select * from process"; + std::string sqlSelect1 = "select * from process where id = 1"; + + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: ProcessFilterTableTest + * @tc.desc: Process filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ProcessFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-32"); + std::string sqlSelect = "select * from process_filter"; + uint64_t id = 1; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint32_t internalPid = 1; + + stream_.traceDataCache_->GetProcessFilterData()->AppendNewFilter(id, name, internalPid); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: ProcessMeasureTableTest + * @tc.desc: Process Measure table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ProcessMeasureTableTest, TestSize.Level1) +{ + TS_LOGI("test31-33"); + std::string sqlSelect = "select * from process_measure"; + uint32_t type = 1; + uint64_t timeStamp = 1663869124160; + int64_t value = 1; + uint32_t filterId = 1; + + stream_.traceDataCache_->GetProcessMeasureData()->AppendMeasureData(type, timeStamp, value, filterId); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: ProcessMeasureFilterTableTest + * @tc.desc: Process Measure filter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ProcessMeasureFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-34"); + std::string sqlSelect = "select * from process_measure_filter"; + std::string sqlSelect1 = "select * from process_measure_filter where id = 1"; + std::string sqlSelect2 = "select * from process_measure_filter where ipid < 1"; + std::string sqlSelect3 = "select * from process_measure_filter where name = \"name\""; + uint64_t id = 1; + DataIndex name = stream_.traceDataCache_->GetDataIndex("name"); + uint32_t internalPid = 1; + + uint64_t id1 = 1; + DataIndex name1 = stream_.traceDataCache_->GetDataIndex("name1"); + uint32_t internalPid1 = 1; + + stream_.traceDataCache_->GetProcessMeasureFilterData()->AppendNewFilter(id, name, internalPid); + stream_.traceDataCache_->GetProcessMeasureFilterData()->AppendNewFilter(id1, name1, internalPid1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: RawTableTest + * @tc.desc: Raw table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, RawTableTest, TestSize.Level1) +{ + TS_LOGI("test31-35"); + std::string sqlSelect = "select * from raw"; + std::string sqlSelect1 = "select * from raw where id = 1"; + std::string sqlSelect2 = "select * from raw where name = \"sched_waking\""; + std::string sqlSelect3 = "select * from raw where ts = 1663869124160"; + std::string sqlSelect4 = "select * from raw where itid < 2"; + uint32_t id = 1; + uint64_t timeStamp = 1663869124160; + uint32_t name = stream_.traceDataCache_->GetDataIndex("cpu_idle"); + uint32_t cpu = 1; + uint32_t internalTid = 1; + + uint32_t id1 = 2; + uint64_t timestamp1 = 1663869224160; + uint32_t name1 = stream_.traceDataCache_->GetDataIndex("sched_waking"); + uint32_t cpu1 = 2; + uint32_t internalTid1 = 2; + + stream_.traceDataCache_->GetRawData()->AppendRawData(id, timeStamp, name, cpu, internalTid); + stream_.traceDataCache_->GetRawData()->AppendRawData(id1, timestamp1, name1, cpu1, internalTid1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: SchedSliceTest + * @tc.desc: Sched slice table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, SchedSliceTest, TestSize.Level1) +{ + TS_LOGI("test31-36"); + std::string sqlSelect = "select * from sched_slice"; + std::string sqlSelect1 = "select * from sched_slice where id = 1"; + std::string sqlSelect2 = "select * from sched_slice where ts > 1"; + std::string sqlSelect3 = "select * from sched_slice where cpu < 1"; + std::string sqlSelect4 = "select * from sched_slice where itid >= 1"; + std::string sqlSelect5 = "select * from sched_slice where ipid <= 1"; + std::string sqlSelect6 = "select * from sched_slice where dur >= 200"; + uint64_t ts = 1663869124160; + uint64_t dur = 200; + uint64_t cpu = 1; + uint64_t internalTid = 1; + uint64_t endState = 1; + uint64_t priority = 1; + + uint64_t ts1 = 1663869224160; + uint64_t dur1 = 200; + uint64_t cpu1 = 2; + uint64_t internalTid1 = 2; + uint64_t endState1 = 2; + uint64_t priority1 = 2; + + stream_.traceDataCache_->GetSchedSliceData()->AppendSchedSlice(ts, dur, cpu, internalTid, endState, priority); + stream_.traceDataCache_->GetSchedSliceData()->AppendSchedSlice(ts1, dur1, cpu1, internalTid1, endState1, priority1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect6.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: SmapsTest + * @tc.desc: Smaps table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, SmapsTest, TestSize.Level1) +{ + TS_LOGI("test31-37"); + std::string sqlSelect = "select * from smaps"; + uint64_t timeStamp = 1663869124160; + std::string startAddr = "startAddr"; + std::string endAddr = "endAddr"; + uint64_t dirty = 1; + uint64_t swapper = 1; + uint64_t rss = 1; + uint64_t pss = 1; + uint64_t size = 2; + double reside = 1; + DataIndex protectionId = stream_.traceDataCache_->GetDataIndex("protection"); + DataIndex pathId = stream_.traceDataCache_->GetDataIndex("path"); + + stream_.traceDataCache_->GetSmapsData()->AppendNewData(timeStamp, startAddr, endAddr, dirty, swapper, rss, pss, + size, reside, protectionId, pathId); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: StatTableTest + * @tc.desc: Stat table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, StatTableTest, TestSize.Level1) +{ + TS_LOGI("test31-38"); + std::string sqlSelect = "select * from stat"; + stream_.traceDataCache_->GetStatAndInfo(); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 420); +} +/** + * @tc.name: SymbolsTableTest + * @tc.desc: Symbols table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, SymbolsTableTest, TestSize.Level1) +{ + TS_LOGI("test31-39"); + std::string sqlSelect = "select * from symbols"; + std::string sqlSelect1 = "select * from symbols where id = 1"; + std::string sqlSelect2 = "select * from symbols where id < 1"; + const DataIndex& name = stream_.traceDataCache_->GetDataIndex("name"); + const uint64_t& addr = 1; + + const DataIndex& name1 = stream_.traceDataCache_->GetDataIndex("name1"); + const uint64_t& addr1 = 2; + + stream_.traceDataCache_->GetSymbolsData()->InsertSymbol(name, addr); + stream_.traceDataCache_->GetSymbolsData()->InsertSymbol(name1, addr1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: SyscallTableTest + * @tc.desc: Syscall table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, SyscallTableTest, TestSize.Level1) +{ + TS_LOGI("test31-40"); + std::string sqlSelect = "select * from syscall"; + int64_t sysCallNum = 1; + DataIndex type = stream_.traceDataCache_->GetDataIndex("type"); + uint64_t ipid = 1; + uint64_t timeStamp = 1663869124160; + int64_t ret = 1; + + stream_.traceDataCache_->GetSysCallData()->AppendSysCallData(sysCallNum, type, ipid, timeStamp, ret); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: SysEventFilterTableTest + * @tc.desc: SysEventFilter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, SysEventFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-41"); + std::string sqlSelect = "select * from sys_event_filter"; + std::string sqlSelect1 = "select * from sys_event_filter where id = 1"; + std::string sqlSelect2 = "select * from sys_event_filter where id > 1"; + std::string sqlSelect3 = "select * from sys_event_filter where id < 1"; + std::string sqlSelect4 = "select * from sys_event_filter where id >= 1"; + std::string sqlSelect5 = "select * from sys_event_filter where id <= 1"; + uint64_t filterId = 1; + DataIndex type = stream_.traceDataCache_->GetDataIndex("type"); + DataIndex nameId = stream_.traceDataCache_->GetDataIndex("name"); + + uint64_t filterId1 = 2; + DataIndex type1 = stream_.traceDataCache_->GetDataIndex("type1"); + DataIndex nameId1 = stream_.traceDataCache_->GetDataIndex("name1"); + + stream_.traceDataCache_->GetSysMeasureFilterData()->AppendNewFilter(filterId, type, nameId); + stream_.traceDataCache_->GetSysMeasureFilterData()->AppendNewFilter(filterId1, type1, nameId1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 2); +} +/** + * @tc.name: SysMemMeasureTableTest + * @tc.desc: SysMemMeasure table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, SysMemMeasureTableTest, TestSize.Level1) +{ + TS_LOGI("test31-42"); + std::string sqlSelect = "select * from sys_mem_measure"; + uint32_t type = 1; + uint64_t timeStamp = 1663869124160; + int64_t value = 1; + uint32_t filterId = stream_.traceDataCache_->GetDataIndex("filter"); + + stream_.traceDataCache_->GetSysMemMeasureData()->AppendMeasureData(type, timeStamp, value, filterId); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: ThreadTableTest + * @tc.desc: Thread table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ThreadTableTest, TestSize.Level1) +{ + TS_LOGI("test31-43"); + std::string sqlSelect = "select * from thread"; + + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: ThreadFilterTableTest + * @tc.desc: ThreadFilter table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ThreadFilterTableTest, TestSize.Level1) +{ + TS_LOGI("test31-44"); + std::string sqlSelect = "select * from thread_filter"; + uint64_t filterId = stream_.traceDataCache_->GetDataIndex("ilter"); + uint32_t nameIndex = stream_.traceDataCache_->GetDataIndex("name"); + uint64_t internalTid = 1; + + stream_.traceDataCache_->GetThreadFilterData()->AppendNewFilter(filterId, nameIndex, internalTid); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +/** + * @tc.name: ThreadStateTableTest + * @tc.desc: ThreadState table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, ThreadStateTableTest, TestSize.Level1) +{ + TS_LOGI("test31-45"); + std::string sqlSelect = "select * from thread_state"; + std::string sqlSelect1 = "select * from thread_state where id = 1"; + std::string sqlSelect2 = "select * from thread_state where tid > 1"; + std::string sqlSelect3 = "select * from thread_state where pid < 1"; + std::string sqlSelect4 = "select * from thread_state where itid >= 1"; + std::string sqlSelect5 = "select * from thread_state where cpu <= 1"; + std::string sqlSelect6 = "select * from thread_state where ts = 1663869124160"; + std::string sqlSelect7 = "select * from thread_state where dur = 1"; + std::string sqlSelect8 = "select * from thread_state where state = \"idState\""; + InternalTime ts = 1663869124160; + InternalTime dur = 200; + InternalCpu cpu = 1; + InternalTid itid = 1; + TableRowId idState = 1; + + InternalTime ts1 = 1663869224160; + InternalTime dur1 = 200; + InternalCpu cpu1 = 2; + InternalTid itid1 = 2; + TableRowId idState1 = 2; + + stream_.traceDataCache_->GetThreadStateData()->AppendThreadState(ts, dur, cpu, itid, idState); + stream_.traceDataCache_->GetThreadStateData()->AppendThreadState(ts1, dur1, cpu1, itid1, idState1); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect1.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect2.c_str(), false); + EXPECT_EQ(row, 2); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect3.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect4.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect5.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect6.c_str(), false); + EXPECT_EQ(row, 1); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect7.c_str(), false); + EXPECT_EQ(row, 0); + row = stream_.traceDataCache_->SearchDatabase(sqlSelect8.c_str(), false); + EXPECT_EQ(row, 0); +} +/** + * @tc.name: TraceRangeTableTest + * @tc.desc: TraceRange table test + * @tc.type: FUNC + */ +HWTEST_F(TableTest, TraceRangeTableTest, TestSize.Level1) +{ + TS_LOGI("test31-46"); + std::string sqlSelect = "select * from trace_range"; + + stream_.traceDataCache_->UpdateTraceRange(); + auto row = stream_.traceDataCache_->SearchDatabase(sqlSelect.c_str(), false); + EXPECT_EQ(row, 1); +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/trace_streamer/test/unittest/wasm_func_test.cpp b/trace_streamer/test/unittest/wasm_func_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17d85b08eedad1a52c0061894e375bf094d523c9 --- /dev/null +++ b/trace_streamer/test/unittest/wasm_func_test.cpp @@ -0,0 +1,86 @@ +/* + * 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 +#include + +#include "rpc/rpc_server.h" +#include "wasm_func.cpp" + +using namespace testing::ext; +namespace SysTuning { +namespace TraceStreamer { +class WasmFuncTest : public ::testing::Test { +public: + void SetUp() + { + stream_.InitFilter(); + } + void TearDown() {} + +public: + TraceStreamerSelector stream_ = {}; +}; +constexpr int32_t MAX_TESET_BUF_SIZE = 1024; + +/** + * @tc.name: CorrectTraceData + * @tc.desc: Upload correct trace file data + * @tc.type: FUNC + */ +HWTEST_F(WasmFuncTest, CorrectTraceData, TestSize.Level1) +{ + TS_LOGI("test32-1"); + std::string parseData("sugov:0-178 ( 178) [001] .... 28462.257501: cpu_frequency: state=816000 cpu_id=0 \n"); + std::string sqlQuery("select * from measure;"); + + char out[MAX_TESET_BUF_SIZE] = {0}; + + int32_t ret = TraceStreamerParseData((const uint8_t*)parseData.c_str(), parseData.length()); + EXPECT_EQ(0, ret); + ret = TraceStreamerParseDataOver(); + EXPECT_EQ(0, ret); + ret = TraceStreamerSqlQuery((const uint8_t*)sqlQuery.c_str(), sqlQuery.length(), (uint8_t*)out, MAX_TESET_BUF_SIZE); + TS_LOGI("sql value:%s", out); + EXPECT_NE(-1, ret); + ret = TraceStreamerReset(); + EXPECT_EQ(0, ret); +} + +/** + * @tc.name: WrongTraceData + * @tc.desc: Upload wrong tracking file data + * @tc.type: FUNC + */ +HWTEST_F(WasmFuncTest, WrongTraceData, TestSize.Level1) +{ + TS_LOGI("test32-2"); + std::string parseData("sugov:0-178 ( 178) [001] .... 28462.277458: cpu_frequency: state=600000 cpu_id=2 \n"); + std::string sqlQuery("select * from measure_a;"); + + char out[MAX_TESET_BUF_SIZE] = {0}; + + int32_t ret = TraceStreamerParseData((const uint8_t*)parseData.c_str(), parseData.length()); + EXPECT_EQ(0, ret); + ret = TraceStreamerParseDataOver(); + EXPECT_EQ(0, ret); + ret = TraceStreamerSqlQuery((const uint8_t*)sqlQuery.c_str(), sqlQuery.length(), (uint8_t*)out, MAX_TESET_BUF_SIZE); + TS_LOGI("sql value:%s", out); + EXPECT_EQ(-1, ret); + ret = TraceStreamerReset(); + EXPECT_EQ(0, ret); +} +} // namespace TraceStreamer +} // namespace SysTuning \ No newline at end of file diff --git a/trace_streamer/test_pbdecoder.sh b/trace_streamer/test_pbdecoder.sh new file mode 100755 index 0000000000000000000000000000000000000000..000b6ad13d01c63e4ffebe65366e1531b85335c4 --- /dev/null +++ b/trace_streamer/test_pbdecoder.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# 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. +# set -e +./build.sh testpb +rm -rf out/test/*.xml +rm -rf out/test_debug/*.xml +find out/test -name "*.gcda" -print0 | xargs -0 rm +find out/test_debug -name "*.gcda" -print0 | xargs -0 rm +mkdir -p out/test/data/resource +mkdir -p out/test_debug/data/resource +cp test/resource/* out/test/data/resource/ +cp test/resource/* out/test_debug/data/resource/ +cd out/test +./trace_streamer_ut