diff --git a/arkui-plugins/common/plugin-context.ts b/arkui-plugins/common/plugin-context.ts index 95843cb7b6d27b7fc3af59a6669544741e0625da..05a8b76812e22992d0cc37e594880bc776b5370b 100644 --- a/arkui-plugins/common/plugin-context.ts +++ b/arkui-plugins/common/plugin-context.ts @@ -21,12 +21,14 @@ export class PluginContext { private program: arkts.Program | undefined; private projectConfig: ProjectConfig | undefined; private contextPtr: number | undefined; + private compileJobInfo: CompileJobInfo | undefined; constructor() { this.ast = undefined; this.program = undefined; this.projectConfig = undefined; this.contextPtr = undefined; + this.compileJobInfo = undefined; } /** @@ -72,6 +74,10 @@ export class PluginContext { public getContextPtr(): number | undefined { return this.contextPtr; } + + public getCompileJob(): CompileJobInfo | undefined { + return this.compileJobInfo; + } } export interface DependentModuleConfig { @@ -120,3 +126,8 @@ export type PluginExecutor = { name: string; handler: PluginHandlerFunction; }; + +export interface CompileJobInfo { + filePath: string; + compileType: string; +} diff --git a/arkui-plugins/memo-plugins/index.ts b/arkui-plugins/memo-plugins/index.ts index aa5c2de65a05c30a87710b35e2cb346098076e43..b53f8c91ee53e73ca881b93c7bad764dc8a6d79a 100644 --- a/arkui-plugins/memo-plugins/index.ts +++ b/arkui-plugins/memo-plugins/index.ts @@ -84,9 +84,8 @@ export function unmemoizeTransform(): Plugins { arkts.Performance.getInstance().createEvent('memo-recheck'); arkts.recheckSubtree(script); arkts.Performance.getInstance().stopEvent('memo-recheck', false); - arkts.Performance.getInstance().clearAllEvents(true); - arkts.Performance.getInstance().visualizeEvents(true); + arkts.Performance.getInstance().visualizeEvents(true, this.getCompileJob()?.filePath, this.getCompileJob()?.compileType); arkts.Performance.getInstance().clearHistory(); arkts.Performance.getInstance().clearTotalDuration(); diff --git a/arkui-plugins/test/.gitignore b/arkui-plugins/test/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..7ca223086b2534987bf380f3363a6f3a22ae05d8 --- /dev/null +++ b/arkui-plugins/test/.gitignore @@ -0,0 +1,2 @@ +*.log +*.csv \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/.gitignore b/arkui-plugins/test/gen-benchmark/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..47301ae580b13de40a2d20286213babf105af763 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/.gitignore @@ -0,0 +1,8 @@ +*.ets +__pycache__ +out/ +*.zip +*.log +*.xlsx +*.whl +*.csv \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/README.md b/arkui-plugins/test/gen-benchmark/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7b5ffd02d947979cc5558f71a96b6a4cf84b032d --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/README.md @@ -0,0 +1,4 @@ + +``` +npm run gen_benchmark +``` \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_builtin_components.py b/arkui-plugins/test/gen-benchmark/gen_builtin_components.py new file mode 100755 index 0000000000000000000000000000000000000000..6ea56b6f0668266a3253fa77baa889242ae65a70 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_builtin_components.py @@ -0,0 +1,198 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'builtinComponents.ets' + +MAIN_TEMPLATE = """ +/** + * 内置组件 + */ + +import {{ memo, __memo_context_type, __memo_id_type }} from "@ohos.arkui.stateManagement" + +import {{ Text, TextAttribute, Column, Component, Button, ButtonAttribute, ClickEvent, + UserView, Image, Slider, Toggle, DatePicker, Progress, TextInput, Row, List, Tabs, + FontWeight, ButtonType, SliderStyle, ToggleType, Color, $r, BarPosition, TabContent, + ProgressType, Checkbox, ForEach, SliderChangeMode, ListItem, TextAlign, EnterKeyType, + SubmitEvent, EditableTextOnChangeCallback, Callback, FontStyle, OnCheckboxChangeCallback, + ImageFit }} from "@ohos.arkui.component" + +import {{ State }} from "@ohos.arkui.stateManagement" + +@Component +struct BuiltinComponents {{ + @State message: string = 'Hello ArkTS' + @State sliderValue: number = 50 + @State toggleValue: boolean = false + @State pickerValue: string = 'Option1' + @State dateValue: Date = new Date() + @State progressValue: number = 0.3 + @State textValue: string = '' + @State radioValue: string = 'Radio1' + @State checkboxValues: boolean[] = [false, false, false] + @State indexValue: number = 0 + + build() {{ + Column() {{ +{content} + }} + }} +}} +""" + +COMPONENTES_GROUP = """ + // 1. 文本组件 + Text(this.message) + .fontSize(30) + .fontWeight(FontWeight.Bold) + .fontColor(Color.Blue) + .fontStyle(FontStyle.Normal) + .draggable(true) + .onClick((e:ClickEvent) => {{ + this.message = 'Text clicked!' + }}) + + // 2. 按钮组件 + Button('Click Me') + .width(200) + .height(50) + .type(ButtonType.Capsule) + .onClick((e:ClickEvent) => {{ + this.message = 'Button clicked!' + }}) + + // 3. 图片组件 + Image($r('app.media.startIcon')) + .width(100) + .height(100) + .sourceSize({{width:1392, height:1080}}) + .borderWidth(1) + .objectFit(ImageFit.Contain) + .borderRadius(50) + + // 4. 滑动条组件 + Slider({{ + value: this.sliderValue, + min: 0, + max: 100, + step: 1, + style: SliderStyle.OutSet + }}) + .width('90%') + .onChange((value: Double, mode: SliderChangeMode) => {{ + this.sliderValue = value + }}) + + // 5. 开关组件 + Toggle({{ type: ToggleType.Switch, isOn: this.toggleValue }}) + .width(100) + .height(40) + .padding(15) + .selectedColor(Color.Green) + .onChange((isOn: boolean) => {{ + this.toggleValue = isOn + }}) + + // 6. 日期选择器 + DatePicker({{ + start: new Date('1970-1-1'), + end: new Date('2030-12-31'), + selected: this.dateValue + }}) + .width('90%') + .onDateChange((value: Date) => {{ + this.dateValue = value + }} as Callback) + + // 7. 进度条 + Progress({{ + value: this.progressValue, + total: 1.0, + type: ProgressType.Linear + }}) + .width('90%') + .height(100) + + // 8. 输入框 + TextInput({{ placeholder: 'Enter text' }}) + .width('90%') + .height(50) + .onChange((value: string) => {{ + this.textValue = value + }} as EditableTextOnChangeCallback) + + // 9. 复选框 + Row() {{ + Checkbox() + .select(this.checkboxValues[0]) + .onChange((value: boolean) => {{ + this.checkboxValues[0] = value + }} as OnCheckboxChangeCallback) + Checkbox() + .select(this.checkboxValues[1]) + .onChange((value: boolean) => {{ + this.checkboxValues[1] = value + }} as OnCheckboxChangeCallback) + }} + + // 10. 列表组件 + List() {{ + ForEach([1, 2, 3, 4, 5], (item: Int, index: Double) => {{ + ListItem() {{ + Text(`Item ${{item}}`) + .width('100%') + .textAlign(TextAlign.Center) + }} + .width('100%') + .height(60) + .backgroundColor('#f0f0f0') + }}) + }} + .width('100%') + .height(200) + + // 11. 页签组件 + Tabs({{ barPosition: BarPosition.Start }}) {{ + TabContent() {{ + Text('Tab1 Content').fontSize(20) + }}.tabBar('Tab1') + + TabContent() {{ + Text('Tab2 Content') + .fontSize(20) + }}.tabBar('Tab2') + }} + .width('100%') + .height(150) +""" + + +def process(component_count, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + content = '' + for i in range(int(component_count / 11)): + content += COMPONENTES_GROUP.format() + '\n' + f.write(MAIN_TEMPLATE.format(content=content)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_builtin_components_11.py b/arkui-plugins/test/gen-benchmark/gen_builtin_components_11.py new file mode 100644 index 0000000000000000000000000000000000000000..9ac6f4727bccd200c31e77cf64ecab23f90bcee5 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_builtin_components_11.py @@ -0,0 +1,189 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'builtinComponents.ets' + +MAIN_TEMPLATE = """ +/** + * 内置组件 + */ + +@Entry +@Component +struct BuiltinComponents {{ + @State message: string = 'Hello ArkTS' + @State sliderValue: number = 50 + @State toggleValue: boolean = false + @State pickerValue: string = 'Option1' + @State dateValue: Date = new Date() + @State progressValue: number = 0.3 + @State textValue: string = '' + @State radioValue: string = 'Radio1' + @State checkboxValues: boolean[] = [false, false, false] + @State indexValue: number = 0 + + build() {{ + Column() {{ +{content} + }} + }} +}} + +""" + +COMPONENT_GROUP = """ +// 1. 文本组件 + Text(this.message) + .fontSize(30) + .fontWeight(FontWeight.Bold) + .fontColor(Color.Blue) + .fontStyle(FontStyle.Normal) + .draggable(true) + .onClick((e:ClickEvent) => {{ + this.message = 'Text clicked!' + }}) + + // 2. 按钮组件 + Button('Click Me') + .width(200) + .height(50) + .type(ButtonType.Capsule) + .onClick((e:ClickEvent) => {{ + this.message = 'Button clicked!' + }}) + + // 3. 图片组件 + Image($r('app.media.startIcon')) + .width(100) + .height(100) + .sourceSize({{width:1392, height:1080}}) + .borderWidth(1) + .objectFit(ImageFit.Contain) + .borderRadius(50) + + // 4. 滑动条组件 + Slider({{ + value: this.sliderValue, + min: 0, + max: 100, + step: 1, + style: SliderStyle.OutSet + }}) + .width('90%') + .onChange((value) => {{ + this.sliderValue = value + }}) + + // 5. 开关组件 + Toggle({{ type: ToggleType.Switch, isOn: this.toggleValue }}) + .width(100) + .height(40) + .padding(15) + .selectedColor(Color.Green) + .onChange((isOn: boolean) => {{ + this.toggleValue = isOn + }}) + + // 6. 日期选择器 + DatePicker({{ + start: new Date('1970-1-1'), + end: new Date('2030-12-31'), + selected: this.dateValue + }}) + .width('90%') + .onDateChange((value: Date) => {{ + this.dateValue = value + }}) + + // 7. 进度条 + Progress({{ + value: this.progressValue, + total: 1.0, + type: ProgressType.Linear + }}) + .width('90%') + .height(100) + + // 8. 输入框 + TextInput({{ placeholder: 'Enter text' }}) + .width('90%') + .height(50) + .onChange((value: string) => {{ + this.textValue = value + }}) + + // 9. 复选框 + Row() {{ + Checkbox() + .select(this.checkboxValues[0]) + .onChange((value: boolean) => {{ + this.checkboxValues[0] = value + }}) + Checkbox() + .select(this.checkboxValues[1]) + .onChange((value: boolean) => {{ + this.checkboxValues[1] = value + }} ) + }} + + // 10. 列表组件 + List() {{ + ForEach([1, 2, 3, 4, 5], (item: number) => {{ + ListItem() {{ + Text(`Item ${{item}}`) + .width('100%') + .textAlign(TextAlign.Center) + }} + .width('100%') + .height(60) + .backgroundColor('#f0f0f0') + }}) + }} + .width('100%') + .height(200) + + // 11. 页签组件 + Tabs({{ barPosition: BarPosition.Start }}) {{ + TabContent() {{ + Text('Tab1 Content').fontSize(20) + }}.tabBar('Tab1') + + TabContent() {{ + Text('Tab2 Content') + .fontSize(20) + }}.tabBar('Tab2') + }} + .width('100%') + .height(150) +""" + + +def process(component_count, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + content = '' + for i in range(int(component_count / 11)): + content += COMPONENT_GROUP.format() + '\n' + f.write(MAIN_TEMPLATE.format(content=content)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_custom_components.py b/arkui-plugins/test/gen-benchmark/gen_custom_components.py new file mode 100755 index 0000000000000000000000000000000000000000..2304042a1e7bb6a0d2004570fd6e93558804f0cf --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_custom_components.py @@ -0,0 +1,84 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME1 = 'customComponents1.ets' +FILE_NAME2 = 'customComponents2.ets' +MAIN_TEMPLATE = """ +/** + * 自定义组件 + */ + +import {{ State }} from "@ohos.arkui.stateManagement" +import {{ Component, Column, ClickEvent, FontWeight, Text }} from "@ohos.arkui.component" + +@Component +struct CustomComponentsMain {{ + build() {{ +{main_body} + }} +}} + +{components} +""" + +COMPONENT_TEMPLATE = """ +@Component +struct Component{id} {{ + message: string = "hello world" + + build() {{ + Column() {{ + Text(this.message) + .fontSize(30) + .fontWeight(FontWeight.Bold) + .onClick((e:ClickEvent) => {{ + this.message = 'Text clicked!' + }}) + }} + }} +}} +""" + + +def process(component_count, path_perfix=''): + file_path1 = FILE_NAME1 + if (path_perfix != ''): + file_path1 = os.path.join(path_perfix, FILE_NAME1) + with open(file_path1, 'w', encoding='UTF-8') as f: + main_body = '' + components = '' + for i in range(component_count): + main_body += ' Component{}()\n'.format(i) + components += COMPONENT_TEMPLATE.format(id=i) + '\n' + f.write(MAIN_TEMPLATE.format(main_body=main_body, components=components)) + + + call_count = component_count * 9 + file_path2 = FILE_NAME2 + if (path_perfix != ''): + file_path2 = os.path.join(path_perfix, FILE_NAME2) + with open(file_path2, 'w', encoding='UTF-8') as f: + main_body = '' + components = COMPONENT_TEMPLATE.format(id=321) + '\n' + for i in range(call_count): + main_body += ' Component321()\n\n' + f.write(MAIN_TEMPLATE.format(main_body=main_body, components=components)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_custom_components_11.py b/arkui-plugins/test/gen-benchmark/gen_custom_components_11.py new file mode 100644 index 0000000000000000000000000000000000000000..a1b64affa2fe7b5836ed494696642db6692d2da8 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_custom_components_11.py @@ -0,0 +1,84 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME1 = 'customComponents1.ets' +FILE_NAME2 = 'customComponents2.ets' +MAIN_TEMPLATE = """ +/** + * 自定义组件 + */ + +@Entry +@Component +struct CustomComponentsMain {{ + build() {{ + Column() {{ +{main_body} + }} + }} +}} + +{components} +""" + +COMPONENT_TEMPLATE = """ +@Component +struct Component{id} {{ + message: string = "hello world" + + build() {{ + Column() {{ + Text(this.message) + .fontSize(30) + .fontWeight(FontWeight.Bold) + .onClick((e:ClickEvent) => {{ + this.message = 'Text clicked!' + }}) + }} + }} +}} +""" + + +def process(component_count, path_perfix=''): + file_path1 = FILE_NAME1 + if (path_perfix != ''): + file_path1 = os.path.join(path_perfix, FILE_NAME1) + with open(file_path1, 'w', encoding='UTF-8') as f: + main_body = '' + components = '' + for i in range(component_count): + main_body += ' Component{}()\n'.format(i) + components += COMPONENT_TEMPLATE.format(id=i) + '\n' + f.write(MAIN_TEMPLATE.format(main_body=main_body, components=components)) + + + call_count = component_count * 9 + file_path2 = FILE_NAME2 + if (path_perfix != ''): + file_path2 = os.path.join(path_perfix, FILE_NAME2) + with open(file_path2, 'w', encoding='UTF-8') as f: + main_body = '' + components = COMPONENT_TEMPLATE.format(id=321) + '\n' + for i in range(call_count): + main_body += ' Component321()\n\n' + f.write(MAIN_TEMPLATE.format(main_body=main_body, components=components)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_many_import.py b/arkui-plugins/test/gen-benchmark/gen_many_import.py new file mode 100755 index 0000000000000000000000000000000000000000..59c912a27ad859ae07a8dedb79b18cc844977bec --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_many_import.py @@ -0,0 +1,96 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import shutil +import os +import sys + +MAIN_FILE_NAME = 'manyImportMain.ets' +OUT_DIR = 'manyImportFiles' + +MAIN_TEMPLATE = """ +/** + * 多级import + */ + +import {{ Component, Column }} from "@ohos.arkui.component" +import {{ ManyImportComponent1 }} from "./manyImportFiles/manyImportFile1" + +@Component +struct ManyImportMain {{ + build() {{ + Column() {{ + ManyImportComponent1() + }} + }} +}} +""" +COMPONENT_TEMPLATE = """ +import {{ Component, Column, Text }} from "@ohos.arkui.component" +import {{ State }} from "@ohos.arkui.stateManagement" +{component_import_content} + +@Component +export struct ManyImportComponent{id} {{ + @State message: string = 'Hello ArkTS' + + build() {{ + Column() {{ + Text(this.message) +{component_build_content} + }} + }} +}} +""" + + +def process(file_count, path_perfix=''): + file_path = MAIN_FILE_NAME + out_dir = OUT_DIR + if (path_perfix != ''): + file_path = os.path.join(path_perfix, MAIN_FILE_NAME) + out_dir = os.path.join(path_perfix, OUT_DIR) + + try: + shutil.rmtree(out_dir) + except Exception: + pass + + try: + os.mkdir(out_dir) + except Exception as e: + raise e + + with open(file_path, 'w', encoding='UTF-8') as f: + f.write(MAIN_TEMPLATE.format()) + + for i in range(1, file_count + 1): + file_name = os.path.join(out_dir, "manyImportFile{}.ets".format(i)) + + with open(file_name, 'w', encoding='UTF-8') as f: + component_import_content = '' + component_build_content = '' + if i * 2 <= file_count: + component_import_content += "import {{ ManyImportComponent{} }} from \"./manyImportFile{}\"\n".format(i * 2, i * 2) + component_build_content += " ManyImportComponent{}()\n".format(i * 2) + if i * 2 + 1 <= file_count: + component_import_content += "import {{ ManyImportComponent{} }} from \"./manyImportFile{}\"\n".format(i * 2 + 1, i * 2 + 1) + component_build_content += " ManyImportComponent{}()\n".format(i * 2 + 1) + f.write(COMPONENT_TEMPLATE.format(id=i, component_import_content=component_import_content, component_build_content=component_build_content)) + + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_many_import_11.py b/arkui-plugins/test/gen-benchmark/gen_many_import_11.py new file mode 100644 index 0000000000000000000000000000000000000000..89e4d3797beed7a1184f21ad26b8d07fea78e555 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_many_import_11.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import shutil +import os +import sys + +MAIN_FILE_NAME = 'manyImportMain.ets' +OUT_DIR = 'manyImportFiles' + +MAIN_TEMPLATE = """ +/** + * 多级import + */ + +import {{ ManyImportComponent1 }} from "./manyImportFiles/manyImportFile1" + +@Entry +@Component +struct ManyImportMain {{ + build() {{ + Column() {{ + ManyImportComponent1() + }} + }} +}} +""" +COMPONENT_TEMPLATE = """ +{component_import_content} + +@Component +export struct ManyImportComponent{id} {{ + @State message: string = 'Hello ArkTS' + + build() {{ + Column() {{ + Text(this.message) +{component_build_content} + }} + }} +}} +""" + + +def process(file_count, path_perfix=''): + file_path = MAIN_FILE_NAME + out_dir = OUT_DIR + if (path_perfix != ''): + file_path = os.path.join(path_perfix, MAIN_FILE_NAME) + out_dir = os.path.join(path_perfix, OUT_DIR) + + try: + shutil.rmtree(out_dir) + except Exception: + pass + + try: + os.mkdir(out_dir) + except Exception as e: + raise e + + with open(file_path, 'w', encoding='UTF-8') as f: + f.write(MAIN_TEMPLATE.format()) + + for i in range(1, file_count + 1): + file_name = os.path.join(out_dir, "manyImportFile{}.ets".format(i)) + + with open(file_name, 'w', encoding='UTF-8') as f: + component_import_content = '' + component_build_content = '' + if i * 2 <= file_count: + component_import_content += "import {{ ManyImportComponent{} }} from \"./manyImportFile{}\"\n".format(i * 2, i * 2) + component_build_content += " ManyImportComponent{}()\n".format(i * 2) + if i * 2 + 1 <= file_count: + component_import_content += "import {{ ManyImportComponent{} }} from \"./manyImportFile{}\"\n".format(i * 2 + 1, i * 2 + 1) + component_build_content += " ManyImportComponent{}()\n".format(i * 2 + 1) + f.write(COMPONENT_TEMPLATE.format(id=i, component_import_content=component_import_content, component_build_content=component_build_content)) + + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_memo.py b/arkui-plugins/test/gen-benchmark/gen_memo.py new file mode 100755 index 0000000000000000000000000000000000000000..a4bb725b1f8827ce0823206ce6e506b0447a650c --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_memo.py @@ -0,0 +1,70 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'positionalMemoization.ets' +MAIN_TEMPLATE = """ +/** + * memo + */ + +import {{ Component, Column, Text, ClickEvent, Button, FontWeight }} from "@ohos.arkui.component" +import {{ State, memo }} from "@ohos.arkui.stateManagement" + +@Component +struct PositionalMemoizationMain {{ + @State num: number = 0; + +{memo_functions} + + build() {{ + Column() {{ + Button('Click me!') + .fontSize(30) + .fontWeight(FontWeight.Bold) + .onClick((e:ClickEvent) => {{ +{call_memo} + }}) + }} + }} +}} +""" + +FUNCTION_TEMPLATE = """ + @memo + add{id}(a: number, b: number): number {{ + return a + b; + }} +""" + + +def process(function_count, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + memo_functions = '' + call_memo = '' + for i in range(function_count): + memo_functions += FUNCTION_TEMPLATE.format(id=i) + call_memo += " this.num = this.add{}(this.num, this.num);\n".format(i) + f.write(MAIN_TEMPLATE.format(memo_functions=memo_functions, call_memo=call_memo)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_nonui_files.py b/arkui-plugins/test/gen-benchmark/gen_nonui_files.py new file mode 100755 index 0000000000000000000000000000000000000000..bbdb63e27147c8169a29ab8e91f15890614e8c49 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_nonui_files.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +import shutil + +MAIN_TEMPLATE = """ +import {{ BusinessError }} from '@ohos.base' +import buffer from "@ohos.buffer" +import util from '@ohos.util' +import rpc from '@ohos.rpc' +import cryptoFramework from '@ohos.security.cryptoFramework' +import relationalStore from '@ohos.data.relationalStore' + +{content} +""" + +CLASS_TEMPLATE = """ +export class Class{id} {{ + name1: string; + name2: string; + name3: string; + constructor(name1: string, name2: string, name3: string) {{ + this.name1 = name1; + this.name2 = name2; + this.name3 = name3; + }} + + add(a:number, b:number): number {{ + return a + b; + }} +}} +""" + +OUT_DIR = 'nonUIFiles' + + +def process(file_count, class_count, path_perfix=''): + out_dir = OUT_DIR + if (path_perfix != ''): + out_dir = os.path.join(path_perfix, OUT_DIR) + + try: + shutil.rmtree(out_dir) + except Exception: + pass + try: + os.mkdir(out_dir) + except Exception as e: + raise e + + for i in range(file_count): + content = '' + for j in range(class_count): + content += CLASS_TEMPLATE.format(id=str(i) + '_' + str(j)) + file_path = os.path.join(out_dir, "nonUIFile{}.ets".format(i)) + with open(file_path, 'w', encoding='UTF-8') as f: + f.write(MAIN_TEMPLATE.format(content=content)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), int(args[2]), str(args[3])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_resource_reference.py b/arkui-plugins/test/gen-benchmark/gen_resource_reference.py new file mode 100755 index 0000000000000000000000000000000000000000..e96015e4c047082ab118121973ad3e7901a15bc6 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_resource_reference.py @@ -0,0 +1,51 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'resourceReference.ets' + +MAIN_TEMPLATE = """ +/** + * $r + */ + +import {{ Component, Column, $r }} from "@ohos.arkui.component" + +@Component +struct ResourceReferenceMain {{ + build() {{ + Column() {{}} +{content} + }} +}} +""" + + +def process(image_count, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + content = '' + for i in range(image_count): + content += ' .width($r(\'app.media.startIcon\'))\n\n' + f.write(MAIN_TEMPLATE.format(content=content)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_resource_reference_11.py b/arkui-plugins/test/gen-benchmark/gen_resource_reference_11.py new file mode 100644 index 0000000000000000000000000000000000000000..f6459f36fede4696e70aa50e3c8eabb79bda3a15 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_resource_reference_11.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'resourceReference.ets' + +MAIN_TEMPLATE = """ +/** + * $r + */ + +@Entry +@Component +struct ResourceReferenceMain {{ + build() {{ + Column() {{}} +{content} + }} +}} +""" + + +def process(image_count, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + content = '' + for i in range(image_count): + content += ' .width($r(\'app.media.startIcon\'))\n\n' + f.write(MAIN_TEMPLATE.format(content=content)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_state_var.py b/arkui-plugins/test/gen-benchmark/gen_state_var.py new file mode 100755 index 0000000000000000000000000000000000000000..c81d64ff5a614e5426b43417e04f05fd0ac4192b --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_state_var.py @@ -0,0 +1,155 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'stateVariables.ets' + +TEMPLATE = """ +/** + * 状态变量 + */ + +import {{ State, Prop, Provide, Consume, Link }} from "@ohos.arkui.stateManagement" +import {{ Component, Column, ClickEvent, Button }} from "@ohos.arkui.component" + +@Component +struct StateVariablesMain {{ + //============================================================================= +{fa_prop_decl} + + //============================================================================= +{fa_link_decl} + + //============================================================================= +{fa_provide_decl} + + build() {{ + Column() {{ + //============================================================================= + PropVariables( + {{ +{fa_prop_param} + }} + ) + + //============================================================================= + LinkVariables( + {{ +{fa_link_param} + }} + ) + + //============================================================================= + ConsumeVariables() + }} + }} +}} + +@Component +struct PropVariables {{ + //============================================================================= +{son_prop_decl} + + build() {{ + Column() {{ + Button('Click Me') + .onClick((e: ClickEvent) => {{ + {son_prop_body} + }}) + }} + }} +}} + +@Component +struct LinkVariables {{ +{son_link_decl} + + //============================================================================= + + build() {{ + Column() {{ + Button('Click Me') + .onClick((e: ClickEvent) => {{ + {son_link_body} + }}) + }} + }} +}} + +@Component +struct ConsumeVariables {{ +{son_consume_decl} + + //============================================================================= + + build() {{ + Column() {{ + Button('Click Me') + .onClick((e: ClickEvent) => {{ + {son_consume_body} + }}) + }} + }} +}} +""" + + +def process(count_each_type, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + son_prop_decl = '' + son_prop_body = '' + son_link_decl = '' + son_link_body = '' + son_consume_decl = '' + son_consume_body = '' + fa_prop_decl = '' + fa_link_decl = '' + fa_provide_decl = '' + fa_prop_param = '' + fa_link_param = '' + for i in range(int(count_each_type / 6)): + son_prop_decl += " @Prop prop_num{}: number = 0;\n".format(i) + son_prop_body += " this.prop_num{}++;\n".format(i) + son_link_decl += " @Link link_num{}: number = 0;\n".format(i) + son_link_body += " this.link_num{}++;\n".format(i) + son_consume_decl += " @Consume consume_num{}: number;\n".format(i) + son_consume_body += " this.consume_num{}++;\n".format(i) + fa_prop_decl += " @State prop_num{}: number = 0;\n".format(i) + fa_link_decl += " @State link_num{}: number = 0;\n".format(i) + fa_provide_decl += " @Provide consume_num{}: number = 0;\n".format(i) + fa_prop_param += " prop_num{}: this.prop_num{},\n".format(i, i) + fa_link_param += " link_num{}: this.link_num{},\n".format(i, i) + + f.write(TEMPLATE.format(son_prop_decl=son_prop_decl, + son_prop_body=son_prop_body, + son_link_decl=son_link_decl, + son_link_body=son_link_body, + son_consume_decl=son_consume_decl, + son_consume_body=son_consume_body, + fa_prop_decl=fa_prop_decl, + fa_link_decl=fa_link_decl, + fa_provide_decl=fa_provide_decl, + fa_prop_param=fa_prop_param, + fa_link_param=fa_link_param)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/gen_state_var_11.py b/arkui-plugins/test/gen-benchmark/gen_state_var_11.py new file mode 100644 index 0000000000000000000000000000000000000000..eed842371458913d9e8def3193f2cbc5ece7273e --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/gen_state_var_11.py @@ -0,0 +1,153 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os + +FILE_NAME = 'stateVariables.ets' + +TEMPLATE = """ +/** + * 状态变量 + */ + +@Entry +@Component +struct StateVariablesMain {{ + //============================================================================= +{fa_prop_decl} + + //============================================================================= +{fa_link_decl} + + //============================================================================= +{fa_provide_decl} + + build() {{ + Column() {{ + //============================================================================= + PropVariables( + {{ +{fa_prop_param} + }} + ) + + //============================================================================= + LinkVariables( + {{ +{fa_link_param} + }} + ) + + //============================================================================= + ConsumeVariables() + }} + }} +}} + +@Component +struct PropVariables {{ + //============================================================================= +{son_prop_decl} + + build() {{ + Column() {{ + Button('Click Me') + .onClick((e: ClickEvent) => {{ + {son_prop_body} + }}) + }} + }} +}} + +@Component +struct LinkVariables {{ +{son_link_decl} + + //============================================================================= + + build() {{ + Column() {{ + Button('Click Me') + .onClick((e: ClickEvent) => {{ + {son_link_body} + }}) + }} + }} +}} + +@Component +struct ConsumeVariables {{ +{son_consume_decl} + + //============================================================================= + + build() {{ + Column() {{ + Button('Click Me') + .onClick((e: ClickEvent) => {{ + {son_consume_body} + }}) + }} + }} +}} +""" + + +def process(count_each_type, path_perfix=''): + file_path = FILE_NAME + if (path_perfix != ''): + file_path = os.path.join(path_perfix, FILE_NAME) + + with open(file_path, 'w', encoding='UTF-8') as f: + son_prop_decl = '' + son_prop_body = '' + son_link_decl = '' + son_link_body = '' + son_consume_decl = '' + son_consume_body = '' + fa_prop_decl = '' + fa_link_decl = '' + fa_provide_decl = '' + fa_prop_param = '' + fa_link_param = '' + for i in range(int(count_each_type / 6)): + son_prop_decl += " @Prop prop_num{}: number = 0;\n".format(i) + son_prop_body += " this.prop_num{}++;\n".format(i) + son_link_decl += " @Link link_num{}: number;\n".format(i) + son_link_body += " this.link_num{}++;\n".format(i) + son_consume_decl += " @Consume consume_num{}: number;\n".format(i) + son_consume_body += " this.consume_num{}++;\n".format(i) + fa_prop_decl += " @State prop_num{}: number = 0;\n".format(i) + fa_link_decl += " @State link_num{}: number = 0;\n".format(i) + fa_provide_decl += " @Provide consume_num{}: number = 0;\n".format(i) + fa_prop_param += " prop_num{}: this.prop_num{},\n".format(i, i) + fa_link_param += " link_num{}: this.link_num{},\n".format(i, i) + + f.write(TEMPLATE.format(son_prop_decl=son_prop_decl, + son_prop_body=son_prop_body, + son_link_decl=son_link_decl, + son_link_body=son_link_body, + son_consume_decl=son_consume_decl, + son_consume_body=son_consume_body, + fa_prop_decl=fa_prop_decl, + fa_link_decl=fa_link_decl, + fa_provide_decl=fa_provide_decl, + fa_prop_param=fa_prop_param, + fa_link_param=fa_link_param)) + +if __name__ == '__main__': + args = sys.argv + process(int(args[1]), str(args[2])) \ No newline at end of file diff --git a/arkui-plugins/test/gen-benchmark/main.py b/arkui-plugins/test/gen-benchmark/main.py new file mode 100755 index 0000000000000000000000000000000000000000..5e27848cee095e1230ed54c6213f6f856ff27f7a --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/main.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import sys +import shutil +import os +import gen_state_var +import gen_builtin_components +import gen_custom_components +import gen_memo +import gen_resource_reference +import gen_many_import +import gen_builtin_components_11 +import gen_custom_components_11 +import gen_many_import_11 +import gen_resource_reference_11 +import gen_state_var_11 + +LOC = 10000 +OUT_DIR = 'out' + +if __name__ == '__main__': + current_file_dir = os.path.dirname(os.path.abspath(__file__)) + out_dir = os.path.join(current_file_dir, OUT_DIR) + + try: + shutil.rmtree(out_dir) + except Exception: + pass + try: + os.mkdir(out_dir) + except Exception as e: + raise e + + args = sys.argv + if len(args) == 2: + LOC = int(args[1]) + + out_dir_12 = os.path.join(out_dir, '1.2') + try: + os.mkdir(out_dir_12) + except Exception as e: + raise e + gen_builtin_components.process(int(LOC / 11.363636363636363), out_dir_12) + gen_custom_components.process(int(LOC / 19.0), out_dir_12) + gen_many_import.process(int(int(LOC * 0.1)), out_dir_12) + gen_memo.process(int(LOC / 6.0), out_dir_12) + gen_resource_reference.process(int(LOC / 2.0), out_dir_12) + gen_state_var.process(int(LOC / 1.8333333333333333), out_dir_12) + + out_dir_11 = os.path.join(out_dir, '1.1') + try: + os.mkdir(out_dir_11) + except Exception as e: + raise e + gen_builtin_components_11.process(int(LOC / 11.363636363636363), out_dir_11) + gen_custom_components_11.process(int(LOC / 19.0), out_dir_11) + gen_many_import_11.process(int(LOC * 0.1), out_dir_11) + gen_resource_reference_11.process(int(LOC / 2.0), out_dir_11) + gen_state_var_11.process(int(LOC / 1.8333333333333333), out_dir_11) + + print("\033[32m========= Generate successful, results saved to ./gen-benchmark/out =========\033[0m") diff --git a/arkui-plugins/test/gen-benchmark/requirements.txt b/arkui-plugins/test/gen-benchmark/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..77dc03e32fca649bba8b6eaa128334396ab4cce5 --- /dev/null +++ b/arkui-plugins/test/gen-benchmark/requirements.txt @@ -0,0 +1,3 @@ +pandas +dataclasses +chardet \ No newline at end of file diff --git a/arkui-plugins/test/package.json b/arkui-plugins/test/package.json index 34fcd06f257643b847cfab3cd038ba33af3a21fb..2d916a9e5136bb8481d36897d23ef0676bc38eee 100644 --- a/arkui-plugins/test/package.json +++ b/arkui-plugins/test/package.json @@ -12,7 +12,8 @@ "clean:all": "npm run clean:localtest && npm run clean:test", "test": "npm run clean:all && npm run compile:plugins && cd .. && npm run test", "test:gdb": "npm run clean:all && npm run compile:plugins && cd .. && npm run test:gdb", - "localtest": "rm -rf dist && node localtest_config.js && npm run compile:plugins && LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_config.json", + "gen_benchmark": "pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r gen-benchmark/requirements.txt >/dev/null && python3 gen-benchmark/main.py", + "localtest": "rm -f performance.log output.csv && rm -rf dist && node localtest_config.js && npm run compile:plugins && LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_config.json && pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r performance-analyser/requirements.txt >/dev/null && python3 performance-analyser/collect_duration.py", "localtest_gdb": "LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib gdb --args node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_config.json", "localtest_decl": "rm -rf dist && node localtest_decl_config.js && npm run compile:plugins && LD_LIBRARY_PATH=$INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/ets2panda/lib node $INIT_CWD/../../../../out/sdk/ohos-sdk/linux/ets/ets1.2/build-tools/driver/build-system/dist/entry.js ./demo/localtest/build_decl_config.json", "localtest_all": "npm run localtest_decl && npm run localtest", diff --git a/arkui-plugins/test/performance-analyser/collect_duration.py b/arkui-plugins/test/performance-analyser/collect_duration.py new file mode 100644 index 0000000000000000000000000000000000000000..782e00133afa9618e9c9411d2bc92e350ca5df8b --- /dev/null +++ b/arkui-plugins/test/performance-analyser/collect_duration.py @@ -0,0 +1,109 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt + +import re +from collections import defaultdict +import pandas as pd +from dataclasses import dataclass +import os +import chardet + +NEED_FLAG_LIST = [ + 'plugin total', + 'memo-checked', + 'memo-recheck', + 'ui-parsed', + 'ui-recheck', + 'ui-checked', + 'ui-syntax' +] + +OUTPUT_CSV = 'output.csv' +LOG_FILE = 'performance.log' +ENCODING = '' +if os.name == 'nt': + ENCODING = 'GBK' +else: + ENCODING = 'UTF-8' + + +@dataclass(frozen=True) +class CompileTask: + file_name: str + compile_type: str + + +def analyze_performance_logs(log_content): + task_pattern = re.compile(r'\[PERFORMANCE\] ===== FINAL RESULT START ====(.*?)\[PERFORMANCE\] ===== FINAL RESULT END ====', re.DOTALL) + tasks = task_pattern.findall(log_content) + file_totals = defaultdict(lambda: defaultdict(float)) + + for task in tasks: + lines = [line.strip() for line in task.split('\n') if line.strip()] + file_name = re.match(r'\s*filePath:\s*(.*)\s*', lines[0]).group(1) + compile_type = re.match(r'\s*compileType:\s*(.*)\s*', lines[1]).group(1) + task = CompileTask(file_name, compile_type) + + for line in lines: + stage_match = re.match(r'^([^:]+):[^\(]+\((.*)\)', line) + if stage_match is None: + continue + stage_name = stage_match.group(1).strip() + if stage_name.startswith('- '): + stage_name = stage_name[2:] + if stage_name == 'TOTAL': + stage_name = 'plugin total' + if stage_name in NEED_FLAG_LIST: + ms = stage_match.group(2).strip() + file_totals[task][stage_name] += float(ms) + + return file_totals + + +def detect_encoding(file_path): + with open(file_path, 'rb') as f: + raw_data = f.read() + result = chardet.detect(raw_data) + return result['encoding'] + + +def collect_duration(): + log_encoding = detect_encoding(LOG_FILE) + with open(LOG_FILE, 'r', encoding=log_encoding) as f: + log_content = f.read() + file_totals = analyze_performance_logs(log_content) + + data = [] + for task, metrics in file_totals.items(): + row = { + 'file_name': task.file_name, + 'compile_type': task.compile_type, + **metrics + } + data.append(row) + df = pd.DataFrame(data) + columns_order = ['file_name', 'compile_type'] + [col for col in NEED_FLAG_LIST if col != 'plugin total'] + ['plugin total'] + valid_columns = [col for col in columns_order if col in df.columns] + df = df[valid_columns] + + df.loc[-1] = ['', '汇总行'] + df.iloc[:, 2:].sum().tolist() + df.sort_values('plugin total', ascending=False, inplace=True) + df.to_csv(OUTPUT_CSV, index=False, encoding=ENCODING) + +if __name__ == "__main__": + collect_duration() + print("\033[32m========= Performance results saved to output.csv =========\033[0m") \ No newline at end of file diff --git a/arkui-plugins/test/performance-analyser/requirements.txt b/arkui-plugins/test/performance-analyser/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..77dc03e32fca649bba8b6eaa128334396ab4cce5 --- /dev/null +++ b/arkui-plugins/test/performance-analyser/requirements.txt @@ -0,0 +1,3 @@ +pandas +dataclasses +chardet \ No newline at end of file diff --git a/arkui-plugins/ui-plugins/index.ts b/arkui-plugins/ui-plugins/index.ts index a50014ecfaaa4482de0f3059feb2b273b93a3327..74e67ea1b207af2cc4d35b2a5e25b441d08f85d8 100644 --- a/arkui-plugins/ui-plugins/index.ts +++ b/arkui-plugins/ui-plugins/index.ts @@ -118,7 +118,7 @@ function checkedTransform(this: PluginContext): arkts.EtsScript | undefined { arkts.recheckSubtree(script); arkts.Performance.getInstance().stopEvent('ui-recheck', false); arkts.Performance.getInstance().clearAllEvents(false); - arkts.Performance.getInstance().visualizeEvents(true); + arkts.Performance.getInstance().visualizeEvents(true, this.getCompileJob()?.filePath, this.getCompileJob()?.compileType); arkts.Performance.getInstance().clearHistory(); arkts.Performance.getInstance().clearTotalDuration(); this.setArkTSAst(script); diff --git a/arkui-plugins/ui-syntax-plugins/index.ts b/arkui-plugins/ui-syntax-plugins/index.ts index 53232081ede8d769c434e28a3bbb0b038e6a304f..006f5dd68f3f63cbab2d770062c78dfcd29b338b 100644 --- a/arkui-plugins/ui-syntax-plugins/index.ts +++ b/arkui-plugins/ui-syntax-plugins/index.ts @@ -20,25 +20,29 @@ import { createUISyntaxRuleProcessor } from './processor'; import rules from './rules'; export function uiSyntaxLinterTransform(): Plugins { - const processor = createUISyntaxRuleProcessor(rules); - return { - name: 'ui-syntax-plugin', - parsed(this: PluginContext): arkts.EtsScript | undefined { - const contextPtr = arkts.arktsGlobal.compilerContext?.peer ?? this.getContextPtr(); - if (!contextPtr) { - return undefined; - } - let program = arkts.getOrUpdateGlobalContext(contextPtr).program; - const node = program.astNode; - if (node) { - const script = new ParsedUISyntaxLinterTransformer(processor).visitor( - node, - ) as arkts.EtsScript; - arkts.setAllParents(script); - this.setArkTSAst(script); - return script; - } - return undefined; - } - }; + const processor = createUISyntaxRuleProcessor(rules); + return { + name: 'ui-syntax-plugin', + parsed(this: PluginContext): arkts.EtsScript | undefined { + const contextPtr = this.getContextPtr() ?? arkts.arktsGlobal.compilerContext?.peer; + if (!contextPtr) { + return undefined; + } + let program = arkts.getOrUpdateGlobalContext(contextPtr).program; + const node = program.astNode; + if (node) { + arkts.Performance.getInstance().createEvent('ui-syntax'); + const script = new ParsedUISyntaxLinterTransformer(processor).visitor(node) as arkts.EtsScript; + arkts.setAllParents(script); + this.setArkTSAst(script); + arkts.Performance.getInstance().stopEvent('ui-syntax', false); + arkts.Performance.getInstance().clearAllEvents(false); + arkts.Performance.getInstance().visualizeEvents(true, this.getCompileJob()?.filePath, this.getCompileJob()?.compileType); + arkts.Performance.getInstance().clearHistory(); + arkts.Performance.getInstance().clearTotalDuration(); + return script; + } + return undefined; + }, + }; } diff --git a/koala-wrapper/src/arkts-api/utilities/performance.ts b/koala-wrapper/src/arkts-api/utilities/performance.ts index c938de34c133bf65a15d51689e47623741fe87ec..944ece2ec2050ebc8777299ae24e3b85d9157e8f 100644 --- a/koala-wrapper/src/arkts-api/utilities/performance.ts +++ b/koala-wrapper/src/arkts-api/utilities/performance.ts @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import * as fs from 'fs'; interface Event { name: string, @@ -159,7 +160,7 @@ export class Performance { this.historyEvents = new Map(); } - visualizeEvents(shouldLog: boolean = false): void { + visualizeEvents(shouldLog: boolean = false, filePath: string = '', compileType: string = ''): void { if (this.shouldSkip) { return; } @@ -181,10 +182,19 @@ export class Performance { const [finalResult, _] = buildVisualization(null, 0); if (shouldLog) { - console.log(`[PERFORMANCE] ===== FINAL RESULT ====`); + console.log(`[PERFORMANCE] ===== FINAL RESULT START ====`); + console.log(`filePath: ${filePath}`); + console.log(`compileType: ${compileType}`); console.log(`TOTAL: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})`); console.log(finalResult.trimEnd()); - console.log(`[PERFORMANCE] ===== FINAL RESULT ====`); + console.log(`[PERFORMANCE] ===== FINAL RESULT END ====`); + + fs.appendFileSync('./performance.log', `[PERFORMANCE] ===== FINAL RESULT START ====\n`); + fs.appendFileSync('./performance.log', `filePath: ${filePath}\n`); + fs.appendFileSync('./performance.log', `compileType: ${compileType}\n`); + fs.appendFileSync('./performance.log', `TOTAL: ${formatTime(this.totalDuration)}(${round(this.totalDuration)})\n`); + fs.appendFileSync('./performance.log', finalResult.trimEnd() + '\n'); + fs.appendFileSync('./performance.log', `[PERFORMANCE] ===== FINAL RESULT END ====\n`); } } } \ No newline at end of file