Mark libpagemap vendor_available.
am: 775665d0fe -s ours
Change-Id: If2fd9319761c8b6e7c63559ccb89ffe75ed3df38
diff --git a/boot_control_copy/boot_control_copy.c b/boot_control_copy/boot_control_copy.c
index 7302243..d8a5d18 100644
--- a/boot_control_copy/boot_control_copy.c
+++ b/boot_control_copy/boot_control_copy.c
@@ -16,6 +16,7 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
diff --git a/brillo_config/Android.mk b/brillo_config/Android.mk
index fb0cd75..e5bb75a 100644
--- a/brillo_config/Android.mk
+++ b/brillo_config/Android.mk
@@ -24,12 +24,6 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_OEM)/$(OSRELEASED_DIRECTORY)
include $(BUILD_SYSTEM)/base_rules.mk
-# Attempt to populate the product id from a file in the product path.
-LOADED_BRILLO_PRODUCT_ID := $(call cfgtree-get-if-exists,brillo/product_id)
-
-# We don't really have a default value for the product id as the backend
-# interaction will not work if this is not set correctly.
-$(LOCAL_BUILT_MODULE): BRILLO_PRODUCT_ID ?= "$(LOADED_BRILLO_PRODUCT_ID)"
$(LOCAL_BUILT_MODULE):
$(hide) mkdir -p $(dir $@)
echo $(BRILLO_PRODUCT_ID) > $@
@@ -42,10 +36,6 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)
include $(BUILD_SYSTEM)/base_rules.mk
-# Attempt to populate the system id from a file in the product path.
-LOADED_BRILLO_SYSTEM_ID := $(call cfgtree-get-if-exists,brillo/system_id)
-
-$(LOCAL_BUILT_MODULE): BRILLO_SYSTEM_ID ?= "$(LOADED_BRILLO_SYSTEM_ID)"
$(LOCAL_BUILT_MODULE):
$(hide) mkdir -p $(dir $@)
echo $(BRILLO_SYSTEM_ID) > $@
@@ -57,15 +47,9 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_OEM)/$(OSRELEASED_DIRECTORY)
include $(BUILD_SYSTEM)/base_rules.mk
-# The version is set to 0 if the user did not set the actual version and
-# a version cannot be loaded from the product cfgtree.
+# The version is set to 0 if the user did not set the actual version.
# This allows us to have a valid version number while being easy to filter.
ifeq ($(BRILLO_PRODUCT_VERSION),)
-# Load from file first
-BRILLO_PRODUCT_VERSION := $(call cfgtree-get-if-exists,brillo/product_version)
-endif
-# If the version is still empty, override it with 0
-ifeq ($(BRILLO_PRODUCT_VERSION),)
BRILLO_PRODUCT_VERSION := "0"
endif
ifeq ($(shell echo $(BRILLO_PRODUCT_VERSION) | grep -E '^[0-9]+$$'),)
@@ -86,15 +70,9 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/$(OSRELEASED_DIRECTORY)
include $(BUILD_SYSTEM)/base_rules.mk
-# The version is set to 0.0 if the user did not set the actual version and
-# a version cannot be loaded from the product cfgtree.
+# The version is set to 0.0 if the user did not set the actual version.
# This allows us to have a valid version number while being easy to filter.
ifeq ($(BRILLO_SYSTEM_VERSION),)
-# Load from file first
-BRILLO_SYSTEM_VERSION := $(call cfgtree-get-if-exists,brillo/system_version)
-endif
-# If the version is still empty, override it with 0.0
-ifeq ($(BRILLO_SYSTEM_VERSION),)
BRILLO_SYSTEM_VERSION := "0.0"
endif
ifeq ($(shell echo $(BRILLO_SYSTEM_VERSION) | grep -E '^[0-9]+\.[0-9]+$$'),)
diff --git a/ext4_utils/Android.bp b/ext4_utils/Android.bp
index a2987aa..493fae5 100644
--- a/ext4_utils/Android.bp
+++ b/ext4_utils/Android.bp
@@ -41,11 +41,11 @@
android: {
srcs: [
- "key_control.cpp",
"ext4_crypt.cpp",
],
shared_libs: [
"libbase",
+ "libkeyutils",
"libselinux",
],
diff --git a/ext4_utils/ext4_crypt_init_extensions.cpp b/ext4_utils/ext4_crypt_init_extensions.cpp
index ee8bfbe..2bf8801 100644
--- a/ext4_utils/ext4_crypt_init_extensions.cpp
+++ b/ext4_utils/ext4_crypt_init_extensions.cpp
@@ -31,10 +31,10 @@
#include <android-base/strings.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
+#include <keyutils.h>
#include <logwrap/logwrap.h>
#include "ext4_utils/ext4_crypt.h"
-#include "ext4_utils/key_control.h"
#define TAG "ext4_utils"
@@ -56,15 +56,6 @@
return 0;
}
-int e4crypt_do_init_user0()
-{
- const char* argv[] = { "/system/bin/vdc", "--wait", "cryptfs", "init_user0" };
- int rc = android_fork_execvp_ext(arraysize(argv), (char**) argv, NULL, false,
- LOG_KLOG, false, NULL, NULL, 0);
- LOG(INFO) << "init_user0 result: " << rc;
- return rc;
-}
-
int e4crypt_set_directory_policy(const char* dir)
{
// Only set policy on first level /data directories
diff --git a/ext4_utils/include/ext4_utils/ext4_crypt_init_extensions.h b/ext4_utils/include/ext4_utils/ext4_crypt_init_extensions.h
index e208b45..f14d4a9 100644
--- a/ext4_utils/include/ext4_utils/ext4_crypt_init_extensions.h
+++ b/ext4_utils/include/ext4_utils/ext4_crypt_init_extensions.h
@@ -27,7 +27,6 @@
// They will not operate properly outside of init
int e4crypt_install_keyring();
int e4crypt_set_directory_policy(const char* path);
-int e4crypt_do_init_user0();
__END_DECLS
diff --git a/ext4_utils/include/ext4_utils/key_control.h b/ext4_utils/include/ext4_utils/key_control.h
deleted file mode 100644
index 9b18413..0000000
--- a/ext4_utils/include/ext4_utils/key_control.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _KEY_CONTROL_H_
-#define _KEY_CONTROL_H_
-
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-__BEGIN_DECLS
-
-// ext4enc:TODO - get these keyring standard definitions from proper system file
-// keyring serial number type
-typedef int32_t key_serial_t;
-
-// special process keyring shortcut IDs
-#define KEY_SPEC_THREAD_KEYRING (-1) // key ID for thread-specific keyring
-#define KEY_SPEC_PROCESS_KEYRING (-2) // key ID for process-specific keyring
-#define KEY_SPEC_SESSION_KEYRING (-3) // key ID for session-specific keyring
-#define KEY_SPEC_USER_KEYRING (-4) // key ID for UID-specific keyring
-#define KEY_SPEC_USER_SESSION_KEYRING (-5) // key ID for UID-session keyring
-#define KEY_SPEC_GROUP_KEYRING (-6) // key ID for GID-specific keyring
-
-key_serial_t add_key(const char *type,
- const char *description,
- const void *payload,
- size_t plen,
- key_serial_t ringid);
-
-long keyctl_unlink(key_serial_t key, key_serial_t keyring);
-
-long keyctl_setperm(key_serial_t id, int permissions);
-
-long keyctl_search(key_serial_t ringid, const char *type,
- const char *description, key_serial_t destringid);
-
-__END_DECLS
-
-#endif // _KEY_CONTROL_H_
diff --git a/ext4_utils/key_control.cpp b/ext4_utils/key_control.cpp
deleted file mode 100644
index e295cbe..0000000
--- a/ext4_utils/key_control.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include "ext4_utils/key_control.h"
-
-#include <stdarg.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-#include <linux/keyctl.h>
-
-static long keyctl(int cmd, ...)
-{
- va_list va;
- unsigned long arg2, arg3, arg4, arg5;
-
- va_start(va, cmd);
- arg2 = va_arg(va, unsigned long);
- arg3 = va_arg(va, unsigned long);
- arg4 = va_arg(va, unsigned long);
- arg5 = va_arg(va, unsigned long);
- va_end(va);
- return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
-}
-
-key_serial_t add_key(const char *type,
- const char *description,
- const void *payload,
- size_t plen,
- key_serial_t ringid)
-{
- return syscall(__NR_add_key, type, description, payload, plen, ringid);
-}
-
-long keyctl_unlink(key_serial_t key, key_serial_t keyring)
-{
- return keyctl(KEYCTL_UNLINK, key, keyring);
-}
-
-long keyctl_setperm(key_serial_t id, int permissions)
-{
- return keyctl(KEYCTL_SETPERM, id, permissions);
-}
-
-long keyctl_search(key_serial_t ringid, const char *type,
- const char *description, key_serial_t destringid)
-{
- return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid);
-}
diff --git a/f2fs_utils/Android.bp b/f2fs_utils/Android.bp
new file mode 100644
index 0000000..afa5627
--- /dev/null
+++ b/f2fs_utils/Android.bp
@@ -0,0 +1,204 @@
+// Copyright 2017 The Android Open Source Project
+
+cc_library_host_static {
+ name: "libf2fs_utils_host",
+
+ srcs: ["f2fs_utils.c"],
+
+ static_libs: [
+ "libsparse",
+ "libz",
+ ],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "external/f2fs-tools/mkfs",
+ ],
+
+ cflags: ["-Wno-unused-parameter"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_host_static {
+ name: "libf2fs_ioutils_host",
+
+ srcs: ["f2fs_ioutils.c"],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "external/f2fs-tools/mkfs",
+ ],
+
+ cflags: ["-Wno-unused-parameter"],
+
+ static_libs: [
+ "libselinux",
+ "libsparse",
+ "libext2_uuid",
+ "libz",
+ ],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_host_static {
+ name: "libf2fs_dlutils_host",
+
+ srcs: ["f2fs_dlutils.c"],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "external/f2fs-tools/mkfs",
+ ],
+ // Will attempt to dlopen("libf2fs_fmt_host_dyn")
+ host_ldlibs: ["-ldl"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_binary_host {
+ name: "make_f2fs",
+
+ srcs: ["make_f2fs_main.c"],
+
+ // libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
+ host_ldlibs: [
+ "-ldl",
+ ],
+
+ ldflags: [
+ "-rdynamic"
+ ],
+
+ // The following libf2fs_* are from system/extras/f2fs_utils,
+ // and do not use code in external/f2fs-tools.
+ static_libs: [
+ "libf2fs_utils_host",
+ "libf2fs_ioutils_host",
+ "libf2fs_dlutils_host",
+ "libsparse",
+ "libz",
+ ],
+
+ required: ["libf2fs_fmt_host_dyn"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libf2fs_dlutils",
+
+ srcs: ["f2fs_dlutils.c"],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "external/f2fs-tools/mkfs",
+ ],
+
+ shared_libs: ["libdl"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_static {
+ name: "libf2fs_dlutils_static",
+
+ srcs: ["f2fs_dlutils.c"],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "external/f2fs-tools/mkfs",
+ ],
+
+ shared_libs: ["libdl"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_static {
+ name: "libf2fs_utils_static",
+
+ srcs: ["f2fs_utils.c"],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "external/f2fs-tools/mkfs",
+ ],
+
+ cflags: ["-Wno-unused-parameter"],
+
+ static_libs: ["libsparse"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libf2fs_sparseblock",
+
+ srcs: ["f2fs_sparseblock.c"],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ ],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "system/core/include/log",
+ ],
+
+ export_include_dirs: ["."]
+}
+
+cc_binary {
+ name: "f2fs_sparseblock",
+
+ srcs: ["f2fs_sparseblock.c"],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ ],
+
+ include_dirs: [
+ "external/f2fs-tools/include",
+ "system/core/include/log",
+ ],
+}
+
+cc_prebuilt_binary {
+ name: "mkf2fsuserimg.sh",
+
+ srcs: ["mkf2fsuserimg.sh"],
+
+ host_supported: true,
+}
diff --git a/f2fs_utils/Android.mk b/f2fs_utils/Android.mk
deleted file mode 100644
index 32ed0ed..0000000
--- a/f2fs_utils/Android.mk
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-ifeq ($(HOST_OS),linux)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libf2fs_utils_host
-LOCAL_SRC_FILES := f2fs_utils.c
-LOCAL_STATIC_LIBRARIES := \
- libsparse \
- libz
-LOCAL_C_INCLUDES := external/f2fs-tools/include external/f2fs-tools/mkfs
-LOCAL_CFLAGS := -Wno-unused-parameter
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := f2fs_ioutils.c
-LOCAL_C_INCLUDES := external/f2fs-tools/include external/f2fs-tools/mkfs
-LOCAL_CFLAGS := -Wno-unused-parameter
-LOCAL_STATIC_LIBRARIES := \
- libselinux \
- libsparse \
- libext2_uuid \
- libz
-LOCAL_MODULE := libf2fs_ioutils_host
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := f2fs_dlutils.c
-LOCAL_C_INCLUDES := external/f2fs-tools/include external/f2fs-tools/mkfs
-# Will attempt to dlopen("libf2fs_fmt_host_dyn")
-LOCAL_LDLIBS := -ldl
-LOCAL_MODULE := libf2fs_dlutils_host
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := make_f2fs_main.c
-LOCAL_MODULE := make_f2fs
-# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
-LOCAL_LDFLAGS := -ldl -rdynamic
-# The following libf2fs_* are from system/extras/f2fs_utils,
-# and do not use code in external/f2fs-tools.
-LOCAL_STATIC_LIBRARIES := libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
-LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn
-LOCAL_STATIC_LIBRARIES += \
- libsparse \
- libz
-include $(BUILD_HOST_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libf2fs_dlutils
-LOCAL_SRC_FILES := f2fs_dlutils.c
-LOCAL_C_INCLUDES := external/f2fs-tools/include external/f2fs-tools/mkfs
-LOCAL_SHARED_LIBRARIES := libdl
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libf2fs_dlutils_static
-LOCAL_SRC_FILES := f2fs_dlutils.c
-LOCAL_C_INCLUDES := external/f2fs-tools/include external/f2fs-tools/mkfs
-LOCAL_SHARED_LIBRARIES := libdl
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libf2fs_utils_static
-LOCAL_SRC_FILES := f2fs_utils.c
-LOCAL_C_INCLUDES := external/f2fs-tools/include external/f2fs-tools/mkfs
-LOCAL_CFLAGS := -Wno-unused-parameter
-LOCAL_STATIC_LIBRARIES := \
- libsparse
-include $(BUILD_STATIC_LIBRARY)
-
-endif
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libf2fs_sparseblock
-LOCAL_SRC_FILES := f2fs_sparseblock.c
-LOCAL_SHARED_LIBRARIES := liblog libcutils
-LOCAL_C_INCLUDES := external/f2fs-tools/include \
- system/core/include/log
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := f2fs_sparseblock
-LOCAL_SRC_FILES := f2fs_sparseblock.c
-LOCAL_SHARED_LIBRARIES := liblog libcutils
-LOCAL_C_INCLUDES := external/f2fs-tools/include \
- system/core/include/log
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := mkf2fsuserimg.sh
-LOCAL_SRC_FILES := mkf2fsuserimg.sh
-LOCAL_MODULE_CLASS := EXECUTABLES
-# We don't need any additional suffix.
-LOCAL_MODULE_SUFFIX :=
-LOCAL_BUILT_MODULE_STEM := $(notdir $(LOCAL_SRC_FILES))
-LOCAL_IS_HOST_MODULE := true
-include $(BUILD_PREBUILT)
-
-
diff --git a/f2fs_utils/f2fs_dlutils.c b/f2fs_utils/f2fs_dlutils.c
index 40be416..2ba3f7c 100644
--- a/f2fs_utils/f2fs_dlutils.c
+++ b/f2fs_utils/f2fs_dlutils.c
@@ -38,15 +38,16 @@
#define F2FS_DYN_LIB "libf2fs_fmt_host_dyn.so"
int (*f2fs_format_device_dl)(void);
-void (*f2fs_init_configuration_dl)(struct f2fs_configuration *);
+void (*f2fs_init_configuration_dl)(void);
+struct f2fs_configuration *c_dl;
int f2fs_format_device(void) {
assert(f2fs_format_device_dl);
return f2fs_format_device_dl();
}
-void f2fs_init_configuration(struct f2fs_configuration *config) {
+void f2fs_init_configuration(void) {
assert(f2fs_init_configuration_dl);
- f2fs_init_configuration_dl(config);
+ f2fs_init_configuration_dl();
}
int dlopenf2fs() {
@@ -58,7 +59,8 @@
}
f2fs_format_device_dl = dlsym(f2fs_lib, "f2fs_format_device");
f2fs_init_configuration_dl = dlsym(f2fs_lib, "f2fs_init_configuration");
- if (!f2fs_format_device_dl || !f2fs_init_configuration_dl) {
+ c_dl = dlsym(f2fs_lib, "c");
+ if (!f2fs_format_device_dl || !f2fs_init_configuration_dl || !c_dl) {
return -1;
}
return 0;
diff --git a/f2fs_utils/f2fs_ioutils.c b/f2fs_utils/f2fs_ioutils.c
index 4c12096..d3bc727 100644
--- a/f2fs_utils/f2fs_ioutils.c
+++ b/f2fs_utils/f2fs_ioutils.c
@@ -83,7 +83,7 @@
#endif
-struct f2fs_configuration config;
+extern struct f2fs_configuration *c_dl;
struct sparse_file *f2fs_sparse_file;
struct buf_item {
@@ -96,9 +96,9 @@
static int dev_write_fd(void *buf, __u64 offset, size_t len)
{
- if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
+ if (lseek64(c_dl->devices[0].fd, (off64_t)offset, SEEK_SET) < 0)
return -1;
- ssize_t written = write(config.fd, buf, len);
+ ssize_t written = write(c_dl->devices[0].fd, buf, len);
if (written == -1)
return -1;
if ((size_t)written != len)
@@ -138,7 +138,7 @@
return 0;
}
-void f2fs_finalize_device(struct f2fs_configuration *c)
+void f2fs_finalize_device()
{
}
@@ -162,18 +162,22 @@
int dev_write(void *buf, __u64 offset, size_t len)
{
- if (config.fd >= 0) {
+ if (c_dl->devices[0].fd >= 0) {
return dev_write_fd(buf, offset, len);
} else {
return dev_write_sparse(buf, offset, len);
}
}
+int dev_write_block(void *buf, __u64 offset)
+{
+ return dev_write(buf, offset << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
+}
int dev_fill(void *buf, __u64 offset, size_t len)
{
int ret;
- if (config.fd >= 0) {
+ if (c_dl->devices[0].fd >= 0) {
return dev_write_fd(buf, offset, len);
}
// sparse file fills with zero by default.
diff --git a/f2fs_utils/f2fs_sparseblock.c b/f2fs_utils/f2fs_sparseblock.c
index d5c1f3a..27225c6 100644
--- a/f2fs_utils/f2fs_sparseblock.c
+++ b/f2fs_utils/f2fs_sparseblock.c
@@ -28,9 +28,9 @@
#member, le64_to_cpu((ptr)->member), le64_to_cpu((ptr)->member) ); \
} while (0);
-#define segno_in_journal(sum, i) ((sum)->sit_j.entries[i].segno)
+#define segno_in_journal(jnl, i) ((jnl)->sit_j.entries[i].segno)
-#define sit_in_journal(sum, i) ((sum)->sit_j.entries[i].se)
+#define sit_in_journal(jnl, i) ((jnl)->sit_j.entries[i].se)
static void dbg_print_raw_sb_info(struct f2fs_super_block *sb)
{
@@ -132,27 +132,28 @@
SLOGD("+--------------------------------------------------------+\n");
SLOGD("| F2FS_INFO |\n");
SLOGD("+--------------------------------------------------------+\n");
- SLOGD("blocks_per_segment: %"PRIu64, info->blocks_per_segment);
+ SLOGD("blocks_per_segment: %" PRIu64, info->blocks_per_segment);
SLOGD("block_size: %d", info->block_size);
SLOGD("sit_bmp loc: %p", info->sit_bmp);
SLOGD("sit_bmp_size: %d", info->sit_bmp_size);
- SLOGD("blocks_per_sit: %"PRIu64, info->blocks_per_sit);
+ SLOGD("blocks_per_sit: %" PRIu64, info->blocks_per_sit);
SLOGD("sit_blocks loc: %p", info->sit_blocks);
SLOGD("sit_sums loc: %p", info->sit_sums);
- SLOGD("sit_sums num: %d", le16_to_cpu(info->sit_sums->n_sits));
+ SLOGD("sit_sums num: %d", le16_to_cpu(info->sit_sums->journal.n_sits));
unsigned int i;
- for(i = 0; i < (le16_to_cpu(info->sit_sums->n_sits)); i++) {
- SLOGD("entry %d in journal entries is for segment %d",i, le32_to_cpu(segno_in_journal(info->sit_sums, i)));
+ for(i = 0; i < (le16_to_cpu(info->sit_sums->journal.n_sits)); i++) {
+ SLOGD("entry %d in journal entries is for segment %d", i,
+ le32_to_cpu(segno_in_journal(&info->sit_sums->journal, i)));
}
- SLOGD("cp_blkaddr: %"PRIu64, info->cp_blkaddr);
- SLOGD("cp_valid_cp_blkaddr: %"PRIu64, info->cp_valid_cp_blkaddr);
- SLOGD("sit_blkaddr: %"PRIu64, info->sit_blkaddr);
- SLOGD("nat_blkaddr: %"PRIu64, info->nat_blkaddr);
- SLOGD("ssa_blkaddr: %"PRIu64, info->ssa_blkaddr);
- SLOGD("main_blkaddr: %"PRIu64, info->main_blkaddr);
- SLOGD("total_user_used: %"PRIu64, info->total_user_used);
- SLOGD("total_blocks: %"PRIu64, info->total_blocks);
+ SLOGD("cp_blkaddr: %" PRIu64, info->cp_blkaddr);
+ SLOGD("cp_valid_cp_blkaddr: %" PRIu64, info->cp_valid_cp_blkaddr);
+ SLOGD("sit_blkaddr: %" PRIu64, info->sit_blkaddr);
+ SLOGD("nat_blkaddr: %" PRIu64, info->nat_blkaddr);
+ SLOGD("ssa_blkaddr: %" PRIu64, info->ssa_blkaddr);
+ SLOGD("main_blkaddr: %" PRIu64, info->main_blkaddr);
+ SLOGD("total_user_used: %" PRIu64, info->total_user_used);
+ SLOGD("total_blocks: %" PRIu64, info->total_blocks);
SLOGD("\n\n");
}
@@ -362,7 +363,7 @@
if (is_set_ckpt_flags(cp, CP_COMPACT_SUM_FLAG)) {
if (read_structure_blk(fd, info->cp_valid_cp_blkaddr + le32_to_cpu(cp->cp_pack_start_sum), buffer, 1))
return -1;
- memcpy(&info->sit_sums->n_sits, &buffer[SUM_JOURNAL_SIZE], SUM_JOURNAL_SIZE);
+ memcpy(&info->sit_sums->journal.n_sits, &buffer[SUM_JOURNAL_SIZE], SUM_JOURNAL_SIZE);
} else {
u64 blk_addr;
if (is_set_ckpt_flags(cp, CP_UMOUNT_FLAG))
@@ -505,9 +506,9 @@
/* check the SIT entries in the journal */
found = 0;
- for(i = 0; i < le16_to_cpu(info->sit_sums->n_sits); i++) {
- if (le32_to_cpu(segno_in_journal(info->sit_sums, i)) == segnum) {
- sit_entry = &sit_in_journal(info->sit_sums, i);
+ for(i = 0; i < le16_to_cpu(info->sit_sums->journal.n_sits); i++) {
+ if (le32_to_cpu(segno_in_journal(&info->sit_sums->journal, i)) == segnum) {
+ sit_entry = &sit_in_journal(&info->sit_sums->journal, i);
found = 1;
break;
}
diff --git a/f2fs_utils/f2fs_utils.c b/f2fs_utils/f2fs_utils.c
index 6254c08..5223680 100644
--- a/f2fs_utils/f2fs_utils.c
+++ b/f2fs_utils/f2fs_utils.c
@@ -42,15 +42,11 @@
extern void flush_sparse_buffs();
-struct f2fs_configuration config;
+extern struct f2fs_configuration *c_dl;
struct sparse_file *f2fs_sparse_file;
extern int dlopenf2fs();
static void reset_f2fs_info() {
- // Reset all the global data structures used by make_f2fs so it
- // can be called again.
- memset(&config, 0, sizeof(config));
- config.fd = -1;
if (f2fs_sparse_file) {
sparse_file_destroy(f2fs_sparse_file);
f2fs_sparse_file = NULL;
@@ -64,10 +60,15 @@
return -1;
}
reset_f2fs_info();
- f2fs_init_configuration(&config);
+ f2fs_init_configuration();
len &= ~((__u64)(F2FS_BLKSIZE - 1));
- config.total_sectors = len / config.sector_size;
- config.start_sector = 0;
+ c_dl->ndevs = 1;
+ c_dl->devices[0].total_sectors = len / c_dl->devices[0].sector_size;
+ c_dl->sector_size = c_dl->devices[0].sector_size;
+ c_dl->sectors_per_blk = F2FS_BLKSIZE / c_dl->sector_size;
+ c_dl->total_sectors = c_dl->devices[0].total_sectors;
+ c_dl->start_sector = 0;
+ c_dl->trim = 0;
f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, len);
f2fs_format_device();
sparse_file_write(f2fs_sparse_file, fd, /*gzip*/0, /*sparse*/1, /*crc*/0);
diff --git a/memory_replay/Android.mk b/memory_replay/Android.mk
index 7179d61..2b299ad 100644
--- a/memory_replay/Android.mk
+++ b/memory_replay/Android.mk
@@ -47,6 +47,7 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/tests
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE := memory_replay_tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_SHARED_LIBRARIES := libbase
diff --git a/memory_replay/AndroidTest.xml b/memory_replay/AndroidTest.xml
new file mode 100644
index 0000000..cf3879a
--- /dev/null
+++ b/memory_replay/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for memory_replay_tests">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="memory_replay_tests->/data/local/tmp/memory_replay_tests" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="memory_replay_tests" />
+ </test>
+</configuration>
diff --git a/mmap-perf/Android.mk b/mmap-perf/Android.mk
index 4ea6a54..8379b08 100644
--- a/mmap-perf/Android.mk
+++ b/mmap-perf/Android.mk
@@ -19,6 +19,7 @@
LOCAL_SRC_FILES := mmapPerf.cpp
LOCAL_MODULE := mmapPerf
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
diff --git a/mmap-perf/AndroidTest.xml b/mmap-perf/AndroidTest.xml
new file mode 100644
index 0000000..386876f
--- /dev/null
+++ b/mmap-perf/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for mmapPerf">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="mmapPerf->/data/benchmarktest/mmapPerf" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+ <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+ <option name="benchmark-module-name" value="mmapPerf" />
+ </test>
+</configuration>
diff --git a/perfprofd/Android.mk b/perfprofd/Android.mk
deleted file mode 100644
index 73a9ecb..0000000
--- a/perfprofd/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/perfprofd/tests/Android.bp b/perfprofd/tests/Android.bp
index f3a5bb8..7bd5041 100644
--- a/perfprofd/tests/Android.bp
+++ b/perfprofd/tests/Android.bp
@@ -24,6 +24,7 @@
//
cc_test {
name: "perfprofd_test",
+ test_suites: ["device-tests"],
clang: true,
stl: "libc++",
@@ -39,4 +40,8 @@
],
srcs: ["perfprofd_test.cc"],
cppflags: perfprofd_test_cppflags,
+ data: [
+ "canned.perf.data",
+ "callchain.canned.perf.data",
+ ],
}
diff --git a/perfprofd/tests/Android.mk b/perfprofd/tests/Android.mk
deleted file mode 100644
index 30ea7c9..0000000
--- a/perfprofd/tests/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# Unit tests are in Android.bp
-
-#
-# Canned perf.data file needed by unit test.
-#
-include $(CLEAR_VARS)
-LOCAL_MODULE := canned.perf.data
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := DATA
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_NATIVE_TESTS)/perfprofd_test
-LOCAL_SRC_FILES := canned.perf.data
-include $(BUILD_PREBUILT)
-
-#
-# Second canned perf.data file needed by unit test.
-#
-include $(CLEAR_VARS)
-LOCAL_MODULE := callchain.canned.perf.data
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := DATA
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_NATIVE_TESTS)/perfprofd_test
-LOCAL_SRC_FILES := callchain.canned.perf.data
-include $(BUILD_PREBUILT)
diff --git a/perfprofd/tests/AndroidTest.xml b/perfprofd/tests/AndroidTest.xml
new file mode 100644
index 0000000..5d3eda1
--- /dev/null
+++ b/perfprofd/tests/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for perfprofd_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="perfprofd_test->/data/local/tmp/perfprofd_test" />
+ <option name="push" value="canned.perf.data->/data/local/tmp/perfprofd_test" />
+ <option name="push" value="callchain.canned.perf.data->/data/local/tmp/perfprofd_test" />
+
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="perfprofd_test" />
+ </test>
+</configuration>
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index af4e781..eb72d88 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -315,6 +315,7 @@
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := simpleperf_unit_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CPPFLAGS := $(simpleperf_cppflags_target)
LOCAL_SRC_FILES := \
$(simpleperf_unit_test_src_files) \
@@ -354,6 +355,7 @@
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := simpleperf_cpu_hotplug_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_CPPFLAGS := $(simpleperf_cppflags_target)
LOCAL_SRC_FILES := $(simpleperf_cpu_hotplug_test_src_files)
LOCAL_STATIC_LIBRARIES := libsimpleperf $(simpleperf_static_libraries_target)
diff --git a/simpleperf/AndroidTest.xml b/simpleperf/AndroidTest.xml
new file mode 100644
index 0000000..310cd2a
--- /dev/null
+++ b/simpleperf/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for simpleperf_unit_test and simpleperf_cpu_hotplug_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="simpleperf_unit_test->/data/local/tmp/simpleperf_unit_test" />
+ <option name="push" value="simpleperf_cpu_hotplug_test->/data/local/tmp/simpleperf_cpu_hotplug_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="simpleperf_unit_test" />
+ </test>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="simpleperf_cpu_hotplug_test" />
+ </test>
+</configuration>
diff --git a/simpleperf/README.md b/simpleperf/README.md
index 5412f90..a5da220 100644
--- a/simpleperf/README.md
+++ b/simpleperf/README.md
@@ -1,17 +1,112 @@
-# Simpleperf Introduction
-## What is simpleperf
-Simpleperf is a native profiling tool for Android. Its command-line interface
-supports broadly the same options as the linux-tools perf, but also supports
-various Android-specific improvements.
+# Simpleperf
-Simpleperf is part of the Android Open Source Project. The source code is at
-https://android.googlesource.com/platform/system/extras/+/master/simpleperf/.
-The latest document is at
-https://android.googlesource.com/platform/system/extras/+show/master/simpleperf/README.md.
-Bugs and feature requests can be submitted at
-http://github.com/android-ndk/ndk/issues.
+Simpleperf is a native profiling tool for Android. It can be used to profile
+both Android applications and native processes running on Android. It can
+profile both Java and C++ code on Android. It can be used on Android L
+and above.
-## How simpleperf works
+Simpleperf is part of the Android Open Source Project. The source code is [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/).
+The latest document is [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/README.md).
+Bugs and feature requests can be submitted at http://github.com/android-ndk/ndk/issues.
+
+
+## Table of Contents
+
+- [Simpleperf introduction](#simpleperf-introduction)
+ - [Why simpleperf](#why-simpleperf)
+ - [Tools in simpleperf](#tools-in-simpleperf)
+ - [Simpleperf's profiling principle](#simpleperfs-profiling-principle)
+ - [Main simpleperf commands](#main-simpleperf-commands)
+ - [Simpleperf list](#simpleperf-list)
+ - [Simpleperf stat](#simpleperf-stat)
+ - [Simpleperf record](#simpleperf-record)
+ - [Simpleperf report](#simpleperf-report)
+- [Android application profiling](#android-application-profiling)
+ - [Prepare an Android application](#prepare-an-android-application)
+ - [Record and report profiling data (using command-lines)](#record-and-report-profiling-data-using-commandlines)
+ - [Record and report profiling data (using python scripts)](#record-and-report-profiling-data-using-python-scripts)
+ - [Record and report call graph](#record-and-report-call-graph)
+ - [Visualize profiling data](#visualize-profiling-data)
+ - [Annotate source code](#annotate-source-code)
+
+
+## Simpleperf introduction
+
+### Why simpleperf
+
+Simpleperf works similar to linux-tools-perf, but it has some specific features for
+Android profiling:
+
+1. Aware of Android environment
+
+ a. It can profile embedded shared libraries in apk.
+
+ b. It reads symbols and debug information from .gnu_debugdata section.
+
+ c. It gives suggestions when errors occur.
+
+ d. When recording with -g option, unwind the stack before writting to file to
+ save storage space.
+
+ e. It supports adding additional information (like symbols) in perf.data, to
+ support recording on device and reporting on host.
+
+2. Using python scripts for profiling tasks
+
+3. Easy to release
+
+ a. Simpleperf executables on device are built as static binaries. They can be
+ pushed on any Android device and run.
+
+ b. Simpleperf executables on host are built as static binaries, and support
+ different hosts: mac, linux and windows.
+
+
+### Tools in simpleperf
+
+Simpleperf is periodically released with Android ndk, located at `simpleperf/`.
+The latest release can be found [here](https://android.googlesource.com/platform/prebuilts/simpleperf/).
+Simpleperf tools contain executables, shared libraries and python scripts.
+
+**Simpleperf executables running on Android device**
+Simpleperf executables running on Android device are located at `bin/android/`.
+Each architecture has one executable, like `bin/android/arm64/simpleperf`. It
+can record and report profiling data. It provides a command-line interface
+broadly the same as the linux-tools perf, and also supports some additional
+features for Android-specific profiling.
+
+**Simpleperf executables running on hosts**
+Simpleperf executables running on hosts are located at `bin/darwin`, `bin/linux`
+and `bin/windows`. Each host and architecture has one executable, like
+`bin/linux/x86_64/simpleperf`. It provides a command-line interface for
+reporting profiling data on hosts.
+
+**Simpleperf report shared libraries used on host**
+Simpleperf report shared libraries used on host are located at `bin/darwin`,
+`bin/linux` and `bin/windows`. Each host and architecture has one library, like
+`bin/linux/x86_64/libsimpleperf_report.so`. It is a library for parsing
+profiling data.
+
+**Python scripts**
+Python scripts are written to help different profiling tasks.
+
+`annotate.py` is used to annotate source files based on profiling data.
+
+`app_profiler.py` is used to profile Android applications.
+
+`binary_cache_builder.py` is used to pull libraries from Android devices.
+
+`pprof_proto_generator.py` is used to convert profiling data to format used by pprof.
+
+`report.py` is used to provide a GUI interface to report profiling result.
+
+`report_sample.py` is used to generate flamegraph.
+
+`simpleperf_report_lib.py` provides a python interface for parsing profiling data.
+
+
+### Simpleperf's profiling principle
+
Modern CPUs have a hardware component called the performance monitoring unit
(PMU). The PMU has several hardware counters, counting events like how many cpu
cycles have happened, how many instructions have executed, or how many cache
@@ -45,24 +140,28 @@
The report command reads a "perf.data" file and any shared libraries used by
the profiled processes, and outputs a report showing where the time was spent.
-## Main simpleperf commands
-Simpleperf supports several subcommands, including list, stat, record, report.
+
+### Main simpleperf commands
+
+Simpleperf supports several subcommands, including list, stat, record and report.
Each subcommand supports different options. This section only covers the most
important subcommands and options. To see all subcommands and options,
use --help.
# List all subcommands.
- $simpleperf --help
+ $ simpleperf --help
# Print help message for record subcommand.
- $simpleperf record --help
+ $ simpleperf record --help
-### simpleperf list
+
+#### Simpleperf list
+
simpleperf list is used to list all events available on the device. Different
devices may support different events because of differences in hardware and
kernel.
- $simpleperf list
+ $ simpleperf list
List of hw-cache events:
branch-loads
...
@@ -75,7 +174,9 @@
task-clock
...
-### simpleperf stat
+
+#### Simpleperf stat
+
simpleperf stat is used to get a raw event counter information of the profiled program
or system-wide. By passing options, we can select which events to use, which
processes/threads to monitor, how long to monitor and the print interval.
@@ -83,7 +184,7 @@
# Stat using default events (cpu-cycles,instructions,...), and monitor
# process 7394 for 10 seconds.
- $simpleperf stat -p 7394 --duration 10
+ $ simpleperf stat -p 7394 --duration 10
Performance counter statistics:
1,320,496,145 cpu-cycles # 0.131736 GHz (100%)
@@ -95,14 +196,14 @@
Total test time: 10.023829 seconds.
-#### Select events
+**Select events**
We can select which events to use via -e option. Below are examples:
# Stat event cpu-cycles.
- $simpleperf stat -e cpu-cycles -p 11904 --duration 10
+ $ simpleperf stat -e cpu-cycles -p 11904 --duration 10
# Stat event cache-references and cache-misses.
- $simpleperf stat -e cache-references,cache-misses -p 11904 --duration 10
+ $ simpleperf stat -e cache-references,cache-misses -p 11904 --duration 10
When running the stat command, if the number of hardware events is larger than
the number of hardware counters available in the PMU, the kernel shares hardware
@@ -111,7 +212,7 @@
showing the percentage of the total time that each event was actually monitored.
# Stat using event cache-references, cache-references:u,....
- $simpleperf stat -p 7394 -e cache-references,cache-references:u,cache-references:k,cache-misses,cache-misses:u,cache-misses:k,instructions --duration 1
+ $ simpleperf stat -p 7394 -e cache-references,cache-references:u,cache-references:k,cache-misses,cache-misses:u,cache-misses:k,instructions --duration 1
Performance counter statistics:
4,331,018 cache-references # 4.861 M/sec (87%)
@@ -130,7 +231,7 @@
--group option. Below is an example.
# Stat using event cache-references, cache-references:u,....
- $simpleperf stat -p 7394 --group cache-references,cache-misses --group cache-references:u,cache-misses:u --group cache-references:k,cache-misses:k -e instructions --duration 1
+ $ simpleperf stat -p 7394 --group cache-references,cache-misses --group cache-references:u,cache-misses:u --group cache-references:k,cache-misses:k -e instructions --duration 1
Performance counter statistics:
3,638,900 cache-references # 4.786 M/sec (74%)
@@ -143,59 +244,61 @@
Total test time: 1.029843 seconds.
-#### Select target to monitor
+**Select target to monitor**
We can select which processes or threads to monitor via -p option or -t option.
Monitoring a process is the same as monitoring all threads in the process.
Simpleperf can also fork a child process to run the new command and then monitor
the child process. Below are examples.
# Stat process 11904 and 11905.
- $simpleperf stat -p 11904,11905 --duration 10
+ $ simpleperf stat -p 11904,11905 --duration 10
# Stat thread 11904 and 11905.
- $simpleperf stat -t 11904,11905 --duration 10
+ $ simpleperf stat -t 11904,11905 --duration 10
# Start a child process running `ls`, and stat it.
- $simpleperf stat ls
+ $ simpleperf stat ls
-#### Decide how long to monitor
+**Decide how long to monitor**
When monitoring existing threads, we can use --duration option to decide how long
to monitor. When monitoring a child process running a new command, simpleperf
monitors until the child process ends. In this case, we can use Ctrl-C to stop monitoring
at any time. Below are examples.
# Stat process 11904 for 10 seconds.
- $simpleperf stat -p 11904 --duration 10
+ $ simpleperf stat -p 11904 --duration 10
# Stat until the child process running `ls` finishes.
- $simpleperf stat ls
+ $ simpleperf stat ls
# Stop monitoring using Ctrl-C.
- $simpleperf stat -p 11904 --duration 10
+ $ simpleperf stat -p 11904 --duration 10
^C
-#### Decide the print interval
+**Decide the print interval**
When monitoring perf counters, we can also use --interval option to decide the print
interval. Below are examples.
# Print stat for process 11904 every 300ms.
- $simpleperf stat -p 11904 --duration 10 --interval 300
+ $ simpleperf stat -p 11904 --duration 10 --interval 300
# Print system wide stat at interval of 300ms for 10 seconds (rooted device only).
# system wide profiling needs root privilege
- $su 0 simpleperf stat -a --duration 10 --interval 300
+ $ su 0 simpleperf stat -a --duration 10 --interval 300
-#### Display counters in systrace
+**Display counters in systrace**
simpleperf can also work with systrace to dump counters in the collected trace.
Below is an example to do a system wide stat
# capture instructions (kernel only) and cache misses with interval of 300 milliseconds for 15 seconds
- $su 0 simpleperf stat -e instructions:k,cache-misses -a --interval 300 --duration 15
+ $ su 0 simpleperf stat -e instructions:k,cache-misses -a --interval 300 --duration 15
# on host launch systrace to collect trace for 10 seconds
- (HOST)$external/chromium-trace/systrace.py --time=10 -o new.html sched gfx view
+ (HOST)$ external/chromium-trace/systrace.py --time=10 -o new.html sched gfx view
# open the collected new.html in browser and perf counters will be shown up
-### simpleperf record
+
+#### Simpleperf record
+
simpleperf record is used to dump records of the profiled program. By passing
options, we can select which events to use, which processes/threads to monitor,
what frequency to dump records, how long to monitor, and where to store records.
@@ -203,31 +306,31 @@
# Record on process 7394 for 10 seconds, using default event (cpu-cycles),
# using default sample frequency (4000 samples per second), writing records
# to perf.data.
- $simpleperf record -p 7394 --duration 10
+ $ simpleperf record -p 7394 --duration 10
simpleperf I 07-11 21:44:11 17522 17522 cmd_record.cpp:316] Samples recorded: 21430. Samples lost: 0.
-#### Select events
+**Select events**
In most cases, the cpu-cycles event is used to evaluate consumed cpu time.
As a hardware event, it is both accurate and efficient. We can also use other
events via -e option. Below is an example.
# Record using event instructions.
- $simpleperf record -e instructions -p 11904 --duration 10
+ $ simpleperf record -e instructions -p 11904 --duration 10
-#### Select target to monitor
+**Select target to monitor**
The way to select target in record command is similar to that in stat command.
Below are examples.
# Record process 11904 and 11905.
- $simpleperf record -p 11904,11905 --duration 10
+ $ simpleperf record -p 11904,11905 --duration 10
# Record thread 11904 and 11905.
- $simpleperf record -t 11904,11905 --duration 10
+ $ simpleperf record -t 11904,11905 --duration 10
# Record a child process running `ls`.
- $simpleperf record ls
+ $ simpleperf record ls
-#### Set the frequency to record
+**Set the frequency to record**
We can set the frequency to dump records via the -f or -c options. For example,
-f 4000 means dumping approximately 4000 records every second when the monitored
thread runs. If a monitored thread runs 0.2s in one second (it can be preempted
@@ -236,33 +339,35 @@
means dumping one record whenever 10000 events happen. Below are examples.
# Record with sample frequency 1000: sample 1000 times every second running.
- $simpleperf record -f 1000 -p 11904,11905 --duration 10
+ $ simpleperf record -f 1000 -p 11904,11905 --duration 10
# Record with sample period 100000: sample 1 time every 100000 events.
- $simpleperf record -c 100000 -t 11904,11905 --duration 10
+ $ simpleperf record -c 100000 -t 11904,11905 --duration 10
-#### Decide how long to monitor
+**Decide how long to monitor**
The way to decide how long to monitor in record command is similar to that in
stat command. Below are examples.
# Record process 11904 for 10 seconds.
- $simpleperf record -p 11904 --duration 10
+ $ simpleperf record -p 11904 --duration 10
# Record until the child process running `ls` finishes.
- $simpleperf record ls
+ $ simpleperf record ls
# Stop monitoring using Ctrl-C.
- $simpleperf record -p 11904 --duration 10
+ $ simpleperf record -p 11904 --duration 10
^C
-#### Set the path to store records
+**Set the path to store records**
By default, simpleperf stores records in perf.data in current directory. We can
use -o option to set the path to store records. Below is an example.
# Write records to data/perf2.data.
- $simpleperf record -p 11904 -o data/perf2.data --duration 10
+ $ simpleperf record -p 11904 -o data/perf2.data --duration 10
-### simpleperf report
+
+#### Simpleperf report
+
simpleperf report is used to report based on perf.data generated by simpleperf
record command. Report command groups records into different sample entries,
sorts sample entries based on how many events each sample entry contains, and
@@ -280,7 +385,7 @@
# Reports perf.data, using only records sampled in libsudo-game-jni.so,
# grouping records using thread name(comm), process id(pid), thread id(tid),
# function name(symbol), and showing sample count for each row.
- $simpleperf report --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort comm,pid,tid,symbol -n
+ $ simpleperf report --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort comm,pid,tid,symbol -n
Cmdline: /data/data/com.example.sudogame/simpleperf record -p 7394 --duration 10
Arch: arm64
Event: cpu-cycles (type 0, config 0)
@@ -293,13 +398,13 @@
13.82% 4088 sudogame 7394 7394 randomBlock_r(Board&, int, int, int, int, int)
6.24% 1756 sudogame 7394 7394 @plt
-#### Set the path to read records
+**Set the path to read records**
By default, simpleperf reads perf.data in current directory. We can use -i
option to select another file to read records.
- $simpleperf report -i data/perf2.data
+ $ simpleperf report -i data/perf2.data
-#### Set the path to find executable binaries
+**Set the path to find executable binaries**
If reporting function symbols, simpleperf needs to read executable binaries
used by the monitored processes to get symbol table and debug information. By
default, the paths are the executable binaries used by monitored processes while
@@ -307,236 +412,264 @@
symbol table and debug information. So we can use --symfs to redirect the paths.
Below is an example.
- $simpleperf report
+ $ simpleperf report
# In this case, when simpleperf wants to read executable binary /A/b,
# it reads file in /A/b.
- $simpleperf report --symfs /debug_dir
+ $ simpleperf report --symfs /debug_dir
# In this case, when simpleperf wants to read executable binary /A/b,
# it prefers file in /debug_dir/A/b to file in /A/b.
-#### Filter records
+**Filter records**
When reporting, it happens that not all records are of interest. Simpleperf
supports five filters to select records of interest. Below are examples.
# Report records in threads having name sudogame.
- $simpleperf report --comms sudogame
+ $ simpleperf report --comms sudogame
# Report records in process 7394 or 7395
- $simpleperf report --pids 7394,7395
+ $ simpleperf report --pids 7394,7395
# Report records in thread 7394 or 7395.
- $simpleperf report --tids 7394,7395
+ $ simpleperf report --tids 7394,7395
# Report records in libsudo-game-jni.so.
- $simpleperf report --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so
+ $ simpleperf report --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so
# Report records in function checkValid or canFindSolution_r.
- $simpleperf report --symbols "checkValid(Board const&, int, int);canFindSolution_r(Board&, int, int)"
+ $ simpleperf report --symbols "checkValid(Board const&, int, int);canFindSolution_r(Board&, int, int)"
-#### Decide how to group records into sample entries
+**Decide how to group records into sample entries**
Simpleperf uses --sort option to decide how to group sample entries. Below are
examples.
# Group records based on their process id: records having the same process
# id are in the same sample entry.
- $simpleperf report --sort pid
+ $ simpleperf report --sort pid
# Group records based on their thread id and thread comm: records having
# the same thread id and thread name are in the same sample entry.
- $simpleperf report --sort tid,comm
+ $ simpleperf report --sort tid,comm
# Group records based on their binary and function: records in the same
# binary and function are in the same sample entry.
- $simpleperf report --sort dso,symbol
+ $ simpleperf report --sort dso,symbol
# Default option: --sort comm,pid,tid,dso,symbol. Group records in the same
# thread, and belong to the same function in the same binary.
- $simpleperf report
+ $ simpleperf report
-## Features of simpleperf
-Simpleperf works similar to linux-tools-perf, but it has following improvements:
-1. Aware of Android environment. Simpleperf handles some Android specific
-situations when profiling. For example, it can profile embedded shared libraries
-in apk, read symbol table and debug information from .gnu_debugdata section. If
-possible, it gives suggestions when facing errors, like how to disable
-perf_harden to enable profiling.
-2. Support unwinding while recording. If we want to use -g option to record and
-report call-graph of a program, we need to dump user stack and register set in
-each record, and then unwind the stack to find the call chain. Simpleperf
-supports unwinding while recording, so it doesn’t need to store user stack in
-perf.data. So we can profile for a longer time with limited space on device.'
-3. Support scripts to make profiling on Android more convenient.
-4. Build in static binaries. Simpleperf is a static binary, so it doesn’t need
-supporting shared libraries to run. It means there is no limitation of Android
-version that simpleperf can run on, although some devices don’t support
-profiling.
-# Simpleperf tools in ndk
-Simpleperf tools in ndk contain three parts: simpleperf executable running on
-Android device, simpleperf executable running on host, and python scripts.
+## Android application profiling
-## Simpleperf on device
-Simpleperf running on device is located at bin/android directory. It contains
-static binaries running on Android on different architectures. They can be used
-to profile processes running device, and generate perf.data.
+This section shows how to profile an Android application.
+[Here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/demo/README.md) are examples. And we use
+[SimpleperfExamplePureJava](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/demo/SimpleperfExamplePureJava) project to show the profiling results.
-## Simpleperf on host
-Simpleperfs running on host are located at bin/darwin, bin/linux and
-bin/windows.They can be used to parse perf.data on host.
+Simpleperf only supports profiling native instructions in binaries in ELF
+format. If the Java code is executed by interpreter, or with jit cache, it
+can’t be profiled by simpleperf. As Android supports Ahead-of-time compilation,
+it can compile Java bytecode into native instructions with debug information.
+On devices with Android version <= M, we need root privilege to compile Java
+bytecode with debug information. However, on devices with Android version >= N,
+we don't need root privilege to do so.
-## Scripts
-Scripts are used to make it convenient to profile and parse profiling results.
-app_profiler.py is used to profile an android application. It prepares
-profiling environments, downloads simpleperf on device, generates and pulls
-perf.data on host. It is configured by app_profiler.config.
-binary_cache_builder.py is used to pull native binaries from device to host.
-It is used by app_profiler.py.
-annotate.py is used to annotate source files using perf.data. It is configured
-by annotate.config.
-report.py reports perf.data in a GUI window.
-simpleperf_report_lib.py is used to enumerate samples in perf.data. Internally
-it uses libsimpleperf_report.so to parse perf.data. It can be used to translate
-samples in perf.data to other forms. One example using simpleperf_report_lib.py
-is report_sample.py.
+Profiling an Android application involves three steps:
+1. Prepare the application.
+2. Record profiling data.
+3. Report profiling data.
-# Examples of using simpleperf tools
-This section shows how to use simpleperf tools to profile an Android
-application.
+To profile, we can use either command lines or python scripts. Below shows both.
-## Prepare a debuggable Application
-The package name of the application is com.example.sudogame. It has both java
-code and c++ code. We need to run a copy of the app with
-android:debuggable=”true” in its AndroidManifest.xml <application> element,
-because we can’t use run-as for non-debuggable apps. The application should
-has been installed on device, and we can connect device via adb.
-## Profile using command line
-To record profiling data, we need to download simpleperf and native libraries
-with debug information on device, run simpleperf to generate profiling data
-file: perf.data, and run simpleperf to report perf.data. Below are the steps.
+### Prepare an Android application
-### 1. Enable profiling
+Before profiling, we need to install the application to be profiled on an Android device.
+To get valid profiling results, please check following points:
- $adb shell setprop security.perf_harden 0
+**1. The application should be debuggable.**
+It means [android:debuggable](https://developer.android.com/guide/topics/manifest/application-element.html#debug)
+should be true. So we need to use debug [build type](https://developer.android.com/studio/build/build-variants.html#build-types)
+instead of release build type. It is understandable because we can't profile others' apps.
+However, on a rooted Android device, the application doesn't need to be debuggable.
-### 2. Find the process running the app
-Run `ps` in the app’s context. On >=O devices, run `ps -e` instead.
+**2. Run on an Android device >= L.**
+Profiling on emulators are not yet supported. And to profile Java code, we need
+the jvm running in oat mode, which is only available >= L.
- $adb shell
- angler:/ $ run-as com.example.sudogame
- angler:/data/data/com.example.sudogame $ ps
- u0_a93 10324 570 1030480 58104 SyS_epoll_ 00f41b7528 S com.example.sudogame
- u0_a93 10447 10441 7716 1588 sigsuspend 753c515d34 S sh
- u0_a93 10453 10447 9112 1644 0 7ba07ff664 R ps
+**3. On Android O, add `wrap.sh` in the apk.**
+To profile Java code, we need the jvm running in oat mode. But on Android O,
+debuggable applications are forced to run in jit mode. To work around this,
+we need to add a `wrap.sh` in the apk. So if you are running on Android O device,
+Check [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/demo/SimpleperfExamplePureJava/app/profiling.gradle)
+for how to add `wrap.sh` in the apk.
-So process 10324 runs the app.
+**4. Make sure C++ code is compiled with optimizing flags.**
+If the application contains C++ code, it can be compiled with -O0 flag in debug build type.
+This makes C++ code slow. Check [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/demo/SimpleperfExamplePureJava/app/profiling.gradle)
+for how to avoid that.
-### 3. Download simpleperf to the app’s data directory
-First we need to find out which architecture the app is using. There are many
-ways, here we just check the map of the process.
+**5. Use native libraries with debug info in the apk when possible.**
+If the application contains C++ code or pre-compiled native libraries, try to use
+unstripped libraries in the apk. This helps simpleperf generating better profiling
+results. Check [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/demo/SimpleperfExamplePureJava/app/profiling.gradle)
+for how to use unstripped libraries.
- angler:/data/data/com.example.sudogame $cat /proc/10324/maps | grep boot.art
- 70f34000-7144e000 r--p 00000000 fd:00 1082 /system/framework/arm/boot.oat
+Here we use [SimpleperfExamplePureJava](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/demo/SimpleperfExamplePureJava) as an example.
+It builds an app-profiling.apk for profiling.
-The file path shows it is arm. So we download simpleperf in arm directory on
-device.
+ $ git clone https://android.googlesource.com/platform/system/extras
+ $ cd extras/simpleperf/demo
+ # Open SimpleperfExamplesPureJava project with Android studio,
+ # and build this project sucessfully, otherwise the `./gradlew` command below will fail.
+ $ cd SimpleperfExamplePureJava
- $adb push bin/android/arm/simpleperf /data/local/tmp
- $adb shell
- angler:/ $ run-as com.example.sudogame
- angler:/data/data/com.example.sudogame $ cp /data/local/tmp/simpleperf .
+ # On windows, use "gradlew" instead.
+ $ ./gradlew clean assemble
+ $ adb install -r app/build/outputs/apk/app-profiling.apk
-### 4. Record perf.data
- angler:/data/data/com.example.sudogame $./simpleperf record -p 10324 --duration 30
- simpleperf I 01-01 09:26:39 10598 10598 cmd_record.cpp:341] Samples recorded: 49471. Samples lost: 0.
- angler:/data/data/com.example.sudogame $ls -lh perf.data
- -rw-rw-rw- 1 u0_a93 u0_a93 2.6M 2017-01-01 09:26 perf.data
+### Record and report profiling data (using command-lines)
-Don’t forget to run the app while recording. Otherwise, we may get no samples
-because the process is always sleeping.
+We recommend using python scripts for profiling because they are more convenient.
+But using command-line will give us a better understanding of the profile process
+step by step. So we first show how to use command lines.
-### 5. Report perf.data
-There are different ways to report perf.data. Below shows some examples.
+**1. Enable profiling**
-Report samples in different threads.
+ $ adb shell setprop security.perf_harden 0
- angler:/data/data/com.example.sudogame $./simpleperf report --sort pid,tid,comm
- Cmdline: /data/data/com.example.sudogame/simpleperf record -p 10324 --duration 30
- Arch: arm64
- Event: cpu-cycles (type 0, config 0)
- Samples: 49471
- Event count: 16700769019
+**2. Fully compile the app**
- Overhead Pid Tid Command
- 66.31% 10324 10324 xample.sudogame
- 30.97% 10324 10340 RenderThread
+We need to compile Java bytecode into native instructions to profile Java code
+in the application. This needs different commands on different Android versions.
+
+On Android >= N:
+
+ $ adb shell setprop debug.generate-debug-info true
+ $ adb shell cmd package compile -f -m speed com.example.simpleperf.simpleperfexamplepurejava
+ # Restart the app to take effect
+ $ adb shell am force-stop com.example.simpleperf.simpleperfexamplepurejava
+
+On Android M devices, We need root privilege to force Android to fully compile
+Java code into native instructions in ELF binaries with debug information. We
+also need root privilege to read compiled native binaries (because installd
+writes them to a directory whose uid/gid is system:install). So profiling Java
+code can only be done on rooted devices.
+
+ $ adb root
+ $ adb shell setprop dalvik.vm.dex2oat-flags -g
+
+ # Reinstall the app.
+ $ adb install -r app/build/outputs/apk/app-profiling.apk
+
+On Android L devices, we also need root privilege to compile the app with debug info
+and access the native binaries.
+
+ $ adb root
+ $ adb shell setprop dalvik.vm.dex2oat-flags --include-debug-symbols
+
+ # Reinstall the app.
+ $ adb install -r app/build/outputs/apk/app-profiling.apk
+
+
+**3. Find the app process**
+
+ # Start the app if needed
+ $ adb shell am start -n com.example.simpleperf.simpleperfexamplepurejava/.MainActivity
+
+ # Run `ps` in the app's context. On Android >= O devicces, run `ps -e` instead.
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava ps | grep simpleperf
+ u0_a151 6885 3346 1590504 53980 SyS_epoll_ 6fc2024b6c S com.example.simpleperf.simpleperfexamplepurejava
+
+So the id of the app process is `6885`. We will use this number in the command lines below,
+please replace this number with what you get by running `ps` command.
+
+**4. Download simpleperf to the app's data directory**
+
+ # Find which architecture the app is using.
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava cat /proc/6885/maps | grep boot.oat
+ 708e6000-70e33000 r--p 00000000 103:09 1214 /system/framework/arm64/boot.oat
+
+ # The app uses /arm64/boot.oat, so push simpleperf in bin/android/arm64/ to device.
+ $ cd ../../scripts/
+ $ adb push bin/android/arm64/simpleperf /data/local/tmp
+ $ adb shell chmod a+x /data/local/tmp/simpleperf
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava cp /data/local/tmp/simpleperf .
+
+
+**5. Record perf.data**
+
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava ./simpleperf record -p 6885 --duration 10
+ simpleperf I 04-27 20:41:11 6940 6940 cmd_record.cpp:357] Samples recorded: 40008. Samples lost: 0.
+
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava ls -lh perf.data
+ simpleperf I 04-27 20:31:40 5999 5999 cmd_record.cpp:357] Samples recorded: 39949. Samples lost: 0.
+
+The profiling data is recorded at perf.data.
+
+Normally we need to use the app when profiling, otherwise we may record no samples.
+But in this case, the MainActivity starts a busy thread. So we don't need to use
+the app while profiling.
+
+There are many options to record profiling data, check [record command](#simpleperf-record) for details.
+
+**6. Report perf.data**
+
+ # Pull perf.data on host.
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava cat perf.data >perf.data
+
+ # Report samples using corresponding simpleperf executable on host.
+ # On windows, use "bin\windows\x86_64\simpleperf" instead.
+ $ bin/linux/x86_64/simpleperf report
...
+ Overhead Command Pid Tid Shared Object Symbol
+ 83.54% Thread-2 6885 6900 /data/app/com.example.simpleperf.simpleperfexamplepurejava-2/oat/arm64/base.odex void com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()
+ 16.11% Thread-2 6885 6900 /data/app/com.example.simpleperf.simpleperfexamplepurejava-2/oat/arm64/base.odex int com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.callFunction(int)
-Report samples in different binaries in the main thread.
+There are many ways to show reports, check [report command](#simpleperf-report) for details.
- angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --sort dso -n
- ...
- Overhead Sample Shared Object
- 37.71% 9970 /system/lib/libc.so
- 35.45% 9786 [kernel.kallsyms]
- 8.71% 3305 /system/lib/libart.so
- 6.44% 2405 /system/framework/arm/boot-framework.oat
- 5.64% 1480 /system/lib/libcutils.so
- 1.55% 426 /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so
- ...
-Report samples in different functions in libsudo-game-jni.so in the main thread.
+### Record and report profiling data (using python scripts)
- angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --dsos /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so --sort symbol -n
- ...
- Overhead Sample Symbol
- 8.94% 35 libsudo-game-jni.so[+1d54]
- 5.71% 25 libsudo-game-jni.so[+1dae]
- 5.70% 23 @plt
- 5.09% 22 libsudo-game-jni.so[+1d88]
- 4.54% 19 libsudo-game-jni.so[+1d82]
- 3.61% 14 libsudo-game-jni.so[+1f3c]
- ...
+Besides command lines, We can use `app-profiler.py` to profile Android applications.
+It downloads simpleperf on device, records perf.data, and collects profiling
+results and native binaries on host. It is configured by `app-profiler.config`.
-In the above result, most symbols are binary name[+virual_addr]. It is because
-libsudo-game-jni.so used on device has stripped .symbol section. We can
-download libsudo-game-jni.so having debug information on device. In android
-studio project, it locates at
-app/build/intermediates/binaries/debug/arm/obj/armeabi-v7a/libsudo-game-jni.so.
-We have to download libsudo-game-jni.so to the same relative path as recorded
-in perf.data (otherwise, simpleperf can’t find it). In this case, it is
-/data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so.
+**1. Fill `app-profiler.config`**
-Report symbols using libraries with debug information.
+ Change `app_package_name` line to app_package_name="com.example.simpleperf.simpleperfexamplepurejava"
+ Change `apk_file_path` line to apk_file_path = "../SimpleperfExamplePureJava/app/build/outputs/apk/app-profiling.apk"
+ Change `android_studio_project_dir` line to android_studio_project_dir = "../SimpleperfExamplePureJava/"
+ Change `record_options` line to record_options = "--duration 10"
- $adb push app/build/intermediates/binaries/debug/arm/obj/armeabi-v7a/libsudo-game-jni.so /data/local/tmp
- $adb shell
- angler:/ $ run-as com.example.sudogame
- angler:/data/data/com.example.sudogame $ mkdir -p data/app/com.example.sudogame-1/lib/arm
- angler:/data/data/com.example.sudogame $cp /data/local/tmp/libsudo-game-jni.so data/app/com.example.sudogame-1/lib/arm
- angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --dsos /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so --sort symbol -n --symfs .
- ...
- Overhead Sample Symbol
- 75.18% 317 checkValid(Board const&, int, int)
- 14.43% 60 canFindSolution_r(Board&, int, int)
- 5.70% 23 @plt
- 3.51% 20 randomBlock_r(Board&, int, int, int, int, int)
- ...
+`apk_file_path` is needed to fully compile the application on Android L/M. It is
+not necessary on Android >= N.
-Report samples in one function
+`android_studio_project_dir` is used to search native libraries in the
+application. It is not necessary for profiling.
- angler:/data/data/com.example.sudogame $./simpleperf report --tids 10324 --dsos /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so --symbols “checkValid(Board const&, int, int)” --sort vaddr_in_file -n --symfs .
- ...
- Overhead Sample VaddrInFile
- 11.89% 35 0x1d54
- 7.59% 25 0x1dae
- 6.77% 22 0x1d88
- 6.03% 19 0x1d82
- ...
+`record_options` can be set to any option accepted by simpleperf record command.
-### 6. Record and report call graph
+**2. Run `app-profiler.py`**
+
+ $ python app_profiler.py
+
+
+If running successfully, it will collect profiling data in perf.data in current
+directory, and related native binaries in binary_cache/.
+
+**3. Report perf.data**
+
+We can use `report.py` to report perf.data.
+
+ $ python report.py
+
+We can add any option accepted by `simpleperf report` command to `report.py`.
+
+
+### Record and report call graph
+
A call graph is a tree showing function call relations. Below is an example.
main() {
@@ -555,271 +688,123 @@
|
|-> FunctionTwo
+
#### Record dwarf based call graph
-To generate call graph, simpleperf needs to generate call chain for each record.
-Simpleperf requests kernel to dump user stack and user register set for each
-record, then it backtraces the user stack to find the function call chain. To
-parse the call chain, it needs support of dwarf call frame information, which
-usually resides in .eh_frame or .debug_frame section of the binary. So we need
-to use --symfs to point out where is libsudo-game-jni.so with debug information.
- angler:/data/data/com.example.sudogame $./simpleperf record -p 10324 -g --symfs . --duration 30
- simpleperf I 01-01 09:59:42 11021 11021 cmd_record.cpp:341] Samples recorded: 60700. Samples lost: 1240.
+When using command lines, add `-g` option like below:
-Note that kernel can’t dump user stack >= 64K, so the dwarf based call graph
-doesn’t contain call chains consuming >= 64K stack. What’s more, because we
-need to dump stack in each record, it is likely to lost records. Usually, it
-doesn’t matter to lost some records.
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava ./simpleperf record -g -p 6685 --duration 10
+
+When using python scripts, change `app-profiler.config` as below:
+
+ Change `record_options` line to record_options = "--duration 10 -g"
+
+Recording dwarf based call graph needs support of debug information
+in native binaries. So if using native libraries in the application,
+it is better to contain non-stripped native libraries in the apk.
+
#### Record stack frame based call graph
-Another way to generate call graph is to rely on the kernel parsing the call
-chain for each record. To make it possible, kernel has to be able to identify
-the stack frame of each function call. This is not always possible, because
-compilers can optimize away stack frames, or use a stack frame style not
-recognized by the kernel. So how well it works depends (It works well on arm64,
-but not well on arm).
- angler:/data/data/com.example.sudogame $./simpleperf record -p 10324 --call-graph fp --symfs . --duration 30
- simpleperf I 01-01 10:03:58 11267 11267 cmd_record.cpp:341] Samples recorded: 56736. Samples lost: 0.
+When using command lines, add `--call-graph fp` option like below:
+
+ $ adb shell run-as com.example.simpleperf.simpleperfexamplepurejava ./simpleperf record --call-graph fp -p 6685 --duration 10
+
+When using python scripts, change `app-profiler.config` as below:
+
+ Change `record_options` line to record_options = "--duration 10 --call-graph fp"
+
+Recording stack frame based call graphs needs support of stack frame
+register. Notice that on arm architecture, the stack frame register
+is not well supported, even if compiled using -O0 -g -fno-omit-frame-pointer
+options. It is because the kernel can't unwind user stack containing both
+arm/thumb code. **So please consider using dwarf based call graph on arm
+architecture, or profiling in arm64 environment.**
+
#### Report call graph
-Report accumulated period. In the table below, the first column is “Children”,
-it is the cpu cycle percentage of a function and functions called by that
-function. The second column is “Self”, it is the cpu cycle percentage of just a
-function. For example, checkValid() itself takes 1.28% cpus, but it takes
-29.43% by running itself and calling other functions.
- angler:/data/data/com.example.sudogame $./simpleperf report --children --symfs .
+To report call graph using command lines, add `-g` option.
+
+ $ bin/linux/x86_64/simpleperf report -g
...
- Children Self Command Pid Tid Shared Object Symbol
- 31.94% 0.00% xample.sudogame 10324 10324 [kernel.kallsyms] [kernel.kallsyms][+ffffffc000204268]
- 31.10% 0.92% xample.sudogame 10324 10324 /system/lib/libc.so writev
- 29.43% 1.28% xample.sudogame 10324 10324 /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so checkValid(Board const&, int, int)
- 28.43% 0.34% xample.sudogame 10324 10324 /system/lib/liblog.so __android_log_print
- 28.24% 0.00% xample.sudogame 10324 10324 /system/lib/libcutils.so libcutils.so[+107b7]
- 28.10% 0.27% xample.sudogame 10324 10324 /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so canFindSolution_r(Board&, int, int)
- ...
+ Children Self Command Pid Tid Shared Object Symbol
+ 99.97% 0.00% Thread-2 10859 10876 /system/framework/arm64/boot.oat java.lang.Thread.run
+ |
+ -- java.lang.Thread.run
+ |
+ -- void com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()
+ |--83.66%-- [hit in function]
+ |
+ |--16.22%-- int com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.callFunction(int)
+ | |--99.97%-- [hit in function]
-Report call graph.
+To report call graph using python scripts, add `-g` option.
- angler:/data/data/com.example.sudogame $./simpleperf report -g --symfs . >report
- angler:/data/data/com.example.sudogame $exit
- angler:/ $cp /data/data/com.example.sudogame/report /data/local/tmp
- angler:/ $exit
- $adb pull /data/local/tmp/report .
- $cat report
- ...
- 29.43% 1.28% xample.sudogame 10324 10324 /data/app/com.example.sudogame-1/lib/arm/libsudo-game-jni.so checkValid(Board const&, int, int)
- |
- -- checkValid(Board const&, int, int)
- |
- |--95.50%-- __android_log_print
- | |--0.68%-- [hit in function]
- | |
- | |--51.84%-- __android_log_buf_write
- | | |--2.07%-- [hit in function]
- | | |
- | | |--30.74%-- libcutils.so[+c69d]
- ...
+ $ python report.py -g
+ # Double-click an item started with '+' to show its callgraph.
-Report call graph in callee mode. We can also show how a function is called by
-other functions.
+### Visualize profiling data
- angler:/data/data/com.example.sudogame $./simpleperf report -g callee --symfs . >report
- $adb shell run-as com.example.sudogame cat report >report
- $cat report
- …
- 28.43% 0.34% xample.sudogame 10324 10324 /system/lib/liblog.so __android_log_print
- |
- -- __android_log_print
- |
- |--97.82%-- checkValid(Board const&, int, int)
- | |--0.13%-- [hit in function]
- | |
- | |--94.89%-- canFindSolution_r(Board&, int, int)
- | | |--0.01%-- [hit in function]
- | | |
- ...
+`simpleperf_report_lib.py` provides an interface reading samples from perf.data.
+By using it, You can write python scripts to read perf.data or convert perf.data
+to other formats. Below are two examples.
-## Profile java code
-Simpleperf only supports profiling native instructions in binaries in ELF
-format. If the java code is executed by interpreter, or with jit cache, it
-can’t be profiled by simpleperf. As Android supports Ahead-of-time compilation,
-it can compile java bytecode into native instructions with debug information.
-On devices with Android version <= M, we need root privilege to compile java
-bytecode with debug information. However, on devices with Android version >= N,
-we don't need root privilege to do so.
-
-### On Android N
-#### 1. Fully compile java code into native instructions.
-
- $adb shell setprop debug.generate-debug-info true
- $adb shell cmd package compile -f -m speed com.example.sudogame
- // restart the app to take effect
-
-#### 2. Record perf.data
-
- angler:/data/data/com.example.sudogame $./simpleperf record -p 11826 -g --symfs . --duration 30
- simpleperf I 01-01 10:31:40 11859 11859 cmd_record.cpp:341] Samples recorded: 50576. Samples lost: 2139.
-
-#### 3. Report perf.data
-
- angler:/data/data/com.example.sudogame $./simpleperf report -g --symfs . >report
- angler:/data/data/com.example.sudogame $exit
- angler:/ $cp /data/data/com.example.sudogame/report /data/local/tmp
- angler:/ $exit
- $adb pull /data/local/tmp/report .
- $cat report
- ...
- 21.14% 0.00% xample.sudogame 11826 11826 /data/app/com.example.sudogame-1/oat/arm/base.odex boolean com.example.sudogame.MainActivity.onOptionsItemSelected(android.view.MenuItem)
- |
- -- boolean com.example.sudogame.MainActivity.onOptionsItemSelected(android.view.MenuItem)
- |
- --99.99%-- void com.example.sudogame.GameView.startNewGame()
- |--0.01%-- [hit in function]
- |
- |--99.87%-- void com.example.sudogame.GameModel.reInit()
- | |--0.01%-- [hit in function]
- | |
- | |--89.65%-- boolean com.example.sudogame.GameModel.canFindSolution(int[][])
- | | |
- | | |--99.95%-- Java_com_example_sudogame_GameModel_canFindSolution
- | | | |
- | | | |--99.49%-- canFindSolution(Board&)
- | | | | |--0.01%-- [hit in function]
- | | | | |
- | | | | |--99.97%-- canFindSolution_r(Board&, int, int)
- | | | | | canFindSolution_r(Board&, int, int)
- ...
-
-### On Android M
-On M devices, We need root privilege to force Android fully compiling java code
-into native instructions in ELF binaries with debug information. We also need
-root privilege to read compiled native binaries (because installd writes them
-to a directory whose uid/gid is system:install). So profiling java code can
-only be done on rooted devices.
-
- $adb root
- $adb shell setprop dalvik.vm.dex2oat-flags -g
-
- # Reinstall the app.
- $adb install -r app-debug.apk
-
- # Change to the app’s data directory.
- $ adb root && adb shell
- device# cd `run-as com.example.sudogame pwd`
-
- # Record as root as simpleperf needs to read the generated native binary.
- device#./simpleperf record -p 25636 -g --symfs . -f 1000 --duration 30
- simpleperf I 01-02 07:18:20 27182 27182 cmd_record.cpp:323] Samples recorded: 23552. Samples lost: 39.
-
-### On Android L
-On L devices, we also need root privilege to compile the app with debug info
-and access the native binaries.
-
- $adb root
- $adb shell setprop dalvik.vm.dex2oat-flags --include-debug-symbols
-
- # Reinstall the app.
- $adb install -r app-debug.apk
-
-## Profile using scripts
-Although using command line is flexible, it can be too complex. So we have
-python scripts to help running commands.
-
-### Record using app_profiler.py
-app_profiler.py is used to profile an Android application. It sets up profiling
-environment, downloads simpleperf and native libraries with debug information,
-runs simpleperf to generate perf.data, and pulls perf.data and binaries from
-device to host.
-It is configured by app_profiler.config. Below is an example.
-
-app_profiler.config:
-
- app_package_name = “com.example.sudogame”
- android_studio_project_dir = “/AndroidStudioProjects/SudoGame” # absolute path of the project
- ...
- record_options = "-e cpu-cycles:u -f 4000 -g --dump-symbols --duration 30"
- ...
-
-run app_profiler.py:
-
- $python app_profiler.py
- ...
- INFO:root:profiling is finished.
-
-It pulls generated perf.data on host, and collects binaries from device in
-binary_cache.
-
-### Report using report.py
-
- $python report.py -g
-
-It generates a GUI interface to report data.
-
-### Process samples using simpleperf_report_lib.py
-simpleperf_report_lib.py provides an interface reading samples from perf.data.
-An example is report_sample.py.
### Show flamegraph
- $python report_sample.py >out.perf
- $stackcollapse-perf.pl out.perf >out.folded
- $./flamegraph.pl out.folded >a.svg
+ $ python report_sample.py >out.perf
+ $ stackcollapse-perf.pl out.perf >out.folded
+ $ ./flamegraph.pl out.folded >a.svg
+
### Visualize using pprof
+
pprof is a tool for visualization and analysis of profiling data. It can
be got from https://github.com/google/pprof. pprof_proto_generator.py can
generate profiling data in a format acceptable by pprof.
- $python pprof_proto_generator.py
- $pprof -pdf pprof.profile
+ $ python pprof_proto_generator.py
+ $ pprof -pdf pprof.profile
+
### Annotate source code
-annotate.py reads perf.data and binaries in binary_cache. Then it knows which
-source file:line each sample hits. So it can annotate source code. annotate.py
-is configured by annotate.config. Below is an example.
-annotate.config:
+`annotate.py` reads perf.data, binaries in `binary-cache` (collected by `app-profiler.py`)
+and source code, and generates annoated source code in `annotated_files/`.
+It is configured by `annotate.config`.
+
+**1. Fill `annotate.config`**
+
+ Change `source_dirs` line to source_dirs = ["../SimpleperfExamplePureJava"]
+ Change `addr2line_path` line to addr2line_path = "addr2line"
+
+`addr2line` is need to annotate source code. It can be found in Android ndk release.
+Please set `addr2line_path` to the location of `addr2line` if it can't be found
+in PATH environment variable.
+
+**2. Run `annotate.py`**
+
+ $ python annotate.py
+
+
+**3. Read annotated code**
+
+The annotated source code is located at `annotated_files/`.
+`annotated_files/summary` shows how each source file is annotated.
+
+One annotated source file is `annotated_files/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java`.
+It's content is similar to below:
+
+ // [file] shows how much time is spent in current file.
+ /* [file] acc_p: 99.966552%, p: 99.837438% */package com.example.simpleperf.simpleperfexamplepurejava;
...
- source_dirs = [“/AndroidStudio/SudoGame”] # It is a directory containing source code.
+ // [func] shows how much time is spent in current function.
+ /* [func] acc_p: 16.213395%, p: 16.209250% */ private int callFunction(int a) {
...
+ // This shows how much time is spent in current line.
+ // acc_p field means how much time is spent in current line and functions called by current line.
+ // p field means how much time is spent just in current line.
+ /* acc_p: 99.966552%, p: 83.628188% */ i = callFunction(i);
-run annotate.py:
-
- $python annotate.py
-
-It generates annotated_files directory.
-annotated_files/summary file contains summary information for each source file.
-An example is as below.
-
- /AndroidStudioProjects/SudoGame/app/src/main/jni/sudo-game-jni.cpp: accumulated_period: 25.587937%, period: 1.250961%
- function (checkValid(Board const&, int, int)): line 99, accumulated_period: 23.564356%, period: 0.908457%
- function (canFindSolution_r(Board&, int, int)): line 135, accumulated_period: 22.260125%, period: 0.142359%
- function (canFindSolution(Board&)): line 166, accumulated_period: 22.233101%, period: 0.000000%
- function (Java_com_example_sudogame_GameModel_canFindSolution): line 470, accumulated_period: 21.983184%, period: 0.000000%
- function (Java_com_example_sudogame_GameModel_initRandomBoard): line 430, accumulated_period: 2.226896%, period: 0.000000%
-
- line 27: accumulated_period: 0.011729%, period: 0.000000%
- line 32: accumulated_period: 0.004362%, period: 0.000000%
- line 33: accumulated_period: 0.004427%, period: 0.000000%
- line 36: accumulated_period: 0.003303%, period: 0.000000%
- line 39: accumulated_period: 0.010367%, period: 0.004123%
- line 41: accumulated_period: 0.162219%, period: 0.000000%
-
-annotated_files/ also contains annotated source files which are found by
-annotate.py. For example, part of checkValid() function in libsudo-game-jni.cpp
-is annotated as below.
-
- /* [func] acc_p: 23.564356%, p: 0.908457% */static bool checkValid(const Board& board, int curR, int curC) {
- /* acc_p: 0.037933%, p: 0.037933% */ int digit = board.digits[curR][curC];
- /* acc_p: 0.162355%, p: 0.162355% */ for (int r = 0; r < BOARD_ROWS; ++r) {
- /* acc_p: 0.020880%, p: 0.020880% */ if (r == curR) {
- /* acc_p: 0.034691%, p: 0.034691% */ continue;
- }
- /* acc_p: 0.176490%, p: 0.176490% */ if (board.digits[r][curC] == digit) {
- /* acc_p: 14.957673%, p: 0.059022% */ LOGI("conflict (%d, %d) (%d, %d)", curR, curC, r, curC);
- /* acc_p: 0.016296%, p: 0.016296% */ return false;
- }
- }
diff --git a/simpleperf/SampleComparator.h b/simpleperf/SampleComparator.h
index 9eefeb4..7778181 100644
--- a/simpleperf/SampleComparator.h
+++ b/simpleperf/SampleComparator.h
@@ -60,6 +60,7 @@
branch_from.map->dso->Path().c_str());
BUILD_COMPARE_STRING_FUNCTION(CompareSymbolFrom,
branch_from.symbol->DemangledName());
+BUILD_COMPARE_VALUE_FUNCTION(CompareCallGraphDuplicated, callchain.duplicated);
template <typename EntryT>
int CompareTotalPeriod(const EntryT* sample1, const EntryT* sample2) {
@@ -68,6 +69,11 @@
return Compare(period2, period1);
}
+template <typename EntryT>
+int ComparePeriod(const EntryT* sample1, const EntryT* sample2) {
+ return Compare(sample2->period, sample1->period);
+}
+
// SampleComparator is a class using a collection of compare functions to
// compare two samples.
diff --git a/simpleperf/SampleDisplayer.h b/simpleperf/SampleDisplayer.h
index 4317582..2dde02e 100644
--- a/simpleperf/SampleDisplayer.h
+++ b/simpleperf/SampleDisplayer.h
@@ -106,13 +106,21 @@
public:
CallgraphDisplayer(uint32_t max_stack = UINT32_MAX,
- double percent_limit = 0.0)
- : max_stack_(max_stack), percent_limit_(percent_limit) {}
+ double percent_limit = 0.0,
+ bool brief_callgraph = false)
+ : max_stack_(max_stack), percent_limit_(percent_limit), brief_callgraph_(brief_callgraph) {}
virtual ~CallgraphDisplayer() {}
void operator()(FILE* fp, const SampleT* sample) {
+ if (sample->callchain.children.empty()) {
+ return;
+ }
std::string prefix = " ";
+ if (brief_callgraph_ && sample->callchain.duplicated) {
+ fprintf(fp, "%s[skipped in brief callgraph mode]\n", prefix.c_str());
+ return;
+ }
fprintf(fp, "%s|\n", prefix.c_str());
fprintf(fp, "%s-- %s\n", prefix.c_str(), PrintSampleName(sample).c_str());
prefix.append(3, ' ');
@@ -169,6 +177,7 @@
private:
uint32_t max_stack_;
double percent_limit_;
+ bool brief_callgraph_;
};
// SampleDisplayer is a class using a collections of display functions to show a
diff --git a/simpleperf/callchain.h b/simpleperf/callchain.h
index 2267fec..b2a0457 100644
--- a/simpleperf/callchain.h
+++ b/simpleperf/callchain.h
@@ -38,10 +38,13 @@
template <typename EntryT>
struct CallChainRoot {
typedef CallChainNode<EntryT> NodeT;
+ // If duplicated = true, this call tree is part of another call tree.
+ // And we don't need to show it in brief callgraph report mode.
+ bool duplicated;
uint64_t children_period;
std::vector<std::unique_ptr<NodeT>> children;
- CallChainRoot() : children_period(0) {}
+ CallChainRoot() : duplicated(false), children_period(0) {}
void AddCallChain(
const std::vector<EntryT*>& callchain, uint64_t period,
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index 191d641..2ce5295 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -49,7 +49,7 @@
void DumpFileHeader();
void DumpAttrSection();
void DumpDataSection();
- void DumpFeatureSection();
+ bool DumpFeatureSection();
std::string record_filename_;
std::unique_ptr<RecordFileReader> record_file_reader_;
@@ -75,7 +75,9 @@
DumpFileHeader();
DumpAttrSection();
DumpDataSection();
- DumpFeatureSection();
+ if (!DumpFeatureSection()) {
+ return false;
+ }
return true;
}
@@ -180,7 +182,7 @@
}, false);
}
-void DumpRecordCommand::DumpFeatureSection() {
+bool DumpRecordCommand::DumpFeatureSection() {
std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
for (const auto& pair : section_map) {
int feature = pair.first;
@@ -220,8 +222,18 @@
symbol.addr, symbol.addr + symbol.len);
}
}
+ } else if (feature == FEAT_META_INFO) {
+ std::unordered_map<std::string, std::string> info_map;
+ if (!record_file_reader_->ReadMetaInfoFeature(&info_map)) {
+ return false;
+ }
+ PrintIndented(1, "meta_info:\n");
+ for (auto& pair : info_map) {
+ PrintIndented(2, "%s = %s\n", pair.first.c_str(), pair.second.c_str());
+ }
}
}
+ return true;
}
void RegisterDumpRecordCommand() {
diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp
index 0248aa9..7aa0c96 100644
--- a/simpleperf/cmd_list.cpp
+++ b/simpleperf/cmd_list.cpp
@@ -20,6 +20,7 @@
#include <vector>
#include <android-base/logging.h>
+#include <android-base/test_utils.h>
#include "command.h"
#include "environment.h"
@@ -27,17 +28,60 @@
#include "event_fd.h"
#include "event_type.h"
+static bool IsEventTypeSupported(const EventType& event_type) {
+ if (event_type.type != PERF_TYPE_RAW) {
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
+ // Exclude kernel to list supported events even when
+ // /proc/sys/kernel/perf_event_paranoid is 2.
+ attr.exclude_kernel = 1;
+ return IsEventAttrSupported(attr);
+ }
+ if (event_type.limited_arch == "arm" && GetBuildArch() != ARCH_ARM &&
+ GetBuildArch() != ARCH_ARM64) {
+ return false;
+ }
+ // Because the kernel may not check whether the raw event is supported by the cpu pmu.
+ // We can't decide whether the raw event is supported by calling perf_event_open().
+ // Instead, we can check if it can collect some real number.
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
+ std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, gettid(), -1, nullptr);
+ if (event_fd == nullptr) {
+ return false;
+ }
+ auto work_function = []() {
+ TemporaryFile tmpfile;
+ FILE* fp = fopen(tmpfile.path, "w");
+ if (fp == nullptr) {
+ return;
+ }
+ for (int i = 0; i < 10; ++i) {
+ fprintf(fp, "output some data\n");
+ }
+ fclose(fp);
+ };
+ work_function();
+ PerfCounter counter;
+ if (!event_fd->ReadCounter(&counter)) {
+ return false;
+ }
+ return (counter.value != 0u);
+}
+
static void PrintEventTypesOfType(uint32_t type, const std::string& type_name,
const std::vector<EventType>& event_types) {
printf("List of %s:\n", type_name.c_str());
+ if (type == PERF_TYPE_RAW && (GetBuildArch() == ARCH_ARM || GetBuildArch() == ARCH_ARM64)) {
+ printf(" # Please refer to PMU event numbers listed in ARMv8 manual for details.\n");
+ printf(" # A possible link is https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile.\n");
+ }
for (auto& event_type : event_types) {
if (event_type.type == type) {
- perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
- // Exclude kernel to list supported events even when
- // /proc/sys/kernel/perf_event_paranoid is 2.
- attr.exclude_kernel = 1;
- if (IsEventAttrSupported(attr)) {
- printf(" %s\n", event_type.name.c_str());
+ if (IsEventTypeSupported(event_type)) {
+ printf(" %s", event_type.name.c_str());
+ if (!event_type.description.empty()) {
+ printf("\t\t# %s", event_type.description.c_str());
+ }
+ printf("\n");
}
}
}
@@ -48,7 +92,7 @@
public:
ListCommand()
: Command("list", "list available event types",
- "Usage: simpleperf list [hw|sw|cache|tracepoint]\n"
+ "Usage: simpleperf list [hw|sw|cache|raw|tracepoint]\n"
" List all available perf events on this machine.\n") {
}
@@ -64,6 +108,7 @@
{"hw", {PERF_TYPE_HARDWARE, "hardware events"}},
{"sw", {PERF_TYPE_SOFTWARE, "software events"}},
{"cache", {PERF_TYPE_HW_CACHE, "hw-cache events"}},
+ {"raw", {PERF_TYPE_RAW, "raw events provided by cpu pmu"}},
{"tracepoint", {PERF_TYPE_TRACEPOINT, "tracepoint events"}},
{"user-space-sampler", {SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS, "user-space samplers"}},
};
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 1cbb86c..acba6ab 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -29,6 +29,7 @@
#include <android-base/parsedouble.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
+#include <android-base/test_utils.h>
#include "command.h"
#include "dwarf_unwind.h"
@@ -75,6 +76,7 @@
"Usage: simpleperf record [options] [command [command-args]]\n"
" Gather sampling information of running [command]. And -a/-p/-t option\n"
" can be used to change target of sampling information.\n"
+" The default options are: -e cpu-cycles -f 4000 -o perf.data.\n"
"-a System-wide collection.\n"
"-b Enable take branch stack sampling. Same as '-j any'\n"
"-c count Set event sample period. It means recording one sample when\n"
@@ -87,9 +89,6 @@
"--cpu cpu_item1,cpu_item2,...\n"
" Collect samples only on the selected cpus. cpu_item can be cpu\n"
" number like 1, or cpu range like 0-3.\n"
-"--dump-symbols Dump symbols in perf.data. By default perf.data doesn't contain\n"
-" symbol information for samples. This option is used when there\n"
-" is no symbol information in report environment.\n"
"--duration time_in_sec Monitor for time_in_sec seconds instead of running\n"
" [command]. Here time_in_sec may be any positive\n"
" floating point number.\n"
@@ -126,6 +125,9 @@
" possible value <= 1024 will be used.\n"
"--no-dump-kernel-symbols Don't dump kernel symbols in perf.data. By default\n"
" kernel symbols will be dumped when needed.\n"
+"--no-dump-symbols Don't dump symbols in perf.data. By default symbols are\n"
+" dumped in perf.data, to support reporting in another\n"
+" environment.\n"
"--no-inherit Don't record created child threads/processes.\n"
"--no-unwind If `--call-graph dwarf` option is used, then the user's stack\n"
" will be unwound by default. Use this option to disable the\n"
@@ -137,9 +139,11 @@
" will be unwound while recording by default. But it may lose\n"
" records as stacking unwinding can be time consuming. Use this\n"
" option to unwind the user's stack after recording.\n"
+"--start_profiling_fd fd_no After starting profiling, write \"STARTED\" to\n"
+" <fd_no>, then close <fd_no>.\n"
"--symfs <dir> Look for files with symbols relative to this directory.\n"
" This option is used to provide files with symbol table and\n"
-" debug information, which are used by --dump-symbols and -g.\n"
+" debug information, which are used for unwinding and dumping symbols.\n"
"-t tid1,tid2,... Record events on existing threads. Mutually exclusive with -a.\n"
// clang-format on
),
@@ -157,13 +161,14 @@
child_inherit_(true),
duration_in_sec_(0),
can_dump_kernel_symbols_(true),
- dump_symbols_(false),
+ dump_symbols_(true),
event_selection_set_(false),
mmap_page_range_(std::make_pair(1, DESIRED_PAGES_IN_MAPPED_BUFFER)),
record_filename_("perf.data"),
start_sampling_time_in_ns_(0),
sample_record_count_(0),
- lost_record_count_(0) {
+ lost_record_count_(0),
+ start_profiling_fd_(-1) {
// Stop profiling if parent exits.
prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
}
@@ -219,15 +224,18 @@
uint64_t sample_record_count_;
uint64_t lost_record_count_;
+ int start_profiling_fd_;
};
bool RecordCommand::Run(const std::vector<std::string>& args) {
+ // 0. Do some environment preparation.
if (!CheckPerfEventLimit()) {
return false;
}
if (!InitPerfClock()) {
return false;
}
+ PrepareVdsoFile();
// 1. Parse options, and use default measured event type if not given.
std::vector<std::string> workload_args;
@@ -321,6 +329,12 @@
if (workload != nullptr && !workload->IsStarted() && !workload->Start()) {
return false;
}
+ if (start_profiling_fd_ != -1) {
+ if (!android::base::WriteStringToFd("STARTED", start_profiling_fd_)) {
+ PLOG(ERROR) << "failed to write to start_profiling_fd_";
+ }
+ close(start_profiling_fd_);
+ }
if (!loop->RunLoop()) {
return false;
}
@@ -421,8 +435,6 @@
return false;
}
cpus_ = GetCpusFromString(args[i]);
- } else if (args[i] == "--dump-symbols") {
- dump_symbols_ = true;
} else if (args[i] == "--duration") {
if (!NextArgumentOrError(args, &i)) {
return false;
@@ -492,6 +504,8 @@
mmap_page_range_.first = mmap_page_range_.second = pages;
} else if (args[i] == "--no-dump-kernel-symbols") {
can_dump_kernel_symbols_ = false;
+ } else if (args[i] == "--no-dump-symbols") {
+ dump_symbols_ = false;
} else if (args[i] == "--no-inherit") {
child_inherit_ = false;
} else if (args[i] == "--no-unwind") {
@@ -512,6 +526,14 @@
event_selection_set_.AddMonitoredProcesses(pids);
} else if (args[i] == "--post-unwind") {
post_unwind_ = true;
+ } else if (args[i] == "--start_profiling_fd") {
+ if (!NextArgumentOrError(args, &i)) {
+ return false;
+ }
+ if (!android::base::ParseInt(args[i].c_str(), &start_profiling_fd_, 0)) {
+ LOG(ERROR) << "Invalid start_profiling_fd: " << args[i];
+ return false;
+ }
} else if (args[i] == "--symfs") {
if (!NextArgumentOrError(args, &i)) {
return false;
@@ -559,6 +581,13 @@
}
}
+ if (fp_callchain_sampling_) {
+ if (GetBuildArch() == ARCH_ARM) {
+ LOG(WARNING) << "`--callgraph fp` option doesn't work well on arm architecture, "
+ << "consider using `-g` option or profiling on aarch64 architecture.";
+ }
+ }
+
if (system_wide_collection_ && event_selection_set_.HasMonitoredTarget()) {
LOG(ERROR) << "Record system wide and existing processes/threads can't be "
"used at the same time.";
@@ -905,7 +934,9 @@
const std::vector<std::string>& args) {
// Read data section of perf.data to collect hit file information.
thread_tree_.ClearThreadAndMap();
- Dso::ReadKernelSymbolsFromProc();
+ if (CheckKernelSymbolAddresses()) {
+ Dso::ReadKernelSymbolsFromProc();
+ }
auto callback = [&](const Record* r) {
thread_tree_.Update(*r);
if (r->type() == PERF_RECORD_SAMPLE) {
@@ -916,7 +947,7 @@
return false;
}
- size_t feature_count = 4;
+ size_t feature_count = 5;
if (branch_sampling_) {
feature_count++;
}
@@ -959,6 +990,13 @@
!record_file_writer_->WriteBranchStackFeature()) {
return false;
}
+
+ std::unordered_map<std::string, std::string> info_map;
+ info_map["simpleperf_version"] = GetSimpleperfVersion();
+ if (!record_file_writer_->WriteMetaInfoFeature(info_map)) {
+ return false;
+ }
+
if (!record_file_writer_->EndWriteFeatures()) {
return false;
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 3820c2c..571a3ca 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -16,6 +16,9 @@
#include <gtest/gtest.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
@@ -136,6 +139,18 @@
ASSERT_TRUE(RunRecordCmd({"--call-graph", "fp"}));
}
+TEST(record_cmd, fp_callchain_sampling_warning_on_arm) {
+ if (GetBuildArch() != ARCH_ARM) {
+ GTEST_LOG_(INFO) << "This test does nothing as it only tests on arm arch.";
+ return;
+ }
+ ASSERT_EXIT(
+ {
+ exit(RunRecordCmd({"--call-graph", "fp"}) ? 0 : 1);
+ },
+ testing::ExitedWithCode(0), "doesn't work well on arm");
+}
+
TEST(record_cmd, system_wide_fp_callchain_sampling) {
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a", "--call-graph", "fp"})));
}
@@ -239,11 +254,11 @@
TEST(record_cmd, kernel_symbol) {
TemporaryFile tmpfile;
- ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
+ ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols"}, tmpfile.path));
bool success;
CheckKernelSymbol(tmpfile.path, true, &success);
ASSERT_TRUE(success);
- ASSERT_TRUE(RunRecordCmd({"--no-dump-kernel-symbols"}, tmpfile.path));
+ ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols", "--no-dump-kernel-symbols"}, tmpfile.path));
CheckKernelSymbol(tmpfile.path, false, &success);
ASSERT_TRUE(success);
}
@@ -288,26 +303,26 @@
*success = true;
}
-TEST(record_cmd, dump_symbols) {
+TEST(record_cmd, no_dump_symbols) {
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
bool success;
- CheckDsoSymbolRecords(tmpfile.path, false, &success);
- ASSERT_TRUE(success);
- ASSERT_TRUE(RunRecordCmd({"--dump-symbols"}, tmpfile.path));
CheckDsoSymbolRecords(tmpfile.path, true, &success);
ASSERT_TRUE(success);
+ ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols"}, tmpfile.path));
+ CheckDsoSymbolRecords(tmpfile.path, false, &success);
+ ASSERT_TRUE(success);
if (IsDwarfCallChainSamplingSupported()) {
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(1, &workloads);
std::string pid = std::to_string(workloads[0]->GetPid());
ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}, tmpfile.path));
bool success;
- CheckDsoSymbolRecords(tmpfile.path, false, &success);
- ASSERT_TRUE(success);
- ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g", "--dump-symbols"}, tmpfile.path));
CheckDsoSymbolRecords(tmpfile.path, true, &success);
ASSERT_TRUE(success);
+ ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g", "--no-dump-symbols"}, tmpfile.path));
+ CheckDsoSymbolRecords(tmpfile.path, false, &success);
+ ASSERT_TRUE(success);
}
}
@@ -316,9 +331,8 @@
GTEST_LOG_(INFO) << "Test requires root privilege";
return;
}
- system("echo 0 >/proc/sys/kernel/kptr_restrict");
TemporaryFile tmpfile;
- ASSERT_TRUE(RunRecordCmd({"--dump-symbols", "-a", "-o", tmpfile.path, "sleep", "1"}));
+ ASSERT_TRUE(RunRecordCmd({"-a", "-o", tmpfile.path, "sleep", "1"}));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
ASSERT_TRUE(reader != nullptr);
std::map<int, SectionDesc> section_map = reader->FeatureSectionDescriptors();
@@ -395,3 +409,31 @@
uint64_t end_time_in_ns = GetSystemClock();
ASSERT_GT(end_time_in_ns - start_time_in_ns, static_cast<uint64_t>(2e9));
}
+
+TEST(record_cmd, start_profiling_fd_option) {
+ int pipefd[2];
+ ASSERT_EQ(0, pipe(pipefd));
+ int read_fd = pipefd[0];
+ int write_fd = pipefd[1];
+ ASSERT_EXIT(
+ {
+ close(read_fd);
+ exit(RunRecordCmd({"--start_profiling_fd", std::to_string(write_fd)}) ? 0 : 1);
+ },
+ testing::ExitedWithCode(0), "");
+ close(write_fd);
+ std::string s;
+ ASSERT_TRUE(android::base::ReadFdToString(read_fd, &s));
+ close(read_fd);
+ ASSERT_EQ("STARTED", s);
+}
+
+TEST(record_cmd, record_meta_info_feature) {
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::unordered_map<std::string, std::string> info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map));
+ ASSERT_NE(info_map.find("simpleperf_version"), info_map.end());
+}
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index f160dea..29cf743 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -99,6 +99,7 @@
std::vector<SampleEntry*> samples;
uint64_t total_samples;
uint64_t total_period;
+ uint64_t total_error_callchains;
};
BUILD_COMPARE_VALUE_FUNCTION(CompareVaddrInFile, vaddr_in_file);
@@ -112,7 +113,8 @@
: SampleTreeBuilder(sample_comparator),
thread_tree_(thread_tree),
total_samples_(0),
- total_period_(0) {}
+ total_period_(0),
+ total_error_callchains_(0) {}
void SetFilters(const std::unordered_set<int>& pid_filter,
const std::unordered_set<int>& tid_filter,
@@ -126,11 +128,13 @@
symbol_filter_ = symbol_filter;
}
- SampleTree GetSampleTree() const {
+ SampleTree GetSampleTree() {
+ AddCallChainDuplicateInfo();
SampleTree sample_tree;
sample_tree.samples = GetSamples();
sample_tree.total_samples = total_samples_;
sample_tree.total_period = total_period_;
+ sample_tree.total_error_callchains = total_error_callchains_;
return sample_tree;
}
@@ -178,6 +182,11 @@
const uint64_t& acc_info) override {
const ThreadEntry* thread = sample->thread;
const MapEntry* map = thread_tree_->FindMap(thread, ip, in_kernel);
+ if (thread_tree_->IsUnknownDso(map->dso)) {
+ // The unwinders can give wrong ip addresses, which can't map to a valid dso. Skip them.
+ total_error_callchains_++;
+ return nullptr;
+ }
uint64_t vaddr_in_file;
const Symbol* symbol = thread_tree_->FindSymbol(map, ip, &vaddr_in_file);
std::unique_ptr<SampleEntry> callchain_sample(new SampleEntry(
@@ -241,6 +250,7 @@
uint64_t total_samples_;
uint64_t total_period_;
+ uint64_t total_error_callchains_;
};
struct SampleTreeBuilderOptions {
@@ -297,12 +307,15 @@
"report", "report sampling information in perf.data",
// clang-format off
"Usage: simpleperf report [options]\n"
+"The default options are: -i perf.data --sort comm,pid,tid,dso,symbol.\n"
"-b Use the branch-to addresses in sampled take branches instead of the\n"
" instruction addresses. Only valid for perf.data recorded with -b/-j\n"
" option.\n"
"--children Print the overhead accumulated by appearing in the callchain.\n"
"--comms comm1,comm2,... Report only for selected comms.\n"
"--dsos dso1,dso2,... Report only for selected dsos.\n"
+"--full-callgraph Print full call graph. Used with -g option. By default,\n"
+" brief call graph is printed.\n"
"-g [callee|caller] Print call graph. If callee mode is used, the graph\n"
" shows how functions are called from others. Otherwise,\n"
" the graph shows how functions call others.\n"
@@ -351,7 +364,8 @@
callgraph_show_callee_(false),
callgraph_max_stack_(UINT32_MAX),
callgraph_percent_limit_(0),
- raw_period_(false) {}
+ raw_period_(false),
+ brief_callgraph_(true) {}
bool Run(const std::vector<std::string>& args);
@@ -386,6 +400,7 @@
uint32_t callgraph_max_stack_;
double callgraph_percent_limit_;
bool raw_period_;
+ bool brief_callgraph_;
std::string report_filename_;
};
@@ -443,7 +458,8 @@
}
std::vector<std::string> strs = android::base::Split(args[i], ",");
filter.insert(strs.begin(), strs.end());
-
+ } else if (args[i] == "--full-callgraph") {
+ brief_callgraph_ = false;
} else if (args[i] == "-g") {
print_callgraph_ = true;
accumulate_callchain_ = true;
@@ -640,7 +656,7 @@
ReportCmdCallgraphDisplayerWithVaddrInFile());
} else {
displayer.AddExclusiveDisplayFunction(ReportCmdCallgraphDisplayer(
- callgraph_max_stack_, callgraph_percent_limit_));
+ callgraph_max_stack_, callgraph_percent_limit_, brief_callgraph_));
}
}
}
@@ -650,6 +666,10 @@
SampleComparator<SampleEntry> sort_comparator;
sort_comparator.AddCompareFunction(CompareTotalPeriod);
+ if (print_callgraph_) {
+ sort_comparator.AddCompareFunction(CompareCallGraphDuplicated);
+ }
+ sort_comparator.AddCompareFunction(ComparePeriod);
sort_comparator.AddComparator(comparator);
sample_tree_sorter_.reset(new ReportCmdSampleTreeSorter(sort_comparator));
sample_tree_displayer_.reset(new ReportCmdSampleTreeDisplayer(displayer));
@@ -798,6 +818,11 @@
fprintf(report_fp, "Event: %s (type %u, config %llu)\n", attr.name.c_str(),
attr.attr.type, attr.attr.config);
fprintf(report_fp, "Samples: %" PRIu64 "\n", sample_tree.total_samples);
+ if (sample_tree.total_error_callchains != 0) {
+ fprintf(report_fp, "Error Callchains: %" PRIu64 ", %f%%\n",
+ sample_tree.total_error_callchains,
+ sample_tree.total_error_callchains * 100.0 / sample_tree.total_samples);
+ }
fprintf(report_fp, "Event count: %" PRIu64 "\n\n", sample_tree.total_period);
sample_tree_displayer_->DisplaySamples(report_fp, sample_tree.samples, &sample_tree);
}
diff --git a/simpleperf/cmd_report_sample.cpp b/simpleperf/cmd_report_sample.cpp
index 886d1b4..f43f682 100644
--- a/simpleperf/cmd_report_sample.cpp
+++ b/simpleperf/cmd_report_sample.cpp
@@ -88,12 +88,10 @@
bool DumpProtobufReport(const std::string& filename);
bool ProcessRecord(std::unique_ptr<Record> record);
bool PrintSampleRecordInProtobuf(const SampleRecord& record);
- void GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip,
- uint64_t* pvaddr_in_file, uint32_t* pfile_id,
- int32_t* psymbol_id);
- void GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip,
- uint64_t* pvaddr_in_file, Dso** pdso,
- const Symbol** psymbol);
+ bool GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip, bool omit_unknown_dso,
+ uint64_t* pvaddr_in_file, uint32_t* pfile_id, int32_t* psymbol_id);
+ bool GetCallEntry(const ThreadEntry* thread, bool in_kernel, uint64_t ip, bool omit_unknown_dso,
+ uint64_t* pvaddr_in_file, Dso** pdso, const Symbol** psymbol);
bool PrintLostSituationInProtobuf();
bool PrintFileInfoInProtobuf();
bool PrintSampleRecord(const SampleRecord& record);
@@ -186,7 +184,6 @@
return false;
}
protobuf_coded_os.reset(nullptr);
- google::protobuf::ShutdownProtobufLibrary();
} else {
PrintLostSituation();
fflush(report_fp_);
@@ -276,6 +273,7 @@
static size_t sample_count = 0;
FprintIndented(report_fp_, 0, "sample %zu:\n", ++sample_count);
FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", sample.time());
+ FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", sample.event_count());
FprintIndented(report_fp_, 1, "thread_id: %d\n", sample.thread_id());
FprintIndented(report_fp_, 1, "callchain:\n");
for (int i = 0; i < sample.callchain_size(); ++i) {
@@ -332,7 +330,6 @@
return false;
}
}
- google::protobuf::ShutdownProtobufLibrary();
return true;
}
@@ -359,13 +356,15 @@
proto::Record proto_record;
proto::Sample* sample = proto_record.mutable_sample();
sample->set_time(r.time_data.time);
+ sample->set_event_count(r.period_data.period);
sample->set_thread_id(r.tid_data.tid);
bool in_kernel = r.InKernel();
const ThreadEntry* thread =
thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
- GetCallEntry(thread, in_kernel, r.ip_data.ip, &vaddr_in_file, &file_id,
- &symbol_id);
+ bool ret = GetCallEntry(thread, in_kernel, r.ip_data.ip, false, &vaddr_in_file, &file_id,
+ &symbol_id);
+ CHECK(ret);
proto::Sample_CallChainEntry* callchain = sample->add_callchain();
callchain->set_vaddr_in_file(vaddr_in_file);
callchain->set_file_id(file_id);
@@ -395,8 +394,9 @@
continue;
}
}
- GetCallEntry(thread, in_kernel, ip, &vaddr_in_file, &file_id,
- &symbol_id);
+ if (!GetCallEntry(thread, in_kernel, ip, true, &vaddr_in_file, &file_id, &symbol_id)) {
+ break;
+ }
callchain = sample->add_callchain();
callchain->set_vaddr_in_file(vaddr_in_file);
callchain->set_file_id(file_id);
@@ -412,14 +412,17 @@
return true;
}
-void ReportSampleCommand::GetCallEntry(const ThreadEntry* thread,
+bool ReportSampleCommand::GetCallEntry(const ThreadEntry* thread,
bool in_kernel, uint64_t ip,
+ bool omit_unknown_dso,
uint64_t* pvaddr_in_file,
uint32_t* pfile_id,
int32_t* psymbol_id) {
Dso* dso;
const Symbol* symbol;
- GetCallEntry(thread, in_kernel, ip, pvaddr_in_file, &dso, &symbol);
+ if (!GetCallEntry(thread, in_kernel, ip, omit_unknown_dso, pvaddr_in_file, &dso, &symbol)) {
+ return false;
+ }
if (!dso->GetDumpId(pfile_id)) {
*pfile_id = dso->CreateDumpId();
}
@@ -430,18 +433,24 @@
} else {
*psymbol_id = -1;
}
+ return true;
}
-void ReportSampleCommand::GetCallEntry(const ThreadEntry* thread,
+bool ReportSampleCommand::GetCallEntry(const ThreadEntry* thread,
bool in_kernel, uint64_t ip,
+ bool omit_unknown_dso,
uint64_t* pvaddr_in_file, Dso** pdso,
const Symbol** psymbol) {
const MapEntry* map = thread_tree_.FindMap(thread, ip, in_kernel);
+ if (omit_unknown_dso && thread_tree_.IsUnknownDso(map->dso)) {
+ return false;
+ }
*psymbol = thread_tree_.FindSymbol(map, ip, pvaddr_in_file, pdso);
// If we can't find symbol, use the dso shown in the map.
if (*psymbol == thread_tree_.UnknownSymbol()) {
*pdso = map->dso;
}
+ return true;
}
bool ReportSampleCommand::PrintLostSituationInProtobuf() {
@@ -507,11 +516,13 @@
FprintIndented(report_fp_, 0, "sample:\n");
FprintIndented(report_fp_, 1, "time: %" PRIu64 "\n", r.time_data.time);
+ FprintIndented(report_fp_, 1, "event_count: %" PRIu64 "\n", r.period_data.period);
FprintIndented(report_fp_, 1, "thread_id: %d\n", r.tid_data.tid);
bool in_kernel = r.InKernel();
const ThreadEntry* thread =
thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
- GetCallEntry(thread, in_kernel, r.ip_data.ip, &vaddr_in_file, &dso, &symbol);
+ bool ret = GetCallEntry(thread, in_kernel, r.ip_data.ip, false, &vaddr_in_file, &dso, &symbol);
+ CHECK(ret);
FprintIndented(report_fp_, 1, "vaddr_in_file: %" PRIx64 "\n", vaddr_in_file);
FprintIndented(report_fp_, 1, "file: %s\n", dso->Path().c_str());
FprintIndented(report_fp_, 1, "symbol: %s\n", symbol->DemangledName());
@@ -541,7 +552,9 @@
continue;
}
}
- GetCallEntry(thread, in_kernel, ip, &vaddr_in_file, &dso, &symbol);
+ if (!GetCallEntry(thread, in_kernel, ip, true, &vaddr_in_file, &dso, &symbol)) {
+ break;
+ }
FprintIndented(report_fp_, 2, "vaddr_in_file: %" PRIx64 "\n",
vaddr_in_file);
FprintIndented(report_fp_, 2, "file: %s\n", dso->Path().c_str());
diff --git a/simpleperf/cmd_report_sample_test.cpp b/simpleperf/cmd_report_sample_test.cpp
index d07f0fd..3e92396 100644
--- a/simpleperf/cmd_report_sample_test.cpp
+++ b/simpleperf/cmd_report_sample_test.cpp
@@ -54,3 +54,28 @@
ASSERT_TRUE(android::base::ReadFileToString(tmpfile2.path, &data));
ASSERT_NE(data.find("file:"), std::string::npos);
}
+
+TEST(cmd_report_sample, no_skipped_file_id) {
+ TemporaryFile tmpfile;
+ TemporaryFile tmpfile2;
+ ASSERT_TRUE(ReportSampleCmd()->Run({"-i", GetTestData(PERF_DATA_WITH_WRONG_IP_IN_CALLCHAIN),
+ "-o", tmpfile.path, "--protobuf"}));
+ ASSERT_TRUE(ReportSampleCmd()->Run({"--dump-protobuf-report", tmpfile.path, "-o",
+ tmpfile2.path}));
+ // If wrong ips in callchain are omitted, "unknown" file path will not be generated.
+ std::string data;
+ ASSERT_TRUE(android::base::ReadFileToString(tmpfile2.path, &data));
+ ASSERT_EQ(data.find("unknown"), std::string::npos);
+}
+
+TEST(cmd_report_sample, sample_has_event_count) {
+ TemporaryFile tmpfile;
+ TemporaryFile tmpfile2;
+ ASSERT_TRUE(ReportSampleCmd()->Run({"-i", GetTestData(PERF_DATA_WITH_SYMBOLS),
+ "-o", tmpfile.path, "--protobuf"}));
+ ASSERT_TRUE(ReportSampleCmd()->Run(
+ {"--dump-protobuf-report", tmpfile.path, "-o", tmpfile2.path}));
+ std::string data;
+ ASSERT_TRUE(android::base::ReadFileToString(tmpfile2.path, &data));
+ ASSERT_NE(data.find("event_count:"), std::string::npos);
+}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index e29c8d8..bf690c0 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -131,10 +131,9 @@
static bool CheckCalleeMode(std::vector<std::string>& lines) {
bool found = false;
- for (size_t i = 0; i + 2 < lines.size(); ++i) {
+ for (size_t i = 0; i + 1 < lines.size(); ++i) {
if (lines[i].find("GlobalFunc") != std::string::npos &&
- lines[i + 1].find('|') != std::string::npos &&
- lines[i + 2].find("main") != std::string::npos) {
+ lines[i + 1].find("main") != std::string::npos) {
found = true;
break;
}
@@ -144,10 +143,9 @@
static bool CheckCallerMode(std::vector<std::string>& lines) {
bool found = false;
- for (size_t i = 0; i + 2 < lines.size(); ++i) {
+ for (size_t i = 0; i + 1 < lines.size(); ++i) {
if (lines[i].find("main") != std::string::npos &&
- lines[i + 1].find('|') != std::string::npos &&
- lines[i + 2].find("GlobalFunc") != std::string::npos) {
+ lines[i + 1].find("GlobalFunc") != std::string::npos) {
found = true;
break;
}
@@ -433,7 +431,7 @@
Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g", "--max-stack", "0"});
ASSERT_TRUE(success);
ASSERT_EQ(content.find("89.03"), std::string::npos);
- Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g", "--max-stack", "1"});
+ Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g", "--max-stack", "2"});
ASSERT_TRUE(success);
ASSERT_NE(content.find("89.03"), std::string::npos);
@@ -464,6 +462,15 @@
ASSERT_EQ(content.find("%"), std::string::npos);
}
+TEST_F(ReportCommandTest, full_callgraph_option) {
+ Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
+ ASSERT_TRUE(success);
+ ASSERT_NE(content.find("skipped in brief callgraph mode"), std::string::npos);
+ Report(CALLGRAPH_FP_PERF_DATA, {"-g", "--full-callgraph"});
+ ASSERT_TRUE(success);
+ ASSERT_EQ(content.find("skipped in brief callgraph mode"), std::string::npos);
+}
+
#if defined(__linux__)
#include "event_selection_set.h"
diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp
index cdd5593..a0929bc 100644
--- a/simpleperf/cmd_stat.cpp
+++ b/simpleperf/cmd_stat.cpp
@@ -238,6 +238,14 @@
sap_mid);
}
}
+ if (android::base::EndsWith(s.type_name, "-refill")) {
+ std::string other_name = s.type_name.substr(0, s.type_name.size() - strlen("-refill"));
+ const CounterSummary* other = FindSummary(other_name, s.modifier);
+ if (other != nullptr && other->IsMonitoredAtTheSameTime(s) && other->count != 0) {
+ double miss_rate = static_cast<double>(s.count) / other->count;
+ return android::base::StringPrintf("%f%%%cmiss rate", miss_rate * 100, sap_mid);
+ }
+ }
double rate = s.count / (duration_in_sec / s.scale);
if (rate > 1e9) {
return android::base::StringPrintf("%.3lf%cG/sec", rate / 1e9, sap_mid);
diff --git a/simpleperf/demo/README.md b/simpleperf/demo/README.md
new file mode 100644
index 0000000..8530dc6
--- /dev/null
+++ b/simpleperf/demo/README.md
@@ -0,0 +1,110 @@
+# Examples of using simpleperf to profile Android applications
+
+## Table of Contents
+
+- [Introduction](#introduction)
+- [Profiling Java application](#profiling-java-application)
+- [Profiling Java/C++ application](#profiling-javac-application)
+
+## Introduction
+
+Simpleperf is a native profiler used on Android platform. It can be used to profile Android
+applications. It's document is at [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/README.md).
+Instructions of preparing your Android application for profiling are [here](https://android.googlesource.com/platform/system/extras/+/master/simpleperf/README.md#Android-application-profiling).
+This directory is to show examples of using simpleperf to profile Android applications. The
+meaning of each directory is as below:
+
+ ../scripts/ -- contain simpleperf binaries and scripts.
+ SimpleperfExamplePureJava/ -- contains an Android Studio project using only Java code.
+ SimpleperfExampleWithNative/ -- contains an Android Studio project using both Java and C++ code.
+
+It can be downloaded as below:
+
+ $ git clone https://android.googlesource.com/platform/system/extras
+ $ cd extras/simpleperf/demo
+
+## Profiling Java application
+
+ Android Studio project: SimpleExamplePureJava
+ test device: Android O (Google Pixel XL)
+ test device: Android N (Google Nexus 5X)
+
+steps:
+1. Build and install app:
+```
+# Open SimpleperfExamplesPureJava project with Android Studio,
+# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
+$ cd SimpleperfExamplePureJava
+
+# On windows, use "gradlew" instead.
+$ ./gradlew clean assemble
+$ adb install -r app/build/outputs/apk/app-profiling.apk
+```
+
+2. Record profiling data:
+```
+$ cd ../../scripts/
+$ gvim app_profiler.config
+ change app_package_name line to: app_package_name = "com.example.simpleperf.simpleperfexamplepurejava"
+$ python app_profiler.py
+ It runs the application and collects profiling data in perf.data, binaries on device in binary_cache/.
+```
+
+3. Show profiling data:
+```
+a. show call graph in txt mode
+ # On windows, use "bin\windows\x86\simpleperf" instead.
+ $ bin/linux/x86_64/simpleperf report -g | more
+ If on other hosts, use corresponding simpleperf binary.
+b. show call graph in gui mode
+ $ python report.py -g
+c. show samples in source code
+ $ gvim annotate.config
+ change source_dirs line to: source_dirs = ["../demo/SimpleperfExamplePureJava"]
+ $ python annotate.py
+ $ gvim annotated_files/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java
+ check the annoated source file MainActivity.java.
+```
+
+## Profiling Java/C++ application
+
+ Android Studio project: SimpleExampleWithNative
+ test device: Android O (Google Pixel XL)
+ test device: Android N (Google Nexus 5X)
+
+steps:
+1. Build and install app:
+```
+# Open SimpleperfExamplesPureJava project with Android Studio,
+# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
+$ cd SimpleperfExampleWithNative
+
+# On windows, use "gradlew" instead.
+$ ./gradlew clean assemble
+$ adb install -r app/build/outputs/apk/app-profiling.apk
+```
+
+2. Record profiling data:
+```
+$ cd ../../scripts/
+$ gvim app_profiler.config
+ change app_package_name line to: app_package_name = "com.example.simpleperf.simpleperfexamplewithnative"
+$ python app_profiler.py
+ It runs the application and collects profiling data in perf.data, binaries on device in binary_cache/.
+```
+
+3. Show profiling data:
+```
+a. show call graph in txt mode
+ # On windows, use "bin\windows\x86\simpleperf" instead.
+ $ bin/linux/x86_64/simpleperf report -g | more
+ If on other hosts, use corresponding simpleperf binary.
+b. show call graph in gui mode
+ $ python report.py -g
+c. show samples in source code
+ $ gvim annotate.config
+ change source_dirs line to: source_dirs = ["../demo/SimpleperfExampleWithNative"]
+ $ python annotate.py
+ $ find . -name "native-lib.cpp" | xargs gvim
+ check the annoated source file native-lib.cpp.
+```
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.gitignore b/simpleperf/demo/SimpleperfExamplePureJava/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.idea/compiler.xml b/simpleperf/demo/SimpleperfExamplePureJava/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.idea/compiler.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <resourceExtensions />
+ <wildcardResourcePatterns>
+ <entry name="!?*.java" />
+ <entry name="!?*.form" />
+ <entry name="!?*.class" />
+ <entry name="!?*.groovy" />
+ <entry name="!?*.scala" />
+ <entry name="!?*.flex" />
+ <entry name="!?*.kt" />
+ <entry name="!?*.clj" />
+ <entry name="!?*.aj" />
+ </wildcardResourcePatterns>
+ <annotationProcessing>
+ <profile default="true" name="Default" enabled="false">
+ <processorPath useClasspath="true" />
+ </profile>
+ </annotationProcessing>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.idea/copyright/profiles_settings.xml b/simpleperf/demo/SimpleperfExamplePureJava/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+ <settings default="" />
+</component>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.idea/gradle.xml b/simpleperf/demo/SimpleperfExamplePureJava/.idea/gradle.xml
new file mode 100644
index 0000000..7ac24c7
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.idea/gradle.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="GradleSettings">
+ <option name="linkedExternalProjectsSettings">
+ <GradleProjectSettings>
+ <option name="distributionType" value="DEFAULT_WRAPPED" />
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
+ <option name="modules">
+ <set>
+ <option value="$PROJECT_DIR$" />
+ <option value="$PROJECT_DIR$/app" />
+ </set>
+ </option>
+ <option name="resolveModulePerSourceSet" value="false" />
+ </GradleProjectSettings>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.idea/misc.xml b/simpleperf/demo/SimpleperfExamplePureJava/.idea/misc.xml
new file mode 100644
index 0000000..fbb6828
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.idea/misc.xml
@@ -0,0 +1,46 @@
+<?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" />
+ <option name="myNullables">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+ </list>
+ </value>
+ </option>
+ <option name="myNotNulls">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+ </list>
+ </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">
+ <output url="file://$PROJECT_DIR$/build/classes" />
+ </component>
+ <component name="ProjectType">
+ <option name="id" value="Android" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.idea/modules.xml b/simpleperf/demo/SimpleperfExamplePureJava/.idea/modules.xml
new file mode 100644
index 0000000..5b6be61
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.idea/modules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/SimpleperfExamplePureJava.iml" filepath="$PROJECT_DIR$/SimpleperfExamplePureJava.iml" />
+ <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
+ </modules>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/.idea/runConfigurations.xml b/simpleperf/demo/SimpleperfExamplePureJava/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="RunConfigurationProducerService">
+ <option name="ignoredProducers">
+ <set>
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+ </set>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/.gitignore b/simpleperf/demo/SimpleperfExamplePureJava/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/build.gradle b/simpleperf/demo/SimpleperfExamplePureJava/app/build.gradle
new file mode 100644
index 0000000..02a9b3c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/build.gradle
@@ -0,0 +1,32 @@
+apply plugin: 'com.android.application'
+
+apply from: 'profiling.gradle'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+ defaultConfig {
+ applicationId "com.example.simpleperf.simpleperfexamplepurejava"
+ minSdkVersion 15
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ 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'
+ })
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling.gradle b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling.gradle
new file mode 100644
index 0000000..661d549
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling.gradle
@@ -0,0 +1,60 @@
+
+// Set when building only part of the abis in the apk.
+def abiFiltersForWrapScript = []
+
+android {
+ buildTypes {
+ profiling {
+ initWith debug
+ externalNativeBuild {
+ cmake {
+ // cmake Debug build type uses -O0, which makes the code slow.
+ arguments "-DCMAKE_BUILD_TYPE=Release"
+ }
+ }
+ packagingOptions {
+ // Contain debug info in the libraries.
+ doNotStrip "**.so"
+
+ // Exclude wrap.sh for architectures not built.
+ if (abiFiltersForWrapScript) {
+ def exclude_abis = ["armeabi", "armeabi-v7a", "arm64-v8a",
+ "x86", "x86_64", "mips", "mips64"]
+ .findAll{ !(it in abiFiltersForWrapScript) }
+ .collect{ "**/" + it + "/wrap.sh" }
+ excludes += exclude_abis
+ }
+ }
+
+ // Add lib/xxx/wrap.sh in the apk. This is to enable java profiling on Android O
+ // devices.
+ sourceSets {
+ main {
+ resources {
+ srcDir {
+ "profiling_apk_add_dir"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+def writeWrapScriptToFullyCompileJavaApp(wrapFile) {
+ wrapFile.withWriter { writer ->
+ writer.write('#!/system/bin/sh\n')
+ writer.write('\$@\n')
+ }
+}
+
+task createProfilingApkAddDir {
+ for (String abi : ["armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"]) {
+ def dir = new File("app/profiling_apk_add_dir/lib/" + abi)
+ dir.mkdirs()
+ def wrapFile = new File(dir, "wrap.sh")
+ writeWrapScriptToFullyCompileJavaApp(wrapFile)
+ println "write file " + wrapFile.path
+ }
+}
+
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips64/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/mips64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86_64/wrap.sh b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/proguard-rules.pro b/simpleperf/demo/SimpleperfExamplePureJava/app/proguard-rules.pro
new file mode 100644
index 0000000..b9d149a
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/yabinc/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# 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
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java b/simpleperf/demo/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..e4c2791
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.simpleperf.simpleperfexamplepurejava;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation 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() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.example.simpleperf.simpleperfexamplepurejava", appContext.getPackageName());
+ }
+}
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/AndroidManifest.xml b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9a07958
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.simpleperf.simpleperfexamplepurejava">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java
new file mode 100644
index 0000000..18ff524
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/java/com/example/simpleperf/simpleperfexamplepurejava/MainActivity.java
@@ -0,0 +1,33 @@
+package com.example.simpleperf.simpleperfexamplepurejava;
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ createBusyThread();
+ }
+
+ void createBusyThread() {
+ new Thread(new Runnable() {
+
+ volatile int i = 0;
+
+ @Override
+ public void run() {
+ while (true) {
+ i = callFunction(i);
+ }
+ }
+
+ private int callFunction(int a) {
+ return a+1;
+ }
+ }).start();
+ }
+}
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/layout/activity_main.xml b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..1aa4458
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,18 @@
+<?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.MainActivity">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello World!"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/colors.xml b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/strings.xml b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9cb14df
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">SimpleperfExamplePureJava</string>
+</resources>
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/styles.xml b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java b/simpleperf/demo/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java
new file mode 100644
index 0000000..0f3813d
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/app/src/test/java/com/example/simpleperf/simpleperfexamplepurejava/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.simpleperf.simpleperfexamplepurejava;
+
+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() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/build.gradle b/simpleperf/demo/SimpleperfExamplePureJava/build.gradle
new file mode 100644
index 0000000..b78a0b8
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/gradle.properties b/simpleperf/demo/SimpleperfExamplePureJava/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/gradle.properties
@@ -0,0 +1,17 @@
+# 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=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.jar b/simpleperf/demo/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.properties b/simpleperf/demo/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..287d38f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 26 19:57:50 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
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/gradlew b/simpleperf/demo/SimpleperfExamplePureJava/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# 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
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# 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
+
+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" ] ; 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, switch paths to Windows format before running java
+if $cygwin ; 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=$((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
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/gradlew.bat b/simpleperf/demo/SimpleperfExamplePureJava/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/simpleperf/demo/SimpleperfExamplePureJava/settings.gradle b/simpleperf/demo/SimpleperfExamplePureJava/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExamplePureJava/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.gitignore b/simpleperf/demo/SimpleperfExampleWithNative/.gitignore
new file mode 100644
index 0000000..39fb081
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.idea/compiler.xml b/simpleperf/demo/SimpleperfExampleWithNative/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.idea/compiler.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <resourceExtensions />
+ <wildcardResourcePatterns>
+ <entry name="!?*.java" />
+ <entry name="!?*.form" />
+ <entry name="!?*.class" />
+ <entry name="!?*.groovy" />
+ <entry name="!?*.scala" />
+ <entry name="!?*.flex" />
+ <entry name="!?*.kt" />
+ <entry name="!?*.clj" />
+ <entry name="!?*.aj" />
+ </wildcardResourcePatterns>
+ <annotationProcessing>
+ <profile default="true" name="Default" enabled="false">
+ <processorPath useClasspath="true" />
+ </profile>
+ </annotationProcessing>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.idea/copyright/profiles_settings.xml b/simpleperf/demo/SimpleperfExampleWithNative/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+<component name="CopyrightManager">
+ <settings default="" />
+</component>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.idea/gradle.xml b/simpleperf/demo/SimpleperfExampleWithNative/.idea/gradle.xml
new file mode 100644
index 0000000..7ac24c7
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.idea/gradle.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="GradleSettings">
+ <option name="linkedExternalProjectsSettings">
+ <GradleProjectSettings>
+ <option name="distributionType" value="DEFAULT_WRAPPED" />
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
+ <option name="modules">
+ <set>
+ <option value="$PROJECT_DIR$" />
+ <option value="$PROJECT_DIR$/app" />
+ </set>
+ </option>
+ <option name="resolveModulePerSourceSet" value="false" />
+ </GradleProjectSettings>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.idea/misc.xml b/simpleperf/demo/SimpleperfExampleWithNative/.idea/misc.xml
new file mode 100644
index 0000000..fbb6828
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.idea/misc.xml
@@ -0,0 +1,46 @@
+<?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" />
+ <option name="myNullables">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
+ </list>
+ </value>
+ </option>
+ <option name="myNotNulls">
+ <value>
+ <list size="4">
+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
+ </list>
+ </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">
+ <output url="file://$PROJECT_DIR$/build/classes" />
+ </component>
+ <component name="ProjectType">
+ <option name="id" value="Android" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.idea/modules.xml b/simpleperf/demo/SimpleperfExampleWithNative/.idea/modules.xml
new file mode 100644
index 0000000..4aa0093
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.idea/modules.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/SimpleperfExampleWithNative.iml" filepath="$PROJECT_DIR$/SimpleperfExampleWithNative.iml" />
+ <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
+ </modules>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/.idea/runConfigurations.xml b/simpleperf/demo/SimpleperfExampleWithNative/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="RunConfigurationProducerService">
+ <option name="ignoredProducers">
+ <set>
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+ </set>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/.gitignore b/simpleperf/demo/SimpleperfExampleWithNative/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/CMakeLists.txt b/simpleperf/demo/SimpleperfExampleWithNative/app/CMakeLists.txt
new file mode 100644
index 0000000..f8e6e8b
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/CMakeLists.txt
@@ -0,0 +1,44 @@
+# For more information about using CMake with Android Studio, read the
+# documentation: https://d.android.com/studio/projects/add-native-code.html
+
+# Sets the minimum version of CMake required to build the native library.
+
+cmake_minimum_required(VERSION 3.4.1)
+
+# Creates and names a library, sets it as either STATIC
+# or SHARED, and provides the relative paths to its source code.
+# You can define multiple libraries, and CMake builds them for you.
+# Gradle automatically packages shared libraries with your APK.
+
+add_library( # Sets the name of the library.
+ native-lib
+
+ # Sets the library as a shared library.
+ SHARED
+
+ # Provides a relative path to your source file(s).
+ src/main/cpp/native-lib.cpp )
+
+# Searches for a specified prebuilt library and stores the path as a
+# variable. Because CMake includes system libraries in the search path by
+# default, you only need to specify the name of the public NDK library
+# you want to add. CMake verifies that the library exists before
+# completing its build.
+
+find_library( # Sets the name of the path variable.
+ log-lib
+
+ # Specifies the name of the NDK library that
+ # you want CMake to locate.
+ log )
+
+# Specifies libraries CMake should link to your target library. You
+# can link multiple libraries, such as libraries you define in this
+# build script, prebuilt third-party libraries, or system libraries.
+
+target_link_libraries( # Specifies the target library.
+ native-lib
+
+ # Links the target library to the log library
+ # included in the NDK.
+ ${log-lib} )
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/build.gradle b/simpleperf/demo/SimpleperfExampleWithNative/app/build.gradle
new file mode 100644
index 0000000..efa47c2
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/build.gradle
@@ -0,0 +1,42 @@
+apply plugin: 'com.android.application'
+
+apply from: 'profiling.gradle'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+ defaultConfig {
+ applicationId "com.example.simpleperf.simpleperfexamplewithnative"
+ minSdkVersion 15
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ externalNativeBuild {
+ cmake {
+ cppFlags "-std=c++11"
+ }
+ }
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ externalNativeBuild {
+ cmake {
+ path "CMakeLists.txt"
+ }
+ }
+}
+
+dependencies {
+ 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'
+ })
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'com.android.support.constraint:constraint-layout:1.0.2'
+ testCompile 'junit:junit:4.12'
+}
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling.gradle b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling.gradle
new file mode 100644
index 0000000..661d549
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling.gradle
@@ -0,0 +1,60 @@
+
+// Set when building only part of the abis in the apk.
+def abiFiltersForWrapScript = []
+
+android {
+ buildTypes {
+ profiling {
+ initWith debug
+ externalNativeBuild {
+ cmake {
+ // cmake Debug build type uses -O0, which makes the code slow.
+ arguments "-DCMAKE_BUILD_TYPE=Release"
+ }
+ }
+ packagingOptions {
+ // Contain debug info in the libraries.
+ doNotStrip "**.so"
+
+ // Exclude wrap.sh for architectures not built.
+ if (abiFiltersForWrapScript) {
+ def exclude_abis = ["armeabi", "armeabi-v7a", "arm64-v8a",
+ "x86", "x86_64", "mips", "mips64"]
+ .findAll{ !(it in abiFiltersForWrapScript) }
+ .collect{ "**/" + it + "/wrap.sh" }
+ excludes += exclude_abis
+ }
+ }
+
+ // Add lib/xxx/wrap.sh in the apk. This is to enable java profiling on Android O
+ // devices.
+ sourceSets {
+ main {
+ resources {
+ srcDir {
+ "profiling_apk_add_dir"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+def writeWrapScriptToFullyCompileJavaApp(wrapFile) {
+ wrapFile.withWriter { writer ->
+ writer.write('#!/system/bin/sh\n')
+ writer.write('\$@\n')
+ }
+}
+
+task createProfilingApkAddDir {
+ for (String abi : ["armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"]) {
+ def dir = new File("app/profiling_apk_add_dir/lib/" + abi)
+ dir.mkdirs()
+ def wrapFile = new File(dir, "wrap.sh")
+ writeWrapScriptToFullyCompileJavaApp(wrapFile)
+ println "write file " + wrapFile.path
+ }
+}
+
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/arm64-v8a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi-v7a/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/armeabi/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips64/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/mips64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86_64/wrap.sh b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
new file mode 100644
index 0000000..047ea6f
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/profiling_apk_add_dir/lib/x86_64/wrap.sh
@@ -0,0 +1,2 @@
+#!/system/bin/sh
+$@
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/proguard-rules.pro b/simpleperf/demo/SimpleperfExampleWithNative/app/proguard-rules.pro
new file mode 100644
index 0000000..b9d149a
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/yabinc/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# 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
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java b/simpleperf/demo/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..3b21b44
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/androidTest/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.simpleperf.simpleperfexamplewithnative;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumentation 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() throws Exception {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.example.simpleperf.simpleperfexamplewithnative", appContext.getPackageName());
+ }
+}
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/AndroidManifest.xml b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..94078ff
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.simpleperf.simpleperfexamplewithnative">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp
new file mode 100644
index 0000000..5cd0607
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/cpp/native-lib.cpp
@@ -0,0 +1,62 @@
+#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;
+ }
+}
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java
new file mode 100644
index 0000000..4dbf482
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/java/com/example/simpleperf/simpleperfexamplewithnative/MainActivity.java
@@ -0,0 +1,33 @@
+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();
+}
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/layout/activity_main.xml b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..9b06408
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@
+<?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.MainActivity">
+
+ <TextView
+ android:id="@+id/sample_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello World!"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/colors.xml b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..3ab3e9c
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#3F51B5</color>
+ <color name="colorPrimaryDark">#303F9F</color>
+ <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/strings.xml b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..1ac079d
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">SimpleperfExampleWithNative</string>
+</resources>
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/styles.xml b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java b/simpleperf/demo/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java
new file mode 100644
index 0000000..5bb893b
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/app/src/test/java/com/example/simpleperf/simpleperfexamplewithnative/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.simpleperf.simpleperfexamplewithnative;
+
+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() throws Exception {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/build.gradle b/simpleperf/demo/SimpleperfExampleWithNative/build.gradle
new file mode 100644
index 0000000..b78a0b8
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/gradle.properties b/simpleperf/demo/SimpleperfExampleWithNative/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/gradle.properties
@@ -0,0 +1,17 @@
+# 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=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.jar b/simpleperf/demo/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.properties b/simpleperf/demo/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..4a462f0
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 26 20:39:16 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
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/gradlew b/simpleperf/demo/SimpleperfExampleWithNative/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# 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
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# 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
+
+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" ] ; 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, switch paths to Windows format before running java
+if $cygwin ; 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=$((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
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/gradlew.bat b/simpleperf/demo/SimpleperfExampleWithNative/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/simpleperf/demo/SimpleperfExampleWithNative/settings.gradle b/simpleperf/demo/SimpleperfExampleWithNative/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/simpleperf/demo/SimpleperfExampleWithNative/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 40603fe..4f202bc 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -60,6 +60,8 @@
std::unordered_map<std::string, BuildId> Dso::build_id_map_;
size_t Dso::dso_count_;
uint32_t Dso::g_dump_id_;
+std::unique_ptr<TemporaryFile> Dso::vdso_64bit_;
+std::unique_ptr<TemporaryFile> Dso::vdso_32bit_;
void Dso::SetDemangle(bool demangle) { demangle_ = demangle; }
@@ -119,6 +121,14 @@
build_id_map_ = std::move(map);
}
+void Dso::SetVdsoFile(std::unique_ptr<TemporaryFile> vdso_file, bool is_64bit) {
+ if (is_64bit) {
+ vdso_64bit_ = std::move(vdso_file);
+ } else {
+ vdso_32bit_ = std::move(vdso_file);
+ }
+}
+
BuildId Dso::FindExpectedBuildIdForPath(const std::string& path) {
auto it = build_id_map_.find(path);
if (it != build_id_map_.end()) {
@@ -131,12 +141,12 @@
return FindExpectedBuildIdForPath(path_);
}
-std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type,
- const std::string& dso_path) {
- return std::unique_ptr<Dso>(new Dso(dso_type, dso_path));
+std::unique_ptr<Dso> Dso::CreateDso(DsoType dso_type, const std::string& dso_path,
+ bool force_64bit) {
+ return std::unique_ptr<Dso>(new Dso(dso_type, dso_path, force_64bit));
}
-Dso::Dso(DsoType type, const std::string& path)
+Dso::Dso(DsoType type, const std::string& path, bool force_64bit)
: type_(type),
path_(path),
debug_file_path_(path),
@@ -158,6 +168,12 @@
if (IsRegularFile(file_path)) {
debug_file_path_ = path_in_symfs;
}
+ } else if (path == "[vdso]") {
+ if (force_64bit && vdso_64bit_ != nullptr) {
+ debug_file_path_ = vdso_64bit_->path;
+ } else if (!force_64bit && vdso_32bit_ != nullptr) {
+ debug_file_path_ = vdso_32bit_->path;
+ }
}
size_t pos = path.find_last_of("/\\");
if (pos != std::string::npos) {
@@ -179,6 +195,8 @@
read_kernel_symbols_from_proc_ = false;
build_id_map_.clear();
g_dump_id_ = 0;
+ vdso_64bit_ = nullptr;
+ vdso_32bit_ = nullptr;
}
}
@@ -326,11 +344,15 @@
}
}
-bool CheckReadSymbolResult(ElfStatus result, const std::string& filename) {
+bool Dso::CheckReadSymbolResult(ElfStatus result, const std::string& filename) {
if (result == ElfStatus::NO_ERROR) {
LOG(VERBOSE) << "Read symbols from " << filename << " successfully";
return true;
} else if (result == ElfStatus::NO_SYMBOL_TABLE) {
+ if (path_ == "[vdso]") {
+ // Vdso only contains dynamic symbol table, and we can't change that.
+ return true;
+ }
// Lacking symbol table isn't considered as an error but worth reporting.
LOG(WARNING) << filename << " doesn't contain symbol table";
return true;
diff --git a/simpleperf/dso.h b/simpleperf/dso.h
index b742a9c..f41b140 100644
--- a/simpleperf/dso.h
+++ b/simpleperf/dso.h
@@ -22,7 +22,10 @@
#include <unordered_map>
#include <vector>
+#include <android-base/test_utils.h>
+
#include "build_id.h"
+#include "read_elf.h"
struct Symbol {
uint64_t addr;
@@ -96,9 +99,10 @@
static void SetBuildIds(
const std::vector<std::pair<std::string, BuildId>>& build_ids);
static BuildId FindExpectedBuildIdForPath(const std::string& path);
+ static void SetVdsoFile(std::unique_ptr<TemporaryFile> vdso_file, bool is_64bit);
- static std::unique_ptr<Dso> CreateDso(DsoType dso_type,
- const std::string& dso_path);
+ static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path,
+ bool force_64bit = false);
~Dso();
@@ -148,8 +152,10 @@
static std::unordered_map<std::string, BuildId> build_id_map_;
static size_t dso_count_;
static uint32_t g_dump_id_;
+ static std::unique_ptr<TemporaryFile> vdso_64bit_;
+ static std::unique_ptr<TemporaryFile> vdso_32bit_;
- Dso(DsoType type, const std::string& path);
+ Dso(DsoType type, const std::string& path, bool force_64bit);
void Load();
bool LoadKernel();
bool LoadKernelModule();
@@ -157,6 +163,7 @@
bool LoadEmbeddedElfFile();
void FixupSymbolLength();
BuildId GetExpectedBuildId();
+ bool CheckReadSymbolResult(ElfStatus result, const std::string& filename);
const DsoType type_;
// path of the shared library used by the profiled program
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index ed161c2..d0cb835 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -451,12 +451,18 @@
LOG(ERROR) << "failed to parse " << kptr_restrict_file << ": " << s;
return false;
}
+ // Accessible to everyone?
if (value == 0) {
return true;
}
+ // Accessible to root?
if (value == 1 && IsRoot()) {
return true;
}
+ // Can we make it accessible to us?
+ if (IsRoot() && android::base::WriteStringToFile("1", kptr_restrict_file)) {
+ return true;
+ }
LOG(WARNING) << "Access to kernel symbol addresses is restricted. If "
<< "possible, please do `echo 0 >/proc/sys/kernel/kptr_restrict` "
<< "to fix this.";
@@ -475,3 +481,31 @@
}
return GetBuildArch();
}
+
+void PrepareVdsoFile() {
+ // vdso is an elf file in memory loaded in each process's user space by the kernel. To read
+ // symbols from it and unwind through it, we need to dump it into a file in storage.
+ // It doesn't affect much when failed to prepare vdso file, so there is no need to return values.
+ std::vector<ThreadMmap> thread_mmaps;
+ if (!GetThreadMmapsInProcess(getpid(), &thread_mmaps)) {
+ return;
+ }
+ const ThreadMmap* vdso_map = nullptr;
+ for (const auto& map : thread_mmaps) {
+ if (map.name == "[vdso]") {
+ vdso_map = ↦
+ break;
+ }
+ }
+ if (vdso_map == nullptr) {
+ return;
+ }
+ std::string s(vdso_map->len, '\0');
+ memcpy(&s[0], reinterpret_cast<void*>(static_cast<uintptr_t>(vdso_map->start_addr)),
+ vdso_map->len);
+ std::unique_ptr<TemporaryFile> tmpfile(new TemporaryFile);
+ if (!android::base::WriteStringToFile(s, tmpfile->path)) {
+ return;
+ }
+ Dso::SetVdsoFile(std::move(tmpfile), sizeof(size_t) == sizeof(uint64_t));
+}
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index 11eee2f..2f4d58b 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -89,5 +89,6 @@
#endif
ArchType GetMachineArch();
+void PrepareVdsoFile();
#endif // SIMPLE_PERF_ENVIRONMENT_H_
diff --git a/simpleperf/environment_test.cpp b/simpleperf/environment_test.cpp
index 9b4cbab..4891467 100644
--- a/simpleperf/environment_test.cpp
+++ b/simpleperf/environment_test.cpp
@@ -16,6 +16,9 @@
#include <gtest/gtest.h>
+#include <android-base/file.h>
+
+#include "dso.h"
#include "environment.h"
TEST(environment, GetCpusFromString) {
@@ -24,3 +27,18 @@
ASSERT_EQ(GetCpusFromString("0,2-3"), std::vector<int>({0, 2, 3}));
ASSERT_EQ(GetCpusFromString("1,0-3,3,4"), std::vector<int>({0, 1, 2, 3, 4}));
}
+
+TEST(environment, PrepareVdsoFile) {
+ std::string content;
+ ASSERT_TRUE(android::base::ReadFileToString("/proc/self/maps", &content));
+ if (content.find("[vdso]") == std::string::npos) {
+ // Vdso isn't used, no need to test.
+ return;
+ }
+ PrepareVdsoFile();
+ std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_ELF_FILE, "[vdso]",
+ sizeof(size_t) == sizeof(uint64_t));
+ ASSERT_TRUE(dso != nullptr);
+ const std::vector<Symbol>& symbols = dso->GetSymbols();
+ ASSERT_FALSE(symbols.empty());
+}
diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp
index 18eff2d..c6edb24 100644
--- a/simpleperf/event_fd.cpp
+++ b/simpleperf/event_fd.cpp
@@ -103,7 +103,7 @@
uint64_t EventFd::Id() const {
if (id_ == 0) {
PerfCounter counter;
- if (ReadCounter(&counter)) {
+ if (InnerReadCounter(&counter)) {
id_ = counter.id;
}
}
@@ -119,23 +119,30 @@
return true;
}
-bool EventFd::ReadCounter(PerfCounter* counter) const {
+bool EventFd::InnerReadCounter(PerfCounter* counter) const {
CHECK(counter != nullptr);
- uint64_t pre_counter = counter->value;
if (!android::base::ReadFully(perf_event_fd_, counter, sizeof(*counter))) {
PLOG(ERROR) << "ReadCounter from " << Name() << " failed";
return false;
}
+ return true;
+}
+
+bool EventFd::ReadCounter(PerfCounter* counter) {
+ if (!InnerReadCounter(counter)) {
+ return false;
+ }
// Trace is always available to systrace if enabled
if (tid_ > 0) {
ATRACE_INT64(android::base::StringPrintf(
"%s_tid%d_cpu%d", event_name_.c_str(), tid_,
- cpu_).c_str(), counter->value - pre_counter);
+ cpu_).c_str(), counter->value - last_counter_value_);
} else {
ATRACE_INT64(android::base::StringPrintf(
"%s_cpu%d", event_name_.c_str(),
- cpu_).c_str(), counter->value - pre_counter);
+ cpu_).c_str(), counter->value - last_counter_value_);
}
+ last_counter_value_ = counter->value;
return true;
}
diff --git a/simpleperf/event_fd.h b/simpleperf/event_fd.h
index f1ddb55..ab47cc5 100644
--- a/simpleperf/event_fd.h
+++ b/simpleperf/event_fd.h
@@ -60,7 +60,7 @@
// this file.
bool EnableEvent();
- bool ReadCounter(PerfCounter* counter) const;
+ bool ReadCounter(PerfCounter* counter);
// Create mapped buffer used to receive records sent by the kernel.
// mmap_pages should be power of 2.
@@ -96,8 +96,10 @@
mmap_metadata_page_(nullptr),
mmap_data_buffer_(nullptr),
mmap_data_buffer_size_(0),
- ioevent_ref_(nullptr) {}
+ ioevent_ref_(nullptr),
+ last_counter_value_(0) {}
+ bool InnerReadCounter(PerfCounter* counter) const;
// Discard how much data we have read, so the kernel can reuse this part of
// mapped area to store new data.
void DiscardMmapData(size_t discard_size);
@@ -123,6 +125,9 @@
IOEventRef ioevent_ref_;
+ // Used by atrace to generate value difference between two ReadCounter() calls.
+ uint64_t last_counter_value_;
+
DISALLOW_COPY_AND_ASSIGN(EventFd);
};
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index b966273..86f57b9 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -450,7 +450,7 @@
return true;
}
-static bool ReadCounter(const EventFd* event_fd, CounterInfo* counter) {
+static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
if (!event_fd->ReadCounter(&counter->counter)) {
return false;
}
diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp
index bfa6aac..a69067d 100644
--- a/simpleperf/event_type.cpp
+++ b/simpleperf/event_type.cpp
@@ -23,11 +23,13 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include "event_attr.h"
#include "utils.h"
-#define EVENT_TYPE_TABLE_ENTRY(name, type, config) {name, type, config},
+#define EVENT_TYPE_TABLE_ENTRY(name, type, config, description, limited_arch) \
+ {name, type, config, description, limited_arch},
static const std::vector<EventType> static_event_type_array = {
#include "event_type_table.h"
@@ -54,7 +56,7 @@
LOG(DEBUG) << "unexpected id '" << id_content << "' in " << id_path;
continue;
}
- result.push_back(EventType(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id));
+ result.push_back(EventType(system_name + ":" + event_name, PERF_TYPE_TRACEPOINT, id, "", ""));
}
}
std::sort(result.begin(), result.end(),
@@ -77,7 +79,7 @@
const EventType* FindEventTypeByName(const std::string& name) {
const EventType* result = nullptr;
for (auto& event_type : GetAllEventTypes()) {
- if (event_type.name == name) {
+ if (android::base::EqualsIgnoreCase(event_type.name, name)) {
result = &event_type;
break;
}
diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h
index a1e401f..a804b08 100644
--- a/simpleperf/event_type.h
+++ b/simpleperf/event_type.h
@@ -36,8 +36,10 @@
// the event type is supported by the kernel.
struct EventType {
- EventType(const std::string& name, uint32_t type, uint64_t config)
- : name(name), type(type), config(config) {
+ EventType(const std::string& name, uint32_t type, uint64_t config,
+ const std::string& description, const std::string& limited_arch)
+ : name(name), type(type), config(config), description(description),
+ limited_arch(limited_arch) {
}
EventType() : type(0), config(0) {
@@ -46,6 +48,8 @@
std::string name;
uint32_t type;
uint64_t config;
+ std::string description;
+ std::string limited_arch;
};
const std::vector<EventType>& GetAllEventTypes();
diff --git a/simpleperf/event_type_table.h b/simpleperf/event_type_table.h
index 123216c..3ecf2c8 100644
--- a/simpleperf/event_type_table.h
+++ b/simpleperf/event_type_table.h
@@ -1,67 +1,116 @@
// This file is auto-generated by generate-event_table.py.
-{"cpu-cycles", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES},
-{"instructions", PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS},
-{"cache-references", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES},
-{"cache-misses", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES},
-{"branch-instructions", PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS},
-{"branch-misses", PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES},
-{"bus-cycles", PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES},
-{"stalled-cycles-frontend", PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND},
-{"stalled-cycles-backend", PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND},
+EVENT_TYPE_TABLE_ENTRY("cpu-cycles", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, "", "")
+EVENT_TYPE_TABLE_ENTRY("instructions", PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, "", "")
+EVENT_TYPE_TABLE_ENTRY("cache-references", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES, "", "")
+EVENT_TYPE_TABLE_ENTRY("cache-misses", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-instructions", PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-misses", PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES, "", "")
+EVENT_TYPE_TABLE_ENTRY("bus-cycles", PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES, "", "")
+EVENT_TYPE_TABLE_ENTRY("stalled-cycles-frontend", PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, "", "")
+EVENT_TYPE_TABLE_ENTRY("stalled-cycles-backend", PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND, "", "")
-{"cpu-clock", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK},
-{"task-clock", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK},
-{"page-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS},
-{"context-switches", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES},
-{"cpu-migrations", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS},
-{"minor-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN},
-{"major-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ},
-{"alignment-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS},
-{"emulation-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS},
+EVENT_TYPE_TABLE_ENTRY("cpu-clock", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, "", "")
+EVENT_TYPE_TABLE_ENTRY("task-clock", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK, "", "")
+EVENT_TYPE_TABLE_ENTRY("page-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS, "", "")
+EVENT_TYPE_TABLE_ENTRY("context-switches", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES, "", "")
+EVENT_TYPE_TABLE_ENTRY("cpu-migrations", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS, "", "")
+EVENT_TYPE_TABLE_ENTRY("minor-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN, "", "")
+EVENT_TYPE_TABLE_ENTRY("major-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ, "", "")
+EVENT_TYPE_TABLE_ENTRY("alignment-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS, "", "")
+EVENT_TYPE_TABLE_ENTRY("emulation-faults", PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS, "", "")
-{"L1-dcache-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"L1-dcache-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"L1-dcache-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"L1-dcache-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"L1-dcache-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"L1-dcache-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"L1-icache-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"L1-icache-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"L1-icache-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"L1-icache-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"L1-icache-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"L1-icache-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"LLC-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"LLC-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"LLC-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"LLC-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"LLC-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"LLC-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"dTLB-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"dTLB-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"dTLB-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"dTLB-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"dTLB-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"dTLB-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"iTLB-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"iTLB-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"iTLB-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"iTLB-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"iTLB-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"iTLB-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"branch-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"branch-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"branch-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"branch-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"branch-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"branch-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"node-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"node-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"node-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"node-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
-{"node-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16))},
-{"node-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16))},
+EVENT_TYPE_TABLE_ENTRY("L1-dcache-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-dcache-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-dcache-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-dcache-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-dcache-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-dcache-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1D) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-icache-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-icache-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-icache-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-icache-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-icache-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("L1-icache-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_L1I) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("LLC-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("LLC-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("LLC-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("LLC-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("LLC-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("LLC-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_LL) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("dTLB-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("dTLB-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("dTLB-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("dTLB-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("dTLB-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("dTLB-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_DTLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("iTLB-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("iTLB-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("iTLB-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("iTLB-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("iTLB-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("iTLB-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_ITLB) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("branch-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_BPU) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("node-loads", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("node-load-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_READ << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("node-stores", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("node-store-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_WRITE << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("node-prefetches", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)), "", "")
+EVENT_TYPE_TABLE_ENTRY("node-prefetch-misses", PERF_TYPE_HW_CACHE, ((PERF_COUNT_HW_CACHE_NODE) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)), "", "")
-{"inplace-sampler", SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS, SIMPLEPERF_CONFIG_INPLACE_SAMPLER},
+EVENT_TYPE_TABLE_ENTRY("inplace-sampler", SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS, SIMPLEPERF_CONFIG_INPLACE_SAMPLER, "", "")
+
+EVENT_TYPE_TABLE_ENTRY("raw-sw-incr", PERF_TYPE_RAW, 0x0, "software increment", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-icache-refill", PERF_TYPE_RAW, 0x1, "level 1 instruction cache refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-itlb-refill", PERF_TYPE_RAW, 0x2, "level 1 instruction TLB refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-dcache-refill", PERF_TYPE_RAW, 0x3, "level 1 data cache refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-dcache", PERF_TYPE_RAW, 0x4, "level 1 data cache access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-dtlb-refill", PERF_TYPE_RAW, 0x5, "level 1 data TLB refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-load-retired", PERF_TYPE_RAW, 0x6, "load (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-store-retired", PERF_TYPE_RAW, 0x7, "store (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-instruction-retired", PERF_TYPE_RAW, 0x8, "instructions (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-exception-taken", PERF_TYPE_RAW, 0x9, "exception taken", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-exception-return", PERF_TYPE_RAW, 0xa, "exception return (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-cid-write-retired", PERF_TYPE_RAW, 0xb, "write to CONTEXIDR (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-pc-write-retired", PERF_TYPE_RAW, 0xc, "software change of the PC (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-br-immed-retired", PERF_TYPE_RAW, 0xd, "immediate branch (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-br-return-retired", PERF_TYPE_RAW, 0xe, "procedure return (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-unaligned-ldst-retired", PERF_TYPE_RAW, 0xf, "unaligned load or store (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-br-mis-pred", PERF_TYPE_RAW, 0x10, "mispredicted or not predicted branch speculatively executed", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-cpu-cycles", PERF_TYPE_RAW, 0x11, "cpu cycles", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-br-pred", PERF_TYPE_RAW, 0x12, "predictable branch speculatively executed", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-mem-access", PERF_TYPE_RAW, 0x13, "data memory access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-icache", PERF_TYPE_RAW, 0x14, "level 1 instruction cache access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-dcache-wb", PERF_TYPE_RAW, 0x15, "level 1 data cache write-back", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-dcache", PERF_TYPE_RAW, 0x16, "level 2 data cache access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-dcache-refill", PERF_TYPE_RAW, 0x17, "level 2 data cache refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-dcache-wb", PERF_TYPE_RAW, 0x18, "level 2 data cache write-back", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-bus-access", PERF_TYPE_RAW, 0x19, "bus access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-memory-error", PERF_TYPE_RAW, 0x1a, "local memory error", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-inst-spec", PERF_TYPE_RAW, 0x1b, "operation speculatively executed", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-ttbr-write-retired", PERF_TYPE_RAW, 0x1c, "write to TTBR (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-bus-cycles", PERF_TYPE_RAW, 0x1d, "bus cycle", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-dcache-allocate", PERF_TYPE_RAW, 0x1f, "level 1 data cache allocation without refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-dcache-allocate", PERF_TYPE_RAW, 0x20, "level 2 data cache allocation without refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-br-retired", PERF_TYPE_RAW, 0x21, "branch (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-br-mis-pred-retired", PERF_TYPE_RAW, 0x22, "mispredicted branch (instruction architecturally executed)", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-stall-frontend", PERF_TYPE_RAW, 0x23, "no operation issued due to the frontend", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-stall-backend", PERF_TYPE_RAW, 0x24, "no operation issued due to the backend", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-dtlb", PERF_TYPE_RAW, 0x25, "level 1 data or unified TLB access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l1-itlb", PERF_TYPE_RAW, 0x26, "level 1 instruction TLB access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-icache", PERF_TYPE_RAW, 0x27, "level 2 instruction cache access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-icache-refill", PERF_TYPE_RAW, 0x28, "level 2 instruction cache refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l3-dcache-allocate", PERF_TYPE_RAW, 0x29, "level 3 data or unified cache allocation without refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l3-dcache-refill", PERF_TYPE_RAW, 0x2a, "level 3 data or unified cache refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l3-dcache", PERF_TYPE_RAW, 0x2b, "level 3 data or unified cache access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l3-dcache-wb", PERF_TYPE_RAW, 0x2c, "level 3 data or unified cache write-back", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-dtlb-refill", PERF_TYPE_RAW, 0x2d, "level 2 data or unified TLB refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-itlb-refill", PERF_TYPE_RAW, 0x2e, "level 2 instruction TLB refill", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-dtlb", PERF_TYPE_RAW, 0x2f, "level 2 data or unified TLB access", "arm")
+EVENT_TYPE_TABLE_ENTRY("raw-l2-itlb", PERF_TYPE_RAW, 0x30, "level 2 instruction TLB access", "arm")
diff --git a/simpleperf/generate_event_type_table.py b/simpleperf/generate_event_type_table.py
index eaffd60..f410c13 100755
--- a/simpleperf/generate_event_type_table.py
+++ b/simpleperf/generate_event_type_table.py
@@ -16,12 +16,18 @@
#
-def gen_event_type_entry_str(event_type_name, event_type, event_config):
+def gen_event_type_entry_str(event_type_name, event_type, event_config, description='',
+ limited_arch=''):
"""
- return string like:
- {"cpu-cycles", PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES},
+ return string as below:
+ EVENT_TYPE_TABLE_ENTRY(event_type_name, event_type, event_config, description, limited_arch)
"""
- return '{"%s", %s, %s},\n' % (event_type_name, event_type, event_config)
+ return 'EVENT_TYPE_TABLE_ENTRY("%s", %s, %s, "%s", "%s")\n' % (
+ event_type_name, event_type, event_config, description, limited_arch)
+
+def gen_arm_event_type_entry_str(event_type_name, event_type, event_config, description):
+ return gen_event_type_entry_str(event_type_name, event_type, event_config, description,
+ "arm")
def gen_hardware_events():
@@ -105,19 +111,83 @@
return generated_str
-
def gen_user_space_events():
generated_str = gen_event_type_entry_str("inplace-sampler",
"SIMPLEPERF_TYPE_USER_SPACE_SAMPLERS",
"SIMPLEPERF_CONFIG_INPLACE_SAMPLER")
return generated_str
+def gen_arm_raw_events():
+ # Refer to "Table D5-7 PMU event numbers" in ARMv8 specification.
+ raw_types = [
+ [0x00, "sw-incr", "software increment"],
+ [0x01, "l1-icache-refill", "level 1 instruction cache refill"],
+ [0x02, "l1-itlb-refill", "level 1 instruction TLB refill"],
+ [0x03, "l1-dcache-refill", "level 1 data cache refill"],
+ [0x04, "l1-dcache", "level 1 data cache access"],
+ [0x05, "l1-dtlb-refill", "level 1 data TLB refill"],
+ [0x06, "load-retired", "load (instruction architecturally executed)"],
+ [0x07, "store-retired", "store (instruction architecturally executed)"],
+ [0x08, "instruction-retired", "instructions (instruction architecturally executed)"],
+ [0x09, "exception-taken", "exception taken"],
+ [0x0a, "exception-return", "exception return (instruction architecturally executed)"],
+ [0x0b, "cid-write-retired", "write to CONTEXIDR (instruction architecturally executed)"],
+ [0x0c, "pc-write-retired", "software change of the PC (instruction architecturally executed)"],
+ [0x0d, "br-immed-retired", "immediate branch (instruction architecturally executed)"],
+ [0x0e, "br-return-retired", "procedure return (instruction architecturally executed)"],
+ [0x0f, "unaligned-ldst-retired", "unaligned load or store (instruction architecturally executed)"],
+ [0x10, "br-mis-pred", "mispredicted or not predicted branch speculatively executed"],
+ [0x11, "cpu-cycles", "cpu cycles"],
+ [0x12, "br-pred", "predictable branch speculatively executed"],
+ [0x13, "mem-access", "data memory access"],
+ [0x14, "l1-icache", "level 1 instruction cache access"],
+ [0x15, "l1-dcache-wb", "level 1 data cache write-back"],
+ [0x16, "l2-dcache", "level 2 data cache access"],
+ [0x17, "l2-dcache-refill", "level 2 data cache refill"],
+ [0x18, "l2-dcache-wb", "level 2 data cache write-back"],
+ [0x19, "bus-access", "bus access"],
+ [0x1a, "memory-error", "local memory error"],
+ [0x1b, "inst-spec", "operation speculatively executed"],
+ [0x1c, "ttbr-write-retired", "write to TTBR (instruction architecturally executed)"],
+ [0x1d, "bus-cycles", "bus cycle"],
+ # [0x1e, "chain", ""], // Not useful in user space.
+ [0x1f, "l1-dcache-allocate", "level 1 data cache allocation without refill"],
+ [0x20, "l2-dcache-allocate", "level 2 data cache allocation without refill"],
+ [0x21, "br-retired", "branch (instruction architecturally executed)"],
+ [0x22, "br-mis-pred-retired", "mispredicted branch (instruction architecturally executed)"],
+ [0x23, "stall-frontend", "no operation issued due to the frontend"],
+ [0x24, "stall-backend", "no operation issued due to the backend"],
+ [0x25, "l1-dtlb", "level 1 data or unified TLB access"],
+ [0x26, "l1-itlb", "level 1 instruction TLB access"],
+ [0x27, "l2-icache", "level 2 instruction cache access"],
+ [0x28, "l2-icache-refill", "level 2 instruction cache refill"],
+ [0x29, "l3-dcache-allocate", "level 3 data or unified cache allocation without refill"],
+ [0x2a, "l3-dcache-refill", "level 3 data or unified cache refill"],
+ [0x2b, "l3-dcache", "level 3 data or unified cache access"],
+ [0x2c, "l3-dcache-wb", "level 3 data or unified cache write-back"],
+ [0x2d, "l2-dtlb-refill", "level 2 data or unified TLB refill"],
+ [0x2e, "l2-itlb-refill", "level 2 instruction TLB refill"],
+ [0x2f, "l2-dtlb", "level 2 data or unified TLB access"],
+ [0x30, "l2-itlb", "level 2 instruction TLB access"],
+ ]
+ generated_str = ""
+ for item in raw_types:
+ event_type = 'PERF_TYPE_RAW'
+ event_type_name = "raw-" + item[1]
+ event_config = '0x%x' % item[0]
+ description = item[2]
+ generated_str += gen_arm_event_type_entry_str(event_type_name, event_type, event_config,
+ description)
+ return generated_str
+
+
def gen_events():
generated_str = "// This file is auto-generated by generate-event_table.py.\n\n"
generated_str += gen_hardware_events() + '\n'
generated_str += gen_software_events() + '\n'
generated_str += gen_hw_cache_events() + '\n'
generated_str += gen_user_space_events() + '\n'
+ generated_str += gen_arm_raw_events() + '\n'
return generated_str
generated_str = gen_events()
diff --git a/simpleperf/get_test_data.h b/simpleperf/get_test_data.h
index 9fb2293..963fe00 100644
--- a/simpleperf/get_test_data.h
+++ b/simpleperf/get_test_data.h
@@ -76,9 +76,9 @@
// perf_with_kernel_symbol.data is generated by `sudo simpleperf record ls -l`.
static const std::string PERF_DATA_WITH_KERNEL_SYMBOL = "perf_with_kernel_symbol.data";
-// perf_with_symbols.data is generated by `sudo simpleperf record --dump-symbols` a process calling func2(int,int).
+// perf_with_symbols.data is generated by `sudo simpleperf record` a process calling func2(int,int).
static const std::string PERF_DATA_WITH_SYMBOLS = "perf_with_symbols.data";
-// perf_with_symbols.data is generated by `sudo simpleperf record --dump-symbols` a process using
+// perf_with_symbols.data is generated by `sudo simpleperf record` a process using
// a binary having non zero min virtual address.
static const std::string PERF_DATA_WITH_SYMBOLS_FOR_NONZERO_MINVADDR_DSO =
"perf_with_symbols_for_nonzero_minvaddr_dso.data";
@@ -105,4 +105,7 @@
// generated by `dd if=/dev/zero of=invalid_perf.data bs=1024 count=1`.
static const std::string INVALID_PERF_DATA = "invalid_perf.data";
+// generated by recording an app.
+static const std::string PERF_DATA_WITH_WRONG_IP_IN_CALLCHAIN = "wrong_ip_callchain_perf.data";
+
#endif // SIMPLE_PERF_GET_TEST_DATA_H_
diff --git a/simpleperf/main.cpp b/simpleperf/main.cpp
index 07b0e4b..ae3e629 100644
--- a/simpleperf/main.cpp
+++ b/simpleperf/main.cpp
@@ -24,8 +24,6 @@
#include "command.h"
#include "utils.h"
-constexpr int SIMPLEPERF_VERSION = 1;
-
int main(int argc, char** argv) {
android::base::InitLogging(argv, android::base::StderrLogger);
std::vector<std::string> args;
@@ -46,8 +44,7 @@
return 1;
}
} else if (strcmp(argv[i], "--version") == 0) {
- LOG(INFO) << "Simpleperf version " << SIMPLEPERF_VERSION << ", revision "
- << SIMPLEPERF_REVISION;
+ LOG(INFO) << "Simpleperf version " << GetSimpleperfVersion();
return 0;
} else {
args.push_back(argv[i]);
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index 51d4f43..32c91fa 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -56,6 +56,7 @@
uint32_t file_type,
uint64_t min_vaddr,
const std::vector<const Symbol*>& symbols);
+ bool WriteMetaInfoFeature(const std::unordered_map<std::string, std::string>& info_map);
bool EndWriteFeatures();
// Normally, Close() should be called after writing. But if something
@@ -148,6 +149,7 @@
bool ReadFileFeature(size_t& read_pos, std::string* file_path,
uint32_t* file_type, uint64_t* min_vaddr,
std::vector<Symbol>* symbols);
+ bool ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map);
void LoadBuildIdAndFileFeatures(ThreadTree& thread_tree);
diff --git a/simpleperf/record_file_format.h b/simpleperf/record_file_format.h
index efa000c..f9ed6f3 100644
--- a/simpleperf/record_file_format.h
+++ b/simpleperf/record_file_format.h
@@ -19,34 +19,47 @@
#include "perf_event.h"
-// The file structure of perf.data:
-// file_header
-// id_section
-// attr section
-// data section
-// feature section
-//
-// The feature section has the following structure:
-// a section descriptor array, each element contains the section information of one add_feature.
-// data section of feature 1
-// data section of feature 2
-// ....
+/*
+The file structure of perf.data:
+ file_header
+ id_section
+ attr section
+ data section
+ feature section
-// file feature section:
-// file_struct files[];
-//
-// struct file_struct {
-// uint32_t size; // size of rest fields in file_struct
-// char file_path[];
-// uint32_t file_type;
-// uint64_t min_vaddr;
-// uint32_t symbol_count;
-// struct {
-// uint64_t start_vaddr;
-// uint32_t len;
-// char symbol_name[];
-// } symbol_table;
-// };
+The feature section has the following structure:
+ a section descriptor array, each element contains the section information of one add_feature.
+ data section of feature 1
+ data section of feature 2
+ ....
+
+file feature section:
+ file_struct files[];
+
+ struct file_struct {
+ uint32_t size; // size of rest fields in file_struct
+ char file_path[];
+ uint32_t file_type;
+ uint64_t min_vaddr;
+ uint32_t symbol_count;
+ struct {
+ uint64_t start_vaddr;
+ uint32_t len;
+ char symbol_name[];
+ } symbol_table;
+ };
+
+meta_info feature section:
+ meta_info infos[];
+
+ struct meta_info {
+ char key[];
+ char value[];
+ };
+ keys in meta_info feature section include:
+ simpleperf_version,
+
+*/
namespace PerfFileFormat {
@@ -74,6 +87,7 @@
FEAT_SIMPLEPERF_START = 128,
FEAT_FILE = FEAT_SIMPLEPERF_START,
+ FEAT_META_INFO,
FEAT_MAX_NUM = 256,
};
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
index 0fdb6dd..67f35be 100644
--- a/simpleperf/record_file_reader.cpp
+++ b/simpleperf/record_file_reader.cpp
@@ -434,6 +434,23 @@
return true;
}
+bool RecordFileReader::ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map) {
+ std::vector<char> buf;
+ if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
+ return false;
+ }
+ const char* p = buf.data();
+ const char* end = buf.data() + buf.size();
+ while (p < end) {
+ const char* key = p;
+ const char* value = key + strlen(key) + 1;
+ CHECK(value < end);
+ (*info_map)[p] = value;
+ p = value + strlen(value) + 1;
+ }
+ return true;
+}
+
void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
std::vector<BuildIdRecord> records = ReadBuildIdFeature();
std::vector<std::pair<std::string, BuildId>> build_ids;
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index 4fe725b..530611e 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -157,3 +157,29 @@
ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids);
}
}
+
+TEST_F(RecordFileTest, write_meta_info_feature_section) {
+ // Write to a record file.
+ std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
+ ASSERT_TRUE(writer != nullptr);
+ AddEventType("cpu-cycles");
+ ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
+
+ // Write meta_info feature section.
+ ASSERT_TRUE(writer->BeginWriteFeatures(1));
+ std::unordered_map<std::string, std::string> info_map;
+ for (int i = 0; i < 100; ++i) {
+ std::string s = std::to_string(i);
+ info_map[s] = s + s;
+ }
+ ASSERT_TRUE(writer->WriteMetaInfoFeature(info_map));
+ ASSERT_TRUE(writer->EndWriteFeatures());
+ ASSERT_TRUE(writer->Close());
+
+ // Read from a record file.
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::unordered_map<std::string, std::string> read_info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&read_info_map));
+ ASSERT_EQ(read_info_map, info_map);
+}
diff --git a/simpleperf/record_file_writer.cpp b/simpleperf/record_file_writer.cpp
index fe62ab5..083a746 100644
--- a/simpleperf/record_file_writer.cpp
+++ b/simpleperf/record_file_writer.cpp
@@ -328,6 +328,28 @@
return WriteFeatureEnd(FEAT_FILE);
}
+bool RecordFileWriter::WriteMetaInfoFeature(
+ const std::unordered_map<std::string, std::string>& info_map) {
+ uint32_t size = 0u;
+ for (auto& pair : info_map) {
+ size += pair.first.size() + 1;
+ size += pair.second.size() + 1;
+ }
+ std::vector<char> buf(size);
+ char* p = buf.data();
+ for (auto& pair : info_map) {
+ MoveToBinaryFormat(pair.first.c_str(), pair.first.size() + 1, p);
+ MoveToBinaryFormat(pair.second.c_str(), pair.second.size() + 1, p);
+ }
+ if (!WriteFeatureBegin(FEAT_META_INFO)) {
+ return false;
+ }
+ if (!Write(buf.data(), buf.size())) {
+ return false;
+ }
+ return WriteFeatureEnd(FEAT_META_INFO);
+}
+
bool RecordFileWriter::WriteFeatureBegin(int feature) {
auto it = features_.find(feature);
if (it == features_.end()) {
diff --git a/simpleperf/report_sample.proto b/simpleperf/report_sample.proto
index c591aba..5e1d860 100644
--- a/simpleperf/report_sample.proto
+++ b/simpleperf/report_sample.proto
@@ -15,6 +15,8 @@
option java_outer_classname = "SimpleperfReport";
message Sample {
+ // Wall clock time for current sample.
+ // By default, it is perf clock used in kernel.
optional uint64 time = 1;
optional int32 thread_id = 2;
@@ -32,6 +34,13 @@
}
repeated CallChainEntry callchain = 3;
+
+ // Count of the events that have happened since last sample (regardless of
+ // whether the last sample is lost). The event type is decided by '-e' option
+ // in simpleperf record command. By default, '-e cpu-cycles' is used, and this
+ // field is the number of cpu cycles.
+ optional uint64 event_count = 4;
+
}
message LostSituation {
diff --git a/simpleperf/sample_tree.h b/simpleperf/sample_tree.h
index ba6bbbe..c7a0ac8 100644
--- a/simpleperf/sample_tree.h
+++ b/simpleperf/sample_tree.h
@@ -17,6 +17,8 @@
#ifndef SIMPLE_PERF_SAMPLE_TREE_H_
#define SIMPLE_PERF_SAMPLE_TREE_H_
+#include <unordered_map>
+
#include "callchain.h"
#include "dwarf_unwind.h"
#include "perf_regs.h"
@@ -157,6 +159,7 @@
if (use_caller_as_callchain_root_) {
std::reverse(callchain.begin(), callchain.end());
}
+ EntryT* parent = nullptr;
while (callchain.size() >= 2) {
EntryT* sample = callchain[0];
callchain.erase(callchain.begin());
@@ -166,6 +169,8 @@
}
added_set.insert(sample);
InsertCallChainForSample(sample, callchain, acc_info);
+ UpdateCallChainParentInfo(sample, parent);
+ parent = sample;
}
}
}
@@ -253,16 +258,48 @@
});
}
+ void AddCallChainDuplicateInfo() {
+ if (build_callchain_) {
+ for (EntryT* sample : sample_set_) {
+ auto it = callchain_parent_map_.find(sample);
+ if (it != callchain_parent_map_.end() && !it->second.has_multiple_parents) {
+ sample->callchain.duplicated = true;
+ }
+ }
+ }
+ }
+
std::set<EntryT*, SampleComparator<EntryT>> sample_set_;
bool accumulate_callchain_;
private:
+ void UpdateCallChainParentInfo(EntryT* sample, EntryT* parent) {
+ if (parent == nullptr) {
+ return;
+ }
+ auto it = callchain_parent_map_.find(sample);
+ if (it == callchain_parent_map_.end()) {
+ CallChainParentInfo info;
+ info.parent = parent;
+ info.has_multiple_parents = false;
+ callchain_parent_map_[sample] = info;
+ } else if (it->second.parent != parent) {
+ it->second.has_multiple_parents = true;
+ }
+ }
+
const SampleComparator<EntryT> sample_comparator_;
// If a CallChainSample is filtered out, it is stored in callchain_sample_set_
// and only used in other EntryT's callchain.
std::set<EntryT*, SampleComparator<EntryT>> callchain_sample_set_;
std::vector<std::unique_ptr<EntryT>> sample_storage_;
+ struct CallChainParentInfo {
+ EntryT* parent;
+ bool has_multiple_parents;
+ };
+ std::unordered_map<EntryT*, CallChainParentInfo> callchain_parent_map_;
+
bool use_branch_address_;
bool build_callchain_;
bool use_caller_as_callchain_root_;
diff --git a/simpleperf/scripts/annotate.py b/simpleperf/scripts/annotate.py
index d25a6cd..a77f6a2 100644
--- a/simpleperf/scripts/annotate.py
+++ b/simpleperf/scripts/annotate.py
@@ -65,7 +65,7 @@
dso = self.dso_dict.get(dso_name)
if dso is None:
self.dso_dict[dso_name] = dso = dict()
- if not dso.has_key(addr):
+ if addr not in dso:
dso[addr] = None
@@ -95,7 +95,8 @@
addr_str = '\n'.join(addr_str)
subproc = subprocess.Popen([self.addr2line_path, '-e', dso_path, '-aifC'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- (stdoutdata, _) = subproc.communicate(addr_str)
+ (stdoutdata, _) = subproc.communicate(str_to_bytes(addr_str))
+ stdoutdata = bytes_to_str(stdoutdata)
stdoutdata = stdoutdata.strip().split('\n')
if len(stdoutdata) < len(addrs):
log_fatal("addr2line didn't output enough lines")
@@ -106,13 +107,16 @@
out_pos += 1
assert addr_line[:2] == "0x"
assert out_pos < len(stdoutdata)
- assert addrs[addr_pos] == int(addr_line, 16)
source_lines = []
while out_pos < len(stdoutdata) and stdoutdata[out_pos][:2] != "0x":
function = stdoutdata[out_pos]
out_pos += 1
assert out_pos < len(stdoutdata)
- file, line = stdoutdata[out_pos].split(':')
+ # Handle lines like "C:\Users\...\file:32".
+ items = stdoutdata[out_pos].rsplit(':', 1)
+ if len(items) != 2:
+ continue
+ (file, line) = items
line = line.split()[0] # Remove comments after line number
out_pos += 1
if file.find('?') != -1:
@@ -124,8 +128,8 @@
else:
line = int(line)
source_lines.append(SourceLine(file, function, line))
- dso[addrs[addr_pos]] = source_lines
- addr_pos += 1
+ dso[addrs[addr_pos]] = source_lines
+ addr_pos += 1
assert addr_pos == len(addrs)
@@ -267,7 +271,7 @@
'annotate_dest_dir', 'comm_filters', 'pid_filters',
'tid_filters', 'dso_filters', 'addr2line_path']
for name in config_names:
- if not config.has_key(name):
+ if name not in config:
log_fatal('config [%s] is missing' % name)
symfs_dir = config['symfs_dir']
if symfs_dir and not os.path.isdir(symfs_dir):
@@ -432,7 +436,7 @@
def _add_dso_period(self, dso_name, period, used_dso_dict):
- if not used_dso_dict.has_key(dso_name):
+ if dso_name not in used_dso_dict:
used_dso_dict[dso_name] = True
dso_period = self.dso_periods.get(dso_name)
if dso_period is None:
@@ -441,7 +445,7 @@
def _add_file_period(self, source, period, used_file_dict):
- if not used_file_dict.has_key(source.file_key):
+ if source.file_key not in used_file_dict:
used_file_dict[source.file_key] = True
file_period = self.file_periods.get(source.file)
if file_period is None:
@@ -450,14 +454,14 @@
def _add_line_period(self, source, period, used_line_dict):
- if not used_line_dict.has_key(source.line_key):
+ if source.line_key not in used_line_dict:
used_line_dict[source.line_key] = True
file_period = self.file_periods[source.file]
file_period.add_line_period(source.line, period)
def _add_function_period(self, source, period, used_function_dict):
- if not used_function_dict.has_key(source.function_key):
+ if source.function_key not in used_function_dict:
used_function_dict[source.function_key] = True
file_period = self.file_periods[source.file]
file_period.add_function_period(source.function, source.line, period)
@@ -468,14 +472,14 @@
with open(summary, 'w') as f:
f.write('total period: %d\n\n' % self.period)
dso_periods = sorted(self.dso_periods.values(),
- cmp=lambda x, y: cmp(y.period.acc_period, x.period.acc_period))
+ key=lambda x: x.period.acc_period, reverse=True)
for dso_period in dso_periods:
f.write('dso %s: %s\n' % (dso_period.dso_name,
self._get_percentage_str(dso_period.period)))
f.write('\n')
file_periods = sorted(self.file_periods.values(),
- cmp=lambda x, y: cmp(y.period.acc_period, x.period.acc_period))
+ key=lambda x: x.period.acc_period, reverse=True)
for file_period in file_periods:
f.write('file %s: %s\n' % (file_period.file,
self._get_percentage_str(file_period.period)))
@@ -486,8 +490,7 @@
for func_name in file_period.function_dict.keys():
func_start_line, period = file_period.function_dict[func_name]
values.append((func_name, func_start_line, period))
- values = sorted(values,
- cmp=lambda x, y: cmp(y[2].acc_period, x[2].acc_period))
+ values = sorted(values, key=lambda x: x[2].acc_period, reverse=True)
for value in values:
f.write('\tfunction (%s): line %d, %s\n' % (
value[0], value[1], self._get_percentage_str(value[2])))
@@ -558,6 +561,9 @@
path = key
from_path = path
to_path = os.path.join(dest_dir, path[1:])
+ elif is_windows() and key.find(':\\') != -1 and os.path.isfile(key):
+ from_path = key
+ to_path = os.path.join(dest_dir, key.replace(':\\', '\\'))
else:
path = key[1:] if key.startswith('/') else key
# Change path on device to path on host
@@ -607,7 +613,10 @@
for line in range(1, len(lines) + 1):
annotate = annotates.get(line)
if annotate is None:
- annotate = empty_annotate
+ if not lines[line-1].strip():
+ annotate = ''
+ else:
+ annotate = empty_annotate
else:
annotate = '/* ' + annotate + (
' ' * (max_annotate_cols - len(annotate))) + ' */'
@@ -624,3 +633,4 @@
config = load_config(args.config)
annotator = SourceFileAnnotator(config)
annotator.annotate()
+ log_info('annotate finish successfully, please check result in annotated_files/.')
\ No newline at end of file
diff --git a/simpleperf/scripts/app_profiler.config b/simpleperf/scripts/app_profiler.config
index 4b61edb..63dbd96 100644
--- a/simpleperf/scripts/app_profiler.config
+++ b/simpleperf/scripts/app_profiler.config
@@ -50,7 +50,7 @@
# Profiling record options that will be passed directly to `simpleperf record` command on device.
# As we can't stop profiling by Ctrl-C, we need to set how long to profile using "--duration".
-record_options = "-e cpu-cycles:u -f 4000 -g --dump-symbols --duration 10"
+record_options = "-e cpu-cycles:u -f 4000 -g --duration 10"
# The path to store generated perf.data on host.
diff --git a/simpleperf/scripts/app_profiler.py b/simpleperf/scripts/app_profiler.py
index a47f1aa..05e9534 100644
--- a/simpleperf/scripts/app_profiler.py
+++ b/simpleperf/scripts/app_profiler.py
@@ -49,7 +49,7 @@
'record_options', 'perf_data_path', 'adb_path', 'readelf_path',
'binary_cache_dir']
for name in config_names:
- if not config.has_key(name):
+ if name not in config:
log_fatal('config [%s] is missing' % name)
native_lib_dir = config.get('native_lib_dir')
if native_lib_dir and not os.path.isdir(native_lib_dir):
@@ -177,7 +177,8 @@
def _find_app_process(self):
- result, output = self.adb.run_and_return_output(['shell', 'ps'])
+ ps_args = ['-e'] if self.android_version >= 8 else []
+ result, output = self.adb.run_and_return_output(['shell', 'ps'] + ps_args)
if not result:
return None
output = output.split('\n')
diff --git a/simpleperf/scripts/bin/android/arm/simpleperf b/simpleperf/scripts/bin/android/arm/simpleperf
index 6f0d531..4bb1ef9 100755
--- a/simpleperf/scripts/bin/android/arm/simpleperf
+++ b/simpleperf/scripts/bin/android/arm/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/arm64/simpleperf b/simpleperf/scripts/bin/android/arm64/simpleperf
index ef839be..365a943 100755
--- a/simpleperf/scripts/bin/android/arm64/simpleperf
+++ b/simpleperf/scripts/bin/android/arm64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/x86/simpleperf b/simpleperf/scripts/bin/android/x86/simpleperf
index 7d86dc6..6d77115 100755
--- a/simpleperf/scripts/bin/android/x86/simpleperf
+++ b/simpleperf/scripts/bin/android/x86/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/android/x86_64/simpleperf b/simpleperf/scripts/bin/android/x86_64/simpleperf
index f2909e2..c31dc40 100755
--- a/simpleperf/scripts/bin/android/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/android/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86/libsimpleperf_report.dylib b/simpleperf/scripts/bin/darwin/x86/libsimpleperf_report.dylib
index cbed361..cccfd9c 100755
--- a/simpleperf/scripts/bin/darwin/x86/libsimpleperf_report.dylib
+++ b/simpleperf/scripts/bin/darwin/x86/libsimpleperf_report.dylib
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86/simpleperf b/simpleperf/scripts/bin/darwin/x86/simpleperf
index 0c79c11..a73138b 100755
--- a/simpleperf/scripts/bin/darwin/x86/simpleperf
+++ b/simpleperf/scripts/bin/darwin/x86/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib b/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
index 7a70fa7..a734c87 100755
--- a/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
+++ b/simpleperf/scripts/bin/darwin/x86_64/libsimpleperf_report.dylib
Binary files differ
diff --git a/simpleperf/scripts/bin/darwin/x86_64/simpleperf b/simpleperf/scripts/bin/darwin/x86_64/simpleperf
index ccb6a90..3ca9e1a 100755
--- a/simpleperf/scripts/bin/darwin/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/darwin/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86/libsimpleperf_report.so b/simpleperf/scripts/bin/linux/x86/libsimpleperf_report.so
index d92ce41..d79ed74 100755
--- a/simpleperf/scripts/bin/linux/x86/libsimpleperf_report.so
+++ b/simpleperf/scripts/bin/linux/x86/libsimpleperf_report.so
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86/simpleperf b/simpleperf/scripts/bin/linux/x86/simpleperf
index 58206a4..7459a3e 100755
--- a/simpleperf/scripts/bin/linux/x86/simpleperf
+++ b/simpleperf/scripts/bin/linux/x86/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so b/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
index a6636cf..5f5671b 100755
--- a/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
+++ b/simpleperf/scripts/bin/linux/x86_64/libsimpleperf_report.so
Binary files differ
diff --git a/simpleperf/scripts/bin/linux/x86_64/simpleperf b/simpleperf/scripts/bin/linux/x86_64/simpleperf
index bf387dc..186cf1a 100755
--- a/simpleperf/scripts/bin/linux/x86_64/simpleperf
+++ b/simpleperf/scripts/bin/linux/x86_64/simpleperf
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll b/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll
index a6d09d0..1f985ed 100755
--- a/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll
+++ b/simpleperf/scripts/bin/windows/x86/libsimpleperf_report.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll b/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll
new file mode 100755
index 0000000..3aa88d7
--- /dev/null
+++ b/simpleperf/scripts/bin/windows/x86/libwinpthread-1.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86/simpleperf.exe b/simpleperf/scripts/bin/windows/x86/simpleperf.exe
index c16bf36..46822bd 100755
--- a/simpleperf/scripts/bin/windows/x86/simpleperf.exe
+++ b/simpleperf/scripts/bin/windows/x86/simpleperf.exe
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll b/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
index 817dc51..e774593 100755
--- a/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
+++ b/simpleperf/scripts/bin/windows/x86_64/libsimpleperf_report.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll b/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll
new file mode 100755
index 0000000..b2fd346
--- /dev/null
+++ b/simpleperf/scripts/bin/windows/x86_64/libwinpthread-1.dll
Binary files differ
diff --git a/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
index ee83c21..46822bd 100755
--- a/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
+++ b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
Binary files differ
diff --git a/simpleperf/scripts/binary_cache_builder.py b/simpleperf/scripts/binary_cache_builder.py
index aa0e6e6..950e2fb 100644
--- a/simpleperf/scripts/binary_cache_builder.py
+++ b/simpleperf/scripts/binary_cache_builder.py
@@ -39,7 +39,7 @@
config_names = ['perf_data_path', 'symfs_dirs', 'adb_path',
'readelf_path', 'binary_cache_dir']
for name in config_names:
- if not config.has_key(name):
+ if name not in config:
log_fatal('config for "%s" is missing' % name)
self.perf_data_path = config.get('perf_data_path')
@@ -82,7 +82,7 @@
for symbol in symbols:
dso_name = symbol.dso_name
- if not binaries.has_key(dso_name):
+ if dso_name not in binaries:
binaries[dso_name] = lib.GetBuildIdForPath(dso_name)
self.binaries = binaries
@@ -182,6 +182,7 @@
if not self.readelf_path:
return ""
output = subprocess.check_output([self.readelf_path, '-n', file])
+ output = bytes_to_str(output)
result = re.search(r'Build ID:\s*(\S+)', output)
if result:
build_id = result.group(1)
@@ -197,6 +198,7 @@
if not self.readelf_path:
return False
output = subprocess.check_output([self.readelf_path, '-S', file])
+ output = bytes_to_str(output)
if output.find('.symtab') != -1:
return True
return False
diff --git a/simpleperf/scripts/pprof_proto_generator.py b/simpleperf/scripts/pprof_proto_generator.py
index 5f8d143..fa2fdb1 100644
--- a/simpleperf/scripts/pprof_proto_generator.py
+++ b/simpleperf/scripts/pprof_proto_generator.py
@@ -31,7 +31,6 @@
import profile_pb2
import re
import shutil
-import subprocess
import sys
import time
@@ -257,7 +256,10 @@
self.lib = ReportLib()
if config.get('binary_cache_dir'):
- self.lib.SetSymfs(config['binary_cache_dir'])
+ if not os.path.isdir(config.get('binary_cache_dir')):
+ config['binary_cache_dir'] = ''
+ else:
+ self.lib.SetSymfs(config['binary_cache_dir'])
if config.get('record_file'):
self.lib.SetRecordFile(config['record_file'])
if config.get('kallsyms'):
@@ -316,7 +318,8 @@
self.add_sample(sample)
# 2. Generate line info for locations and functions.
- self.gen_source_lines()
+ if self.config.get('binary_cache_dir'):
+ self.gen_source_lines()
# 3. Produce samples/locations/functions in profile
for sample in self.sample_list:
@@ -379,11 +382,14 @@
def get_location_id(self, ip, symbol):
mapping_id = self.get_mapping_id(symbol.mapping[0], symbol.dso_name)
location = Location(mapping_id, ip, symbol.vaddr_in_file)
- # Default line info only contains the function name
- line = Line()
- line.function_id = self.get_function_id(symbol.symbol_name, symbol.dso_name,
- symbol.symbol_addr)
- location.lines.append(line)
+ function_id = self.get_function_id(symbol.symbol_name, symbol.dso_name,
+ symbol.symbol_addr)
+ if function_id:
+ # Add Line only when it has a valid function id, see http://b/36988814.
+ # Default line info only contains the function name
+ line = Line()
+ line.function_id = function_id
+ location.lines.append(line)
exist_location = self.location_map.get(location.key)
if exist_location:
@@ -462,10 +468,13 @@
source_id = 0
for source in sources:
if source.file and source.function and source.line:
+ function_id = self.get_function_id(source.function, dso_name, 0)
+ if function_id == 0:
+ continue
if source_id == 0:
# Clear default line info
location.lines = []
- location.lines.append(self.add_line(source, dso_name))
+ location.lines.append(self.add_line(source, dso_name, function_id))
source_id += 1
for function in self.function_list:
@@ -478,9 +487,8 @@
if source.line:
function.start_line = source.line
- def add_line(self, source, dso_name):
+ def add_line(self, source, dso_name, function_id):
line = Line()
- function_id = self.get_function_id(source.function, dso_name, 0)
function = self.get_function(function_id)
function.source_filename_id = self.get_string_id(source.file)
line.function_id = function_id
@@ -506,8 +514,12 @@
profile_mapping.build_id = mapping.build_id_id
profile_mapping.has_filenames = True
profile_mapping.has_functions = True
- profile_mapping.has_line_numbers = True
- profile_mapping.has_inline_frames = True
+ if self.config.get('binary_cache_dir'):
+ profile_mapping.has_line_numbers = True
+ profile_mapping.has_inline_frames = True
+ else:
+ profile_mapping.has_line_numbers = False
+ profile_mapping.has_inline_frames = False
def gen_profile_location(self, location):
profile_location = self.profile.location.add()
diff --git a/simpleperf/scripts/report.py b/simpleperf/scripts/report.py
index 6bba677..908b9e9 100644
--- a/simpleperf/scripts/report.py
+++ b/simpleperf/scripts/report.py
@@ -28,9 +28,11 @@
import re
import subprocess
import sys
-from tkFont import *
-from Tkinter import *
-from ttk import *
+
+from tkinter import *
+from tkinter.font import Font
+from tkinter.ttk import *
+
from utils import *
PAD_X = 3
@@ -111,6 +113,8 @@
vertical_columns = []
last_node = None
+ has_skipped_callgraph = False
+
for line in lines[line_id:]:
if not line:
in_report_context = not in_report_context
@@ -139,6 +143,10 @@
if not line.strip('| \t'):
continue
+ if line.find('skipped in brief callgraph mode') != -1:
+ has_skipped_callgraph = True
+ continue
+
if line.find('-') == -1:
line = line.strip('| \t')
function_name = line
@@ -168,6 +176,9 @@
call_tree_stack[depth] = node
last_node = node
+ if has_skipped_callgraph:
+ log_warning('some callgraphs are skipped in brief callgraph mode')
+
return event_reports
@@ -230,20 +241,19 @@
def display_call_tree(self, tree, parent_id, node, indent):
id = parent_id
- indent_str = ' ' * indent
+ indent_str = ' ' * indent
if node.percentage != 100.0:
- percentage_str = '%.2f%%' % node.percentage
+ percentage_str = '%.2f%% ' % node.percentage
else:
percentage_str = ''
- first_open = True if node.percentage == 100.0 else False
for i in range(len(node.call_stack)):
s = indent_str
- s += '+ ' if node.children else ' '
+ s += '+ ' if node.children and i == len(node.call_stack) - 1 else ' '
s += percentage_str if i == 0 else ' ' * len(percentage_str)
s += node.call_stack[i]
- child_open = first_open if i == 0 else True
+ child_open = False if i == len(node.call_stack) - 1 and indent > 1 else True
id = tree.insert(id, 'end', None, values=[s], open=child_open,
tag='set_font')
@@ -271,7 +281,7 @@
def call_simpleperf_report(args, report_file):
output_fh = open(report_file, 'w')
simpleperf_path = get_host_binary_path('simpleperf')
- args = [simpleperf_path, 'report'] + args
+ args = [simpleperf_path, 'report', '--full-callgraph'] + args
subprocess.check_call(args, stdout=output_fh)
output_fh.close()
diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py
index 27ce08a..c540059 100644
--- a/simpleperf/scripts/simpleperf_report_lib.py
+++ b/simpleperf/scripts/simpleperf_report_lib.py
@@ -37,17 +37,11 @@
def _char_pt(str):
- if sys.version_info < (3, 0):
- return str
- # In python 3, str are wide strings whereas the C api expects 8 bit strings, hence we have to convert
- # For now using utf-8 as the encoding.
- return str.encode('utf-8')
+ return str_to_bytes(str)
def _char_pt_to_str(char_pt):
- if sys.version_info < (3, 0):
- return char_pt
- return char_pt.decode('utf-8')
+ return bytes_to_str(char_pt)
class SampleStruct(ct.Structure):
@@ -167,14 +161,9 @@
self.convert_to_str = (sys.version_info >= (3, 0))
def _load_dependent_lib(self):
- # As the windows dll is built with mingw we need to also find "libwinpthread-1.dll".
- # Load it before libsimpleperf_report.dll if it does exist in the same folder as this script.
+ # As the windows dll is built with mingw we need to load "libwinpthread-1.dll".
if is_windows():
- libwinpthread_path = os.path.join(get_script_dir(), "libwinpthread-1.dll")
- if os.path.exists(libwinpthread_path):
- self._libwinpthread = ct.CDLL(libwinpthread_path)
- else:
- log_fatal('%s is missing' % libwinpthread_path)
+ self._libwinpthread = ct.CDLL(get_host_binary_path('libwinpthread-1.dll'))
def Close(self):
if self._instance is None:
diff --git a/simpleperf/scripts/update.py b/simpleperf/scripts/update.py
index 7065ef0..53ac74f 100644
--- a/simpleperf/scripts/update.py
+++ b/simpleperf/scripts/update.py
@@ -46,7 +46,8 @@
InstallEntry('sdk_arm64-sdk', 'simpleperf_host32', 'linux/x86/simpleperf', True),
InstallEntry('sdk_mac', 'simpleperf_host', 'darwin/x86_64/simpleperf'),
InstallEntry('sdk_mac', 'simpleperf_host32', 'darwin/x86/simpleperf'),
- InstallEntry('sdk', 'simpleperf.exe', 'windows/x86_64/simpleperf.exe', True),
+ # simpleperf.exe on x86_64 windows doesn't work, use simpleperf32.exe instead.
+ InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86_64/simpleperf.exe', True),
InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86/simpleperf.exe', True),
# libsimpleperf_report.so on host
@@ -56,6 +57,12 @@
InstallEntry('sdk_mac', 'libsimpleperf_report32.so', 'darwin/x86/libsimpleperf_report.dylib'),
InstallEntry('sdk', 'libsimpleperf_report.dll', 'windows/x86_64/libsimpleperf_report.dll', True),
InstallEntry('sdk', 'libsimpleperf_report32.dll', 'windows/x86/libsimpleperf_report.dll', True),
+
+ # libwinpthread-1.dll on windows host
+ InstallEntry('local:../../../../prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/bin/libwinpthread-1.dll',
+ 'libwinpthread-1.dll', 'windows/x86_64/libwinpthread-1.dll', False),
+ InstallEntry('local:../../../../prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/lib32/libwinpthread-1.dll',
+ 'libwinpthread-1_32.dll', 'windows/x86/libwinpthread-1.dll', False),
]
@@ -71,13 +78,16 @@
subprocess.check_call(cmd)
-def fetch_artifact(branch, build, target, pattern):
+def fetch_artifact(branch, build, target, name):
"""Fetches and artifact from the build server."""
+ if target.startswith('local:'):
+ shutil.copyfile(target[6:], name)
+ return
logger().info('Fetching %s from %s %s (artifacts matching %s)', build,
- target, branch, pattern)
+ target, branch, name)
fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
cmd = [fetch_artifact_path, '--branch', branch, '--target', target,
- '--bid', build, pattern]
+ '--bid', build, name]
check_call(cmd)
diff --git a/simpleperf/scripts/utils.py b/simpleperf/scripts/utils.py
index ab76c3f..0185374 100644
--- a/simpleperf/scripts/utils.py
+++ b/simpleperf/scripts/utils.py
@@ -31,6 +31,9 @@
def is_windows():
return sys.platform == 'win32' or sys.platform == 'cygwin'
+def is_python3():
+ return sys.version_info >= (3, 0)
+
def log_debug(msg):
logging.debug(msg)
@@ -47,6 +50,17 @@
def log_fatal(msg):
raise Exception(msg)
+def str_to_bytes(str):
+ if not is_python3():
+ return str
+ # In python 3, str are wide strings whereas the C api expects 8 bit strings, hence we have to convert
+ # For now using utf-8 as the encoding.
+ return str.encode('utf-8')
+
+def bytes_to_str(bytes):
+ if not is_python3():
+ return bytes
+ return bytes.decode('utf-8')
def get_target_binary_path(arch, binary_name):
if arch == 'aarch64':
@@ -65,6 +79,8 @@
if is_windows():
if binary_name.endswith('.so'):
binary_name = binary_name[0:-3] + '.dll'
+ elif binary_name.find('.') == -1:
+ binary_name += '.exe'
dir = os.path.join(dir, 'windows')
elif sys.platform == 'darwin': # OSX
if binary_name.endswith('.so'):
@@ -95,6 +111,7 @@
(stdoutdata, _) = subproc.communicate()
result = (subproc.returncode == 0)
if stdoutdata:
+ stdoutdata = bytes_to_str(stdoutdata)
log_debug(stdoutdata)
log_debug('run adb cmd: %s [result %s]' % (adb_args, result))
return (result, stdoutdata)
@@ -141,7 +158,12 @@
if not os.path.exists(config_file):
log_fatal("can't find config_file: %s" % config_file)
config = {}
- execfile(config_file, config)
+ if is_python3():
+ with open(config_file, 'r') as fh:
+ source = fh.read()
+ exec(source, config)
+ else:
+ execfile(config_file, config)
return config
diff --git a/simpleperf/testdata/wrong_ip_callchain_perf.data b/simpleperf/testdata/wrong_ip_callchain_perf.data
new file mode 100644
index 0000000..633f2d1
--- /dev/null
+++ b/simpleperf/testdata/wrong_ip_callchain_perf.data
Binary files differ
diff --git a/simpleperf/thread_tree.cpp b/simpleperf/thread_tree.cpp
index c40607d..a6f86a8 100644
--- a/simpleperf/thread_tree.cpp
+++ b/simpleperf/thread_tree.cpp
@@ -130,7 +130,7 @@
uint64_t len, uint64_t pgoff, uint64_t time,
const std::string& filename) {
ThreadEntry* thread = FindThreadOrNew(pid, tid);
- Dso* dso = FindUserDsoOrNew(filename);
+ Dso* dso = FindUserDsoOrNew(filename, start_addr);
MapEntry* map =
AllocateMap(MapEntry(start_addr, len, pgoff, time, dso, false));
FixOverlappedMap(thread->maps, map);
@@ -138,10 +138,11 @@
CHECK(pair.second);
}
-Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename) {
+Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_addr) {
auto it = user_dso_tree_.find(filename);
if (it == user_dso_tree_.end()) {
- user_dso_tree_[filename] = Dso::CreateDso(DSO_ELF_FILE, filename);
+ bool force_64bit = start_addr > UINT_MAX;
+ user_dso_tree_[filename] = Dso::CreateDso(DSO_ELF_FILE, filename, force_64bit);
it = user_dso_tree_.find(filename);
}
return it->second.get();
@@ -322,6 +323,7 @@
for (auto& p : user_dso_tree_) {
result.push_back(p.second.get());
}
+ result.push_back(unknown_dso_.get());
return result;
}
diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h
index e6536bb..8df6b7b 100644
--- a/simpleperf/thread_tree.h
+++ b/simpleperf/thread_tree.h
@@ -100,6 +100,7 @@
const Symbol* FindSymbol(const MapEntry* map, uint64_t ip,
uint64_t* pvaddr_in_file, Dso** pdso = nullptr);
const Symbol* FindKernelSymbol(uint64_t ip);
+ bool IsUnknownDso(const Dso* dso) const { return dso == unknown_dso_.get(); }
const Symbol* UnknownSymbol() const { return &unknown_symbol_; }
void ShowIpForUnknownSymbol() { show_ip_for_unknown_symbol_ = true; }
@@ -122,7 +123,7 @@
private:
ThreadEntry* CreateThread(int pid, int tid);
Dso* FindKernelDsoOrNew(const std::string& filename);
- Dso* FindUserDsoOrNew(const std::string& filename);
+ Dso* FindUserDsoOrNew(const std::string& filename, uint64_t start_addr = 0);
MapEntry* AllocateMap(const MapEntry& value);
void FixOverlappedMap(MapSet* maps, const MapEntry* map);
diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp
index 62a8b63..1dbe078 100644
--- a/simpleperf/utils.cpp
+++ b/simpleperf/utils.cpp
@@ -31,6 +31,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <7zCrc.h>
#include <Xz.h>
@@ -337,3 +338,9 @@
tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000);
return tv;
}
+
+constexpr int SIMPLEPERF_VERSION = 1;
+
+std::string GetSimpleperfVersion() {
+ return android::base::StringPrintf("%d.%s", SIMPLEPERF_VERSION, SIMPLEPERF_REVISION);
+}
diff --git a/simpleperf/utils.h b/simpleperf/utils.h
index fc21a99..775fd5c 100644
--- a/simpleperf/utils.h
+++ b/simpleperf/utils.h
@@ -169,4 +169,6 @@
timeval SecondToTimeval(double time_in_sec);
+std::string GetSimpleperfVersion();
+
#endif // SIMPLE_PERF_UTILS_H_
diff --git a/tests/binder/benchmarks/Android.mk b/tests/binder/benchmarks/Android.mk
index fa7629c..b43dd32 100644
--- a/tests/binder/benchmarks/Android.mk
+++ b/tests/binder/benchmarks/Android.mk
@@ -34,6 +34,7 @@
frameworks/base/include
LOCAL_MODULE := binderAddInts
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_SRC_FILES := binderAddInts.cpp
include $(BUILD_NATIVE_BENCHMARK)
diff --git a/tests/binder/benchmarks/AndroidTest.xml b/tests/binder/benchmarks/AndroidTest.xml
new file mode 100644
index 0000000..9b04422
--- /dev/null
+++ b/tests/binder/benchmarks/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for binderAddInts">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="binderAddInts->/data/benchmarktest/binderAddInts" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+ <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+ <option name="benchmark-module-name" value="binderAddInts" />
+ </test>
+</configuration>
diff --git a/tests/timetest/Android.mk b/tests/timetest/Android.mk
index b644894..0485cae 100644
--- a/tests/timetest/Android.mk
+++ b/tests/timetest/Android.mk
@@ -26,6 +26,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := time-unit-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests
LOCAL_CFLAGS += $(test_c_flags)
LOCAL_SRC_FILES := $(test_src_files)
diff --git a/tests/timetest/AndroidTest.xml b/tests/timetest/AndroidTest.xml
new file mode 100644
index 0000000..ec328ac
--- /dev/null
+++ b/tests/timetest/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<configuration description="Config for time-unit-tests">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="time-unit-tests->/data/local/tmp/time-unit-tests" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="time-unit-tests" />
+ </test>
+</configuration>
\ No newline at end of file