--- /dev/null
+*.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
--- /dev/null
+# Default ignored files
+/shelf/
+/workspace.xml
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <bytecodeTargetLevel target="17" />
+ </component>
+</project>
\ No newline at end of file
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<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
--- /dev/null
+<?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
--- /dev/null
+/build
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+<?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
--- /dev/null
+/*
+ * 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;
+ }
+}
+
--- /dev/null
+/*
+ * 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);
+ }
+ };
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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()));
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+<?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>
--- /dev/null
+<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
--- /dev/null
+<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
--- /dev/null
+<?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
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+<?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>
--- /dev/null
+<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
--- /dev/null
+<?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
--- /dev/null
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
--- /dev/null
+<?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 "Setting" to config profile, click "Start" 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>
--- /dev/null
+<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>
--- /dev/null
+<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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+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
--- /dev/null
+// 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
--- /dev/null
+# 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
--- /dev/null
+[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" }
+
--- /dev/null
+#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
--- /dev/null
+#!/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" "$@"
--- /dev/null
+@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
--- /dev/null
+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'
--- /dev/null
+<!--\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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+<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
--- /dev/null
+<?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
--- /dev/null
+<?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>
--- /dev/null
+# 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