Use relative symlink for AOTC accepted/tizen_unified accepted/tizen_unified_dev accepted/tizen_unified_x tizen accepted/tizen/unified/20240909.100119 accepted/tizen/unified/dev/20240910.111451 accepted/tizen/unified/x/20240910.014311
authorWoongsuk Cho <ws77.cho@samsung.com>
Sun, 8 Sep 2024 23:23:53 +0000 (08:23 +0900)
committer조웅석/MDE Lab(SR)/삼성전자 <ws77.cho@samsung.com>
Mon, 9 Sep 2024 01:47:34 +0000 (10:47 +0900)
In VD cases, an app is temporarily installed in a temporal location
and then moved to its actual location during device booting.

When the app is installed at the temporary location, if AOTC runs,
it creates internal symlinks for ni.dll and pdb.
If these symlinks are created based on absolute paths,
they will point to incorrect locations when the app's position changes later.

To resolve this issue, modify the code so that symlinks are generated using relative paths.

209 files changed:
.github/CODEOWNERS [new file with mode: 0644]
.github/gbs.conf [new file with mode: 0644]
.github/workflows/gbs-build.yml [new file with mode: 0644]
.github/workflows/launcher-action.yml [new file with mode: 0644]
.gitignore
NativeLauncher/CMakeLists.txt
NativeLauncher/dotnet.debugger
NativeLauncher/hydra/hydra_main.cc
NativeLauncher/inc/launcher_env.h
NativeLauncher/inc/ni_common.h
NativeLauncher/inc/path_manager.h
NativeLauncher/inc/tac_common.h
NativeLauncher/inc/tac_db.h
NativeLauncher/inc/utils.h
NativeLauncher/installer-plugin/prefer_dotnet_aot_plugin.cc
NativeLauncher/launcher/lib/core_runtime.cc
NativeLauncher/launcher/lib/injection.cc
NativeLauncher/launcher/lib/injection.h
NativeLauncher/tool/dotnettool.cc
NativeLauncher/tool/multi_target_resolver.cc
NativeLauncher/tool/ni_common.cc
NativeLauncher/tool/tac_common.cc
NativeLauncher/tool/tac_db.cc
NativeLauncher/tool/tac_installer.cc
NativeLauncher/util/path_manager.cc
NativeLauncher/util/utils.cc
dotnet-launcher.manifest
packaging/715.dotnet_regen_app_ni.patch.sh
packaging/dotnet-launcher.spec
scripts/github-comment.sh [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.sln [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.cs [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.csproj [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/shared/res/Launcher_TC_EXCEPTION_01.png [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/tizen-manifest.xml [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.sln [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.cs [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.csproj [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/shared/res/Launcher_TC_EXCEPTION_02.png [new file with mode: 0755]
tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/tizen-manifest.xml [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.sln [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Directory.Build.targets [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.cs [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.csproj [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/aarch64/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/arm/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/arm64/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/armel/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/riscv64/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/x64/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/x86/test.so [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/shared/res/Launcher_TC_PLUGIN_11.png [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/tizen-manifest.xml [new file with mode: 0755]
tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/tizen_dotnet_project.yaml [new file with mode: 0755]
tests/Benchmark/TizenBenchmark/Directory.Build.targets [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroArguments.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroArgumentsSource.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroArrayParam.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroBasic.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroBenchmarkBaseline.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroCategories.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroCategoryBaseline.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroCategoryDiscoverer.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroColdStart.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroComparableComplexParam.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroConfigSource.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroConfigUnion.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroCustomMono.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroCustomMonoArguments.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroDeferredExecution.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroDisassembly.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyAllJits.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyDry.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyRyuJit.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroDotTraceDiagnoser.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroEnvVars.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroEventPipeProfiler.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroEventPipeProfilerAdvanced.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroExport.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroExportJson.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroExportXml.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroFilters.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroFluentConfigBuilder.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroGcMode.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroGenericTypeArguments.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroHardwareCounters.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroInProcess.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroInProcessWrongEnv.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroInliningDiagnoser.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroJitStatsDiagnoser.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroJobBaseline.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroJoin.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroLargeAddressAware.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroMonitoring.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroMultimodal.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroNativeMemory.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroNuGet.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroOrderAttr.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroOrderManual.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroOutliers.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroParams.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroParamsAllValues.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroParamsSource.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroPercentiles.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroPowerPlan.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroRankColumn.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroRatioSD.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroRatioStyle.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupGlobal.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupIteration.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupTarget.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroStaThread.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroStatisticalTesting.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroStatisticsColumns.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroStopOnFirstError.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroTagColumn.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroTailcall.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroUnicode.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/IntroWasm.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/Intro/TizenDotnet.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/TizenBenchmark.cs [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/TizenBenchmark.csproj [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/shared/res/TizenBenchmark.png [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/tizen-manifest.xml [new file with mode: 0644]
tests/Benchmark/TizenBenchmark/tizen_dotnet_project.yaml [new file with mode: 0644]
tests/Benchmark/org.tizen.dotnet.TizenBenchmark-1.0.0.tpk [new file with mode: 0644]
tests/GC/AndroidGCTest/.gitignore [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/.gitignore [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/compiler.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/deploymentTargetSelector.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/gradle.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/migrations.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/misc.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/.idea/other.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/.gitignore [new file with mode: 0644]
tests/GC/AndroidGCTest/app/achartengine/achartengine-1.2.0.jar [new file with mode: 0644]
tests/GC/AndroidGCTest/app/build.gradle [new file with mode: 0644]
tests/GC/AndroidGCTest/app/proguard-rules.pro [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/androidTest/java/com/android/gctest/ExampleInstrumentedTest.java [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/AndroidManifest.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/AndroidGCTestMain.java [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/MainActivity.java [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/Profile.java [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/ProfileSettingActivity.java [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/ResultActivity.java [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/drawable/ic_launcher_background.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/drawable/ic_launcher_foreground.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/layout/activity_main.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/layout/activity_profile_config.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/layout/activity_result.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/menu/main.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-anydpi/ic_launcher.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/raw/profile.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/values-night/themes.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/values/colors.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/values/dimens.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/values/strings.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/values/styles.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/values/themes.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/xml/backup_rules.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/main/res/xml/data_extraction_rules.xml [new file with mode: 0644]
tests/GC/AndroidGCTest/app/src/test/java/com/android/gctest/ExampleUnitTest.java [new file with mode: 0644]
tests/GC/AndroidGCTest/build.gradle [new file with mode: 0644]
tests/GC/AndroidGCTest/gradle.properties [new file with mode: 0644]
tests/GC/AndroidGCTest/gradle/libs.versions.toml [new file with mode: 0644]
tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.jar [new file with mode: 0644]
tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.properties [new file with mode: 0644]
tests/GC/AndroidGCTest/gradlew [new file with mode: 0755]
tests/GC/AndroidGCTest/gradlew.bat [new file with mode: 0644]
tests/GC/AndroidGCTest/settings.gradle [new file with mode: 0644]
tests/GC/TizenGCTest/Directory.Build.targets [new file with mode: 0755]
tests/GC/TizenGCTest/GCTest.cs [new file with mode: 0755]
tests/GC/TizenGCTest/Profile.cs [new file with mode: 0755]
tests/GC/TizenGCTest/TizenGCTest.cs [new file with mode: 0755]
tests/GC/TizenGCTest/TizenGCTest.csproj [new file with mode: 0755]
tests/GC/TizenGCTest/res/profile.xml [new file with mode: 0755]
tests/GC/TizenGCTest/shared/res/TizenGCTest.png [new file with mode: 0755]
tests/GC/TizenGCTest/tizen-manifest.xml [new file with mode: 0755]
tests/GC/TizenGCTest/tizen_dotnet_project.yaml [new file with mode: 0755]
tests/Performance/measure [new file with mode: 0755]
tests/Performance/org.tizen.example.AppCommon.Tizen.Mobile-1.0.0.tpk [new file with mode: 0755]
tests/Performance/org.tizen.example.ApplicationControl.Tizen.Mobile-1.0.0.tpk [new file with mode: 0755]
tests/Performance/org.tizen.example.Puzzle.Tizen.Mobile-1.0.0.tpk [new file with mode: 0755]
tests/Performance/org.tizen.example.Settings.Tizen.Mobile-1.0.0.tpk [new file with mode: 0755]
tests/Performance/org.tizen.example.System_info.Tizen.Mobile-1.0.0.tpk [new file with mode: 0755]
tests/Performance/org.tizen.example.Xamarin.Hello.F_HUB.Tizen-1.0.0.tpk [new file with mode: 0755]
tests/TCs/1_AOT/AOT.py
tests/TCs/2_PLUGIN/PLUGIN.py
tests/TCs/3_PRELOAD/PRELOAD.py
tests/TCs/4_TAC/TAC_RO.py [new file with mode: 0755]
tests/TCs/4_TAC/TAC_RW.py [moved from tests/TCs/4_TAC/TAC.py with 98% similarity]
tests/TCs/5_TLC/TLC.py
tests/TCs/6_TOOL/TOOL.py
tests/TCs/7_EXCEPTION/EXCEPTION.py [new file with mode: 0755]
tests/TCs/8_LAUNCH/LAUNCH.py [moved from tests/TCs/7_LAUNCH/LAUNCH.py with 98% similarity]
tests/TCs/8_LAUNCH/README.md [moved from tests/TCs/7_LAUNCH/README.md with 100% similarity]
tests/TCs/ALL.py
tests/TCs/Utils.py

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644 (file)
index 0000000..82a84e7
--- /dev/null
@@ -0,0 +1 @@
+* @ws77-cho @leee-lee @dheon-jung @j-h-choi
diff --git a/.github/gbs.conf b/.github/gbs.conf
new file mode 100644 (file)
index 0000000..8b7d01e
--- /dev/null
@@ -0,0 +1,42 @@
+[profile.Tizen-Unified]
+repos = repo.Unified_base, repo.Unified_main
+buildroot = .GBS-ROOT/launcher-Unified
+
+[profile.Tizen-Unified-X]
+repos = repo.Unified_x_base, repo.Unified_x_main
+buildroot = .GBS-ROOT/launcher-Unified-X
+
+[profile.VD-PontusM]
+repos = repo.VD_base, repo.VD_PontusM_main
+buildroot = .GBS-ROOT/launcher-PontusM
+
+[profile.VD-KantSU2e]
+repos = repo.VD_base, repo.VD_KantSU2e_main
+buildroot = .GBS-ROOT/launcher-KantSU2e
+
+[profile.da]
+repos = repo.DA_base, repo.DA_main
+
+
+[repo.Unified_base]
+url = http://download.tizen.org/snapshots/TIZEN/Tizen/Tizen-Base/latest/repos/standard/packages/
+[repo.Unified_main]
+url = http://download.tizen.org/snapshots/TIZEN/Tizen/Tizen-Unified/latest/repos/standard/packages/
+
+[repo.Unified_x_base]
+url = http://download.tizen.org/snapshots/TIZEN/Tizen/Tizen-Base-X/latest/repos/standard/packages/
+[repo.Unified_x_main]
+url = http://download.tizen.org/snapshots/TIZEN/Tizen/Tizen-Unified-X/latest/repos/standard/packages/
+
+[repo.VD_base]
+url = http://168.219.244.109/base/current/standard/latest/repos/base/armv7l/packages/
+[repo.VD_PontusM_main]
+url = http://168.219.244.109/products/tv/official/2025/ONEMAIN/PontusM_ATSC/latest/repos/product/armv7l/packages/
+[repo.VD_KantSU2e_main]
+url = http://168.219.244.109/products/tv/official/2025/ONEMAIN/KantSU2e_ATSC/latest/repos/product/armv7l/packages/
+
+[repo.DA_base]
+url = http://10.113.136.26/snapshots/DA/Tizen-7.0/Tizen-7.0-DA-Base/latest/repos/standard/packages/
+[repo.DA_main]
+url = http://10.113.136.26/snapshots/DA/Tizen-7.0/Tizen-7.0-DA-Unified/latest/repos/MESON64/packages/
+
diff --git a/.github/workflows/gbs-build.yml b/.github/workflows/gbs-build.yml
new file mode 100644 (file)
index 0000000..2938db8
--- /dev/null
@@ -0,0 +1,207 @@
+name: "GBS build"
+
+on:
+  pull_request_target:
+    branches:
+    - tizen
+
+jobs:
+  Tizen_Unified_armv7l_GBS_Build:
+    runs-on: [ code-linux, code-large ]
+    container:
+      image: actions-docker.bart.sec.samsung.net/docker-gbs-base:ubuntu-20.04
+      options: --user root --privileged
+    steps:
+    - name: Setup .NET
+      uses: code-actions/setup-dotnet@v1
+      with:
+        dotnet-version: '6.0.310'
+
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Build
+      run: |
+        gbs -c .github/gbs.conf build -A armv7l --include-all --clean -P Tizen-Unified
+      if: success()
+
+    - name: Upload artifacts
+      uses: code-actions/upload-artifact@v3
+      with:
+        name: launcher-rpm-Tizen-Unified-armv7l
+        path: .GBS-ROOT/launcher-Unified/local/repos/Tizen_Unified/armv7l/RPMS/*.rpm
+      if: success()
+
+    - name: Leave comment
+      if: failure()
+      uses: code-actions/github-script@v5
+      with:
+        script: |
+          github.rest.issues.createComment({
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            issue_number: context.issue.number,
+            body: 'Please check the build status of Tizen_Unified_armv7l.'
+          })
+
+  Tizen_Unified_X_armv7l_GBS_Build:
+    runs-on: [ code-linux, code-large ]
+    container:
+      image: actions-docker.bart.sec.samsung.net/docker-gbs-base:ubuntu-20.04
+      options: --user root --privileged
+    steps:
+    - name: Setup .NET
+      uses: code-actions/setup-dotnet@v1
+      with:
+        dotnet-version: '6.0.310'
+
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Build
+      run: |
+        gbs -c .github/gbs.conf build -A armv7l --include-all --clean -P Tizen-Unified-X
+      if: success()
+
+    - name: Upload artifacts
+      uses: code-actions/upload-artifact@v3
+      with:
+        name: launcher-rpm-Tizen-Unified-X-RPI4-armv7l
+        path: .GBS-ROOT/launcher-Unified-X/local/repos/Tizen_Unified_X/armv7l/RPMS/*.rpm
+      if: success()
+
+    - name: Leave comment
+      if: failure()
+      uses: code-actions/github-script@v5
+      with:
+        script: |
+          github.rest.issues.createComment({
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            issue_number: context.issue.number,
+            body: 'Please check the build status of Tizen_Unified_X_armv7l.'
+          })
+
+  Tizen_Unified_X_riscv64_GBS_Build:
+    runs-on: [ code-linux, code-large ]
+    container:
+      image: actions-docker.bart.sec.samsung.net/docker-gbs-base:ubuntu-20.04
+      options: --user root --privileged
+    steps:
+    - name: Setup .NET
+      uses: code-actions/setup-dotnet@v1
+      with:
+        dotnet-version: '6.0.310'
+
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Build
+      run: |
+        gbs -c .github/gbs.conf build -A riscv64 --include-all --clean -P Tizen-Unified-X
+      if: success()
+
+    - name: Upload artifacts
+      uses: code-actions/upload-artifact@v3
+      with:
+        name: launcher-rpm-Tizen-Unified-X-VF2-riscv64
+        path: .GBS-ROOT/launcher-Unified-X/local/repos/Tizen_Unified_X/riscv64/RPMS/*.rpm
+      if: success()
+
+    - name: Leave comment
+      if: failure()
+      uses: code-actions/github-script@v5
+      with:
+        script: |
+          github.rest.issues.createComment({
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            issue_number: context.issue.number,
+            body: 'Please check the build status of Tizen_Unified_X_riscv64.'
+          })
+
+#  VD_PontusM_armv7l_GBS_Build:
+#    runs-on: [ code-linux, code-large ]
+#    container:
+#      image: actions-docker.bart.sec.samsung.net/docker-gbs-base:ubuntu-20.04
+#      options: --user root --privileged
+#    steps:
+#    - name: Setup .NET
+#      uses: code-actions/setup-dotnet@v1
+#      with:
+#        dotnet-version: '6.0.310'
+
+#    - name: Checkout
+#      uses: code-actions/checkout@v3
+#      with:
+#        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+#    - name: Build
+#      run: |
+#        gbs -c .github/gbs.conf build -A armv7l --include-all --clean -P VD-PontusM
+#      if: success()
+
+#    - name: Upload artifacts
+#      uses: code-actions/upload-artifact@v3
+#      with:
+#        name: launcher-rpm-VD-PontusM-armv7l
+#        path: .GBS-ROOT/launcher-PontusM/local/repos/VD_PontusM/armv7l/RPMS/*.rpm
+#      if: success()
+
+#    - name: Leave comment
+#      if: failure()
+#      uses: code-actions/github-script@v5
+#      with:
+#        script: |
+#          github.rest.issues.createComment({
+#            owner: context.repo.owner,
+#            repo: context.repo.repo,
+#            issue_number: context.issue.number,
+#            body: 'Please check the build status of VD_PontusM_armv7l.'
+#          })
+
+#  VD_KantSU2e_armv7l_GBS_build:
+#    runs-on: [ code-linux, code-large ]
+#    container:
+#      image: actions-docker.bart.sec.samsung.net/docker-gbs-base:ubuntu-20.04
+#      options: --user root --privileged
+#    steps:
+#    - name: Setup .NET
+#      uses: code-actions/setup-dotnet@v1
+#      with:
+#        dotnet-version: '6.0.310'
+
+#    - name: Checkout
+#      uses: code-actions/checkout@v3
+#        with:
+#          ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+#    - name: Build
+#      run: |
+#        gbs -c .github/gbs.conf build -A armv7l --include-all -P VD-KantSU2e
+#      if: success()
+
+#    - name: Upload artifacts
+#      uses: code-actions/upload-artifact@v3
+#      with:
+#        name: launcher-rpm-VD-KantSU2e-armv7l
+#        path: .GBS-ROOT/launcher-KantSU2e/local/repos/VD_KantSU2e/armv7l/RPMS/*.rpm
+#      if: success()
+
+#    - name: Leave comment
+#      if: failure()
+#      uses: code-actions/github-script@v5
+#      with:
+#        script: |
+#          github.rest.issues.createComment({
+#            owner: context.repo.owner,
+#            repo: context.repo.repo,
+#            issue_number: context.issue.number,
+#            body: 'Please check the build status of VD_KantSU2e_armv7l.'
+#          })
diff --git a/.github/workflows/launcher-action.yml b/.github/workflows/launcher-action.yml
new file mode 100644 (file)
index 0000000..a4ccb5e
--- /dev/null
@@ -0,0 +1,290 @@
+name: "Launcher Action"
+
+on:
+  pull_request_target:
+    branches:
+    - tizen
+
+jobs:
+  Tizen_RPI4_Flash:
+    runs-on: [ self-hosted ]
+    steps:
+    - name: RPI4_Flash
+      shell: bash
+      run: |
+        dude download -k > ./dude.log
+        sleep 60
+        sdb devices
+      if: success()
+
+  Tizen_Unified_armv7l_GBS_Build:
+    runs-on: [ code-linux, code-large ]
+    container:
+      image: actions-docker.bart.sec.samsung.net/docker-gbs-base:ubuntu-20.04
+      options: --user root --privileged
+    steps:
+    - name: Setup .NET
+      uses: code-actions/setup-dotnet@v1
+      with:
+        dotnet-version: '6.0.310'
+
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Build
+      run: |
+        gbs -c .github/gbs.conf build -A armv7l --include-all --clean -P Tizen-Unified
+      if: success()
+
+    - name: Upload artifacts
+      uses: code-actions/upload-artifact@v3
+      with:
+        name: launcher-rpm-Tizen-Unified-armv7l
+        path: .GBS-ROOT/launcher-Unified/local/repos/Tizen_Unified/armv7l/RPMS/*.rpm
+      if: success()
+
+    - name: Leave comment
+      if: failure()
+      uses: code-actions/github-script@v5
+      with:
+        script: |
+          github.rest.issues.createComment({
+            owner: context.repo.owner,
+            repo: context.repo.repo,
+            issue_number: context.issue.number,
+            body: 'Please check the build status of Tizen_Unified_armv7l.'
+          })
+
+  Tizen_Unified_launcher_performance:
+    runs-on: [ self-hosted ]
+    needs: [Tizen_RPI4_Flash, Tizen_Unified_armv7l_GBS_Build]
+    steps:
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Connect RPI4
+      shell: bash
+      run: |
+        sdb devices
+        sdb -d root on
+        sdb -d shell mount -o remount,rw /
+        sdb -d shell osu --resize
+        echo "device 10000000d15e1aff is ready."
+      if: success()
+
+    - name: Download artifacts
+      uses: code-actions/download-artifact@v3
+      with:
+        name: launcher-rpm-Tizen-Unified-armv7l
+        path: ./
+      if: success()
+
+    - name: Install App
+      shell: bash
+      run: |
+        sdb -d install ./tests/Performance/org.tizen.example.AppCommon.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.ApplicationControl.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.Puzzle.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.Settings.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.System_info.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.Xamarin.Hello.F_HUB.Tizen-1.0.0.tpk
+      if: success()
+
+    - name: Run Performance Before PR
+      shell: bash
+      run: |
+        ./tests/Performance/measure -o ./tests/Performance/result_before.log
+      if: success()
+
+    - name: Install RPM
+      shell: bash
+      run: |
+        ls ./
+        sdb -d shell rm /root/dotnet-launcher-*.rpm
+        sdb -d push ./dotnet-launcher-[0-9]*.armv7l.rpm /root
+        sdb -d shell rpm -Uvh --force /root/dotnet-launcher-[0-9]*.armv7l.rpm
+        sdb -d shell "setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet && setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-loader && setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-launcher && setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-hydra-loader"
+        sdb -d shell "killall -9 dotnet-loader"
+        sleep 30
+      if: success()
+
+    - name: Install App
+      shell: bash
+      run: |
+        sdb -d install ./tests/Performance/org.tizen.example.AppCommon.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.ApplicationControl.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.Puzzle.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.Settings.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.System_info.Tizen.Mobile-1.0.0.tpk
+        sdb -d install ./tests/Performance/org.tizen.example.Xamarin.Hello.F_HUB.Tizen-1.0.0.tpk
+      if: success()
+
+    - name: Run Performance After PR
+      shell: bash
+      run: |
+        ./tests/Performance/measure -o ./tests/Performance/result_after.log
+      if: success()
+
+    - name: Compare Performance
+      shell: bash
+      run: |
+        echo "### Before Performance Result ###" > ./tests/Performance/result.log
+        ./tests/Performance/measure -f ./tests/Performance/result_before.log >> ./tests/Performance/result.log
+        echo -e "\n### After Performance Result ###" >> ./tests/Performance/result.log
+        ./tests/Performance/measure -f ./tests/Performance/result_after.log >> ./tests/Performance/result.log
+        echo -e "\n### Compare Performance Result ###" >> ./tests/Performance/result.log
+        ./tests/Performance/measure --compare ./tests/Performance/result_before.log ./tests/Performance/result_after.log >> ./tests/Performance/result.log
+      if: success()
+
+    - name: Result Performance
+      shell: bash
+      run: |
+        cat ./tests/Performance/result.log
+        sed -i '1s/^/\`\`\`\n/' ./tests/Performance/result.log
+        echo -e "\n" >> ./tests/Performance/result.log
+        sdb -d shell "cat /etc/info.ini" >> ./tests/Performance/result.log
+        echo "\`\`\`" >> ./tests/Performance/result.log
+      if: success()
+
+    - name: Comment Result
+      run: |
+        ./scripts/github-comment.sh ${{github.event.pull_request.number}} ./tests/Performance/result.log
+      if: success()
+
+  Tizen_Unified_launcher_tc:
+    runs-on: [ self-hosted ]
+    needs: Tizen_Unified_launcher_performance
+    steps:
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Build TC
+      shell: bash
+      run: |
+        ./tests/Apps/BuildTPK.py
+      if: success()
+
+    - name: Connect RPI4
+      shell: bash
+      run: |
+        sdb devices
+        sdb -d root on
+        sdb -d shell mount -o remount,rw /
+        sdb -d shell osu --resize
+        echo "device 10000000d15e1aff is ready."
+      if: success()
+
+    - name: Download artifacts
+      uses: code-actions/download-artifact@v3
+      with:
+        name: launcher-rpm-Tizen-Unified-armv7l
+        path: ./
+      if: success()
+
+    - name: Install RPM
+      shell: bash
+      run: |
+        ls ./
+        sdb -d shell rm /root/dotnet-launcher-*.rpm
+        sdb -d push ./dotnet-launcher-[0-9]*.armv7l.rpm /root
+        sdb -d shell rpm -Uvh --force /root/dotnet-launcher-[0-9]*.armv7l.rpm
+        sdb -d shell "setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet && setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-loader && setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-launcher && setcap cap_setgid,cap_sys_admin+ei /usr/bin/dotnet-hydra-loader"
+        sdb -d shell "killall -9 dotnet-loader"
+        sdb -d shell "cat /etc/info.ini" >> ./tests/TCs/device.info
+        sleep 30
+      if: success()
+
+    - name: Run TC
+      shell: bash
+      run: |
+        ./tests/TCs/ALL.py
+      if: success()
+
+    - name: Result TC
+      shell: bash
+      run: |
+        cat ./tests/TCs/result.log
+        sed -i '1s/^/\`\`\`\n/' ./tests/TCs/result.log
+        echo -e "\n" >> ./tests/TCs/result.log
+        cat ./tests/TCs/device.info >> ./tests/TCs/result.log
+        echo "\`\`\`" >> ./tests/TCs/result.log
+      if: success()
+
+    - name: Comment Result
+      run: |
+        ./scripts/github-comment.sh ${{github.event.pull_request.number}} ./tests/TCs/result.log
+      if: success()
+
+  Tizen_Dotnet_Benchmark:
+    runs-on: [ self-hosted ]
+    needs: Tizen_Unified_launcher_tc
+    steps:
+    - name: Checkout
+      uses: code-actions/checkout@v3
+      with:
+        ref: refs/pull/${{ github.event.pull_request.number }}/head
+
+    - name: Connect RPI4
+      shell: bash
+      run: |
+        sleep 60
+        sdb devices
+        sdb -d root on
+        sdb -d shell mount -o remount,rw /
+        echo "device 10000000d15e1aff is ready."
+      if: success()
+
+    - name: Install App
+      shell: bash
+      run: |
+        sdb -d install ./tests/Benchmark/org.tizen.dotnet.TizenBenchmark-1.0.0.tpk
+      if: success()
+
+    - name: Run Benchmark
+      shell: bash
+      run: |
+        sdb -d shell "rm /tmp/BenchmarkDotnet/*.log"
+        sdb -d shell "app_launcher -k org.tizen.dotnet.TizenBenchmark"
+        sdb -d shell "app_launcher -s org.tizen.dotnet.TizenBenchmark"
+      if: success()
+
+    - name: Print&Pull Log
+      shell: bash
+      run: |
+        sdb shell "dlogutil -c"
+        sdb shell "dlogutil -v time STDOUT" > stdout.log &
+        DLOG_STREAMER_PID=$!
+        echo $DLOG_STREAMER_PID
+        while inotifywait -qqre modify stdout.log;
+        do
+            GET_LOG="$(tail -1 stdout.log)"
+            echo $GET_LOG
+            if [[ $GET_LOG =~ "##### Tizen.NET Benchmark END #####" ]]; then
+                sdb -d pull /tmp/BenchmarkDotnet ./tests/Benchmark/
+                kill -9 $DLOG_STREAMER_PID > /dev/null 2>&1
+                break
+            fi
+        done
+      if: success()
+
+    - name: Result Benchmark
+      run: |
+        echo "\`\`\`" > ./tests/Benchmark/benchmark.result
+        for file in ./tests/Benchmark/*.log; do if [[ $file =~ "BenchmarkRun-" ]]; then continue; fi; echo $file; sed -n '/ Summary /,/ Legends /p' $file | grep -v '*'; done >> ./tests/Benchmark/benchmark.result
+        echo -e "\n" >> ./tests/Benchmark/benchmark.result
+        sdb -d shell "cat /etc/info.ini" >> ./tests/Benchmark/benchmark.result
+        echo "\`\`\`" >> ./tests/Benchmark/benchmark.result
+        cat ./tests/Benchmark/benchmark.result
+      if: success()
+
+    - name: Comment Result
+      run: |
+        ./scripts/github-comment.sh ${{github.event.pull_request.number}} ./tests/Benchmark/benchmark.result
+      if: success()
+
index 7787ef1..ee19670 100644 (file)
@@ -4,4 +4,4 @@ tags
 .vs/
 [Bb]in/
 [Oo]bj/
-
+.vscode/
index 019d031..bafb9ff 100644 (file)
@@ -55,6 +55,10 @@ IF(DEFINED READ_ONLY_APP_UPDATE_DIR)
     SET(EXTRA_CFLAGS_COMMON "${EXTRA_CFLAGS_COMMON} -DREAD_ONLY_APP_UPDATE_DIR=${READ_ONLY_APP_UPDATE_DIR}")
 ENDIF(DEFINED READ_ONLY_APP_UPDATE_DIR)
 
+IF(DEFINED READ_ONLY_TAC_DIR)
+    SET(EXTRA_CFLAGS_COMMON "${EXTRA_CFLAGS_COMMON} -DREAD_ONLY_TAC_DIR=${READ_ONLY_TAC_DIR}")
+ENDIF(DEFINED READ_ONLY_TAC_DIR)
+
 IF(DEFINED USE_DEFAULT_BASE_ADDR)
     SET(EXTRA_CFLAGS_COMMON "${EXTRA_CFLAGS_COMMON} -DUSE_DEFAULT_BASE_ADDR")
 ENDIF(DEFINED USE_DEFAULT_BASE_ADDR)
index 1f8f89a..cbc31ec 100644 (file)
@@ -102,3 +102,31 @@ DEFAULT_OPT 6003
 DEFAULT_OPT --
 DEFAULT_OPT /home/owner/share/tmp/sdk_tools/netcoredbg/netcoredbg
 EXTRA_KEY __DLP_DEBUG_ARG__
+
+[DEBUGGER]
+NAME MEMORYPROFILER
+EXE /home/owner/share/tmp/sdk_tools/profiler/profctl/profctl
+APP_TYPE dotnet|dotnet-nui
+DEFAULT_OPT -v
+DEFAULT_OPT -f
+DEFAULT_OPT -p
+DEFAULT_OPT /home/owner/share/tmp/sdk_tools/profiler/heaptrack/heaptrack_fifo
+DEFAULT_OPT -w
+DEFAULT_OPT -e
+DEFAULT_OPT /home/owner/share/tmp/sdk_tools/profiler/heaptrack/heaptrack_interpret
+DEFAULT_OPT -o
+DEFAULT_OPT /home/owner/share/tmp/sdk_tools/profiler/profctl/profctl_heaptrack.log
+DEFAULT_OPT -E
+DEFAULT_OPT DUMP_HEAPTRACK_OUTPUT=/home/owner/share/tmp/sdk_tools/profiler/heaptrack/heaptrack_fifo
+DEFAULT_OPT CORECLR_PROFILER={C7BAD323-25F0-4C0B-B354-566390B215CA}
+DEFAULT_OPT CORECLR_PROFILER_PATH=/home/owner/share/tmp/sdk_tools/profiler/heaptrack/libprofiler.so
+DEFAULT_OPT PROF_CONFIG_FILENAME=/home/owner/share/tmp/sdk_tools/profiler/heaptrack/profiler.config
+DEFAULT_OPT CORECLR_ENABLE_PROFILING=1
+DEFAULT_OPT COMPlus_LogEnable=1
+DEFAULT_OPT UNW_ARM_UNWIND_METHOD=4
+DEFAULT_OPT HEAPTRACK_NATIVE_ENABLE=1
+DEFAULT_OPT -c
+DEFAULT_OPT 6005
+DEFAULT_OPT -d
+DEFAULT_OPT 6006
+DEFAULT_OPT --
index 7ced0a3..a1bd3f0 100644 (file)
@@ -123,8 +123,7 @@ static void preloadAssemblies()
        while ((dp = readdir(dirp)) != NULL) {
                if (dp->d_type != DT_DIR) {
                        // Make sure that the file name follows naming conventions.
-                       if (dp->d_name &&
-                               isdigit(dp->d_name[0]) &&
+                       if (isdigit(dp->d_name[0]) &&
                                isdigit(dp->d_name[1]) &&
                                (dp->d_name[2] == '.')) {
                                preloadFiles.insert(preloadDir + dp->d_name);
index 6b24f87..6f38566 100644 (file)
 #define APP_NI_SUB_TMP_DIR           ".native_image_tmp"
 #define TAC_SYMLINK_SUB_DIR          ".tac_symlink"
 #define TAC_SHA_256_INFO             ".SHA256.info"
-#define TAC_APP_LIST_DB              "/opt/usr/dotnet/.TAC.App.list.db"
-#define TAC_APP_LIST_RESTORE_DB      "/opt/usr/dotnet/.TAC.App.list.restore.db"
-#define TLC_APP_LIST_DB              "/opt/usr/dotnet/.TLC.App.list.db"
-#define TLC_APP_LIST_RESTORE_DB      "/opt/usr/dotnet/.TLC.App.list.restore.db"
-#define TLC_LIBRARIES_DIR            "/opt/usr/dotnet/Libraries"
+#define TAC_APP_LIST_DB              ".TAC.App.list.db"
+#define TAC_APP_LIST_RESTORE_DB      ".TAC.App.list.restore.db"
+#define TLC_APP_LIST_DB              ".TLC.App.list.db"
+#define TLC_APP_LIST_RESTORE_DB      ".TLC.App.list.restore.db"
+#define TLC_LIBRARIES_DIR            "Libraries"
 #define TIZEN_DOTNET_NUGET           "Tizen.NET"
 #define TIZEN_DOTNET_SDK_NUGET       "Tizen.NET.Sdk"
 #define NET_STANDARD_LIBRARY_NUGET   "NETStandard.Library"
 #define PRE_COMPILED_PACKAGE_FILE    "._TIZEN_DOTNET_PRE_COMPILED_PACKAGE"
 
 #if defined (__aarch64__)
-#define ARCHITECTURE_IDENTIFIER      "arm64"
+#define ARCHITECTURE_IDENTIFIER              "arm64"
+#define ARCHITECTURE_IDENTIFIER_GENERAL      ARCHITECTURE_IDENTIFIER
 #elif defined (__arm__)
-#define ARCHITECTURE_IDENTIFIER      "armel"
+#define ARCHITECTURE_IDENTIFIER              "armel"
+#define ARCHITECTURE_IDENTIFIER_GENERAL      "arm"
 #elif defined (__x86_64__)
-#define ARCHITECTURE_IDENTIFIER      "x64"
+#define ARCHITECTURE_IDENTIFIER              "x64"
+#define ARCHITECTURE_IDENTIFIER_GENERAL      ARCHITECTURE_IDENTIFIER
 #elif defined (__i386__)
-#define ARCHITECTURE_IDENTIFIER      "x86"
+#define ARCHITECTURE_IDENTIFIER              "x86"
+#define ARCHITECTURE_IDENTIFIER_GENERAL      ARCHITECTURE_IDENTIFIER
 #elif defined (__riscv)
-#define ARCHITECTURE_IDENTIFIER      "riscv64"
+#define ARCHITECTURE_IDENTIFIER              "riscv64"
+#define ARCHITECTURE_IDENTIFIER_GENERAL      ARCHITECTURE_IDENTIFIER
 #else
-#error                               "Unknown target"
+#error                                       "Unknown target"
 #endif
 
 #endif //__LAUNCHER_ENV_H_
index 28b387f..1fdbf33 100644 (file)
@@ -117,6 +117,15 @@ ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt);
 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt);
 
 /**
+ * @brief create native images for all DLLs in a package with specified path.
+ * @param[in] rootPath path of package
+ * @param[in] flags additional flags for the image generator
+ * @parma[in] rpk if true, generate RPK native image (default value is false)
+ * @return ni_error_e
+ */
+ni_error_e createNIUnderPkgRootWithPath(const std::string& rootPath, NIOption* opt, bool rpk = false);
+
+/**
  * @brief remove platform native images (.NETCore + TizenFX)
  */
 void removeNIPlatform();
@@ -137,16 +146,18 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId);
 /**
  * @brief regenerate native images of all installed packages (tpk, rpk)
  * @param[in] flags additional flags for the image generator
+ * @param[in] removeOnly if it is set true, ni creation is skipped (default : false)
  * @return ni_error_e
  */
-ni_error_e regeneratePkgNI(NIOption* opt);
+ni_error_e regeneratePkgNI(NIOption* opt, bool removeOnly = false);
 
 /**
  * @brief regenerate native image of TAC for all shared assembly.
  * @param[in] flags additional flags for the image generator
+ * @param[in] removeOnly if it is set true, ni creation is skipped. (default : false)
  * @return ni_error_e
  */
-ni_error_e regenerateTACNI(NIOption* opt);
+ni_error_e regenerateTACNI(NIOption* opt, bool removeOnly = false);
 
 /**
  * @brief Sets the priority of the process to the specified values from -20 to 19.(default : 0)
index b3bc88e..ab23578 100644 (file)
@@ -133,6 +133,12 @@ public:
        const std::string& getAppNIPaths();
 
        /**
+        * @brief Get the list of directories for using as a value for CLR APP_PATHS key
+        * @return the list(":" seperated) of paths to probe in
+        */
+       const std::string& getAppCLRPaths();
+
+       /**
         * @brief Set addtional dll searching path for App.
         * @param[in] paths path
         */
@@ -163,6 +169,7 @@ private:
        std::string tizenfxPath;
        std::string appPaths;
        std::string appNIPaths;
+       std::string appCLRPaths;
        std::string nativeDllSearchingPaths;
        std::string appTacPath;
        std::string extraDllPaths;
index 17e2441..32ff451 100644 (file)
@@ -31,9 +31,10 @@ typedef enum {
 
 /**
  * @brief restore database of TAC
+ * @param[in] tac readonly flag
  * @return tac_error_e
  */
-tac_error_e tac_restoreDB();
+tac_error_e tac_restoreDB(bool isReadonly);
 
 /**
  * @brief disable tac feature.
@@ -66,8 +67,9 @@ std::vector<std::string> getLibrariesInfo(const std::string& rootPath);
 
 /**
  * @brief restore database of TLC
+ * @param[in] tlc readonly flag
  * @return tac_error_e
  */
-tac_error_e tlc_restoreDB();
+tac_error_e tlc_restoreDB(bool isReadonly);
 
 #endif /* __TAC_COMMON_H__ */
index 896f20d..c808911 100644 (file)
@@ -24,9 +24,9 @@ int sqliteCb(void *count, int argc, char **argv, char **colName);
 
 
 /* TAC related DB functions */
-int tac_createDB();
+int tac_createDB(bool isReadonly);
 
-int tac_openDB();
+int tac_openDB(bool isReadonly);
 
 int tac_insertDB(const std::string& pkgId, const std::string& np, const std::string& tac_name, const std::string& tac_version);
 
@@ -44,9 +44,9 @@ bool tac_closeDB();
 
 
 /* TAC related DB functions */
-int tlc_createDB();
+int tlc_createDB(bool isReadonly);
 
-int tlc_openDB();
+int tlc_openDB(bool isReadonly);
 
 int tlc_insertDB(const std::string& pkgId, const std::string& fileSha);
 
index 38c6361..6dd5467 100644 (file)
@@ -128,6 +128,28 @@ std::string changeExtension(const std::string& path, const std::string& from, co
 bool isReadOnlyArea(const std::string& path);
 
 /**
+ * @brief check the package is 'readonly' or not
+ * @param[in] package ID
+ * @return bool package readonly value
+ */
+bool isReadOnlyPkg(const std::string& pkgId);
+
+/**
+ * @brief get db path of tac
+ * @param[in] tac readonly flag
+ * @param[in] db file name
+ * @return tac db path
+ */
+std::string tacDBPath(bool isReadonly, const std::string& dbName);
+
+/**
+ * @brief get library path of tlc
+ * @param[in] tlac readonly flag
+ * @return tlc library path
+ */
+std::string tlcLBPath(bool isReadonly);
+
+/**
  * @brief split path with ":" delimiter and put that in the vector
  * @param[in] source path
  * @param[out] string vector
@@ -164,6 +186,13 @@ bool isDirectory(const std::string& path);
 bool isManagedAssembly(const std::string& fileName);
 
 /**
+ * @brief check the file is native image or not.
+ * @param[in] file path
+ * @return return true when the file is native image.
+ */
+bool isNativeImage(const std::string& filePath);
+
+/**
  * @brief Resolve assembly files from directories and append their paths to the given list.
  * @remark If a native image exists for an assembly in the same directory, it will be used.
  *         If multiple assemblies of the same name exist, the first one will be used.
index 427eb63..75bb2f9 100644 (file)
@@ -72,6 +72,15 @@ extern "C" int PKGMGR_MDPARSER_PLUGIN_INSTALL(const char *pkgId, const char *app
                iter = g_list_next(iter);
        }
 
+       // if package contains native image, skip AOT.
+       std::string rootPath = getRootPath(pkgId);
+       if (!rootPath.empty()) {
+               if (exist(concatPath(rootPath, concatPath("bin", APP_NI_SUB_DIR)))) {
+                       _INFO("Package already contains native images. Skip native image generation");
+                       doAOT = false;
+               }
+       }
+
        if (doAOT) {
                _DBG("Prefer dotnet application AOT set TRUE");
 
index 8431610..3c2cb50 100644 (file)
@@ -262,7 +262,7 @@ bool initializeCoreClr(PathManager* pm, const std::string& tpa)
 
        const char *propertyValues[] = {
                tpa.c_str(),
-               pm->getAppPaths().c_str(),
+               pm->getAppCLRPaths().c_str(),
                pm->getAppNIPaths().c_str(),
                pm->getNativeDllSearchingPaths().c_str(),
                "UseLatestBehaviorWhenTFMNotSpecified",
@@ -323,9 +323,9 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
                return -1;
        }
 
-       // checkInjection checks dotnet-launcher run mode
+       // checkProfilerInjection checks dotnet-launcher run mode
        // At the moment, this mechanism is used only when the Memory Profiler is started.
-       int res = checkInjection();
+       int res = checkProfilerInjection();
        if (res != 0) {
                _ERR("Failed to initnialize Memory Profiler");
                return -1;
@@ -359,6 +359,11 @@ int CoreRuntime::initialize(const char* appType, LaunchMode launchMode)
        // Disable config cache to set environment after coreclr_initialize()
        putenv(const_cast<char *>("COMPlus_DisableConfigCache=1"));
 
+       // Disable debugger for loader
+       if (launchMode == LaunchMode::loader) {
+               putenv(const_cast<char *>("DOTNET_EnableDiagnostics_Debugger=0"));
+       }
+
        // Set environment variable for System.Environment.SpecialFolder
        initEnvForSpecialFolder();
 
@@ -527,6 +532,7 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i
                return -1;
        }
 
+       std::string newPath = path;
        pluginSetAppInfo(appId, path);
 
        // temporal root path is overrided to real application root path
@@ -573,14 +579,19 @@ int CoreRuntime::launch(const char* appId, const char* root, const char* path, i
 
        setSwitch("Switch.System.Diagnostics.StackTrace.ShowILOffsets", true);
 
+       std::string exec = replaceAll(path, "/bin/", "/bin/.native_image/");
+       if (exist(exec)) {
+               newPath = exec;
+       }
+
        pluginBeforeExecute();
 
-       _INFO("execute assembly : %s", path);
+       _INFO("execute assembly : %s", newPath.c_str());
 
        unsigned int ret = 0;
-       int st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
+       int st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, newPath.c_str(), &ret);
        if (st < 0)
-               _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
+               _ERR("Failed to Execute Assembly %s (0x%08x)", newPath.c_str(), st);
        return ret;
 }
 
index 819af59..30a2a82 100644 (file)
  */
 
 #include "log.h"
-
+#include "utils.h"
 #include <cstdlib>
 #include <cstring>
-
+#include <string>
 #include <dlfcn.h>
 
-#define HT_PATH "/home/owner/share/tmp/sdk_tools/heaptrack/"
-#define HT_LIB_PATH HT_PATH "libprofiler.so"
-#define HT_INJECTION_LIB_PATH HT_PATH "libheaptrack_inject.so"
+#define SDK_TOOLS_PATH   "/home/owner/share/tmp/sdk_tools/"
+#define LIB_INJECTION   "libheaptrack_inject.so"
+#define CORPROF_LIB_PATH SDK_TOOLS_PATH "coreprofiler/libcoreprof.so"
 
-static int injectLibrary(const char path[])
+static int injectHeaptrackLibrary(const char path[])
 {
        typedef int inject_func();
-
-       int res = -1;
        void *lib = nullptr;
        inject_func *inject = nullptr;
        const char *inject_sym = "dotnet_launcher_inject";
@@ -40,40 +38,51 @@ static int injectLibrary(const char path[])
        lib = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
        if (lib == nullptr) {
                _ERR("%s", dlerror());
-               return res;
+               return -1;
        }
 
        inject = reinterpret_cast<inject_func*>(dlsym(lib, inject_sym));
        if (inject == nullptr) {
                _ERR("%s is not found in the %s", inject_sym, path);
-               return res;
+               return -1;
        }
 
-       res = inject();
-       return res;
+       return inject();
 }
 
-int checkInjection()
+int checkProfilerInjection()
 {
        char *env = nullptr;
-
        env = getenv("CORECLR_PROFILER_PATH");
        if (env == nullptr) {
                return 0;
        }
 
-       // At the moment, this mechanism is used only when the Memory Profiler is started.
-       if (strcmp(env, HT_LIB_PATH) != 0) {
-               return 0;
+       if (!exist(env)) {
+               return -1;
        }
 
-       _INFO("##### Perform injection #########");
+        if (strcmp(env, CORPROF_LIB_PATH) == 0) {
+                return 0;
+       }
+
+
+       if (strstr(env, SDK_TOOLS_PATH) == NULL) {
+               return -1;
+       }
+
+       _INFO("##### Perform profiler injection #########");
+
+       std::string path = concatPath(getBaseName(env), LIB_INJECTION);
+       if (!exist(path)) {
+               return -1;
+       }
 
-       if (injectLibrary(HT_INJECTION_LIB_PATH) != 0) {
-               _INFO("##### Injection failed #########");
+       if (injectHeaptrackLibrary(path.c_str()) != 0) {
+               _ERR("##### Heaptrack injection failed #########");
                return -1;
        }
 
-       _INFO("##### Injection finished #########");
+       _INFO("##### Profiler injection finished #########");
        return 0;
 }
index 6bcf111..042fe42 100644 (file)
@@ -17,6 +17,6 @@
 #ifndef __INJETION_INTERFACE_H__
 #define __INJETION_INTERFACE_H__
 
-int checkInjection();
+int checkProfilerInjection();
 
 #endif // __INJETION_INTERFACE_H__
index 39b5206..d65454a 100644 (file)
@@ -39,11 +39,15 @@ void DisplayUsage() {
                "       --ni-dll                  - Create NI for DLL\n"
                "       --ni-pkg                  - Create NI for package\n"
                "                                   (If package is installed under RO area, NI files are generated under RW area)\n"
+               "       --ni-pkg-with-path        - Create NI for package with root path\n"
+               "                                   (If package is installed under RO area, NI files are generated under RW area)\n"
                "       --ni-dir                  - Create NI for directory\n"
                "       --ni-reset-system         - Remove System NI files\n"
+               "       --ni-reset-all-app        - Remove All App NI files\n"
                "       --ni-reset-pkg            - Remove App NI files\n"
                "       --ni-reset-dir            - Remove NI for directory\n"
                "       --ni-regen-all-app        - Re-generate All App NI files\n"
+               "       --tac-reset-all           - Remove All TAC NI files\n"
                "       --tac-regen-all           - Re-generate All TAC files\n"
                "       --tac-restore-db          - Restore TAC Database\n"
                "       --tac-disable-pkg         - Disable TAC for package\n"
@@ -95,6 +99,248 @@ void DisplayUsage() {
                "   # dotnettool --rm-app-profile org.tizen.FormsGallery\n"
                "\n");
 }
+static std::vector<std::string> args;
+static std::vector<std::string>::iterator it;
+
+//sh-3.2# dotnettool --ni-system [AssemblyDirectory] [AssemblyDirectory] ...
+static void dotnettool_ni_system(NIOption* opt)
+{
+       std::string inputs;
+       while (it != args.end()) {
+               std::string dir = std::string(*it);
+               inputs = inputs + ":" + dir;
+               it = args.erase(it);
+       }
+       if (createNIPlatform(inputs, opt) != NI_ERROR_NONE) {
+               _SERR("Failed to generate system NI");
+       }
+}
+
+//sh-3.2# dotnettool --ni-dll [assemblyPath] [assemblyPath] ...
+static void dotnettool_ni_dll(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("DLL path is missing");
+       }
+       std::vector<std::string> inputs;
+       while (it != args.end()) {
+               std::string dll = std::string(*it);
+               inputs.push_back(dll);
+               opt->refFiles.push_back(dll);
+               if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
+                       opt->inputBubbleRefFiles.push_back(dll);
+               }
+               it = args.erase(it);
+       }
+       for (auto &dll : inputs) {
+               int ret = createNIDll(dll, opt);
+               if (ret != NI_ERROR_NONE && ret != NI_ERROR_ALREADY_EXIST) {
+                       _SERR("Failed to generate NI file [%s]", dll.c_str());
+                       break;
+               }
+       }
+}
+
+//sh-3.2# dotnettool --ni-pkg [pkgId] [pkgId] ...
+static void dotnettool_ni_pkg(NIOption* opt)
+{
+       if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+               _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+               DisplayUsage();
+               return;
+       }
+       if (args.size() < 1) {
+               _SERR("Package name is missing");
+       }
+       while (it != args.end()) {
+               std::string pkg = std::string(*it);
+               if (createNIUnderPkgRoot(pkg, opt) != NI_ERROR_NONE) {
+                       _SERR("Failed to generate app NI [%s]", pkg.c_str());
+                       break;
+               }
+               it = args.erase(it);
+       }
+}
+
+//sh-3.2# dotnettool --ni-pkg-with-path [path] [path] ...
+static void dotnettool_ni_pkg_with_path(NIOption* opt)
+{
+       if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+               _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+               DisplayUsage();
+               return;
+       }
+       if (args.size() < 1) {
+               _SERR("Package name is missing");
+       }
+       while (it != args.end()) {
+               std::string path = std::string(*it);
+               if (createNIUnderPkgRootWithPath(path, opt) != NI_ERROR_NONE) {
+                       _SERR("Failed to generate app NI from path[%s]", path.c_str());
+                       break;
+               }
+               it = args.erase(it);
+       }
+}
+
+//sh-3.2# dotnettool --ni-dir [AssemblyDirectory] [AssemblyDirectory] ...
+static void dotnettool_ni_dir(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("Directory path is missing");
+       }
+       std::string dir;
+       while (it != args.end()) {
+               if (!dir.empty()) {
+                       dir += std::string(":");
+               }
+               dir += std::string(*it);
+               it = args.erase(it);
+       }
+       if (createNIUnderDirs(dir, opt) != NI_ERROR_NONE) {
+               _SERR("Failed to generate NI directory");
+       }
+}
+
+//sh-3.2# dotnettool --ni-reset-all-app
+static void dotnettool_ni_reset_all_app(NIOption* opt)
+{
+       if (regeneratePkgNI(opt, true) != NI_ERROR_NONE) {
+               _SERR("Failed to reseet all app NI");
+       }
+}
+
+//sh-3.2# dotnettool --ni-reset-pkg [pkgId] [pkgId] ...
+static void dotnettool_ni_reset_pkg(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("Package name is missing");
+       }
+       while (it != args.end()) {
+               std::string pkg = std::string(*it);
+               if (removeNIUnderPkgRoot(pkg) != NI_ERROR_NONE) {
+                       _SERR("Failed to remove dlls for given package [%s]", pkg.c_str());
+                       break;
+               }
+               it = args.erase(it);
+       }
+}
+
+//sh-3.2# dotnettool --ni-reset-dir [AssemblyDirectory] [AssemblyDirectory] ...
+static void dotnettool_ni_reset_dir(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("Directory path is missing");
+       }
+       while (it != args.end()) {
+               std::string dir = std::string(*it);
+               removeNIUnderDirs(dir);
+               it = args.erase(it);
+       }
+}
+
+//sh-3.2# dotnettool --ni-regen-all-app
+static void dotnettool_ni_regen_all_app(NIOption* opt)
+{
+       if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+               _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+               DisplayUsage();
+               return;
+       }
+       if (regeneratePkgNI(opt) != NI_ERROR_NONE) {
+               _SERR("Failed to regenerate all app NI");
+       }
+}
+
+//sh-3.2# dotnettool --tac-reset-all
+static void dotnettool_tac_reset_all(NIOption* opt)
+{
+       if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+               _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+               DisplayUsage();
+               return;
+       }
+       if (regenerateTACNI(opt, true) != NI_ERROR_NONE) {
+               _SERR("Failed to remove all TAC NI files");
+       }
+}
+
+//sh-3.2# dotnettool --tac-regen-all
+static void dotnettool_tac_regen_all(NIOption* opt)
+{
+       if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+               _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+               DisplayUsage();
+               return;
+       }
+       if (regenerateTACNI(opt) != NI_ERROR_NONE) {
+               _SERR("Failed to regenerate all TAC");
+       }
+}
+
+//sh-3.2# dotnettool --tac-restore-db
+static void dotnettool_tac_restore_db(NIOption* opt)
+{
+       if (tac_restoreDB(false) != TAC_ERROR_NONE) {
+               _SERR("Failed to restore TAC db of RW");
+       }
+       if (tlc_restoreDB(false) != TAC_ERROR_NONE) {
+               _SERR("Failed to restore TLC db of RW");
+       }
+       if (tac_restoreDB(true) != TAC_ERROR_NONE) {
+               _SERR("Failed to restore TAC db of RO");
+       }
+       if (tlc_restoreDB(true) != TAC_ERROR_NONE) {
+               _SERR("Failed to restore TLC db of RO");
+       }
+}
+
+//sh-3.2# dotnettool --tac-enable-pkg [pkgId] [pkgId] ...
+static void dotnettool_tac_enable_pkg(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("Package name is missing");
+       }
+       while (it != args.end()) {
+               std::string pkg = std::string(*it);
+               if (enableTACPackage(pkg) != TAC_ERROR_NONE) {
+                       _SERR("Failed to enable tac [%s]", pkg.c_str());
+                       break;
+               }
+               it = args.erase(it);
+       }
+}
+
+//sh-3.2# dotnettool --tac-disable-pkg [pkgId] [pkgId] ...
+static void dotnettool_tac_disable_pkg(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("Package name is missing");
+       }
+       while (it != args.end()) {
+               std::string pkg = std::string(*it);
+               if (disableTACPackage(pkg) != TAC_ERROR_NONE) {
+                       _SERR("Failed to disable tac [%s]", pkg.c_str());
+                       break;
+               }
+               it = args.erase(it);
+       }
+}
+
+//sh-3.2# dotnettool --rm-app-profile [pkgId] [pkgId] ...
+static void dotnettool_rm_app_profile(NIOption* opt)
+{
+       if (args.size() < 1) {
+               _SERR("Package name is missing");
+       }
+       while (it != args.end()) {
+               std::string pkg = std::string(*it);
+               if (removeAppProfileData(pkg) != PROFILE_ERROR_NONE) {
+                       _SERR("Failed to remove [%s] profile data", pkg.c_str());
+               }
+               it = args.erase(it);
+       }
+}
 
 int main(int argc, char* argv[])
 {
@@ -118,13 +364,12 @@ int main(int argc, char* argv[])
                return -1;
        }
 
-       std::vector<std::string> args;
        for (int i = 0; i < argc; ++i) {
                std::string arg = argv[i];
 
                if ((arg == "-?") || (arg == "-h") || (arg == "--h")) {
                        DisplayUsage();
-                       return 0;
+                       return -1;
                } else if (arg == "--verbose") {
                        opt->flags |= NI_FLAGS_VERBOSE;
                } else if (arg == "--inputbubble") {
@@ -142,7 +387,7 @@ int main(int argc, char* argv[])
                        if (i >= argc) {
                                _SOUT("Priority value(-20 ~ 19) should be followed for --set-priority option");
                                DisplayUsage();
-                               return 0;
+                               return -1;
                        }
 
                        opt->flags |= NI_FLAGS_SET_PRIORITY;
@@ -152,14 +397,14 @@ int main(int argc, char* argv[])
                        } catch (...) {
                                _SERR("Invalid argument: %s", argv[i]);
                                DisplayUsage();
-                               return 0;
+                               return -1;
                        }
                } else if (arg == "--mibc") {
                        ++i;
                        if (i >= argc) {
                                _SOUT("File path containing Mibc files should be followed for --mibc option");
                                DisplayUsage();
-                               return 0;
+                               return -1;
                        }
 
                        opt->flags |= NI_FLAGS_MIBC;
@@ -169,6 +414,7 @@ int main(int argc, char* argv[])
                        for (const auto &path : paths) {
                                if (!isFile(path) || isDirectory(path)) {
                                        _SERR("Mibc file path is missing or does not exist");
+                                       DisplayUsage();
                                        return -1;
                                }
                                opt->mibcPath.push_back(path);
@@ -178,7 +424,7 @@ int main(int argc, char* argv[])
                        if (i >= argc) {
                                _SOUT("Path for references should be followed for --inputbubbleref option");
                                DisplayUsage();
-                               return 0;
+                               return -1;
                        }
 
                        opt->flags |= NI_FLAGS_INPUT_BUBBLE_REF;
@@ -193,7 +439,7 @@ int main(int argc, char* argv[])
                        if (i >= argc) {
                                _SOUT("Path for references should be followed for --ref option");
                                DisplayUsage();
-                               return 0;
+                               return -1;
                        }
 
                        std::vector<std::string> files;
@@ -222,204 +468,64 @@ int main(int argc, char* argv[])
                return -1;
        }
 
-       std::vector<std::string>::iterator it = args.begin();
+       it = args.begin();
        std::string cmd = std::string(*it);
        it = args.erase(it);
 
-       //sh-3.2# dotnettool --ni-system [AssemblyDirectory] [AssemblyDirectory] ...
        if (cmd == "--ni-system") {
-               std::string inputs;
-               while (it != args.end()) {
-                       const std::string dir = std::string(*it);
-                       inputs = inputs + ":" + dir;
-                       it = args.erase(it);
-               }
-               int ret = createNIPlatform(inputs, opt);
-               if (ret != NI_ERROR_NONE) {
-                       _SERR("Failed to generate system NI");
-               }
+               dotnettool_ni_system(opt);
        }
-       //sh-3.2# dotnettool --ni-dll [assemblyPath] [assemblyPath] ...
        else if (cmd == "--ni-dll") {
-               if (args.size() < 1) {
-                       _SERR("DLL path is missing");
-               }
-               std::vector<std::string> inputs;
-               while (it != args.end()) {
-                       std::string dll = std::string(*it);
-                       inputs.push_back(dll);
-                       opt->refFiles.push_back(dll);
-                       if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
-                               opt->inputBubbleRefFiles.push_back(dll);
-                       }
-                       it = args.erase(it);
-               }
-
-               for (auto &dll : inputs) {
-                       int ret = createNIDll(dll, opt);
-                       if (ret != NI_ERROR_NONE && ret != NI_ERROR_ALREADY_EXIST) {
-                               _SERR("Failed to generate NI file [%s]", dll.c_str());
-                               break;
-                       }
-               }
+               dotnettool_ni_dll(opt);
        }
-       //sh-3.2# dotnettool --ni-pkg [pkgId] [pkgId] ...
        else if (cmd == "--ni-pkg") {
-               if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
-                       _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
-                       DisplayUsage();
-                       return -1;
-               }
-
-               if (args.size() < 1) {
-                       _SERR("Package name is missing");
-               }
-               while (it != args.end()) {
-                       std::string pkg = std::string(*it);
-                       int ret = createNIUnderPkgRoot(pkg, opt);
-                       if (ret != NI_ERROR_NONE) {
-                               _SERR("Failed to generate app NI [%s]", pkg.c_str());
-                               break;
-                       }
-                       it = args.erase(it);
-               }
+               dotnettool_ni_pkg(opt);
+       }
+       else if (cmd == "--ni-pkg-with-path") {
+               dotnettool_ni_pkg_with_path(opt);
        }
-       //sh-3.2# dotnettool --ni-dir [AssemblyDirectory] [AssemblyDirectory] ...
        else if (cmd == "--ni-dir") {
-               if (args.size() < 1) {
-                       _SERR("Directory path is missing");
-               }
-               std::string dir;
-               while (it != args.end()) {
-                       if (!dir.empty()) {
-                               dir += std::string(":");
-                       }
-                       dir += std::string(*it);
-                       it = args.erase(it);
-               }
-               if (createNIUnderDirs(dir, opt) != NI_ERROR_NONE) {
-                       _SERR("Failed to generate NI directory");
-               }
+               dotnettool_ni_dir(opt);
        }
-       //sh-3.2# dotnettool --ni-reset-system
        else if (cmd == "--ni-reset-system") {
                removeNIPlatform();
        }
-       //sh-3.2# dotnettool --ni-reset-pkg [pkgId] [pkgId] ...
+       else if (cmd == "--ni-reset-all-app") {
+               dotnettool_ni_reset_all_app(opt);
+       }
        else if (cmd == "--ni-reset-pkg") {
-               if (args.size() < 1) {
-                       _SERR("Package name is missing");
-               }
-               while (it != args.end()) {
-                       std::string pkg = std::string(*it);
-                       int ret = removeNIUnderPkgRoot(pkg);
-                       if (ret != NI_ERROR_NONE) {
-                               _SERR("Failed to remove dlls for given package [%s]", pkg.c_str());
-                               break;
-                       }
-                       it = args.erase(it);
-               }
+               dotnettool_ni_reset_pkg(opt);
        }
-       //sh-3.2# dotnettool --ni-reset-dir [AssemblyDirectory] [AssemblyDirectory] ...
        else if (cmd == "--ni-reset-dir") {
-               if (args.size() < 1) {
-                       _SERR("Directory path is missing");
-               }
-               while (it != args.end()) {
-                       const std::string dir = std::string(*it);
-                       removeNIUnderDirs(dir);
-                       it = args.erase(it);
-               }
+               dotnettool_ni_reset_dir(opt);
        }
-       //sh-3.2# dotnettool --ni-regen-all-app
        else if (cmd == "--ni-regen-all-app") {
-               if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
-                       _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
-                       DisplayUsage();
-                       return -1;
-               }
-
-               int ret = regeneratePkgNI(opt);
-               if (ret != NI_ERROR_NONE) {
-                       _SERR("Failed to regenerate all app NI");
-               }
+               dotnettool_ni_regen_all_app(opt);
+       }
+       else if (cmd == "--tac-reset-all") {
+               dotnettool_tac_reset_all(opt);
        }
-       //sh-3.2# dotnettool --tac-regen-all
        else if (cmd == "--tac-regen-all") {
-               if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
-                       _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
-                       DisplayUsage();
-                       return -1;
-               }
-
-               int ret = regenerateTACNI(opt);
-               if (ret != NI_ERROR_NONE) {
-                       _SERR("Failed to regenerate all TAC");
-               }
+               dotnettool_tac_regen_all(opt);
        }
-       //sh-3.2# dotnettool --tac-restore-db
        else if (cmd == "--tac-restore-db") {
-               int ret = tac_restoreDB();
-               if (ret != TAC_ERROR_NONE) {
-                       _SERR("Failed to restore TAC db");
-               }
-               ret = tlc_restoreDB();
-               if (ret != TAC_ERROR_NONE) {
-                       _SERR("Failed to restore TLC db");
-               }
+               dotnettool_tac_restore_db(opt);
        }
-       //sh-3.2# dotnettool --tac-enable-pkg [pkgId] [pkgId] ...
        else if (cmd == "--tac-enable-pkg") {
-               if (args.size() < 1) {
-                       _SERR("Package name is missing");
-               }
-               while (it != args.end()) {
-                       std::string pkg = std::string(*it);
-                       int ret = enableTACPackage(pkg);
-                       if (ret != TAC_ERROR_NONE) {
-                               _SERR("Failed to enable tac [%s]", pkg.c_str());
-                               break;
-                       }
-                       it = args.erase(it);
-               }
+               dotnettool_tac_enable_pkg(opt);
        }
-       //sh-3.2# dotnettool --tac-disable-pkg [pkgId] [pkgId] ...
        else if (cmd == "--tac-disable-pkg") {
-               if (args.size() < 1) {
-                       _SERR("Package name is missing");
-               }
-               while (it != args.end()) {
-                       std::string pkg = std::string(*it);
-                       int ret = disableTACPackage(pkg);
-                       if (ret != TAC_ERROR_NONE) {
-                               _SERR("Failed to disable tac [%s]", pkg.c_str());
-                               break;
-                       }
-                       it = args.erase(it);
-               }
+               dotnettool_tac_disable_pkg(opt);
        }
-       //sh-3.2# dotnettool --resolve-all-app
        else if (cmd == "--resolve-all-app") {
                resolveAllApps();
        }
-       //sh-3.2# dotnettool --rm-app-profile [pkgId] [pkgId] ...
        else if (cmd == "--rm-app-profile") {
-               if (args.size() < 1) {
-                       _SERR("Package name is missing");
-               }
-               while (it != args.end()) {
-                       std::string pkg = std::string(*it);
-                       if (removeAppProfileData(pkg) != PROFILE_ERROR_NONE) {
-                               _SERR("Failed to remove [%s] profile data", pkg.c_str());
-                       }
-                       it = args.erase(it);
-               }
+               dotnettool_rm_app_profile(opt);
        }
-       //sh-3.2# dotnettool --rm-all-app-profile
        else if (cmd == "--rm-all-app-profile") {
                removeAllAppProfileData();
        }
-       //sh-3.2# dotnettool --check-all-app-privilege
        else if (cmd == "--check-all-app-privilege") {
                checkAllAppPrivilege();
        }
index 5c12aaa..9542a35 100644 (file)
@@ -124,8 +124,27 @@ static bool moveAllFilesTo(const std::string& from, const std::string& to)
 int resolvePlatformSpecificFiles(const std::string& rootPath)
 {
        std::string appBinPath = concatPath(rootPath, "bin");
+       std::string appLibPath = concatPath(rootPath, "lib");
        std::string runtimesPath = concatPath(appBinPath, "runtimes");
 
+       // remove unused arch directory
+       std::vector<std::string> archList = {"x86", "x64", "arm", "armel", "arm64", "aarch64", "riscv32", "riscv64"};
+       archList.erase(find(archList.begin(), archList.end(), ARCHITECTURE_IDENTIFIER));
+       if (!strncmp(ARCHITECTURE_IDENTIFIER, "armel", 5)) {
+               archList.erase(find(archList.begin(), archList.end(), "arm"));
+       } else if (!strncmp(ARCHITECTURE_IDENTIFIER, "arm64", 5)) {
+               archList.erase(find(archList.begin(), archList.end(), "aarch64"));
+       }
+
+       for (const auto &arch : archList) {
+               std::string archPath = concatPath(appLibPath, arch);
+               if (exist(archPath)) {
+                       if (!removeAll(archPath)) {
+                               _ERR("Failed to remove %s directory", archPath.c_str());
+                       }
+               }
+       }
+
        // if runtimes directory doesnot exist, return 0
        if (!isDirectory(runtimesPath)) {
                return 0;
index 36c2040..f5a00da 100644 (file)
 
 #define __XSTR(x) #x
 #define __STR(x) __XSTR(x)
-#if defined(__arm__) || defined(__aarch64__)
 static const char* __NATIVE_LIB_DIR = __STR(NATIVE_LIB_DIR);
-#endif
 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
+static const char* __RUNTIME_DIR = __STR(RUNTIME_DIR);
 static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
 
 #ifdef UNIQUE_DEFAULT_BASE_ADDR_SUPPORT
@@ -262,7 +261,7 @@ static std::string getNIFilePath(const std::string& absDllPath, NIOption* opt)
 
        size_t index = dllPath.find_last_of(".");
        if (index == std::string::npos) {
-               _SERR("File doesnot contain extension. fail to get NI file name");
+               _SERR("File does not contain extension. fail to get NI file name");
                return "";
        }
        std::string fName = dllPath.substr(0, index);
@@ -321,7 +320,7 @@ static ni_error_e getTargetDllList(const std::string& path, std::vector<std::str
        }
 
        auto func = [&fileList, opt](const std::string& f_path, const std::string& f_name) {
-               if (isManagedAssembly(f_name) && !checkNIExistence(f_path, opt)) {
+               if (isManagedAssembly(f_name) && !isR2RImage(f_path) && !checkNIExistence(f_path, opt)) {
                        fileList.push_back(getAbsolutePath(f_path));
                }
        };
@@ -428,7 +427,7 @@ static ni_error_e makePdbSymlinkForNI(std::string dllPath, std::string niPath)
                if (exist(pdbPath)) {
                        std::string targetPDBPath = changeExtension(niPath, ".ni.dll", ".pdb");
                        if (!exist(targetPDBPath)) {
-                               bf::create_symlink(pdbPath, targetPDBPath);
+                               bf::create_symlink(concatPath("..", getFileName(pdbPath)), targetPDBPath);
                                copySmackAndOwnership(pdbPath, targetPDBPath, true);
                        }
                }
@@ -687,6 +686,18 @@ static void renameAppNITmpPath(NIOption* opt)
                        _SERR("Fail to rename from .native_image_tmp to .native_image");
                } else {
                        _SOUT("Success to rename from %s to %s", niTmpPath.c_str(), niPath.c_str());
+                       try {
+                               for (auto& ni : bf::recursive_directory_iterator(niPath)) {
+                                       std::string niFile = ni.path().string();
+                                       if (isNativeImage(niFile)) {
+                                               std::string dllFile = changeExtension(niFile, ".ni.dll", ".dll");
+                                               bf::create_symlink(getFileName(niFile), dllFile);
+                                               copySmackAndOwnership(niFile, dllFile, true);
+                                       }
+                               }
+                       } catch (const bf::filesystem_error& error) {
+                               _ERR("Failed to recursive directory: %s", error.what());
+                       }
                }
        }
 }
@@ -813,45 +824,6 @@ static ni_error_e doAOTFile(const std::string& dllFile, const std::string& refPa
        return doAOTList(dllList, refPaths, opt);
 }
 
-static ni_error_e removeAndCreateNI(const char* pkgId, NIOption* pOptions)
-{
-       if (removeNIUnderPkgRoot(pkgId) != NI_ERROR_NONE) {
-               _SERR("Failed to remove previous dlls from [%s]", pkgId);
-               return NI_ERROR_UNKNOWN;
-       }
-
-       if (createNIUnderPkgRoot(pkgId, pOptions) != NI_ERROR_NONE) {
-               _SERR("Failed to generate NI file [%s]", pkgId);
-               return NI_ERROR_UNKNOWN;
-       }
-
-       _SOUT("Complete make native image for pkg (%s)", pkgId);
-       return NI_ERROR_NONE;
-}
-
-static bool isReadOnlyPkg(std::string pkgId)
-{
-       int ret = 0;
-       bool readonly = false;
-       pkgmgrinfo_pkginfo_h handle;
-
-       ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
-       if (ret != PMINFO_R_OK) {
-               _ERR("Fail to get pkginfo");
-               return false;
-       }
-
-       ret = pkgmgrinfo_pkginfo_is_readonly(handle, &readonly);
-       if (ret != PMINFO_R_OK) {
-               _ERR("Fail to get is_readonly");
-               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-               return false;
-       }
-
-       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
-       return readonly;
-}
-
 // callback function of "pkgmgrinfo_appinfo_metadata_filter_foreach"
 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
 {
@@ -886,14 +858,25 @@ static int pkgAotCb(pkgmgrinfo_pkginfo_h handle, void *userData)
 
 ni_error_e initNICommon()
 {
-#if defined(__arm__) || defined(__aarch64__)
+#ifdef __i386__
+       _SERR("x86 doesnot supported. skip ni file generation");
+       return NI_ERROR_NOT_SUPPORTED;
+#endif
 
        char *env = nullptr;
        env = getenv("MIC_CROSSGEN2_ENABLED");
        if (env != nullptr && !strcmp(env, "1")) {
                CORERUN_CMD = std::string("/opt/usr/dotnet/mic/crossgen2");
                CROSSGEN2_PATH = "";
-               CLRJIT_PATH = std::string("/opt/usr/dotnet/mic/libclrjit_unix_") + ARCHITECTURE_IDENTIFIER + std::string("_x64.so");
+               CLRJIT_PATH = std::string("/opt/usr/dotnet/mic/libclrjit_");
+               if (strstr(bf::read_symlink(__RUNTIME_DIR).string().c_str(), "6.0.") != NULL) {
+                       CLRJIT_PATH.append("unix_"); //6.0.X
+                       CLRJIT_PATH.append(ARCHITECTURE_IDENTIFIER);
+               } else {
+                       CLRJIT_PATH.append("universal_");
+                       CLRJIT_PATH.append(ARCHITECTURE_IDENTIFIER_GENERAL);
+               }
+               CLRJIT_PATH.append("_x64.so");
        }
 
        // get interval value
@@ -927,10 +910,6 @@ ni_error_e initNICommon()
        }
 
        return NI_ERROR_NONE;
-#else
-       _SERR("crossgen supports arm/arm64 architecture only. skip ni file generation");
-       return NI_ERROR_NOT_SUPPORTED;
-#endif
 }
 
 void finalizeNICommon()
@@ -961,7 +940,7 @@ ni_error_e createNIDll(const std::string& dllPath, NIOption* opt)
        return doAOTFile(dllPath, std::string(), opt);
 }
 
-ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, NIOption* opt)
+static ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& refPaths, NIOption* opt)
 {
        ni_error_e ret;
 
@@ -1018,6 +997,12 @@ ni_error_e createNIUnderTAC(const std::string& targetPath, const std::string& re
                                        _SOUT("%s symbolic link file generated successfully.", symNIPath.c_str());
                                        _INFO("%s symbolic link file generated successfully.", symNIPath.c_str());
                                }
+                               std::string symPath = changeExtension(symNIPath, ".ni.dll", ".dll");
+                               removeFile(symPath);
+                               bf::create_symlink(niPath, symPath);
+                               copySmackAndOwnership(targetPath.c_str(), symPath.c_str(), true);
+                               _SOUT("%s symbolic link file generated successfully.", symPath.c_str());
+                               _INFO("%s symbolic link file generated successfully.", symPath.c_str());
                        }
                }
        }
@@ -1068,6 +1053,17 @@ ni_error_e createNIUnderDirs(const std::string& rootPaths, NIOption* opt)
 
 ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt)
 {
+       std::string rootPath = getRootPath(pkgId);
+       if (rootPath.empty()) {
+               _SERR("Failed to get root path from [%s]", pkgId.c_str());
+               return NI_ERROR_INVALID_PACKAGE;
+       }
+
+       return createNIUnderPkgRootWithPath(rootPath, opt, isRPK(pkgId));
+}
+
+ni_error_e createNIUnderPkgRootWithPath(const std::string& rootPath, NIOption* opt, bool rpk)
+{
        if (!isR2RImage(concatPath(__pm->getRuntimePath(), "System.Private.CoreLib.dll"))) {
                _SERR("The native image of System.Private.CoreLib does not exist.\n"
                                "Run the command to create the native image\n"
@@ -1075,9 +1071,8 @@ ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt)
                return NI_ERROR_CORE_NI_FILE;
        }
 
-       std::string rootPath = getRootPath(pkgId);
        if (rootPath.empty()) {
-               _SERR("Failed to get root path from [%s]", pkgId.c_str());
+               _SERR("Failed. rootPath should be set");
                return NI_ERROR_INVALID_PACKAGE;
        }
        __pm->setAppRootPath(rootPath);
@@ -1089,13 +1084,13 @@ ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt)
        }
 
        std::string targetDirs;
-       if (isRPK(pkgId)) {
+       if (rpk) {
                opt->flags &= ~NI_FLAGS_APPNI; // added to exclude logic of APP_NI
                opt->flags |= NI_FLAGS_NO_PIPELINE; // added the flag to set the output path
 
                std::string paths = getResourcePaths(rootPath);
                if (paths.empty()) {
-                       _SERR("Failed to get rpk paths from [%s]", pkgId.c_str());
+                       _SERR("Failed to get rpk paths from rootPath[%s]", rootPath.c_str());
                        return NI_ERROR_UNKNOWN;
                }
                targetDirs = paths;
@@ -1105,6 +1100,10 @@ ni_error_e createNIUnderPkgRoot(const std::string& pkgId, NIOption* opt)
                if (isReadOnlyArea(rootPath)) {
                        opt->flags |= NI_FLAGS_APP_UNDER_RO_AREA;
                        opt->flags |= NI_FLAGS_NO_PIPELINE;
+                       std::string tmpPath = replaceAll(rootPath, getBaseName(rootPath), __READ_ONLY_APP_UPDATE_DIR);
+                       if (!removeAll(tmpPath)){
+                               _SERR("Fail to remove RO App update path : %s", tmpPath.c_str());
+                       }
                        _SERR("Only no-pipeline mode supported for RO app. Set no-pipeline option forcibly");
                } else {
                        opt->flags &= ~NI_FLAGS_APP_UNDER_RO_AREA;
@@ -1167,6 +1166,28 @@ void removeNIUnderDirs(const std::string& rootPaths)
        }
 }
 
+static void removeNIUnderTAC(const std::string& rootPaths)
+{
+       auto convert = [&rootPaths](const std::string& path, const std::string& filename) {
+               if (isNativeImage(path)) {
+                       std::string assemblyPath = changeExtension(path, ".ni.dll", ".dll");
+                       if (exist(assemblyPath)) {
+                               if (removeFile(assemblyPath)) {
+                                       bf::create_symlink(changeExtension(bf::read_symlink(path).string(), ".ni.dll", ".dll"), assemblyPath);
+                                       copySmackAndOwnership(rootPaths.c_str(), assemblyPath.c_str(), true);
+                               }
+                       }
+                       removeFile(path);
+               }
+       };
+
+       std::vector<std::string> paths;
+       splitPath(rootPaths, paths);
+       for (const auto &path : paths) {
+               scanFilesInDirectory(path, convert, -1);
+       }
+}
+
 ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
 {
        std::vector<std::string> paths;
@@ -1199,7 +1220,7 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
                        if (!isReadOnlyArea(path)) {
                                // Only the native image inside the TAC should be removed.
                                if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
-                                       removeNIUnderDirs(path);
+                                       removeNIUnderTAC(path);
                                } else {
                                        if (isDirectory(path)) {
                                                if (!removeAll(path.c_str())) {
@@ -1209,14 +1230,19 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
                                }
                        }
                }
+               paths.clear();
 
                // In special cases, the ni file may exist in the dll location.
                // The code below is to avoid this exceptional case.
                std::string appPaths = __pm->getAppPaths();
                splitPath(appPaths, paths);
                for (const auto &path : paths) {
-                       if (isDirectory(path)) {
-                               removeNIUnderDirs(path);
+                       if (strstr(path.c_str(), TAC_SYMLINK_SUB_DIR) != NULL) {
+                               removeNIUnderTAC(path);
+                       } else {
+                               if (isDirectory(path)) {
+                                       removeNIUnderDirs(path);
+                               }
                        }
                }
        }
@@ -1224,7 +1250,7 @@ ni_error_e removeNIUnderPkgRoot(const std::string& pkgId)
        return NI_ERROR_NONE;
 }
 
-ni_error_e regeneratePkgNI(NIOption* opt)
+ni_error_e regeneratePkgNI(NIOption* opt, bool removeOnly)
 {
        std::vector<std::string> pkgList;
        ni_error_e ret = NI_ERROR_NONE;
@@ -1275,11 +1301,18 @@ ni_error_e regeneratePkgNI(NIOption* opt)
                        continue;
                }
 
-               if (removeAndCreateNI(pkg.c_str(), opt) != NI_ERROR_NONE) {
+               if (removeNIUnderPkgRoot(pkg) != NI_ERROR_NONE) {
                        _SERR("Failed to remove previous dlls from [%s]", pkg.c_str());
                        ret = NI_ERROR_UNKNOWN;
-               } else {
-                       _SOUT("Complete make application to native image");
+               }
+
+               if (!removeOnly) {
+                       if (createNIUnderPkgRoot(pkg, opt) != NI_ERROR_NONE) {
+                               _SERR("Failed to generate NI file [%s]", pkg.c_str());
+                               ret = NI_ERROR_UNKNOWN;
+                       } else {
+                               _SOUT("Complete make application to native image");
+                       }
                }
        }
 
@@ -1311,7 +1344,7 @@ static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
                return 0;
        }
 
-       sqlite3 *tac_db = openDB(TAC_APP_LIST_DB);
+       sqlite3 *tac_db = openDB(concatPath(__DOTNET_DIR, TAC_APP_LIST_DB));
        if (!tac_db) {
                _SERR("Sqlite open error");
                return -1;
@@ -1342,30 +1375,32 @@ static int regenTacCb(pkgmgrinfo_appinfo_h handle, void *userData)
        return 0;
 }
 
-ni_error_e regenerateTACNI(NIOption* opt)
+ni_error_e regenerateTACNI(NIOption* opt, bool removeOnly)
 {
        removeNIUnderDirs(__DOTNET_DIR);
 
-       pkgmgrinfo_appinfo_metadata_filter_h handle;
-       int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
-       if (ret != PMINFO_R_OK) {
-               return NI_ERROR_UNKNOWN;
-       }
+       if (!removeOnly) {
+               pkgmgrinfo_appinfo_metadata_filter_h handle;
+               int ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
+               if (ret != PMINFO_R_OK) {
+                       return NI_ERROR_UNKNOWN;
+               }
 
-       ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE_TRUE);
-       if (ret != PMINFO_R_OK) {
-               pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
-               return NI_ERROR_UNKNOWN;
-       }
+               ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, TAC_METADATA_KEY, METADATA_VALUE_TRUE);
+               if (ret != PMINFO_R_OK) {
+                       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+                       return NI_ERROR_UNKNOWN;
+               }
+
+               ret = pkgmgrAppMDFilterForeach(handle, regenTacCb, &opt);
+               if (ret != 0) {
+                       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
+                       return NI_ERROR_UNKNOWN;
+               }
 
-       ret = pkgmgrAppMDFilterForeach(handle, regenTacCb, &opt);
-       if (ret != 0) {
                pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
-               return NI_ERROR_UNKNOWN;
        }
 
-       pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
-
        return NI_ERROR_NONE;
 }
 
index 03ff5a8..9dbe5ef 100644 (file)
@@ -34,6 +34,7 @@
 #define __STR(x) __XSTR(x)
 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
 static const char* __READ_ONLY_APP_UPDATE_DIR = __STR(READ_ONLY_APP_UPDATE_DIR);
+static const char* __READ_ONLY_TAC_DIR = __STR(READ_ONLY_TAC_DIR);
 #undef __STR
 #undef __XSTR
 
@@ -42,14 +43,15 @@ static sqlite3 *tlc_db = NULL;
 static std::vector<std::string> restore_nuget;
 static std::vector<std::string> restore_library;
 
-static void cleanupDirectory()
+static void cleanupDirectory(bool isReadonly)
 {
        std::vector<std::string> removeNuget;
        try {
-               for (auto& nuget : bf::recursive_directory_iterator(__DOTNET_DIR)) {
+               std::string tacLocation = isReadonly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
+               for (auto& nuget : bf::recursive_directory_iterator(tacLocation)) {
                        std::string nugetPath = nuget.path().string();
                        if (!bf::is_directory(nugetPath) ||
-                               nugetPath.find(TLC_LIBRARIES_DIR) != std::string::npos ||
+                               nugetPath.find(tlcLBPath(isReadonly)) != std::string::npos ||
                                nugetPath.find(__READ_ONLY_APP_UPDATE_DIR) != std::string::npos) {
                                continue;
                        }
@@ -84,6 +86,7 @@ static int tac_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
        char *pkgId = NULL;
        char *root = NULL;
        char *exec = NULL;
+       bool *isReadOnly = (bool*)userData;
 
        int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
        if (ret != PMINFO_R_OK) {
@@ -91,6 +94,10 @@ static int tac_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
                return -1;
        }
 
+       if (userData == NULL || isReadOnlyPkg(pkgId) != *isReadOnly) {
+               return -1;
+       }
+
        ret = pkgmgrinfo_appinfo_get_root_path(handle, &root);
        if (ret != PMINFO_R_OK) {
                _SERR("Failed to get root path");
@@ -128,7 +135,7 @@ static int tac_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
                                "INSERT INTO TAC (PKGID, NUGET, NAME, VERSION) " \
                                "VALUES (%Q, %Q, %Q, %Q);",     pkgId, nuget.c_str(), name.c_str(), version.c_str());
                        insertDB(tac_db, sql);
-                       restore_nuget.push_back(concatPath(__DOTNET_DIR, nuget));
+                       restore_nuget.push_back(concatPath(*isReadOnly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR, nuget));
                        sqlite3_free(sql);
                }
        }
@@ -137,20 +144,21 @@ static int tac_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
        return 0;
 }
 
-tac_error_e tac_restoreDB()
+tac_error_e tac_restoreDB(bool isReadonly)
 {
-       if (!removeFile(TAC_APP_LIST_RESTORE_DB)) {
-               _SERR("Failed to remove of %s", TAC_APP_LIST_RESTORE_DB);
+       std::string tacRestoreDbPath = tacDBPath(isReadonly, TAC_APP_LIST_RESTORE_DB);
+       if (!removeFile(tacRestoreDbPath)) {
+               _SERR("Failed to remove of %s", tacRestoreDbPath.c_str());
                return TAC_ERROR_UNKNOWN;
        }
 
-       std::string dbRestoreJournal = TAC_APP_LIST_RESTORE_DB + std::string("-journal");
+       std::string dbRestoreJournal = tacRestoreDbPath + std::string("-journal");
        if (!removeFile(dbRestoreJournal)) {
                _SERR("Failed to remove of %s", dbRestoreJournal.c_str());
                return TAC_ERROR_UNKNOWN;
        }
 
-       tac_db = createDB(TAC_APP_LIST_RESTORE_DB, CREATE_TAC_DB_TABLE);
+       tac_db = createDB(tacRestoreDbPath, CREATE_TAC_DB_TABLE);
        if (!tac_db) {
                _SERR("Sqlite create error");
                return TAC_ERROR_UNKNOWN;
@@ -169,7 +177,7 @@ tac_error_e tac_restoreDB()
                return TAC_ERROR_UNKNOWN;
        }
 
-       ret = pkgmgrAppMDFilterForeach(handle, tac_restoreDBCb, NULL);
+       ret = pkgmgrAppMDFilterForeach(handle, tac_restoreDBCb, &isReadonly);
        if (ret != 0) {
                pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
                return TAC_ERROR_UNKNOWN;
@@ -182,16 +190,17 @@ tac_error_e tac_restoreDB()
                tac_db = NULL;
        }
 
-       if (!copyFile(TAC_APP_LIST_RESTORE_DB, TAC_APP_LIST_DB)) {
-               _SERR("Failed to copy of %s", TAC_APP_LIST_DB);
+       std::string tacDbPath = tacDBPath(isReadonly, TAC_APP_LIST_DB);
+       if (!copyFile(tacRestoreDbPath, tacDbPath)) {
+               _SERR("Failed to copy of %s", tacDbPath.c_str());
                return TAC_ERROR_UNKNOWN;
        }
-       if (!removeFile(TAC_APP_LIST_RESTORE_DB)) {
-               _SERR("Failed to remove of %s", TAC_APP_LIST_RESTORE_DB);
+       if (!removeFile(tacRestoreDbPath)) {
+               _SERR("Failed to remove of %s", tacRestoreDbPath.c_str());
                return TAC_ERROR_UNKNOWN;
        }
 
-       std::string dbJournal = TAC_APP_LIST_DB + std::string("-journal");
+       std::string dbJournal = tacDbPath + std::string("-journal");
        if (!copyFile(dbRestoreJournal, dbJournal)) {
                _SERR("Failed to copy of %s", dbJournal.c_str());
                return TAC_ERROR_UNKNOWN;
@@ -201,7 +210,7 @@ tac_error_e tac_restoreDB()
                return TAC_ERROR_UNKNOWN;
        }
 
-       cleanupDirectory();
+       cleanupDirectory(isReadonly);
 
        return TAC_ERROR_NONE;
 }
@@ -243,20 +252,23 @@ tac_error_e disableTACPackage(const std::string& pkgId)
                                std::string fileName = symlinkAssembly.path().filename().string();
                                if (isSymlinkFile(symPath)) {
                                        std::string originPath = bf::read_symlink(symPath).string();
-                                       if (!isR2RImage(symPath)) {
-                                               std::string dllPath = concatPath(binDir, fileName);
-                                               if (!copyFile(originPath, dllPath)) {
-                                                       _SERR("Failed to copy of %s", dllPath.c_str());
-                                                       return TAC_ERROR_UNKNOWN;
-                                               }
-                                               copySmackAndOwnership(binDir.c_str(), concatPath(binDir, fileName).c_str());
-                                       } else {
+                                       if (isNativeImage(fileName)) {
                                                std::string niPath = concatPath(binNIDir, fileName);
                                                if (!copyFile(originPath, niPath)) {
                                                        _SERR("Failed to copy of %s", niPath.c_str());
                                                        return TAC_ERROR_UNKNOWN;
                                                }
                                                copySmackAndOwnership(binDir.c_str(), niPath.c_str());
+                                               std::string dllFile = changeExtension(niPath, ".ni.dll", ".dll");
+                                               bf::create_symlink(niPath, dllFile);
+                                               copySmackAndOwnership(niPath, dllFile, true);
+                                       } else {
+                                               std::string dllPath = concatPath(binDir, fileName);
+                                               if (!copyFile(changeExtension(originPath, ".ni.dll", ".dll"), dllPath)) {
+                                                       _SERR("Failed to copy of %s", dllPath.c_str());
+                                                       return TAC_ERROR_UNKNOWN;
+                                               }
+                                               copySmackAndOwnership(binDir.c_str(), concatPath(binDir, fileName).c_str());
                                        }
                                }
                        }
@@ -274,6 +286,7 @@ tac_error_e disableTACPackage(const std::string& pkgId)
 
 tac_error_e enableTACPackage(const std::string& pkgId)
 {
+       std::string tacLocation = isReadOnlyPkg(pkgId) ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
        std::string rootPath = getRootPath(pkgId);
        if (rootPath.empty()) {
                _SERR("Failed to get root path from [%s]", pkgId.c_str());
@@ -319,7 +332,7 @@ tac_error_e enableTACPackage(const std::string& pkgId)
        for (auto& npAssembly : depsJsonParser(rootPath, execName)) {
                std::string nugetPackage = npAssembly.substr(0, npAssembly.rfind(':'));
                std::string assemblyName = npAssembly.substr(npAssembly.rfind(':') + 1);
-               std::string nugetPath = concatPath(__DOTNET_DIR, nugetPackage);
+               std::string nugetPath = concatPath(tacLocation, nugetPackage);
                if (exist(nugetPath)) {
                        std::string originPath = concatPath(nugetPath, assemblyName);
                        if (exist(originPath)) {
@@ -338,16 +351,25 @@ tac_error_e enableTACPackage(const std::string& pkgId)
        for (auto& originPath : enableNuget) {
                if (exist(originPath)) {
                        std::string fileName = originPath.substr(originPath.rfind('/') + 1);
+                       std::string originNIPath = changeExtension(originPath, ".dll", ".ni.dll");
                        if (exist(binNIDir)) {
-                               std::string originNIPath = changeExtension(originPath, "dll", "ni.dll");
                                if (exist(originNIPath)) {
-                                       if (createSymlinkFile(tacDir, binNIDir, originNIPath, changeExtension(fileName, "dll", "ni.dll")) != TAC_ERROR_NONE) {
+                                       if (createSymlinkFile(tacDir, binNIDir, originNIPath, changeExtension(fileName, ".dll", ".ni.dll")) != TAC_ERROR_NONE) {
                                                return TAC_ERROR_UNKNOWN;
+                                       } else {
+                                               if (remove(concatPath(binNIDir, fileName).c_str())) {
+                                                       _SERR("Failed to remove of %s", concatPath(binNIDir, fileName).c_str());
+                                                       return TAC_ERROR_UNKNOWN;
+                                               }
                                        }
                                }
-                       }
-                       if (createSymlinkFile(tacDir, binDir, originPath, fileName) != TAC_ERROR_NONE) {
-                               return TAC_ERROR_UNKNOWN;
+                               if (createSymlinkFile(tacDir, binDir, originNIPath, fileName) != TAC_ERROR_NONE) {
+                                       return TAC_ERROR_UNKNOWN;
+                               }
+                       } else {
+                               if (createSymlinkFile(tacDir, binDir, originPath, fileName) != TAC_ERROR_NONE) {
+                                       return TAC_ERROR_UNKNOWN;
+                               }
                        }
                }
        }
@@ -360,7 +382,7 @@ tac_error_e enableTACPackage(const std::string& pkgId)
 std::vector<std::string> depsJsonParser(const std::string& rootPath, const std::string& execName)
 {
        std::vector<std::string> parserData;
-       std::string depsJsonName = changeExtension(execName, "dll", "deps.json");
+       std::string depsJsonName = changeExtension(execName, ".dll", ".deps.json");
        std::string depsJsonPath = concatPath(rootPath, depsJsonName);
        try {
                if (exist(depsJsonPath)) {
@@ -427,6 +449,7 @@ static int tlc_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
        char *pkgId = NULL;
        char *root = NULL;
        std::string rootPath;
+       bool *isReadOnly = (bool*)userData;
 
        int ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
        if (ret != PMINFO_R_OK) {
@@ -434,6 +457,10 @@ static int tlc_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
                return -1;
        }
 
+       if (userData == NULL || isReadOnlyPkg(pkgId) != *isReadOnly) {
+               return -1;
+       }
+
        ret = pkgmgrinfo_appinfo_get_root_path(handle, &root);
        if (ret != PMINFO_R_OK) {
                _SERR("Failed to get root path");
@@ -454,20 +481,21 @@ static int tlc_restoreDBCb(pkgmgrinfo_appinfo_h handle, void *userData)
        return 0;
 }
 
-tac_error_e tlc_restoreDB()
+tac_error_e tlc_restoreDB(bool isReadonly)
 {
-       if (!removeFile(TLC_APP_LIST_RESTORE_DB)) {
-               _SERR("Failed to remove of %s", TLC_APP_LIST_RESTORE_DB);
+       std::string tlcRestoreDbPath = tacDBPath(isReadonly, TLC_APP_LIST_RESTORE_DB);
+       if (!removeFile(tlcRestoreDbPath)) {
+               _SERR("Failed to remove of %s", tlcRestoreDbPath.c_str());
                return TAC_ERROR_UNKNOWN;
        }
 
-       std::string dbRestoreJournal = TLC_APP_LIST_RESTORE_DB + std::string("-journal");
+       std::string dbRestoreJournal = tlcRestoreDbPath + std::string("-journal");
        if (!removeFile(dbRestoreJournal)) {
                _SERR("Failed to remove of %s", dbRestoreJournal.c_str());
                return TAC_ERROR_UNKNOWN;
        }
 
-       tlc_db = createDB(TLC_APP_LIST_RESTORE_DB, CREATE_TLC_DB_TABLE);
+       tlc_db = createDB(tlcRestoreDbPath, CREATE_TLC_DB_TABLE);
        if (!tlc_db) {
                _SERR("Sqlite create error");
                return TAC_ERROR_UNKNOWN;
@@ -486,7 +514,7 @@ tac_error_e tlc_restoreDB()
                return TAC_ERROR_UNKNOWN;
        }
 
-       ret = pkgmgrAppMDFilterForeach(handle, tlc_restoreDBCb, NULL);
+       ret = pkgmgrAppMDFilterForeach(handle, tlc_restoreDBCb, &isReadonly);
        if (ret != 0) {
                pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
                return TAC_ERROR_UNKNOWN;
@@ -499,16 +527,17 @@ tac_error_e tlc_restoreDB()
                tlc_db = NULL;
        }
 
-       if (!copyFile(TLC_APP_LIST_RESTORE_DB, TLC_APP_LIST_DB)) {
-               _SERR("Failed to copy of %s", TLC_APP_LIST_DB);
+       std::string tlcDbPath = tacDBPath(isReadonly, TLC_APP_LIST_DB);
+       if (!copyFile(tlcRestoreDbPath, tlcDbPath)) {
+               _SERR("Failed to copy of %s", tlcDbPath.c_str());
                return TAC_ERROR_UNKNOWN;
        }
-       if (!removeFile(TLC_APP_LIST_RESTORE_DB)) {
-               _SERR("Failed to remove of %s", TLC_APP_LIST_RESTORE_DB);
+       if (!removeFile(tlcRestoreDbPath)) {
+               _SERR("Failed to remove of %s", tlcRestoreDbPath.c_str());
                return TAC_ERROR_UNKNOWN;
        }
 
-       std::string dbJournal = TLC_APP_LIST_DB + std::string("-journal");
+       std::string dbJournal = tlcDbPath + std::string("-journal");
        if (!copyFile(dbRestoreJournal, dbJournal)) {
                _SERR("Failed to copy of %s", dbJournal.c_str());
                return TAC_ERROR_UNKNOWN;
@@ -533,7 +562,7 @@ tac_error_e tlc_restoreDB()
                }
        };
 
-       scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
+       scanFilesInDirectory(tlcLBPath(isReadonly), convert, 0);
 
        return TAC_ERROR_NONE;
 }
index 3484b5f..9e1a231 100644 (file)
@@ -28,6 +28,7 @@
 #define __XSTR(x) #x
 #define __STR(x) __XSTR(x)
 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
+static const char* __READ_ONLY_TAC_DIR = __STR(READ_ONLY_TAC_DIR);
 #undef __STR
 #undef __XSTR
 
@@ -42,16 +43,17 @@ int sqliteCb(void *count, int argc, char **argv, char **colName)
        return 0;
 }
 
-int tac_createDB()
+int tac_createDB(bool isReadonly)
 {
-       tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
+       std::string tacDbPath = tacDBPath(isReadonly, TAC_APP_LIST_DB);
+       tac_db = createDB(tacDbPath, CREATE_TAC_DB_TABLE);
        if (!tac_db) {
                _ERR("Sqlite create error. So restore the database.");
-               if (tac_restoreDB() != TAC_ERROR_NONE) {
+               if (tac_restoreDB(isReadonly) != TAC_ERROR_NONE) {
                        _ERR("Sqlite create error");
                        return -1;
                }
-               tac_db = createDB(TAC_APP_LIST_DB, CREATE_TAC_DB_TABLE);
+               tac_db = createDB(tacDbPath, CREATE_TAC_DB_TABLE);
                if (!tac_db) {
                        _ERR("Sqlite create error");
                        return -1;
@@ -61,16 +63,17 @@ int tac_createDB()
        return 0;
 }
 
-int tac_openDB()
+int tac_openDB(bool isReadonly)
 {
-       tac_db = openDB(TAC_APP_LIST_DB);
+       std::string tacDbPath = tacDBPath(isReadonly, TAC_APP_LIST_DB);
+       tac_db = openDB(tacDbPath);
        if (!tac_db) {
                _ERR("Sqlite open error. So restore the database.");
-               if (tac_restoreDB() != TAC_ERROR_NONE) {
+               if (tac_restoreDB(isReadonly) != TAC_ERROR_NONE) {
                        _ERR("Sqlite open error");
                        return -1;
                }
-               tac_db = openDB(TAC_APP_LIST_DB);
+               tac_db = openDB(tacDbPath);
                if (!tac_db) {
                        _ERR("Sqlite open error");
                        return -1;
@@ -168,22 +171,25 @@ bool tac_closeDB()
        return false;
 }
 
-int tlc_createDB()
+int tlc_createDB(bool isReadonly)
 {
-       if (!createDir(TLC_LIBRARIES_DIR)) {
-               _ERR("Cannot create directory: %s", TLC_LIBRARIES_DIR);
+       std::string tlcPath = tlcLBPath(isReadonly);
+       if (!createDir(tlcPath)) {
+               _ERR("Cannot create directory: %s", tlcPath.c_str());
                return -1;
        }
-       copySmackAndOwnership(__DOTNET_DIR, TLC_LIBRARIES_DIR);
+       std::string tacLocation = isReadonly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
+       copySmackAndOwnership(tacLocation, tlcPath);
 
-       tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
+       std::string tlcDbPath = tacDBPath(isReadonly, TLC_APP_LIST_DB);
+       tlc_db = createDB(tlcDbPath, CREATE_TLC_DB_TABLE);
        if (!tlc_db) {
                _ERR("Sqlite create error. So restore the database.");
-               if (tlc_restoreDB() != TAC_ERROR_NONE) {
+               if (tlc_restoreDB(isReadonly) != TAC_ERROR_NONE) {
                        _ERR("Sqlite create error");
                        return -1;
                }
-               tlc_db = createDB(TLC_APP_LIST_DB, CREATE_TLC_DB_TABLE);
+               tlc_db = createDB(tlcDbPath, CREATE_TLC_DB_TABLE);
                if (!tlc_db) {
                        _ERR("Sqlite create error");
                        return -1;
@@ -193,16 +199,17 @@ int tlc_createDB()
        return 0;
 }
 
-int tlc_openDB()
+int tlc_openDB(bool isReadonly)
 {
-       tlc_db = openDB(TLC_APP_LIST_DB);
+       std::string tlcDbPath = tacDBPath(isReadonly, TLC_APP_LIST_DB);
+       tlc_db = openDB(tlcDbPath);
        if (!tlc_db) {
                _ERR("Sqlite open error. So restore the database.");
-               if (tlc_restoreDB() != TAC_ERROR_NONE) {
+               if (tlc_restoreDB(isReadonly) != TAC_ERROR_NONE) {
                        _ERR("Sqlite open error");
                        return 0;
                }
-               tlc_db = openDB(TLC_APP_LIST_DB);
+               tlc_db = openDB(tlcDbPath);
                if (!tlc_db) {
                        _ERR("Sqlite open error");
                        return 0;
index b8b7b66..9260cba 100644 (file)
@@ -38,6 +38,7 @@
 #define __XSTR(x) #x
 #define __STR(x) __XSTR(x)
 static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
+static const char* __READ_ONLY_TAC_DIR = __STR(READ_ONLY_TAC_DIR);
 #undef __STR
 #undef __XSTR
 
@@ -50,6 +51,8 @@ static std::vector<std::string> updateTlc;
 static tac_state tacState = TAC_STATE_NONE;
 static std::string prevInstallPkgId = std::string("");
 static std::string prevFinishPkgId = std::string("");
+static std::string tacLocation = __DOTNET_DIR;
+static bool isTacReadonly = false;
 
 // initialize static vector to support multi-package install scenario
 static void tacInitialize()
@@ -116,7 +119,7 @@ static bool compareSHA256Info(std::string sha256Info, std::string nugetPackage)
 static bool copyAssemblyCreateSymlink(std::string binPath, std::string tacDir, std::string nugetPackage, bool isCreateTacDir)
 {
        std::string binNiPath = concatPath(binPath, APP_NI_SUB_DIR);
-       std::string tac_version_dir = concatPath(__DOTNET_DIR, nugetPackage);
+       std::string tac_version_dir = concatPath(tacLocation, nugetPackage);
        bool nuget_restoration = false;
        for (auto& npAssemblySha : nugetPackagesAssembliesSha) {
                std::string nuget_package_assembly = npAssemblySha.substr(0, npAssemblySha.rfind(':'));
@@ -143,9 +146,9 @@ static bool copyAssemblyCreateSymlink(std::string binPath, std::string tacDir, s
                                        break;
                                }
                                if (exist(concatPath(tac_version_dir, niFile)) && exist(binNiPath)) {
-                                       bf::create_symlink(concatPath(tac_version_dir, niFile), concatPath(tacDir, niFile), error);
+                                       bf::create_symlink(concatPath(tac_version_dir, niFile), concatPath(tacDir, assembly), error);
                                        if (error) {
-                                               _ERR("Failed to create symlink %s file", concatPath(tacDir, niFile).c_str());
+                                               _ERR("Failed to create symlink %s file", concatPath(tacDir, assembly).c_str());
                                        }
                                }
 
@@ -189,7 +192,7 @@ static void copyLibraryCreateSymlink(const std::string pkgId, std::vector<std::s
                std::string library = librarySha.substr(0, librarySha.find(':'));
                std::string filename = library.substr(library.rfind('/') + 1);
                std::string fileSha = filename + ".." + librarySha.substr(librarySha.find(':') + 1);
-               std::string shaPath = concatPath(TLC_LIBRARIES_DIR, fileSha);
+               std::string shaPath = concatPath(tlcLBPath(isTacReadonly), fileSha);
                bool fileCopied = false;
                if (!exist(shaPath)) {
                        if (!copyFile(library, shaPath)) {
@@ -261,7 +264,7 @@ static int generateTAC(const std::string& pkgId, const std::string& binPath)
                _INFO("TAC version : %s", tac_version.c_str());
 
                bs::error_code error;
-               std::string tac_version_dir = concatPath(__DOTNET_DIR, np);
+               std::string tac_version_dir = concatPath(tacLocation, np);
                std::string sha256_info = concatPath(tac_version_dir, TAC_SHA_256_INFO);
                bool isCreateTacDir = false;
                if (!exist(tac_version_dir)) {
@@ -347,7 +350,7 @@ void tacUpdateDB(const std::string& pkgId)
                }
 
                if (count == 0) {
-                       std::string tac_version_dir_prev = concatPath(__DOTNET_DIR, unp);
+                       std::string tac_version_dir_prev = concatPath(tacLocation, unp);
                        std::string tac_version_dir_backup = tac_version_dir_prev + ".bck";
                        if (!copyDir(tac_version_dir_prev, tac_version_dir_backup)) {
                                _ERR("Failed to copy of %s to %s", tac_version_dir_prev.c_str(), tac_version_dir_backup.c_str());
@@ -370,7 +373,7 @@ void tlcUpdateDB(const std::string& pkgId)
                }
 
                if (count == 0) {
-                       std::string library_prev = concatPath(TLC_LIBRARIES_DIR, ulp);
+                       std::string library_prev = concatPath(tlcLBPath(isTacReadonly), ulp);
                        std::string library_backup = library_prev + ".bck";
                        if (!copyFile(library_prev, library_backup)) {
                                _ERR("Failed to copy of %s", library_prev.c_str());
@@ -391,6 +394,9 @@ int tacInstall(const std::string& pkgId, tac_state state, bool tacForce)
 
        tacInitialize();
 
+       isTacReadonly = isReadOnlyPkg(pkgId);
+       tacLocation = isTacReadonly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
+
        // Can be multiple apps in one package
        if (strcmp(pkgId.c_str(), prevInstallPkgId.c_str()) == 0) {
                _INFO("TAC Plugin(INSTALL) already run for same pkgId (%s)", pkgId.c_str());
@@ -430,7 +436,7 @@ int tacInstall(const std::string& pkgId, tac_state state, bool tacForce)
                return 0;
        }
 
-       if (tac_createDB() != 0) {
+       if (tac_createDB(isTacReadonly) != 0) {
                return -1;
        }
 
@@ -440,7 +446,7 @@ int tacInstall(const std::string& pkgId, tac_state state, bool tacForce)
        }
 
        ///// TLC /////
-       if (tlc_createDB() != 0) {
+       if (tlc_createDB(isTacReadonly) != 0) {
                tac_closeDB();
                return -1;
        }
@@ -459,6 +465,9 @@ int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce)
 
        tacInitialize();
 
+       isTacReadonly = isReadOnlyPkg(pkgId);
+       tacLocation = isTacReadonly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
+
        // Can be multiple apps in one package
        if (strcmp(pkgId.c_str(), prevInstallPkgId.c_str()) == 0) {
                _INFO("TAC Plugin(UPGRADE) already run for same pkgId (%s)", pkgId.c_str());
@@ -498,7 +507,7 @@ int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce)
        }
 
        tacState = TAC_STATE_UPGRADE;
-       if (tac_createDB() != 0) {
+       if (tac_createDB(isTacReadonly) != 0) {
                return -1;
        }
 
@@ -539,7 +548,7 @@ int tacUpgrade(const std::string& pkgId, tac_state state, bool tacForce)
        }
 
        ///// TLC /////
-       if (tlc_createDB() != 0) {
+       if (tlc_createDB(isTacReadonly) != 0) {
                tac_closeDB();
                return -1;
        }
@@ -569,6 +578,9 @@ int tacUninstall(const std::string& pkgId, tac_state state)
 
        tacInitialize();
 
+       isTacReadonly = isReadOnlyPkg(pkgId);
+       tacLocation = isTacReadonly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
+
        // Can be multiple apps in one package
        if (strcmp(pkgId.c_str(), prevInstallPkgId.c_str()) == 0) {
                _INFO("TAC Plugin(UNINSTALL) already run for same pkgId (%s)", pkgId.c_str());
@@ -577,7 +589,7 @@ int tacUninstall(const std::string& pkgId, tac_state state)
        prevInstallPkgId = pkgId;
 
        tacState= state;
-       if (tac_openDB() != 0) {
+       if (tac_openDB(isTacReadonly) != 0) {
                return -1;
        }
 
@@ -591,7 +603,7 @@ int tacUninstall(const std::string& pkgId, tac_state state)
        tacUpdateDB(pkgId);
 
        ///// TLC /////
-       if (tlc_openDB() != 0) {
+       if (tlc_openDB(isTacReadonly) != 0) {
                tac_closeDB();
                return -1;
        }
@@ -622,7 +634,7 @@ int tacRemoved(const std::string& pkgId)
 
 void undoStep(std::string tac)
 {
-       std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
+       std::string current_tac = concatPath(tacLocation, tac.substr(0, tac.find('/')));
        try {
                for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
                        std::string bck_path = bck.path().string();
@@ -647,7 +659,7 @@ void undoStep(std::string tac)
                }
        };
 
-       scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
+       scanFilesInDirectory(tlcLBPath(isTacReadonly), convert, 0);
 }
 
 void install_Undo()
@@ -688,6 +700,9 @@ int tacUndo(const std::string& pkgId)
        _DBG("[===== PKGMGR_MDPARSER_PLUGIN_UNDO =====]");
        _INFO("PackageID : %s", pkgId.c_str());
 
+       isTacReadonly = isReadOnlyPkg(pkgId);
+       tacLocation = isTacReadonly ? __READ_ONLY_TAC_DIR : __DOTNET_DIR;
+
        // Can be multiple apps in one package
        if (strcmp(pkgId.c_str(), prevFinishPkgId.c_str()) == 0) {
                _INFO("TAC Plugin(UNDO) already run for same pkgId (%s)", pkgId.c_str());
@@ -714,10 +729,10 @@ int tacUndo(const std::string& pkgId)
 
 void changeOwnershipTAC(std::string current_tac)
 {
-       copySmackAndOwnership(__DOTNET_DIR, current_tac);
+       copySmackAndOwnership(tacLocation, current_tac);
        try {
                for (auto& path : bf::recursive_directory_iterator(current_tac))
-                       copySmackAndOwnership(__DOTNET_DIR, path.path().string());
+                       copySmackAndOwnership(tacLocation, path.path().string());
        } catch (const bf::filesystem_error& error) {
                _ERR("Failed to recursive directory: %s", error.what());
        }
@@ -725,7 +740,7 @@ void changeOwnershipTAC(std::string current_tac)
 
 void cleanStep(std::string tac)
 {
-       std::string current_tac = concatPath(__DOTNET_DIR, tac.substr(0, tac.find('/')));
+       std::string current_tac = concatPath(tacLocation, tac.substr(0, tac.find('/')));
        try {
                for (auto& bck : bf::recursive_directory_iterator(current_tac)) {
                        std::string bck_path = bck.path().string();
@@ -764,18 +779,18 @@ void cleanStep(std::string tac)
                }
        };
 
-       scanFilesInDirectory(TLC_LIBRARIES_DIR, convert, 0);
+       scanFilesInDirectory(tlcLBPath(isTacReadonly), convert, 0);
 }
 
 void install_Clean()
 {
        for (auto& cd : createDirectories) {
                changeOwnershipTAC(cd);
-               copySmackAndOwnership(__DOTNET_DIR, cd.substr(0, cd.rfind('/')));
+               copySmackAndOwnership(tacLocation, cd.substr(0, cd.rfind('/')));
        }
 
        for (auto& cl : createLibraries) {
-               copySmackAndOwnership(__DOTNET_DIR, cl);
+               copySmackAndOwnership(tacLocation, cl);
        }
 }
 
@@ -792,7 +807,7 @@ void update_Clean()
        if (!tacDB.empty()) {
                for (auto& np : tacDB) {
                        cleanStep(np);
-                       changeOwnershipTAC(concatPath(__DOTNET_DIR, np.substr(0, np.find('/'))));
+                       changeOwnershipTAC(concatPath(tacLocation, np.substr(0, np.find('/'))));
                }
        }
        unInstall_Clean();
@@ -854,13 +869,15 @@ int tacClean(const std::string& pkgId)
        }
 
        if (tac_closeDB()) {
-               copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB);
-               copySmackAndOwnership(__DOTNET_DIR, TAC_APP_LIST_DB + std::string("-journal"));
+               std::string tacDbPath = tacDBPath(isTacReadonly, TAC_APP_LIST_DB);
+               copySmackAndOwnership(tacLocation, tacDbPath);
+               copySmackAndOwnership(tacLocation, tacDbPath + std::string("-journal"));
        }
 
        if (tlc_closeDB()) {
-               copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB);
-               copySmackAndOwnership(__DOTNET_DIR, TLC_APP_LIST_DB + std::string("-journal"));
+               std::string tlcDbPath = tacDBPath(isTacReadonly, TLC_APP_LIST_DB);
+               copySmackAndOwnership(tacLocation, tlcDbPath);
+               copySmackAndOwnership(tacLocation, tlcDbPath + std::string("-journal"));
        }
 
        return 0;
index 2eac3b7..2d1f41c 100644 (file)
@@ -65,10 +65,12 @@ void PathManager::updateAppRelatedPath(const std::string& appRootPath, const std
        appTacPath = concatPath(appBinPath, TAC_SYMLINK_SUB_DIR);
        appPaths = appRootPath + ":" + appBinPath + ":" + appLibPath + ":" + appTacPath;
        appNIPaths = appNIBinPath + ":" + appNILibPath + ":" + appTacPath;
+       appCLRPaths = appNIPaths + ":" + appPaths;
 
        if (!extraDllPaths.empty()) {
                appPaths = appPaths + ":" + extraDllPaths;
                appNIPaths = appNIPaths + ":" + extraDllPaths;
+               appCLRPaths = appCLRPaths + ":" + extraDllPaths;
        }
 }
 
@@ -192,6 +194,7 @@ void PathManager::setExtraDllPaths(const char* paths)
        if (!extraDllPaths.empty()) {
                appPaths = appPaths + ":" + extraDllPaths;
                appNIPaths = appNIPaths + ":" + extraDllPaths;
+               appCLRPaths = appCLRPaths + ":" + extraDllPaths;
        }
 }
 
@@ -235,6 +238,12 @@ const std::string& PathManager::getAppNIPaths()
        return appNIPaths;
 }
 
+// return ni dll and dll searching paths for app
+const std::string& PathManager::getAppCLRPaths()
+{
+       return appCLRPaths;
+}
+
 // return native dll searching paths for app
 const std::string& PathManager::getNativeDllSearchingPaths()
 {
index f1dcc59..a637db9 100644 (file)
 #include "path_manager.h"
 #include "r2r_checker.h"
 
+#define __XSTR(x) #x
+#define __STR(x) __XSTR(x)
+static const char* __DOTNET_DIR = __STR(DOTNET_DIR);
+static const char* __READ_ONLY_TAC_DIR = __STR(READ_ONLY_TAC_DIR);
+#undef __STR
+#undef __XSTR
+
 static bool iCompare(const std::string& a, int aOffset, const std::string& b, int bOffset, int length)
 {
        return static_cast<int>(a.length()) - length >= aOffset &&
@@ -59,6 +66,11 @@ bool isManagedAssembly(const std::string& fileName)
        return iCompare(fileName, fileName.size()-4, ".dll", 0, 4);
 }
 
+bool isNativeImage(const std::string& fileName)
+{
+       return iCompare(fileName, fileName.size()-7, ".ni", 0, 3);
+}
+
 std::string concatPath(const std::string& path1, const std::string& path2)
 {
        std::string path(path1);
@@ -265,6 +277,45 @@ bool isReadOnlyArea(const std::string& path)
 
 }
 
+bool isReadOnlyPkg(const std::string& pkgId)
+{
+       uid_t uid = 0;
+       int ret = 0;
+       bool readonly = false;
+       pkgmgrinfo_pkginfo_h handle;
+
+       if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
+               _ERR("Failed to get UID");
+               return false;
+       }
+
+       ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
+       if (ret != PMINFO_R_OK) {
+               _ERR("Fail to get pkginfo");
+               return false;
+       }
+
+       ret = pkgmgrinfo_pkginfo_is_readonly(handle, &readonly);
+       if (ret != PMINFO_R_OK) {
+               _ERR("Fail to get is_readonly");
+               pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+               return false;
+       }
+
+       pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
+       return readonly;
+}
+
+std::string tacDBPath(bool isReadonly, const std::string& dbName)
+{
+       return isReadonly ? concatPath(__READ_ONLY_TAC_DIR, dbName) : concatPath(__DOTNET_DIR, dbName);
+}
+
+std::string tlcLBPath(bool isReadonly)
+{
+       return isReadonly ? concatPath(__READ_ONLY_TAC_DIR, TLC_LIBRARIES_DIR) : concatPath(__DOTNET_DIR, TLC_LIBRARIES_DIR);
+}
+
 std::string getBaseName(const std::string& path)
 {
        auto pos = path.find_last_of(PATH_SEPARATOR);
@@ -291,7 +342,11 @@ std::string replaceAll(const std::string& str, const std::string& pattern, const
 
 std::string changeExtension(const std::string& path, const std::string& from, const std::string& to)
 {
-       return path.substr(0, path.rfind(from)) + to;
+       std::string result = path;
+       if (path.rfind(from) != std::string::npos) {
+               result = path.substr(0, path.rfind(from)) + to;
+       }
+       return result;
 }
 
 bool isFile(const std::string& path)
index ec6f15f..737e625 100644 (file)
@@ -4,6 +4,7 @@
     </request>
     <assign>
         <filesystem path="/opt/usr/dotnet" label="System::Shared" type="transmutable" />
+        <filesystem path="/usr/share/dotnet.tizen/tac" label="System::Shared" type="transmutable" />
         <filesystem path="/opt/usr/dotnet/apps" label="User::Home"/>
         <filesystem path="/usr/bin/dotnet-loader" label="User" exec_label="User" />
         <filesystem path="/usr/bin/dotnet-hydra-loader" label="User" exec_label="User" />
index c877058..12496a9 100644 (file)
@@ -4,6 +4,9 @@
 
 PATH=/usr/bin:/bin:/usr/sbin:/sbin
 
+# remove application native image files of RO app
+rm -rf /opt/usr/dotnet/apps/*
+
 /usr/bin/dotnettool --tac-regen-all
 /usr/bin/dotnettool --ni-regen-all-app --skip-ro-app
 /usr/bin/dotnettool --resolve-all-app
index 20b0899..9b63d32 100644 (file)
@@ -58,6 +58,7 @@ Requires(preun): /usr/bin/systemctl
 %define _native_lib_dir /usr/share/dotnet.tizen/lib
 %define _dotnet_dir /opt/usr/dotnet
 %define _readonly_app_update_dir /opt/usr/dotnet/apps
+%define _readonly_tac_dir /usr/share/dotnet.tizen/tac
 %define _system_base_addr_file /opt/usr/dotnet.system.base.addr
 %define _tizen_preload_dir /usr/share/dotnet.tizen/preload
 
@@ -161,6 +162,7 @@ cmake \
        -DINSTALL_PLUGIN_DIR=%{_install_plugin_dir} \
        -DDOTNET_DIR=%{_dotnet_dir} \
        -DREAD_ONLY_APP_UPDATE_DIR=%{_readonly_app_update_dir} \
+       -DREAD_ONLY_TAC_DIR=%{_readonly_tac_dir} \
        -DVERSION=%{version} \
        -DNATIVE_LIB_DIR=%{_native_lib_dir} \
 %ifarch %{arm} aarch64
@@ -187,6 +189,7 @@ mv Managed/Tizen.Runtime/bin/Release/Tizen.Runtime.pdb %{buildroot}%{_framework_
 
 mkdir -p %{buildroot}%{_dotnet_dir}
 mkdir -p %{buildroot}%{_readonly_app_update_dir}
+mkdir -p %{buildroot}%{_readonly_tac_dir}
 mkdir -p %{buildroot}%{_native_lib_dir}
 ln -sf %{_libdir}/libsqlite3.so.0 %{buildroot}%{_native_lib_dir}/libsqlite3.so
 
@@ -240,6 +243,7 @@ chsmack -a User /usr/bin/dotnet-uts-loader
 %{_framework_dir}/Tizen.Runtime.dll
 %{_dotnet_dir}
 %{_readonly_app_update_dir}
+%{_readonly_tac_dir}
 %{_tizen_preload_dir}
 %{_rw_update_scripts_dir}/%{_rw_dotnet_update_script}
 %if 0%{_build_dotnet_plugin}
diff --git a/scripts/github-comment.sh b/scripts/github-comment.sh
new file mode 100755 (executable)
index 0000000..fb4fba5
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+html_content="$(cat $2)"
+
+json_payload=$(jq -n --arg body "$html_content" '{"body": $body}')
+echo "[GITHUB COMMENT] json_payload --> ${json_payload}"
+
+curl -L \
+    -X POST \
+    -H "Accept: application/vnd.github+json" \
+    -H "Authorization: Bearer $JH_GITHUB_TOKEN" \
+    https://github.sec.samsung.net/api/v3/repos/dotnet/launcher/issues/$1/comments \
+    -d "$json_payload"
+
+exit 0
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.sln b/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.sln
new file mode 100755 (executable)
index 0000000..543df3d
--- /dev/null
@@ -0,0 +1,27 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio Version 17\r
+VisualStudioVersion = 17.5.33627.172\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher_TC_EXCEPTION_01", "Launcher_TC_EXCEPTION_01\Launcher_TC_EXCEPTION_01.csproj", "{54606EFF-D558-4127-97BF-7020DCED4DA7}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Any CPU = Debug|Any CPU\r
+               Release|Any CPU = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {54606EFF-D558-4127-97BF-7020DCED4DA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+               {54606EFF-D558-4127-97BF-7020DCED4DA7}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+               {54606EFF-D558-4127-97BF-7020DCED4DA7}.Debug|Any CPU.Deploy.0 = Debug|Any CPU\r
+               {54606EFF-D558-4127-97BF-7020DCED4DA7}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+               {54606EFF-D558-4127-97BF-7020DCED4DA7}.Release|Any CPU.Build.0 = Release|Any CPU\r
+               {54606EFF-D558-4127-97BF-7020DCED4DA7}.Release|Any CPU.Deploy.0 = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+               SolutionGuid = {988BEE6E-FFA8-4340-BED5-A5CD6478EC93}\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.cs b/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.cs
new file mode 100755 (executable)
index 0000000..5eaf56d
--- /dev/null
@@ -0,0 +1,69 @@
+using System;\r
+using Tizen.NUI;\r
+using Tizen.NUI.BaseComponents;\r
+\r
+namespace Launcher_TC_EXCEPTION_01\r
+{\r
+    internal class Program : NUIApplication\r
+    {\r
+        private void ExceptionTest()\r
+        {\r
+            string foo = null;\r
+            foo.ToUpper();\r
+        }\r
+\r
+        public void TC()\r
+        {\r
+            try\r
+            {\r
+                ExceptionTest();\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                Console.WriteLine(e.Message);\r
+                Console.WriteLine(e.ToString());\r
+            }\r
+        }\r
+\r
+        protected override void OnCreate()\r
+        {\r
+            base.OnCreate();\r
+            Initialize();\r
+            TC();\r
+        }\r
+\r
+        void Initialize()\r
+        {\r
+            Window.Instance.KeyEvent += OnKeyEvent;\r
+\r
+            TextLabel text = new TextLabel("Hello Tizen NUI World");\r
+            text.HorizontalAlignment = HorizontalAlignment.Center;\r
+            text.VerticalAlignment = VerticalAlignment.Center;\r
+            text.TextColor = Color.Blue;\r
+            text.PointSize = 30.0f;\r
+            text.HeightResizePolicy = ResizePolicyType.FillToParent;\r
+            text.WidthResizePolicy = ResizePolicyType.FillToParent;\r
+            Window.Instance.GetDefaultLayer().Add(text);\r
+\r
+            Animation animation = new Animation(2000);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);\r
+            animation.Looping = true;\r
+            animation.Play();\r
+        }\r
+\r
+        public void OnKeyEvent(object sender, Window.KeyEventArgs e)\r
+        {\r
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))\r
+            {\r
+                Exit();\r
+            }\r
+        }\r
+\r
+        static void Main(string[] args)\r
+        {\r
+            var app = new Program();\r
+            app.Run(args);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.csproj b/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01.csproj
new file mode 100755 (executable)
index 0000000..f53261d
--- /dev/null
@@ -0,0 +1,27 @@
+<Project Sdk="Tizen.NET.Sdk/1.0.9">\r
+\r
+       <PropertyGroup>\r
+               <OutputType>Exe</OutputType>\r
+               <TargetFramework>tizen60</TargetFramework>\r
+       </PropertyGroup>\r
+\r
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+               <DebugType>portable</DebugType>\r
+       </PropertyGroup>\r
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+               <DebugType>None</DebugType>\r
+       </PropertyGroup>\r
+\r
+       <ItemGroup>\r
+               <Folder Include="lib\" />\r
+               <Folder Include="res\" />\r
+       </ItemGroup>\r
+\r
+       <ItemGroup>\r
+               <PackageReference Include="Tizen.NET.TV" Version="5.5.0.4922">\r
+                       <ExcludeAssets>Runtime</ExcludeAssets>\r
+               </PackageReference>\r
+\r
+       </ItemGroup>\r
+\r
+</Project>\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/shared/res/Launcher_TC_EXCEPTION_01.png b/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/shared/res/Launcher_TC_EXCEPTION_01.png
new file mode 100755 (executable)
index 0000000..9f3cb98
Binary files /dev/null and b/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/shared/res/Launcher_TC_EXCEPTION_01.png differ
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/tizen-manifest.xml b/tests/Apps/Launcher_TC_EXCEPTION_01/Launcher_TC_EXCEPTION_01/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..55af907
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<manifest xmlns="http://tizen.org/ns/packages" api-version="6.5" package="org.tizen.example.Launcher_TC_EXCEPTION_01" version="1.0.0">\r
+       <feature name="http://tizen.org/feature/screen.size.normal.1080.1920">true</feature>\r
+  <profile name="common" />\r
+  <ui-application appid="org.tizen.example.Launcher_TC_EXCEPTION_01"\r
+                                       exec="Launcher_TC_EXCEPTION_01.dll"\r
+                                       type="dotnet"\r
+                                       multiple="false"\r
+                                       taskmanage="true"\r
+                                       nodisplay="false"\r
+                                       launch_mode="single">\r
+    <label>Launcher_TC_EXCEPTION_01</label>\r
+    <icon>Launcher_TC_EXCEPTION_01.png</icon>\r
+  </ui-application>\r
+  <tv-info api-version="9.9.0">\r
+    <infolink>T-INFOLINK2022-1000</infolink>\r
+  </tv-info>\r
+</manifest>\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.sln b/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.sln
new file mode 100755 (executable)
index 0000000..dc3611b
--- /dev/null
@@ -0,0 +1,27 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio Version 17\r
+VisualStudioVersion = 17.5.33627.172\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher_TC_EXCEPTION_02", "Launcher_TC_EXCEPTION_02\Launcher_TC_EXCEPTION_02.csproj", "{56FEFF50-B69E-4FA4-BC8C-3717101E3506}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Any CPU = Debug|Any CPU\r
+               Release|Any CPU = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {56FEFF50-B69E-4FA4-BC8C-3717101E3506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+               {56FEFF50-B69E-4FA4-BC8C-3717101E3506}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+               {56FEFF50-B69E-4FA4-BC8C-3717101E3506}.Debug|Any CPU.Deploy.0 = Debug|Any CPU\r
+               {56FEFF50-B69E-4FA4-BC8C-3717101E3506}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+               {56FEFF50-B69E-4FA4-BC8C-3717101E3506}.Release|Any CPU.Build.0 = Release|Any CPU\r
+               {56FEFF50-B69E-4FA4-BC8C-3717101E3506}.Release|Any CPU.Deploy.0 = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+               SolutionGuid = {54AA6825-7BE4-4AF0-A5AB-6FBCC23E26D3}\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.cs b/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.cs
new file mode 100755 (executable)
index 0000000..a928380
--- /dev/null
@@ -0,0 +1,69 @@
+using System;\r
+using Tizen.NUI;\r
+using Tizen.NUI.BaseComponents;\r
+\r
+namespace Launcher_TC_EXCEPTION_02\r
+{\r
+    internal class Program : NUIApplication\r
+    {\r
+        private void ExceptionTest()\r
+        {\r
+            string foo = null;\r
+            foo.ToUpper();\r
+        }\r
+\r
+        public void TC()\r
+        {\r
+            try\r
+            {\r
+                ExceptionTest();\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                Console.WriteLine(e.Message);\r
+                Console.WriteLine(e.ToString());\r
+            }\r
+        }\r
+\r
+        protected override void OnCreate()\r
+        {\r
+            base.OnCreate();\r
+            Initialize();\r
+            TC();\r
+        }\r
+\r
+        void Initialize()\r
+        {\r
+            Window.Instance.KeyEvent += OnKeyEvent;\r
+\r
+            TextLabel text = new TextLabel("Hello Tizen NUI World");\r
+            text.HorizontalAlignment = HorizontalAlignment.Center;\r
+            text.VerticalAlignment = VerticalAlignment.Center;\r
+            text.TextColor = Color.Blue;\r
+            text.PointSize = 30.0f;\r
+            text.HeightResizePolicy = ResizePolicyType.FillToParent;\r
+            text.WidthResizePolicy = ResizePolicyType.FillToParent;\r
+            Window.Instance.GetDefaultLayer().Add(text);\r
+\r
+            Animation animation = new Animation(2000);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);\r
+            animation.Looping = true;\r
+            animation.Play();\r
+        }\r
+\r
+        public void OnKeyEvent(object sender, Window.KeyEventArgs e)\r
+        {\r
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))\r
+            {\r
+                Exit();\r
+            }\r
+        }\r
+\r
+        static void Main(string[] args)\r
+        {\r
+            var app = new Program();\r
+            app.Run(args);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.csproj b/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02.csproj
new file mode 100755 (executable)
index 0000000..f53261d
--- /dev/null
@@ -0,0 +1,27 @@
+<Project Sdk="Tizen.NET.Sdk/1.0.9">\r
+\r
+       <PropertyGroup>\r
+               <OutputType>Exe</OutputType>\r
+               <TargetFramework>tizen60</TargetFramework>\r
+       </PropertyGroup>\r
+\r
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+               <DebugType>portable</DebugType>\r
+       </PropertyGroup>\r
+       <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+               <DebugType>None</DebugType>\r
+       </PropertyGroup>\r
+\r
+       <ItemGroup>\r
+               <Folder Include="lib\" />\r
+               <Folder Include="res\" />\r
+       </ItemGroup>\r
+\r
+       <ItemGroup>\r
+               <PackageReference Include="Tizen.NET.TV" Version="5.5.0.4922">\r
+                       <ExcludeAssets>Runtime</ExcludeAssets>\r
+               </PackageReference>\r
+\r
+       </ItemGroup>\r
+\r
+</Project>\r
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/shared/res/Launcher_TC_EXCEPTION_02.png b/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/shared/res/Launcher_TC_EXCEPTION_02.png
new file mode 100755 (executable)
index 0000000..9f3cb98
Binary files /dev/null and b/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/shared/res/Launcher_TC_EXCEPTION_02.png differ
diff --git a/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/tizen-manifest.xml b/tests/Apps/Launcher_TC_EXCEPTION_02/Launcher_TC_EXCEPTION_02/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..3b722d2
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<manifest xmlns="http://tizen.org/ns/packages" api-version="6.5" package="org.tizen.example.Launcher_TC_EXCEPTION_02" version="1.0.0">\r
+       <feature name="http://tizen.org/feature/screen.size.normal.1080.1920">true</feature>\r
+  <profile name="common" />\r
+  <ui-application appid="org.tizen.example.Launcher_TC_EXCEPTION_02"\r
+                                       exec="Launcher_TC_EXCEPTION_02.dll"\r
+                                       type="dotnet-nui"\r
+                                       multiple="false"\r
+                                       taskmanage="true"\r
+                                       nodisplay="false"\r
+                                       launch_mode="single">\r
+    <label>Launcher_TC_EXCEPTION_02</label>\r
+    <icon>Launcher_TC_EXCEPTION_02.png</icon>\r
+  </ui-application>\r
+  <tv-info api-version="9.9.0">\r
+    <infolink>T-INFOLINK2022-1000</infolink>\r
+  </tv-info>\r
+</manifest>\r
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.sln b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.sln
new file mode 100755 (executable)
index 0000000..1d4f0dc
--- /dev/null
@@ -0,0 +1,27 @@
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio Version 16\r
+VisualStudioVersion = 16.0.31005.135\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher_TC_PLUGIN_11", "Launcher_TC_PLUGIN_11\Launcher_TC_PLUGIN_11.csproj", "{3daa496e-195a-4708-8316-dd6207adbd9a}"\r
+EndProject\r
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{c9bd2802-b0a0-41c2-9453-e159261615bc}"\r
+       ProjectSection(SolutionItems) = preProject\r
+               tizen_workspace.yaml = tizen_workspace.yaml\r
+       EndProjectSection\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Any CPU = Debug|Any CPU\r
+               Release|Any CPU = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {3daa496e-195a-4708-8316-dd6207adbd9a}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+               {3daa496e-195a-4708-8316-dd6207adbd9a}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+               {3daa496e-195a-4708-8316-dd6207adbd9a}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+               {3daa496e-195a-4708-8316-dd6207adbd9a}.Release|Any CPU.Build.0 = Release|Any CPU\r
+\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Directory.Build.targets b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Directory.Build.targets
new file mode 100755 (executable)
index 0000000..67fcf5d
--- /dev/null
@@ -0,0 +1,21 @@
+<!--\r
+***********************************************************************************************\r
+<Build.Directory.targets>\r
+WARNING:  DO NOT MODIFY this file. Incorrect changes to this file will make it\r
+          impossible to load or build your projects from the IDE.\r
+\r
+***********************************************************************************************\r
+-->\r
+\r
+<Project>    \r
+       <Target Name="BuildDotnet" AfterTargets="TizenPackage" >\r
+        <Message Text="Tizen Build starts here ------------" Importance="high"/>\r
+        <Message Text="$(MSBuildProjectDirectory)" Importance="high"/>\r
+        <PropertyGroup>\r
+            <WorkspaceFolder>$([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))</WorkspaceFolder>\r
+        </PropertyGroup>\r
+        <Message Text="Workspace: '$(WorkspaceFolder)'"  Importance="high" />\r
+\r
+               <Exec Command="C:\tizen-studio\tools\tizen-core\tz.exe pack  -S $(ProjectDir) $(WorkspaceFolder)"> </Exec>\r
+    </Target>\r
+</Project>\r
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.cs b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.cs
new file mode 100755 (executable)
index 0000000..9c6e1b8
--- /dev/null
@@ -0,0 +1,49 @@
+using System;\r
+using Tizen.NUI;\r
+using Tizen.NUI.BaseComponents;\r
+\r
+namespace Launcher_TC_PLUGIN_11\r
+{\r
+    class Program : NUIApplication\r
+    {\r
+        protected override void OnCreate()\r
+        {\r
+            base.OnCreate();\r
+            Initialize();\r
+        }\r
+\r
+        void Initialize()\r
+        {\r
+            Window.Instance.KeyEvent += OnKeyEvent;\r
+\r
+            TextLabel text = new TextLabel("Hello Tizen NUI World");\r
+            text.HorizontalAlignment = HorizontalAlignment.Center;\r
+            text.VerticalAlignment = VerticalAlignment.Center;\r
+            text.TextColor = Color.Blue;\r
+            text.PointSize = 12.0f;\r
+            text.HeightResizePolicy = ResizePolicyType.FillToParent;\r
+            text.WidthResizePolicy = ResizePolicyType.FillToParent;\r
+            Window.Instance.GetDefaultLayer().Add(text);\r
+\r
+            Animation animation = new Animation(2000);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);\r
+            animation.Looping = true;\r
+            animation.Play();\r
+        }\r
+\r
+        public void OnKeyEvent(object sender, Window.KeyEventArgs e)\r
+        {\r
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))\r
+            {\r
+                Exit();\r
+            }\r
+        }\r
+\r
+        static void Main(string[] args)\r
+        {\r
+            var app = new Program();\r
+            app.Run(args);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.csproj b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11.csproj
new file mode 100755 (executable)
index 0000000..4926595
--- /dev/null
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>net6.0-tizen</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugType>portable</DebugType>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <DebugType>None</DebugType>\r
+  </PropertyGroup>\r
+\r
+  <ItemGroup>\r
+    <Folder Include="res\" />\r
+  </ItemGroup>\r
+\r
+</Project>\r
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/aarch64/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/aarch64/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/arm/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/arm/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/arm64/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/arm64/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/armel/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/armel/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/riscv64/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/riscv64/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/x64/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/x64/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/x86/test.so b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/lib/x86/test.so
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/shared/res/Launcher_TC_PLUGIN_11.png b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/shared/res/Launcher_TC_PLUGIN_11.png
new file mode 100755 (executable)
index 0000000..9f3cb98
Binary files /dev/null and b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/shared/res/Launcher_TC_PLUGIN_11.png differ
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/tizen-manifest.xml b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..7f43df3
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="9.0" package="org.tizen.example.Launcher_TC_PLUGIN_11" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="org.tizen.example.Launcher_TC_PLUGIN_11"
+                                       exec="Launcher_TC_PLUGIN_11.dll"
+                                       type="dotnet-nui"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single"
+                    api-version="12">
+    <label>Launcher_TC_PLUGIN_11</label>
+    <icon>Launcher_TC_PLUGIN_11.png</icon>
+    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+  </ui-application>
+</manifest>
diff --git a/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/tizen_dotnet_project.yaml b/tests/Apps/Launcher_TC_PLUGIN_11/Launcher_TC_PLUGIN_11/tizen_dotnet_project.yaml
new file mode 100755 (executable)
index 0000000..d5eb080
--- /dev/null
@@ -0,0 +1,9 @@
+# csproj file path
+csproj_file: Launcher_TC_PLUGIN_11.csproj
+
+# files monitored for dirty/modified status
+files:
+  - Launcher_TC_PLUGIN_11.csproj
+  - Launcher_TC_PLUGIN_11.cs
+  - tizen-manifest.xml
+  - shared/res/Launcher_TC_PLUGIN_11.png
\ No newline at end of file
diff --git a/tests/Benchmark/TizenBenchmark/Directory.Build.targets b/tests/Benchmark/TizenBenchmark/Directory.Build.targets
new file mode 100644 (file)
index 0000000..67fcf5d
--- /dev/null
@@ -0,0 +1,21 @@
+<!--\r
+***********************************************************************************************\r
+<Build.Directory.targets>\r
+WARNING:  DO NOT MODIFY this file. Incorrect changes to this file will make it\r
+          impossible to load or build your projects from the IDE.\r
+\r
+***********************************************************************************************\r
+-->\r
+\r
+<Project>    \r
+       <Target Name="BuildDotnet" AfterTargets="TizenPackage" >\r
+        <Message Text="Tizen Build starts here ------------" Importance="high"/>\r
+        <Message Text="$(MSBuildProjectDirectory)" Importance="high"/>\r
+        <PropertyGroup>\r
+            <WorkspaceFolder>$([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))</WorkspaceFolder>\r
+        </PropertyGroup>\r
+        <Message Text="Workspace: '$(WorkspaceFolder)'"  Importance="high" />\r
+\r
+               <Exec Command="C:\tizen-studio\tools\tizen-core\tz.exe pack  -S $(ProjectDir) $(WorkspaceFolder)"> </Exec>\r
+    </Target>\r
+</Project>\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroArguments.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroArguments.cs
new file mode 100644 (file)
index 0000000..88c726f
--- /dev/null
@@ -0,0 +1,29 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroArguments\r
+    {\r
+        [Params(true, false)] // Arguments can be combined with Params\r
+        public bool AddExtra5Milliseconds;\r
+\r
+        [Benchmark]\r
+        [Arguments(100, 10)]\r
+        [Arguments(100, 20)]\r
+        [Arguments(200, 10)]\r
+        [Arguments(200, 20)]\r
+        public void Benchmark(int a, int b)\r
+        {\r
+            if (AddExtra5Milliseconds)\r
+                Thread.Sleep(a + b + 5);\r
+            else\r
+                Thread.Sleep(a + b);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroArgumentsSource.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroArgumentsSource.cs
new file mode 100644 (file)
index 0000000..4470f7f
--- /dev/null
@@ -0,0 +1,35 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroArgumentsSource\r
+    {\r
+        [Benchmark]\r
+        [ArgumentsSource(nameof(Numbers))]\r
+        public double ManyArguments(double x, double y) => Math.Pow(x, y);\r
+\r
+        public IEnumerable<object[]> Numbers() // for multiple arguments it's an IEnumerable of array of objects (object[])\r
+        {\r
+            yield return new object[] { 1.0, 1.0 };\r
+            yield return new object[] { 2.0, 2.0 };\r
+            yield return new object[] { 4.0, 4.0 };\r
+            yield return new object[] { 10.0, 10.0 };\r
+        }\r
+\r
+        [Benchmark]\r
+        [ArgumentsSource(nameof(TimeSpans))]\r
+        public void SingleArgument(TimeSpan time) => Thread.Sleep(time);\r
+\r
+        public IEnumerable<object> TimeSpans() // for single argument it's an IEnumerable of objects (object)\r
+        {\r
+            yield return TimeSpan.FromMilliseconds(10);\r
+            yield return TimeSpan.FromMilliseconds(100);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroArrayParam.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroArrayParam.cs
new file mode 100644 (file)
index 0000000..ead0b43
--- /dev/null
@@ -0,0 +1,36 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroArrayParam\r
+    {\r
+        [Benchmark]\r
+        [ArgumentsSource(nameof(Data))]\r
+        public int ArrayIndexOf(int[] array, int value)\r
+            => Array.IndexOf(array, value);\r
+\r
+        [Benchmark]\r
+        [ArgumentsSource(nameof(Data))]\r
+        public int ManualIndexOf(int[] array, int value)\r
+        {\r
+            for (int i = 0; i < array.Length; i++)\r
+                if (array[i] == value)\r
+                    return i;\r
+\r
+            return -1;\r
+        }\r
+\r
+        public IEnumerable<object[]> Data()\r
+        {\r
+            yield return new object[] { new int[] { 1, 2, 3 }, 4 };\r
+            yield return new object[] { Enumerable.Range(0, 100).ToArray(), 4 };\r
+            yield return new object[] { Enumerable.Range(0, 100).ToArray(), 101 };\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroBasic.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroBasic.cs
new file mode 100644 (file)
index 0000000..6a75b4e
--- /dev/null
@@ -0,0 +1,22 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // It is very easy to use BenchmarkDotNet. You should just create a class\r
+    public class IntroBasic\r
+    {\r
+        // And define a method with the Benchmark attribute\r
+        [Benchmark]\r
+        public void Sleep() => Thread.Sleep(10);\r
+\r
+        // You can write a description for your method.\r
+        [Benchmark(Description = "Thread.Sleep(10)")]\r
+        public void SleepWithDescription() => Thread.Sleep(10);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroBenchmarkBaseline.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroBenchmarkBaseline.cs
new file mode 100644 (file)
index 0000000..9e9c4a2
--- /dev/null
@@ -0,0 +1,22 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroBenchmarkBaseline\r
+    {\r
+        [Benchmark]\r
+        public void Time50() => Thread.Sleep(50);\r
+\r
+        [Benchmark(Baseline = true)]\r
+        public void Time100() => Thread.Sleep(100);\r
+\r
+        [Benchmark]\r
+        public void Time150() => Thread.Sleep(150);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroCategories.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroCategories.cs
new file mode 100644 (file)
index 0000000..2224716
--- /dev/null
@@ -0,0 +1,33 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DryJob]\r
+    [CategoriesColumn]\r
+    [BenchmarkCategory("Awesome")]\r
+    [AnyCategoriesFilter("A", "1")]\r
+    public class IntroCategories\r
+    {\r
+        [Benchmark]\r
+        [BenchmarkCategory("A", "1")]\r
+        public void A1() => Thread.Sleep(10); // Will be benchmarked\r
+\r
+        [Benchmark]\r
+        [BenchmarkCategory("A", "2")]\r
+        public void A2() => Thread.Sleep(10); // Will be benchmarked\r
+\r
+        [Benchmark]\r
+        [BenchmarkCategory("B", "1")]\r
+        public void B1() => Thread.Sleep(10); // Will be benchmarked\r
+\r
+        [Benchmark]\r
+        [BenchmarkCategory("B", "2")]\r
+        public void B2() => Thread.Sleep(10);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroCategoryBaseline.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroCategoryBaseline.cs
new file mode 100644 (file)
index 0000000..9223ad4
--- /dev/null
@@ -0,0 +1,28 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]\r
+    [CategoriesColumn]\r
+    public class IntroCategoryBaseline\r
+    {\r
+        [BenchmarkCategory("Fast"), Benchmark(Baseline = true)]\r
+        public void Time50() => Thread.Sleep(50);\r
+\r
+        [BenchmarkCategory("Fast"), Benchmark]\r
+        public void Time100() => Thread.Sleep(100);\r
+\r
+        [BenchmarkCategory("Slow"), Benchmark(Baseline = true)]\r
+        public void Time550() => Thread.Sleep(550);\r
+\r
+        [BenchmarkCategory("Slow"), Benchmark]\r
+        public void Time600() => Thread.Sleep(600);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroCategoryDiscoverer.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroCategoryDiscoverer.cs
new file mode 100644 (file)
index 0000000..c45c6e8
--- /dev/null
@@ -0,0 +1,50 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Running;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Reflection;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DryJob]\r
+    [CategoriesColumn]\r
+    [CustomCategoryDiscoverer]\r
+    public class IntroCategoryDiscoverer\r
+    {\r
+        private class CustomCategoryDiscoverer : DefaultCategoryDiscoverer\r
+        {\r
+            public override string[] GetCategories(MethodInfo method)\r
+            {\r
+                var categories = new List<string>();\r
+                categories.AddRange(base.GetCategories(method));\r
+                categories.Add("All");\r
+                categories.Add(method.Name.Substring(0, 1));\r
+                return categories.ToArray();\r
+            }\r
+        }\r
+\r
+        [AttributeUsage(AttributeTargets.Class)]\r
+        private class CustomCategoryDiscovererAttribute : Attribute, IConfigSource\r
+        {\r
+            public CustomCategoryDiscovererAttribute()\r
+            {\r
+                Config = ManualConfig.CreateEmpty()\r
+                    .WithCategoryDiscoverer(new CustomCategoryDiscoverer());\r
+            }\r
+\r
+            public IConfig Config { get; }\r
+        }\r
+\r
+\r
+        [Benchmark]\r
+        public void Foo() { }\r
+\r
+        [Benchmark]\r
+        public void Bar() { }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroColdStart.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroColdStart.cs
new file mode 100644 (file)
index 0000000..9be7b9a
--- /dev/null
@@ -0,0 +1,31 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [SimpleJob(RunStrategy.ColdStart, iterationCount: 5)]\r
+    [MinColumn, MaxColumn, MeanColumn, MedianColumn]\r
+    public class IntroColdStart\r
+    {\r
+        private bool firstCall;\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            if (firstCall == false)\r
+            {\r
+                firstCall = true;\r
+                Console.WriteLine("// First call");\r
+                Thread.Sleep(1000);\r
+            }\r
+            else\r
+                Thread.Sleep(10);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroComparableComplexParam.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroComparableComplexParam.cs
new file mode 100644 (file)
index 0000000..7ed9e62
--- /dev/null
@@ -0,0 +1,41 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroComparableComplexParam\r
+    {\r
+        [ParamsSource(nameof(ValuesForA))]\r
+        public ComplexParam? A { get; set; }\r
+\r
+        public IEnumerable<ComplexParam> ValuesForA => new[] { new ComplexParam(1, "First"), new ComplexParam(2, "Second") };\r
+\r
+        [Benchmark]\r
+        public object? Benchmark() => A;\r
+\r
+        // Only non generic IComparable is required to provide custom order behavior, but implementing IComparable<> too is customary.\r
+        public class ComplexParam : IComparable<ComplexParam>, IComparable\r
+        {\r
+            public ComplexParam(int value, string name)\r
+            {\r
+                Value = value;\r
+                Name = name;\r
+            }\r
+\r
+            public int Value { get; set; }\r
+\r
+            public string Name { get; set; }\r
+\r
+            public override string ToString() => Name;\r
+\r
+            public int CompareTo(ComplexParam? other) => other == null ? 1 : Value.CompareTo(other.Value);\r
+\r
+            public int CompareTo(object obj) => obj is ComplexParam other ? CompareTo(other) : throw new ArgumentException();\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroConfigSource.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroConfigSource.cs
new file mode 100644 (file)
index 0000000..9c67de5
--- /dev/null
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [MyConfigSource(Jit.LegacyJit, Jit.RyuJit)]\r
+    public class IntroConfigSource\r
+    {\r
+        /// <summary>\r
+        /// Dry-x64 jobs for specific jits\r
+        /// </summary>\r
+        private class MyConfigSourceAttribute : Attribute, IConfigSource\r
+        {\r
+            public IConfig Config { get; }\r
+\r
+            public MyConfigSourceAttribute(params Jit[] jits)\r
+            {\r
+                var jobs = jits\r
+                    .Select(jit => new Job(Job.Dry) { Environment = { Jit = jit, Platform = Platform.X64 } })\r
+                    .ToArray();\r
+                Config = ManualConfig.CreateEmpty().AddJob(jobs);\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            Thread.Sleep(10);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroConfigUnion.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroConfigUnion.cs
new file mode 100644 (file)
index 0000000..4846b7c
--- /dev/null
@@ -0,0 +1,40 @@
+using BenchmarkDotNet.Analysers;\r
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Columns;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Exporters.Csv;\r
+using BenchmarkDotNet.Exporters;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Loggers;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    public class IntroConfigUnion\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.Dry);\r
+                AddLogger(ConsoleLogger.Default);\r
+                AddColumn(TargetMethodColumn.Method, StatisticColumn.Max);\r
+                AddExporter(RPlotExporter.Default, CsvExporter.Default);\r
+                AddAnalyser(EnvironmentAnalyser.Default);\r
+                UnionRule = ConfigUnionRule.AlwaysUseLocal;\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            Thread.Sleep(10);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroCustomMono.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroCustomMono.cs
new file mode 100644 (file)
index 0000000..fd326a1
--- /dev/null
@@ -0,0 +1,101 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Running;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // *** Attribute Style ***\r
+\r
+    [MonoJob("Mono x64", @"C:\Program Files\Mono\bin\mono.exe")]\r
+    [MonoJob("Mono x86", @"C:\Program Files (x86)\Mono\bin\mono.exe")]\r
+    public class IntroCustomMono\r
+    {\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+\r
+    // *** Object Style ***\r
+\r
+    [Config(typeof(Config))]\r
+    public class IntroCustomMonoObjectStyle\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.ShortRun.WithRuntime(new MonoRuntime(\r
+                    "Mono x64", @"C:\Program Files\Mono\bin\mono.exe")));\r
+                AddJob(Job.ShortRun.WithRuntime(new MonoRuntime(\r
+                    "Mono x86", @"C:\Program Files (x86)\Mono\bin\mono.exe")));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+\r
+    // ** Object Style, Using AOT **\r
+\r
+    [Config(typeof(Config))]\r
+    public class IntroCustomMonoObjectStyleAot\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public void AddMono(string name, string mono_top_dir)\r
+            {\r
+                var aot_compile_args = "--aot=llvm";\r
+                var mono_bcl = $@"{mono_top_dir}\lib\mono\4.5";\r
+                var mono_bin = $@"{mono_top_dir}\bin\mono.exe";\r
+                AddJob(Job.ShortRun.WithRuntime(new MonoRuntime(\r
+                    name, mono_bin, aot_compile_args, mono_bcl)));\r
+            }\r
+\r
+            public Config()\r
+            {\r
+                AddMono("Mono x64", @"C:\Program Files\Mono");\r
+                AddMono("Mono x86", @"C:\Program Files (x86)\Mono");\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+\r
+    // *** Fluent Config ***\r
+\r
+    public class IntroCustomMonoFluentConfig\r
+    {\r
+        public static void Run()\r
+        {\r
+            BenchmarkRunner.Run<IntroCustomMonoFluentConfig>(ManualConfig\r
+                .CreateMinimumViable()\r
+                .AddJob(Job.ShortRun.WithRuntime(new MonoRuntime(\r
+                    "Mono x64", @"C:\Program Files\Mono\bin\mono.exe")))\r
+                .AddJob(Job.ShortRun.WithRuntime(new MonoRuntime(\r
+                    "Mono x86", @"C:\Program Files (x86)\Mono\bin\mono.exe"))));\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroCustomMonoArguments.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroCustomMonoArguments.cs
new file mode 100644 (file)
index 0000000..2e2ee32
--- /dev/null
@@ -0,0 +1,47 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(ConfigWithCustomArguments))]\r
+    public class IntroCustomMonoArguments\r
+    {\r
+        public class ConfigWithCustomArguments : ManualConfig\r
+        {\r
+            public ConfigWithCustomArguments()\r
+            {\r
+                // --optimize=MODE , -O=mode\r
+                // MODE is a comma separated list of optimizations. They also allow\r
+                // optimizations to be turned off by prefixing the optimization\r
+                // name with a minus sign.\r
+\r
+                AddJob(Job.Default\r
+                    .WithRuntime(MonoRuntime.Default)\r
+                    .WithArguments(new[] { new MonoArgument("--optimize=inline") })\r
+                    .WithId("Inlining enabled"));\r
+                AddJob(Job.Default\r
+                    .WithRuntime(MonoRuntime.Default)\r
+                    .WithArguments(new[] { new MonoArgument("--optimize=-inline") })\r
+                    .WithId("Inlining disabled"));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Sample()\r
+        {\r
+            ShouldGetInlined(); ShouldGetInlined(); ShouldGetInlined();\r
+            ShouldGetInlined(); ShouldGetInlined(); ShouldGetInlined();\r
+            ShouldGetInlined(); ShouldGetInlined(); ShouldGetInlined();\r
+        }\r
+\r
+        private void ShouldGetInlined() { }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroDeferredExecution.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroDeferredExecution.cs
new file mode 100644 (file)
index 0000000..b425ac8
--- /dev/null
@@ -0,0 +1,35 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroDeferredExecution\r
+    {\r
+        private readonly int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\r
+\r
+        private readonly Consumer consumer = new Consumer();\r
+\r
+        /// <summary>\r
+        /// this benchmark returns a deferred LINQ query which is NOT executed\r
+        /// so the benchmark measures the cost of creating the query, not the actual execution\r
+        /// this is WRONG\r
+        /// You can read more about LINQ and Deferred Execution <see href="https://blogs.msdn.microsoft.com/charlie/2007/12/10/linq-and-deferred-execution/">here</see>\r
+        /// </summary>\r
+        /// <returns>deferred LINQ query</returns>\r
+        [Benchmark]\r
+        public IEnumerable<int> Wrong() => from number in numbers orderby number descending select number;\r
+\r
+        /// <summary>\r
+        /// this benchmark uses .Consume extension method which executes given deferred query and consumes its result\r
+        /// so the benchmark measures the cost of creating the query and executing it\r
+        /// </summary>\r
+        [Benchmark]\r
+        public void Ok() => (from number in numbers orderby number descending select number).Consume(consumer);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroDisassembly.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroDisassembly.cs
new file mode 100644 (file)
index 0000000..90eca54
--- /dev/null
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Diagnosers;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DisassemblyDiagnoser(printInstructionAddresses: true, syntax: DisassemblySyntax.Masm)]\r
+    public class IntroDisassembly\r
+    {\r
+        private int[] field = Enumerable.Range(0, 100).ToArray();\r
+\r
+        [Benchmark]\r
+        public int SumLocal()\r
+        {\r
+            var local = field; // we use local variable that points to the field\r
+\r
+            int sum = 0;\r
+            for (int i = 0; i < local.Length; i++)\r
+                sum += local[i];\r
+\r
+            return sum;\r
+        }\r
+\r
+        [Benchmark]\r
+        public int SumField()\r
+        {\r
+            int sum = 0;\r
+            for (int i = 0; i < field.Length; i++)\r
+                sum += field[i];\r
+\r
+            return sum;\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyAllJits.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyAllJits.cs
new file mode 100644 (file)
index 0000000..deccfdd
--- /dev/null
@@ -0,0 +1,57 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Diagnosers;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(MultipleJits))]\r
+    public class IntroDisassemblyAllJits\r
+    {\r
+        public class MultipleJits : ManualConfig\r
+        {\r
+            public MultipleJits()\r
+            {\r
+                AddJob(Job.ShortRun.WithPlatform(Platform.X86).WithRuntime(new MonoRuntime(name: "Mono x86", customPath: @"C:\Program Files (x86)\Mono\bin\mono.exe")));\r
+                AddJob(Job.ShortRun.WithPlatform(Platform.X64).WithRuntime(new MonoRuntime(name: "Mono x64", customPath: @"C:\Program Files\Mono\bin\mono.exe")));\r
+\r
+                AddJob(Job.ShortRun.WithJit(Jit.LegacyJit).WithPlatform(Platform.X86).WithRuntime(ClrRuntime.Net462));\r
+                AddJob(Job.ShortRun.WithJit(Jit.LegacyJit).WithPlatform(Platform.X64).WithRuntime(ClrRuntime.Net462));\r
+\r
+                AddJob(Job.ShortRun.WithJit(Jit.RyuJit).WithPlatform(Platform.X64).WithRuntime(ClrRuntime.Net462));\r
+\r
+                // RyuJit for .NET Core 5.0\r
+                AddJob(Job.ShortRun.WithJit(Jit.RyuJit).WithPlatform(Platform.X64).WithRuntime(CoreRuntime.Core50));\r
+\r
+                AddDiagnoser(new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig(maxDepth: 3, exportDiff: true)));\r
+            }\r
+        }\r
+\r
+        private Increment increment = new Increment();\r
+\r
+        [Benchmark]\r
+        public int CallVirtualMethod() => increment.OperateTwice(10);\r
+\r
+        public abstract class Operation  // abstract unary integer operation\r
+        {\r
+            public abstract int Operate(int input);\r
+\r
+            public int OperateTwice(int input) => Operate(Operate(input)); // two virtual calls to Operate\r
+        }\r
+\r
+        public sealed class Increment : Operation // concrete, sealed operation: increment by fixed amount\r
+        {\r
+            public readonly int Amount;\r
+            public Increment(int amount = 1) { Amount = amount; }\r
+\r
+            public override int Operate(int input) => input + Amount;\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyDry.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyDry.cs
new file mode 100644 (file)
index 0000000..2a01eca
--- /dev/null
@@ -0,0 +1,21 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DisassemblyDiagnoser(maxDepth: 3)]\r
+    [DryJob]\r
+    public class IntroDisassemblyDry\r
+    {\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyRyuJit.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroDisassemblyRyuJit.cs
new file mode 100644 (file)
index 0000000..97bd833
--- /dev/null
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DisassemblyDiagnoser(printSource: true)]\r
+    [RyuJitX64Job]\r
+    public class IntroDisassemblyRyuJit\r
+    {\r
+        private int[] field = Enumerable.Range(0, 100).ToArray();\r
+\r
+        [Benchmark]\r
+        public int SumLocal()\r
+        {\r
+            var local = field; // we use local variable that points to the field\r
+\r
+            int sum = 0;\r
+            for (int i = 0; i < local.Length; i++)\r
+                sum += local[i];\r
+\r
+            return sum;\r
+        }\r
+\r
+        [Benchmark]\r
+        public int SumField()\r
+        {\r
+            int sum = 0;\r
+            for (int i = 0; i < field.Length; i++)\r
+                sum += field[i];\r
+\r
+            return sum;\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroDotTraceDiagnoser.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroDotTraceDiagnoser.cs
new file mode 100644 (file)
index 0000000..5b968e9
--- /dev/null
@@ -0,0 +1,32 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Diagnostics.dotTrace;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // Enables dotTrace profiling for all jobs\r
+    [DotTraceDiagnoser]\r
+    // Adds the default "external-process" job\r
+    // Profiling is performed using dotTrace command-line Tools\r
+    // See: https://www.jetbrains.com/help/profiler/Performance_Profiling__Profiling_Using_the_Command_Line.html\r
+    [SimpleJob]\r
+    // Adds an "in-process" job\r
+    // Profiling is performed using dotTrace SelfApi\r
+    // NuGet reference: https://www.nuget.org/packages/JetBrains.Profiler.SelfApi\r
+    [InProcess]\r
+    public class IntroDotTraceDiagnoser\r
+    {\r
+        [Benchmark]\r
+        public void Fibonacci() => Fibonacci(30);\r
+\r
+        private static int Fibonacci(int n)\r
+        {\r
+            return n <= 1 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroEnvVars.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroEnvVars.cs
new file mode 100644 (file)
index 0000000..69f4646
--- /dev/null
@@ -0,0 +1,36 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(ConfigWithCustomEnvVars))]\r
+    public class IntroEnvVars\r
+    {\r
+        private class ConfigWithCustomEnvVars : ManualConfig\r
+        {\r
+            private const string JitNoInline = "COMPlus_JitNoInline";\r
+\r
+            public ConfigWithCustomEnvVars()\r
+            {\r
+                AddJob(Job.Default.WithRuntime(CoreRuntime.Core21).WithId("Inlining enabled"));\r
+                AddJob(Job.Default.WithRuntime(CoreRuntime.Core21)\r
+                    .WithEnvironmentVariables(new EnvironmentVariable(JitNoInline, "1"))\r
+                    .WithId("Inlining disabled"));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroEventPipeProfiler.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroEventPipeProfiler.cs
new file mode 100644 (file)
index 0000000..9a15c45
--- /dev/null
@@ -0,0 +1,20 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Diagnosers;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [ShortRunJob]\r
+    [EventPipeProfiler(EventPipeProfile.CpuSampling)]\r
+    public class IntroEventPipeProfiler\r
+    {\r
+        [Benchmark]\r
+        public void Sleep() => Thread.Sleep(2000);\r
+    }\r
+\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroEventPipeProfilerAdvanced.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroEventPipeProfilerAdvanced.cs
new file mode 100644 (file)
index 0000000..2f3fabd
--- /dev/null
@@ -0,0 +1,52 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Diagnosers;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using Microsoft.Diagnostics.NETCore.Client;\r
+using Microsoft.Diagnostics.Tracing.Parsers;\r
+using System;\r
+using System.Buffers;\r
+using System.Collections.Generic;\r
+using System.Diagnostics.Tracing;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(CustomConfig))]\r
+    public class IntroEventPipeProfilerAdvanced\r
+    {\r
+        private class CustomConfig : ManualConfig\r
+        {\r
+            public CustomConfig()\r
+            {\r
+                AddJob(Job.ShortRun.WithRuntime(CoreRuntime.Core50));\r
+\r
+                var providers = new[]\r
+                {\r
+                    new EventPipeProvider(ClrTraceEventParser.ProviderName, EventLevel.Verbose,\r
+                        (long) (ClrTraceEventParser.Keywords.Exception\r
+                        | ClrTraceEventParser.Keywords.GC\r
+                        | ClrTraceEventParser.Keywords.Jit\r
+                        | ClrTraceEventParser.Keywords.JitTracing // for the inlining events\r
+                        | ClrTraceEventParser.Keywords.Loader\r
+                        | ClrTraceEventParser.Keywords.NGen)),\r
+                    new EventPipeProvider("System.Buffers.ArrayPoolEventSource", EventLevel.Informational, long.MaxValue),\r
+                };\r
+\r
+                AddDiagnoser(new EventPipeProfiler(providers: providers));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void RentAndReturn_Shared()\r
+        {\r
+            var pool = ArrayPool<byte>.Shared;\r
+            byte[] array = pool.Rent(10000);\r
+            pool.Return(array);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroExport.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroExport.cs
new file mode 100644 (file)
index 0000000..3e8d397
--- /dev/null
@@ -0,0 +1,43 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [ShortRunJob]\r
+    [MediumRunJob]\r
+    [KeepBenchmarkFiles]\r
+\r
+    [AsciiDocExporter]\r
+    [CsvExporter]\r
+    [CsvMeasurementsExporter]\r
+    [HtmlExporter]\r
+    [PlainExporter]\r
+    [RPlotExporter]\r
+    [JsonExporterAttribute.Brief]\r
+    [JsonExporterAttribute.BriefCompressed]\r
+    [JsonExporterAttribute.Full]\r
+    [JsonExporterAttribute.FullCompressed]\r
+    [MarkdownExporterAttribute.Default]\r
+    [MarkdownExporterAttribute.GitHub]\r
+    [MarkdownExporterAttribute.StackOverflow]\r
+    [MarkdownExporterAttribute.Atlassian]\r
+    [XmlExporterAttribute.Brief]\r
+    [XmlExporterAttribute.BriefCompressed]\r
+    [XmlExporterAttribute.Full]\r
+    [XmlExporterAttribute.FullCompressed]\r
+    public class IntroExport\r
+    {\r
+        private Random random = new Random(42);\r
+\r
+        [Benchmark(Baseline = true)]\r
+        public void Sleep10() => Thread.Sleep(10);\r
+\r
+        [Benchmark]\r
+        public void Sleep50Noisy() => Thread.Sleep(random.Next(100));\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroExportJson.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroExportJson.cs
new file mode 100644 (file)
index 0000000..6e45fad
--- /dev/null
@@ -0,0 +1,48 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Exporters.Json;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // *** Attribute style ***\r
+\r
+    [DryJob]\r
+    [JsonExporterAttribute.Brief]\r
+    [JsonExporterAttribute.Full]\r
+    [JsonExporterAttribute.BriefCompressed]\r
+    [JsonExporterAttribute.FullCompressed]\r
+    [JsonExporter("-custom", indentJson: true, excludeMeasurements: true)]\r
+    public class IntroExportJson\r
+    {\r
+        [Benchmark] public void Sleep10() => Thread.Sleep(10);\r
+        [Benchmark] public void Sleep20() => Thread.Sleep(20);\r
+    }\r
+\r
+    // *** Object style ***\r
+\r
+    [Config(typeof(Config))]\r
+    public class IntroJsonExportObjectStyle\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddExporter(JsonExporter.Brief);\r
+                AddExporter(JsonExporter.Brief);\r
+                AddExporter(JsonExporter.Full);\r
+                AddExporter(JsonExporter.BriefCompressed);\r
+                AddExporter(JsonExporter.FullCompressed);\r
+                AddExporter(JsonExporter.Custom("-custom", indentJson: true, excludeMeasurements: true));\r
+            }\r
+        }\r
+\r
+        [Benchmark] public void Sleep10() => Thread.Sleep(10);\r
+        [Benchmark] public void Sleep20() => Thread.Sleep(20);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroExportXml.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroExportXml.cs
new file mode 100644 (file)
index 0000000..1c069a3
--- /dev/null
@@ -0,0 +1,22 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DryJob]\r
+    [XmlExporterAttribute.Brief]\r
+    [XmlExporterAttribute.Full]\r
+    [XmlExporterAttribute.BriefCompressed]\r
+    [XmlExporterAttribute.FullCompressed]\r
+    [XmlExporter("-custom", indentXml: true, excludeMeasurements: true)]\r
+    public class IntroExportXml\r
+    {\r
+        [Benchmark] public void Sleep10() => Thread.Sleep(10);\r
+        [Benchmark] public void Sleep20() => Thread.Sleep(20);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroFilters.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroFilters.cs
new file mode 100644 (file)
index 0000000..7edf1c4
--- /dev/null
@@ -0,0 +1,45 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Filters;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DryJob]\r
+    [Config(typeof(Config))]\r
+    public class IntroFilters\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            // We will benchmark ONLY method with\r
+            // names (which contains "A" OR "1") AND (have length < 3)\r
+            public Config()\r
+            {\r
+                // benchmark with names which contains "A" OR "1"\r
+                AddFilter(new DisjunctionFilter(\r
+                    new NameFilter(name => name.Contains("A")),\r
+                    new NameFilter(name => name.Contains("1"))\r
+                ));\r
+\r
+                // benchmark with names with length < 3\r
+                AddFilter(new NameFilter(name => name.Length < 3));\r
+            }\r
+        }\r
+\r
+        [Benchmark] public void A1() => Thread.Sleep(10); // Will be benchmarked\r
+        [Benchmark] public void A2() => Thread.Sleep(10); // Will be benchmarked\r
+        [Benchmark] public void A3() => Thread.Sleep(10); // Will be benchmarked\r
+        [Benchmark] public void B1() => Thread.Sleep(10); // Will be benchmarked\r
+        [Benchmark] public void B2() => Thread.Sleep(10);\r
+        [Benchmark] public void B3() => Thread.Sleep(10);\r
+        [Benchmark] public void C1() => Thread.Sleep(10); // Will be benchmarked\r
+        [Benchmark] public void C2() => Thread.Sleep(10);\r
+        [Benchmark] public void C3() => Thread.Sleep(10);\r
+        [Benchmark] public void Aaa() => Thread.Sleep(10);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroFluentConfigBuilder.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroFluentConfigBuilder.cs
new file mode 100644 (file)
index 0000000..f27e7f8
--- /dev/null
@@ -0,0 +1,50 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Running;\r
+using BenchmarkDotNet.Validators;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Security.Cryptography;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class Algo_Md5VsSha256\r
+    {\r
+        private const int N = 10000;\r
+        private readonly byte[] data;\r
+\r
+        private readonly MD5 md5 = MD5.Create();\r
+        private readonly SHA256 sha256 = SHA256.Create();\r
+\r
+        public Algo_Md5VsSha256()\r
+        {\r
+            data = new byte[N];\r
+            new Random(42).NextBytes(data);\r
+        }\r
+\r
+        [Benchmark(Baseline = true)]\r
+        public byte[] Md5() => md5.ComputeHash(data);\r
+\r
+        [Benchmark]\r
+        public byte[] Sha256() => sha256.ComputeHash(data);\r
+    }\r
+\r
+    public class IntroFluentConfigBuilder\r
+    {\r
+        public static void Run()\r
+        {\r
+            BenchmarkRunner\r
+                .Run<Algo_Md5VsSha256>(\r
+                    DefaultConfig.Instance\r
+                        .AddJob(Job.Default.WithRuntime(ClrRuntime.Net462))\r
+                        .AddJob(Job.Default.WithRuntime(CoreRuntime.Core21))\r
+                        .AddValidator(ExecutionValidator.FailOnError));\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroGcMode.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroGcMode.cs
new file mode 100644 (file)
index 0000000..e8093a1
--- /dev/null
@@ -0,0 +1,49 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Order;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Runtime.CompilerServices;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    [Orderer(SummaryOrderPolicy.FastestToSlowest)]\r
+    [MemoryDiagnoser]\r
+    public class IntroGcMode\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.MediumRun.WithGcServer(true).WithGcForce(true).WithId("ServerForce"));\r
+                AddJob(Job.MediumRun.WithGcServer(true).WithGcForce(false).WithId("Server"));\r
+                AddJob(Job.MediumRun.WithGcServer(false).WithGcForce(true).WithId("Workstation"));\r
+                AddJob(Job.MediumRun.WithGcServer(false).WithGcForce(false).WithId("WorkstationForce"));\r
+            }\r
+        }\r
+\r
+        [Benchmark(Description = "new byte[10kB]")]\r
+        public byte[] Allocate()\r
+        {\r
+            return new byte[10000];\r
+        }\r
+\r
+        [Benchmark(Description = "stackalloc byte[10kB]")]\r
+        public unsafe void AllocateWithStackalloc()\r
+        {\r
+            var array = stackalloc byte[10000];\r
+            Consume(array);\r
+        }\r
+\r
+        [MethodImpl(MethodImplOptions.NoInlining)]\r
+        private static unsafe void Consume(byte* input)\r
+        {\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroGenericTypeArguments.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroGenericTypeArguments.cs
new file mode 100644 (file)
index 0000000..33b5f96
--- /dev/null
@@ -0,0 +1,17 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [GenericTypeArguments(typeof(int))]\r
+    [GenericTypeArguments(typeof(char))]\r
+    public class IntroGenericTypeArguments<T>\r
+    {\r
+        [Benchmark] public T Create() => Activator.CreateInstance<T>();\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroHardwareCounters.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroHardwareCounters.cs
new file mode 100644 (file)
index 0000000..8f55a70
--- /dev/null
@@ -0,0 +1,62 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Diagnosers;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [HardwareCounters(\r
+        HardwareCounter.BranchMispredictions,\r
+        HardwareCounter.BranchInstructions)]\r
+    public class IntroHardwareCounters\r
+    {\r
+        private const int N = 32767;\r
+        private readonly int[] sorted, unsorted;\r
+\r
+        public IntroHardwareCounters()\r
+        {\r
+            var random = new Random(0);\r
+            unsorted = new int[N];\r
+            sorted = new int[N];\r
+            for (int i = 0; i < N; i++)\r
+                sorted[i] = unsorted[i] = random.Next(256);\r
+            Array.Sort(sorted);\r
+        }\r
+\r
+        private static int Branch(int[] data)\r
+        {\r
+            int sum = 0;\r
+            for (int i = 0; i < N; i++)\r
+                if (data[i] >= 128)\r
+                    sum += data[i];\r
+            return sum;\r
+        }\r
+\r
+        private static int Branchless(int[] data)\r
+        {\r
+            int sum = 0;\r
+            for (int i = 0; i < N; i++)\r
+            {\r
+                int t = (data[i] - 128) >> 31;\r
+                sum += ~t & data[i];\r
+            }\r
+            return sum;\r
+        }\r
+\r
+        [Benchmark]\r
+        public int SortedBranch() => Branch(sorted);\r
+\r
+        [Benchmark]\r
+        public int UnsortedBranch() => Branch(unsorted);\r
+\r
+        [Benchmark]\r
+        public int SortedBranchless() => Branchless(sorted);\r
+\r
+        [Benchmark]\r
+        public int UnsortedBranchless() => Branchless(unsorted);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroInProcess.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroInProcess.cs
new file mode 100644 (file)
index 0000000..0dbc155
--- /dev/null
@@ -0,0 +1,54 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Order;\r
+using BenchmarkDotNet.Toolchains.InProcess.Emit;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Runtime.CompilerServices;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    [Orderer(SummaryOrderPolicy.FastestToSlowest)]\r
+    [MemoryDiagnoser]\r
+    public class IntroInProcess\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.MediumRun\r
+                    .WithLaunchCount(1)\r
+                    .WithId("OutOfProc"));\r
+\r
+                AddJob(Job.MediumRun\r
+                    .WithLaunchCount(1)\r
+                    .WithToolchain(InProcessEmitToolchain.Instance)\r
+                    .WithId("InProcess"));\r
+            }\r
+        }\r
+\r
+        [Benchmark(Description = "new byte[10kB]")]\r
+        public byte[] Allocate()\r
+        {\r
+            return new byte[10000];\r
+        }\r
+\r
+        [Benchmark(Description = "stackalloc byte[10kB]")]\r
+        public unsafe void AllocateWithStackalloc()\r
+        {\r
+            var array = stackalloc byte[10000];\r
+            Consume(array);\r
+        }\r
+\r
+        [MethodImpl(MethodImplOptions.NoInlining)]\r
+        private static unsafe void Consume(byte* input)\r
+        {\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroInProcessWrongEnv.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroInProcessWrongEnv.cs
new file mode 100644 (file)
index 0000000..1d830e2
--- /dev/null
@@ -0,0 +1,54 @@
+using System;\r
+using System.Runtime.CompilerServices;\r
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Order;\r
+using BenchmarkDotNet.Toolchains.InProcess;\r
+using BenchmarkDotNet.Toolchains.InProcess.Emit;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    [Orderer(SummaryOrderPolicy.FastestToSlowest)]\r
+    [MemoryDiagnoser]\r
+    public class IntroInProcessWrongEnv\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                var wrongPlatform = Environment.Is64BitProcess\r
+                    ? Platform.X64\r
+                    : Platform.X86;\r
+\r
+                AddJob(Job.MediumRun\r
+                    .WithLaunchCount(1)\r
+                    .WithPlatform(wrongPlatform)\r
+                    .WithToolchain(InProcessEmitToolchain.Instance)\r
+                    .WithId("InProcess"));\r
+\r
+                AddValidator(InProcessValidator.DontFailOnError);\r
+            }\r
+        }\r
+\r
+        [Benchmark(Description = "new byte[10kB]")]\r
+        public byte[] Allocate()\r
+        {\r
+            return new byte[10000];\r
+        }\r
+\r
+        [Benchmark(Description = "stackalloc byte[10kB]")]\r
+        public unsafe void AllocateWithStackalloc()\r
+        {\r
+            var array = stackalloc byte[10000];\r
+            Consume(array);\r
+        }\r
+\r
+        [MethodImpl(MethodImplOptions.NoInlining)]\r
+        private static unsafe void Consume(byte* input)\r
+        {\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroInliningDiagnoser.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroInliningDiagnoser.cs
new file mode 100644 (file)
index 0000000..3ea6e51
--- /dev/null
@@ -0,0 +1,42 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Runtime.CompilerServices;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [BenchmarkDotNet.Diagnostics.Windows.Configs.InliningDiagnoser(logFailuresOnly: false, allowedNamespaces: new[] { "BenchmarkDotNet.Samples" })]\r
+    public class IntroInliningDiagnoser\r
+    {\r
+        [Benchmark]\r
+        public int IterationTest()\r
+        {\r
+            int j = 0;\r
+            for (int i = 0; i < short.MaxValue; ++i)\r
+            {\r
+                j = i + AddThree(i);\r
+            }\r
+\r
+            return j + ReturnFive() + AddThree(ReturnFive());\r
+        }\r
+\r
+        [Benchmark]\r
+        public int SplitJoin()\r
+            => string.Join(",", new string[1000]).Split(',').Length;\r
+\r
+        private int ReturnFive()\r
+        {\r
+            return 5;\r
+        }\r
+\r
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]\r
+        private int AddThree(int a)\r
+        {\r
+            return a + 3;\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroJitStatsDiagnoser.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroJitStatsDiagnoser.cs
new file mode 100644 (file)
index 0000000..9521be8
--- /dev/null
@@ -0,0 +1,14 @@
+using BenchmarkDotNet.Attributes;\r
+using System.Threading;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+\r
+    [BenchmarkDotNet.Diagnostics.Windows.Configs.JitStatsDiagnoser]\r
+    public class IntroJitStatsDiagnoser\r
+    {\r
+        [Benchmark]\r
+        public void Sleep() => Thread.Sleep(10);\r
+    }\r
+\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroJobBaseline.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroJobBaseline.cs
new file mode 100644 (file)
index 0000000..0672acc
--- /dev/null
@@ -0,0 +1,21 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [SimpleJob(runtimeMoniker: RuntimeMoniker.Net462, baseline: true)]\r
+    [SimpleJob(runtimeMoniker: RuntimeMoniker.Mono)]\r
+    [SimpleJob(runtimeMoniker: RuntimeMoniker.Net50)]\r
+    public class IntroJobBaseline\r
+    {\r
+        [Benchmark]\r
+        public int SplitJoin()\r
+            => string.Join(",", new string[1000]).Split(',').Length;\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroJoin.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroJoin.cs
new file mode 100644 (file)
index 0000000..f9f874c
--- /dev/null
@@ -0,0 +1,36 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // Run BenchmarkSwitcher with arguments: "--join --category=IntroJoinA"\r
+\r
+    [DryJob]\r
+    public class IntroJoin1\r
+    {\r
+        [Benchmark]\r
+        [BenchmarkCategory("IntroJoinA")]\r
+        public void A() => Thread.Sleep(10);\r
+\r
+        [Benchmark]\r
+        [BenchmarkCategory("IntroJoinB")]\r
+        public void B() => Thread.Sleep(10);\r
+    }\r
+\r
+    [DryJob]\r
+    public class IntroJoin2\r
+    {\r
+        [Benchmark]\r
+        [BenchmarkCategory("IntroJoinA")]\r
+        public void A() => Thread.Sleep(10);\r
+\r
+        [Benchmark]\r
+        [BenchmarkCategory("IntroJoinB")]\r
+        public void B() => Thread.Sleep(10);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroLargeAddressAware.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroLargeAddressAware.cs
new file mode 100644 (file)
index 0000000..9fecc01
--- /dev/null
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Runtime.InteropServices;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [MemoryDiagnoser]\r
+    [Config(typeof(Config))]\r
+    public class IntroLargeAddressAware\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.Default\r
+                    .WithRuntime(ClrRuntime.Net462)\r
+                    .WithPlatform(Platform.X86)\r
+                    .WithLargeAddressAware(value: RuntimeInformation.IsOSPlatform(OSPlatform.Windows))\r
+                    .WithId("Framework"));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void AllocateMoreThan2GB()\r
+        {\r
+            const int oneGB = 1024 * 1024 * 1024;\r
+            const int halfGB = oneGB / 2;\r
+            byte[] bytes1 = new byte[oneGB];\r
+            byte[] bytes2 = new byte[oneGB];\r
+            byte[] bytes3 = new byte[halfGB];\r
+            GC.KeepAlive(bytes1);\r
+            GC.KeepAlive(bytes2);\r
+            GC.KeepAlive(bytes3);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroMonitoring.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroMonitoring.cs
new file mode 100644 (file)
index 0000000..c51dd74
--- /dev/null
@@ -0,0 +1,24 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [SimpleJob(RunStrategy.Monitoring, iterationCount: 10, id: "MonitoringJob")]\r
+    [MinColumn, Q1Column, Q3Column, MaxColumn]\r
+    public class IntroMonitoring\r
+    {\r
+        private Random random = new Random(42);\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            Thread.Sleep(random.Next(10) * 10);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroMultimodal.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroMultimodal.cs
new file mode 100644 (file)
index 0000000..9bfaecc
--- /dev/null
@@ -0,0 +1,26 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [MValueColumn]\r
+    [SimpleJob(RunStrategy.Throughput, 1, 0, -1, 1, "MyJob")]\r
+    public class IntroMultimodal\r
+    {\r
+        private readonly Random rnd = new Random(42);\r
+\r
+        private void Multimodal(int n)\r
+            => Thread.Sleep((rnd.Next(n) + 1) * 100);\r
+\r
+        [Benchmark] public void Unimodal() => Multimodal(1);\r
+        [Benchmark] public void Bimodal() => Multimodal(2);\r
+        [Benchmark] public void Trimodal() => Multimodal(3);\r
+        [Benchmark] public void Quadrimodal() => Multimodal(4);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroNativeMemory.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroNativeMemory.cs
new file mode 100644 (file)
index 0000000..a005119
--- /dev/null
@@ -0,0 +1,56 @@
+using System;\r
+using System.Drawing;\r
+using System.Runtime.InteropServices;\r
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Diagnostics.Windows.Configs;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [ShortRunJob]\r
+    [NativeMemoryProfiler]\r
+    [MemoryDiagnoser]\r
+    public class IntroNativeMemory\r
+    {\r
+        [Benchmark]\r
+        public void BitmapWithLeaks()\r
+        {\r
+            var flag = new Bitmap(200, 100);\r
+            var graphics = Graphics.FromImage(flag);\r
+            var blackPen = new Pen(Color.Black, 3);\r
+            graphics.DrawLine(blackPen, 100, 100, 500, 100);\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Bitmap()\r
+        {\r
+            using (var flag = new Bitmap(200, 100))\r
+            {\r
+                using (var graphics = Graphics.FromImage(flag))\r
+                {\r
+                    using (var blackPen = new Pen(Color.Black, 3))\r
+                    {\r
+                        graphics.DrawLine(blackPen, 100, 100, 500, 100);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+\r
+        private const int Size = 20; // Greater value could cause System.OutOfMemoryException for test with memory leaks.\r
+        private int ArraySize = Size * Marshal.SizeOf(typeof(int));\r
+\r
+        [Benchmark]\r
+        public unsafe void AllocHGlobal()\r
+        {\r
+            IntPtr unmanagedHandle = Marshal.AllocHGlobal(ArraySize);\r
+            Span<byte> unmanaged = new Span<byte>(unmanagedHandle.ToPointer(), ArraySize);\r
+            Marshal.FreeHGlobal(unmanagedHandle);\r
+        }\r
+\r
+        [Benchmark]\r
+        public unsafe void AllocHGlobalWithLeaks()\r
+        {\r
+            IntPtr unmanagedHandle = Marshal.AllocHGlobal(ArraySize);\r
+            Span<byte> unmanaged = new Span<byte>(unmanagedHandle.ToPointer(), ArraySize);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroNuGet.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroNuGet.cs
new file mode 100644 (file)
index 0000000..c4a5fb2
--- /dev/null
@@ -0,0 +1,47 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Jobs;\r
+using Newtonsoft.Json;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    /// <summary>\r
+    /// Benchmarks between various versions of a NuGet package\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// Only supported with the CsProjCoreToolchain toolchain\r
+    /// </remarks>\r
+    [Config(typeof(Config))]\r
+    public class IntroNuGet\r
+    {\r
+        // Specify jobs with different versions of the same NuGet package to benchmark.\r
+        // The NuGet versions referenced on these jobs must be greater or equal to the\r
+        // same NuGet version referenced in this benchmark project.\r
+        // Example: This benchmark project references Newtonsoft.Json 9.0.1\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                var baseJob = Job.MediumRun;\r
+\r
+                AddJob(baseJob.WithNuGet("Newtonsoft.Json", "11.0.2").WithId("11.0.2"));\r
+                AddJob(baseJob.WithNuGet("Newtonsoft.Json", "11.0.1").WithId("11.0.1"));\r
+                AddJob(baseJob.WithNuGet("Newtonsoft.Json", "10.0.3").WithId("10.0.3"));\r
+                AddJob(baseJob.WithNuGet("Newtonsoft.Json", "10.0.2").WithId("10.0.2"));\r
+                AddJob(baseJob.WithNuGet("Newtonsoft.Json", "10.0.1").WithId("10.0.1"));\r
+                AddJob(baseJob.WithNuGet("Newtonsoft.Json", "9.0.1").WithId("9.0.1"));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void SerializeAnonymousObject()\r
+            => JsonConvert.SerializeObject(\r
+                new { hello = "world", price = 1.99, now = DateTime.UtcNow });\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroOrderAttr.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroOrderAttr.cs
new file mode 100644 (file)
index 0000000..d24e5c3
--- /dev/null
@@ -0,0 +1,25 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Order;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Orderer(SummaryOrderPolicy.FastestToSlowest, MethodOrderPolicy.Declared)]\r
+    [DryJob]\r
+    public class IntroOrderAttr\r
+    {\r
+        [Params(1, 2, 3)]\r
+        public int X { get; set; }\r
+\r
+        [Benchmark]\r
+        public void Slow() => Thread.Sleep(X * 100);\r
+\r
+        [Benchmark]\r
+        public void Fast() => Thread.Sleep(X * 50);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroOrderManual.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroOrderManual.cs
new file mode 100644 (file)
index 0000000..610b9f9
--- /dev/null
@@ -0,0 +1,61 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Order;\r
+using BenchmarkDotNet.Reports;\r
+using BenchmarkDotNet.Running;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Collections.Immutable;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    [DryJob]\r
+    [RankColumn]\r
+    public class IntroOrderManual\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config() => Orderer = new FastestToSlowestOrderer();\r
+\r
+            private class FastestToSlowestOrderer : IOrderer\r
+            {\r
+                public IEnumerable<BenchmarkCase> GetExecutionOrder(ImmutableArray<BenchmarkCase> benchmarksCase,\r
+                    IEnumerable<BenchmarkLogicalGroupRule>? order = null) =>\r
+                    from benchmark in benchmarksCase\r
+                    orderby benchmark.Parameters["X"] descending,\r
+                        benchmark.Descriptor.WorkloadMethodDisplayInfo\r
+                    select benchmark;\r
+\r
+                public IEnumerable<BenchmarkCase> GetSummaryOrder(ImmutableArray<BenchmarkCase> benchmarksCase, Summary summary) =>\r
+                    from benchmark in benchmarksCase\r
+                    orderby summary[benchmark].ResultStatistics.Mean\r
+                    select benchmark;\r
+\r
+                public string GetHighlightGroupKey(BenchmarkCase benchmarkCase) => null;\r
+\r
+                public string GetLogicalGroupKey(ImmutableArray<BenchmarkCase> allBenchmarksCases, BenchmarkCase benchmarkCase) =>\r
+                    benchmarkCase.Job.DisplayInfo + "_" + benchmarkCase.Parameters.DisplayInfo;\r
+\r
+                public IEnumerable<IGrouping<string, BenchmarkCase>> GetLogicalGroupOrder(IEnumerable<IGrouping<string, BenchmarkCase>> logicalGroups,\r
+                    IEnumerable<BenchmarkLogicalGroupRule>? order = null) =>\r
+                    logicalGroups.OrderBy(it => it.Key);\r
+\r
+                public bool SeparateLogicalGroups => true;\r
+            }\r
+        }\r
+\r
+        [Params(1, 2, 3)]\r
+        public int X { get; set; }\r
+\r
+        [Benchmark]\r
+        public void Fast() => Thread.Sleep(X * 50);\r
+\r
+        [Benchmark]\r
+        public void Slow() => Thread.Sleep(X * 100);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroOutliers.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroOutliers.cs
new file mode 100644 (file)
index 0000000..a12ebe2
--- /dev/null
@@ -0,0 +1,37 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Jobs;\r
+using Perfolizer.Mathematics.OutlierDetection;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    public class IntroOutliers\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                var jobBase = Job.Default.WithWarmupCount(0).WithIterationCount(10).WithInvocationCount(1).WithUnrollFactor(1);\r
+                AddJob(jobBase.WithOutlierMode(OutlierMode.DontRemove).WithId("DontRemoveOutliers"));\r
+                AddJob(jobBase.WithOutlierMode(OutlierMode.RemoveUpper).WithId("RemoveUpperOutliers"));\r
+            }\r
+        }\r
+\r
+        private int counter;\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            counter++;\r
+            int noise = counter % 10 == 0 ? 500 : 0;\r
+            Thread.Sleep(100 + noise);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroParams.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroParams.cs
new file mode 100644 (file)
index 0000000..0e8b908
--- /dev/null
@@ -0,0 +1,22 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroParams\r
+    {\r
+        [Params(100, 200)]\r
+        public int A { get; set; }\r
+\r
+        [Params(10, 20)]\r
+        public int B { get; set; }\r
+\r
+        [Benchmark]\r
+        public void Benchmark() => Thread.Sleep(A + B + 5);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroParamsAllValues.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroParamsAllValues.cs
new file mode 100644 (file)
index 0000000..947ce1b
--- /dev/null
@@ -0,0 +1,35 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [DryJob]\r
+    public class IntroParamsAllValues\r
+    {\r
+        public enum CustomEnum\r
+        {\r
+            One = 1,\r
+            Two,\r
+            Three\r
+        }\r
+\r
+        [ParamsAllValues]\r
+        public CustomEnum E { get; set; }\r
+\r
+        [ParamsAllValues]\r
+        public bool? B { get; set; }\r
+\r
+        [Benchmark]\r
+        public void Benchmark()\r
+        {\r
+            Thread.Sleep(\r
+                (int)E * 100 +\r
+                (B == true ? 20 : B == false ? 10 : 0));\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroParamsSource.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroParamsSource.cs
new file mode 100644 (file)
index 0000000..d06d4f3
--- /dev/null
@@ -0,0 +1,30 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroParamsSource\r
+    {\r
+        // property with public setter\r
+        [ParamsSource(nameof(ValuesForA))]\r
+        public int A { get; set; }\r
+\r
+        // public field\r
+        [ParamsSource(nameof(ValuesForB))]\r
+        public int B;\r
+\r
+        // public property\r
+        public IEnumerable<int> ValuesForA => new[] { 100, 200 };\r
+\r
+        // public static method\r
+        public static IEnumerable<int> ValuesForB() => new[] { 10, 20 };\r
+\r
+        [Benchmark]\r
+        public void Benchmark() => Thread.Sleep(A + B + 5);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroPercentiles.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroPercentiles.cs
new file mode 100644 (file)
index 0000000..9dfc833
--- /dev/null
@@ -0,0 +1,60 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Columns;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // Using percentiles for adequate timings representation\r
+    [Config(typeof(Config))]\r
+    [SimpleJob(RunStrategy.ColdStart, launchCount: 4,\r
+        warmupCount: 3, iterationCount: 20, id: "MyJob")]\r
+    public class IntroPercentiles\r
+    {\r
+        // To share between runs.\r
+        // DO NOT do this in production code. The System.Random IS NOT thread safe.\r
+        private static readonly Random Rnd = new Random();\r
+\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddColumn(\r
+                    StatisticColumn.P0,\r
+                    StatisticColumn.P25,\r
+                    StatisticColumn.P50,\r
+                    StatisticColumn.P67,\r
+                    StatisticColumn.P80,\r
+                    StatisticColumn.P85,\r
+                    StatisticColumn.P90,\r
+                    StatisticColumn.P95,\r
+                    StatisticColumn.P100);\r
+            }\r
+        }\r
+\r
+        [Benchmark(Baseline = true)]\r
+        public void ConstantDelays() => Thread.Sleep(20);\r
+\r
+        [Benchmark]\r
+        public void RandomDelays() => Thread.Sleep(10 + (int)(20 * Rnd.NextDouble()));\r
+\r
+        [Benchmark]\r
+        public void RareDelays()\r
+        {\r
+            int rndTime = 10;\r
+            // Bigger delays for 15% of the runs\r
+            if (Rnd.NextDouble() > 0.85)\r
+            {\r
+                rndTime += 30;\r
+            }\r
+\r
+            Thread.Sleep(rndTime);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroPowerPlan.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroPowerPlan.cs
new file mode 100644 (file)
index 0000000..01e0524
--- /dev/null
@@ -0,0 +1,46 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [Config(typeof(Config))]\r
+    public class IntroPowerPlan\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.MediumRun.WithPowerPlan(new Guid("e9a42b02-d5df-448d-aa00-03f14749eb61")));\r
+                AddJob(Job.MediumRun.WithPowerPlan(PowerPlan.UltimatePerformance));\r
+                AddJob(Job.MediumRun.WithPowerPlan(PowerPlan.UserPowerPlan));\r
+                AddJob(Job.MediumRun.WithPowerPlan(PowerPlan.HighPerformance));\r
+                AddJob(Job.MediumRun.WithPowerPlan(PowerPlan.Balanced));\r
+                AddJob(Job.MediumRun.WithPowerPlan(PowerPlan.PowerSaver));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public int IterationTest()\r
+        {\r
+            int j = 0;\r
+            for (int i = 0; i < short.MaxValue; ++i)\r
+            {\r
+                j = i;\r
+            }\r
+\r
+            return j;\r
+        }\r
+\r
+        [Benchmark]\r
+        public int SplitJoin()\r
+            => string.Join(",", new string[1000]).Split(',').Length;\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroRankColumn.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroRankColumn.cs
new file mode 100644 (file)
index 0000000..3c1d3c8
--- /dev/null
@@ -0,0 +1,29 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Mathematics;\r
+using BenchmarkDotNet.Order;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [ShortRunJob]\r
+    [Orderer(SummaryOrderPolicy.FastestToSlowest)]\r
+    [RankColumn(NumeralSystem.Arabic)]\r
+    [RankColumn(NumeralSystem.Roman)]\r
+    [RankColumn(NumeralSystem.Stars)]\r
+    public class IntroRankColumn\r
+    {\r
+        [Params(1, 2)]\r
+        public int Factor;\r
+\r
+        [Benchmark]\r
+        public void Foo() => Thread.Sleep(Factor * 100);\r
+\r
+        [Benchmark]\r
+        public void Bar() => Thread.Sleep(Factor * 200);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroRatioSD.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroRatioSD.cs
new file mode 100644 (file)
index 0000000..e77dc4e
--- /dev/null
@@ -0,0 +1,38 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using Perfolizer.Mathematics.OutlierDetection;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // Don't remove outliers\r
+    [Outliers(OutlierMode.DontRemove)]\r
+    // Skip jitting, pilot, warmup; measure 10 iterations\r
+    [SimpleJob(RunStrategy.Monitoring, iterationCount: 10, invocationCount: 1)]\r
+    public class IntroRatioSD\r
+    {\r
+        private int counter;\r
+\r
+        [GlobalSetup]\r
+        public void Setup() => counter = 0;\r
+\r
+        [Benchmark(Baseline = true)]\r
+        public void Base()\r
+        {\r
+            Thread.Sleep(100);\r
+            if (++counter % 7 == 0)\r
+                Thread.Sleep(5000); // Emulate outlier\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Slow() => Thread.Sleep(200);\r
+\r
+        [Benchmark]\r
+        public void Fast() => Thread.Sleep(50);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroRatioStyle.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroRatioStyle.cs
new file mode 100644 (file)
index 0000000..09d85b9
--- /dev/null
@@ -0,0 +1,34 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Columns;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Reports;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [ShortRunJob, Config(typeof(Config))]\r
+    public class IntroRatioStyle\r
+    {\r
+        [Benchmark(Baseline = true)]\r
+        public void Baseline() => Thread.Sleep(1000);\r
+\r
+        [Benchmark]\r
+        public void Bar() => Thread.Sleep(150);\r
+\r
+        [Benchmark]\r
+        public void Foo() => Thread.Sleep(1150);\r
+\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                SummaryStyle = SummaryStyle.Default.WithRatioStyle(RatioStyle.Trend);\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupGlobal.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupGlobal.cs
new file mode 100644 (file)
index 0000000..801230d
--- /dev/null
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroSetupCleanupGlobal\r
+    {\r
+        [Params(10, 100, 1000)]\r
+        public int N;\r
+\r
+        private int[] data;\r
+\r
+        [GlobalSetup]\r
+        public void GlobalSetup()\r
+        {\r
+            data = new int[N]; // executed once per each N value\r
+        }\r
+\r
+        [Benchmark]\r
+        public int Logic()\r
+        {\r
+            int res = 0;\r
+            for (int i = 0; i < N; i++)\r
+                res += data[i];\r
+            return res;\r
+        }\r
+\r
+        [GlobalCleanup]\r
+        public void GlobalCleanup()\r
+        {\r
+            // Disposing logic\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupIteration.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupIteration.cs
new file mode 100644 (file)
index 0000000..92accd2
--- /dev/null
@@ -0,0 +1,39 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [SimpleJob(RunStrategy.Monitoring, launchCount: 1,\r
+        warmupCount: 2, iterationCount: 3)]\r
+    public class IntroSetupCleanupIteration\r
+    {\r
+        private int setupCounter;\r
+        private int cleanupCounter;\r
+\r
+        [IterationSetup]\r
+        public void IterationSetup()\r
+            => Console.WriteLine($"// IterationSetup ({++setupCounter})");\r
+\r
+        [IterationCleanup]\r
+        public void IterationCleanup()\r
+            => Console.WriteLine($"// IterationCleanup ({++cleanupCounter})");\r
+\r
+        [GlobalSetup]\r
+        public void GlobalSetup()\r
+            => Console.WriteLine("// " + "GlobalSetup");\r
+\r
+        [GlobalCleanup]\r
+        public void GlobalCleanup()\r
+            => Console.WriteLine("// " + "GlobalCleanup");\r
+\r
+        [Benchmark]\r
+        public void Benchmark()\r
+            => Console.WriteLine("// " + "Benchmark");\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupTarget.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroSetupCleanupTarget.cs
new file mode 100644 (file)
index 0000000..fc8332f
--- /dev/null
@@ -0,0 +1,40 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Engines;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [SimpleJob(RunStrategy.Monitoring, launchCount: 0,\r
+        warmupCount: 0, iterationCount: 1)]\r
+    public class IntroSetupCleanupTarget\r
+    {\r
+        [GlobalSetup(Target = nameof(BenchmarkA))]\r
+        public void GlobalSetupA()\r
+            => Console.WriteLine("// " + "GlobalSetup A");\r
+\r
+        [Benchmark]\r
+        public void BenchmarkA()\r
+            => Console.WriteLine("// " + "Benchmark A");\r
+\r
+        [GlobalSetup(Targets = new[] { nameof(BenchmarkB), nameof(BenchmarkC) })]\r
+        public void GlobalSetupB()\r
+            => Console.WriteLine("// " + "GlobalSetup B");\r
+\r
+        [Benchmark]\r
+        public void BenchmarkB()\r
+            => Console.WriteLine("// " + "Benchmark B");\r
+\r
+        [Benchmark]\r
+        public void BenchmarkC()\r
+            => Console.WriteLine("// " + "Benchmark C");\r
+\r
+        [Benchmark]\r
+        public void BenchmarkD()\r
+            => Console.WriteLine("// " + "Benchmark D");\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroStaThread.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroStaThread.cs
new file mode 100644 (file)
index 0000000..a463eb7
--- /dev/null
@@ -0,0 +1,23 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class IntroStaThread\r
+    {\r
+        [Benchmark, System.STAThread]\r
+        public void CheckForSTA()\r
+        {\r
+            if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)\r
+            {\r
+                throw new ThreadStateException(\r
+                    "The current threads apartment state is not STA");\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroStatisticalTesting.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroStatisticalTesting.cs
new file mode 100644 (file)
index 0000000..c48b468
--- /dev/null
@@ -0,0 +1,28 @@
+using BenchmarkDotNet.Attributes;\r
+using Perfolizer.Mathematics.SignificanceTesting;\r
+using Perfolizer.Mathematics.Thresholds;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [StatisticalTestColumn(StatisticalTestKind.Welch, ThresholdUnit.Microseconds, 1, true)]\r
+    [StatisticalTestColumn(StatisticalTestKind.MannWhitney, ThresholdUnit.Microseconds, 1, true)]\r
+    [StatisticalTestColumn(StatisticalTestKind.Welch, ThresholdUnit.Ratio, 0.03, true)]\r
+    [StatisticalTestColumn(StatisticalTestKind.MannWhitney, ThresholdUnit.Ratio, 0.03, true)]\r
+    [SimpleJob(warmupCount: 0, iterationCount: 5)]\r
+    public class IntroStatisticalTesting\r
+    {\r
+        [Benchmark] public void Sleep50() => Thread.Sleep(50);\r
+        [Benchmark] public void Sleep97() => Thread.Sleep(97);\r
+        [Benchmark] public void Sleep99() => Thread.Sleep(99);\r
+        [Benchmark(Baseline = true)] public void Sleep100() => Thread.Sleep(100);\r
+        [Benchmark] public void Sleep101() => Thread.Sleep(101);\r
+        [Benchmark] public void Sleep103() => Thread.Sleep(103);\r
+        [Benchmark] public void Sleep150() => Thread.Sleep(150);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroStatisticsColumns.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroStatisticsColumns.cs
new file mode 100644 (file)
index 0000000..fbb7342
--- /dev/null
@@ -0,0 +1,36 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Security.Cryptography;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [MediumRunJob, SkewnessColumn, KurtosisColumn]\r
+    public class IntroStatisticsColumns\r
+    {\r
+        private const int N = 10000;\r
+        private readonly byte[] data;\r
+\r
+        private readonly MD5 md5 = MD5.Create();\r
+        private readonly SHA256 sha256 = SHA256.Create();\r
+\r
+        public IntroStatisticsColumns()\r
+        {\r
+            data = new byte[N];\r
+            new Random(42).NextBytes(data);\r
+        }\r
+\r
+        [Benchmark(Baseline = true)]\r
+        public byte[] Md5A() => md5.ComputeHash(data);\r
+\r
+        [Benchmark]\r
+        public byte[] Md5B() => md5.ComputeHash(data);\r
+\r
+        [Benchmark]\r
+        public byte[] Sha256() => sha256.ComputeHash(data);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroStopOnFirstError.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroStopOnFirstError.cs
new file mode 100644 (file)
index 0000000..d67db95
--- /dev/null
@@ -0,0 +1,20 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [StopOnFirstError]\r
+    public class IntroStopOnFirstError\r
+    {\r
+        [Benchmark(Baseline = true)]\r
+        public int FirstMethod() => throw new Exception("Example exception.");\r
+\r
+        [Benchmark]\r
+        public int SecondMethod() => 1;\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroTagColumn.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroTagColumn.cs
new file mode 100644 (file)
index 0000000..5c3b362
--- /dev/null
@@ -0,0 +1,40 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Columns;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Jobs;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // You can add custom tags per each method using Columns\r
+    [Config(typeof(Config))]\r
+    public class IntroTagColumn\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config()\r
+            {\r
+                AddJob(Job.Dry);\r
+                AddColumn(new TagColumn("Kind", name => name.Substring(0, 3)));\r
+                AddColumn(new TagColumn("Number", name => name.Substring(3)));\r
+            }\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo1() => Thread.Sleep(10);\r
+\r
+        [Benchmark]\r
+        public void Foo12() => Thread.Sleep(10);\r
+\r
+        [Benchmark]\r
+        public void Bar3() => Thread.Sleep(10);\r
+\r
+        [Benchmark]\r
+        public void Bar34() => Thread.Sleep(10);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroTailcall.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroTailcall.cs
new file mode 100644 (file)
index 0000000..999f0ba
--- /dev/null
@@ -0,0 +1,28 @@
+using BenchmarkDotNet.Attributes;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    [BenchmarkDotNet.Diagnostics.Windows.Configs.TailCallDiagnoser]\r
+    [LegacyJitX86Job, LegacyJitX64Job, RyuJitX64Job]\r
+    public class IntroTailcall\r
+    {\r
+        [Benchmark]\r
+        public long Calc()\r
+            => FactorialWithoutTailing(7) - FactorialWithTailing(7);\r
+\r
+        private static long FactorialWithoutTailing(int depth)\r
+            => depth == 0 ? 1 : depth * FactorialWithoutTailing(depth - 1);\r
+\r
+        private static long FactorialWithTailing(int pos, int depth)\r
+            => pos == 0 ? depth : FactorialWithTailing(pos - 1, depth * pos);\r
+\r
+        private static long FactorialWithTailing(int depth)\r
+            => FactorialWithTailing(depth - 1, depth);\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroUnicode.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroUnicode.cs
new file mode 100644 (file)
index 0000000..77dcd2d
--- /dev/null
@@ -0,0 +1,69 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Running;\r
+using BenchmarkDotNet.Toolchains.DotNetCli;\r
+using BenchmarkDotNet.Toolchains.MonoWasm;\r
+using BenchmarkDotNet.Toolchains;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+using BenchmarkDotNet.Loggers;\r
+using System.Diagnostics;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // *** Attribute Style ***\r
+    [UnicodeConsoleLogger]\r
+    public class IntroUnicode\r
+    {\r
+        [Benchmark]\r
+        public long Foo()\r
+        {\r
+            long waitUntil = Stopwatch.GetTimestamp() + 1000;\r
+            while (Stopwatch.GetTimestamp() < waitUntil) { }\r
+            return waitUntil;\r
+        }\r
+    }\r
+\r
+    // *** Object Style ***\r
+    [Config(typeof(Config))]\r
+    public class IntroUnicodeObjectStyle\r
+    {\r
+        private class Config : ManualConfig\r
+        {\r
+            public Config() => AddLogger(ConsoleLogger.Unicode);\r
+        }\r
+\r
+        [Benchmark]\r
+        public long Foo()\r
+        {\r
+            long waitUntil = Stopwatch.GetTimestamp() + 1000;\r
+            while (Stopwatch.GetTimestamp() < waitUntil) { }\r
+            return waitUntil;\r
+        }\r
+    }\r
+\r
+    // *** Fluent Config ***\r
+    public class IntroUnicodeFluentConfig\r
+    {\r
+        public static void Run()\r
+        {\r
+            BenchmarkRunner.Run<IntroUnicodeFluentConfig>(\r
+                DefaultConfig.Instance\r
+                    .AddLogger(ConsoleLogger.Unicode));\r
+        }\r
+\r
+        [Benchmark]\r
+        public long Foo()\r
+        {\r
+            long waitUntil = Stopwatch.GetTimestamp() + 1000;\r
+            while (Stopwatch.GetTimestamp() < waitUntil) { }\r
+            return waitUntil;\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/IntroWasm.cs b/tests/Benchmark/TizenBenchmark/Intro/IntroWasm.cs
new file mode 100644 (file)
index 0000000..6872095
--- /dev/null
@@ -0,0 +1,61 @@
+using BenchmarkDotNet.Attributes;\r
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Environments;\r
+using BenchmarkDotNet.Jobs;\r
+using BenchmarkDotNet.Loggers;\r
+using BenchmarkDotNet.Running;\r
+using BenchmarkDotNet.Toolchains.DotNetCli;\r
+using BenchmarkDotNet.Toolchains.MonoWasm;\r
+using BenchmarkDotNet.Toolchains;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Diagnostics;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    // *** Command Line Arguments ***\r
+    public class IntroWasmCmdConfig\r
+    {\r
+        // the args must contain:\r
+        // an information that we want to run benchmark as Wasm:\r
+        // --runtimes Wasm\r
+        // path to dotnet cli\r
+        // --cli /home/adam/projects/runtime/dotnet.sh\r
+        public static void Run(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(IntroWasmCmdConfig).Assembly).Run(args);\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+\r
+    // *** Fluent Config ***\r
+    public class IntroWasmFluentConfig\r
+    {\r
+        public static void Run()\r
+        {\r
+            // the Wasm Toolchain requires two mandatory arguments:\r
+            const string cliPath = @"/home/adam/projects/runtime/dotnet.sh";\r
+\r
+            WasmRuntime runtime = new WasmRuntime(msBuildMoniker: "net5.0");\r
+            NetCoreAppSettings netCoreAppSettings = new NetCoreAppSettings(\r
+                targetFrameworkMoniker: "net5.0", runtimeFrameworkVersion: null, name: "Wasm",\r
+                customDotNetCliPath: cliPath);\r
+            IToolchain toolChain = WasmToolchain.From(netCoreAppSettings);\r
+\r
+            BenchmarkRunner.Run<IntroCustomMonoFluentConfig>(DefaultConfig.Instance\r
+                .AddJob(Job.ShortRun.WithRuntime(runtime).WithToolchain(toolChain)));\r
+        }\r
+\r
+        [Benchmark]\r
+        public void Foo()\r
+        {\r
+            // Benchmark body\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/Intro/TizenDotnet.cs b/tests/Benchmark/TizenBenchmark/Intro/TizenDotnet.cs
new file mode 100644 (file)
index 0000000..d1109c5
--- /dev/null
@@ -0,0 +1,951 @@
+using BenchmarkDotNet.Configs;\r
+using BenchmarkDotNet.Exporters;\r
+using BenchmarkDotNet.Loggers;\r
+using BenchmarkDotNet.Running;\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading.Tasks;\r
+\r
+namespace TizenBenchmark.Intro\r
+{\r
+    public class TizenDotnet\r
+    {\r
+        void IntroArguments()\r
+        {\r
+            Console.WriteLine("##### IntroArguments Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroArguments>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroArguments Benchmark END #####");\r
+        }\r
+        void IntroArgumentsSource()\r
+        {\r
+            Console.WriteLine("##### IntroArgumentsSource Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroArgumentsSource>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroArgumentsSource Benchmark END #####");\r
+        }\r
+        void IntroArrayParam()\r
+        {\r
+            Console.WriteLine("##### IntroArrayParam Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroArrayParam>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroArrayParam Benchmark END #####");\r
+        }\r
+        void IntroBasic()\r
+        {\r
+            Console.WriteLine("##### IntroBasic Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroBasic>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroBasic Benchmark END #####");\r
+        }\r
+        void IntroBenchmarkBaseline()\r
+        {\r
+            Console.WriteLine("##### IntroBenchmarkBaseline Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroBenchmarkBaseline>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroBenchmarkBaseline Benchmark END #####");\r
+        }\r
+        void IntroCategories()\r
+        {\r
+            Console.WriteLine("##### IntroCategories Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroCategories>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroCategories Benchmark END #####");\r
+        }\r
+        void IntroCategoryBaseline()\r
+        {\r
+            Console.WriteLine("##### IntroCategoryBaseline Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroCategoryBaseline>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroCategoryBaseline Benchmark END #####");\r
+        }\r
+        void IntroCategoryDiscoverer()\r
+        {\r
+            Console.WriteLine("##### IntroCategoryDiscoverer Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroCategoryDiscoverer>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroCategoryDiscoverer Benchmark END #####");\r
+        }\r
+        void IntroColdStart()\r
+        {\r
+            Console.WriteLine("##### IntroColdStart Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroColdStart>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroColdStart Benchmark END #####");\r
+        }\r
+        void IntroComparableComplexParam()\r
+        {\r
+            Console.WriteLine("##### IntroComparableComplexParam Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroComparableComplexParam>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroComparableComplexParam Benchmark END #####");\r
+        }\r
+        void IntroConfigSource()\r
+        {\r
+            Console.WriteLine("##### IntroConfigSource Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroConfigSource>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroConfigSource Benchmark END #####");\r
+        }\r
+        void IntroConfigUnion()\r
+        {\r
+            Console.WriteLine("##### IntroConfigUnion Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroConfigUnion>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroConfigUnion Benchmark END #####");\r
+        }\r
+        void IntroCustomMono()\r
+        {\r
+            Console.WriteLine("##### IntroCustomMono Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            //var summary = BenchmarkRunner.Run<IntroCustomMono>(config);\r
+            //MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            //Console.WriteLine(logger.GetLog());\r
+\r
+            //summary = BenchmarkRunner.Run<IntroCustomMonoObjectStyle>(config);\r
+            //MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            //Console.WriteLine(logger.GetLog());\r
+\r
+            //summary = BenchmarkRunner.Run<IntroCustomMonoObjectStyleAot>(config);\r
+            //MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            //Console.WriteLine(logger.GetLog());\r
+\r
+            var summary = BenchmarkRunner.Run<IntroCustomMonoFluentConfig>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroCustomMono Benchmark END #####");\r
+        }\r
+        void IntroCustomMonoArguments()\r
+        {\r
+            Console.WriteLine("##### IntroCustomMonoArguments Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroCustomMonoArguments>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroCustomMonoArguments Benchmark END #####");\r
+        }\r
+        void IntroDeferredExecution()\r
+        {\r
+            Console.WriteLine("##### IntroDeferredExecution Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroDeferredExecution>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroDeferredExecution Benchmark END #####");\r
+        }\r
+        void IntroDisassembly()\r
+        {\r
+            Console.WriteLine("##### IntroDisassembly Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroDisassembly>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroDisassembly Benchmark END #####");\r
+        }\r
+        void IntroDisassemblyAllJits()\r
+        {\r
+            Console.WriteLine("##### IntroDisassemblyAllJits Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroDisassemblyAllJits>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroDisassemblyAllJits Benchmark END #####");\r
+        }\r
+        void IntroDisassemblyDry()\r
+        {\r
+            Console.WriteLine("##### IntroDisassemblyDry Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroDisassemblyDry>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroDisassemblyDry Benchmark END #####");\r
+        }\r
+        void IntroDisassemblyRyuJit()\r
+        {\r
+            Console.WriteLine("##### IntroDisassemblyRyuJit Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroDisassemblyRyuJit>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroDisassemblyRyuJit Benchmark END #####");\r
+        }\r
+        void IntroDotTraceDiagnoser()\r
+        {\r
+            Console.WriteLine("##### IntroDotTraceDiagnoser Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroDotTraceDiagnoser>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroDotTraceDiagnoser Benchmark END #####");\r
+        }\r
+        void IntroEnvVars()\r
+        {\r
+            Console.WriteLine("##### IntroEnvVars Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroEnvVars>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroEnvVars Benchmark END #####");\r
+        }\r
+        void IntroEventPipeProfiler()\r
+        {\r
+            Console.WriteLine("##### IntroEventPipeProfiler Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroEventPipeProfiler>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroEventPipeProfiler Benchmark END #####");\r
+        }\r
+        void IntroEventPipeProfilerAdvanced()\r
+        {\r
+            Console.WriteLine("##### IntroEventPipeProfilerAdvanced Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroEventPipeProfilerAdvanced>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroEventPipeProfilerAdvanced Benchmark END #####");\r
+        }\r
+        void IntroExport()\r
+        {\r
+            Console.WriteLine("##### IntroExport Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroExport>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroExport Benchmark END #####");\r
+        }\r
+        void IntroExportJson()\r
+        {\r
+            Console.WriteLine("##### IntroExportJson Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroExportJson>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroExportJson Benchmark END #####");\r
+        }\r
+        void IntroExportXml()\r
+        {\r
+            Console.WriteLine("##### IntroExportXml Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroExportXml>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroExportXml Benchmark END #####");\r
+        }\r
+        void IntroFilters()\r
+        {\r
+            Console.WriteLine("##### IntroFilters Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroFilters>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroFilters Benchmark END #####");\r
+        }\r
+        void IntroFluentConfigBuilder()\r
+        {\r
+            Console.WriteLine("##### IntroFluentConfigBuilder Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroFluentConfigBuilder>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroFluentConfigBuilder Benchmark END #####");\r
+        }\r
+        void IntroGcMode()\r
+        {\r
+            Console.WriteLine("##### IntroGcMode Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroGcMode>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroGcMode Benchmark END #####");\r
+        }\r
+        void IntroGenericTypeArguments()\r
+        {\r
+            Console.WriteLine("##### IntroGenericTypeArguments Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroGenericTypeArguments<int>>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+\r
+            summary = BenchmarkRunner.Run<IntroGenericTypeArguments<char>>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroGenericTypeArguments Benchmark END #####");\r
+        }\r
+        void IntroHardwareCounters()\r
+        {\r
+            Console.WriteLine("##### IntroHardwareCounters Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroHardwareCounters>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroHardwareCounters Benchmark END #####");\r
+        }\r
+        void IntroInliningDiagnoser()\r
+        {\r
+            Console.WriteLine("##### IntroInliningDiagnoser Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroInliningDiagnoser>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroInliningDiagnoser Benchmark END #####");\r
+        }\r
+        void IntroInProcess()\r
+        {\r
+            Console.WriteLine("##### IntroInProcess Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroInProcess>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroInProcess Benchmark END #####");\r
+        }\r
+        void IntroInProcessWrongEnv()\r
+        {\r
+            Console.WriteLine("##### IntroInProcessWrongEnv Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroInProcessWrongEnv>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroInProcessWrongEnv Benchmark END #####");\r
+        }\r
+        void IntroJitStatsDiagnoser()\r
+        {\r
+            Console.WriteLine("##### IntroJitStatsDiagnoser Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroJitStatsDiagnoser>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroJitStatsDiagnoser Benchmark END #####");\r
+        }\r
+        void IntroJobBaseline()\r
+        {\r
+            Console.WriteLine("##### IntroJobBaseline Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroJobBaseline>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroJobBaseline Benchmark END #####");\r
+        }\r
+        void IntroJoin()\r
+        {\r
+            Console.WriteLine("##### IntroJoin Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroJoin1>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+\r
+            summary = BenchmarkRunner.Run<IntroJoin2>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroJoin Benchmark END #####");\r
+        }\r
+        void IntroLargeAddressAware()\r
+        {\r
+            Console.WriteLine("##### IntroLargeAddressAware Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroLargeAddressAware>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroLargeAddressAware Benchmark END #####");\r
+        }\r
+        void IntroMonitoring()\r
+        {\r
+            Console.WriteLine("##### IntroMonitoring Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroMonitoring>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroMonitoring Benchmark END #####");\r
+        }\r
+        void IntroMultimodal()\r
+        {\r
+            Console.WriteLine("##### IntroMultimodal Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroMultimodal>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroMultimodal Benchmark END #####");\r
+        }\r
+        void IntroNativeMemory()\r
+        {\r
+            Console.WriteLine("##### IntroNativeMemory Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroNativeMemory>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroNativeMemory Benchmark END #####");\r
+        }\r
+        void IntroNuGet()\r
+        {\r
+            Console.WriteLine("##### IntroNuGet Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroNuGet>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroNuGet Benchmark END #####");\r
+        }\r
+        void IntroOrderAttr()\r
+        {\r
+            Console.WriteLine("##### IntroOrderAttr Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroOrderAttr>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroOrderAttr Benchmark END #####");\r
+        }\r
+        void IntroOrderManual()\r
+        {\r
+            Console.WriteLine("##### IntroOrderManual Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroOrderManual>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroOrderManual Benchmark END #####");\r
+        }\r
+        void IntroOutliers()\r
+        {\r
+            Console.WriteLine("##### IntroOutliers Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroOutliers>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroOutliers Benchmark END #####");\r
+        }\r
+        void IntroParams()\r
+        {\r
+            Console.WriteLine("##### IntroParams Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroParams>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroParams Benchmark END #####");\r
+        }\r
+        void IntroParamsAllValues()\r
+        {\r
+            Console.WriteLine("##### IntroParamsAllValues Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroParamsAllValues>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroParamsAllValues Benchmark END #####");\r
+        }\r
+        void IntroParamsSource()\r
+        {\r
+            Console.WriteLine("##### aIntroParamsSourceaa Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroParamsSource>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroParamsSource Benchmark END #####");\r
+        }\r
+        void IntroPercentiles()\r
+        {\r
+            Console.WriteLine("##### IntroPercentiles Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroPercentiles>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroPercentiles Benchmark END #####");\r
+        }\r
+        void IntroPowerPlan()\r
+        {\r
+            Console.WriteLine("##### IntroPowerPlan Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroPowerPlan>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroPowerPlan Benchmark END #####");\r
+        }\r
+        void IntroRankColumn()\r
+        {\r
+            Console.WriteLine("##### IntroRankColumn Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroRankColumn>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroRankColumn Benchmark END #####");\r
+        }\r
+        void IntroRatioSD()\r
+        {\r
+            Console.WriteLine("##### IntroRatioSD Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroRatioSD>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroRatioSD Benchmark END #####");\r
+        }\r
+        void IntroRatioStyle()\r
+        {\r
+            Console.WriteLine("##### IntroRatioStyle Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroRatioStyle>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroRatioStyle Benchmark END #####");\r
+        }\r
+        void IntroSetupCleanupGlobal()\r
+        {\r
+            Console.WriteLine("##### IntroSetupCleanupGlobal Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroSetupCleanupGlobal>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroSetupCleanupGlobal Benchmark END #####");\r
+        }\r
+        void IntroSetupCleanupIteration()\r
+        {\r
+            Console.WriteLine("##### IntroSetupCleanupIteration Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroSetupCleanupIteration>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroSetupCleanupIteration Benchmark END #####");\r
+        }\r
+        void IntroSetupCleanupTarget()\r
+        {\r
+            Console.WriteLine("##### IntroSetupCleanupTarget Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroSetupCleanupTarget>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroSetupCleanupTarget Benchmark END #####");\r
+        }\r
+        void IntroStaThread()\r
+        {\r
+            Console.WriteLine("##### IntroStaThread Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroStaThread>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroStaThread Benchmark END #####");\r
+        }\r
+        void IntroStatisticalTesting()\r
+        {\r
+            Console.WriteLine("##### IntroStatisticalTesting Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroStatisticalTesting>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroStatisticalTesting Benchmark END #####");\r
+        }\r
+        void IntroStatisticsColumns()\r
+        {\r
+            Console.WriteLine("##### IntroStatisticsColumns Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroStatisticsColumns>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroStatisticsColumns Benchmark END #####");\r
+        }\r
+        void IntroStopOnFirstError()\r
+        {\r
+            Console.WriteLine("##### IntroStopOnFirstError Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroStopOnFirstError>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroStopOnFirstError Benchmark END #####");\r
+        }\r
+        void IntroTagColumn()\r
+        {\r
+            Console.WriteLine("##### IntroTagColumn Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroTagColumn>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroTagColumn Benchmark END #####");\r
+        }\r
+        void IntroTailcall()\r
+        {\r
+            Console.WriteLine("##### IntroTailcall Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroTailcall>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroTailcall Benchmark END #####");\r
+        }\r
+        void IntroUnicode()\r
+        {\r
+            Console.WriteLine("##### IntroUnicode Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroUnicode>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+\r
+            summary = BenchmarkRunner.Run<IntroUnicodeObjectStyle>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+\r
+            summary = BenchmarkRunner.Run<IntroUnicodeFluentConfig>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroUnicode Benchmark END #####");\r
+        }\r
+        void IntroWasm()\r
+        {\r
+            Console.WriteLine("##### IntroWasm Benchmark START #####");\r
+            var logger = new AccumulationLogger();\r
+            var config = default(IConfig);\r
+            config = new DebugInProcessConfig();\r
+            config = config.WithArtifactsPath("/tmp/BenchmarkDotnet");\r
+\r
+            var summary = BenchmarkRunner.Run<IntroWasmCmdConfig>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+\r
+            summary = BenchmarkRunner.Run<IntroWasmFluentConfig>(config);\r
+            MarkdownExporter.Console.ExportToLog(summary, logger);\r
+            Console.WriteLine(logger.GetLog());\r
+            Console.WriteLine("##### IntroWasm Benchmark END #####");\r
+        }\r
+\r
+\r
+        public void Benchmark()\r
+        {\r
+            Console.WriteLine("##### Tizen.NET Benchmark START #####");\r
+            IntroArguments(); //1\r
+            IntroArgumentsSource(); //1\r
+            IntroArrayParam(); //1\r
+            IntroBasic(); //1\r
+            IntroBenchmarkBaseline(); //1\r
+            //IntroCategories();\r
+            IntroCategoryBaseline(); //1\r
+            //IntroCategoryDiscoverer();\r
+            //IntroColdStart();\r
+            IntroComparableComplexParam(); //1\r
+            //IntroConfigSource();\r
+            //IntroConfigUnion();\r
+            IntroCustomMono(); //1\r
+            //IntroCustomMonoArguments();\r
+            IntroDeferredExecution(); //1\r
+            //IntroDisassembly();\r
+            //IntroDisassemblyAllJits();\r
+            //IntroDisassemblyDry();\r
+            //IntroDisassemblyRyuJit();\r
+            //IntroDotTraceDiagnoser();\r
+            //IntroEnvVars();\r
+            //IntroEventPipeProfiler();\r
+            //IntroEventPipeProfilerAdvanced();\r
+            //IntroExport();\r
+            //IntroExportJson();\r
+            //IntroExportXml();\r
+            //IntroFilters();\r
+            //IntroFluentConfigBuilder();\r
+            //IntroGcMode();\r
+            IntroGenericTypeArguments(); //2\r
+            IntroHardwareCounters(); //1\r
+            //IntroInliningDiagnoser();\r
+            //IntroInProcess();\r
+            IntroInProcessWrongEnv(); //1\r
+            //IntroJitStatsDiagnoser();\r
+            //IntroJobBaseline();\r
+            //IntroJoin();\r
+            //IntroLargeAddressAware();\r
+            //IntroMonitoring();\r
+            //IntroMultimodal();\r
+            //IntroNativeMemory();\r
+            //IntroNuGet();\r
+            //IntroOrderAttr();\r
+            //IntroOrderManual();\r
+            //IntroOutliers();\r
+            IntroParams(); //1\r
+            //IntroParamsAllValues();\r
+            IntroParamsSource(); //1\r
+            //IntroPercentiles();\r
+            //IntroPowerPlan();\r
+            //IntroRankColumn();\r
+            //IntroRatioSD();\r
+            //IntroRatioStyle();\r
+            IntroSetupCleanupGlobal(); //1\r
+            //IntroSetupCleanupIteration();\r
+            //IntroSetupCleanupTarget();\r
+            IntroStaThread(); //1\r
+            //IntroStatisticalTesting();\r
+            //IntroStatisticsColumns();\r
+            //IntroStopOnFirstError();\r
+            //IntroTagColumn();\r
+            //IntroTailcall();\r
+            IntroUnicode(); //3\r
+            IntroWasm(); //2\r
+            Console.WriteLine("##### Tizen.NET Benchmark END #####");\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/TizenBenchmark.cs b/tests/Benchmark/TizenBenchmark/TizenBenchmark.cs
new file mode 100644 (file)
index 0000000..d559200
--- /dev/null
@@ -0,0 +1,51 @@
+using Tizen.NUI;\r
+using Tizen.NUI.BaseComponents;\r
+\r
+namespace TizenBenchmark\r
+{\r
+    class Program : NUIApplication\r
+    {\r
+        protected override void OnCreate()\r
+        {\r
+            base.OnCreate();\r
+            Initialize();\r
+        }\r
+\r
+        void Initialize()\r
+        {\r
+            Intro.TizenDotnet benchmark = new Intro.TizenDotnet();\r
+            benchmark.Benchmark();\r
+\r
+            Window.Instance.KeyEvent += OnKeyEvent;\r
+\r
+            TextLabel text = new TextLabel("Hello Tizen NUI World");\r
+            text.HorizontalAlignment = HorizontalAlignment.Center;\r
+            text.VerticalAlignment = VerticalAlignment.Center;\r
+            text.TextColor = Color.Blue;\r
+            text.PointSize = 12.0f;\r
+            text.HeightResizePolicy = ResizePolicyType.FillToParent;\r
+            text.WidthResizePolicy = ResizePolicyType.FillToParent;\r
+            Window.Instance.GetDefaultLayer().Add(text);\r
+\r
+            Animation animation = new Animation(2000);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(180.0f)), PositionAxis.X), 0, 500);\r
+            animation.AnimateTo(text, "Orientation", new Rotation(new Radian(new Degree(0.0f)), PositionAxis.X), 500, 1000);\r
+            animation.Looping = true;\r
+            animation.Play();\r
+        }\r
+\r
+        public void OnKeyEvent(object sender, Window.KeyEventArgs e)\r
+        {\r
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))\r
+            {\r
+                Exit();\r
+            }\r
+        }\r
+\r
+        static void Main(string[] args)\r
+        {\r
+            var app = new Program();\r
+            app.Run(args);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/Benchmark/TizenBenchmark/TizenBenchmark.csproj b/tests/Benchmark/TizenBenchmark/TizenBenchmark.csproj
new file mode 100644 (file)
index 0000000..0ce1585
--- /dev/null
@@ -0,0 +1,30 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>net6.0-tizen</TargetFramework>\r
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>\r
+  </PropertyGroup>\r
+\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugType>portable</DebugType>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <DebugType>None</DebugType>\r
+  </PropertyGroup>\r
+\r
+  <ItemGroup>\r
+    <Folder Include="lib\" />\r
+    <Folder Include="res\" />\r
+  </ItemGroup>\r
+\r
+  <ItemGroup>\r
+    <PackageReference Include="BenchmarkDotNet" Version="0.13.12" />\r
+    <PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.12" />\r
+    <PackageReference Include="BenchmarkDotNet.Diagnostics.dotTrace" Version="0.13.12" />\r
+    <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.12" />\r
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />\r
+    <PackageReference Include="System.Drawing.Common" Version="8.0.0" />\r
+  </ItemGroup>\r
+\r
+</Project>\r
diff --git a/tests/Benchmark/TizenBenchmark/shared/res/TizenBenchmark.png b/tests/Benchmark/TizenBenchmark/shared/res/TizenBenchmark.png
new file mode 100644 (file)
index 0000000..9f3cb98
Binary files /dev/null and b/tests/Benchmark/TizenBenchmark/shared/res/TizenBenchmark.png differ
diff --git a/tests/Benchmark/TizenBenchmark/tizen-manifest.xml b/tests/Benchmark/TizenBenchmark/tizen-manifest.xml
new file mode 100644 (file)
index 0000000..9ebeb6f
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="8.0" package="org.tizen.dotnet.TizenBenchmark" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="org.tizen.dotnet.TizenBenchmark"
+                                       exec="TizenBenchmark.dll"
+                                       type="dotnet"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single"
+          api-version="11">
+    <label>TizenBenchmark</label>
+    <icon>TizenBenchmark.png</icon>
+    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+  </ui-application>
+</manifest>
diff --git a/tests/Benchmark/TizenBenchmark/tizen_dotnet_project.yaml b/tests/Benchmark/TizenBenchmark/tizen_dotnet_project.yaml
new file mode 100644 (file)
index 0000000..2ad0cf0
--- /dev/null
@@ -0,0 +1,9 @@
+# csproj file path
+csproj_file: TizenBenchmark.csproj
+
+# files monitored for dirty/modified status
+files:
+  - TizenBenchmark.csproj
+  - TizenBenchmark.cs
+  - tizen-manifest.xml
+  - shared/res/TizenBenchmark.png
\ No newline at end of file
diff --git a/tests/Benchmark/org.tizen.dotnet.TizenBenchmark-1.0.0.tpk b/tests/Benchmark/org.tizen.dotnet.TizenBenchmark-1.0.0.tpk
new file mode 100644 (file)
index 0000000..68102ad
Binary files /dev/null and b/tests/Benchmark/org.tizen.dotnet.TizenBenchmark-1.0.0.tpk differ
diff --git a/tests/GC/AndroidGCTest/.gitignore b/tests/GC/AndroidGCTest/.gitignore
new file mode 100644 (file)
index 0000000..aa724b7
--- /dev/null
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/tests/GC/AndroidGCTest/.idea/.gitignore b/tests/GC/AndroidGCTest/.idea/.gitignore
new file mode 100644 (file)
index 0000000..26d3352
--- /dev/null
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/tests/GC/AndroidGCTest/.idea/compiler.xml b/tests/GC/AndroidGCTest/.idea/compiler.xml
new file mode 100644 (file)
index 0000000..b589d56
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <bytecodeTargetLevel target="17" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/.idea/deploymentTargetSelector.xml b/tests/GC/AndroidGCTest/.idea/deploymentTargetSelector.xml
new file mode 100644 (file)
index 0000000..b268ef3
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="deploymentTargetSelector">
+    <selectionStates>
+      <SelectionState runConfigName="app">
+        <option name="selectionMode" value="DROPDOWN" />
+      </SelectionState>
+    </selectionStates>
+  </component>
+</project>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/.idea/gradle.xml b/tests/GC/AndroidGCTest/.idea/gradle.xml
new file mode 100644 (file)
index 0000000..0897082
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="GradleMigrationSettings" migrationVersion="1" />
+  <component name="GradleSettings">
+    <option name="linkedExternalProjectsSettings">
+      <GradleProjectSettings>
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
+        <option name="modules">
+          <set>
+            <option value="$PROJECT_DIR$" />
+            <option value="$PROJECT_DIR$/app" />
+          </set>
+        </option>
+        <option name="resolveExternalAnnotations" value="false" />
+      </GradleProjectSettings>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/.idea/migrations.xml b/tests/GC/AndroidGCTest/.idea/migrations.xml
new file mode 100644 (file)
index 0000000..f8051a6
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectMigrations">
+    <option name="MigrateToGradleLocalJavaHome">
+      <set>
+        <option value="$PROJECT_DIR$" />
+      </set>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/.idea/misc.xml b/tests/GC/AndroidGCTest/.idea/misc.xml
new file mode 100644 (file)
index 0000000..8978d23
--- /dev/null
@@ -0,0 +1,9 @@
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/build/classes" />
+  </component>
+  <component name="ProjectType">
+    <option name="id" value="Android" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/.idea/other.xml b/tests/GC/AndroidGCTest/.idea/other.xml
new file mode 100644 (file)
index 0000000..94c96f6
--- /dev/null
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="direct_access_persist.xml">
+    <option name="deviceSelectionList">
+      <list>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="27" />
+          <option name="brand" value="DOCOMO" />
+          <option name="codename" value="F01L" />
+          <option name="id" value="F01L" />
+          <option name="manufacturer" value="FUJITSU" />
+          <option name="name" value="F-01L" />
+          <option name="screenDensity" value="360" />
+          <option name="screenX" value="720" />
+          <option name="screenY" value="1280" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="28" />
+          <option name="brand" value="DOCOMO" />
+          <option name="codename" value="SH-01L" />
+          <option name="id" value="SH-01L" />
+          <option name="manufacturer" value="SHARP" />
+          <option name="name" value="AQUOS sense2 SH-01L" />
+          <option name="screenDensity" value="480" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2160" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="31" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="a51" />
+          <option name="id" value="a51" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy A51" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="akita" />
+          <option name="id" value="akita" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 8a" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="b0q" />
+          <option name="id" value="b0q" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy S22 Ultra" />
+          <option name="screenDensity" value="600" />
+          <option name="screenX" value="1440" />
+          <option name="screenY" value="3088" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="32" />
+          <option name="brand" value="google" />
+          <option name="codename" value="bluejay" />
+          <option name="id" value="bluejay" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 6a" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="caiman" />
+          <option name="id" value="caiman" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 9 Pro" />
+          <option name="screenDensity" value="360" />
+          <option name="screenX" value="960" />
+          <option name="screenY" value="2142" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="comet" />
+          <option name="id" value="comet" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 9 Pro Fold" />
+          <option name="screenDensity" value="390" />
+          <option name="screenX" value="2076" />
+          <option name="screenY" value="2152" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="29" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="crownqlteue" />
+          <option name="id" value="crownqlteue" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy Note9" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="2220" />
+          <option name="screenY" value="1080" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="dm3q" />
+          <option name="id" value="dm3q" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy S23 Ultra" />
+          <option name="screenDensity" value="600" />
+          <option name="screenX" value="1440" />
+          <option name="screenY" value="3088" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="e1q" />
+          <option name="id" value="e1q" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy S24" />
+          <option name="screenDensity" value="480" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2340" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="google" />
+          <option name="codename" value="felix" />
+          <option name="id" value="felix" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel Fold" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="2208" />
+          <option name="screenY" value="1840" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="felix" />
+          <option name="id" value="felix" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel Fold" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="2208" />
+          <option name="screenY" value="1840" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="google" />
+          <option name="codename" value="felix_camera" />
+          <option name="id" value="felix_camera" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel Fold (Camera-enabled)" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="2208" />
+          <option name="screenY" value="1840" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="gts8uwifi" />
+          <option name="id" value="gts8uwifi" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy Tab S8 Ultra" />
+          <option name="screenDensity" value="320" />
+          <option name="screenX" value="1848" />
+          <option name="screenY" value="2960" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="husky" />
+          <option name="id" value="husky" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 8 Pro" />
+          <option name="screenDensity" value="390" />
+          <option name="screenX" value="1008" />
+          <option name="screenY" value="2244" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="30" />
+          <option name="brand" value="motorola" />
+          <option name="codename" value="java" />
+          <option name="id" value="java" />
+          <option name="manufacturer" value="Motorola" />
+          <option name="name" value="G20" />
+          <option name="screenDensity" value="280" />
+          <option name="screenX" value="720" />
+          <option name="screenY" value="1600" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="komodo" />
+          <option name="id" value="komodo" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 9 Pro XL" />
+          <option name="screenDensity" value="360" />
+          <option name="screenX" value="1008" />
+          <option name="screenY" value="2244" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="google" />
+          <option name="codename" value="lynx" />
+          <option name="id" value="lynx" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 7a" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="31" />
+          <option name="brand" value="google" />
+          <option name="codename" value="oriole" />
+          <option name="id" value="oriole" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 6" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="google" />
+          <option name="codename" value="panther" />
+          <option name="id" value="panther" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 7" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="q5q" />
+          <option name="id" value="q5q" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy Z Fold5" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1812" />
+          <option name="screenY" value="2176" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="30" />
+          <option name="brand" value="google" />
+          <option name="codename" value="r11" />
+          <option name="id" value="r11" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel Watch" />
+          <option name="screenDensity" value="320" />
+          <option name="screenX" value="384" />
+          <option name="screenY" value="384" />
+          <option name="type" value="WEAR_OS" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="30" />
+          <option name="brand" value="google" />
+          <option name="codename" value="redfin" />
+          <option name="id" value="redfin" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 5" />
+          <option name="screenDensity" value="440" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2340" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="shiba" />
+          <option name="id" value="shiba" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 8" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2400" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="33" />
+          <option name="brand" value="google" />
+          <option name="codename" value="tangorpro" />
+          <option name="id" value="tangorpro" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel Tablet" />
+          <option name="screenDensity" value="320" />
+          <option name="screenX" value="1600" />
+          <option name="screenY" value="2560" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="34" />
+          <option name="brand" value="google" />
+          <option name="codename" value="tokay" />
+          <option name="id" value="tokay" />
+          <option name="manufacturer" value="Google" />
+          <option name="name" value="Pixel 9" />
+          <option name="screenDensity" value="420" />
+          <option name="screenX" value="1080" />
+          <option name="screenY" value="2424" />
+        </PersistentDeviceSelectionData>
+        <PersistentDeviceSelectionData>
+          <option name="api" value="29" />
+          <option name="brand" value="samsung" />
+          <option name="codename" value="x1q" />
+          <option name="id" value="x1q" />
+          <option name="manufacturer" value="Samsung" />
+          <option name="name" value="Galaxy S20" />
+          <option name="screenDensity" value="480" />
+          <option name="screenX" value="1440" />
+          <option name="screenY" value="3200" />
+        </PersistentDeviceSelectionData>
+      </list>
+    </option>
+  </component>
+</project>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/.gitignore b/tests/GC/AndroidGCTest/app/.gitignore
new file mode 100644 (file)
index 0000000..42afabf
--- /dev/null
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/achartengine/achartengine-1.2.0.jar b/tests/GC/AndroidGCTest/app/achartengine/achartengine-1.2.0.jar
new file mode 100644 (file)
index 0000000..6356acc
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/achartengine/achartengine-1.2.0.jar differ
diff --git a/tests/GC/AndroidGCTest/app/build.gradle b/tests/GC/AndroidGCTest/app/build.gradle
new file mode 100644 (file)
index 0000000..bb39129
--- /dev/null
@@ -0,0 +1,41 @@
+plugins {
+    alias(libs.plugins.android.application)
+}
+
+android {
+    namespace 'com.android.gctest'
+    compileSdk 34
+
+    defaultConfig {
+        applicationId "com.android.gctest"
+        minSdk 29
+        targetSdk 34
+        versionCode 1
+        versionName "1.0"
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+}
+
+dependencies {
+
+    implementation libs.appcompat
+    implementation libs.material
+    implementation libs.activity
+    implementation libs.constraintlayout
+    implementation files('achartengine/achartengine-1.2.0.jar')
+    testImplementation libs.junit
+    androidTestImplementation libs.ext.junit
+    androidTestImplementation libs.espresso.core
+}
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/proguard-rules.pro b/tests/GC/AndroidGCTest/app/proguard-rules.pro
new file mode 100644 (file)
index 0000000..481bb43
--- /dev/null
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/androidTest/java/com/android/gctest/ExampleInstrumentedTest.java b/tests/GC/AndroidGCTest/app/src/androidTest/java/com/android/gctest/ExampleInstrumentedTest.java
new file mode 100644 (file)
index 0000000..8583426
--- /dev/null
@@ -0,0 +1,26 @@
+package com.android.gctest;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        assertEquals("com.android.gctest", appContext.getPackageName());
+    }
+}
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/AndroidManifest.xml b/tests/GC/AndroidGCTest/app/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..6177998
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <application
+        android:allowBackup="true"
+        android:dataExtractionRules="@xml/data_extraction_rules"
+        android:fullBackupContent="@xml/backup_rules"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/Theme.AndroidGCTest"
+        tools:targetApi="31"
+        android:largeHeap="true">
+        <activity
+            android:name=".MainActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ResultActivity" >
+        </activity>
+        <activity
+            android:name=".ProfileSettingActivity" >
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/AndroidGCTestMain.java b/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/AndroidGCTestMain.java
new file mode 100644 (file)
index 0000000..4923f46
--- /dev/null
@@ -0,0 +1,1166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.gctest;
+
+import java.io.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Random;
+import java.lang.reflect.Method;
+
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Message;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.Log;
+
+// 6 kinds of small objects
+class TreeNode { // object size = 16
+    TreeNode left, right;
+    TreeNode (TreeNode l, TreeNode r) { left = l; right = r; }
+    TreeNode () { }
+    int count() {
+        int c = 1;
+        if (left != null)
+            c += left.count();
+        if (right != null)
+            c += right.count();
+        return c;
+    }
+}
+
+class TreeNode32 extends TreeNode { // object size = 24
+    private long payload1;
+    TreeNode32(TreeNode32 l, TreeNode32 r) { left = l; right = r; }
+    TreeNode32() { }
+}
+
+class TreeNode64 extends TreeNode { // object size = 40
+    private long payload1, payload2, payload3;
+    TreeNode64(TreeNode64 l, TreeNode64 r) { left = l; right = r; }
+    TreeNode64() { }
+}
+
+class TreeNode128 extends TreeNode { // object size = 96
+    private long payload1, payload2, payload3, payload4, payload5;
+    private long payload6, payload7, payload8, payload9, payload10;
+    TreeNode128(TreeNode128 l, TreeNode128 r) { left = l; right = r; }
+    TreeNode128() { }
+}
+
+class TreeNode256 extends TreeNode { // object size = 192
+    private long payload1, payload2, payload3, payload4, payload5;
+    private long payload6, payload7, payload8, payload9, payload10;
+    private long payload11, payload12, payload13, payload14, payload15;
+    private long payload16, payload17, payload18, payload19, payload20;
+    private long payload21, payload22;
+    TreeNode256(TreeNode256 l, TreeNode256 r) { left = l; right = r; }
+    TreeNode256() { }
+}
+
+class TreeNode512 extends TreeNode { // object size = 336
+    private long payload1, payload2, payload3, payload4, payload5;
+    private long payload6, payload7, payload8, payload9, payload10;
+    private long payload11, payload12, payload13, payload14, payload15;
+    private long payload16, payload17, payload18, payload19, payload20;
+    private long payload101, payload102, payload103, payload104, payload105;
+    private long payload106, payload107, payload108, payload109, payload100;
+    private long payload111, payload112, payload113, payload114, payload115;
+    private long payload116, payload117, payload118, payload119, payload120;
+    TreeNode512(TreeNode512 l, TreeNode512 r) { left = l; right = r; }
+    TreeNode512() { }
+}
+
+class LinkNode {
+    LinkNode next;
+    TreeNode treeNode;
+    LinkNode(TreeNode n) { treeNode = n; }
+    LinkNode() { }
+}
+
+class LivedLink {
+    public LinkNode treeHead;
+    LivedLink() { treeHead = null;}
+    void insertNode(TreeNode newTree) {
+        if (treeHead == null) {
+            treeHead = new LinkNode(newTree);
+            treeHead.next = null;
+        } else {
+            LinkNode newNode = new LinkNode(newTree);
+            newNode.next = treeHead;
+            treeHead = newNode;
+        }
+    }
+}
+
+public class AndroidGCTestMain {
+    private final String mTag = "AndroidGCTest";
+    private MainActivity mActivity = null;
+
+    // size of small objects
+    public static final int OBJECT_16_BYTE = 0;
+    public static final int OBJECT_32_BYTE = 1;
+    public static final int OBJECT_64_BYTE = 2;
+    public static final int OBJECT_128_BYTE = 3;
+    public static final int OBJECT_256_BYTE = 4;
+    public static final int OBJECT_512_BYTE = 5;
+    public static final int OBJECT_LARGE_BYTE = 6;
+    public static final int OBJECT_SIZE_TYPE = 7;
+    private final int[] mObjectSize = new int[]{16, 24, 40, 96, 192, 336};
+
+    // size of large object, default is 12KByte
+    private int mLargeObjectSize = 0;
+    // array element type distribution for large object
+    // {1-byte array, 2-byte array, 4-byte array, 8-byte array}
+    private float[] mLargeObjectDistribution = null;
+
+    // allocation configuration
+    // total allocate size
+    private int mTotalAllocateSize = 0;
+    // total allocate size by one thread
+    private int mTotalAllocSizePerThread = 0;
+
+    // unit for tree allocation/deletion operation.
+    // mBucketSize is also the unit to measure object lifetime.
+    // Benchmark allocates mBucketSize of data -> deletes some data
+    // -> allocates mBucketSize of Data
+    private int mBucketSize = 0;
+
+    // allocated object size distribution
+    // {[1-16], [17-32], [33-64], [65, 128], [129, 256], [257, 512], >12K}
+    private float[] mSizeDistribution = null;
+
+    // allocated object lifetime:
+    // mLifetime[X][0] is long lived object percentage of object size X,
+    // mLifetime[X][1] is percentage of object die immediately,
+    // mLifetime[X][2] is percentage of object die in next period after
+    // creation period ...
+    private float[][] mLifetime =  null;
+
+    private int mLongLiveSmallObjectSize;
+
+    // a big array to store random values to decide object size of next allocated object
+    private byte[][] mObjectSizeRandom = null;
+    // a big array to store random values to decide lifetime of next allocated object
+    private byte[][] mLifetimeRandom = null;
+    private int mShortLiveTreeCount;
+    private int mTotalNodeCount;
+    private final int mTreeCountParallel = 4;
+
+    private int[] mLargeArrayLength = null;
+    private int[] mLargeArrayNum = null;
+    private int[] mLargeArrayInter = null;
+    private int mLongLiveLargeObjectSize;
+    private int[][] mDieNumLargeObject = null;
+
+    // thread mode configuration
+    private int mThreadNum;
+    private boolean mSingleThread = false;
+
+    private long[] mElapseTime = null;
+    private int[] mHeapFootprint = null;
+    private long[] mHeapBytesAllocated = null;
+
+    private long mTotalGcCount;
+    private long mTotalGcTime;
+    private long mTotalBlockingGcCount;
+    private long mTotalBlockingGcTime;
+    public final String[] GC_CAUSE_ART = new String[]{"Alloc", "Background", "Explicit",
+            "NativeAlloc", "CollectorTransition", "DisableMovingGc", "HomogeneousSpaceCompact",
+            "HeapTrim"};
+    public final String[] GC_CAUSE_DALVIK = new String[]{"GC_FOR_ALLOC","GC_CONCURRENT",
+            "GC_EXPLICIT", "GC_BEFORE_OOM"};
+    private int[] mGcCauseCount = null;
+    private float[] mGcPauseTime = null;
+    private float[] mGcTotalTime = null;
+    private String[] mGcCause = null;
+
+    private boolean isArt;
+    private boolean mWorkloadComplete;
+    private int mIterNum = 100;
+
+    private FileWriter fileOutput;
+    private BenchThread[] mTestThreads;
+    private boolean mOutOfMemory;
+
+    // initialize benchmark setting
+    private void init() {
+        // thread number;
+        if (mSingleThread) {
+            mThreadNum = 1;
+        } else if (mThreadNum == 0) {
+            mThreadNum = Runtime.getRuntime().availableProcessors();
+        }
+        if (mThreadNum == 0) {
+            mThreadNum = 1;
+        }
+
+        if (mSizeDistribution == null) {
+            mSizeDistribution = new float[]{0.0436f,0.5465f,0.2103f,0.1499f,
+                    0.0275f,0.0125f,0.0097f};
+        }
+        if (mLifetime == null) {
+            mLifetime = new float[][] {
+                    {0.0865f,0.5404f,0.2887f,0.0865f},
+                    {0.0469f,0.7724f,0.1460f,0.0346f},
+                    {0.1154f,0.5982f,0.1880f,0.0984f},
+                    {0.0662f,0.7851f,0.1077f,0.0411f},
+                    {0.0520f,0.8778f,0.0503f,0.0198f},
+                    {0.1628f,0.7137f,0.0821f,0.0414f},
+                    {0.0923f,0.7117f,0.1769f,0.0192f} // large object lifetime
+            };
+        }
+
+        if (mLargeObjectDistribution == null) {
+            mLargeObjectDistribution = new float[]{0.9f, 0.07f, 0.02f, 0.01f};
+        }
+
+        if (mTotalAllocateSize == 0) {
+            mTotalAllocateSize = 100 * 1024 * 1024;
+        }
+        mTotalAllocSizePerThread = mTotalAllocateSize / mThreadNum;
+
+        if (mBucketSize == 0) {
+            mBucketSize = 1 * 1024 * 1024;
+        }
+
+        if (mLargeObjectSize == 0) {
+            mLargeObjectSize = 12 * 1024;
+        }
+
+        Log.i(mTag, "Allocate Size: " + (mTotalAllocateSize / 1024) + " kB");
+        Log.i(mTag, "BucketSize: " + (mBucketSize / 1024) + " kB");
+        Log.i(mTag, "Large object size: " + (mLargeObjectSize / 1024) + " kB");
+        Log.i(mTag, "Single Thread: " + mSingleThread);
+        Log.i(mTag, "Thread number: " + mThreadNum);
+        Log.i(mTag, "Stress test part iterates " + mIterNum + " times");
+
+        String curDate = DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());
+        try {
+            fileOutput = new FileWriter("/sdcard/AndroidGCTest-result.txt", true);
+            fileOutput.append("\n\n" + curDate);
+
+            fileOutput.append("\nWorkload configuration:");
+            fileOutput.append("\n\tAllocate Size: " + (mTotalAllocateSize / 1024) + " kB");
+            fileOutput.append("\n\tBucketSize: " + (mBucketSize / 1024) + " kB");
+            fileOutput.append("\n\tLarge object size: " + (mLargeObjectSize / 1024) + " kB");
+            fileOutput.append("\n\tThread mode: "
+                    + (mSingleThread? "Single-Thread" : "Multi-Thread"));
+            fileOutput.append("\n\tThread number: " + mThreadNum);
+            fileOutput.append("\n\tStress test part iterates " + mIterNum + " times");
+        } catch (IOException e) {
+            Log.i(mTag, "Cannot open /sdcard/AndroidGCTest-result.txt" + e.getMessage());
+        }
+
+        int smallObjectSize, largeObjectSize;
+        largeObjectSize = (int)(mTotalAllocSizePerThread * mSizeDistribution[OBJECT_LARGE_BYTE]);
+        smallObjectSize = mTotalAllocSizePerThread - largeObjectSize;
+
+        float[] countDistr = new float[OBJECT_LARGE_BYTE];
+        float nodeSize = 0.0f;
+        int[] sizeThreshold = new int[OBJECT_LARGE_BYTE];
+        int lifetimeLen = mLifetime[0].length;
+        int[][] lifetimeThreshold = new int[OBJECT_LARGE_BYTE][lifetimeLen];
+        float sum = 0.0f;
+        for (int i = 0; i < OBJECT_LARGE_BYTE; i++) {
+            countDistr[i] = mSizeDistribution[i]
+                    / (1 - mSizeDistribution[OBJECT_LARGE_BYTE]) / mObjectSize[i];
+            sum += countDistr[i];
+        }
+
+        mLongLiveSmallObjectSize = 0;
+        float sum1 = 0.0f;
+        for (int i = 0; i < OBJECT_LARGE_BYTE; i++) {
+            sum1 += countDistr[i];
+            sizeThreshold[i] = (int)(sum1 * 1000 / sum + 0.5);
+            nodeSize += mObjectSize[i] * countDistr[i] / sum;
+
+            float sum2 = 0.0f;
+            for (int j = 1; j < lifetimeLen; j++) {
+                sum2 += mLifetime[i][j];
+                lifetimeThreshold[i][j-1] = (int)(sum2 * 1000 + 0.5);
+            }
+            lifetimeThreshold[i][lifetimeLen - 1] = 1000;
+
+            mLongLiveSmallObjectSize += mTotalAllocSizePerThread * mSizeDistribution[i]
+                    * mLifetime[i][0];
+        }
+        sizeThreshold[OBJECT_512_BYTE] = 1000;
+
+
+        mShortLiveTreeCount = (int)(smallObjectSize / mBucketSize + 0.5);
+        mTotalNodeCount = (int)(mBucketSize / nodeSize * 1.11);
+
+        mObjectSizeRandom = new byte[mThreadNum][mTotalNodeCount];
+        mLifetimeRandom = new byte[mThreadNum][mTotalNodeCount];
+        for (int i = 0; i < mThreadNum; i++) {
+            Random r_size = new Random(i);
+            Random r_lifetime = new Random(i + mThreadNum);
+            for (int j = 0; j < mTotalNodeCount; j++) {
+                int vs = r_size.nextInt(1000);
+                int vl = r_lifetime.nextInt(1000);
+                for (int k = 0; k < OBJECT_LARGE_BYTE; k++) {
+                    if (vs < sizeThreshold[k]) {
+                        mObjectSizeRandom[i][j] = (byte)(OBJECT_16_BYTE + k);
+                        for (int l = 0; l < lifetimeLen; l++) {
+                            if (vl < lifetimeThreshold[k][l]) {
+                                mLifetimeRandom[i][j] = (byte)l;
+                                break;
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        mLongLiveLargeObjectSize = (int)(largeObjectSize * mLifetime[OBJECT_LARGE_BYTE][0]);
+        mDieNumLargeObject = new int[4][lifetimeLen - 1];
+        mLargeArrayInter = new int[4];
+        mLargeArrayLength = new int[4];
+        mLargeArrayNum = new int[4];
+        for (int i = 0; i < 4; i++) {
+            mLargeArrayLength[i] = (int)((largeObjectSize * mLargeObjectDistribution[i]
+                    / mLargeObjectSize) + 0.5);
+            if (mLargeArrayLength[i] == 0) {
+                mLargeArrayInter[i] = mShortLiveTreeCount + 1;
+                mLargeArrayNum[i] = 0;
+                continue;
+            }
+            if (mShortLiveTreeCount > mLargeArrayLength[i]) {
+                mLargeArrayInter[i] = mShortLiveTreeCount / mLargeArrayLength[i];
+                mLargeArrayNum[i] = 1;
+                mLargeArrayLength[i] = mShortLiveTreeCount/mLargeArrayInter[i] + 1;
+            } else {
+                mLargeArrayInter[i] = 1;
+                mLargeArrayNum[i] = (int)(mLargeArrayLength[i]/(float)mShortLiveTreeCount + 0.5);
+                mLargeArrayLength[i] = mLargeArrayNum[i] * mShortLiveTreeCount;
+            }
+
+            sum = 0.0f;
+            for (int j = 1; j < lifetimeLen; j++) {
+                sum += mLifetime[OBJECT_LARGE_BYTE][j];
+                mDieNumLargeObject[i][j-1] = (int)(mLargeArrayNum[i] * sum);
+            }
+        }
+
+        Log.i(mTag, "init done");
+    }
+
+    private void clearInitData() {
+        Log.i(mTag, "clear auxiliary data to run workload");
+        mLifetime = null;
+        mLargeObjectDistribution = null;
+        mSizeDistribution = null;
+        mObjectSizeRandom = null;
+        mLifetimeRandom = null;
+        mLargeArrayInter = null;
+        mLargeArrayLength = null;
+        mLargeArrayNum = null;
+        mDieNumLargeObject = null;
+        Runtime.getRuntime().runFinalization();
+        Runtime.getRuntime().gc();
+    }
+
+    AndroidGCTestMain() {
+        init();
+    }
+    AndroidGCTestMain(MainActivity activity, int heapSize, int bucketSize, int largeObjectSize,
+                      float[]sizeDistr, float[][] lifetimeDistr, float[] largeObjectSizeDist,
+                      boolean singleThread, int thread_num, int exeTime) {
+        mActivity = activity;
+        mTotalAllocateSize = heapSize * 1024 * 1024;
+        mBucketSize = bucketSize * 1024 * 1024;
+        mLargeObjectSize = largeObjectSize * 1024;
+        mSizeDistribution = sizeDistr;
+        mLifetime = lifetimeDistr;
+        mLargeObjectDistribution = largeObjectSizeDist;
+        mSingleThread = singleThread;
+        mThreadNum = mSingleThread? 1 : thread_num;
+        mIterNum = exeTime > 0 ? exeTime : 100;
+        init();
+    }
+
+    private void freeArrays(byte[][] byteArray, char[][] charArray, int[][] intArray,
+                            long[][] longArray, int[] arrayIdx, int treeCount) {
+        int len = mDieNumLargeObject[0].length;
+        int died, release, phase;
+
+        phase = treeCount % mLargeArrayInter[0];
+        if (byteArray != null && phase <= len) {
+            int curIdx = arrayIdx[0] - mLargeArrayNum[0];
+            while (curIdx >= 0 && phase <= len) {
+                if (phase == 0)
+                    died = 0;
+                else
+                    died = mDieNumLargeObject[0][phase - 1];
+                if (phase == len) {
+                    if (byteArray[curIdx + died] != null) {
+                        for (int i = died; i < mLargeArrayNum[0]; i++)
+                            byteArray[curIdx + i] = null;
+                    }
+                    break;
+                }
+                release = mDieNumLargeObject[0][phase];
+                for (int i = died; i < release; i++) {
+                    if (i >= mLargeArrayNum[0])
+                        break;
+                    byteArray[curIdx + i] = null;
+                }
+                curIdx -= mLargeArrayNum[0];
+                phase += mLargeArrayInter[0];
+            }
+        }
+
+        phase = treeCount % mLargeArrayInter[1];
+        if (charArray != null && phase < mLargeArrayNum[1]) {
+            int curIdx = arrayIdx[1] - mLargeArrayNum[1];
+            while (curIdx >= 0 && phase <= len) {
+                if (phase == 0)
+                    died = 0;
+                else
+                    died = mDieNumLargeObject[1][phase - 1];
+                if (phase == len) {
+                    if (charArray[curIdx + died] != null) {
+                        for (int i = died; i < mLargeArrayNum[1]; i++)
+                            charArray[curIdx + i] = null;
+                    }
+                    break;
+                }
+                release = mDieNumLargeObject[1][phase];
+                for (int i = died; i < release; i++) {
+                    if (i >= mLargeArrayNum[1])
+                        break;
+                    charArray[curIdx + i] = null;
+                }
+                curIdx -= mLargeArrayNum[1];
+                phase += mLargeArrayInter[1];
+            }
+        }
+
+        phase = treeCount % mLargeArrayInter[2];
+        if (intArray != null && phase < mLargeArrayNum[2]) {
+            int curIdx = arrayIdx[2] - mLargeArrayNum[2];
+            while (curIdx >= 0 && phase <= len) {
+                if (phase == 0)
+                    died = 0;
+                else
+                    died = mDieNumLargeObject[2][phase - 1];
+                if (phase == len) {
+                    if (intArray[curIdx + died] != null) {
+                        for (int i = died; i < mLargeArrayNum[2]; i++)
+                            intArray[curIdx + i] = null;
+                    }
+                    break;
+                }
+                release = mDieNumLargeObject[2][phase];
+                for (int i = died; i < release; i++) {
+                    if (i >= mLargeArrayNum[2])
+                        break;
+                    intArray[curIdx + i] = null;
+                }
+                curIdx -= mLargeArrayNum[2];
+                phase += mLargeArrayInter[2];
+            }
+        }
+
+        phase = treeCount % mLargeArrayInter[3];
+        if (longArray != null && phase < mLargeArrayNum[3]) {
+            int curIdx = arrayIdx[3] - mLargeArrayNum[3];
+            while (curIdx >= 0 && phase <= len) {
+                if (phase == 0)
+                    died = 0;
+                else
+                    died = mDieNumLargeObject[3][phase - 1];
+                if (phase == len) {
+                    if (longArray[curIdx + died] != null) {
+                        for (int i = died; i < mLargeArrayNum[3]; i++)
+                            longArray[curIdx + i] = null;
+                    }
+                    break;
+                }
+                release = mDieNumLargeObject[3][phase];
+                for (int i = died; i < release; i++) {
+                    if (i >= mLargeArrayNum[3])
+                        break;
+                    longArray[curIdx + i] = null;
+                }
+                curIdx -= mLargeArrayNum[3];
+                phase += mLargeArrayInter[3];
+            }
+        }
+    }
+
+    private void makeTreesLongLive(TreeNode[] trees, int allocSize, int myId, int[] nodeCount) {
+        while (true) {
+            if (allocSize <= 0) {
+                trees = null;
+                return;
+            }
+
+            int len = trees.length;
+            TreeNode[] nextTrees = new TreeNode[len*2];
+            byte random;
+            for (int i = 0; i < len; i++) {
+                TreeNode node = null;
+                random = mObjectSizeRandom[myId][nodeCount[0]];
+                switch (random) {
+                    case OBJECT_16_BYTE:
+                        node = new TreeNode();
+                        break;
+                    case OBJECT_32_BYTE:
+                        node = new TreeNode32();
+                        break;
+                    case OBJECT_64_BYTE:
+                        node = new TreeNode64();
+                        break;
+                    case OBJECT_128_BYTE:
+                        node = new TreeNode128();
+                        break;
+                    case OBJECT_256_BYTE:
+                        node = new TreeNode256();
+                        break;
+                    case OBJECT_512_BYTE:
+                        node = new TreeNode512();
+                        break;
+                }
+                trees[i].left = node;
+                nextTrees[2 * i] = node;
+                allocSize -= mObjectSize[random];
+                nodeCount[0]++;
+                if (nodeCount[0] == mTotalNodeCount)
+                    nodeCount[0] = 0;
+
+                random = mObjectSizeRandom[myId][nodeCount[0]];
+                switch (random) {
+                    case OBJECT_16_BYTE:
+                        node = new TreeNode();
+                        break;
+                    case OBJECT_32_BYTE:
+                        node = new TreeNode32();
+                        break;
+                    case OBJECT_64_BYTE:
+                        node = new TreeNode64();
+                        break;
+                    case OBJECT_128_BYTE:
+                        node = new TreeNode128();
+                        break;
+                    case OBJECT_256_BYTE:
+                        node = new TreeNode256();
+                        break;
+                    case OBJECT_512_BYTE:
+                        node = new TreeNode512();
+                        break;
+                }
+                trees[i].right = node;
+                nextTrees[2*i + 1] = node;
+                allocSize -= mObjectSize[random];
+                nodeCount[0]++;
+                if (nodeCount[0] == mTotalNodeCount)
+                    nodeCount[0] = 0;
+
+                if (allocSize <= 0) {
+                    trees = null;
+                    break;
+                }
+            }
+            trees = null;
+            trees = nextTrees;
+        }
+    }
+
+    private void makeTreesShortLive(TreeNode[] trees, int allocSize, int myId, int[] nodeCount) {
+        int lifetimeLen = mLifetime[0].length;
+        int[] curTreeIdx = new int[lifetimeLen];
+        int[] nextTreeIdx = new int[lifetimeLen];
+        TreeNode[][] curTrees = new TreeNode[lifetimeLen][1];
+        TreeNode[][] nextTrees = new TreeNode[lifetimeLen][];
+        for (int i = 0; i < lifetimeLen; i++) {
+            curTrees[i][0] = trees[i];
+            curTreeIdx[i] = 0;
+        }
+
+        while (true) {
+            if (allocSize <= 0) {
+                trees = null;
+                return;
+            }
+
+            byte rs = mObjectSizeRandom[myId][nodeCount[0]];
+            TreeNode node = null;
+            switch (rs) {
+                case OBJECT_16_BYTE:
+                    node = new TreeNode();
+                    break;
+                case OBJECT_32_BYTE:
+                    node = new TreeNode32();
+                    break;
+                case OBJECT_64_BYTE:
+                    node = new TreeNode64();
+                    break;
+                case OBJECT_128_BYTE:
+                    node = new TreeNode128();
+                    break;
+                case OBJECT_256_BYTE:
+                    node = new TreeNode256();
+                    break;
+                case OBJECT_512_BYTE:
+                    node = new TreeNode512();
+                    break;
+            }
+
+            byte rl = mLifetimeRandom[myId][nodeCount[0]];
+            if (nextTrees[rl] == null) {
+                nextTrees[rl] = new TreeNode[curTrees[rl].length << 1];
+                nextTreeIdx[rl] = 0;
+                nextTrees[rl][0] = node;
+            } else {
+                nextTrees[rl][++nextTreeIdx[rl]] = node;
+            }
+            TreeNode parent = curTrees[rl][curTreeIdx[rl]];
+            if (parent.left == null) {
+                parent.left = node;
+            } else {
+                parent.right = node;
+                curTreeIdx[rl]++;
+                if (curTreeIdx[rl] == curTrees[rl].length) {
+                    curTrees[rl] = nextTrees[rl];
+                    nextTrees[rl] = null;
+                    curTreeIdx[rl] = 0;
+                }
+            }
+
+            allocSize -= mObjectSize[rs];
+            nodeCount[0]++;
+            if (nodeCount[0] == mTotalNodeCount) nodeCount[0] = 0;
+        }
+    }
+
+    public boolean allocTrace(int myId) throws OutOfMemoryError {
+        // long-lived data
+        Log.i(mTag, "Thread-" + myId + " ----- Build long lived trees -----");
+
+        LivedLink longLiveTreeLink = new LivedLink();
+        TreeNode[] trees = new TreeNode[mTreeCountParallel];
+
+        int[] nodeCount = new int[]{0};
+        for (int i = 0; i < mTreeCountParallel; i++) {
+            TreeNode node = new TreeNode();
+            longLiveTreeLink.insertNode(node);
+            trees[i] = node;
+        }
+
+        makeTreesLongLive(trees, mLongLiveSmallObjectSize, myId, nodeCount);
+
+        trees = null;
+
+        Log.i(mTag, "Thread-" + myId + " ----- Build long lived byte array -----");
+        int longLiveArrayCount = (int)(mLongLiveLargeObjectSize / mLargeObjectSize + 0.5);
+        if (longLiveArrayCount <= 0)
+            longLiveArrayCount = 1;
+        byte[][] longLiveByteArrays = new byte[longLiveArrayCount][];
+        for (int i = 0; i < longLiveArrayCount; i++) {
+            longLiveByteArrays[i] = new byte[mLargeObjectSize];
+            for (int j = 0; j < mLargeObjectSize; j+=100)
+                longLiveByteArrays[i][j] = (byte) 0xff;
+        }
+
+        // stress test
+        Log.i(mTag, "Thread-" + myId + " ----- Stress test -----");
+        Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
+
+        int lifetimeLen = mLifetime[0].length;
+        TreeNode[][] shortLiveTrees = new TreeNode[lifetimeLen][lifetimeLen];
+
+        byte[][] shortLiveByteArray = null;
+        char[][] shortLiveCharArray = null;
+        int[][] shortLiveIntArray = null;
+        long[][] shortLiveLongArray = null;
+
+        nodeCount[0] = 0;
+        int round = 0;
+
+        for (int iter = 0; iter < mIterNum; iter++) {
+            if (mOutOfMemory)
+                break;
+            int[] allocIdx = new int[]{0, 0, 0, 0};
+
+            if (mLargeArrayLength[0] != 0)
+                shortLiveByteArray = new byte[mLargeArrayLength[0]][];
+            if (mLargeArrayLength[1] != 0)
+                shortLiveCharArray = new char[mLargeArrayLength[1]][];
+            if (mLargeArrayLength[2] != 0)
+                shortLiveIntArray = new int[mLargeArrayLength[2]][];
+            if (mLargeArrayLength[3] != 0)
+                shortLiveLongArray = new long[mLargeArrayLength[3]][];
+
+            int treeCount = 0;
+            while (treeCount < mShortLiveTreeCount) {
+                int treesIdx = round % lifetimeLen;
+                round++;
+                for (int i = 0; i < lifetimeLen; i++) {
+                    TreeNode node = new TreeNode();
+                    shortLiveTrees[treesIdx][i] = node;
+                }
+                makeTreesShortLive(shortLiveTrees[treesIdx], mBucketSize, myId, nodeCount);
+
+                for (int i = 0; i < lifetimeLen; i++) {
+                    int idx = (treesIdx - i + lifetimeLen) % lifetimeLen;
+                    shortLiveTrees[idx][i] = null;
+                }
+
+                if ((mLargeArrayLength[0] > 0) && ((treeCount % mLargeArrayInter[0]) == 0)) {
+                    for (int n = 0; n < mLargeArrayNum[0]; n++)
+                        shortLiveByteArray[allocIdx[0] + n] = new byte[mLargeObjectSize];
+                    allocIdx[0] += mLargeArrayNum[0];
+                }
+
+                if ((mLargeArrayLength[1] > 0) && ((treeCount % mLargeArrayInter[1]) == 0)) {
+                    for (int n = 0; n < mLargeArrayNum[1]; n++)
+                        shortLiveCharArray[allocIdx[1] + n] = new char[mLargeObjectSize/2];
+                    allocIdx[1] += mLargeArrayNum[1];
+                }
+
+                if ((mLargeArrayLength[2] > 0) && ((treeCount % mLargeArrayInter[2]) == 0)) {
+                    for (int n = 0; n < mLargeArrayNum[2]; n++)
+                        shortLiveIntArray[allocIdx[2] + n] = new int[mLargeObjectSize/4];
+                    allocIdx[2] += mLargeArrayNum[2];
+                }
+
+                if ((mLargeArrayLength[3] > 0) && ((treeCount % mLargeArrayInter[3]) == 0)) {
+                    for (int n = 0; n < mLargeArrayNum[3]; n++)
+                        shortLiveLongArray[allocIdx[3] + n] = new long[mLargeObjectSize/8];
+                    allocIdx[3] += mLargeArrayNum[3];
+                }
+
+                freeArrays(shortLiveByteArray, shortLiveCharArray, shortLiveIntArray,
+                        shortLiveLongArray, allocIdx, treeCount);
+
+                treeCount++;
+            }
+
+            if (myId == 0) {
+                Debug.getMemoryInfo(memInfo);
+                mHeapFootprint[iter] = memInfo.dalvikPss;
+                if (getRuntimeStatMethod != null)
+                    mHeapBytesAllocated[iter] = (getRuntimeStat("art.gc.bytes-allocated")
+                            - getRuntimeStat("art.gc.bytes-freed")) / 1024;
+                else
+                    mHeapBytesAllocated[iter] = (Runtime.getRuntime().totalMemory()
+                            - Runtime.getRuntime().freeMemory()) / 1024;
+
+                Message m = mActivity.getHandler().obtainMessage(MainActivity.BenchmarkProgress);
+                m.arg1 = iter + 1;
+                mActivity.getHandler().sendMessage(m);
+            }
+        }
+
+        if (longLiveTreeLink.treeHead.treeNode != null
+                && longLiveByteArrays[0][100] == (byte)0xff
+                && longLiveByteArrays[longLiveArrayCount - 1][200] == (byte)0xff)
+            return true;
+        return false;
+    }
+
+    class BenchThread extends Thread {
+        private  int myId;
+        BenchThread (int id) {
+            super();
+            myId = id;
+        }
+        public void run() {
+            mElapseTime[myId] = 0;
+            long start = System.currentTimeMillis();
+            try {
+                if (!allocTrace(myId))
+                    Log.i(mTag, "Error in thread-" + myId);
+            } catch (OutOfMemoryError e) {
+                mOutOfMemory = true;
+                Log.i(mTag, "Thread-" + myId + " meets OutOfMemory");
+
+                Message m = mActivity.getHandler().obtainMessage(
+                        MainActivity.BenchmarkOutOfMemoryError);
+                m.arg1 = myId;
+                mActivity.getHandler().sendMessage(m);
+            }
+            mElapseTime[myId] = System.currentTimeMillis() - start;
+        }
+    }
+
+    public void start() {
+        if (getRuntimeStatMethod == null) {
+            try {
+                Class c = Class.forName("android.os.Debug");
+                getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class);
+            } catch (ClassNotFoundException e) {
+                Log.w(mTag, "Cannot find android.os.Debug class");
+            } catch (NoSuchMethodException e) {
+                Log.w(mTag, "No getRuntimeStat method in android.os.Debug");
+            }
+        }
+        mElapseTime = new long[mThreadNum];
+        mHeapFootprint = new int[mIterNum];
+        mHeapBytesAllocated = new long[mIterNum];
+        isArt = false;
+        String vmVersion = System.getProperty("java.vm.version");
+        isArt = vmVersion != null && vmVersion.startsWith("2");
+        String androidVersion = Build.VERSION.RELEASE;
+        String deviceName = Build.MODEL;
+        String deviceDesc = deviceName + "/" + "android-" + androidVersion
+                + ", runtime: " + (isArt? "ART" :"Dalvik");
+        mTotalGcCount = getRuntimeStat("art.gc.gc-count");
+        mTotalGcTime = getRuntimeStat("art.gc.gc-time");
+        mTotalBlockingGcCount = getRuntimeStat("art.gc.blocking-gc-count");
+        mTotalBlockingGcTime = getRuntimeStat("art.gc.blocking-gc-time");
+        if (isArt)
+            mGcCauseCount = new int[]{0, 0, 0, 0, 0, 0, 0, 0};
+        else
+            mGcCauseCount = new int[]{0, 0, 0, 0};
+
+        mWorkloadComplete = false;
+        clearLogcat();
+        Thread logcat = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                readLogcat();
+            }
+        });
+        logcat.start();
+
+        mOutOfMemory = false;
+        mTestThreads = new BenchThread[mThreadNum];
+        for (int i = 1; i < mThreadNum; i++) {
+            mTestThreads[i] = new BenchThread(i);
+            mTestThreads[i].start();
+        }
+
+        mElapseTime[0] = 0;
+        long start = System.currentTimeMillis();
+        try {
+            if (!allocTrace(0))
+                Log.i(mTag, "Error in thread-0");
+        } catch (OutOfMemoryError e) {
+            mOutOfMemory = true;
+            Log.i(mTag, "Thread-0 meets OutOfMemory");
+            Message m = mActivity.getHandler().obtainMessage(
+                    MainActivity.BenchmarkOutOfMemoryError);
+            m.arg1 = 0;
+            mActivity.getHandler().sendMessage(m);
+        }
+        mElapseTime[0] = System.currentTimeMillis() - start;
+
+        for (int i = 1; i < mThreadNum; i++) {
+            try {
+                mTestThreads[i].join();
+            } catch (InterruptedException e) {
+                Log.i(mTag, "Waiting thread " + i + " finish interrupted by "
+                        + e.getLocalizedMessage());
+            }
+        }
+        SystemClock.sleep(1000);
+        mWorkloadComplete = true;
+        Runtime.getRuntime().runFinalization();
+        Runtime.getRuntime().gc();
+        try {
+            logcat.join();
+        } catch (InterruptedException e) {
+            Log.i(mTag, "Waiting logcat finish interrupted by " + e.getLocalizedMessage());
+        }
+        if (mOutOfMemory) {
+            try {
+                if (fileOutput != null) {
+                    fileOutput.append("\nOutOfMemory! Please config proifle or "
+                            + "Java Runtime and run again!\n");
+                    fileOutput.flush();
+                    fileOutput.close();
+                }
+            } catch (IOException e) {
+                Log.i(mTag, "Cannot write to /sdcard/AndroidGCTest-result.txt"
+                        + e.getMessage());
+            }
+        } else {
+            mTotalGcCount = getRuntimeStat("art.gc.gc-count") - mTotalGcCount;
+            mTotalGcTime = getRuntimeStat("art.gc.gc-time") - mTotalGcTime;
+            mTotalBlockingGcCount = getRuntimeStat("art.gc.blocking-gc-count")
+                    - mTotalBlockingGcCount;
+            mTotalBlockingGcTime = getRuntimeStat("art.gc.blocking-gc-time")
+                    - mTotalBlockingGcTime;
+            long maxTime = 0;
+            String completionTime = "";
+            for (int i = 0; i < mThreadNum; i++) {
+                if (maxTime < mElapseTime[i])
+                    maxTime = mElapseTime[i];
+                Log.i(mTag, "Thread-" + i + " completion time: "
+                        + String.valueOf((mElapseTime[i])) + "ms");
+                completionTime += "Thread-" + i + " completion time: "
+                        + String.valueOf((mElapseTime[i])) + "ms\n";
+            }
+            String totalTime = "AndroidGCTest is done by " + mThreadNum
+                    + " threads. Completion time is " + maxTime + "ms";
+            Log.i(mTag, totalTime);
+            completionTime += totalTime + "\n";
+            String gcDesc = "Total GC count: " + mTotalGcCount;
+            gcDesc += "\nTotal GC time: " + mTotalGcTime + "ms";
+            gcDesc += "\nTotal Blocking GC count: " + mTotalBlockingGcCount;
+            gcDesc += "\nTotal Blocking GC time: " + mTotalBlockingGcTime + "ms";
+            Log.i(mTag, "Total GC count: " + mTotalGcCount);
+            Log.i(mTag, "Total GC time: " + mTotalGcTime + "ms");
+            Log.i(mTag, "Total Blocking GC count: " + mTotalBlockingGcCount);
+            Log.i(mTag, "Total Blocking GC time: " + mTotalBlockingGcTime + "ms");
+            String pauseDesc = "";
+            String[] causes;
+            if (isArt)
+                causes = GC_CAUSE_ART;
+            else
+                causes = GC_CAUSE_DALVIK;
+            for (int i = 0; i < causes.length; i++) {
+                Log.i(mTag, mGcCauseCount[i] + " GCs for " + causes[i] + " from logcat");
+                gcDesc += "\n" + mGcCauseCount[i] + " GCs for " + causes[i] + " from logcat";
+            }
+            for (int i = 0; i < mGcPauseTime.length; i++) {
+                String gc_time = "GC-" + i + ": " + mGcCause[i] + ", pause "
+                        + mGcPauseTime[i] + "ms, total " + mGcTotalTime[i] + "ms";
+                pauseDesc += "\n" + gc_time;
+                Log.i(mTag, gc_time);
+            }
+            try {
+                if (fileOutput != null) {
+                    fileOutput.append("\n" + "Device config:\n\t" + deviceDesc);
+                    fileOutput.append("\n" + completionTime);
+                    fileOutput.append("\n" + "Heap status after each iteration "
+                            + "(footprint, bytes allocated):\n");
+                    for (int j = 0; j < mIterNum; j++)
+                        fileOutput.append("\t" + mHeapFootprint[j] + " kB, "
+                                + mHeapBytesAllocated[j] + " kB\n");
+                    fileOutput.append(gcDesc);
+                    fileOutput.append(pauseDesc);
+                    fileOutput.flush();
+                    fileOutput.close();
+                }
+            } catch (IOException e) {
+                Log.i(mTag, "Cannot write to /sdcard/AndroidGCTest-result.txt"
+                        + e.getMessage());
+            }
+            if (mActivity != null) {
+                Message m = mActivity.getHandler().obtainMessage(
+                        MainActivity.BenchmarkDone);
+                Bundle b = new Bundle();
+                b.putBoolean(ResultActivity.KEY_VM_TYPE, isArt);
+                b.putString("device", deviceDesc);
+                b.putLongArray(ResultActivity.KEY_THREAD_COMPLETE_TIME, mElapseTime);
+                b.putLong(ResultActivity.KEY_WORKLOAD_COMPLETE_TIME, maxTime);
+                b.putLongArray(ResultActivity.KEY_BYTES_LIVING, mHeapBytesAllocated);
+                b.putIntArray(ResultActivity.KEY_HEAP_FOOTPRINT, mHeapFootprint);
+                b.putFloatArray(ResultActivity.KEY_GC_PAUSE_TIME, mGcPauseTime);
+                b.putFloatArray(ResultActivity.KEY_GC_COMPLETION_TIME, mGcTotalTime);
+                b.putStringArray(ResultActivity.KEY_GC_CAUSE, mGcCause);
+                m.setData(b);
+                mActivity.getHandler().sendMessage(m);
+            }
+        }
+        mElapseTime = null;
+        mHeapFootprint = null;
+        mHeapBytesAllocated = null;
+        mGcPauseTime = null;
+        mGcTotalTime = null;
+        mGcCause = null;
+
+        clearInitData();
+    }
+
+    public void stop() {
+    }
+
+    private void clearLogcat() {
+        try {
+            Process process = Runtime.getRuntime().exec("logcat -c");
+            try {
+                process.waitFor();
+            } catch (InterruptedException e) {
+                Log.e(mTag, "Clear logcat fails, interrupted by " + e.getLocalizedMessage());
+            }
+            Log.i(mTag, "Clear logcat before workload running");
+        } catch (Exception e) {
+            Log.e(mTag, "Clear logcat fails, " + e.getLocalizedMessage());
+        }
+    }
+
+    private void readLogcat() {
+        String cmd;
+        if (isArt)
+            cmd = "logcat -s art";
+        else
+            cmd = "logcat -s dalvikvm";
+        ArrayList<Float> gcPauseTimeList = new ArrayList<Float>();
+        ArrayList<Float> gcTotalTimeList = new ArrayList<Float>();
+        ArrayList<String> gcCauseList = new ArrayList<String>();
+        int loggerGcCount = 0;
+        try {
+            Process process = Runtime.getRuntime().exec(cmd);
+            InputStream inStream = process.getInputStream();
+            InputStream errorStream = process.getErrorStream();
+            int error = errorStream.available();
+            if (error > 0) {
+                byte[] errorMsg = new byte[error];
+                errorStream.read(errorMsg);
+                Log.i(mTag, "executing logcat return error message: " + new String(errorMsg));
+            }
+            BufferedReader inReader = new BufferedReader(new InputStreamReader(inStream));
+            String line;
+            while (!mWorkloadComplete && (line = inReader.readLine()) != null) {
+                if (mWorkloadComplete)
+                    break;
+
+                int idx = line.indexOf(": ");
+                if (idx == -1)
+                    continue;
+                line = line.substring(idx+2);
+                boolean isGCLog = false;
+                String gcCause = "";
+                if (isArt) {
+                    for (int i = 0; i < GC_CAUSE_ART.length; i++) {
+                        if ((line.contains("mark sweep") || line.contains("marksweep")
+                                || line.contains("mark compact"))
+                                && line.startsWith(GC_CAUSE_ART[i])) {
+                            isGCLog = true;
+                            mGcCauseCount[i]++;
+                            idx = line.indexOf(" GC ");
+                            if (idx > 0)
+                                gcCause = line.substring(0, idx);
+                            else {
+                                Log.i(mTag, "Error: cannot find ' GC ' from this log, " + line);
+                                continue;
+                            }
+                            break;
+                        }
+                    }
+                } else {
+                    for (int i = 0; i < GC_CAUSE_DALVIK.length; i++) {
+                        if (line.startsWith(GC_CAUSE_DALVIK[i])) {
+                            isGCLog = true;
+                            mGcCauseCount[i]++;
+                            gcCause = GC_CAUSE_DALVIK[i];
+                            break;
+                        }
+                    }
+                }
+                if (!isGCLog)
+                    continue;
+                loggerGcCount++;
+
+                int idx0 = line.indexOf("paused ");
+                int idx1 = line.indexOf(" total ");
+                if (idx0 == -1 || idx1 == -1) {
+                    Log.i(mTag, "Cannot find pause or total completion time from the GC log "
+                            + line);
+                    continue;
+                }
+
+                String pauseTimeStr = line.substring(idx0+7, idx1);
+                String totalTimeStr = line.substring(idx1+7);
+                float completeTime = 0.0f;
+                float pauseTime = 0.0f;
+                idx = totalTimeStr.indexOf("ms");
+                int timeToSec = 1000;
+                if (idx == -1) {
+                    idx = totalTimeStr.indexOf("us");
+                    timeToSec = 1000000;
+                }
+                if (idx == -1) {
+                    idx = totalTimeStr.indexOf("s");
+                    timeToSec = 1;
+                }
+                if (idx == -1) {
+                    Log.i(mTag, "Cannot identify total complete time format, " + line);
+                    continue;
+                }
+                completeTime = Float.parseFloat(totalTimeStr.substring(0, idx)) * 1000 / timeToSec;
+                String[] pauseTimes = pauseTimeStr.split("\\+\\s*|,\\s*");
+                for (int i = 0; i < pauseTimes.length; i++) {
+                    String tmp = pauseTimes[i];
+                    idx = tmp.indexOf("ms");
+                    if (idx > 0) {
+                        pauseTime += Float.parseFloat(tmp.substring(0, idx));
+                    } else {
+                        idx = tmp.indexOf("us");
+                        if (idx > 0) {
+                            pauseTime += Float.parseFloat(tmp.substring(0, idx))/1000;
+                        } else {
+                            Log.i(mTag, "Cannot identify pause time format, " + line);
+                            continue;
+                        }
+                    }
+                }
+                gcPauseTimeList.add(pauseTime);
+                gcTotalTimeList.add(completeTime);
+                gcCauseList.add(gcCause);
+            }
+            errorStream.close();
+            inReader.close();
+            process.destroy();
+            Log.i(mTag, "workload complete, stop reading logcat");
+            mGcTotalTime = new float[loggerGcCount];
+            mGcPauseTime = new float[loggerGcCount];
+            mGcCause = new String[loggerGcCount];
+            for (int i = 0; i < gcPauseTimeList.size(); i++) {
+                mGcTotalTime[i] = gcTotalTimeList.get(i).floatValue();
+                mGcPauseTime[i] = gcPauseTimeList.get(i).floatValue();
+                mGcCause[i] = gcCauseList.get(i);
+            }
+        } catch (OutOfMemoryError e) {
+            mOutOfMemory = true;
+            Log.i(mTag, "logcat thread meets OutOfMemory");
+            Message m = mActivity.getHandler().obtainMessage(
+                    MainActivity.BenchmarkOutOfMemoryError);
+            m.arg1 = -1;
+            mActivity.getHandler().sendMessage(m);
+        } catch (Exception e) {
+            Log.i(mTag, "Cannot run logcat " + e.getMessage());
+        }
+        gcPauseTimeList.clear();
+        gcPauseTimeList = null;
+        gcTotalTimeList.clear();
+        gcTotalTimeList = null;
+        gcCauseList.clear();
+        gcCauseList = null;
+        Log.i(mTag, "logcat done");
+    }
+
+    private static Method getRuntimeStatMethod = null;
+    private long getRuntimeStat(String statName) {
+        if (getRuntimeStatMethod == null) {
+            return 0;
+        }
+        String valueStr;
+        try {
+            valueStr = (String) getRuntimeStatMethod.invoke(null, statName);
+        } catch (Exception e) {
+            Log.w(mTag, "Failed to invoke getRuntimeStat");
+            return 0;
+        }
+        if (valueStr != null)
+            return Long.parseLong(valueStr);
+        return 0;
+    }
+}
+
diff --git a/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/MainActivity.java b/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/MainActivity.java
new file mode 100644 (file)
index 0000000..8cc90ca
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.gctest;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.TextView;
+
+public class MainActivity extends Activity {
+    private final String mTag = "AndroidGCTest";
+    private boolean mRunning;
+
+    private Button mStartButton;
+    private Button mProfileSettingButton;
+    private Spinner mProfileNameList;
+    private SeekBar mSeekBar;
+    private LinearLayout mWorkloadResultLayout;
+    private Button mShowResultButton;
+    private TextView mExeTimeView;
+    private TextView mRuntimeView;
+    private TextView mWorkloadStatus;
+    private Profile mProfile = null;
+    private Bundle mResultData = null;
+
+    // handler to handle BenchmarkDone message
+    final static int BenchmarkDone = 100;
+    final static int BenchmarkProgress = 101;
+    final static int BenchmarkOutOfMemoryError = 102;
+    private class MyHandler extends Handler {
+        public void handleMessage(Message m) {
+            switch(m.what) {
+                case BenchmarkDone:
+                    if (mRunning) {
+                        mRunning = false;
+                        mStartButton.setVisibility(View.VISIBLE);
+                        mProfileSettingButton.setVisibility(View.VISIBLE);
+                        mWorkloadStatus.setText(R.string.workload_status_desc);
+                        mResultData = m.getData();
+                        String device = mResultData.getString("device");
+                        long execution_time = mResultData.getLong(ResultActivity.KEY_WORKLOAD_COMPLETE_TIME);
+                        mRuntimeView.setText(device);
+                        mExeTimeView.setText(String.valueOf(execution_time));
+                        mWorkloadResultLayout.setVisibility(View.VISIBLE);
+                        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+                    }
+                    break;
+                case BenchmarkProgress:
+                    if (mRunning && mSeekBar != null) {
+                        int progress = m.arg1;
+                        if (progress < mSeekBar.getMax())
+                            mSeekBar.setProgress(progress);
+                    }
+                    break;
+                case BenchmarkOutOfMemoryError:
+                    if (mRunning) {
+                        mWorkloadStatus.setText(R.string.outofmemory_desc);
+                        mRunning = false;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    private MyHandler mBenchmarkHandler = null;
+    public Handler getHandler() {
+        return mBenchmarkHandler;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log.i(mTag, "MainActivity onCreate");
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        mBenchmarkHandler = new MyHandler();
+
+        mWorkloadResultLayout = (LinearLayout)findViewById(R.id.workload_result_layout);
+        mSeekBar = (SeekBar)findViewById(R.id.seek_bar);
+        mSeekBar.setVisibility(View.INVISIBLE);
+        mWorkloadResultLayout.setVisibility(View.INVISIBLE);
+        mStartButton = (Button)findViewById(R.id.button_start);
+        mStartButton.setOnClickListener(startWorkload);
+        mWorkloadStatus = (TextView)findViewById(R.id.workload_status);
+
+        mProfileSettingButton = (Button)findViewById(R.id.button_set);
+        mProfileSettingButton.setOnClickListener(settingProfile);
+        mRuntimeView = (TextView)findViewById(R.id.runtime_info);
+        mExeTimeView = (TextView)findViewById(R.id.execution_time);
+        mShowResultButton = (Button)findViewById(R.id.button_result);
+        mShowResultButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // TODO Auto-generated method stub
+                if (mResultData != null) {
+                    Intent intent = new Intent(getApplicationContext(), ResultActivity.class);
+                    Bundle b = new Bundle(mResultData);
+                    intent.putExtra("result_data", b);
+                    startActivity(intent);
+                } else
+                    Log.e(mTag, "no result to show now");
+            }
+        });
+
+        mProfileNameList = (Spinner)findViewById(R.id.profile_list_view);
+        mProfile = Profile.getInstance();
+        Bundle b = getIntent().getExtras();
+        if (b != null && b.containsKey("profile_file")) {
+            FileInputStream profileFile;
+            try {
+                profileFile = new FileInputStream(b.getString("profile_file"));
+                mProfile.parseProfileData(profileFile);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+                Log.i(mTag, "Cannot load profile. " + e.getMessage());
+            }
+        } else {
+            mProfile.parseProfileData(getResources().openRawResource(R.raw.profile));
+        }
+
+        if (mProfile.initialized()) {
+            String[] names = new String[mProfile.mData.size()];
+            for (int i = 0; i < mProfile.mData.size(); i++) {
+                Profile.ProfileData d = mProfile.mData.get(i);
+                names[i] = d.getName();
+            }
+            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+                    android.R.layout.simple_spinner_item, names);
+            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            mProfileNameList.setAdapter(adapter);
+            mProfileNameList.setOnItemSelectedListener(new OnItemSelectedListener() {
+
+                @Override
+                public void onItemSelected(AdapterView<?> arg0, View arg1,
+                                           int arg2, long arg3) {
+                    String name = (String)(arg0.getAdapter().getItem(arg2));
+                    mProfile.setCurrentProfileData(name);
+                }
+
+                @Override
+                public void onNothingSelected(AdapterView<?> arg0) {
+                    // TODO Auto-generated method stub
+                }
+
+            });
+            mProfileNameList.setVisibility(View.VISIBLE);
+            if (b != null && b.containsKey("profile_name")) {
+                int pos = adapter.getPosition(b.getString("profile_name"));
+                mProfileNameList.setSelection(pos);
+            }
+        } else {
+            mProfileNameList.setVisibility(View.INVISIBLE);
+            Log.i(mTag, "Cannot get profile data");
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) {
+            android.os.Process.killProcess(android.os.Process.myPid());
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    protected void onResume() {
+        if (mRunning) {
+            if (mStartButton != null)
+                mStartButton.setVisibility(View.INVISIBLE);
+        }
+        super.onResume();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    private View.OnClickListener startWorkload = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            // TODO Auto-generated method stub
+            Log.i(mTag, "Start Benchmark");
+            Profile.ProfileData profileData = mProfile.getCurrentProfileData();
+            if (profileData == null) {
+                Log.e(mTag, "no profile data?!");
+                return;
+            }
+            final AndroidGCTestMain benchMain = new AndroidGCTestMain((MainActivity)(v.getContext()),
+                    profileData.getTotalSize(), profileData.getBucketSize(),
+                    profileData.getLosThreshold(), profileData.getSizeDistribution(),
+                    profileData.getLifetime(), profileData.getLosElementDist(),
+                    profileData.getThreadMode(), profileData.getThreadNum(),
+                    profileData.getIterationNum());
+
+            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+            mResultData = null;
+            Runtime.getRuntime().runFinalization();
+            Runtime.getRuntime().gc();
+
+            mWorkloadResultLayout.setVisibility(View.INVISIBLE);
+            mProfileSettingButton.setVisibility(View.INVISIBLE);
+            v.setVisibility(View.INVISIBLE);
+            mWorkloadStatus.setText("AndroidGCTest is running");
+            mSeekBar.setVisibility(View.VISIBLE);
+            mSeekBar.setMax(profileData.getIterationNum());
+            mSeekBar.setProgress(0);
+
+            mRunning = true;
+            Thread worker = new Thread(new Runnable() {
+
+                @Override
+                public void run() {
+                    // TODO Auto-generated method stub
+                    benchMain.start();
+                }
+
+            });
+            worker.start();
+        }
+    };
+
+    private View.OnClickListener settingProfile = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            // TODO Auto-generated method stub
+            Intent intent = new Intent(getApplicationContext(), ProfileSettingActivity.class);
+            startActivity(intent);
+        }
+    };
+}
diff --git a/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/Profile.java b/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/Profile.java
new file mode 100644 (file)
index 0000000..0d5e37a
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.gctest;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.util.Log;
+import android.util.Xml;
+
+public class Profile {
+    private final String mTag = "AndroidGCTest";
+    public class ProfileData {
+        private int mId;
+        private String mName;
+        private int mTotalSize;
+        private int mBucketSize;
+        private int mLosThreshold;
+        private float[] mSizeDist;
+        private float[] mLosElementDist;
+        private float[][] mLifetime;
+        private boolean mThreadMode;
+        private int mThreadNum;
+        private int mIterationNum;
+
+        public ProfileData(int id, String name) {
+            mId = id;
+            mName = name;
+        }
+        public String getName() { return mName; }
+        public int getTotalSize() { return mTotalSize; }
+        public int getBucketSize() { return mBucketSize; }
+        public int getLosThreshold() { return mLosThreshold; }
+        public float[] getSizeDistribution() { return mSizeDist; }
+        public float[] getLosElementDist() { return mLosElementDist; }
+        public float[][] getLifetime() { return mLifetime; }
+        public boolean getThreadMode() { return mThreadMode; }
+        public int getThreadNum() { return mThreadMode? 1 : mThreadNum; }
+        public int getIterationNum() { return mIterationNum; }
+
+        public void setName(String name) { mName = name; }
+        public void setTotalSize(int total_size) { mTotalSize = total_size; }
+        public void setBucketSize(int bucket_size) { mBucketSize = bucket_size; }
+        public void setLosThreshold(int los_threshold) { mLosThreshold = los_threshold; }
+        public void setSizeDistribution(float[] size_dist) { mSizeDist = size_dist; }
+        public void setLosElementDist(float[] los_element_dist) {
+            mLosElementDist = los_element_dist;
+        }
+        public void setLifetime(float[][] lifetime) { mLifetime = lifetime; }
+        public void setThreadMode(boolean singleThread) { mThreadMode = singleThread; }
+        public void setThreadNum(int thread_num) {
+            mThreadNum = mThreadMode? 1 : thread_num;
+        }
+        public void setIterationNum(int iteration_num) { mIterationNum = iteration_num; }
+    }
+
+    public boolean mInit = false;
+    int mCurrentProfileId;
+    public ArrayList<ProfileData> mData = null;
+
+    private static Profile instance_;
+    private Profile() {
+        mCurrentProfileId = -1;
+        mInit = false;
+    }
+    public static Profile getInstance() {
+        if (instance_ == null)
+            instance_ = new Profile();
+        return instance_;
+    }
+
+    private boolean initProfileData(InputStream input) {
+        ProfileData newProfile = null;
+        XmlPullParser parser=Xml.newPullParser();
+        try {
+            parser.setInput(new InputStreamReader(input));
+            int eventType = parser.getEventType();
+            float[] floatValues = null;
+            String itemName, name;
+            int idx0 = -1, idx1 = 0;
+            while (eventType != XmlPullParser.END_DOCUMENT) {
+                switch(eventType) {
+                    case XmlPullParser.START_DOCUMENT:
+                        mData = new ArrayList<ProfileData>();
+                        break;
+                    case XmlPullParser.START_TAG:
+                        name = parser.getName();
+                        if (name.matches("profile")) {
+                            newProfile = new ProfileData(
+                                    Integer.parseInt(parser.getAttributeValue(0)),
+                                    parser.getAttributeValue(1));
+                        } else if (name.matches("item")) {
+                            itemName = parser.getAttributeValue(0);
+                            if (itemName.matches("total_size")) {
+                                newProfile.mTotalSize = Integer.parseInt(parser.nextText());
+                            } else if (itemName.matches("bucket_size")) {
+                                newProfile.mBucketSize = Integer.parseInt(parser.nextText());
+                            } else if (itemName.matches("los_threshold")) {
+                                newProfile.mLosThreshold = Integer.parseInt(parser.nextText());
+                            } else if (itemName.matches("thread-mode")) {
+                                newProfile.mThreadMode = Integer.parseInt(parser.nextText()) == 1;
+                            } else if (itemName.matches("thread-num")) {
+                                newProfile.mThreadNum = Integer.parseInt(parser.nextText());
+                            } else if (itemName.matches("iteration-times")) {
+                                newProfile.mIterationNum = Integer.parseInt(parser.nextText());
+                            }
+                        } else if (name.matches("float-array-2d")) {
+                            if ("lifetime".equals(parser.getAttributeValue(0))) {
+                                newProfile.mLifetime = new float[Integer.parseInt(
+                                        parser.getAttributeValue(1))][];
+                                idx0 = 0;
+                            }
+                        } else if(name.matches("float-array")) {
+                            itemName = parser.getAttributeValue(0);
+                            if (itemName.matches("size_dist")) {
+                                newProfile.mSizeDist = new float[Integer.parseInt(
+                                        parser.getAttributeValue(1))];
+                                floatValues = newProfile.mSizeDist;
+                            } else if (itemName.matches("los_element_dist")) {
+                                newProfile.mLosElementDist = new float[Integer.parseInt(
+                                        parser.getAttributeValue(1))];
+                                floatValues = newProfile.mLosElementDist;
+                            } else if (idx0 >= 0) {
+                                newProfile.mLifetime[idx0] = new float[Integer.parseInt(
+                                        parser.getAttributeValue(1))];
+                                floatValues = newProfile.mLifetime[idx0];
+                                idx0++;
+                            }
+                            idx1 = 0;
+                        } else if(name.matches("value")) {
+                            if (floatValues == null) {
+                                Log.i(mTag, "error in parsing profile.xml");
+                                return false;
+                            }
+                            floatValues[idx1++] = Float.parseFloat(parser.nextText());
+                        }
+                        break;
+                    case XmlPullParser.END_TAG:
+                        name = parser.getName();
+                        if ("profile".equals(name))
+                            mData.add(newProfile);
+                        else if ("float-array-2d".equals(name))
+                            idx0 = -1;
+                        break;
+                    default:
+                        break;
+                }
+                eventType = parser.next();
+            }
+        } catch (XmlPullParserException e) {
+            e.printStackTrace();
+            return false;
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            return false;
+        } catch (IOException e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    public ProfileData getProfile(String name) {
+        if (!mInit)
+            return null;
+        for (int i = 0; i < mData.size(); i++) {
+            ProfileData data = mData.get(i);
+            if (data.mName.matches(name)) {
+                mCurrentProfileId = data.mId;
+                return data;
+            }
+        }
+        return null;
+    }
+
+    public boolean parseProfileData(InputStream rawProfileFile) {
+        mInit = initProfileData(rawProfileFile);
+        return mInit;
+    }
+
+    public boolean initialized() {
+        return mInit;
+    }
+
+    public void setCurrentProfileData(String name) {
+        if (!mInit)
+            return;
+        for (int i = 0; i < mData.size(); i++) {
+            ProfileData data = mData.get(i);
+            if (data.mName.matches(name)) {
+                mCurrentProfileId = data.mId;
+                break;
+            }
+        }
+    }
+
+    public ProfileData getCurrentProfileData() {
+        if (!mInit)
+            return null;
+        for (int i = 0; i < mData.size(); i++)
+            if (mData.get(i).mId == mCurrentProfileId)
+                return mData.get(i);
+        return null;
+    }
+}
diff --git a/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/ProfileSettingActivity.java b/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/ProfileSettingActivity.java
new file mode 100644 (file)
index 0000000..eea6e55
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.gctest;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+
+public class ProfileSettingActivity extends Activity {
+    private final String mTag = "AndroidGCTest";
+    private Button mConfirmButton = null;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_profile_config);
+        mConfirmButton = (Button)findViewById(R.id.button_confirm);
+        mConfirmButton.setOnClickListener(settingProfile);
+        Profile profile = Profile.getInstance();
+        showProfileData(profile.getCurrentProfileData());
+    }
+    private View.OnClickListener settingProfile = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            // TODO Auto-generated method stub
+            int heapSize, bucketSize, largeObjectSize;
+            float[] sizeDist = null;
+            float[][] lifetimeDist = null;
+            float[] largeSizeDist = null;
+            boolean singleThread = false;
+            int thread_num = 0, exe_time = 1;
+            heapSize = Integer.parseInt(((EditText)findViewById(
+                    R.id.total_size_v)).getText().toString());
+            bucketSize = Integer.parseInt(((EditText)findViewById(
+                    R.id.bucket_size_v)).getText().toString());
+            largeObjectSize = Integer.parseInt(((EditText)findViewById(
+                    R.id.los_threshold_v)).getText().toString());
+            exe_time = Integer.parseInt(((EditText)findViewById(
+                    R.id.exe_time_v)).getText().toString());
+            thread_num = Integer.parseInt(((EditText)findViewById(
+                    R.id.thread_num)).getText().toString());
+
+            sizeDist = new float[AndroidGCTestMain.OBJECT_SIZE_TYPE];
+            sizeDist[0] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_16_v)).getText().toString());
+            sizeDist[1] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_32_v)).getText().toString());
+            sizeDist[2] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_64_v)).getText().toString());
+            sizeDist[3] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_128_v)).getText().toString());
+            sizeDist[4] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_256_v)).getText().toString());
+            sizeDist[5] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_512_v)).getText().toString());
+            sizeDist[6] = Float.parseFloat(((EditText)findViewById(
+                    R.id.size_dist_los_v)).getText().toString());
+
+            String[][] lifetimeStr = new String[AndroidGCTestMain.OBJECT_SIZE_TYPE][];
+            lifetimeDist = new float[AndroidGCTestMain.OBJECT_SIZE_TYPE][];
+            lifetimeStr[AndroidGCTestMain.OBJECT_16_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_16_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            lifetimeStr[AndroidGCTestMain.OBJECT_32_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_32_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            lifetimeStr[AndroidGCTestMain.OBJECT_64_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_64_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            lifetimeStr[AndroidGCTestMain.OBJECT_128_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_128_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            lifetimeStr[AndroidGCTestMain.OBJECT_256_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_256_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            lifetimeStr[AndroidGCTestMain.OBJECT_512_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_512_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            lifetimeStr[AndroidGCTestMain.OBJECT_LARGE_BYTE] = ((EditText)findViewById(
+                    R.id.lifetime_los_v))
+                    .getText().toString().replaceAll(", ", ",").split(",");
+            for (int i = 0; i < AndroidGCTestMain.OBJECT_SIZE_TYPE; i++) {
+                int len = lifetimeStr[i].length;
+                lifetimeDist[i] = new float[len];
+                for (int j = 0; j < len; j++) {
+                    lifetimeDist[i][j] = Float.parseFloat(lifetimeStr[i][j]);
+                }
+            }
+
+            largeSizeDist = new float[4];
+            largeSizeDist[0] = Float.parseFloat(((EditText)findViewById(
+                    R.id.los_dist_byte_v))
+                    .getText().toString());
+            largeSizeDist[1] = Float.parseFloat(((EditText)findViewById(
+                    R.id.los_dist_char_v))
+                    .getText().toString());
+            largeSizeDist[2] = Float.parseFloat(((EditText)findViewById(
+                    R.id.los_dist_int_v))
+                    .getText().toString());
+            largeSizeDist[3] = Float.parseFloat(((EditText)findViewById(
+                    R.id.los_dist_long_v))
+                    .getText().toString());
+
+            singleThread = ((CheckBox)findViewById(R.id.single_thread)).isChecked();
+            Profile profile = Profile.getInstance();
+            Profile.ProfileData profileData = profile.getCurrentProfileData();
+            profileData.setTotalSize(heapSize);
+            profileData.setBucketSize(bucketSize);
+            profileData.setLosThreshold(largeObjectSize);
+            profileData.setSizeDistribution(sizeDist);
+            profileData.setLifetime(lifetimeDist);
+            profileData.setLosElementDist(largeSizeDist);
+            profileData.setThreadMode(singleThread);
+            profileData.setThreadNum(thread_num);
+            profileData.setIterationNum(exe_time);
+            Intent intent = new Intent(getApplicationContext(), MainActivity.class);
+            intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+            startActivity(intent);
+        }
+    };
+
+    private void showProfileData(Profile.ProfileData data) {
+        ((EditText)findViewById(R.id.total_size_v))
+                .setText(String.valueOf(data.getTotalSize()));
+        ((EditText)findViewById(R.id.bucket_size_v))
+                .setText(String.valueOf(data.getBucketSize()));
+        ((EditText)findViewById(R.id.los_threshold_v))
+                .setText(String.valueOf(data.getLosThreshold()));
+
+        int i = 0;
+        float[] size_dist = data.getSizeDistribution();
+        ((EditText)findViewById(R.id.size_dist_16_v)).setText(String.valueOf(size_dist[i++]));
+        ((EditText)findViewById(R.id.size_dist_32_v)).setText(String.valueOf(size_dist[i++]));
+        ((EditText)findViewById(R.id.size_dist_64_v)).setText(String.valueOf(size_dist[i++]));
+        ((EditText)findViewById(R.id.size_dist_128_v)).setText(String.valueOf(size_dist[i++]));
+        ((EditText)findViewById(R.id.size_dist_256_v)).setText(String.valueOf(size_dist[i++]));
+        ((EditText)findViewById(R.id.size_dist_512_v)).setText(String.valueOf(size_dist[i++]));
+        ((EditText)findViewById(R.id.size_dist_los_v)).setText(String.valueOf(size_dist[i++]));
+
+        i = 0;
+        float[] los_element_dist = data.getLosElementDist();
+        ((EditText)findViewById(R.id.los_dist_byte_v))
+                .setText(String.valueOf(los_element_dist[i++]));
+        ((EditText)findViewById(R.id.los_dist_char_v))
+                .setText(String.valueOf(los_element_dist[i++]));
+        ((EditText)findViewById(R.id.los_dist_int_v))
+                .setText(String.valueOf(los_element_dist[i++]));
+        ((EditText)findViewById(R.id.los_dist_long_v))
+                .setText(String.valueOf(los_element_dist[i++]));
+
+        String[] t = new String[]{"", "", "", "", "", "", ""};
+        float[][] lifetime = data.getLifetime();
+        for (i = 0; i < AndroidGCTestMain.OBJECT_SIZE_TYPE; i++) {
+            for (int j = 0; j < lifetime[i].length; j++) {
+                if (j != 0)
+                    t[i] += ",";
+                t[i] += String.valueOf(lifetime[i][j]);
+            }
+        }
+        i = 0;
+        ((EditText)findViewById(R.id.lifetime_16_v)).setText(t[i++]);
+        ((EditText)findViewById(R.id.lifetime_32_v)).setText(t[i++]);
+        ((EditText)findViewById(R.id.lifetime_64_v)).setText(t[i++]);
+        ((EditText)findViewById(R.id.lifetime_128_v)).setText(t[i++]);
+        ((EditText)findViewById(R.id.lifetime_256_v)).setText(t[i++]);
+        ((EditText)findViewById(R.id.lifetime_512_v)).setText(t[i++]);
+        ((EditText)findViewById(R.id.lifetime_los_v)).setText(t[i++]);
+
+        ((CheckBox)findViewById(R.id.single_thread)).setChecked(data.getThreadMode());
+
+        EditText thread_num_view = (EditText)findViewById(R.id.thread_num);
+        thread_num_view.setText(String.valueOf(data.getThreadNum()));
+        ((EditText)findViewById(R.id.exe_time_v))
+                .setText(String.valueOf(data.getIterationNum()));
+    }
+}
diff --git a/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/ResultActivity.java b/tests/GC/AndroidGCTest/app/src/main/java/com/android/gctest/ResultActivity.java
new file mode 100644 (file)
index 0000000..19f9bc1
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.gctest;
+
+import org.achartengine.ChartFactory;
+import org.achartengine.GraphicalView;
+import org.achartengine.chart.PointStyle;
+import org.achartengine.model.XYMultipleSeriesDataset;
+import org.achartengine.model.XYSeries;
+import org.achartengine.renderer.XYMultipleSeriesRenderer;
+import org.achartengine.renderer.XYSeriesRenderer;
+
+import android.util.Log;
+import android.app.Activity;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.LinearLayout.LayoutParams;
+
+public class ResultActivity extends Activity {
+    private final String mTag = "AndroidGCTest";
+    private long[] mThreadExeTime = null;
+    private long mWorkloadExeTime = 0;
+    private int[] mHeapFootprint = null;
+    private long[] mHeapBytesAllocated = null;
+    private float[] mGcPauseTime = null;
+    private float[] mGcTotalTime = null;
+    private String[] mGcCause = null;
+    private boolean mVmType; // true for ART, false for Dalvik
+
+    public static final String KEY_WORKLOAD_COMPLETE_TIME = "workload_completion_time";
+    public static final String KEY_THREAD_COMPLETE_TIME = "thread_completion_time";
+    public static final String KEY_VM_TYPE = "vm_type";
+    public static final String KEY_HEAP_FOOTPRINT = "heap_footprint";
+    public static final String KEY_BYTES_LIVING = "bytes_living";
+    public static final String KEY_GC_PAUSE_TIME = "gc_pause_time";
+    public static final String KEY_GC_COMPLETION_TIME = "gc_completion_time";
+    public static final String KEY_GC_CAUSE = "gc_cause";
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_result);
+
+        Bundle b = getIntent().getBundleExtra("result_data");
+        if (b == null) {
+            Log.i(mTag, "no result_data bundle!");
+        }
+
+        if (b.containsKey(KEY_VM_TYPE)) {
+            mVmType = b.getBoolean(KEY_VM_TYPE);
+        } else {
+            Log.i(mTag, "no " + KEY_VM_TYPE);
+        }
+
+        if (b.containsKey(KEY_WORKLOAD_COMPLETE_TIME)) {
+            mWorkloadExeTime = b.getLong(KEY_WORKLOAD_COMPLETE_TIME);
+            if (mWorkloadExeTime == 0) {
+                Log.i(mTag, "cannot read " + KEY_WORKLOAD_COMPLETE_TIME);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_WORKLOAD_COMPLETE_TIME);
+        }
+
+        if (b.containsKey(KEY_THREAD_COMPLETE_TIME)) {
+            mThreadExeTime = b.getLongArray(KEY_THREAD_COMPLETE_TIME);
+            if (mThreadExeTime == null) {
+                Log.i(mTag, "cannot read " + KEY_THREAD_COMPLETE_TIME);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_THREAD_COMPLETE_TIME);
+        }
+
+        if (b.containsKey(KEY_HEAP_FOOTPRINT)) {
+            mHeapFootprint = b.getIntArray(KEY_HEAP_FOOTPRINT);
+            if (mHeapFootprint == null) {
+                Log.i(mTag, "cannot read " + KEY_HEAP_FOOTPRINT);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_HEAP_FOOTPRINT);
+        }
+
+        if (b.containsKey(KEY_BYTES_LIVING)) {
+            mHeapBytesAllocated = b.getLongArray(KEY_BYTES_LIVING);
+            if (mHeapBytesAllocated == null) {
+                Log.i(mTag, "cannot read " + KEY_BYTES_LIVING);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_BYTES_LIVING);
+        }
+
+        if (b.containsKey(KEY_GC_PAUSE_TIME)) {
+            mGcPauseTime = b.getFloatArray(KEY_GC_PAUSE_TIME);
+            if (mGcPauseTime == null) {
+                Log.i(mTag, "cannot read " + KEY_GC_PAUSE_TIME);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_GC_PAUSE_TIME);
+        }
+
+        if (b.containsKey(KEY_GC_COMPLETION_TIME)) {
+            mGcTotalTime = b.getFloatArray(KEY_GC_COMPLETION_TIME);
+            if (mGcTotalTime == null) {
+                Log.i(mTag, "cannot read " + KEY_GC_COMPLETION_TIME);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_GC_COMPLETION_TIME);
+        }
+
+        if (b.containsKey(KEY_GC_CAUSE)) {
+            mGcCause = b.getStringArray(KEY_GC_CAUSE);
+            if (mGcCause == null) {
+                Log.i(mTag, "cannot read " + KEY_GC_CAUSE);
+            }
+        } else {
+            Log.i(mTag, "no " + KEY_GC_CAUSE);
+        }
+
+        TextView vm_type = (TextView)findViewById(R.id.vm_type);
+        vm_type.setText("Current runtime engine is " + (mVmType? "ART" : "Dalvik")
+                + ", workload completes in " + mWorkloadExeTime + " ms");
+        Button exeTimeButton = (Button)findViewById(R.id.button_exe_time);
+        exeTimeButton.setClickable(true);
+        exeTimeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // TODO Auto-generated method stub
+                mCurrentDataset.clear();
+                mCurrentRenderer.removeAllRenderers();
+                buildExeTimeInfoChart();
+                mChartView.repaint();
+            }
+        });
+
+        Button heapButton = (Button)findViewById(R.id.button_heap);
+        heapButton.setClickable(true);
+        heapButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // TODO Auto-generated method stub
+                mCurrentDataset.clear();
+                mCurrentRenderer.removeAllRenderers();
+                buildHeapInfoChart();
+                mChartView.repaint();
+            }
+        });
+
+        Button gcButton = (Button)findViewById(R.id.button_gc);
+        gcButton.setClickable(true);
+        gcButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                // TODO Auto-generated method stub
+                mCurrentDataset.clear();
+                mCurrentRenderer.removeAllRenderers();
+                buildGcInfoChart();
+                mChartView.repaint();
+            }
+        });
+        mCurrentRenderer.setApplyBackgroundColor(true);
+        mCurrentRenderer.setBackgroundColor(Color.argb(100, 50, 50, 50));
+        mCurrentRenderer.setAxisTitleTextSize(16);
+        mCurrentRenderer.setChartTitleTextSize(20);
+        mCurrentRenderer.setLabelsTextSize(15);
+        mCurrentRenderer.setLegendTextSize(15);
+        mCurrentRenderer.setMargins(new int[] { 20, 30, 15, 0 });
+        mCurrentRenderer.setZoomButtonsVisible(true);
+        mCurrentRenderer.setPointSize(5);
+    }
+    private XYMultipleSeriesDataset mCurrentDataset = new XYMultipleSeriesDataset();
+    private XYMultipleSeriesRenderer mCurrentRenderer = new XYMultipleSeriesRenderer();
+
+    private GraphicalView mChartView;
+    private void buildExeTimeInfoChart() {
+        Log.i(mTag, "buildExeTimeInfoChart");
+        // workload execution time
+        XYSeries series = new XYSeries("Workload Execution Time");
+        for (int i = 0; i < mThreadExeTime.length; i++) {
+            series.add(i, mThreadExeTime[i]);
+        }
+        mCurrentDataset.addSeries(series);
+        XYSeriesRenderer renderer = new XYSeriesRenderer();
+        // set some renderer properties
+        renderer.setPointStyle(PointStyle.CIRCLE);
+        renderer.setFillPoints(true);
+        renderer.setDisplayChartValues(true);
+        renderer.setDisplayChartValuesDistance(10);
+        renderer.setLineWidth(2.0f);
+        mCurrentRenderer.addSeriesRenderer(renderer);
+        mCurrentRenderer.setChartTitle("Workload Execution Time (ms)");
+        mCurrentRenderer.setYAxisMin(0);
+        mCurrentRenderer.setYAxisMax(mWorkloadExeTime*1.05);
+        mCurrentRenderer.setXAxisMin(0);
+        mCurrentRenderer.setXAxisMax(mThreadExeTime.length);
+    }
+
+    private void buildHeapInfoChart() {
+        Log.i(mTag, "buildHeapInfoChart");
+        // Heap footprint and bytes_allocated
+        double max = 0d;
+        XYSeries series2 = new XYSeries("Heap Footprint");
+        XYSeries series3 = new XYSeries("Bytes Allocated");
+        for (int i = 0; i < mHeapFootprint.length; i++) {
+            series2.add(i, mHeapFootprint[i]);
+            series3.add(i, mHeapBytesAllocated[i]);
+            if (max < mHeapFootprint[i])
+                max = mHeapFootprint[i];
+            if (max < mHeapBytesAllocated[i])
+                max = mHeapBytesAllocated[i];
+        }
+        mCurrentDataset.addSeries(series2);
+        mCurrentDataset.addSeries(series3);
+        XYSeriesRenderer renderer = new XYSeriesRenderer();
+        // set some renderer properties
+        renderer.setPointStyle(PointStyle.CIRCLE);
+        renderer.setFillPoints(true);
+        renderer.setDisplayChartValues(false);
+        renderer.setDisplayChartValuesDistance(10);
+        renderer.setColor(Color.RED);
+        renderer.setLineWidth(1.0f);
+        mCurrentRenderer.addSeriesRenderer(renderer);
+        renderer = new XYSeriesRenderer();
+        // set some renderer properties
+        renderer.setPointStyle(PointStyle.CIRCLE);
+        renderer.setFillPoints(true);
+        renderer.setDisplayChartValues(false);
+        renderer.setDisplayChartValuesDistance(10);
+        renderer.setColor(Color.BLUE);
+        renderer.setLineWidth(1.0f);
+        mCurrentRenderer.addSeriesRenderer(renderer);
+        mCurrentRenderer.setChartTitle("Heap Footprint/Bytes allocated (kB)");
+        mCurrentRenderer.setYAxisMin(0);
+        mCurrentRenderer.setYAxisMax(max*1.05);
+        mCurrentRenderer.setXAxisMin(0);
+        mCurrentRenderer.setXAxisMax(mHeapFootprint.length);
+    }
+
+    private void buildGcInfoChart() {
+        Log.i(mTag, "buildGcInfoChart");
+        // GC status
+        XYSeries series3 = new XYSeries("GC pause time");
+        double max = 0d;
+        for (int i = 0; i < mGcPauseTime.length; i++) {
+            series3.add(i, mGcPauseTime[i]);
+            if (max < mGcPauseTime[i])
+                max = mGcPauseTime[i];
+        }
+        mCurrentDataset.addSeries(series3);
+        XYSeriesRenderer renderer = new XYSeriesRenderer();
+        // set some renderer properties
+        renderer.setPointStyle(PointStyle.CIRCLE);
+        renderer.setFillPoints(true);
+        renderer.setDisplayChartValues(false);
+        renderer.setDisplayChartValuesDistance(10);
+        renderer.setColor(Color.BLUE);
+        renderer.setLineWidth(1.5f);
+        mCurrentRenderer.addSeriesRenderer(renderer);
+        mCurrentRenderer.setChartTitle("Gc Pause Time (ms)");
+        mCurrentRenderer.setYAxisMin(0);
+        mCurrentRenderer.setYAxisMax(max*1.05);
+        mCurrentRenderer.setXAxisMin(0);
+        mCurrentRenderer.setXAxisMax(mGcPauseTime.length);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        if (mChartView == null) {
+            buildExeTimeInfoChart();
+            LinearLayout layout = (LinearLayout) findViewById(R.id.chart);
+            mChartView = ChartFactory.getLineChartView(this,
+                    mCurrentDataset, mCurrentRenderer);
+            layout.addView(mChartView, new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.WRAP_CONTENT));
+        } else {
+            mChartView.repaint();
+        }
+    }
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            mCurrentDataset = null;
+            mCurrentRenderer = null;
+            mThreadExeTime = null;
+            mWorkloadExeTime = 0;
+            mHeapFootprint = null;
+            mHeapBytesAllocated = null;
+            mGcPauseTime = null;
+            mGcTotalTime = null;
+            mGcCause = null;
+            Runtime.getRuntime().runFinalization();
+            Runtime.getRuntime().gc();
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+}
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/drawable/ic_launcher_background.xml b/tests/GC/AndroidGCTest/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644 (file)
index 0000000..07d5da9
--- /dev/null
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#3DDC84"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/drawable/ic_launcher_foreground.xml b/tests/GC/AndroidGCTest/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644 (file)
index 0000000..2b068d1
--- /dev/null
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="85.84757"
+                android:endY="92.4963"
+                android:startX="42.9492"
+                android:startY="49.59793"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/layout/activity_main.xml b/tests/GC/AndroidGCTest/app/src/main/res/layout/activity_main.xml
new file mode 100644 (file)
index 0000000..1776e8f
--- /dev/null
@@ -0,0 +1,129 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/activity_main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context=".MainActivity" >
+
+    <SeekBar
+        android:id="@+id/seek_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true" />
+
+    <LinearLayout
+        android:id="@+id/workload_setting_layout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:baselineAligned="false"
+        android:orientation="horizontal"
+        android:layout_above="@id/seek_bar" >
+
+        <LinearLayout
+            android:layout_width="200dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="vertical" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginTop="10dp"
+                android:textSize="18sp"
+                android:text="@string/profile_list_dest" />
+            <Spinner
+                android:id="@+id/profile_list_view"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginLeft="20dp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:orientation="vertical" >
+            <Button
+                android:id="@+id/button_set"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:text="@string/set_profile_button_desc" />
+
+            <Button
+                android:id="@+id/button_start"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:text="@string/start_button_desc" />
+
+            <TextView
+                android:id="@+id/workload_status"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:textSize="20sp"
+                android:text="@string/workload_status_desc" />
+        </LinearLayout>
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:id="@+id/workload_result_layout"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/seek_bar"
+        android:layout_centerHorizontal="true"
+        android:orientation="vertical" >
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:text="@string/runtime_desc"
+                android:textSize="20sp" />
+
+            <TextView
+                android:id="@+id/runtime_info"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textSize="20sp" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:text="@string/execution_time_desc"
+                android:textSize="20sp" />
+
+            <TextView
+                android:id="@+id/execution_time"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="@color/result_color"
+                android:textSize="24sp" />
+
+        </LinearLayout>
+
+        <Button
+            android:id="@+id/button_result"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/show_result_button_desc" />
+
+    </LinearLayout>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/layout/activity_profile_config.xml b/tests/GC/AndroidGCTest/app/src/main/res/layout/activity_profile_config.xml
new file mode 100644 (file)
index 0000000..66f42f4
--- /dev/null
@@ -0,0 +1,491 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/activity_profile_config"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context=".ProfileSettingActivity" >
+
+    <Button
+        android:id="@+id/button_confirm"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:text="@string/setting_confirm_button_desc" />
+
+    <ScrollView
+        android:id="@+id/scrollView1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/button_confirm" >
+
+        <LinearLayout
+            android:id="@+id/config_table"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layoutMode="clipBounds"
+            android:orientation="vertical" >
+
+
+            <TableLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:shrinkColumns="0" >
+
+                <TableRow
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" >
+
+                    <TextView
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:singleLine="true"
+                        android:text="@string/total_size_desc" />
+
+                    <EditText
+                        android:id="@+id/total_size_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="left"
+                        android:inputType="number"
+                        android:text="@string/total_size_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" >
+
+                    <TextView
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:singleLine="true"
+                        android:text="@string/bucket_size_desc" />
+
+                    <EditText
+                        android:id="@+id/bucket_size_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="left"
+                        android:inputType="number"
+                        android:text="@string/bucket_size_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" >
+
+                    <TextView
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:singleLine="true"
+                        android:text="@string/los_threshold_desc" />
+
+                    <EditText
+                        android:id="@+id/los_threshold_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="left"
+                        android:inputType="number"
+                        android:text="@string/los_threshold_default" />
+                </TableRow>
+
+            </TableLayout>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="left"
+                android:singleLine="true"
+                android:text="@string/object_size_dist_desc" />
+
+            <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <TextView
+                    android:id="@+id/size_desc_16"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentTop="true"
+                    android:gravity="center"
+                    android:text="@string/object_size_16_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_16_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_16"
+                    android:layout_below="@id/size_desc_16"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_16_default" />
+
+                <TextView
+                    android:id="@+id/size_desc_32"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/size_desc_16"
+                    android:gravity="center"
+                    android:text="@string/object_size_32_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_32_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_32"
+                    android:layout_below="@id/size_desc_32"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_32_default" />
+
+                <TextView
+                    android:id="@+id/size_desc_64"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/size_desc_32"
+                    android:gravity="center"
+                    android:text="@string/object_size_64_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_64_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_64"
+                    android:layout_below="@id/size_desc_64"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_64_default" />
+
+                <TextView
+                    android:id="@+id/size_desc_128"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/size_desc_64"
+                    android:gravity="center"
+                    android:text="@string/object_size_128_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_128_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_128"
+                    android:layout_below="@id/size_desc_128"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_128_default" />
+
+                <TextView
+                    android:id="@+id/size_desc_256"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/size_desc_128"
+                    android:gravity="center"
+                    android:text="@string/object_size_256_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_256_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_256"
+                    android:layout_below="@id/size_desc_256"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_256_default" />
+
+                <TextView
+                    android:id="@+id/size_desc_512"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/size_desc_256"
+                    android:gravity="center"
+                    android:text="@string/object_size_512_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_512_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_512"
+                    android:layout_below="@id/size_desc_512"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_512_default" />
+
+                <TextView
+                    android:id="@+id/size_desc_los"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/size_desc_512"
+                    android:gravity="center"
+                    android:text="@string/object_size_los_desc" />
+
+                <EditText
+                    android:id="@+id/size_dist_los_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/size_desc_los"
+                    android:layout_below="@id/size_desc_los"
+                    android:inputType="numberDecimal"
+                    android:text="@string/size_dist_los_default" />
+            </RelativeLayout>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="left"
+                android:singleLine="true"
+                android:text="@string/los_dist_desc" />
+
+            <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <TextView
+                    android:id="@+id/los_dist_desc_byte"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentLeft="true"
+                    android:layout_alignParentTop="true"
+                    android:gravity="center"
+                    android:text="@string/los_dist_byte_desc" />
+
+                <EditText
+                    android:id="@+id/los_dist_byte_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/los_dist_desc_byte"
+                    android:layout_below="@id/los_dist_desc_byte"
+                    android:inputType="numberDecimal"
+                    android:text="@string/los_dist_byte_default" />
+
+                <TextView
+                    android:id="@+id/los_dist_desc_char"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/los_dist_desc_byte"
+                    android:gravity="center"
+                    android:text="@string/los_dist_char_desc" />
+
+                <EditText
+                    android:id="@+id/los_dist_char_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/los_dist_desc_char"
+                    android:layout_below="@id/los_dist_desc_char"
+                    android:inputType="numberDecimal"
+                    android:text="@string/los_dist_char_default" />
+
+                <TextView
+                    android:id="@+id/los_dist_desc_int"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/los_dist_desc_char"
+                    android:gravity="center"
+                    android:text="@string/los_dist_int_desc" />
+
+                <EditText
+                    android:id="@+id/los_dist_int_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/los_dist_desc_int"
+                    android:layout_below="@id/los_dist_desc_int"
+                    android:inputType="numberDecimal"
+                    android:text="@string/los_dist_int_default" />
+
+                <TextView
+                    android:id="@+id/los_dist_desc_long"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="25dp"
+                    android:layout_toRightOf="@id/los_dist_desc_int"
+                    android:gravity="center"
+                    android:text="@string/los_dist_long_desc" />
+
+                <EditText
+                    android:id="@+id/los_dist_long_v"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignLeft="@id/los_dist_desc_long"
+                    android:layout_below="@id/los_dist_desc_long"
+                    android:inputType="numberDecimal"
+                    android:text="@string/los_dist_long_default" />
+            </RelativeLayout>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center"
+                android:text="@string/lifetime_desc" />
+
+            <TableLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_16_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_16_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_16_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_32_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_32_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_32_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_64_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_64_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_64_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_128_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_128_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_128_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_256_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_256_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_256_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_512_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_512_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_512_default" />
+                </TableRow>
+
+                <TableRow
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content" >
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center"
+                        android:text="@string/object_size_los_desc" />
+
+                    <EditText
+                        android:id="@+id/lifetime_los_v"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:inputType="text"
+                        android:text="@string/lifetime_los_default" />
+                </TableRow>
+
+            </TableLayout>
+
+            <CheckBox
+                android:id="@+id/single_thread"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:text="@string/single_thread_desc" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="@string/thread_num_desc" />
+
+            <EditText
+                android:id="@+id/thread_num"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:inputType="number"
+                android:text="@string/thread_num_default" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="@string/exe_time_desc" />
+
+            <EditText
+                android:id="@+id/exe_time_v"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:inputType="number"
+                android:text="@string/exe_time_default" />
+
+        </LinearLayout>
+    </ScrollView>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/layout/activity_result.xml b/tests/GC/AndroidGCTest/app/src/main/res/layout/activity_result.xml
new file mode 100644 (file)
index 0000000..27c4685
--- /dev/null
@@ -0,0 +1,58 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/activity_result"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context=".ResultActivity" >
+
+    <TextView
+        android:id="@+id/vm_type"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:textSize="20sp"
+        android:text="@string/vm_type">
+    </TextView>
+
+    <LinearLayout
+        android:id="@+id/buttons"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/vm_type"
+        android:layout_centerHorizontal="true"
+        android:orientation="horizontal" >
+
+        <Button
+            android:id="@+id/button_exe_time"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="@string/complete_time_desc" />
+
+        <Button
+            android:id="@+id/button_heap"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="@string/heap_desc" />
+
+        <Button
+            android:id="@+id/button_gc"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:text="@string/gc_desc" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/chart"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/buttons"
+        android:layout_marginTop="20dp"
+        android:layout_centerHorizontal="true"
+        android:orientation="horizontal" >
+    </LinearLayout>
+
+</RelativeLayout>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/menu/main.xml b/tests/GC/AndroidGCTest/app/src/main/res/menu/main.xml
new file mode 100644 (file)
index 0000000..3d9b531
--- /dev/null
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/action_button"
+        android:orderInCategory="100"
+        android:showAsAction="collapseActionView"
+        android:title="@string/action_settings"/>
+
+</menu>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-anydpi/ic_launcher.xml b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-anydpi/ic_launcher.xml
new file mode 100644 (file)
index 0000000..6f3b755
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
new file mode 100644 (file)
index 0000000..6f3b755
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644 (file)
index 0000000..c209e78
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644 (file)
index 0000000..b2dfe3d
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644 (file)
index 0000000..4f0f1d6
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644 (file)
index 0000000..62b611d
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644 (file)
index 0000000..948a307
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644 (file)
index 0000000..1b9a695
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644 (file)
index 0000000..28d4b77
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644 (file)
index 0000000..9287f50
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644 (file)
index 0000000..aa7d642
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644 (file)
index 0000000..9126ae3
Binary files /dev/null and b/tests/GC/AndroidGCTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/raw/profile.xml b/tests/GC/AndroidGCTest/app/src/main/res/raw/profile.xml
new file mode 100644 (file)
index 0000000..98a44db
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<profile id="0" name="default">
+    <item name="total_size">100</item>
+    <item name="bucket_size">1</item>
+    <item name="los_threshold">12</item>
+    <float-array name="size_dist" count="7">
+        <value>0.0436</value>
+        <value>0.5465</value>
+        <value>0.2103</value>
+        <value>0.1499</value>
+        <value>0.0275</value>
+        <value>0.0125</value>
+        <value>0.0097</value>
+    </float-array>
+    <float-array-2d name="lifetime" count="7">
+        <float-array name="16b" count="4">
+            <value>0.0865</value>
+            <value>0.5404</value>
+            <value>0.2887</value>
+            <value>0.0865</value>
+        </float-array>
+        <float-array name="32b" count="4">
+            <value>0.0469</value>
+            <value>0.7724</value>
+            <value>0.1460</value>
+            <value>0.0346</value>
+        </float-array>
+        <float-array name="64b" count="4">
+            <value>0.1154</value>
+            <value>0.5982</value>
+            <value>0.1880</value>
+            <value>0.0984</value>
+        </float-array>
+        <float-array name="128b" count="4">
+            <value>0.0662</value>
+            <value>0.7851</value>
+            <value>0.1077</value>
+            <value>0.0411</value>
+        </float-array>
+        <float-array name="256b" count="4">
+            <value>0.0520</value>
+            <value>0.8778</value>
+            <value>0.0503</value>
+            <value>0.0198</value>
+        </float-array>
+        <float-array name="512b" count="4">
+            <value>0.1628</value>
+            <value>0.7137</value>
+            <value>0.0821</value>
+            <value>0.0414</value>
+        </float-array>
+        <float-array name="los" count="4">
+            <value>0.0923</value>
+            <value>0.7117</value>
+            <value>0.1769</value>
+            <value>0.0192</value>
+        </float-array>
+    </float-array-2d>
+    <float-array name="los_element_dist" count="4">
+        <value>0.90</value>
+        <value>0.07</value>
+        <value>0.02</value>
+        <value>0.01</value>
+    </float-array>
+    <item name="thread-mode">0</item>
+    <item name="thread-num">0</item>
+    <item name="iteration-times">10</item>
+</profile>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/values-night/themes.xml b/tests/GC/AndroidGCTest/app/src/main/res/values-night/themes.xml
new file mode 100644 (file)
index 0000000..04eb47b
--- /dev/null
@@ -0,0 +1,7 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Base.Theme.AndroidGCTest" parent="Theme.Material3.DayNight.NoActionBar">
+        <!-- Customize your dark theme here. -->
+        <!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
+    </style>
+</resources>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/values/colors.xml b/tests/GC/AndroidGCTest/app/src/main/res/values/colors.xml
new file mode 100644 (file)
index 0000000..c8524cd
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="black">#FF000000</color>
+    <color name="white">#FFFFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/values/dimens.xml b/tests/GC/AndroidGCTest/app/src/main/res/values/dimens.xml
new file mode 100644 (file)
index 0000000..55c1e59
--- /dev/null
@@ -0,0 +1,7 @@
+<resources>
+
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/values/strings.xml b/tests/GC/AndroidGCTest/app/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..7e40352
--- /dev/null
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">AndroidGCTest</string>
+    <string name="action_settings">Setting</string>
+    <string name="button_desc">Start</string>
+
+    <string name="total_size_desc">Total object size(MB)</string>
+    <string name="total_size_default">100</string>
+
+    <string name="bucket_size_desc">Bucket size(MB)</string>
+    <string name="bucket_size_default">1</string>
+
+    <string name="los_threshold_desc">Large Object Size(KB)</string>
+    <string name="los_threshold_default">12</string>
+
+    <string name="fragment_desc">Placeholder Degree (1 - 10)</string>
+    <string name="fragment_default">6</string>
+
+    <string name="object_size_16_desc">16byte</string>
+    <string name="object_size_32_desc">32byte</string>
+    <string name="object_size_64_desc">64byte</string>
+    <string name="object_size_128_desc">128byte</string>
+    <string name="object_size_256_desc">256byte</string>
+    <string name="object_size_512_desc">512byte</string>
+    <string name="object_size_los_desc">Large Object</string>
+    <string name="object_size_smaollobject_desc">Small Object</string>
+
+    <string name="object_size_dist_desc">Object Size Distribution</string>
+    <string name="size_dist_16_default">0.0436</string>
+    <string name="size_dist_32_default">0.5465</string>
+    <string name="size_dist_64_default">0.2103</string>
+    <string name="size_dist_128_default">0.1499</string>
+    <string name="size_dist_256_default">0.0275</string>
+    <string name="size_dist_512_default">0.0125</string>
+    <string name="size_dist_los_default">0.0097</string>
+
+    <string name="los_dist_desc">Large Object Element Type Distribution</string>
+    <string name="los_dist_byte_desc">Byte Array</string>
+    <string name="los_dist_char_desc">Char Array</string>
+    <string name="los_dist_int_desc">Int Array</string>
+    <string name="los_dist_long_desc">Long Array</string>
+    <string name="los_dist_byte_default">0.90</string>
+    <string name="los_dist_char_default">0.07</string>
+    <string name="los_dist_int_default">0.02</string>
+    <string name="los_dist_long_default">0.01</string>
+
+    <string name="lifetime_desc">Object Lifetime (long lived ratio, die immediately ratio,...)</string>
+    <string name="lifetime_16_default">0.0865,0.5404,0.2887,0.0865</string>
+    <string name="lifetime_32_default">0.0469,0.7724,0.1460,0.0346</string>
+    <string name="lifetime_64_default">0.1154,0.5982,0.1880,0.0984</string>
+    <string name="lifetime_128_default">0.0662,0.7851,0.1077,0.0411</string>
+    <string name="lifetime_256_default">0.0520,0.8778,0.0503,0.0198</string>
+    <string name="lifetime_512_default">0.1628,0.7137,0.0821,0.0414</string>
+    <string name="lifetime_los_default">0.0923,0.7117,0.1769,0.0192</string>
+    <string name="lifetime_smallobject_default">0.0883,0.7146,0.1438,0.0533</string>
+
+    <string name="single_thread_desc">Run in single thread?</string>
+    <string name="thread_num_desc">Thread # (0 means setting #thread as #CPU)</string>
+    <string name="thread_num_default">0</string>
+
+    <string name="exe_time_default">100</string>
+    <string name="exe_time_desc">set the iteration times of stress test phase, iterating 100 times takes ~160s on Nexus 5/ART</string>
+    <!-- <string name="los_threads_desc">Allocate large object in all threads?</string> -->
+
+    <string name="complete_time_desc">Complete Time</string>
+    <string name="heap_desc">Heap Footprint</string>
+    <string name="gc_desc">Gc Pause Time</string>
+    <string name="runtime_desc">Device: </string>
+    <string name="execution_time_desc">Execution time:</string>
+    <string name="show_result_button_desc">Show result details</string>
+    <string name="set_profile_button_desc">Setting</string>
+    <string name="start_button_desc">Start</string>
+    <string name="setting_confirm_button_desc">Confirm changes</string>
+    <string name="profile_list_dest">Select a profile</string>
+    <string name="workload_status_desc">Click &quot;Setting&quot; to config profile, click &quot;Start&quot; to run workload</string>
+    <string name="outofmemory_desc">OutOfMemory! Please config profile or Java Runtime and run again.</string>
+
+    <string name="vm_type">vm type</string>
+</resources>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/values/styles.xml b/tests/GC/AndroidGCTest/app/src/main/res/values/styles.xml
new file mode 100644 (file)
index 0000000..088b892
--- /dev/null
@@ -0,0 +1,21 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+    <color name="result_color">#ff7f27</color>
+
+</resources>
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/values/themes.xml b/tests/GC/AndroidGCTest/app/src/main/res/values/themes.xml
new file mode 100644 (file)
index 0000000..64702ab
--- /dev/null
@@ -0,0 +1,9 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+    <!-- Base application theme. -->
+    <style name="Base.Theme.AndroidGCTest" parent="Theme.Material3.DayNight.NoActionBar">
+        <!-- Customize your light theme here. -->
+        <!-- <item name="colorPrimary">@color/my_light_primary</item> -->
+    </style>
+
+    <style name="Theme.AndroidGCTest" parent="Base.Theme.AndroidGCTest" />
+</resources>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/xml/backup_rules.xml b/tests/GC/AndroidGCTest/app/src/main/res/xml/backup_rules.xml
new file mode 100644 (file)
index 0000000..fa0f996
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample backup rules file; uncomment and customize as necessary.
+   See https://developer.android.com/guide/topics/data/autobackup
+   for details.
+   Note: This file is ignored for devices older that API 31
+   See https://developer.android.com/about/versions/12/backup-restore
+-->
+<full-backup-content>
+    <!--
+   <include domain="sharedpref" path="."/>
+   <exclude domain="sharedpref" path="device.xml"/>
+-->
+</full-backup-content>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/main/res/xml/data_extraction_rules.xml b/tests/GC/AndroidGCTest/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644 (file)
index 0000000..9ee9997
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample data extraction rules file; uncomment and customize as necessary.
+   See https://developer.android.com/about/versions/12/backup-restore#xml-changes
+   for details.
+-->
+<data-extraction-rules>
+    <cloud-backup>
+        <!-- TODO: Use <include> and <exclude> to control what is backed up.
+        <include .../>
+        <exclude .../>
+        -->
+    </cloud-backup>
+    <!--
+    <device-transfer>
+        <include .../>
+        <exclude .../>
+    </device-transfer>
+    -->
+</data-extraction-rules>
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/app/src/test/java/com/android/gctest/ExampleUnitTest.java b/tests/GC/AndroidGCTest/app/src/test/java/com/android/gctest/ExampleUnitTest.java
new file mode 100644 (file)
index 0000000..86efc24
--- /dev/null
@@ -0,0 +1,17 @@
+package com.android.gctest;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+    @Test
+    public void addition_isCorrect() {
+        assertEquals(4, 2 + 2);
+    }
+}
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/build.gradle b/tests/GC/AndroidGCTest/build.gradle
new file mode 100644 (file)
index 0000000..565f8c2
--- /dev/null
@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+alias(libs.plugins.android.application) apply false
+}
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/gradle.properties b/tests/GC/AndroidGCTest/gradle.properties
new file mode 100644 (file)
index 0000000..4387edc
--- /dev/null
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/tests/GC/AndroidGCTest/gradle/libs.versions.toml b/tests/GC/AndroidGCTest/gradle/libs.versions.toml
new file mode 100644 (file)
index 0000000..4874452
--- /dev/null
@@ -0,0 +1,22 @@
+[versions]
+agp = "8.5.0"
+junit = "4.13.2"
+junitVersion = "1.2.1"
+espressoCore = "3.6.1"
+appcompat = "1.7.0"
+material = "1.12.0"
+activity = "1.9.0"
+constraintlayout = "2.1.4"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+
diff --git a/tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.jar b/tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.jar
new file mode 100644 (file)
index 0000000..e708b1c
Binary files /dev/null and b/tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.properties b/tests/GC/AndroidGCTest/gradle/wrapper/gradle-wrapper.properties
new file mode 100644 (file)
index 0000000..ed94214
--- /dev/null
@@ -0,0 +1,6 @@
+#Tue Jul 16 16:27:48 KST 2024
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/tests/GC/AndroidGCTest/gradlew b/tests/GC/AndroidGCTest/gradlew
new file mode 100755 (executable)
index 0000000..4f906e0
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/tests/GC/AndroidGCTest/gradlew.bat b/tests/GC/AndroidGCTest/gradlew.bat
new file mode 100644 (file)
index 0000000..ac1b06f
--- /dev/null
@@ -0,0 +1,89 @@
+@rem\r
+@rem Copyright 2015 the original author or authors.\r
+@rem\r
+@rem Licensed under the Apache License, Version 2.0 (the "License");\r
+@rem you may not use this file except in compliance with the License.\r
+@rem You may obtain a copy of the License at\r
+@rem\r
+@rem      https://www.apache.org/licenses/LICENSE-2.0\r
+@rem\r
+@rem Unless required by applicable law or agreed to in writing, software\r
+@rem distributed under the License is distributed on an "AS IS" BASIS,\r
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+@rem See the License for the specific language governing permissions and\r
+@rem limitations under the License.\r
+@rem\r
+\r
+@if "%DEBUG%" == "" @echo off\r
+@rem ##########################################################################\r
+@rem\r
+@rem  Gradle startup script for Windows\r
+@rem\r
+@rem ##########################################################################\r
+\r
+@rem Set local scope for the variables with windows NT shell\r
+if "%OS%"=="Windows_NT" setlocal\r
+\r
+set DIRNAME=%~dp0\r
+if "%DIRNAME%" == "" set DIRNAME=.\r
+set APP_BASE_NAME=%~n0\r
+set APP_HOME=%DIRNAME%\r
+\r
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.\r
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi\r
+\r
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"\r
+\r
+@rem Find java.exe\r
+if defined JAVA_HOME goto findJavaFromJavaHome\r
+\r
+set JAVA_EXE=java.exe\r
+%JAVA_EXE% -version >NUL 2>&1\r
+if "%ERRORLEVEL%" == "0" goto execute\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:findJavaFromJavaHome\r
+set JAVA_HOME=%JAVA_HOME:"=%\r
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe\r
+\r
+if exist "%JAVA_EXE%" goto execute\r
+\r
+echo.\r
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r
+echo.\r
+echo Please set the JAVA_HOME variable in your environment to match the\r
+echo location of your Java installation.\r
+\r
+goto fail\r
+\r
+:execute\r
+@rem Setup the command line\r
+\r
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar\r
+\r
+\r
+@rem Execute Gradle\r
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*\r
+\r
+:end\r
+@rem End local scope for the variables with windows NT shell\r
+if "%ERRORLEVEL%"=="0" goto mainEnd\r
+\r
+:fail\r
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r
+rem the _cmd.exe /c_ return code!\r
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1\r
+exit /b 1\r
+\r
+:mainEnd\r
+if "%OS%"=="Windows_NT" endlocal\r
+\r
+:omega\r
diff --git a/tests/GC/AndroidGCTest/settings.gradle b/tests/GC/AndroidGCTest/settings.gradle
new file mode 100644 (file)
index 0000000..c0218cb
--- /dev/null
@@ -0,0 +1,23 @@
+pluginManagement {
+    repositories {
+        google {
+            content {
+                includeGroupByRegex("com\\.android.*")
+                includeGroupByRegex("com\\.google.*")
+                includeGroupByRegex("androidx.*")
+            }
+        }
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
+dependencyResolutionManagement {
+    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.name = "AndroidGCTest"
+include ':app'
diff --git a/tests/GC/TizenGCTest/Directory.Build.targets b/tests/GC/TizenGCTest/Directory.Build.targets
new file mode 100755 (executable)
index 0000000..67fcf5d
--- /dev/null
@@ -0,0 +1,21 @@
+<!--\r
+***********************************************************************************************\r
+<Build.Directory.targets>\r
+WARNING:  DO NOT MODIFY this file. Incorrect changes to this file will make it\r
+          impossible to load or build your projects from the IDE.\r
+\r
+***********************************************************************************************\r
+-->\r
+\r
+<Project>    \r
+       <Target Name="BuildDotnet" AfterTargets="TizenPackage" >\r
+        <Message Text="Tizen Build starts here ------------" Importance="high"/>\r
+        <Message Text="$(MSBuildProjectDirectory)" Importance="high"/>\r
+        <PropertyGroup>\r
+            <WorkspaceFolder>$([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))</WorkspaceFolder>\r
+        </PropertyGroup>\r
+        <Message Text="Workspace: '$(WorkspaceFolder)'"  Importance="high" />\r
+\r
+               <Exec Command="C:\tizen-studio\tools\tizen-core\tz.exe pack  -S $(ProjectDir) $(WorkspaceFolder)"> </Exec>\r
+    </Target>\r
+</Project>\r
diff --git a/tests/GC/TizenGCTest/GCTest.cs b/tests/GC/TizenGCTest/GCTest.cs
new file mode 100755 (executable)
index 0000000..f042eea
--- /dev/null
@@ -0,0 +1,1480 @@
+using System;\r
+using System.Collections.Generic;\r
+using System.Diagnostics;\r
+using System.IO;\r
+using System.Security.Claims;\r
+using System.Threading;\r
+using Tizen.Applications;\r
+using Tizen.Content.MediaContent;\r
+using Tizen.Messaging.Messages;\r
+using Tizen;\r
+using Tizen.NUI.Components;\r
+using TizenGCTest;\r
+using Microsoft.VisualBasic;\r
+using System.Linq;\r
+using System.Runtime.InteropServices;\r
+using System.Reflection;\r
+using System.Text;\r
+using Tizen.NUI;\r
+using Tizen.NUI.BaseComponents;\r
+using static System.Net.Mime.MediaTypeNames;\r
+\r
+namespace TizenGCTest\r
+{\r
+    public class TreeNode\r
+    {\r
+        public TreeNode left, right;\r
+        public TreeNode(TreeNode l, TreeNode r)\r
+        {\r
+            left = l;\r
+            right = r;\r
+        }\r
+        public TreeNode() { }\r
+        public int Count()\r
+        {\r
+            int c = 1;\r
+            if (left != null)\r
+                c += left.Count();\r
+            if (right != null)\r
+                c += right.Count();\r
+            return c;\r
+        }\r
+    }\r
+\r
+    class TreeNode32 : TreeNode\r
+    { // object size = 24\r
+        private long payload1;\r
+        public TreeNode32(TreeNode32 l, TreeNode32 r) : base(l, r) { }\r
+        public TreeNode32() { }\r
+    }\r
+\r
+    class TreeNode64 : TreeNode\r
+    { // object size = 40\r
+        private long payload1, payload2, payload3;\r
+        public TreeNode64(TreeNode64 l, TreeNode64 r) : base(l, r) { }\r
+        public TreeNode64() { }\r
+    }\r
+\r
+    class TreeNode128 : TreeNode\r
+    { // object size = 96\r
+        private long payload1, payload2, payload3, payload4, payload5;\r
+        private long payload6, payload7, payload8, payload9, payload10;\r
+        public TreeNode128(TreeNode128 l, TreeNode128 r) : base(l, r) { }\r
+        public TreeNode128() { }\r
+    }\r
+\r
+    class TreeNode256 : TreeNode\r
+    { // object size = 192\r
+        private long payload1, payload2, payload3, payload4, payload5;\r
+        private long payload6, payload7, payload8, payload9, payload10;\r
+        private long payload11, payload12, payload13, payload14, payload15;\r
+        private long payload16, payload17, payload18, payload19, payload20;\r
+        private long payload21, payload22;\r
+        public TreeNode256(TreeNode256 l, TreeNode256 r) : base(l, r) { }\r
+        public TreeNode256() { }\r
+    }\r
+\r
+    class TreeNode512 : TreeNode\r
+    { // object size = 336\r
+        private long payload1, payload2, payload3, payload4, payload5;\r
+        private long payload6, payload7, payload8, payload9, payload10;\r
+        private long payload11, payload12, payload13, payload14, payload15;\r
+        private long payload16, payload17, payload18, payload19, payload20;\r
+        private long payload101, payload102, payload103, payload104, payload105;\r
+        private long payload106, payload107, payload108, payload109, payload100;\r
+        private long payload111, payload112, payload113, payload114, payload115;\r
+        private long payload116, payload117, payload118, payload119, payload120;\r
+        public TreeNode512(TreeNode512 l, TreeNode512 r) : base(l, r) { }\r
+        public TreeNode512() { }\r
+    }\r
+\r
+    public class LinkNode\r
+    {\r
+        public LinkNode Next { get; set; }\r
+        public TreeNode TreeNode { get; set; }\r
+\r
+        public LinkNode(TreeNode n)\r
+        {\r
+            TreeNode = n;\r
+        }\r
+\r
+        public LinkNode() { }\r
+    }\r
+\r
+    class LivedLink\r
+    {\r
+        public LinkNode TreeHead { get; set; }\r
+        public LivedLink() { TreeHead = null; }\r
+        public void insertNode(TreeNode newTree)\r
+        {\r
+            if (TreeHead == null)\r
+            {\r
+                TreeHead = new LinkNode(newTree);\r
+                TreeHead.Next = null;\r
+            }\r
+            else\r
+            {\r
+                LinkNode newNode = new LinkNode(newTree);\r
+                newNode.Next = TreeHead;\r
+                TreeHead = newNode;\r
+            }\r
+        }\r
+    }\r
+\r
+    public class GCTest\r
+    {\r
+        private const String mTag = "TizenGCTest";\r
+\r
+        // size of small objects\r
+        public const int OBJECT_16_BYTE = 0;\r
+        public const int OBJECT_32_BYTE = 1;\r
+        public const int OBJECT_64_BYTE = 2;\r
+        public const int OBJECT_128_BYTE = 3;\r
+        public const int OBJECT_256_BYTE = 4;\r
+        public const int OBJECT_512_BYTE = 5;\r
+        public const int OBJECT_LARGE_BYTE = 6;\r
+        public const int OBJECT_SIZE_TYPE = 7;\r
+        private int[] mObjectSize = new int[] { 16, 24, 40, 96, 192, 336 };\r
+\r
+        // size of large object, default is 12KByte\r
+        private int mLargeObjectSize = 0;\r
+        // array element type distribution for large object\r
+        // {1-byte array, 2-byte array, 4-byte array, 8-byte array}\r
+        private float[] mLargeObjectDistribution = null;\r
+\r
+        // allocation configuration\r
+        // total allocate size\r
+        private int mTotalAllocateSize = 0;\r
+        // total allocate size by one thread\r
+        private int mTotalAllocSizePerThread = 0;\r
+\r
+        // unit for tree allocation/deletion operation.\r
+        // mBucketSize is also the unit to measure object lifetime.\r
+        // Benchmark allocates mBucketSize of data -> deletes some data\r
+        // -> allocates mBucketSize of Data\r
+        private int mBucketSize = 0;\r
+\r
+        // allocated object size distribution\r
+        // {[1-16], [17-32], [33-64], [65, 128], [129, 256], [257, 512], >12K}\r
+        private float[] mSizeDistribution = null;\r
+\r
+        // allocated object lifetime:\r
+        // mLifetime[X][0] is long lived object percentage of object size X,\r
+        // mLifetime[X][1] is percentage of object die immediately,\r
+        // mLifetime[X][2] is percentage of object die in next period after\r
+        // creation period ...\r
+        private float[][] mLifetime = null;\r
+\r
+        private int mLongLiveSmallObjectSize;\r
+\r
+        // a big array to store random values to decide object size of next allocated object\r
+        private byte[][] mObjectSizeRandom = null;\r
+        // a big array to store random values to decide lifetime of next allocated object\r
+        private byte[][] mLifetimeRandom = null;\r
+        private int mShortLiveTreeCount;\r
+        private int mTotalNodeCount;\r
+        private const int mTreeCountParallel = 4;\r
+\r
+        private int[] mLargeArrayLength = null;\r
+        private int[] mLargeArrayNum = null;\r
+        private int[] mLargeArrayInter = null;\r
+        private int mLongLiveLargeObjectSize;\r
+        private int[][] mDieNumLargeObject = null;\r
+\r
+        // thread mode configuration\r
+        private int mThreadNum;\r
+        private bool mSingleThread = false;\r
+\r
+        private long[] mStartTime = null;\r
+        private long[] mEndTime = null;\r
+        private long[] mElapseTime = null;\r
+        private int[] mHeapFootprint = null;\r
+        private long[] mHeapBytesAllocated = null;\r
+\r
+        private long mTotalGcCount;\r
+        private long mTotalGcTime;\r
+        private long mTotalBlockingGcCount;\r
+        private long mTotalBlockingGcTime;\r
+        public String[] GC_CAUSE_ART = new String[]{"Alloc", "Background", "Explicit", "NativeAlloc", "CollectorTransition", "DisableMovingGc", "HomogeneousSpaceCompact", "HeapTrim"};\r
+        public String[] GC_CAUSE_DALVIK = new String[]{"GC_FOR_ALLOC","GC_CONCURRENT", "GC_EXPLICIT", "GC_BEFORE_OOM"};\r
+        private int[] mGcCauseCount = null;\r
+        private float[] mGcPauseTime = null;\r
+        private float[] mGcTotalTime = null;\r
+        private String[] mGcCause = null;\r
+\r
+        private bool isArt;\r
+        private bool mWorkloadComplete;\r
+        private int mIterNum = 100;\r
+\r
+        private StreamWriter fileOutput;\r
+        private BenchThread[] mTestThreads;\r
+        //private Thread[] mThreads;\r
+        private Thread t0, t1, t2, t3;\r
+        private bool mOutOfMemory;\r
+        private bool flag0 = false, flag1 = false, flag2 = false, flag3 = false;\r
+\r
+        private readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);\r
+\r
+        public TextLabel text;\r
+\r
+        private void init()\r
+        {\r
+            // thread number;\r
+            if (mSingleThread)\r
+            {\r
+                mThreadNum = 1;\r
+            }\r
+            else if (mThreadNum == 0)\r
+            {\r
+                //mThreadNum = Runtime.getRuntime().availableProcessors();\r
+                mThreadNum = Environment.ProcessorCount;\r
+            }\r
+            if (mThreadNum == 0)\r
+            {\r
+                mThreadNum = 1;\r
+            }\r
+\r
+            if (mSizeDistribution == null)\r
+            {\r
+                mSizeDistribution = new float[]{0.0436f,0.5465f,0.2103f,0.1499f,\r
+                    0.0275f,0.0125f,0.0097f};\r
+            }\r
+            //if (mLifetime == null)\r
+            {\r
+                mLifetime = new float[][] {\r
+                            new float[] { 0.0865f, 0.5404f, 0.2887f, 0.0865f },\r
+                            new float[] { 0.0469f, 0.7724f, 0.1460f, 0.0346f },\r
+                            new float[] { 0.1154f, 0.5982f, 0.1880f, 0.0984f },\r
+                            new float[] { 0.0662f, 0.7851f, 0.1077f, 0.0411f },\r
+                            new float[] { 0.0520f, 0.8778f, 0.0503f, 0.0198f },\r
+                            new float[] { 0.1628f, 0.7137f, 0.0821f, 0.0414f },\r
+                            new float[] { 0.0923f, 0.7117f, 0.1769f, 0.0192f }// large object lifetime\r
+                            };\r
+           \r
+            }\r
+\r
+            if (mLargeObjectDistribution == null)\r
+            {\r
+                mLargeObjectDistribution = new float[] { 0.9f, 0.07f, 0.02f, 0.01f };\r
+            }\r
+\r
+            if (mTotalAllocateSize == 0)\r
+            {\r
+                mTotalAllocateSize = 100 * 1024 * 1024;\r
+            }\r
+            mTotalAllocSizePerThread = mTotalAllocateSize / mThreadNum;\r
+\r
+            if (mBucketSize == 0)\r
+            {\r
+                mBucketSize = 1 * 1024 * 1024;\r
+            }\r
+\r
+            if (mLargeObjectSize == 0)\r
+            {\r
+                mLargeObjectSize = 12 * 1024;\r
+            }\r
+\r
+            Log.Info(mTag, "Allocate Size: " + (mTotalAllocateSize / 1024) + " kB");\r
+            Log.Info(mTag, "BucketSize: " + (mBucketSize / 1024) + " kB");\r
+            Log.Info(mTag, "Large object size: " + (mLargeObjectSize / 1024) + " kB");\r
+            Log.Info(mTag, "Single Thread: " + mSingleThread);\r
+            Log.Info(mTag, "Thread number: " + mThreadNum);\r
+            Log.Info(mTag, "Stress test part iterates " + mIterNum + " times");\r
+\r
+            string curDate = DateTime.Now.ToString();\r
+            try\r
+            {\r
+                using (StreamWriter fileOutput = new StreamWriter("/tmp/TizenGCTest-result.txt", true))\r
+                {\r
+                    fileOutput.WriteLine();\r
+                    fileOutput.WriteLine(curDate);\r
+\r
+                    fileOutput.WriteLine("Workload configuration:");\r
+                    fileOutput.WriteLine("\tAllocate Size: " + (mTotalAllocateSize / 1024) + " kB");\r
+                    fileOutput.WriteLine("\tBucketSize: " + (mBucketSize / 1024) + " kB");\r
+                    fileOutput.WriteLine("\tLarge object size: " + (mLargeObjectSize / 1024) + " kB");\r
+                    fileOutput.WriteLine("\tThread mode: " + (mSingleThread ? "Single-Thread" : "Multi-Thread"));\r
+                    fileOutput.WriteLine("\t: " + mThreadNum);\r
+                    fileOutput.WriteLine("\tStress test part iterates " + mIterNum + " times");\r
+                }\r
+            }\r
+            catch (IOException e)\r
+            {\r
+                Log.Info(mTag, "Cannot open /tmp/TizenGCTest-result.txt" + e.Message);\r
+            }\r
+\r
+            int smallObjectSize, largeObjectSize;\r
+            largeObjectSize = (int)(mTotalAllocSizePerThread * mSizeDistribution[OBJECT_LARGE_BYTE]);\r
+            smallObjectSize = mTotalAllocSizePerThread - largeObjectSize;\r
+\r
+            float[] countDistr = new float[OBJECT_LARGE_BYTE];\r
+            float nodeSize = 0.0f;\r
+            int[] sizeThreshold = new int[OBJECT_LARGE_BYTE];\r
+            int lifetimeLen = mLifetime[0].Length;\r
+            int[][] lifetimeThreshold = new int[OBJECT_LARGE_BYTE][];\r
+            for (int i = 0; i < OBJECT_LARGE_BYTE; i++)\r
+            {\r
+                lifetimeThreshold[i] = new int[lifetimeLen];\r
+            }\r
+            float sum = 0.0f;\r
+            for (int i = 0; i < OBJECT_LARGE_BYTE; i++)\r
+            {\r
+                countDistr[i] = mSizeDistribution[i]\r
+                        / (1 - mSizeDistribution[OBJECT_LARGE_BYTE]) / mObjectSize[i];\r
+                sum += countDistr[i];\r
+            }\r
+\r
+            mLongLiveSmallObjectSize = 0;\r
+            float sum1 = 0.0f;\r
+            for (int i = 0; i < OBJECT_LARGE_BYTE; i++)\r
+            {\r
+                sum1 += countDistr[i];\r
+                sizeThreshold[i] = (int)(sum1 * 1000 / sum + 0.5);\r
+                nodeSize += mObjectSize[i] * countDistr[i] / sum;\r
+\r
+                float sum2 = 0.0f;\r
+                for (int j = 1; j < lifetimeLen; j++)\r
+                {\r
+                    sum2 += mLifetime[i][j];\r
+                    lifetimeThreshold[i][j - 1] = (int)(sum2 * 1000 + 0.5);\r
+                }\r
+                lifetimeThreshold[i][lifetimeLen - 1] = 1000;\r
+\r
+                mLongLiveSmallObjectSize += (int)(mTotalAllocSizePerThread * mSizeDistribution[i] * mLifetime[i][0]);\r
+            }\r
+            sizeThreshold[OBJECT_512_BYTE] = 1000;\r
+\r
+\r
+            mShortLiveTreeCount = (int)(smallObjectSize / mBucketSize + 0.5);\r
+            mTotalNodeCount = (int)(mBucketSize / nodeSize * 1.11);\r
+\r
+            mObjectSizeRandom = new byte[mThreadNum][];\r
+            mLifetimeRandom = new byte[mThreadNum][];\r
+            for (int i = 0; i < mThreadNum; i++)\r
+            {\r
+                mObjectSizeRandom[i] = new byte[mTotalNodeCount];\r
+                mLifetimeRandom[i] = new byte[mTotalNodeCount];\r
+            }\r
+\r
+            Random r_size = new Random();\r
+            Random r_lifetime = new Random(mThreadNum);\r
+            for (int i = 0; i < mThreadNum; i++)\r
+            {\r
+                r_size = new Random(i);\r
+                r_lifetime = new Random(i + mThreadNum);\r
+                for (int j = 0; j < mTotalNodeCount; j++)\r
+                {\r
+                    int vs = r_size.Next(1000);\r
+                    int vl = r_lifetime.Next(1000);\r
+                    for (int k = 0; k < OBJECT_LARGE_BYTE; k++)\r
+                    {\r
+                        if (vs < sizeThreshold[k])\r
+                        {\r
+                            mObjectSizeRandom[i][j] = (byte)(OBJECT_16_BYTE + k);\r
+                            for (int l = 0; l < lifetimeLen; l++)\r
+                            {\r
+                                if (vl < lifetimeThreshold[k][l])\r
+                                {\r
+                                    mLifetimeRandom[i][j] = (byte)l;\r
+                                    //Log.Info(mTag, "mLifetimeRandom["+i+"]["+j+"] : " + l);\r
+                                    break;\r
+                                }\r
+                            }\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+\r
+            mLongLiveLargeObjectSize = (int)(largeObjectSize * mLifetime[OBJECT_LARGE_BYTE][0]);\r
+            mDieNumLargeObject = new int[4][];\r
+            for (int i = 0; i < 4; i++)\r
+            {\r
+                mDieNumLargeObject[i] = new int[lifetimeLen - 1];\r
+            }\r
+            mLargeArrayInter = new int[4];\r
+            mLargeArrayLength = new int[4];\r
+            mLargeArrayNum = new int[4];\r
+            for (int i = 0; i < 4; i++)\r
+            {\r
+                mLargeArrayLength[i] = (int)((largeObjectSize * mLargeObjectDistribution[i]\r
+                        / mLargeObjectSize) + 0.5);\r
+                if (mLargeArrayLength[i] == 0)\r
+                {\r
+                    mLargeArrayInter[i] = mShortLiveTreeCount + 1;\r
+                    mLargeArrayNum[i] = 0;\r
+                    continue;\r
+                }\r
+                if (mShortLiveTreeCount > mLargeArrayLength[i])\r
+                {\r
+                    mLargeArrayInter[i] = mShortLiveTreeCount / mLargeArrayLength[i];\r
+                    mLargeArrayNum[i] = 1;\r
+                    mLargeArrayLength[i] = mShortLiveTreeCount / mLargeArrayInter[i] + 1;\r
+                }\r
+                else\r
+                {\r
+                    mLargeArrayInter[i] = 1;\r
+                    mLargeArrayNum[i] = (int)(mLargeArrayLength[i] / (float)mShortLiveTreeCount + 0.5);\r
+                    mLargeArrayLength[i] = mLargeArrayNum[i] * mShortLiveTreeCount;\r
+                }\r
+\r
+                sum = 0.0f;\r
+                for (int j = 1; j < lifetimeLen; j++)\r
+                {\r
+                    sum += mLifetime[OBJECT_LARGE_BYTE][j];\r
+                    mDieNumLargeObject[i][j - 1] = (int)(mLargeArrayNum[i] * sum);\r
+                }\r
+            }\r
+            text = new TextLabel();\r
+            text.TextColor = Color.White;\r
+            Window.Instance.GetDefaultLayer().Add(text);\r
+            Log.Info(mTag, "init done");\r
+        }\r
+\r
+        private void clearInitData()\r
+        {\r
+            Log.Info(mTag, "clear auxiliary data to run workload");\r
+            mLifetime = null;\r
+            mLargeObjectDistribution = null;\r
+            mSizeDistribution = null;\r
+            mObjectSizeRandom = null;\r
+            mLifetimeRandom = null;\r
+            mLargeArrayInter = null;\r
+            mLargeArrayLength = null;\r
+            mLargeArrayNum = null;\r
+            mDieNumLargeObject = null;\r
+            //Runtime.getRuntime().runFinalization();\r
+            //Runtime.getRuntime().gc();\r
+            GC.Collect();\r
+            GC.WaitForPendingFinalizers();\r
+        }\r
+\r
+        public GCTest()\r
+        {\r
+            init();\r
+        }\r
+        public GCTest(/*MainActivity activity,*/ int heapSize, int bucketSize, int largeObjectSize,\r
+                          float[] sizeDistr, float[][] lifetimeDistr, float[] largeObjectSizeDist,\r
+                          bool singleThread, int thread_num, int exeTime)\r
+        {\r
+            //mActivity = activity;\r
+            mTotalAllocateSize = heapSize * 1024 * 1024;\r
+            mBucketSize = bucketSize * 1024 * 1024;\r
+            mLargeObjectSize = largeObjectSize * 1024;\r
+            mSizeDistribution = sizeDistr;\r
+            mLifetime = lifetimeDistr;\r
+            mLargeObjectDistribution = largeObjectSizeDist;\r
+            mSingleThread = singleThread;\r
+            mThreadNum = mSingleThread ? 1 : thread_num;\r
+            mIterNum = exeTime > 0 ? exeTime : 100;\r
+            init();\r
+        }\r
+\r
+\r
+        private void freeArrays(byte[][] byteArray, char[][] charArray, int[][] intArray,\r
+                            long[][] longArray, int[] arrayIdx, int treeCount)\r
+        {\r
+            int len = mDieNumLargeObject[0].Length;\r
+            int died, release, phase;\r
+\r
+            phase = treeCount % mLargeArrayInter[0];\r
+            if (byteArray != null && phase <= len)\r
+            {\r
+                int curIdx = arrayIdx[0] - mLargeArrayNum[0];\r
+                while (curIdx >= 0 && phase <= len)\r
+                {\r
+                    if (phase == 0)\r
+                        died = 0;\r
+                    else\r
+                        died = mDieNumLargeObject[0][phase - 1];\r
+                    if (phase == len)\r
+                    {\r
+                        if (byteArray[curIdx + died] != null)\r
+                        {\r
+                            for (int i = died; i < mLargeArrayNum[0]; i++)\r
+                                byteArray[curIdx + i] = null;\r
+                        }\r
+                        break;\r
+                    }\r
+                    release = mDieNumLargeObject[0][phase];\r
+                    for (int i = died; i < release; i++)\r
+                    {\r
+                        if (i >= mLargeArrayNum[0])\r
+                            break;\r
+                        byteArray[curIdx + i] = null;\r
+                    }\r
+                    curIdx -= mLargeArrayNum[0];\r
+                    phase += mLargeArrayInter[0];\r
+                }\r
+            }\r
+\r
+            phase = treeCount % mLargeArrayInter[1];\r
+            if (charArray != null && phase < mLargeArrayNum[1])\r
+            {\r
+                int curIdx = arrayIdx[1] - mLargeArrayNum[1];\r
+                while (curIdx >= 0 && phase <= len)\r
+                {\r
+                    if (phase == 0)\r
+                        died = 0;\r
+                    else\r
+                        died = mDieNumLargeObject[1][phase - 1];\r
+                    if (phase == len)\r
+                    {\r
+                        if (charArray[curIdx + died] != null)\r
+                        {\r
+                            for (int i = died; i < mLargeArrayNum[1]; i++)\r
+                                charArray[curIdx + i] = null;\r
+                        }\r
+                        break;\r
+                    }\r
+                    release = mDieNumLargeObject[1][phase];\r
+                    for (int i = died; i < release; i++)\r
+                    {\r
+                        if (i >= mLargeArrayNum[1])\r
+                            break;\r
+                        charArray[curIdx + i] = null;\r
+                    }\r
+                    curIdx -= mLargeArrayNum[1];\r
+                    phase += mLargeArrayInter[1];\r
+                }\r
+            }\r
+\r
+            phase = treeCount % mLargeArrayInter[2];\r
+            if (intArray != null && phase < mLargeArrayNum[2])\r
+            {\r
+                int curIdx = arrayIdx[2] - mLargeArrayNum[2];\r
+                while (curIdx >= 0 && phase <= len)\r
+                {\r
+                    if (phase == 0)\r
+                        died = 0;\r
+                    else\r
+                        died = mDieNumLargeObject[2][phase - 1];\r
+                    if (phase == len)\r
+                    {\r
+                        if (intArray[curIdx + died] != null)\r
+                        {\r
+                            for (int i = died; i < mLargeArrayNum[2]; i++)\r
+                                intArray[curIdx + i] = null;\r
+                        }\r
+                        break;\r
+                    }\r
+                    release = mDieNumLargeObject[2][phase];\r
+                    for (int i = died; i < release; i++)\r
+                    {\r
+                        if (i >= mLargeArrayNum[2])\r
+                            break;\r
+                        intArray[curIdx + i] = null;\r
+                    }\r
+                    curIdx -= mLargeArrayNum[2];\r
+                    phase += mLargeArrayInter[2];\r
+                }\r
+            }\r
+\r
+            phase = treeCount % mLargeArrayInter[3];\r
+            if (longArray != null && phase < mLargeArrayNum[3])\r
+            {\r
+                int curIdx = arrayIdx[3] - mLargeArrayNum[3];\r
+                while (curIdx >= 0 && phase <= len)\r
+                {\r
+                    if (phase == 0)\r
+                        died = 0;\r
+                    else\r
+                        died = mDieNumLargeObject[3][phase - 1];\r
+                    if (phase == len)\r
+                    {\r
+                        if (longArray[curIdx + died] != null)\r
+                        {\r
+                            for (int i = died; i < mLargeArrayNum[3]; i++)\r
+                                longArray[curIdx + i] = null;\r
+                        }\r
+                        break;\r
+                    }\r
+                    release = mDieNumLargeObject[3][phase];\r
+                    for (int i = died; i < release; i++)\r
+                    {\r
+                        if (i >= mLargeArrayNum[3])\r
+                            break;\r
+                        longArray[curIdx + i] = null;\r
+                    }\r
+                    curIdx -= mLargeArrayNum[3];\r
+                    phase += mLargeArrayInter[3];\r
+                }\r
+            }\r
+        }\r
+\r
+        private void makeTreesLongLive(TreeNode[] trees, int allocSize, int myId, int[] nodeCount)\r
+        {\r
+            while (true)\r
+            {\r
+                if (allocSize <= 0)\r
+                {\r
+                    trees = null;\r
+                    return;\r
+                }\r
+\r
+                int len = trees.Length;\r
+                TreeNode[] nextTrees = new TreeNode[len * 2];\r
+                byte random;\r
+                for (int i = 0; i < len; i++)\r
+                {\r
+                    TreeNode node = null;\r
+                    random = mObjectSizeRandom[myId][nodeCount[0]];\r
+                    switch (random)\r
+                    {\r
+                        case OBJECT_16_BYTE:\r
+                            node = new TreeNode();\r
+                            break;\r
+                        case OBJECT_32_BYTE:\r
+                            node = new TreeNode32();\r
+                            break;\r
+                        case OBJECT_64_BYTE:\r
+                            node = new TreeNode64();\r
+                            break;\r
+                        case OBJECT_128_BYTE:\r
+                            node = new TreeNode128();\r
+                            break;\r
+                        case OBJECT_256_BYTE:\r
+                            node = new TreeNode256();\r
+                            break;\r
+                        case OBJECT_512_BYTE:\r
+                            node = new TreeNode512();\r
+                            break;\r
+                    }\r
+                    trees[i].left = node;\r
+                    nextTrees[2 * i] = node;\r
+                    allocSize -= mObjectSize[random];\r
+                    nodeCount[0]++;\r
+                    if (nodeCount[0] == mTotalNodeCount)\r
+                        nodeCount[0] = 0;\r
+\r
+                    random = mObjectSizeRandom[myId][nodeCount[0]];\r
+                    switch (random)\r
+                    {\r
+                        case OBJECT_16_BYTE:\r
+                            node = new TreeNode();\r
+                            break;\r
+                        case OBJECT_32_BYTE:\r
+                            node = new TreeNode32();\r
+                            break;\r
+                        case OBJECT_64_BYTE:\r
+                            node = new TreeNode64();\r
+                            break;\r
+                        case OBJECT_128_BYTE:\r
+                            node = new TreeNode128();\r
+                            break;\r
+                        case OBJECT_256_BYTE:\r
+                            node = new TreeNode256();\r
+                            break;\r
+                        case OBJECT_512_BYTE:\r
+                            node = new TreeNode512();\r
+                            break;\r
+                    }\r
+                    trees[i].right = node;\r
+                    nextTrees[2 * i + 1] = node;\r
+                    allocSize -= mObjectSize[random];\r
+                    nodeCount[0]++;\r
+                    if (nodeCount[0] == mTotalNodeCount)\r
+                        nodeCount[0] = 0;\r
+\r
+                    if (allocSize <= 0)\r
+                    {\r
+                        trees = null;\r
+                        break;\r
+                    }\r
+                }\r
+                trees = null;\r
+                trees = nextTrees;\r
+            }\r
+        }\r
+\r
+        private void makeTreesShortLive(TreeNode[] trees, int allocSize, int myId, int[] nodeCount)\r
+        {\r
+            int lifetimeLen = mLifetime[0].Length;\r
+            int[] curTreeIdx = new int[lifetimeLen];\r
+            int[] nextTreeIdx = new int[lifetimeLen];\r
+            TreeNode[][] curTrees = new TreeNode[lifetimeLen][];\r
+            TreeNode[][] nextTrees = new TreeNode[lifetimeLen][];\r
+            for (int i = 0; i < lifetimeLen; i++)\r
+            {\r
+                curTrees[i] = new TreeNode[1];\r
+                curTrees[i][0] = trees[i];\r
+                curTreeIdx[i] = 0;\r
+            }\r
+\r
+            while (true)\r
+            {\r
+                if (allocSize <= 0)\r
+                {\r
+                    trees = null;\r
+                    return;\r
+                }\r
+\r
+                byte rs = mObjectSizeRandom[myId][nodeCount[0]];\r
+                TreeNode node = null;\r
+                switch (rs)\r
+                {\r
+                    case OBJECT_16_BYTE:\r
+                        node = new TreeNode();\r
+                        break;\r
+                    case OBJECT_32_BYTE:\r
+                        node = new TreeNode32();\r
+                        break;\r
+                    case OBJECT_64_BYTE:\r
+                        node = new TreeNode64();\r
+                        break;\r
+                    case OBJECT_128_BYTE:\r
+                        node = new TreeNode128();\r
+                        break;\r
+                    case OBJECT_256_BYTE:\r
+                        node = new TreeNode256();\r
+                        break;\r
+                    case OBJECT_512_BYTE:\r
+                        node = new TreeNode512();\r
+                        break;\r
+                }\r
+\r
+                byte rl = mLifetimeRandom[myId][nodeCount[0]];\r
+                if (nextTrees[rl] == null)\r
+                {\r
+                    nextTrees[rl] = new TreeNode[curTrees[rl].Length << 1];\r
+                    nextTreeIdx[rl] = 0;\r
+                    nextTrees[rl][0] = node;\r
+                }\r
+                else\r
+                {\r
+                    nextTrees[rl][++nextTreeIdx[rl]] = node;\r
+                }\r
+                TreeNode parent = curTrees[rl][curTreeIdx[rl]];\r
+                if (parent.left == null)\r
+                {\r
+                    parent.left = node;\r
+                }\r
+                else\r
+                {\r
+                    parent.right = node;\r
+                    curTreeIdx[rl]++;\r
+                    if (curTreeIdx[rl] == curTrees[rl].Length)\r
+                    {\r
+                        curTrees[rl] = nextTrees[rl];\r
+                        nextTrees[rl] = null;\r
+                        curTreeIdx[rl] = 0;\r
+                    }\r
+                }\r
+\r
+                allocSize -= mObjectSize[rs];\r
+                nodeCount[0]++;\r
+                if (nodeCount[0] == mTotalNodeCount) nodeCount[0] = 0;\r
+            }\r
+        }\r
+\r
+        public bool allocTrace(int myId)\r
+        {\r
+            switch(myId) {\r
+                case 0:\r
+                    if (flag0) return false;\r
+                    else flag0 = true;\r
+                    break;\r
+                case 1:\r
+                    if (flag1) return false;\r
+                    else flag1 = true;\r
+                    break;\r
+                case 2:\r
+                    if (flag2) return false;\r
+                    else flag2 = true;\r
+                    break;\r
+                case 3:\r
+                    if (flag3) return false;\r
+                    else flag3 = true;\r
+                    break;\r
+            }\r
+            \r
+            // long-lived data\r
+            Log.Info(mTag, "Thread-" + myId + " ----- Build long lived trees -----");\r
+\r
+            LivedLink longLiveTreeLink = new LivedLink();\r
+            TreeNode[] trees = new TreeNode[mTreeCountParallel];\r
+            int[] nodeCount = new int[] { 0 };\r
+\r
+            for (int i = 0; i < mTreeCountParallel; i++)\r
+            {\r
+                TreeNode node = new TreeNode();\r
+                longLiveTreeLink.insertNode(node);\r
+                trees[i] = node;\r
+            }\r
+\r
+            makeTreesLongLive(trees, mLongLiveSmallObjectSize, myId, nodeCount);\r
+\r
+            trees = null;\r
+\r
+            Log.Info(mTag, "Thread-" + myId + " ----- Build long lived byte array -----");\r
+            int longLiveArrayCount = (int)(mLongLiveLargeObjectSize / mLargeObjectSize + 0.5);\r
+            if (longLiveArrayCount <= 0)\r
+                longLiveArrayCount = 1;\r
+            byte[][] longLiveByteArrays = new byte[longLiveArrayCount][];\r
+            for (int i = 0; i < longLiveArrayCount; i++)\r
+            {\r
+                longLiveByteArrays[i] = new byte[mLargeObjectSize];\r
+                for (int j = 0; j < mLargeObjectSize; j += 100)\r
+                    longLiveByteArrays[i][j] = (byte)0xff;\r
+            }\r
+\r
+            // stress test\r
+            Log.Info(mTag, "Thread-" + myId + " ----- Stress test -----");\r
+            //Debug.MemoryInfo memInfo = new Debug.MemoryInfo();\r
+\r
+            int lifetimeLen = mLifetime[0].Length;\r
+            TreeNode[][] shortLiveTrees = new TreeNode[lifetimeLen][];\r
+            for (int i = 0; i < lifetimeLen; i++)\r
+            {\r
+                shortLiveTrees[i] = new TreeNode[lifetimeLen];\r
+            }\r
+\r
+            byte[][] shortLiveByteArray = null;\r
+            char[][] shortLiveCharArray = null;\r
+            int[][] shortLiveIntArray = null;\r
+            long[][] shortLiveLongArray = null;\r
+\r
+            nodeCount[0] = 0;\r
+            int round = 0;\r
+\r
+            for (int iter = 0; iter < mIterNum; iter++)\r
+            {\r
+                //Log.Info(mTag, "Run " + myId + " - iter : " + iter);\r
+                if (mOutOfMemory)\r
+                    break;\r
+                int[] allocIdx = new int[] { 0, 0, 0, 0 };\r
+\r
+                if (mLargeArrayLength[0] != 0)\r
+                    shortLiveByteArray = new byte[mLargeArrayLength[0]][];\r
+                if (mLargeArrayLength[1] != 0)\r
+                    shortLiveCharArray = new char[mLargeArrayLength[1]][];\r
+                if (mLargeArrayLength[2] != 0)\r
+                    shortLiveIntArray = new int[mLargeArrayLength[2]][];\r
+                if (mLargeArrayLength[3] != 0)\r
+                    shortLiveLongArray = new long[mLargeArrayLength[3]][];\r
+\r
+                int treeCount = 0;\r
+                while (treeCount < mShortLiveTreeCount)\r
+                {\r
+                    int treesIdx = round % lifetimeLen;\r
+                    round++;\r
+                    for (int i = 0; i < lifetimeLen; i++)\r
+                    {\r
+                        TreeNode node = new TreeNode();\r
+                        shortLiveTrees[treesIdx][i] = node;\r
+                    }\r
+                    makeTreesShortLive(shortLiveTrees[treesIdx], mBucketSize, myId, nodeCount);\r
+\r
+                    for (int i = 0; i < lifetimeLen; i++)\r
+                    {\r
+                        int idx = (treesIdx - i + lifetimeLen) % lifetimeLen;\r
+                        shortLiveTrees[idx][i] = null;\r
+                    }\r
+\r
+                    if ((mLargeArrayLength[0] > 0) && ((treeCount % mLargeArrayInter[0]) == 0))\r
+                    {\r
+                        for (int n = 0; n < mLargeArrayNum[0]; n++)\r
+                            shortLiveByteArray[allocIdx[0] + n] = new byte[mLargeObjectSize];\r
+                        allocIdx[0] += mLargeArrayNum[0];\r
+                    }\r
+\r
+                    if ((mLargeArrayLength[1] > 0) && ((treeCount % mLargeArrayInter[1]) == 0))\r
+                    {\r
+                        for (int n = 0; n < mLargeArrayNum[1]; n++)\r
+                            shortLiveCharArray[allocIdx[1] + n] = new char[mLargeObjectSize / 2];\r
+                        allocIdx[1] += mLargeArrayNum[1];\r
+                    }\r
+\r
+                    if ((mLargeArrayLength[2] > 0) && ((treeCount % mLargeArrayInter[2]) == 0))\r
+                    {\r
+                        for (int n = 0; n < mLargeArrayNum[2]; n++)\r
+                            shortLiveIntArray[allocIdx[2] + n] = new int[mLargeObjectSize / 4];\r
+                        allocIdx[2] += mLargeArrayNum[2];\r
+                    }\r
+\r
+                    if ((mLargeArrayLength[3] > 0) && ((treeCount % mLargeArrayInter[3]) == 0))\r
+                    {\r
+                        for (int n = 0; n < mLargeArrayNum[3]; n++)\r
+                            shortLiveLongArray[allocIdx[3] + n] = new long[mLargeObjectSize / 8];\r
+                        allocIdx[3] += mLargeArrayNum[3];\r
+                    }\r
+\r
+                    freeArrays(shortLiveByteArray, shortLiveCharArray, shortLiveIntArray,\r
+                            shortLiveLongArray, allocIdx, treeCount);\r
+\r
+                    treeCount++;\r
+                }\r
+\r
+                if (myId == 0)\r
+                {\r
+                    //Debug.getMemoryInfo(memInfo);\r
+                    //mHeapFootprint[iter] = memInfo.dalvikPss;\r
+                    mHeapFootprint[iter] = (int)GC.GetGCMemoryInfo().HeapSizeBytes;\r
+                    //if (getRuntimeStatMethod != null)\r
+                    //mHeapBytesAllocated[iter] = (GetRuntimeStat("gc.bytes-allocated") - GetRuntimeStat("gc.bytes-freed")) / 1024;\r
+                    //else\r
+                    mHeapBytesAllocated[iter] = (GC.GetTotalMemory(false) / 1024);\r
+\r
+                    //Message m = mActivity.getHandler().obtainMessage(MainActivity.BenchmarkProgress);\r
+                    //m.arg1 = iter + 1;\r
+                    //mActivity.getHandler().sendMessage(m);\r
+\r
+                    text.Text = (((iter + 1) *100) / mIterNum) + "%";\r
+                    Log.Info(mTag, text.Text);\r
+                    \r
+                }\r
+            }\r
+\r
+            if (longLiveTreeLink.TreeHead.TreeNode != null\r
+             && longLiveByteArrays[0][100] == (byte)0xff\r
+             && longLiveByteArrays[longLiveArrayCount - 1][200] == (byte)0xff)\r
+            {\r
+                mEndTime[myId] = (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;\r
+                mElapseTime[myId] = mEndTime[myId] - mStartTime[myId];\r
+                return true;\r
+            }\r
+\r
+            return false;\r
+        }\r
+\r
+        public class BenchThread\r
+        {\r
+            private static int myId;\r
+            private static GCTest gcParent;\r
+            public ThreadStart thread;\r
+\r
+            public BenchThread(int id, GCTest parent)\r
+            {\r
+                myId = id;\r
+                gcParent = parent;\r
+                thread += Run;\r
+            }\r
+\r
+            private void Run()\r
+            {\r
+                gcParent.mElapseTime[myId] = 0;\r
+                gcParent.mStartTime[myId] = (long)(DateTime.UtcNow - gcParent.Jan1st1970).TotalMilliseconds;\r
+                try\r
+                {\r
+                    if (!gcParent.allocTrace(myId))\r
+                    {\r
+                        Log.Info(mTag, "Error in thread-" + myId);\r
+                    }\r
+                }\r
+                catch (OutOfMemoryException e)\r
+                {\r
+                    gcParent.mOutOfMemory = true;\r
+                    Log.Info(mTag, "Thread-" + myId + " meets OutOfMemory");\r
+                    //Message m = mActivity.GetHandler().ObtainMessage(MainActivity.BenchmarkOutOfMemoryError);\r
+                    //m.Arg1 = myId;\r
+                    //mActivity.GetHandler().SendMessage(m);\r
+                }\r
+            }\r
+        }\r
+\r
+        public void start()\r
+        {\r
+            /*if (getRuntimeStatMethod == null)\r
+            {\r
+                try\r
+                {\r
+                    Type c = Type.GetType("Android.OS.Debug");\r
+                    if (c != null)\r
+                        getRuntimeStatMethod = c.GetMethod("GetRuntimeStat", new Type[] { typeof(string) });\r
+                }\r
+                catch (TypeLoadException e)\r
+                {\r
+                    Log.Warn(mTag, "Cannot find Android.OS.Debug class");\r
+                }\r
+                catch (MissingMethodException e)\r
+                {\r
+                    Log.Warn(mTag, "No GetRuntimeStat method in Android.OS.Debug");\r
+                }\r
+            }*/\r
+\r
+            var info1_1 = GC.GetGCMemoryInfo(GCKind.Ephemeral);\r
+            Log.Info(mTag, "Generation: " + info1_1.Generation);\r
+\r
+            var info2_1 = GC.GetGCMemoryInfo();\r
+            Log.Info(mTag, "Generation: " + info2_1.Generation);\r
+\r
+            mElapseTime = new long[mThreadNum];\r
+            mStartTime = new long[mThreadNum];\r
+            mEndTime = new long[mThreadNum];\r
+            mHeapFootprint = new int[mIterNum];\r
+            mHeapBytesAllocated = new long[mIterNum];\r
+            isArt = false;\r
+            //string vmVersion = System.getProperty("java.vm.version");\r
+            //isArt = !string.IsNullOrEmpty(vmVersion) && vmVersion.StartsWith("2");\r
+            //string androidVersion = Build.VERSION.RELEASE;\r
+            //string deviceName = Build.MODEL;\r
+            //string deviceDesc = deviceName + "/" + "android-" + androidVersion + ", runtime: " + (isArt ? "ART" : "Dalvik");\r
+            //mTotalGcCount = info2_1.Index; //GetRuntimeStat("gc.gc-count");\r
+            //mTotalGcTime = (long)info2_1.PauseDurations[0].TotalMilliseconds; //GetRuntimeStat("gc.gc-time");\r
+            //mTotalBlockingGcCount = info1.Index; //GetRuntimeStat("gc.blocking-count");\r
+            //mTotalBlockingGcTime = info1.PauseDurations[0].Milliseconds; //GetRuntimeStat("gc.blocking-gc-time");\r
+            if (isArt)\r
+            {\r
+                mGcCauseCount = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 };\r
+            }\r
+            else\r
+            {\r
+                mGcCauseCount = new int[] { 0, 0, 0, 0 };\r
+            }\r
+\r
+            mWorkloadComplete = false;\r
+            //ClearLogcat();\r
+            //Thread logcat = new Thread(new ThreadStart(readLogcat));\r
+            //logcat.Start();\r
+\r
+            mOutOfMemory = false;\r
+            mTestThreads = new BenchThread[mThreadNum];\r
+            for (int i = 1; i < mThreadNum; i++)\r
+            {\r
+                mTestThreads[i] = new BenchThread(i, this);\r
+                //mThreads[i] = new Thread(mTestThreads[i].thread);\r
+                if (i == 1)\r
+                {\r
+                    t1 = new Thread(mTestThreads[i].thread);\r
+                    t1.Start();\r
+                }\r
+                else if (i == 2)\r
+                {\r
+                    t2 = new Thread(mTestThreads[i].thread);\r
+                    t2.Start();\r
+                }\r
+                else if (i == 3)\r
+                {\r
+                    t3 = new Thread(mTestThreads[i].thread);\r
+                    t3.Start();\r
+                }\r
+                Thread.Sleep(100);\r
+            }\r
+\r
+            mElapseTime[0] = 0;\r
+            mStartTime[0] = (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;\r
+            try\r
+            {\r
+                if (!allocTrace(0))\r
+                {\r
+                    Log.Info(mTag, "Error in thread-0");\r
+                }\r
+            }\r
+            catch (OutOfMemoryException e)\r
+            {\r
+                mOutOfMemory = true;\r
+                Log.Info(mTag, "Thread-0 meets OutOfMemory");\r
+\r
+                //Message m = mActivity.GetHandler().ObtainMessage(MainActivity.BenchmarkOutOfMemoryError);\r
+                //m.Arg1 = 0;\r
+                //mActivity.GetHandler().SendMessage(m);\r
+            }\r
+            mEndTime[0] = (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;\r
+            mElapseTime[0] = mEndTime[0] - mStartTime[0];\r
+\r
+            for (int i = 1; i < mThreadNum; i++)\r
+            {\r
+                try\r
+                {\r
+                    //mThreads[i].Join();\r
+                    if (i == 1)\r
+                    {\r
+                        t1.Join();\r
+                    }\r
+                    else if (i == 2)\r
+                    {\r
+                        t2.Join();\r
+                    }\r
+                    else if (i == 3)\r
+                    {\r
+                        t3.Join();\r
+                    }\r
+                    Thread.Sleep(100);\r
+                }\r
+                catch (ThreadInterruptedException e)\r
+                {\r
+                    Log.Info(mTag, "Waiting thread " + i + " finish interrupted by " + e.Message);\r
+                }\r
+            }\r
+            Thread.Sleep(1000);\r
+            mWorkloadComplete = true;\r
+            GC.Collect();\r
+            GC.WaitForPendingFinalizers();\r
+\r
+            try\r
+            {\r
+                //logcat.Join();\r
+            }\r
+            catch (ThreadInterruptedException e)\r
+            {\r
+                Log.Info(mTag, "Waiting logcat finish interrupted by " + e.Message);\r
+            }\r
+            if (mOutOfMemory)\r
+            {\r
+                try\r
+                {\r
+                    if (fileOutput != null)\r
+                    {\r
+                        fileOutput.WriteLine("\nOutOfMemory! Please config profile or " + "Java Runtime and run again!\n");\r
+                        fileOutput.Flush();\r
+                        fileOutput.Close();\r
+                    }\r
+                }\r
+                catch (IOException e)\r
+                {\r
+                    Log.Info(mTag, "Cannot write to /tmp/TizenGCTest-result.txt" + e.Message);\r
+                }\r
+            }\r
+            else\r
+            {\r
+                var info1_2 = GC.GetGCMemoryInfo(GCKind.Ephemeral);\r
+                print1(info1_2);\r
+\r
+                var info2_2 = GC.GetGCMemoryInfo();\r
+                print2(info2_2, info2_1);\r
+\r
+                String pauseDesc = "";\r
+                /*String[] causes;\r
+                if (isArt)\r
+                    causes = GC_CAUSE_ART;\r
+                else\r
+                    causes = GC_CAUSE_DALVIK;\r
+                for (int i = 0; i < causes.Length; i++)\r
+                {\r
+                    Log.Info(mTag, mGcCauseCount[i] + " GCs for " + causes[i] + " from logcat");\r
+                    gcDesc += "\n" + mGcCauseCount[i] + " GCs for " + causes[i] + " from logcat";\r
+                }*/\r
+                /*for (int i = 0; i < mGcPauseTime.Length; i++)\r
+                {\r
+                    String gc_time = "GC-" + i + ": " + mGcCause[i] + ", pause "\r
+                            + mGcPauseTime[i] + "ms, total " + mGcTotalTime[i] + "ms";\r
+                    pauseDesc += "\n" + gc_time;\r
+                    Log.Info(mTag, gc_time);\r
+                }*/\r
+                try\r
+                {\r
+                    if (fileOutput != null)\r
+                    {\r
+                        //fileOutput.WriteLine("\nDevice config:\n\t" + deviceDesc);\r
+                        fileOutput.WriteLine("\nDevice config:\n\t");\r
+                        //fileOutput.WriteLine(completionTime);\r
+                        fileOutput.WriteLine("Heap status after each iteration (footprint, bytes allocated):\n");\r
+                        for (int j = 0; j < mIterNum; j++)\r
+                        {\r
+                            fileOutput.WriteLine("\t" + mHeapFootprint[j] + " kB, " + mHeapBytesAllocated[j] + " kB");\r
+                        }\r
+                        //fileOutput.WriteLine(gcDesc);\r
+                        fileOutput.WriteLine(pauseDesc);\r
+                        fileOutput.Flush();\r
+                        fileOutput.Close();\r
+                    }\r
+                }\r
+                catch (IOException e)\r
+                {\r
+                    Log.Info(mTag, "Cannot write to /tmp/TizenGCTest-result.txt " + e.Message);\r
+                }\r
+                /*if (mActivity != null)\r
+                {\r
+                    Message m = mActivity.getHandler().obtainMessage(MainActivity.BenchmarkDone);\r
+                    Bundle b = new Bundle();\r
+                    b.putBoolean(ResultActivity.KEY_VM_TYPE, isArt);\r
+                    b.putString("device", deviceDesc);\r
+                    b.putLongArray(ResultActivity.KEY_THREAD_COMPLETE_TIME, mElapseTime);\r
+                    b.putLong(ResultActivity.KEY_WORKLOAD_COMPLETE_TIME, maxTime);\r
+                    b.putLongArray(ResultActivity.KEY_BYTES_LIVING, mHeapBytesAllocated);\r
+                    b.putIntArray(ResultActivity.KEY_HEAP_FOOTPRINT, mHeapFootprint);\r
+                    b.putFloatArray(ResultActivity.KEY_GC_PAUSE_TIME, mGcPauseTime);\r
+                    b.putFloatArray(ResultActivity.KEY_GC_COMPLETION_TIME, mGcTotalTime);\r
+                    b.putStringArray(ResultActivity.KEY_GC_CAUSE, mGcCause);\r
+                    m.setData(b);\r
+                    mActivity.getHandler().sendMessage(m);\r
+                }*/\r
+            }\r
+            mElapseTime = null;\r
+            mHeapFootprint = null;\r
+            mHeapBytesAllocated = null;\r
+            mGcPauseTime = null;\r
+            mGcTotalTime = null;\r
+            mGcCause = null;\r
+\r
+            clearInitData();\r
+        }\r
+\r
+        private void print1(GCMemoryInfo info2)\r
+        {\r
+            mTotalGcCount = info2.Index; //GetRuntimeStat("gc.gc-count") - mTotalGcCount;\r
+            mTotalGcTime = (long)info2.PauseDurations[0].TotalMilliseconds; //GetRuntimeStat("gc.gc-time") - mTotalGcTime;\r
+                                                                            //mTotalBlockingGcCount = GetRuntimeStat("gc.blocking-gc-count") - mTotalBlockingGcCount;\r
+                                                                            //mTotalBlockingGcTime = info2.PauseDurations[0].Milliseconds - info1.PauseDurations[0].Milliseconds; //GetRuntimeStat("gc.blocking-gc-time") - mTotalBlockingGcTime;\r
+            print(info2);\r
+        }\r
+        private void print2(GCMemoryInfo info2, GCMemoryInfo info1)\r
+        {\r
+            mTotalGcCount = info2.Index - info1.Index; //GetRuntimeStat("gc.gc-count") - mTotalGcCount;\r
+            mTotalGcTime = (long)info2.PauseDurations[0].TotalMilliseconds - (long)info1.PauseDurations[0].TotalMilliseconds; //GetRuntimeStat("gc.gc-time") - mTotalGcTime;\r
+                                                                                                                              //mTotalBlockingGcCount = GetRuntimeStat("gc.blocking-gc-count") - mTotalBlockingGcCount;\r
+                                                                                                                              //mTotalBlockingGcTime = info2.PauseDurations[0].Milliseconds - info1.PauseDurations[0].Milliseconds; //GetRuntimeStat("gc.blocking-gc-time") - mTotalBlockingGcTime;\r
+            print(info2);\r
+        }\r
+\r
+        private void print(GCMemoryInfo info2)\r
+        {\r
+            long maxTime = 0;\r
+            //string completionTime = "";\r
+            for (int i = 0; i < mThreadNum; i++)\r
+            {\r
+                if (maxTime < mElapseTime[i])\r
+                {\r
+                    maxTime = mElapseTime[i];\r
+                }\r
+                Log.Info(mTag, "Thread-" + i + " completion time: " + mElapseTime[i].ToString() + "ms");\r
+                //completionTime += "Thread-" + i + " completion time: " + mElapseTime[i].ToString() + "ms\n";\r
+            }\r
+\r
+            String totalTime = "TizenGCTest is done by " + mThreadNum\r
+                    + " threads. Completion time is " + maxTime + "ms";\r
+            Log.Info(mTag, totalTime);\r
+            //completionTime += totalTime + "\n";\r
+            //String gcDesc = "Total GC count: " + mTotalGcCount;\r
+            //gcDesc += "\nTotal GC time: " + mTotalGcTime + "ms";\r
+            //gcDesc += "\nTotal Blocking GC count: " + mTotalBlockingGcCount;\r
+            //gcDesc += "\nTotal Blocking GC time: " + mTotalBlockingGcTime + "ms";\r
+            Log.Info(mTag, "Total GC count: " + mTotalGcCount);\r
+            Log.Info(mTag, "Total GC time: " + mTotalGcTime + "ms");\r
+            //Log.Info(mTag, "Total Blocking GC count: " + mTotalBlockingGcCount);\r
+            //Log.Info(mTag, "Total Blocking GC time: " + mTotalBlockingGcTime + "ms");\r
+\r
+            long totalAfter = 0;\r
+            long totalBefore = 0;\r
+            foreach (var ginfo in info2.GenerationInfo)\r
+            {\r
+                totalAfter += ginfo.SizeAfterBytes;\r
+                totalBefore += ginfo.SizeBeforeBytes;\r
+            }\r
+            Log.Info(mTag, "HeapSizeBytes: " + info2.HeapSizeBytes + ", " + GC.GetTotalMemory(false) + " / GenInfo After : " + totalAfter + ", Before : " + totalBefore);\r
+            Log.Info(mTag, "TotalCommittedBytes: " + info2.TotalCommittedBytes);\r
+            Log.Info(mTag, "Generation: " + info2.Generation);\r
+            Log.Info(mTag, "TotalAvailableMemoryBytes: " + info2.TotalAvailableMemoryBytes);\r
+            Log.Info(mTag, "FinalizationPendingCount: " + info2.FinalizationPendingCount);\r
+            Log.Info(mTag, "Concurrent: " + info2.Concurrent);\r
+            Log.Info(mTag, "Compacted: " + info2.Compacted);\r
+            Log.Info(mTag, "Index: " + info2.Index);\r
+            Log.Info(mTag, "FragmentedBytes: " + info2.FragmentedBytes);\r
+            Log.Info(mTag, "HighMemoryLoadThresholdBytes: " + info2.HighMemoryLoadThresholdBytes);\r
+            Log.Info(mTag, "MemoryLoadBytes: " + info2.MemoryLoadBytes);\r
+        }\r
+\r
+        public void stop()\r
+        {\r
+        }\r
+\r
+        private void ClearLogcat()\r
+        {\r
+            try\r
+            {\r
+                Process process = Process.Start(new ProcessStartInfo("dlogutil", "-c"));\r
+                try\r
+                {\r
+                    process.WaitForExit();\r
+                }\r
+                catch (ThreadInterruptedException e)\r
+                {\r
+                    Log.Error(mTag, "Clear logcat fails, interrupted by " + e.Message);\r
+                }\r
+                Log.Info(mTag, "Clear logcat before workload running");\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                Log.Error(mTag, "Clear logcat fails, " + e.Message);\r
+            }\r
+        }\r
+\r
+        private void readLogcat()\r
+        {\r
+            string cmd = "dlogutil TizenGCTest STDOUT STDERR";\r
+            List<float> gcPauseTimeList = new List<float>();\r
+            List<float> gcTotalTimeList = new List<float>();\r
+            List<string> gcCauseList = new List<string>();\r
+            int loggerGcCount = 0;\r
+            try\r
+            {\r
+                Process process = Process.Start(new ProcessStartInfo("cmd", "/c " + cmd) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false });\r
+                Stream inStream = process.StandardOutput.BaseStream;\r
+                Stream errorStream = process.StandardError.BaseStream;\r
+                int error = errorStream.ReadByte();\r
+                if (error > 0)\r
+                {\r
+                    byte[] errorMsg = new byte[error];\r
+                    errorStream.Read(errorMsg, 0, error);\r
+                    Log.Info(mTag, "executing logcat return error message: " + Encoding.UTF8.GetString(errorMsg));\r
+                }\r
+                StreamReader inReader = new StreamReader(inStream);\r
+                string line;\r
+                while (!mWorkloadComplete && (line = inReader.ReadLine()) != null)\r
+                {\r
+                    if (mWorkloadComplete)\r
+                        break;\r
+\r
+                    int idx = line.IndexOf(": ");\r
+                    if (idx == -1)\r
+                        continue;\r
+                    line = line.Substring(idx + 2);\r
+                    bool isGCLog = false;\r
+                    String gcCause = "";\r
+                    if (isArt)\r
+                    {\r
+                        for (int i = 0; i < GC_CAUSE_ART.Length; i++)\r
+                        {\r
+                            if ((line.Contains("mark sweep") || line.Contains("marksweep")\r
+                                    || line.Contains("mark compact"))\r
+                                    && line.StartsWith(GC_CAUSE_ART[i]))\r
+                            {\r
+                                isGCLog = true;\r
+                                mGcCauseCount[i]++;\r
+                                idx = line.IndexOf(" GC ");\r
+                                if (idx > 0)\r
+                                    gcCause = line.Substring(0, idx);\r
+                                else\r
+                                {\r
+                                    Log.Info(mTag, "Error: cannot find ' GC ' from this log, " + line);\r
+                                    continue;\r
+                                }\r
+                                break;\r
+                            }\r
+                        }\r
+                    }\r
+                    else\r
+                    {\r
+                        for (int i = 0; i < GC_CAUSE_DALVIK.Length; i++)\r
+                        {\r
+                            if (line.StartsWith(GC_CAUSE_DALVIK[i]))\r
+                            {\r
+                                isGCLog = true;\r
+                                mGcCauseCount[i]++;\r
+                                gcCause = GC_CAUSE_DALVIK[i];\r
+                                break;\r
+                            }\r
+                        }\r
+                    }\r
+                    if (!isGCLog)\r
+                        continue;\r
+                    loggerGcCount++;\r
+\r
+                    int idx0 = line.IndexOf("paused ");\r
+                    int idx1 = line.IndexOf(" total ");\r
+                    if (idx0 == -1 || idx1 == -1)\r
+                    {\r
+                        Log.Info(mTag, "Cannot find pause or total completion time from the GC log "\r
+                                + line);\r
+                        continue;\r
+                    }\r
+\r
+                    String pauseTimeStr = line.Substring(idx0 + 7, idx1);\r
+                    String totalTimeStr = line.Substring(idx1 + 7);\r
+                    float completeTime = 0.0f;\r
+                    float pauseTime = 0.0f;\r
+                    idx = totalTimeStr.IndexOf("ms");\r
+                    int timeToSec = 1000;\r
+                    if (idx == -1)\r
+                    {\r
+                        idx = totalTimeStr.IndexOf("us");\r
+                        timeToSec = 1000000;\r
+                    }\r
+                    if (idx == -1)\r
+                    {\r
+                        idx = totalTimeStr.IndexOf("s");\r
+                        timeToSec = 1;\r
+                    }\r
+                    if (idx == -1)\r
+                    {\r
+                        Log.Info(mTag, "Cannot identify total complete time format, " + line);\r
+                        continue;\r
+                    }\r
+                    completeTime = float.Parse(totalTimeStr.Substring(0, idx)) * 1000 / timeToSec;\r
+                    string[] pauseTimes = pauseTimeStr.Split(new string[] { "+ ", ", " }, StringSplitOptions.RemoveEmptyEntries);\r
+                    for (int i = 0; i < pauseTimes.Length; i++)\r
+                    {\r
+                        string tmp = pauseTimes[i];\r
+                        idx = tmp.IndexOf("ms");\r
+                        if (idx > 0)\r
+                        {\r
+                            pauseTime += float.Parse(tmp.Substring(0, idx));\r
+                        }\r
+                        else\r
+                        {\r
+                            idx = tmp.IndexOf("us");\r
+                            if (idx > 0)\r
+                            {\r
+                                pauseTime += float.Parse(tmp.Substring(0, idx)) / 1000;\r
+                            }\r
+                            else\r
+                            {\r
+                                Log.Info(mTag, "Cannot identify pause time format, " + line);\r
+                                continue;\r
+                            }\r
+                        }\r
+                    }\r
+                    gcPauseTimeList.Add(pauseTime);\r
+                    gcTotalTimeList.Add(completeTime);\r
+                    gcCauseList.Add(gcCause);\r
+                }\r
+                errorStream.Close();\r
+                inReader.Close();\r
+                process.Kill();\r
+                Log.Info(mTag, "workload complete, stop reading logcat");\r
+                mGcTotalTime = new float[loggerGcCount];\r
+                mGcPauseTime = new float[loggerGcCount];\r
+                mGcCause = new String[loggerGcCount];\r
+                for (int i = 0; i < gcPauseTimeList.Count; i++)\r
+                {\r
+                    mGcTotalTime[i] = gcTotalTimeList[i];\r
+                    mGcPauseTime[i] = gcPauseTimeList[i];\r
+                    mGcCause[i] = gcCauseList[i];\r
+                }\r
+            }\r
+            catch (OutOfMemoryException e)\r
+            {\r
+                mOutOfMemory = true;\r
+                Log.Info(mTag, "logcat thread meets OutOfMemory");\r
+                //Message m = mActivity.getHandler().obtainMessage(MainActivity.BenchmarkOutOfMemoryError);\r
+                //m.arg1 = -1;\r
+                //mActivity.getHandler().sendMessage(m);\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                Log.Info(mTag, "Cannot run logcat " + e.Message);\r
+            }\r
+            gcPauseTimeList.Clear();\r
+            gcPauseTimeList = null;\r
+            gcTotalTimeList.Clear();\r
+            gcTotalTimeList = null;\r
+            gcCauseList.Clear();\r
+            gcCauseList = null;\r
+            Log.Info(mTag, "logcat done");\r
+        }\r
+\r
+        //private static MethodInfo getRuntimeStatMethod = null;\r
+        /*private long GetRuntimeStat(string statName)\r
+        {\r
+            if (getRuntimeStatMethod == null)\r
+            {\r
+                return 0;\r
+            }\r
+            string valueStr;\r
+            try\r
+            {\r
+                valueStr = (string)getRuntimeStatMethod.Invoke(null, new object[] { statName });\r
+            }\r
+            catch (Exception e)\r
+            {\r
+                Log.Warn(mTag, "Failed to invoke GetRuntimeStat");\r
+                return 0;\r
+            }\r
+            if (valueStr != null)\r
+            {\r
+                return long.Parse(valueStr);\r
+            }\r
+            return 0;\r
+        }*/\r
+    }\r
+}\r
diff --git a/tests/GC/TizenGCTest/Profile.cs b/tests/GC/TizenGCTest/Profile.cs
new file mode 100755 (executable)
index 0000000..70b4746
--- /dev/null
@@ -0,0 +1,383 @@
+using System;\r
+using System.Collections;\r
+using System.Collections.Generic;\r
+using System.IO;\r
+using System.Linq;\r
+using System.Text;\r
+using System.Threading.Tasks;\r
+using System.Xml;\r
+using Tizen.Content.MediaContent;\r
+using Tizen;\r
+using static Tizen.NUI.Shader;\r
+using static TizenGCTest.Profile;\r
+using System.Xml.Linq;\r
+using System.Text.RegularExpressions;\r
+using Tizen.Pims.Contacts.ContactsViews;\r
+using static Tizen.Applications.ApplicationInfoFilter;\r
+\r
+namespace TizenGCTest\r
+{\r
+    public class Profile\r
+    {\r
+        private const String mTag = "TizenGCTest";\r
+        public class ProfileData\r
+        {\r
+            private int mId;\r
+            private string mName;\r
+            private int mTotalSize;\r
+            private int mBucketSize;\r
+            private int mLosThreshold;\r
+            private float[] mSizeDist;\r
+            private float[] mLosElementDist;\r
+            private float[][] mLifetime;\r
+            private float[] mLifetime2;\r
+            private bool mThreadMode;\r
+            private int mThreadNum;\r
+            private int mIterationNum;\r
+\r
+            public ProfileData(int id, string name)\r
+            {\r
+                mId = id;\r
+                mName = name;\r
+            }\r
+\r
+            public int GetId()\r
+            {\r
+                return mId;\r
+            }\r
+\r
+            public string GetName()\r
+            {\r
+                return mName;\r
+            }\r
+\r
+            public int GetTotalSize()\r
+            {\r
+                return mTotalSize;\r
+            }\r
+\r
+            public int GetBucketSize()\r
+            {\r
+                return mBucketSize;\r
+            }\r
+\r
+            public int GetLosThreshold()\r
+            {\r
+                return mLosThreshold;\r
+            }\r
+\r
+            public float[] GetSizeDistribution()\r
+            {\r
+                return mSizeDist;\r
+            }\r
+\r
+            public float[] GetLosElementDist()\r
+            {\r
+                return mLosElementDist;\r
+            }\r
+\r
+            public float[][] GetLifetime()\r
+            {\r
+                return mLifetime;\r
+            }\r
+\r
+            public float[] GetLifetime2()\r
+            {\r
+                return mLifetime2;\r
+            }\r
+\r
+            public bool GetThreadMode()\r
+            {\r
+                return mThreadMode;\r
+            }\r
+\r
+            public int GetThreadNum()\r
+            {\r
+                return mThreadMode ? 1 : mThreadNum;\r
+            }\r
+\r
+            public int GetIterationNum()\r
+            {\r
+                return mIterationNum;\r
+            }\r
+\r
+            public void SetName(string name)\r
+            {\r
+                mName = name;\r
+            }\r
+\r
+            public void SetTotalSize(int totalSize)\r
+            {\r
+                mTotalSize = totalSize;\r
+            }\r
+\r
+            public void SetBucketSize(int bucketSize)\r
+            {\r
+                mBucketSize = bucketSize;\r
+            }\r
+\r
+            public void SetLosThreshold(int losThreshold)\r
+            {\r
+                mLosThreshold = losThreshold;\r
+            }\r
+\r
+            public void SetSizeDistribution(float[] sizeDist)\r
+            {\r
+                mSizeDist = sizeDist;\r
+            }\r
+\r
+            public void SetLosElementDist(float[] losElementDist)\r
+            {\r
+                mLosElementDist = losElementDist;\r
+            }\r
+\r
+            public void SetLifetime(float[][] lifetime)\r
+            {\r
+                mLifetime = lifetime;\r
+            }\r
+\r
+            public void SetLifetime2(float[] lifetime)\r
+            {\r
+                mLifetime2 = lifetime;\r
+            }\r
+\r
+            public void SetThreadMode(bool singleThread)\r
+            {\r
+                mThreadMode = singleThread;\r
+            }\r
+\r
+            public void SetThreadNum(int threadNum)\r
+            {\r
+                mThreadNum = mThreadMode ? 1 : threadNum;\r
+            }\r
+\r
+            public void SetIterationNum(int iterationNum)\r
+            {\r
+                mIterationNum = iterationNum;\r
+            }\r
+        }\r
+\r
+        private static Profile instance_ = null;\r
+        public bool mInit = false;\r
+        int mCurrentProfileId = -1;\r
+        public List<ProfileData> mData = null;\r
+\r
+        private Profile()\r
+        {\r
+            mCurrentProfileId = -1;\r
+            mInit = false;\r
+        }\r
+\r
+        public static Profile getInstance()\r
+        {\r
+            if (instance_ == null)\r
+            {\r
+                instance_ = new Profile();\r
+            }\r
+            return instance_;\r
+        }\r
+\r
+        private bool InitProfileData(String input)\r
+        {\r
+            ProfileData newProfile = null;\r
+            XmlReaderSettings settings = new XmlReaderSettings();\r
+            settings.DtdProcessing = DtdProcessing.Parse;\r
+            XmlReader parser = XmlReader.Create(input, settings);\r
+\r
+            try\r
+            {\r
+                float[] floatValues = null;\r
+                string itemName, name;\r
+                int idx0 = -1, idx1 = 0;\r
+                while (parser.Read())\r
+                {\r
+                    switch (parser.NodeType)\r
+                    {\r
+                        case XmlNodeType.Element:\r
+\r
+                            name = parser.Name;\r
+                            if (name.Equals("profile"))\r
+                            {\r
+                                newProfile = new ProfileData(int.Parse(parser.GetAttribute(0)), parser.GetAttribute(1));\r
+                                //Log.Info(mTag, "profile : " + parser.GetAttribute(0) + " " + parser.GetAttribute(1));\r
+                            }\r
+                            else if (name.Equals("item"))\r
+                            {\r
+                                itemName = parser.GetAttribute(0);\r
+                                if (itemName.Equals("total_size"))\r
+                                {\r
+                                    newProfile.SetTotalSize(int.Parse(parser.ReadElementContentAsString()));\r
+                                    //Log.Info(mTag, "item - total_size : " + newProfile.GetTotalSize());\r
+                                }\r
+                                else if (itemName.Equals("bucket_size"))\r
+                                {\r
+                                    newProfile.SetBucketSize(int.Parse(parser.ReadElementContentAsString()));\r
+                                    //Log.Info(mTag, "item - bucket_size : " + newProfile.GetBucketSize());\r
+                                }\r
+                                else if (itemName.Equals("los_threshold"))\r
+                                {\r
+                                    newProfile.SetLosThreshold(int.Parse(parser.ReadElementContentAsString()));\r
+                                    //Log.Info(mTag, "item - los_threshold : " + newProfile.GetLosThreshold());\r
+                                }\r
+                                else if (itemName.Equals("thread-mode"))\r
+                                {\r
+                                    newProfile.SetThreadMode(int.Parse(parser.ReadElementContentAsString()) == 1);\r
+                                    //Log.Info(mTag, "item - thread-mode : " + newProfile.GetThreadMode());\r
+                                }\r
+                                else if (itemName.Equals("thread-num"))\r
+                                {\r
+                                    newProfile.SetThreadNum(int.Parse(parser.ReadElementContentAsString()));\r
+                                    //Log.Info(mTag, "item - thread-num : " + newProfile.GetThreadNum());\r
+                                }\r
+                                else if (itemName.Equals("iteration-times"))\r
+                                {\r
+                                    newProfile.SetIterationNum(int.Parse(parser.ReadElementContentAsString()));\r
+                                    //Log.Info(mTag, "item - iteration-times : " + newProfile.GetIterationNum());\r
+                                }\r
+                            }\r
+                            else if (name.Equals("float-array-2d"))\r
+                            {\r
+                                if (parser.GetAttribute(0).Equals("lifetime"))\r
+                                {\r
+                                    newProfile.SetLifetime(new float[int.Parse(parser.GetAttribute(1))][]);\r
+                                    idx0 = 0;\r
+                                    //Log.Info(mTag, "float-array-2d - lifetime : " + parser.GetAttribute(1));\r
+                                }\r
+                            }\r
+                            else if (name.Equals("float-array"))\r
+                            {\r
+                                itemName = parser.GetAttribute(0);\r
+                                if (itemName.Equals("size_dist"))\r
+                                {\r
+                                    newProfile.SetSizeDistribution(new float[int.Parse(parser.GetAttribute(1))]);\r
+                                    floatValues = newProfile.GetSizeDistribution();\r
+                                    //Log.Info(mTag, "float-array - size_dist : " + floatValues.Length);\r
+                                }\r
+                                else if (itemName.Equals("los_element_dist"))\r
+                                {\r
+                                    newProfile.SetLosElementDist(new float[int.Parse(parser.GetAttribute(1))]);\r
+                                    floatValues = newProfile.GetLosElementDist();\r
+                                    //Log.Info(mTag, "float-array - los_element_dist : " + floatValues.Length);\r
+                                }\r
+                                else if (idx0 >= 0)\r
+                                {\r
+                                    float[][] lifetime = null;\r
+                                    lifetime = new float[int.Parse(parser.GetAttribute(1))][];\r
+                                    newProfile.SetLifetime(lifetime);\r
+                                    //floatValues = newProfile.GetLifetime()[idx0];\r
+                                    //Log.Info(mTag, "float-array - size_dist : " + floatValues.Length);\r
+\r
+                                    float[] lifetime2 = null;\r
+                                    lifetime2 = new float[int.Parse(parser.GetAttribute(1))];\r
+                                    newProfile.SetLifetime2(lifetime2);\r
+                                    floatValues = newProfile.GetLifetime2();\r
+                                    idx0++;\r
+                                }\r
+                                idx1 = 0;\r
+                            }\r
+                            else if (name.Equals("value"))\r
+                            {\r
+                                if (floatValues == null)\r
+                                {\r
+                                    Log.Info(mTag, "error in parsing profile.xml");\r
+                                    return false;\r
+                                }\r
+                                floatValues[idx1++] = float.Parse(parser.ReadElementContentAsString());\r
+                                //foreach (var value in floatValues)\r
+                                    //if (value != 0)\r
+                                        //Log.Info(mTag, "value : " + value);\r
+                            }\r
+                            break;\r
+                        case XmlNodeType.EndElement:\r
+                            name = parser.Name;\r
+                            if (name.Equals("profile"))\r
+                            {\r
+                                mData = new List<ProfileData>\r
+                                {\r
+                                    newProfile\r
+                                };\r
+                            }\r
+                            else if (name.Equals("float-array-2d"))\r
+                            {\r
+                                idx0 = -1;\r
+                            }\r
+                            break;\r
+                        default:\r
+                            break;\r
+                    }\r
+                }\r
+            }\r
+            catch (XmlException e)\r
+            {\r
+                Log.Error(mTag, e.StackTrace);\r
+                return false;\r
+            }\r
+            catch (FormatException e)\r
+            {\r
+                Log.Error(mTag, e.StackTrace);\r
+                return false;\r
+            }\r
+            catch (IOException e)\r
+            {\r
+                Log.Error(mTag, e.StackTrace);\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public ProfileData GetProfile(string name)\r
+        {\r
+            if (!mInit)\r
+                return null;\r
+            for (int i = 0; i < mData.Count; i++)\r
+            {\r
+                ProfileData data = mData[i];\r
+                if (data.GetName() == name)\r
+                {\r
+                    mCurrentProfileId = data.GetId();\r
+                    return data;\r
+                }\r
+            }\r
+            return null;\r
+        }\r
+\r
+        public bool ParseProfileData(String rawProfileFile)\r
+        {\r
+            mInit = InitProfileData(rawProfileFile);\r
+            return mInit;\r
+        }\r
+\r
+        public bool Initialized()\r
+        {\r
+            return mInit;\r
+        }\r
+\r
+        public void SetCurrentProfileData(string name)\r
+        {\r
+            if (!mInit)\r
+                return;\r
+            for (int i = 0; i < mData.Count; i++)\r
+            {\r
+                ProfileData data = mData[i];\r
+                if (data.GetName() == name)\r
+                {\r
+                    mCurrentProfileId = data.GetId();\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+\r
+        public ProfileData GetCurrentProfileData()\r
+        {\r
+            if (!mInit)\r
+                return null;\r
+            for (int i = 0; i < mData.Count; i++) {\r
+                ProfileData data = mData[i];\r
+                if (mData[i].GetId() == mCurrentProfileId)\r
+                    return data;\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+}\r
diff --git a/tests/GC/TizenGCTest/TizenGCTest.cs b/tests/GC/TizenGCTest/TizenGCTest.cs
new file mode 100755 (executable)
index 0000000..be17056
--- /dev/null
@@ -0,0 +1,100 @@
+using System;\r
+using System.Threading;\r
+using Tizen;\r
+using Tizen.NUI;\r
+using Tizen.NUI.Components;\r
+using Tizen.NUI.BaseComponents;\r
+using static TizenGCTest.Profile;\r
+\r
+namespace TizenGCTest\r
+{\r
+    class Program : NUIApplication\r
+    {\r
+        private const String mTag = "TizenGCTest";\r
+        private Profile mProfile = null;\r
+\r
+        protected override void OnCreate()\r
+        {\r
+            base.OnCreate();\r
+            Initialize();\r
+\r
+            mProfile = Profile.getInstance();\r
+\r
+            mProfile.ParseProfileData("/opt/usr/globalapps/org.tizen.example.TizenGCTest/res/profile.xml");\r
+\r
+            if (mProfile.Initialized())\r
+            {\r
+                string[] names = new string[mProfile.mData.Count];\r
+                for (int i = 0; i < mProfile.mData.Count; i++)\r
+                {\r
+                    ProfileData d = mProfile.mData[i];\r
+                    names[i] = d.GetName();\r
+                }\r
+                mProfile.SetCurrentProfileData("default");\r
+            }\r
+            else\r
+            {\r
+                Log.Info(mTag, "Cannot get profile data");\r
+            }\r
+\r
+            Log.Info(mTag, "TizenGCTest Start!!");\r
+            StartGC();\r
+        }\r
+\r
+\r
+        public void StartGC()\r
+        {\r
+            ProfileData profileData = mProfile.GetCurrentProfileData();\r
+            if (profileData == null)\r
+            {\r
+                Log.Error(mTag, "no profile data?!");\r
+                return;\r
+            }\r
+            GCTest gctest = new GCTest(profileData.GetTotalSize(), profileData.GetBucketSize(),\r
+                                       profileData.GetLosThreshold(), profileData.GetSizeDistribution(),\r
+                                       profileData.GetLifetime(), profileData.GetLosElementDist(),\r
+                                       profileData.GetThreadMode(), profileData.GetThreadNum(),\r
+                                       profileData.GetIterationNum());\r
+\r
+            GC.Collect();\r
+            GC.WaitForPendingFinalizers();\r
+\r
+            //var mRunning = true;\r
+            var worker = new Thread(() =>\r
+            {\r
+                gctest.start();\r
+            });\r
+            worker.Start();\r
+\r
+        }\r
+\r
+        void Initialize()\r
+        {\r
+            Window.Instance.KeyEvent += OnKeyEvent;\r
+\r
+            TextLabel text = new TextLabel("Hello Tizen NUI World");\r
+            text.HorizontalAlignment = HorizontalAlignment.Center;\r
+            text.VerticalAlignment = VerticalAlignment.Center;\r
+            text.TextColor = Color.Blue;\r
+            text.PointSize = 12.0f;\r
+            text.HeightResizePolicy = ResizePolicyType.FillToParent;\r
+            text.WidthResizePolicy = ResizePolicyType.FillToParent;\r
+            Window.Instance.GetDefaultLayer().Add(text);\r
+            \r
+        }\r
+\r
+        public void OnKeyEvent(object sender, Window.KeyEventArgs e)\r
+        {\r
+            if (e.Key.State == Key.StateType.Down && (e.Key.KeyPressedName == "XF86Back" || e.Key.KeyPressedName == "Escape"))\r
+            {\r
+                Exit();\r
+            }\r
+        }\r
+\r
+        static void Main(string[] args)\r
+        {\r
+            var app = new Program();\r
+            app.Run(args);\r
+        }\r
+    }\r
+}\r
diff --git a/tests/GC/TizenGCTest/TizenGCTest.csproj b/tests/GC/TizenGCTest/TizenGCTest.csproj
new file mode 100755 (executable)
index 0000000..afab7fc
--- /dev/null
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>net6.0-tizen</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugType>portable</DebugType>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <DebugType>None</DebugType>\r
+  </PropertyGroup>\r
+  <ItemGroup>\r
+    <Content Include="res\profile.xml" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Folder Include="lib\" />\r
+  </ItemGroup>\r
+\r
+</Project>\r
diff --git a/tests/GC/TizenGCTest/res/profile.xml b/tests/GC/TizenGCTest/res/profile.xml
new file mode 100755 (executable)
index 0000000..9effe2c
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<profile id="0" name="default">\r
+  <item name="total_size">100</item>\r
+  <item name="bucket_size">1</item>\r
+  <item name="los_threshold">12</item>\r
+  <float-array name="size_dist" count="7">\r
+    <value>0.0436</value>\r
+    <value>0.5465</value>\r
+    <value>0.2103</value>\r
+    <value>0.1499</value>\r
+    <value>0.0275</value>\r
+    <value>0.0125</value>\r
+    <value>0.0097</value>\r
+  </float-array>\r
+  <float-array-2d name="lifetime" count="7">\r
+    <float-array name="16b" count="4">\r
+      <value>0.0865</value>\r
+      <value>0.5404</value>\r
+      <value>0.2887</value>\r
+      <value>0.0865</value>\r
+    </float-array>\r
+    <float-array name="32b" count="4">\r
+      <value>0.0469</value>\r
+      <value>0.7724</value>\r
+      <value>0.1460</value>\r
+      <value>0.0346</value>\r
+    </float-array>\r
+    <float-array name="64b" count="4">\r
+      <value>0.1154</value>\r
+      <value>0.5982</value>\r
+      <value>0.1880</value>\r
+      <value>0.0984</value>\r
+    </float-array>\r
+    <float-array name="128b" count="4">\r
+      <value>0.0662</value>\r
+      <value>0.7851</value>\r
+      <value>0.1077</value>\r
+      <value>0.0411</value>\r
+    </float-array>\r
+    <float-array name="256b" count="4">\r
+      <value>0.0520</value>\r
+      <value>0.8778</value>\r
+      <value>0.0503</value>\r
+      <value>0.0198</value>\r
+    </float-array>\r
+    <float-array name="512b" count="4">\r
+      <value>0.1628</value>\r
+      <value>0.7137</value>\r
+      <value>0.0821</value>\r
+      <value>0.0414</value>\r
+    </float-array>\r
+    <float-array name="los" count="4">\r
+      <value>0.0923</value>\r
+      <value>0.7117</value>\r
+      <value>0.1769</value>\r
+      <value>0.0192</value>\r
+    </float-array>\r
+  </float-array-2d>\r
+  <float-array name="los_element_dist" count="4">\r
+    <value>0.90</value>\r
+    <value>0.07</value>\r
+    <value>0.02</value>\r
+    <value>0.01</value>\r
+  </float-array>\r
+  <item name="thread-mode">0</item>\r
+  <item name="thread-num">0</item>\r
+  <item name="iteration-times">10</item>\r
+</profile>\r
diff --git a/tests/GC/TizenGCTest/shared/res/TizenGCTest.png b/tests/GC/TizenGCTest/shared/res/TizenGCTest.png
new file mode 100755 (executable)
index 0000000..9f3cb98
Binary files /dev/null and b/tests/GC/TizenGCTest/shared/res/TizenGCTest.png differ
diff --git a/tests/GC/TizenGCTest/tizen-manifest.xml b/tests/GC/TizenGCTest/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..beed128
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="9.0" package="org.tizen.example.TizenGCTest" version="1.0.0">
+  <profile name="common" />
+  <ui-application appid="org.tizen.example.TizenGCTest"
+                                       exec="TizenGCTest.dll"
+                                       type="dotnet-nui"
+                                       multiple="false"
+                                       taskmanage="true"
+                                       nodisplay="false"
+                                       launch_mode="single"
+                    api-version="12">
+    <label>TizenGCTest</label>
+    <icon>TizenGCTest.png</icon>
+    <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+  </ui-application>
+</manifest>
diff --git a/tests/GC/TizenGCTest/tizen_dotnet_project.yaml b/tests/GC/TizenGCTest/tizen_dotnet_project.yaml
new file mode 100755 (executable)
index 0000000..556e0f2
--- /dev/null
@@ -0,0 +1,9 @@
+# csproj file path
+csproj_file: TizenGCTest.csproj
+
+# files monitored for dirty/modified status
+files:
+  - TizenGCTest.csproj
+  - TizenGCTest.cs
+  - tizen-manifest.xml
+  - shared/res/TizenGCTest.png
\ No newline at end of file
diff --git a/tests/Performance/measure b/tests/Performance/measure
new file mode 100755 (executable)
index 0000000..5da7d68
--- /dev/null
@@ -0,0 +1,418 @@
+#!/usr/bin/env python3
+import argparse, ast, math, os, re, statistics, subprocess, sys, threading
+from time import sleep
+from datetime import datetime
+
+# Global values.
+predefined_list = ["org.tizen.example.AppCommon.Tizen.Mobile",
+                   "org.tizen.example.ApplicationControl.Tizen.Mobile",
+                   "org.tizen.example.Puzzle.Tizen.Mobile",
+                   "org.tizen.example.Settings.Tizen.Mobile",
+                   "org.tizen.example.System_info.Tizen.Mobile",
+                   "org.tizen.example.Xamarin.Hello.F_HUB.Tizen"]
+logfile = None
+dlogs = list()
+
+# Print text to a file.
+def log(text):
+    if not logfile:
+        return
+
+    with open(logfile, 'a') as f:
+        d = f"\n[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] "
+        f.write(d + d.join(str(text).splitlines()))
+
+# Execute a command and return the output as a string.
+def cmd(command):
+    return subprocess.run(command.split(), encoding='utf-8', stdout=subprocess.PIPE).stdout
+
+# Launch an application and return its pid.
+def launch(app_id, serial, standalone=False, pause=10):
+    raw = cmd(f"sdb -s {serial} shell app_launcher {'-e' if standalone else '-s'} {app_id}")
+    if 'successfully launched pid' not in raw:
+        raise Exception(f'Unable to launch {app_id}. Make sure the application is installed on the target device.')
+    sleep(pause)
+    return raw[raw.index('pid') + 6:raw.index('with') - 1]
+
+# Terminate apps if running.
+def terminate(app_ids, serial, pause=0):
+    for app_id in app_ids:
+        cmd(f'sdb -s {serial} shell app_launcher -t {app_id}')
+    # Check if we are failing due to an unhandled exception.
+    if sys.exc_info()[0] is None:
+        sleep(pause)
+
+# Colorize the text.
+def color(text):
+    return f'\033[93m{text}\033[0m' if os.name == 'posix' else text
+
+# Entry point for the dlog thread.
+def dlogger(serial):
+    cmd(f'sdb -s {serial} dlog -c')
+
+    command = f'sdb -s {serial} dlog -v time AUL LAUNCH'
+    with subprocess.Popen(command.split(), encoding='utf-8', stdout=subprocess.PIPE) as p:
+        for line in p.stdout:
+            dlogs.append(line.strip())
+
+# Filter dlogs with conditions.
+def read_dlogs(target=None, pid=0, grep:str=None):
+    ret = list()
+
+    for line in dlogs:
+        split = line.split(')')[0]
+        if target and target not in split:
+            continue
+        elif pid != 0 and str(pid) not in split.split('(')[1]:
+            continue
+        elif grep is None or re.search(grep, line):
+            ret.append(line)
+
+    return ret
+
+# Return a UNIX time in milliseconds from a formatted dlog text.
+def time_in_millis(text):
+    t = text.split()[1]
+    h = int(t[0:2])
+    m = int(t[3:5])
+    s = int(t[6:8])
+    millis = int(t[9:12])
+    offset = int(t[12:15])
+    return ((h - offset) * 3600 + m * 60 + s) % 86400 * 1000 + millis
+
+# Parse time values.
+def parse_stime(ret, app_id):
+    # Detect the launch request.
+    lines = read_dlogs('AUL', grep=f'[Rr]equest cmd\(0:APP_START\)( )?: appid\({app_id}\)')
+    if len(lines) == 0:
+        log(f'Error: parse_stime for app_id={app_id} has failed. No launch request.')
+        return
+    queued = time_in_millis(lines[-1])
+
+    # Get the Launching:done notification.
+    lines = read_dlogs('LAUNCH', grep=f'{app_id}:Application:Launching:done')
+    if len(lines) == 0:
+        log(f'Error: parse_stime for app_id={app_id} has failed. Unable to detect the app launch completion.')
+        return
+    done = time_in_millis(lines[-1])
+
+    ret[app_id]['stime'][-1] = done - queued
+    log(f"{app_id:40.40} {done - queued:8} ms (Launch)")
+
+# Parse memps to get PSS and RSS.
+def parse_memps(ret, serial, pid_map:map):
+    # pid_map is a map of {pid: app_id}.
+    raw = ''
+    app_ids = [ai for ai in pid_map.values() if len(ai) > 0]
+    retry_cnt = 3
+    while not all(ai in raw for ai in app_ids) and retry_cnt > 0:
+        raw = cmd(f'sdb -s {serial} shell memps -v')
+        retry_cnt -= 1
+        sleep(1)
+
+    # len(lines) == len(app_ids) if successful.
+    lines = [l for l in raw.splitlines() if any(ai in l for ai in app_ids)]
+    if len(lines) < len(app_ids):
+        log(f'Warning: Failed to get one or more app ids from memps.\n{lines}')
+
+    for line in lines:
+        if any(ai in line for ai in app_ids):
+            split = [x for x in line.split() if x]
+            ai = pid_map[split[0]] # from pid
+            shar = float(split[1]) + float(split[2])
+            prvt = float(split[3]) + float(split[4])
+            swap = float(split[10])
+            rss = shar + prvt + swap
+            ret[ai]['pss'][-1] = float(split[6])
+            ret[ai]['rss'][-1] = rss
+            ret[ai]['shar'][-1] = shar
+            ret[ai]['prvt'][-1] = prvt
+            ret[ai]['swap'][-1] = swap
+            ret[ai]['file'][-1] = float(split[1]) + float(split[3])
+            ret[ai]['dirt'][-1] = float(split[2]) + float(split[4])
+            log(f'{ai:40.40} {float(split[6]):8.0f} KB (PSS),  {rss:8.0f} KB (RSS)')
+
+# Reduce the dimensionality of the given data.
+def trim(data, recent=False):
+    # If recent is True, only the latest (intermediate) values are taken.
+    # Otherwise, we first remove outlying values and then compute averages.
+    ret = dict((ai, dict()) for ai in data.keys()) # Create a new data structure.
+    for ai, d in data.items(): # d is a dictionary.
+        # Initialize the metadata.
+        ret[ai]['n'] = len(data[ai]['stime']) # N (original length)
+        ret[ai]['na'] = dict((k, 0) for k in d.keys()) # Zero-initialized N/A counts
+        ret[ai]['stdev'] = dict((k, 0) for k in d.keys()) # Zero-initialized standard deviations
+        for key, val in d.items():
+            if recent:
+                ret[ai][key] = val[-1]
+            else:
+                # Only swaps can be zero by nature. Otherwise, use only non-zero values.
+                v = val if key == 'swap' else [x for x in val if x > 0]
+                mean = statistics.mean(v) if len(v) > 0 else 0
+                stdev = statistics.stdev(v) if len(v) > 1 else 0
+                # Use sqrt(mean) as a correction threshold to discard outlying values.
+                cv = v if stdev <= math.sqrt(mean) else [x for x in v if (x >= mean - stdev) and (x <= mean + stdev)]
+                ret[ai][key] = statistics.mean(cv) if len(cv) > 0 else 0
+                ret[ai]['na'][key] = len(val) - len(cv)
+                ret[ai]['stdev'][key] = statistics.stdev(cv) if len(cv) > 1 else 0
+
+    # Compute averages.
+    keys = data[list(data.keys())[0]].keys()
+    mean = dict()
+    for key in keys:
+        val = [ret[ai][key] for ai in data.keys() if ret[ai][key] > 0 or key == 'swap'] # Only non-zeros are valid.
+        mean[key] = statistics.mean(val) if len(val) > 0 else 0
+    ret['Average'] = mean
+
+    return ret
+
+# Display the statistical metadata (N/A and STDEV) of the dataset.
+def report(data:map):
+    print(f"{'':40}{'STIME':>14}{'PSS':>14}{'RSS':>14}")
+    print(f"{'Application':40}{'   N/A   STDEV' * 3}")
+    for app_id in [ai for ai in data.keys() if ai != 'Average']:
+        empty = dict((k, 0) for k in data[app_id].keys()) # for backward compatibility (0 if no data)
+        na = data[app_id].get('na', empty)
+        stdev = data[app_id].get('stdev', empty)
+        b = f"{app_id:40.40}"
+        b += f"{na['stime']:>6}{stdev['stime']:>8.1f}"
+        b += f"{na['pss']:>6}{stdev['pss']:>8.1f}"
+        b += f"{na['rss']:>6}{stdev['rss']:>8.1f}"
+        print(b)
+
+# Display the dataset.
+def display(data:map, verbose=False):
+    b = f"{'Application':40}{'STIME':>6}{'PSS':>8}"
+    if verbose:
+        b += f"{'nSHARED   (%)':>15}{'MULT':>6}{'PRIVATE':>9}{'CODE':>8}{'DATA':>8}"
+    b += f"{'RSS':>8}"
+    print(b)
+
+    for app_id in data.keys():
+        d = data[app_id]
+        b = f"{app_id:40.40}{d['stime']:6.0f}{d['pss']:8.0f}"
+        if verbose:
+            nshared = d['pss'] - d['prvt']
+            b += f"{nshared:9.0f}{nshared / d['pss'] * 100 if d['pss'] > 0 else 0:6.1f}" # nShared (net shared amount)
+            b += f"{(d['rss'] - d['prvt'] - d['swap']) / nshared if nshared > 0 else 0:6.1f}" # Mult
+            b += f"{d['prvt']:9.0f}{d['file']:8.0f}{d['dirt']:8.0f}"
+        b += f"{d['rss']:8.0f}"
+        print(b)
+
+    if verbose:
+        report(data)
+
+# Compare and display the two datasets.
+def compare(data1:map, data2:map, verbose=False):
+    if set(data1.keys()) != set(data2.keys()):
+        raise Exception('Unable to process data because the target app ids do not match.')
+
+    b = f"{'Application':40}{'STIME (ms)':^20}{'PSS (KB)':^24}"
+    if verbose:
+        b += f"{'RSS (KB)':^24}"
+    print(b)
+
+    for app_id in data1.keys():
+        d1 = data1[app_id]
+        d2 = data2[app_id]
+        stt_gain=f"{(d2['stime'] - d1['stime']) / d1['stime'] * 100 if d1['stime'] > 0 else 0:+5.1f}%"
+        pss_gain=f"{(d2['pss'] - d1['pss']) / d1['pss'] * 100 if d1['pss'] > 0 else 0:+5.1f}%"
+        rss_gain=f"{(d2['rss'] - d1['rss']) / d1['rss'] * 100 if d1['rss'] > 0 else 0:+5.1f}%"
+        b = f"{app_id:40.40}{d1['stime']:6.0f}{d2['stime']:6.0f}{stt_gain:>8}"
+        b += f"{d1['pss']:8.0f}{d2['pss']:8.0f}{pss_gain:>8}"
+        if verbose:
+            b += f"{d1['rss']:8.0f}{d2['rss']:8.0f}{rss_gain:>8}"
+        print(b)
+
+# The main data collection logic.
+def run(serial, app_ids=predefined_list, count=5, pause=10, standalone=False, individual=False, post:str=None):
+    # A permission is required to run 'memps -v'.
+    cmd(f'sdb -s {serial} root on')
+
+    # A dictionary of dictionaries containing output values as lists.
+    ret = dict((app_id, {
+        'stime':[], # Traditional startup time in ms
+        'pss':[],   # Proportional set size in KB
+        'rss':[],   # Resident set size
+        'shar':[],  # Shared set size
+        'prvt':[],  # Private set size
+        'swap':[],  # Swap size
+        'file':[],  # File (clean) set size
+        'dirt':[],  # Dirty set size
+        }) for app_id in app_ids)
+
+    # Flush dlogs and terminate any running processes.
+    print('Preparing for the measurement...')
+    if not standalone:
+        # Restart the candidate process if running.
+        cmd(f'sdb -s {serial} shell killall dotnet-launcher dotnet-loader')
+    terminate(app_ids, serial, pause / 2)
+
+    # Start up the dlog thread.
+    # We need to create a dedicated thread because 'dlog -d' is unstable on FH4.0 targets.
+    dlog_thread = threading.Thread(target=dlogger, args=[serial], daemon=True)
+    dlog_thread.start()
+
+    for num_iter in range(count):
+        print(f'Iter {num_iter + 1}/{count}')
+
+        # Zero-initialize values.
+        for app_id in app_ids:
+            for v in ret[app_id].values():
+                v.append(0)
+
+        if individual:
+            for i in range(len(app_ids)):
+                app_id = app_ids[i]
+                print(f'({i + 1}/{len(app_ids)}) Launching {app_id:60.60}', end='\r')
+
+                try:
+                    pid = launch(app_id, serial, standalone, pause)
+                    parse_stime(ret, app_id)
+                    parse_memps(ret, serial, {pid: app_id})
+                    dlogs.clear()
+                finally:
+                    terminate([app_id], serial, pause / 4)
+        else:
+            pid_map = dict() # {pid: app_id}
+            try:
+                for i in range(len(app_ids)):
+                    app_id = app_ids[i]
+                    print(f'({i + 1}/{len(app_ids)}) Launching {app_id:60.60}', end='\r')
+
+                    pid = launch(app_id, serial, standalone, pause)
+                    parse_stime(ret, app_id)
+                    pid_map[pid] = app_id
+                    dlogs.clear()
+
+                # The post-script is only supported in non-individual mode.
+                if post:
+                    res = cmd(post)
+
+                parse_memps(ret, serial, pid_map)
+            finally:
+                terminate(app_ids, serial, pause / 2)
+
+        # Display the intermediate data.
+        print(f"{'':80}",end='\r')
+        display(trim(ret, True), False)
+
+        if post:
+            print(res)
+
+    return ret
+
+# Save the serialized data to a file.
+def export(data, outfile=None):
+    if not outfile:
+        return
+
+    with open(outfile, 'w') as f:
+        f.write(str(data))
+        print(f'\nSuccessfully exported as {outfile}.')
+
+# Check the sdb connection status and get a device serial number.
+def read_serial():
+    raw = subprocess.run('sdb devices'.split(), encoding='utf-8', stdout=subprocess.PIPE).stdout
+    lines = [l for l in raw.splitlines() if not l.startswith('* ')]
+    if len(lines) <= 1:
+        # No target found.
+        return None
+    elif len(lines) == 2:
+        return lines[1].split(' ')[0].split(':')[0].strip()
+    else:
+        # More than one target found.
+        serials = []
+        for idx in range(1, len(lines)):
+            serial = lines[idx].split(' ')[0].split(':')[0].replace('device', '').strip()
+            serials.append(serial)
+            print(f"[{idx}] {serial} - {lines[idx].split(' ')[-1].strip()}")
+        choice = input(f'Select a device [1-{len(lines) - 1}]: ')
+        return serials[int(choice) - 1].strip() if choice.isdigit() else None
+
+# Main entry point for command line usage.
+def main():
+    epilog = \
+  '''output columns:
+  STIME     Startup time in ms
+  PSS       Proportional set size in KB
+  nSHARED   Net shared set size = PSS - PRIVATE
+  (%)       The portion of nSHARED in PSS
+  MULT      Net multiplier = (RSS - PRIVATE - SWAP) / nSHARED
+  PRIVATE   Private set size
+  CODE      File (clean) set size
+  DATA      Dirty (data) set size
+  RSS       Resident set size
+  N/A       The number of omitted samples
+  STDEV     Dispersion of the samples (standard deviation)'''
+
+    parser = argparse.ArgumentParser(description='Tizen .NET performance analysis utility', epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument('APP_ID', type=str, nargs='*', help='target app ids (default: predefined 6 applications)', default=predefined_list)
+    parser.add_argument('-s', metavar='SERIAL', type=str, help='specify a device serial number', default=None)
+    parser.add_argument('-n', metavar='NUM', type=int, help='number of iterations (default: 5)', default=5)
+    parser.add_argument('-t', metavar='SECONDS', type=int, help='minimum time interval between launches (default: 10)', default=10)
+    parser.add_argument('-v', help='print verbose debug information', action='store_true')
+    parser.add_argument('-e', '--standalone', help='launch apps in standalone mode', action='store_true')
+    parser.add_argument('-i', '--individual', help='measure each application individually', action='store_true')
+    parser.add_argument('-p', metavar='CMD', type=str, help='execute a post-script after launching all apps', default=None)
+    parser.add_argument('-o', metavar='OUTFILE', help='export output data to a file', default=None)
+    parser.add_argument('-f', metavar='FILE', help='display data from a file (do not measure)', default=None)
+    parser.add_argument('--last', help='display the most recent measurement data', action='store_true')
+    parser.add_argument('--compare', nargs=2, metavar=('A', 'B'), help='compare two data files', default=None)
+    args = parser.parse_args()
+
+    # Read args.file and exit (if not None).
+    if args.f:
+        with open(args.f, 'r') as f:
+            # Deserialize data from the file.
+            data = ast.literal_eval(f.read())
+            display(data, args.v)
+        exit(0)
+
+    # Read the last measurement data and exit (if --last).
+    if args.last:
+        with open('measure.log', 'r') as f:
+            for line in reversed(f.read().splitlines()):
+                raw = line.split(']')[1].strip()
+                if raw.startswith('{'):
+                    data = ast.literal_eval(raw)
+                    display(data, args.v)
+                    export(data, args.o) # Allow exporting data to OUTFILE.
+                    exit(0)
+        print('The requested data could not be found in measure.log.')
+        exit(1)
+
+    # Compare two input files and exit (if --compare).
+    if args.compare:
+        with open(args.compare[0], 'r') as f1, open(args.compare[1], 'r') as f2:
+            data1 = ast.literal_eval(f1.read())
+            data2 = ast.literal_eval(f2.read())
+            compare(data1, data2, args.v)
+        exit(0)
+
+    # Get a device serial number.
+    serial = args.s if args.s else read_serial()
+    if serial is None:
+        print('No connected device(s).')
+        exit(1)
+
+    # Set up a log file.
+    global logfile
+    logfile = 'measure.log'
+    log(' '.join(sys.argv))
+
+    # Record data.
+    raw = run(serial, args.APP_ID, args.n, args.t, args.standalone, args.individual, args.p)
+    data = trim(raw)
+
+    print('Final Result')
+    display(data, args.v)
+
+    # Create a backup.
+    log(data)
+
+    # Export data.
+    export(data, args.o)
+
+if __name__ == '__main__':
+    main()
diff --git a/tests/Performance/org.tizen.example.AppCommon.Tizen.Mobile-1.0.0.tpk b/tests/Performance/org.tizen.example.AppCommon.Tizen.Mobile-1.0.0.tpk
new file mode 100755 (executable)
index 0000000..37fbd1d
Binary files /dev/null and b/tests/Performance/org.tizen.example.AppCommon.Tizen.Mobile-1.0.0.tpk differ
diff --git a/tests/Performance/org.tizen.example.ApplicationControl.Tizen.Mobile-1.0.0.tpk b/tests/Performance/org.tizen.example.ApplicationControl.Tizen.Mobile-1.0.0.tpk
new file mode 100755 (executable)
index 0000000..8fc9b38
Binary files /dev/null and b/tests/Performance/org.tizen.example.ApplicationControl.Tizen.Mobile-1.0.0.tpk differ
diff --git a/tests/Performance/org.tizen.example.Puzzle.Tizen.Mobile-1.0.0.tpk b/tests/Performance/org.tizen.example.Puzzle.Tizen.Mobile-1.0.0.tpk
new file mode 100755 (executable)
index 0000000..8be0139
Binary files /dev/null and b/tests/Performance/org.tizen.example.Puzzle.Tizen.Mobile-1.0.0.tpk differ
diff --git a/tests/Performance/org.tizen.example.Settings.Tizen.Mobile-1.0.0.tpk b/tests/Performance/org.tizen.example.Settings.Tizen.Mobile-1.0.0.tpk
new file mode 100755 (executable)
index 0000000..83b5c9c
Binary files /dev/null and b/tests/Performance/org.tizen.example.Settings.Tizen.Mobile-1.0.0.tpk differ
diff --git a/tests/Performance/org.tizen.example.System_info.Tizen.Mobile-1.0.0.tpk b/tests/Performance/org.tizen.example.System_info.Tizen.Mobile-1.0.0.tpk
new file mode 100755 (executable)
index 0000000..2ba1a80
Binary files /dev/null and b/tests/Performance/org.tizen.example.System_info.Tizen.Mobile-1.0.0.tpk differ
diff --git a/tests/Performance/org.tizen.example.Xamarin.Hello.F_HUB.Tizen-1.0.0.tpk b/tests/Performance/org.tizen.example.Xamarin.Hello.F_HUB.Tizen-1.0.0.tpk
new file mode 100755 (executable)
index 0000000..21973fe
Binary files /dev/null and b/tests/Performance/org.tizen.example.Xamarin.Hello.F_HUB.Tizen-1.0.0.tpk differ
index 8463227..ee704bc 100755 (executable)
@@ -127,6 +127,9 @@ def run():
         r = round(((p / (len(tc_array) - n)) * 100), 2)
     print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|    {module_name}    |   {p}  |   {f}  |   {n}  | {r} |\n")
+
 # Uninstall the application and restore to original state
 def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_AOT_01.Tizen")
index 6d19123..be55dce 100755 (executable)
@@ -303,6 +303,90 @@ def TC_10():
 
     return "PASS"
 
+# The `Launcher_TC_PLUGIN_11` application should not have a library of other architecture.
+def TC_11():
+    sln_name = "Launcher_TC_PLUGIN_11"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = f"org.tizen.example.Launcher_TC_PLUGIN_11"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    device_abi = get_device_abi()
+    if "arm_32" == device_abi:
+        if not exist(f"{root_path}/lib/arm") or \
+           not exist(f"{root_path}/lib/armel") or \
+           exist(f"{root_path}/lib/aarch64") or \
+           exist(f"{root_path}/lib/arm64") or \
+           exist(f"{root_path}/lib/riscv32") or \
+           exist(f"{root_path}/lib/riscv64") or \
+           exist(f"{root_path}/lib/x64") or \
+           exist(f"{root_path}/lib/x86"):
+            return "FAIL"
+    elif "arm_64" == device_abi:
+        if exist(f"{root_path}/lib/arm") or \
+           exist(f"{root_path}/lib/armel") or \
+           not exist(f"{root_path}/lib/aarch64") or \
+           not exist(f"{root_path}/lib/arm64") or \
+           exist(f"{root_path}/lib/riscv32") or \
+           exist(f"{root_path}/lib/riscv64") or \
+           exist(f"{root_path}/lib/x64") or \
+           exist(f"{root_path}/lib/x86"):
+            return "FAIL"
+    elif "riscv_32" == device_abi:
+        if exist(f"{root_path}/lib/arm") or \
+           exist(f"{root_path}/lib/armel") or \
+           exist(f"{root_path}/lib/aarch64") or \
+           exist(f"{root_path}/lib/arm64") or \
+           not exist(f"{root_path}/lib/riscv32") or \
+           exist(f"{root_path}/lib/riscv64") or \
+           exist(f"{root_path}/lib/x64") or \
+           exist(f"{root_path}/lib/x86"):
+            return "FAIL"
+    elif "riscv_64" == device_abi:
+        if exist(f"{root_path}/lib/arm") or \
+           exist(f"{root_path}/lib/armel") or \
+           exist(f"{root_path}/lib/aarch64") or \
+           exist(f"{root_path}/lib/arm64") or \
+           exist(f"{root_path}/lib/riscv32") or \
+           not exist(f"{root_path}/lib/riscv64") or \
+           exist(f"{root_path}/lib/x64") or \
+           exist(f"{root_path}/lib/x86"):
+            return "FAIL"
+    elif "x86_64" == device_abi:
+        if exist(f"{root_path}/lib/arm") or \
+           exist(f"{root_path}/lib/armel") or \
+           exist(f"{root_path}/lib/aarch64") or \
+           exist(f"{root_path}/lib/arm64") or \
+           exist(f"{root_path}/lib/riscv32") or \
+           exist(f"{root_path}/lib/riscv64") or \
+           not exist(f"{root_path}/lib/x64") or \
+           exist(f"{root_path}/lib/x86"):
+            return "FAIL"
+    elif "x86" == device_abi:
+        if exist(f"{root_path}/lib/arm") or \
+           exist(f"{root_path}/lib/armel") or \
+           exist(f"{root_path}/lib/aarch64") or \
+           exist(f"{root_path}/lib/arm64") or \
+           exist(f"{root_path}/lib/riscv32") or \
+           exist(f"{root_path}/lib/riscv64") or \
+           exist(f"{root_path}/lib/x64") or \
+           not exist(f"{root_path}/lib/x86"):
+            return "FAIL"
+    else:
+        return "NONE - TC_11 is not supported on this platform"
+
+
+    return "PASS"
+
 # Run the test
 def run():
     cmd(f"root on")
@@ -320,6 +404,9 @@ def run():
         r = round(((p / (len(tc_array) - n)) * 100), 2)
     print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|   {module_name}  |  {p}  |   {f}  |   {n}  | {r} |\n")
+
 # Uninstall the application and restore to original state
 def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_01.Tizen")
@@ -332,6 +419,7 @@ def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_08.Tizen")
     cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_09.Tizen")
     cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_10.Tizen")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_PLUGIN_11")
 
 # Main entry point
 def main():
@@ -349,7 +437,7 @@ def main():
             else:
                 tc_array.append(funcMap[tc_num])
     else:
-        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08, TC_09, TC_10]
+        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08, TC_09, TC_10, TC_11]
 
     global serial
     if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
@@ -369,9 +457,10 @@ def main():
 
 
 funcMap = {
-'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04, 'TC_05': TC_05, 'TC_06': TC_06, 'TC_07': TC_07, 'TC_08': TC_08, 'TC_09': TC_09, 'TC_10': TC_10,
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04, 'TC_05': TC_05,
+'TC_06': TC_06, 'TC_07': TC_07, 'TC_08': TC_08, 'TC_09': TC_09, 'TC_10': TC_10, 'TC_11': TC_11,
 'PLUGIN_TC_01': TC_01, 'PLUGIN_TC_02': TC_02, 'PLUGIN_TC_03': TC_03, 'PLUGIN_TC_04': TC_04, 'PLUGIN_TC_05': TC_05,
-'PLUGIN_TC_06': TC_06, 'PLUGIN_TC_07': TC_07, 'PLUGIN_TC_08': TC_08, 'PLUGIN_TC_09': TC_09, 'PLUGIN_TC_10': TC_10
+'PLUGIN_TC_06': TC_06, 'PLUGIN_TC_07': TC_07, 'PLUGIN_TC_08': TC_08, 'PLUGIN_TC_09': TC_09, 'PLUGIN_TC_10': TC_10, 'PLUGIN_TC_11': TC_11
 }
 
 
index 9e84906..c1301a0 100755 (executable)
@@ -109,6 +109,9 @@ def run():
         r = round(((p / (len(tc_array) - n)) * 100), 2)
     print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|  {module_name}  |   {p}  |   {f}  |   {n}  | {r} |\n")
+
 # Uninstall the application and restore to original state
 def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_PRELOAD_01.Tizen")
diff --git a/tests/TCs/4_TAC/TAC_RO.py b/tests/TCs/4_TAC/TAC_RO.py
new file mode 100755 (executable)
index 0000000..4e9d725
--- /dev/null
@@ -0,0 +1,589 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "TAC"
+
+# The `Launcher_TC_TAC_01` application must have TAC applied.
+def TC_01():
+    sln_name = "Launcher_TC_TAC_01.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_01.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/4.6.0.967/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{RO_TAC_DIR}Xamarin.Forms/4.6.0.967/Xamarin.Forms.Platform.Tizen.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/4.6.0.967/Xamarin.Forms.Core.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/4.6.0.967/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_02` application must have TAC applied.
+def TC_02():
+    sln_name = "Launcher_TC_TAC_02.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/4.8.0.1364/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Newtonsoft.Json/13.0.1/ -name *.dll -not -name *.ni.dll")
+    lines3 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2)+len(lines3):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1364/Xamarin.Forms.Platform.Tizen.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1364/Xamarin.Forms.Core.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1364/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Newtonsoft.Json.dll")
+    if f"{RO_TAC_DIR}Newtonsoft.Json/13.0.1/Newtonsoft.Json.dll" not in raw:
+        return "FAIL : The Newtonsoft.Json in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_03` application is normally TAC applied when updating.
+def TC_03():
+    sln_name = "Launcher_TC_TAC_03.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/4.8.0.1687/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}sqlite-net-base/1.7.335/ -name *.dll -not -name *.ni.dll")
+    lines3 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}SQLitePCLRaw.core/2.0.3/ -name *.dll -not -name *.ni.dll")
+    lines4 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2)+len(lines3)+len(lines4):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    if exist(f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1364/ -name *.dll"):
+        return f"FAIL : The Xamarin.Forms/4.8.0.1364 nuget should not exist in {RO_TAC_DIR}"
+
+    if exist(f"{RO_TAC_DIR}Newtonsoft.Json/13.0.1/ -name *.dll"):
+        return f"FAIL : The Newtonsoft.Json/13.0.1 nuget should not exist in {RO_TAC_DIR}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1687/Xamarin.Forms.Platform.Tizen.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1687/Xamarin.Forms.Core.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1687/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep SQLite-net.dll")
+    if f"{RO_TAC_DIR}sqlite-net-base/1.7.335/SQLite-net.dll" not in raw:
+        return "FAIL : The sqlite-net-base in the TAC should be loaded when running the application"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep SQLitePCLRaw.core.dll")
+    if f"{RO_TAC_DIR}SQLitePCLRaw.core/2.0.3/SQLitePCLRaw.core.dll" not in raw:
+        return "FAIL : The SQLitePCLRaw.core in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_04` application should not apply TAC when updating.
+def TC_04():
+    sln_name = "Launcher_TC_TAC_04.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_00.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should not exist"
+
+    if exist(f"{RO_TAC_DIR}Xamarin.Forms/4.8.0.1364/ -name *.dll"):
+        return f"FAIL : The Xamarin.Forms/4.8.0.1364 nuget should not exist in {RO_TAC_DIR}"
+
+    if exist(f"{RO_TAC_DIR}Newtonsoft.Json/13.0.1/ -name *.dll"):
+        return f"FAIL : The Newtonsoft.Json/13.0.1 nuget should not exist in {RO_TAC_DIR}"
+
+    if exist(f"{RO_TAC_DIR}sqlite-net-base/1.7.335/ -name *.dll"):
+        return f"FAIL : The sqlite-net-base/1.7.335 nuget should not exist in {RO_TAC_DIR}"
+
+    if exist(f"{RO_TAC_DIR}SQLitePCLRaw.core/2.0.3/ -name *.dll"):
+        return f"FAIL : The SQLitePCLRaw.core/2.0.3 nuget should not exist in {RO_TAC_DIR}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{root_path}/bin/Xamarin.Forms.Platform.Tizen.dll" not in raw) or \
+       (f"{root_path}/bin/Xamarin.Forms.Core.dll" not in raw) or \
+       (f"{root_path}/bin/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the application should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_05`, `Launcher_TC_TAC_06` applications using the same nuget are normally TAC applied.
+def TC_05():
+    sln_name = "Launcher_TC_TAC_05.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id1 = f"org.tizen.example.Launcher_TC_TAC_05.Tizen"
+
+    root_path = get_root_path(f"{pkg_id1}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id1}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/5.0.0.1558-pre3/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    sln_name = "Launcher_TC_TAC_06.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id2 = f"org.tizen.example.Launcher_TC_TAC_06.Tizen"
+
+    root_path = get_root_path(f"{pkg_id2}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id2}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/5.0.0.1558-pre3/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    cmd(f"shell tpk-backend --force-remove --preload -d {pkg_id1}")
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/5.0.0.1558-pre3/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id2}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id2}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Xamarin.Forms.*.dll")
+    if (f"{RO_TAC_DIR}Xamarin.Forms/5.0.0.1558-pre3/Xamarin.Forms.Platform.Tizen.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/5.0.0.1558-pre3/Xamarin.Forms.Core.dll" not in raw) or \
+       (f"{RO_TAC_DIR}Xamarin.Forms/5.0.0.1558-pre3/Xamarin.Forms.Platform.dll" not in raw):
+        return "FAIL : The Xamarin.Forms in the TAC should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id2}")
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_07` application is normally TAC applied when uninstall.
+def TC_06():
+    sln_name = "Launcher_TC_TAC_07.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_07.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}Xamarin.Forms/4.4.0.991864/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    cmd(f"shell tpk-backend --force-remove --preload -d {pkg_id}")
+
+    if exist(f"{RO_TAC_DIR}Xamarin.Forms/4.4.0.991864/ -name *.dll"):
+        return f"FAIL : The Xamarin.Forms/4.4.0.991864 nuget should not exist in {RO_TAC_DIR}"
+
+    return "PASS"
+
+# The `Launcher_TC_TAC_08` application should be applied to TAC, but The `Launcher_TC_TAC_09` application should not be applied to TAC.
+def TC_07():
+    raw = cmd(f"shell find {FRAMEWORK_DIR}/XSF.*")
+    if "XSF.dll" in raw:
+        cmd(f"shell mv {FRAMEWORK_DIR}/XSF.dll {FRAMEWORK_DIR}/XSF.dll2")
+    elif "XSF.ni.dll" in raw:
+        cmd(f"shell mv {FRAMEWORK_DIR}/XSF.ni.dll {FRAMEWORK_DIR}/XSF.ni.dll2")
+
+    sln_name = "Launcher_TC_TAC_08.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_08.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink/ -name *.dll -not -name *.ni.dll")
+    lines1 = [l for l in raw.splitlines()]
+    raw = cmd(f"shell find {RO_TAC_DIR}XSF/1.0.0.0/ -name *.dll -not -name *.ni.dll")
+    lines2 = [l for l in raw.splitlines()]
+    if len(lines1) != len(lines2):
+        return "FAIL : The number of .dll in the .tac_symlink and .dll in the TAC must match"
+
+    raw = cmd(f"shell ls -alZ {root_path}/bin/.tac_symlink/*.dll")
+    lines = [l for l in raw.splitlines() if ".ni.dll" not in l]
+    for dll in lines:
+        origin_path = dll.split("->")[1].strip()
+        if not exist(f"{origin_path}"):
+            return "FAIL : The original file of the symbolic link must exist"
+
+    sln_name = "Launcher_TC_TAC_09.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_09.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = cmd(f"shell find {root_path}/bin/.tac_symlink -name XSF.dll -not -name XSF.ni.dll")
+    lines = [l for l in raw.splitlines()]
+    if len(lines) != 0:
+        return "FAIL : The version is the same Nuget, but the SHA value is different"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep XSF.dll")
+    if f"{root_path}/bin/XSF.dll" not in raw:
+        return "FAIL : The XSF in the application should be loaded when running the application"
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The Launcher_TC_TAC_10 application should match the information of nuget with the value of TAC DB.
+def TC_08():
+    sln_name = "Launcher_TC_TAC_10.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_10.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if not exist(f"{root_path}/bin/.tac_symlink"):
+        return "FAIL : The .tac_symlink folder should exist"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {RO_TAC_DIR}.TAC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TAC;\n.q\n", encoding="utf-8").stdout
+    lines = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    for rcd in lines:
+        is_exist = False
+        if ("Xamarin.Forms/4.8.0.1560" in rcd) or \
+           ("Newtonsoft.Json/12.0.3" in rcd) or \
+           ("Google.Apis.Core/1.49.0" in rcd) or \
+           ("Google.Apis/1.49.0" in rcd):
+            is_exist = True
+            continue
+        if not is_exist:
+            return "FAIL : TAC database must have a valid value"
+
+    return "PASS"
+
+# The Launcher_TC_TAC_11 application must match the version of the nuget in .deps.json and the version of the nuget in TAC DB.
+def TC_09():
+    sln_name = "Launcher_TC_TAC_11.Tizen"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    raw = cmd(f"push {tpk_path} /usr/apps/.preload-tpk/")
+    if "1 file(s) pushed. 0 file(s) skipped." in raw:
+        cmd(f"shell install_preload_pkg")
+
+    pkg_id = f"org.tizen.example.Launcher_TC_TAC_11.Tizen"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    raw = subprocess.run((f"sdb -s {serial} shell sqlite3 {RO_TAC_DIR}.TAC.App.list.db").split(), stdout=subprocess.PIPE, input=f"select * from TAC;\n.q\n", encoding="utf-8").stdout
+    lines = [l for l in raw.splitlines() if f"{pkg_id}" in l]
+    for nuget in lines:
+        name = nuget.split("|")[3]
+        version = nuget.split("|")[4]
+        raw = cmd(f"shell cat {root_path}/{sln_name}.deps.json | grep {name}/")
+        if f"{version}" not in f"{raw}":
+            return "FAIL : "
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    pn = run_tc_array(module_name, tc_array)
+    n = int(pn.split(":")[0])
+    f = int(pn.split(":")[1])
+    p = int(pn.split(":")[2])
+    r = 0.0
+    if (len(tc_array) - n) != 0:
+        r = round(((p / (len(tc_array) - n)) * 100), 2)
+    print(f"--- {module_name}_RO TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|   {module_name}_RO  |   {p}  |   {f}  |   {n}  | {r} |\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_00.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_01.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_06.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_07.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_08.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_09.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_10.Tizen")
+    cmd(f"shell tpk-backend --force-remove --preload -d org.tizen.example.Launcher_TC_TAC_11.Tizen")
+
+    cmd(f"shell mv {FRAMEWORK_DIR}/XSF.dll2 {FRAMEWORK_DIR}/XSF.dll")
+    cmd(f"shell mv {FRAMEWORK_DIR}/XSF.ni.dll2 {FRAMEWORK_DIR}/XSF.ni.dll")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual excution")
+    args = parser.parse_args()
+
+    global tc_array
+    if args.TC_NUMBER and "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04, TC_05, TC_06, TC_07, TC_08, TC_09]
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}_RO) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04, 'TC_05': TC_05, 'TC_06': TC_06, 'TC_07': TC_07, 'TC_08': TC_08, 'TC_09': TC_09,
+'TAC_TC_01': TC_01, 'TAC_TC_02': TC_02, 'TAC_TC_03': TC_03, 'TAC_TC_04': TC_04, 'TAC_TC_05': TC_05,
+'TAC_TC_06': TC_06, 'TAC_TC_07': TC_07, 'TAC_TC_08': TC_08, 'TAC_TC_09': TC_09
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
similarity index 98%
rename from tests/TCs/4_TAC/TAC.py
rename to tests/TCs/4_TAC/TAC_RW.py
index 78b6f83..cd04125 100755 (executable)
@@ -513,7 +513,10 @@ def run():
     r = 0.0
     if (len(tc_array) - n) != 0:
         r = round(((p / (len(tc_array) - n)) * 100), 2)
-    print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+    print(f"--- {module_name}_RW TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|   {module_name}_RW  |   {p}  |   {f}  |   {n}  | {r} |\n")
 
 # Uninstall the application and restore to original state
 def clean():
@@ -558,7 +561,7 @@ def main():
         exit(1)
 
     device = get_device_type()
-    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}_RW) ===")
 
     run()
     clean()
index 42b1ef6..c958103 100755 (executable)
@@ -582,6 +582,9 @@ def run():
         r = round(((p / (len(tc_array) - n)) * 100), 2)
     print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|    {module_name}    |   {p}  |   {f}  |   {n}  | {r} |\n")
+
 # Uninstall the application and restore to original state
 def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_TLC_01.Tizen")
index 5361c35..3a00ff2 100755 (executable)
@@ -670,6 +670,9 @@ def run():
         r = round(((p / (len(tc_array) - n)) * 100), 2)
     print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|    {module_name}   |  {p}  |   {f}  |   {n}  | {r} |\n")
+
 # Uninstall the application and restore to original state
 def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_TOOL_01.Tizen")
diff --git a/tests/TCs/7_EXCEPTION/EXCEPTION.py b/tests/TCs/7_EXCEPTION/EXCEPTION.py
new file mode 100755 (executable)
index 0000000..58cd8b1
--- /dev/null
@@ -0,0 +1,250 @@
+#!/usr/bin/env python3
+import os, subprocess, sys, argparse
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+from time import sleep
+from Utils import *
+
+
+module_name = "EXCEPTION"
+
+# The `Launcher_TC_EXCEPTION_01` application(apptype : dotnet) should run in `candidate(dotnet-loader)` mode.
+def TC_01():
+    sln_name = "Launcher_TC_EXCEPTION_01"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_EXCEPTION_01"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    if "OK" not in prepare_candidate_process(f"dotnet-loader", f"{pkg_id}"):
+        return f"FAIL : Candidate process should have dotnet-loader"
+
+    pid = launch_and_get_pid(f"-s", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_EXCEPTION_01")
+    if f"{root_path}/bin/Launcher_TC_EXCEPTION_01.dll" not in raw:
+        return "FAIL : The application is run as a candidate mode."
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep dotnet-loader")
+    if f"/usr/bin/dotnet-loader" not in raw:
+        return "FAIL : The application is run as a candidate mode."
+
+    raw = cmd(f"shell dlogutil STDOUT | grep {pid} &")
+    lines = [l for l in raw.splitlines() if "System.NullReferenceException:" in l]
+    for log in lines:
+        if "System.NullReferenceException: Object reference not set to an instance of an object." not in log:
+            return "FAIL : The application can use the try/catch block to catch the NullReferenceException."
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_EXCEPTION_01` application(apptype : dotnet) should run in `standalone(dotnet-launcher)` mode.
+def TC_02():
+    sln_name = "Launcher_TC_EXCEPTION_01"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_EXCEPTION_01"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_EXCEPTION_01")
+    if f"{root_path}/bin/Launcher_TC_EXCEPTION_01.dll" not in raw:
+        return "FAIL : The application is run as a standalone mode"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep dotnet-launcher")
+    if f"/usr/bin/dotnet-launcher" not in raw:
+        return "FAIL : The application is run as a standalone mode."
+
+    raw = cmd(f"shell dlogutil STDOUT | grep {pid} &")
+    lines = [l for l in raw.splitlines() if "System.NullReferenceException:" in l]
+    for log in lines:
+        if "System.NullReferenceException: Object reference not set to an instance of an object." not in log:
+            return "FAIL : The application can use the try/catch block to catch the NullReferenceException."
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_EXCEPTION_02` application(apptype : dotnet-nui) should run in `candidate(dotnet-loader/dotnet-nui-loader)` mode.
+def TC_03():
+    sln_name = "Launcher_TC_EXCEPTION_02"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_EXCEPTION_02"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    loader = "dotnet-nui-loader"
+    if "NOT FOUND" in prepare_candidate_process(f"{loader}", f"{pkg_id}"):
+        loader = "dotnet-loader"
+        if "OK" not in prepare_candidate_process(f"{loader}", f"{pkg_id}"):
+            return f"FAIL : Candidate process should have {loader}"
+    elif "FAIL" not in prepare_candidate_process(f"{loader}", f"{pkg_id}"):
+        return f"FAIL : Candidate process should have {loader}"
+
+    pid = launch_and_get_pid(f"-s", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_EXCEPTION_02")
+    if f"{root_path}/bin/Launcher_TC_EXCEPTION_02.dll" not in raw:
+        return "FAIL : The application is run as a candidate mode"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep {loader}")
+    if f"/usr/bin/{loader}" not in raw:
+        return "FAIL : The application is run as a candidate mode."
+
+    raw = cmd(f"shell dlogutil STDOUT | grep {pid} &")
+    lines = [l for l in raw.splitlines() if "System.NullReferenceException:" in l]
+    for log in lines:
+        if "System.NullReferenceException: Object reference not set to an instance of an object." not in log:
+            return "FAIL : The application can use the try/catch block to catch the NullReferenceException."
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# The `Launcher_TC_EXCEPTION_02` application(apptype : dotnet-nui) should run in `standalone(dotnet-launcher)` mode.
+def TC_04():
+    sln_name = "Launcher_TC_EXCEPTION_02"
+
+    tpk_path = get_tpk_path(tpk_list, f"{sln_name}")
+    if tpk_path == None:
+        return f"FAIL : Get the tpk path for {sln_name}"
+
+    if "OK" not in app_install(f"{tpk_path}"):
+        return f"FAIL : Install the application for {tpk_path}"
+
+    pkg_id = "org.tizen.example.Launcher_TC_EXCEPTION_02"
+
+    root_path = get_root_path(f"{pkg_id}")
+    if root_path == "None":
+        return f"FAIL : Get the root path for {pkg_id}"
+
+    pid = launch_and_get_pid(f"-e", f"{pkg_id}")
+    if 0 == pid:
+        return f"FAIL : Get the pid for {pkg_id}"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep Launcher_TC_EXCEPTION_02")
+    if f"{root_path}/bin/Launcher_TC_EXCEPTION_02.dll" not in raw:
+        return "FAIL : The application is run as a standalone mode"
+
+    raw = cmd(f"shell cat /proc/{pid}/smaps | grep dotnet-launcher")
+    if f"/usr/bin/dotnet-launcher" not in raw:
+        return "FAIL : The application is run as a standalone mode."
+
+    raw = cmd(f"shell dlogutil STDOUT | grep {pid} &")
+    lines = [l for l in raw.splitlines() if "System.NullReferenceException:" in l]
+    for log in lines:
+        if "System.NullReferenceException: Object reference not set to an instance of an object." not in log:
+            return "FAIL : The application can use the try/catch block to catch the NullReferenceException."
+
+    cmd(f"shell app_launcher -t {pkg_id}")
+
+    return "PASS"
+
+# Run the test
+def run():
+    cmd(f"root on")
+    cmd(f"shell mount -o remount,rw /")
+
+    global tpk_list
+    tpk_list = search_tpk(f"{module_name}")
+
+    pn = run_tc_array(module_name, tc_array)
+    n = int(pn.split(":")[0])
+    f = int(pn.split(":")[1])
+    p = int(pn.split(":")[2])
+    r = 0.0
+    if (len(tc_array) - n) != 0:
+        r = round(((p / (len(tc_array) - n)) * 100), 2)
+    print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
+
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"| {module_name} |   {p}  |   {f}  |   {n}  | {r} |\n")
+
+# Uninstall the application and restore to original state
+def clean():
+    cmd(f"uninstall org.tizen.example.Launcher_TC_EXCEPTION_01")
+    cmd(f"uninstall org.tizen.example.Launcher_TC_EXCEPTION_02")
+
+# Main entry point
+def main():
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument("TC_NUMBER", type=str, nargs="*", help="Individual execution")
+    args = parser.parse_args()
+
+    global tc_array
+    if args.TC_NUMBER and "TC_" in args.TC_NUMBER[0]:
+        tc_array = []
+        for tc_num in args.TC_NUMBER:
+            if tc_num not in funcMap:
+                print(f"There is no {tc_num} test.")
+                exit(1)
+            else:
+                tc_array.append(funcMap[tc_num])
+    else:
+        tc_array = [TC_01, TC_02, TC_03, TC_04]
+        #skip TC_03(dotnet-nui-loader)
+
+    global serial
+    if len(sys.argv) >= 2 and "TC_" not in sys.argv[1]:
+        serial = read_serial(sys.argv[1])
+    else:
+        serial = read_serial(None)
+
+    if serial is None:
+        print("No connected device(s).")
+        exit(1)
+
+    device = get_device_type()
+    print(f"=== Dotnet-Launcher [{device}] Test Case - ({module_name}) ===")
+
+    run()
+    clean()
+
+
+funcMap = {
+'TC_01': TC_01, 'TC_02': TC_02, 'TC_03': TC_03, 'TC_04': TC_04,
+'EXCEPTION_TC_01': TC_01, 'EXCEPTION_TC_02': TC_02, 'EXCEPTION_TC_03': TC_03, 'EXCEPTION_TC_04': TC_04
+}
+
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print("\nExit (Pressed Ctrl+C)")
+        exit(1)
similarity index 98%
rename from tests/TCs/7_LAUNCH/LAUNCH.py
rename to tests/TCs/8_LAUNCH/LAUNCH.py
index 62354e4..b03229f 100755 (executable)
@@ -189,6 +189,9 @@ def run():
         r = round(((p / (len(tc_array) - n)) * 100), 2)
     print(f"--- {module_name} TCT Result ---\nNONE : [{n}] / FAIL : [{f}] / PASS : [{p}] - [{r}%]\n")
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write(f"|   {module_name}  |   {p}  |   {f}  |   {n}  | {r} |\n")
+
 # Uninstall the application and restore to original state
 def clean():
     cmd(f"uninstall org.tizen.example.Launcher_TC_LAUNCH_01.Tizen")
index e6ae958..212654b 100755 (executable)
@@ -18,12 +18,18 @@ def get_script_path(dirname):
             if ext == ".py" and \
                "BuildTPK" not in full_filename and \
                "Utils" not in full_filename and \
-               "ALL" not in full_filename:
+               "ALL" not in full_filename and \
+               "candidate_mcj" not in full_filename:
                 script_lists.append(full_filename)
     return script_lists
 
 
 def run(serial):
+    with open(f"{RESULT_PATH}", "w") as file:
+        file.write("==== Dotnet Launcher Unit Test Result ====\n")
+        file.write("|   MODULE  | PASS | FAIL | NONE | RATIO |\n")
+        file.write("------------------------------------------\n")
+
     device = get_device_type()
     print(f"=== Dotnet-Launcher [{device}] Test Case ===")
 
@@ -31,6 +37,16 @@ def run(serial):
         subprocess.run((f"{tc} {serial}").split())
         sleep(3)
 
+    with open(f"{RESULT_PATH}", "a+") as file:
+        file.write("------------------------------------------\n")
+        file.write("|   MODULE  | PASS | FAIL | NONE | RATIO |\n")
+
+
+def result(serial):
+    with open(f"{RESULT_PATH}", "r") as file:
+        result = file.read()
+        print(result)
+
 
 def main():
     serial = read_serial(None)
@@ -40,6 +56,7 @@ def main():
 
     get_script_path("./")
     run(serial)
+    result(serial)
 
 
 if __name__ == "__main__":
index da67ff3..e302854 100755 (executable)
@@ -10,9 +10,11 @@ RUNTIME_DIR = "/usr/share/dotnet.tizen/netcoreapp/"
 FRAMEWORK_DIR = "/usr/share/dotnet.tizen/framework/"
 PRELOAD_DIR = "/usr/share/dotnet.tizen/preload/"
 IBCDATA_DIR = "/usr/share/dotnet.tizen/ibcdata/"
+RO_TAC_DIR = "/usr/share/dotnet.tizen/tac/"
 DOTNET_DIR = "/opt/usr/dotnet/"
 OWNER_DIR = "/home/owner/"
 SPC_DLL = "System.Private.CoreLib.dll"
+RESULT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "result.log"))
 
 # Check the sdb connection status and get a device serial number
 def read_serial(serial):
@@ -109,6 +111,11 @@ def get_device_type():
     raw = cmd(f"shell cat /etc/config/model-config.xml | grep tizen.org/feature/profile")
     return raw.split(">")[1].split("<")[0]
 
+# Get the device type
+def get_platform_version():
+    raw = cmd(f"shell cat /etc/config/model-config.xml | grep tizen.org/feature/platform.version")
+    return raw.split(">")[1].split("<")[0]
+
 # Create the System.Private.CoreLib native image
 def create_spc_ni():
     raw = cmd(f"shell find {RUNTIME_DIR} -name {SPC_DLL}.Backup")
@@ -132,7 +139,10 @@ def remove_system_ni():
 
 # Prepare the candidate process
 def prepare_candidate_process(loader, pkg_id):
-    cmd(f"shell killall dotnet-launcher {loader}")
+    cmd(f"shell killall dotnet-launcher")
+    raw = cmd(f"shell killall {loader}")
+    if "no process found" in raw:
+        return "NOT FOUND"
     sleep(30)
 
     raw = cmd(f"shell ps -ef | grep {loader}")
@@ -154,6 +164,12 @@ def get_device_arch():
     line = [l for l in raw.splitlines() if "cpu_arch" in l]
     return line[0].split(":")[1]
 
+# Get the device abi
+def get_device_abi():
+    raw = cmd("capability")
+    line = [l for l in raw.splitlines() if "core_abi" in l]
+    return line[0].split(":")[1]
+
 # Check the library type
 def check_library_arch(rootpath, library):
     raw = cmd(f"pull {rootpath}/bin/{library} {library}")