# On windows, use "gradlew" instead.
$ ./gradlew clean assemble
-$ adb install -r app/build/outputs/apk/app-profiling.apk
+$ adb install -r app/build/outputs/apk/profiling/app-profiling.apk
```
2. Record profiling data:
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
- implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:25.4.0'
testImplementation 'junit:junit:4.12'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:name=".SleepActivity"
+ android:exported="true">
+
+ </activity>
</application>
</manifest>
\ No newline at end of file
--- /dev/null
+package com.example.simpleperf.simpleperfexampleofkotlin
+
+import android.support.v7.app.AppCompatActivity
+import android.os.Bundle
+
+class SleepActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_sleep)
+ createRunSleepThread();
+ }
+
+ fun createRunSleepThread() {
+ object : Thread() {
+ var counter = 0
+ var totalRunTimeInNs: Long = 0
+ var totalSleepTimeInNs: Long = 0
+
+ fun RunFunction(): Long {
+ var startTimeInNs = System.nanoTime()
+ var i = 0
+ while (i < 10000000) {
+ counter = callFunction(counter)
+ i++
+ }
+ return System.nanoTime() - startTimeInNs
+ }
+
+ fun SleepFunction(sleepTimeInNs: Long): Long {
+ var startTimeInNs = System.nanoTime()
+ Thread.sleep(sleepTimeInNs / 1000000, (sleepTimeInNs % 1000000).toInt())
+ return System.nanoTime() - startTimeInNs
+ }
+
+ override fun run() {
+ while (true) {
+ totalRunTimeInNs += RunFunction()
+ if (totalSleepTimeInNs < totalRunTimeInNs) {
+ totalSleepTimeInNs += SleepFunction(totalRunTimeInNs - totalSleepTimeInNs)
+ }
+ }
+ }
+
+ fun callFunction(i: Int): Int {
+ return i + 1
+ }
+ }.start()
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity">
+
+</android.support.constraint.ConstraintLayout>
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.0.0-alpha4'
+ classpath 'com.android.tools.build:gradle:3.0.0-alpha8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
-#Mon Jun 26 18:23:25 PDT 2017
+#Wed Jul 26 16:12:43 PDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-rc-1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
- <component name="EntryPointsManager">
- <entry_points version="2.0" />
- </component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
</value>
</option>
</component>
- <component name="ProjectLevelVcsManager" settingsEditedManually="false">
- <OptionsSetting value="true" id="Add" />
- <OptionsSetting value="true" id="Remove" />
- <OptionsSetting value="true" id="Checkout" />
- <OptionsSetting value="true" id="Update" />
- <OptionsSetting value="true" id="Status" />
- <OptionsSetting value="true" id="Edit" />
- <ConfirmationsSetting value="0" id="Add" />
- <ConfirmationsSetting value="0" id="Remove" />
- </component>
- <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:name=".SleepActivity"
+ android:exported="true">
+
+ </activity>
</application>
</manifest>
\ No newline at end of file
void createBusyThread() {
new Thread(new Runnable() {
-
volatile int i = 0;
@Override
private int callFunction(int a) {
return a+1;
}
- }).start();
+ }, "BusyThread").start();
}
}
--- /dev/null
+package com.example.simpleperf.simpleperfexamplepurejava;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+public class SleepActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_sleep);
+ createRunSleepThread();
+ }
+
+ void createRunSleepThread() {
+ new Thread(new Runnable() {
+ volatile int counter = 0;
+ long totalRunTimeInNs = 0;
+ long totalSleepTimeInNs = 0;
+
+ private long RunFunction() {
+ long startTimeInNs = System.nanoTime();
+ for (int i = 0; i < 10000000; ++i) {
+ counter = callFunction(counter);
+ }
+ return System.nanoTime() - startTimeInNs;
+ }
+
+ private long SleepFunction(long sleepTimeInNs) {
+ long startTimeInNs = System.nanoTime();
+ try {
+ Thread.sleep(sleepTimeInNs / 1000000, (int) (sleepTimeInNs % 1000000));
+ } catch (Exception e) {
+ }
+ return System.nanoTime() - startTimeInNs;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ totalRunTimeInNs += RunFunction();
+ if (totalSleepTimeInNs < totalRunTimeInNs) {
+ totalSleepTimeInNs += SleepFunction(
+ totalRunTimeInNs - totalSleepTimeInNs);
+ }
+ }
+ }
+
+ private int callFunction(int a) {
+ return a+1;
+ }
+ }, "RunSleepThread").start();
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.simpleperf.simpleperfexamplepurejava.SleepActivity">
+
+</android.support.constraint.ConstraintLayout>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
- <component name="EntryPointsManager">
- <entry_points version="2.0" />
- </component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
</value>
</option>
</component>
- <component name="ProjectLevelVcsManager" settingsEditedManually="false">
- <OptionsSetting value="true" id="Add" />
- <OptionsSetting value="true" id="Remove" />
- <OptionsSetting value="true" id="Checkout" />
- <OptionsSetting value="true" id="Update" />
- <OptionsSetting value="true" id="Status" />
- <OptionsSetting value="true" id="Edit" />
- <ConfirmationsSetting value="0" id="Add" />
- <ConfirmationsSetting value="0" id="Remove" />
- </component>
- <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
}
dependencies {
+ implementation 'com.android.support.constraint:constraint-layout:1.0.2'
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity
+ android:name=".SleepActivity"
+ android:exported="true"></activity>
+ <activity android:name=".MixActivity"
+ android:exported="true">
+
+ </activity>
</application>
</manifest>
\ No newline at end of file
#include <pthread.h>
#include <stdlib.h>
-
+#include <time.h>
#include <string>
-
+#define noinline __attribute__((__noinline__))
extern "C"
JNIEXPORT jstring JNICALL
return;
}
}
+
+static inline uint64_t GetSystemClock() {
+ timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+}
+
+constexpr int LOOP_COUNT = 100000000;
+static uint64_t noinline RunFunction() {
+ uint64_t start_time_in_ns = GetSystemClock();
+ for (volatile int i = 0; i < LOOP_COUNT; ++i) {
+ }
+ return GetSystemClock() - start_time_in_ns;
+}
+
+static uint64_t noinline SleepFunction(unsigned long long sleep_time_in_ns) {
+ uint64_t start_time_in_ns = GetSystemClock();
+ struct timespec req;
+ req.tv_sec = sleep_time_in_ns / 1000000000;
+ req.tv_nsec = sleep_time_in_ns % 1000000000;
+ nanosleep(&req, nullptr);
+ return GetSystemClock() - start_time_in_ns;
+}
+
+static void* SleepThread(void*) {
+ pthread_setname_np(pthread_self(), "SleepThread");
+ uint64_t total_sleep_time_in_ns = 0;
+ uint64_t total_run_time_in_ns = 0;
+ while (true) {
+ total_run_time_in_ns += RunFunction();
+ if (total_sleep_time_in_ns < total_run_time_in_ns) {
+ total_sleep_time_in_ns += SleepFunction(total_run_time_in_ns - total_sleep_time_in_ns);
+ }
+ }
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_example_simpleperf_simpleperfexamplewithnative_SleepActivity_createSleepThreadFromJNI(
+ JNIEnv *env,
+ jobject /* this */) {
+ pthread_t thread;
+ int ret = pthread_create(&thread, nullptr, SleepThread, nullptr);
+ if (ret) {
+ ThrowErrnoException(env, "pthread_create", ret);
+ return;
+ }
+}
+
+extern "C"
+JNIEXPORT int JNICALL
+Java_com_example_simpleperf_simpleperfexamplewithnative_MixActivity_callFunction(
+ JNIEnv *env,
+ jobject /* this */,
+ int a) {
+ return CallFunction(a);
+}
\ No newline at end of file
-package com.example.simpleperf.simpleperfexamplepurejava;
+package com.example.simpleperf.simpleperfexamplewithnative;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
-public class MainActivity extends AppCompatActivity {
+public class MixActivity extends AppCompatActivity {
+
+ static {
+ System.loadLibrary("native-lib");
+ }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
+ setContentView(R.layout.activity_mix);
createBusyThread();
}
void createBusyThread() {
new Thread(new Runnable() {
-
volatile int i = 0;
@Override
}
}
- private int callFunction(int a) {
- return a+1;
- }
- }).start();
+ }, "BusyThread").start();
}
+
+ private native int callFunction(int a);
}
--- /dev/null
+package com.example.simpleperf.simpleperfexamplewithnative;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+public class SleepActivity extends AppCompatActivity {
+
+ static {
+ System.loadLibrary("native-lib");
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_sleep);
+ createSleepThreadFromJNI();
+ }
+
+ private native void createSleepThreadFromJNI();
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.simpleperf.simpleperfexamplewithnative.MixActivity">
+
+</android.support.constraint.ConstraintLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.simpleperf.simpleperfexamplewithnative.SleepActivity">
+
+</android.support.constraint.ConstraintLayout>
buildscript {
repositories {
jcenter()
+ maven { url 'https://maven.google.com' }
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.1'
+ classpath 'com.android.tools.build:gradle:3.0.0-alpha8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
-#Wed Apr 26 20:39:16 PDT 2017
+#Wed Jul 26 15:32:48 PDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
static bool warned = false;
if (!warned) {
warned = true;
- PLOG(INFO) << "Adjust sample freq to max allowed sample freq " << max_sample_freq;
+ LOG(INFO) << "Adjust sample freq to max allowed sample freq " << max_sample_freq;
}
real_attr.sample_freq = max_sample_freq;
}
SIMPLEPERF_SCRIPT_LIST := $(wildcard $(LOCAL_PATH)/*.py $(LOCAL_PATH)/*.config) \
$(LOCAL_PATH)/../README.md \
- $(LOCAL_PATH)/testdata
+ $(LOCAL_PATH)/../demo \
+ $(LOCAL_PATH)/../testdata/perf_with_symbols.data \
+ $(LOCAL_PATH)/../testdata/perf_with_trace_offcpu.data
SIMPLEPERF_SCRIPT_LIST := $(filter-out $(LOCAL_PATH)/update.py,$(SIMPLEPERF_SCRIPT_LIST))
$(HOST_OUT_EXECUTABLES)/simpleperf_script.zip : $(SIMPLEPERF_SCRIPT_LIST)
- zip -j - $^ >$@
+ zip -r - $^ >$@
SIMPLEPERF_SCRIPT_LIST :=
to make sure perf.data is completely generated."""
has_killed = False
while True:
- (result, _) = self.adb.run(['pidof', 'simpleperf'], check_result=False)
+ (result, _) = self.adb.run_and_return_output(['shell', 'pidof', 'simpleperf'])
if not result:
break
if not has_killed:
has_killed = True
- self.adb.run(['pkill', '-l', '2', 'simpleperf'], check_result=False)
+ self.adb.run_and_return_output(['shell', 'pkill', '-l', '2', 'simpleperf'])
time.sleep(1)
has_google_protobuf = False
-class TestExamplesBase(unittest.TestCase):
+adb = AdbHelper()
+# TODO: Change to check ro.build.version.sdk >= 26 when OMR1 is prevalent.
+device_version = adb.check_run_and_return_output(['shell', 'getprop', 'ro.build.version.release'])
+support_trace_offcpu = device_version.find('OMR1') != -1
+
+def build_testdata():
+ """ Collect testdata from ../testdata and ../demo. """
+ from_testdata_path = os.path.join('..', 'testdata')
+ from_demo_path = os.path.join('..', 'demo')
+ if not os.path.isdir(from_testdata_path) or not os.path.isdir(from_demo_path):
+ return
+ copy_testdata_list = ['perf_with_symbols.data', 'perf_with_trace_offcpu.data']
+ copy_demo_list = ['SimpleperfExamplePureJava', 'SimpleperfExampleWithNative',
+ 'SimpleperfExampleOfKotlin']
+
+ testdata_path = "testdata"
+ if os.path.isdir(testdata_path):
+ shutil.rmtree(testdata_path)
+ os.mkdir(testdata_path)
+ for testdata in copy_testdata_list:
+ shutil.copy(os.path.join(from_testdata_path, testdata), testdata_path)
+ for demo in copy_demo_list:
+ shutil.copytree(os.path.join(from_demo_path, demo), os.path.join(testdata_path, demo))
+
+
+class TestExampleBase(unittest.TestCase):
@classmethod
def prepare(cls, example_name, package_name, activity_name, abi=None, adb_root=False):
cls.adb = AdbHelper(enable_switch_to_root=adb_root)
cls.example_path = os.path.join("testdata", example_name)
if not os.path.isdir(cls.example_path):
log_fatal("can't find " + cls.example_path)
- cls.apk_path = os.path.join(cls.example_path, "app-profiling.apk")
- if not os.path.isfile(cls.apk_path):
- log_fatal("can't find " + cls.apk_path)
+ for root, _, files in os.walk(cls.example_path):
+ if 'app-profiling.apk' in files:
+ cls.apk_path = os.path.join(root, 'app-profiling.apk')
+ break
+ if not hasattr(cls, 'apk_path'):
+ log_fatal("can't find app-profiling.apk under " + cls.example_path)
cls.package_name = package_name
cls.activity_name = activity_name
cls.python_path = sys.executable
cls.adb_root = adb_root
cls.compiled = False
+ def setUp(self):
+ if self.id().find('TraceOffCpu') != -1 and not support_trace_offcpu:
+ self.skipTest('trace-offcpu is not supported on device')
+
@classmethod
def tearDownClass(cls):
cls.adb.check_run(["uninstall", cls.package_name])
["has_line_numbers: False"])
-class TestExamplePureJava(TestExamplesBase):
+class TestExamplePureJava(TestExampleBase):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExamplePureJava",
["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()"])
-class TestExamplePureJavaRoot(TestExamplesBase):
+class TestExamplePureJavaRoot(TestExampleBase):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExamplePureJava",
self.common_test_app_profiler()
-class TestExampleWithNative(TestExamplesBase):
+class TestExamplePureJavaTraceOffCpu(TestExampleBase):
+ @classmethod
+ def setUpClass(cls):
+ cls.prepare("SimpleperfExamplePureJava",
+ "com.example.simpleperf.simpleperfexamplepurejava",
+ ".SleepActivity")
+
+ def test_smoke(self):
+ self.run_app_profiler(record_arg = "-g --duration 3 -e cpu-cycles:u --trace-offcpu")
+ self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+ self.check_strings_in_file("report.txt",
+ ["com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run()",
+ "long com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction()",
+ "long com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction(long)"
+ ])
+ self.remove("annotated_files")
+ self.run_cmd(["annotate.py", "-s", self.example_path])
+ self.check_exist(dir="annotated_files")
+ self.check_file_under_dir("annotated_files", "SleepActivity.java")
+ summary_file = os.path.join("annotated_files", "summary")
+ self.check_annotation_summary(summary_file,
+ [("SleepActivity.java", 80, 20),
+ ("run", 80, 0),
+ ("RunFunction", 20, 20),
+ ("SleepFunction", 20, 0),
+ ("line 24", 20, 0),
+ ("line 32", 20, 0)])
+
+
+class TestExampleWithNative(TestExampleBase):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleWithNative",
["BusyLoopThread"])
-class TestExampleWithNativeRoot(TestExamplesBase):
+class TestExampleWithNativeRoot(TestExampleBase):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleWithNative",
self.run_app_profiler(native_lib_dir=self.example_path)
+class TestExampleWithNativeTraceOffCpu(TestExampleBase):
+ @classmethod
+ def setUpClass(cls):
+ cls.prepare("SimpleperfExampleWithNative",
+ "com.example.simpleperf.simpleperfexamplewithnative",
+ ".SleepActivity")
+
+ def test_smoke(self):
+ self.run_app_profiler(record_arg = "-g --duration 3 -e cpu-cycles:u --trace-offcpu")
+ self.run_cmd(["report.py", "-g", "--comms", "SleepThread", "-o", "report.txt"])
+ self.check_strings_in_file("report.txt",
+ ["SleepThread(void*)",
+ "RunFunction()",
+ "SleepFunction(unsigned long long)"])
+ self.remove("annotated_files")
+ self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "SleepThread"])
+ self.check_exist(dir="annotated_files")
+ self.check_file_under_dir("annotated_files", "native-lib.cpp")
+ summary_file = os.path.join("annotated_files", "summary")
+ self.check_annotation_summary(summary_file,
+ [("native-lib.cpp", 80, 20),
+ ("SleepThread", 80, 0),
+ ("RunFunction", 20, 20),
+ ("SleepFunction", 20, 0),
+ ("line 73", 20, 0),
+ ("line 83", 20, 0)])
+
+
+class TestExampleWithNativeJniCall(TestExampleBase):
+ @classmethod
+ def setUpClass(cls):
+ cls.prepare("SimpleperfExampleWithNative",
+ "com.example.simpleperf.simpleperfexamplewithnative",
+ ".MixActivity")
+
+ def test_smoke(self):
+ self.run_app_profiler()
+ self.run_cmd(["report.py", "-g", "--comms", "BusyThread", "-o", "report.txt"])
+ self.check_strings_in_file("report.txt",
+ ["void com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run()",
+ "int com.example.simpleperf.simpleperfexamplewithnative.MixActivity.callFunction(int)",
+ "Java_com_example_simpleperf_simpleperfexamplewithnative_MixActivity_callFunction"])
+ self.remove("annotated_files")
+ self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "BusyThread"])
+ self.check_exist(dir="annotated_files")
+ self.check_file_under_dir("annotated_files", "native-lib.cpp")
+ self.check_file_under_dir("annotated_files", "MixActivity.java")
+ summary_file = os.path.join("annotated_files", "summary")
+ self.check_annotation_summary(summary_file,
+ [("MixActivity.java", 80, 0),
+ ("run", 80, 0),
+ ("line 26", 20, 0),
+ ("native-lib.cpp", 10, 0),
+ ("line 40", 10, 0)])
+
+
class TestExampleWithNativeForceArm(TestExampleWithNative):
@classmethod
def setUpClass(cls):
adb_root=False)
-class TestExampleOfKotlin(TestExamplesBase):
+class TestExampleWithNativeTraceOffCpuForceArm(TestExampleWithNativeTraceOffCpu):
+ @classmethod
+ def setUpClass(cls):
+ cls.prepare("SimpleperfExampleWithNative",
+ "com.example.simpleperf.simpleperfexamplewithnative",
+ ".SleepActivity",
+ abi="armeabi-v7a")
+
+
+class TestExampleOfKotlin(TestExampleBase):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleOfKotlin",
["com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1.run()"])
-class TestExampleOfKotlinRoot(TestExamplesBase):
+class TestExampleOfKotlinRoot(TestExampleBase):
@classmethod
def setUpClass(cls):
cls.prepare("SimpleperfExampleOfKotlin",
self.common_test_app_profiler()
+class TestExampleOfKotlinTraceOffCpu(TestExampleBase):
+ @classmethod
+ def setUpClass(cls):
+ cls.prepare("SimpleperfExampleOfKotlin",
+ "com.example.simpleperf.simpleperfexampleofkotlin",
+ ".SleepActivity")
+
+ def test_smoke(self):
+ self.run_app_profiler(record_arg = "-g --duration 3 -e cpu-cycles:u --trace-offcpu")
+ self.run_cmd(["report.py", "-g", "-o", "report.txt"])
+ self.check_strings_in_file("report.txt",
+ ["void com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.run()",
+ "long com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.RunFunction()",
+ "long com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.SleepFunction(long)"
+ ])
+ self.remove("annotated_files")
+ self.run_cmd(["annotate.py", "-s", self.example_path])
+ self.check_exist(dir="annotated_files")
+ self.check_file_under_dir("annotated_files", "SleepActivity.kt")
+ summary_file = os.path.join("annotated_files", "summary")
+ self.check_annotation_summary(summary_file,
+ [("SleepActivity.kt", 80, 20),
+ ("run", 80, 0),
+ ("RunFunction", 20, 20),
+ ("SleepFunction", 20, 0),
+ ("line 24", 20, 0),
+ ("line 32", 20, 0)])
+
+
class TestReportLib(unittest.TestCase):
def setUp(self):
self.report_lib = ReportLib()
self.assertAlmostEqual(sleep_percentage, 0.4629, delta=0.0001)
-if __name__ == '__main__':
+def main():
+ build_testdata()
test_program = unittest.main(failfast=True, exit=False)
if test_program.result.wasSuccessful():
- TestExamplesBase.cleanupTestFiles()
\ No newline at end of file
+ TestExampleBase.cleanupTestFiles()
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
+++ /dev/null
-package com.example.simpleperf.simpleperfexampleofkotlin
-
-import android.support.v7.app.AppCompatActivity
-import android.os.Bundle
-
-class MainActivity : AppCompatActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- createBusyThread()
- }
-
- fun createBusyThread() {
- object : Thread() {
- var i = 0
-
- override fun run() {
- while (true) {
- i = callFunction(i)
- }
- }
-
- fun callFunction(i: Int): Int {
- return i + 1
- }
- }.start()
- }
-}
+++ /dev/null
-#include <jni.h>
-
-#include <pthread.h>
-#include <stdlib.h>
-
-#include <string>
-
-
-
-extern "C"
-JNIEXPORT jstring JNICALL
-Java_com_example_simpleperf_simpleperfexamplewithnative_MainActivity_stringFromJNI(
- JNIEnv *env,
- jobject /* this */) {
- std::string hello = "Hello from C++";
- return env->NewStringUTF(hello.c_str());
-}
-
-static void ThrowErrnoException(JNIEnv* env, const char* function_name, int err) {
- jclass cls = env->FindClass("android/system/ErrnoException");
- if (cls == nullptr) {
- return;
- }
- jmethodID cid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;I)V");
- if (cid == nullptr) {
- return;
- }
- jstring msg = env->NewStringUTF(function_name);
- if (msg == nullptr) {
- return;
- }
- jthrowable obj = (jthrowable)env->NewObject(cls, cid, msg, err);
- if (obj == nullptr) {
- return;
- }
- env->Throw(obj);
-}
-
-int CallFunction(int a) {
- return a + atoi("1");
-}
-
-static void* BusyLoopThread(void*) {
- volatile int i = 0;
- while (true) {
- i = CallFunction(i);
- }
- return nullptr;
-}
-
-extern "C"
-JNIEXPORT void JNICALL
-Java_com_example_simpleperf_simpleperfexamplewithnative_MainActivity_createBusyThreadFromJNI(
- JNIEnv *env,
- jobject /* this */) {
- pthread_t thread;
- int ret = pthread_create(&thread, nullptr, BusyLoopThread, nullptr);
- if (ret) {
- ThrowErrnoException(env, "pthread_create", ret);
- return;
- }
-}
+++ /dev/null
-package com.example.simpleperf.simpleperfexamplewithnative;
-
-import android.support.v7.app.AppCompatActivity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-public class MainActivity extends AppCompatActivity {
-
- // Used to load the 'native-lib' library on application startup.
- static {
- System.loadLibrary("native-lib");
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // Example of a call to a native method
- TextView tv = (TextView) findViewById(R.id.sample_text);
- tv.setText(stringFromJNI());
-
- createBusyThreadFromJNI();
- }
-
- /**
- * A native method that is implemented by the 'native-lib' native library,
- * which is packaged with this application.
- */
- public native String stringFromJNI();
-
- private native void createBusyThreadFromJNI();
-}