Merge "ext4_utils: Fix FS creation for filesystems with exactly 32768 blocks."
diff --git a/ext4_utils/Android.bp b/ext4_utils/Android.bp
index ea60212..bdf380e 100644
--- a/ext4_utils/Android.bp
+++ b/ext4_utils/Android.bp
@@ -6,8 +6,6 @@
host_supported: true,
recovery_available: true,
srcs: [
- "make_ext4fs.c",
- "ext4fixup.c",
"ext4_utils.c",
"allocate.c",
"contents.c",
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index a970158..ff36a25 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -7,25 +7,6 @@
#
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := make_ext4fs_main.c
-LOCAL_MODULE := make_ext4fs
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES += libcutils
-LOCAL_STATIC_LIBRARIES += \
- libext4_utils \
- libsparse \
- libz
-LOCAL_LDLIBS_windows += -lws2_32
-LOCAL_SHARED_LIBRARIES_darwin += libselinux
-LOCAL_SHARED_LIBRARIES_linux += libselinux
-LOCAL_CFLAGS_darwin := -DHOST
-LOCAL_CFLAGS_linux := -DHOST
-LOCAL_CFLAGS += -Wall -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
LOCAL_SRC_FILES := blk_alloc_to_base_fs.c
LOCAL_MODULE := blk_alloc_to_base_fs
LOCAL_SHARED_LIBRARIES := libcutils
@@ -41,62 +22,6 @@
ifneq ($(HOST_OS),windows)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := make_ext4fs_main.c
-LOCAL_MODULE := make_ext4fs
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libext2_uuid \
- libext4_utils \
- libselinux \
- libz
-LOCAL_CFLAGS := -DREAL_UUID -Wall -Werror
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := setup_fs.c
-LOCAL_MODULE := setup_fs
-LOCAL_SHARED_LIBRARIES += libcutils
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ext4fixup_main.c
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_MODULE := ext4fixup
-LOCAL_SHARED_LIBRARIES += \
- libext4_utils \
- libsparse \
- libz
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ext4fixup_main.c
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_MODULE := ext4fixup
-LOCAL_STATIC_LIBRARIES += \
- libext4_utils \
- libsparse \
- libz
-include $(BUILD_HOST_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := mkuserimg.sh
-LOCAL_SRC_FILES := mkuserimg.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)
-
-
-include $(CLEAR_VARS)
LOCAL_MODULE := mkuserimg_mke2fs.sh
LOCAL_SRC_FILES := mkuserimg_mke2fs.sh
LOCAL_MODULE_CLASS := EXECUTABLES
diff --git a/ext4_utils/contents.c b/ext4_utils/contents.c
index a2cd3b8..73810f3 100644
--- a/ext4_utils/contents.c
+++ b/ext4_utils/contents.c
@@ -22,7 +22,6 @@
#include "allocate.h"
#include "ext4_utils/ext4_utils.h"
-#include "ext4_utils/make_ext4fs.h"
#include "extent.h"
#include "indirect.h"
diff --git a/ext4_utils/ext4fixup.c b/ext4_utils/ext4fixup.c
deleted file mode 100644
index 508e8bd..0000000
--- a/ext4_utils/ext4fixup.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#include "ext4fixup.h"
-
-#ifndef _LARGEFILE64_SOURCE
-#define _LARGEFILE64_SOURCE 1
-#endif
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <sparse/sparse.h>
-
-#include "allocate.h"
-#include "ext4_utils/ext4_extents.h"
-#include "ext4_utils/ext4_utils.h"
-#include "ext4_utils/make_ext4fs.h"
-
-#ifndef _WIN32
-#include <sys/mman.h>
-#endif
-
-#if defined(__APPLE__) && defined(__MACH__)
-#define lseek64 lseek
-#define off64_t off_t
-#endif
-
-/* The inode block count for a file/directory is in units of 512 byte blocks,
- * _NOT_ the filesystem block size!
- */
-#define INODE_BLOCK_SIZE 512
-
-#define MAX_EXT4_BLOCK_SIZE 4096
-
-/* The two modes the recurse_dir() can be in */
-#define SANITY_CHECK_PASS 1
-#define MARK_INODE_NUMS 2
-#define UPDATE_INODE_NUMS 3
-
-/* Magic numbers to indicate what state the update process is in */
-#define MAGIC_STATE_MARKING_INUMS 0x7000151515565512ll
-#define MAGIC_STATE_UPDATING_INUMS 0x6121131211735123ll
-#define MAGIC_STATE_UPDATING_SB 0x15e1715151558477ll
-
-/* Internal state variables corresponding to the magic numbers */
-#define STATE_UNSET 0
-#define STATE_MARKING_INUMS 1
-#define STATE_UPDATING_INUMS 2
-#define STATE_UPDATING_SB 3
-
-/* Used for automated testing of this programs ability to stop and be restarted wthout error */
-static int bail_phase = 0;
-static int bail_loc = 0;
-static int bail_count = 0;
-static int count = 0;
-
-/* global flags */
-static int verbose = 0;
-static int no_write = 0;
-
-static int new_inodes_per_group = 0;
-
-static int no_write_fixup_state = 0;
-
-static int compute_new_inum(unsigned int old_inum)
-{
- unsigned int group, offset;
-
- group = (old_inum - 1) / info.inodes_per_group;
- offset = (old_inum -1) % info.inodes_per_group;
-
- return (group * new_inodes_per_group) + offset + 1;
-}
-
-static int get_fs_fixup_state(int fd)
-{
- unsigned long long magic;
- int ret, len;
-
- if (no_write) {
- return no_write_fixup_state;
- }
-
- lseek64(fd, 0, SEEK_SET);
- len = read(fd, &magic, sizeof(magic));
- if (len != sizeof(magic)) {
- critical_error("cannot read fixup_state\n");
- }
-
- switch (magic) {
- case MAGIC_STATE_MARKING_INUMS:
- ret = STATE_MARKING_INUMS;
- break;
- case MAGIC_STATE_UPDATING_INUMS:
- ret = STATE_UPDATING_INUMS;
- break;
- case MAGIC_STATE_UPDATING_SB:
- ret = STATE_UPDATING_SB;
- break;
- default:
- ret = STATE_UNSET;
- }
- return ret;
-}
-
-static int set_fs_fixup_state(int fd, int state)
-{
- unsigned long long magic;
- struct ext4_super_block sb;
- int len;
-
- if (no_write) {
- no_write_fixup_state = state;
- return 0;
- }
-
- switch (state) {
- case STATE_MARKING_INUMS:
- magic = MAGIC_STATE_MARKING_INUMS;
- break;
- case STATE_UPDATING_INUMS:
- magic = MAGIC_STATE_UPDATING_INUMS;
- break;
- case STATE_UPDATING_SB:
- magic = MAGIC_STATE_UPDATING_SB;
- break;
- case STATE_UNSET:
- default:
- magic = 0ll;
- break;
- }
-
- lseek64(fd, 0, SEEK_SET);
- len = write(fd, &magic, sizeof(magic));
- if (len != sizeof(magic)) {
- critical_error("cannot write fixup_state\n");
- }
-
- read_sb(fd, &sb);
- if (magic) {
- /* If we are in the process of updating the filesystem, make it unmountable */
- sb.s_desc_size |= 1;
- } else {
- /* we are done, so make the filesystem mountable again */
- sb.s_desc_size &= ~1;
- }
-
- if (!no_write) {
- write_sb(fd, 1024, &sb);
- }
-
- return 0;
-}
-
-static int read_inode(int fd, unsigned int inum, struct ext4_inode *inode)
-{
- unsigned int bg_num, bg_offset;
- off64_t inode_offset;
- int len;
-
- bg_num = (inum-1) / info.inodes_per_group;
- bg_offset = (inum-1) % info.inodes_per_group;
-
- inode_offset = ((unsigned long long)aux_info.bg_desc[bg_num].bg_inode_table * info.block_size) +
- (bg_offset * info.inode_size);
-
- if (lseek64(fd, inode_offset, SEEK_SET) < 0) {
- critical_error_errno("failed to seek to inode %d\n", inum);
- }
-
- len=read(fd, inode, sizeof(*inode));
- if (len != sizeof(*inode)) {
- critical_error_errno("failed to read inode %d\n", inum);
- }
-
- return 0;
-}
-
-static int read_block(int fd, unsigned long long block_num, void *block)
-{
- off64_t off;
- unsigned int len;
-
- off = block_num * info.block_size;
-
- if (lseek64(fd, off, SEEK_SET) , 0) {
- critical_error_errno("failed to seek to block %lld\n", block_num);
- }
-
- len=read(fd, block, info.block_size);
- if (len != info.block_size) {
- critical_error_errno("failed to read block %lld\n", block_num);
- }
-
- return 0;
-}
-
-static int write_block(int fd, unsigned long long block_num, void *block)
-{
- off64_t off;
- unsigned int len;
-
- if (no_write) {
- return 0;
- }
-
- off = block_num * info.block_size;
-
- if (lseek64(fd, off, SEEK_SET) < 0) {
- critical_error_errno("failed to seek to block %lld\n", block_num);
- }
-
- len=write(fd, block, info.block_size);
- if (len != info.block_size) {
- critical_error_errno("failed to write block %lld\n", block_num);
- }
-
- return 0;
-}
-
-static void check_inode_bitmap(int fd, unsigned int bg_num)
-{
- unsigned int inode_bitmap_block_num;
- unsigned char block[MAX_EXT4_BLOCK_SIZE];
- int i, bitmap_updated = 0;
-
- /* Using the bg_num, aux_info.bg_desc[], info.inodes_per_group and
- * new_inodes_per_group, retrieve the inode bitmap, and make sure
- * the bits between the old and new size are clear
- */
- inode_bitmap_block_num = aux_info.bg_desc[bg_num].bg_inode_bitmap;
-
- read_block(fd, inode_bitmap_block_num, block);
-
- for (i = info.inodes_per_group; i < new_inodes_per_group; i++) {
- if (bitmap_get_bit(block, i)) {
- bitmap_clear_bit(block, i);
- bitmap_updated = 1;
- }
- }
-
- if (bitmap_updated) {
- if (verbose) {
- printf("Warning: updated inode bitmap for block group %d\n", bg_num);
- }
- write_block(fd, inode_bitmap_block_num, block);
- }
-
- return;
-}
-
-/* Update the superblock and bgdesc of the specified block group */
-static int update_superblocks_and_bg_desc(int fd, int state)
-{
- off64_t ret;
- struct ext4_super_block sb;
- unsigned int num_block_groups, total_new_inodes;
- unsigned int i;
-
-
- read_sb(fd, &sb);
-
- /* Compute how many more inodes are now available */
- num_block_groups = DIV_ROUND_UP(aux_info.len_blocks, info.blocks_per_group);
- total_new_inodes = num_block_groups * (new_inodes_per_group - sb.s_inodes_per_group);
-
- if (verbose) {
- printf("created %d additional inodes\n", total_new_inodes);
- }
-
- /* Update the free inodes count in each block group descriptor */
- for (i = 0; i < num_block_groups; i++) {
- if (state == STATE_UPDATING_SB) {
- aux_info.bg_desc[i].bg_free_inodes_count += (new_inodes_per_group - sb.s_inodes_per_group);
- }
- check_inode_bitmap(fd, i);
- }
-
- /* First some sanity checks */
- if ((sb.s_inodes_count + total_new_inodes) != (new_inodes_per_group * num_block_groups)) {
- critical_error("Failed sanity check on new inode count\n");
- }
- if (new_inodes_per_group % (info.block_size/info.inode_size)) {
- critical_error("Failed sanity check on new inode per group alignment\n");
- }
-
- /* Update the free inodes count in the superblock */
- sb.s_inodes_count += total_new_inodes;
- sb.s_free_inodes_count += total_new_inodes;
- sb.s_inodes_per_group = new_inodes_per_group;
-
- for (i = 0; i < aux_info.groups; i++) {
- if (ext4_bg_has_super_block(i)) {
- unsigned int sb_offset;
-
- if (i == 0) {
- /* The first superblock is offset by 1K to leave room for boot sectors */
- sb_offset = 1024;
- } else {
- sb_offset = 0;
- }
-
- sb.s_block_group_nr = i;
- /* Don't write out the backup superblocks with the bit set in the s_desc_size
- * which prevents the filesystem from mounting. The bit for the primary
- * superblock will be cleared on the final call to set_fs_fixup_state() */
- if (i != 0) {
- sb.s_desc_size &= ~1;
- }
-
- if (!no_write) {
- write_sb(fd,
- (unsigned long long)i
- * info.blocks_per_group * info.block_size
- + sb_offset,
- &sb);
- }
-
- ret = lseek64(fd, ((unsigned long long)i * info.blocks_per_group * info.block_size) +
- (info.block_size * (aux_info.first_data_block + 1)), SEEK_SET);
- if (ret < 0)
- critical_error_errno("failed to seek to block group descriptors");
-
- if (!no_write) {
- ret = write(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
- if (ret < 0)
- critical_error_errno("failed to write block group descriptors");
- if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
- critical_error("failed to write all of block group descriptors");
- }
- }
- if ((bail_phase == 4) && ((unsigned int)bail_count == i)) {
- critical_error("bailing at phase 4\n");
- }
- }
-
- return 0;
-}
-
-
-static int get_direct_blocks(struct ext4_inode *inode, unsigned long long *block_list,
- unsigned int *count)
-{
- unsigned int i = 0;
- unsigned int ret = 0;
- unsigned int sectors_per_block;
-
- sectors_per_block = info.block_size / INODE_BLOCK_SIZE;
- while ((i < (inode->i_blocks_lo / sectors_per_block)) && (i < EXT4_NDIR_BLOCKS)) {
- block_list[i] = inode->i_block[i];
- i++;
- }
-
- *count += i;
-
- if ((inode->i_blocks_lo / sectors_per_block) > EXT4_NDIR_BLOCKS) {
- ret = 1;
- }
-
- return ret;
-}
-
-static int get_indirect_blocks(int fd, struct ext4_inode *inode,
- unsigned long long *block_list, unsigned int *count)
-{
- unsigned int i;
- unsigned int *indirect_block;
- unsigned int sectors_per_block;
-
- sectors_per_block = info.block_size / INODE_BLOCK_SIZE;
-
- indirect_block = (unsigned int *)malloc(info.block_size);
- if (indirect_block == 0) {
- critical_error("failed to allocate memory for indirect_block\n");
- }
-
- read_block(fd, inode->i_block[EXT4_NDIR_BLOCKS], indirect_block);
-
- for(i = 0; i < (inode->i_blocks_lo / sectors_per_block - EXT4_NDIR_BLOCKS); i++) {
- block_list[EXT4_NDIR_BLOCKS+i] = indirect_block[i];
- }
-
- *count += i;
-
- free(indirect_block);
-
- return 0;
-}
-
-static int get_block_list_indirect(int fd, struct ext4_inode *inode, unsigned long long *block_list)
-{
- unsigned int count=0;
-
- if (get_direct_blocks(inode, block_list, &count)) {
- get_indirect_blocks(fd, inode, block_list, &count);
- }
-
- return count;
-}
-
-static int get_extent_ents(struct ext4_extent_header *ext_hdr, unsigned long long *block_list)
-{
- int i, j;
- struct ext4_extent *extent;
- off64_t fs_block_num;
-
- if (ext_hdr->eh_depth != 0) {
- critical_error("get_extent_ents called with eh_depth != 0\n");
- }
-
- /* The extent entries immediately follow the header, so add 1 to the pointer
- * and cast it to an extent pointer.
- */
- extent = (struct ext4_extent *)(ext_hdr + 1);
-
- for (i = 0; i < ext_hdr->eh_entries; i++) {
- fs_block_num = ((off64_t)extent->ee_start_hi << 32) | extent->ee_start_lo;
- for (j = 0; j < extent->ee_len; j++) {
- block_list[extent->ee_block+j] = fs_block_num+j;
- }
- extent++;
- }
-
- return 0;
-}
-
-static int get_extent_idx(int fd, struct ext4_extent_header *ext_hdr, unsigned long long *block_list)
-{
- int i;
- struct ext4_extent_idx *extent_idx;
- struct ext4_extent_header *tmp_ext_hdr;
- off64_t fs_block_num;
- unsigned char block[MAX_EXT4_BLOCK_SIZE];
-
- /* Sanity check */
- if (ext_hdr->eh_depth == 0) {
- critical_error("get_extent_idx called with eh_depth == 0\n");
- }
-
- /* The extent entries immediately follow the header, so add 1 to the pointer
- * and cast it to an extent pointer.
- */
- extent_idx = (struct ext4_extent_idx *)(ext_hdr + 1);
-
- for (i = 0; i < ext_hdr->eh_entries; i++) {
- fs_block_num = ((off64_t)extent_idx->ei_leaf_hi << 32) | extent_idx->ei_leaf_lo;
- read_block(fd, fs_block_num, block);
- tmp_ext_hdr = (struct ext4_extent_header *)block;
-
- if (tmp_ext_hdr->eh_depth == 0) {
- get_extent_ents(tmp_ext_hdr, block_list); /* leaf node, fill in block_list */
- } else {
- get_extent_idx(fd, tmp_ext_hdr, block_list); /* recurse down the tree */
- }
- }
-
- return 0;
-}
-
-static int get_block_list_extents(int fd, struct ext4_inode *inode, unsigned long long *block_list)
-{
- struct ext4_extent_header *extent_hdr;
-
- extent_hdr = (struct ext4_extent_header *)inode->i_block;
-
- if (extent_hdr->eh_magic != EXT4_EXT_MAGIC) {
- critical_error("extent header has unexpected magic value 0x%4.4x\n",
- extent_hdr->eh_magic);
- }
-
- if (extent_hdr->eh_depth == 0) {
- get_extent_ents((struct ext4_extent_header *)inode->i_block, block_list);
- return 0;
- }
-
- get_extent_idx(fd, (struct ext4_extent_header *)inode->i_block, block_list);
-
- return 0;
-}
-
-static int is_entry_dir(int fd, struct ext4_dir_entry_2 *dirp, int pass)
-{
- struct ext4_inode inode;
- int ret = 0;
-
- if (dirp->file_type == EXT4_FT_DIR) {
- ret = 1;
- } else if (dirp->file_type == EXT4_FT_UNKNOWN) {
- /* Somebody was too lazy to fill in the dir entry,
- * so we have to go fetch it from the inode. Grrr.
- */
- /* if UPDATE_INODE_NUMS pass and the inode high bit is not
- * set return false so we don't recurse down the tree that is
- * already updated. Otherwise, fetch inode, and return answer.
- */
- if ((pass == UPDATE_INODE_NUMS) && !(dirp->inode & 0x80000000)) {
- ret = 0;
- } else {
- read_inode(fd, (dirp->inode & 0x7fffffff), &inode);
- if (S_ISDIR(inode.i_mode)) {
- ret = 1;
- }
- }
- }
-
- return ret;
-}
-
-static int recurse_dir(int fd, struct ext4_inode *inode, char *dirbuf, int dirsize, int mode)
-{
- unsigned long long *block_list;
- unsigned int num_blocks;
- struct ext4_dir_entry_2 *dirp, *prev_dirp = 0;
- char name[256];
- unsigned int i, leftover_space, is_dir;
- struct ext4_inode tmp_inode;
- int tmp_dirsize;
- char *tmp_dirbuf;
-
- switch (mode) {
- case SANITY_CHECK_PASS:
- case MARK_INODE_NUMS:
- case UPDATE_INODE_NUMS:
- break;
- default:
- critical_error("recurse_dir() called witn unknown mode!\n");
- }
-
- if (dirsize % info.block_size) {
- critical_error("dirsize %d not a multiple of block_size %d. This is unexpected!\n",
- dirsize, info.block_size);
- }
-
- num_blocks = dirsize / info.block_size;
-
- block_list = malloc((num_blocks + 1) * sizeof(*block_list));
- if (block_list == 0) {
- critical_error("failed to allocate memory for block_list\n");
- }
-
- if (inode->i_flags & EXT4_EXTENTS_FL) {
- get_block_list_extents(fd, inode, block_list);
- } else {
- /* A directory that requires doubly or triply indirect blocks in huge indeed,
- * and will almost certainly not exist, especially since make_ext4fs only creates
- * directories with extents, and the kernel will too, but check to make sure the
- * directory is not that big and give an error if so. Our limit is 12 direct blocks,
- * plus block_size/4 singly indirect blocks, which for a filesystem with 4K blocks
- * is a directory 1036 blocks long, or 4,243,456 bytes long! Assuming an average
- * filename length of 20 (which I think is generous) thats 20 + 8 bytes overhead
- * per entry, or 151,552 entries in the directory!
- */
- if (num_blocks > (info.block_size / 4 + EXT4_NDIR_BLOCKS)) {
- critical_error("Non-extent based directory is too big!\n");
- }
- get_block_list_indirect(fd, inode, block_list);
- }
-
- /* Read in all the blocks for this directory */
- for (i = 0; i < num_blocks; i++) {
- read_block(fd, block_list[i], dirbuf + (i * info.block_size));
- }
-
- dirp = (struct ext4_dir_entry_2 *)dirbuf;
- while (dirp < (struct ext4_dir_entry_2 *)(dirbuf + dirsize)) {
- count++;
- leftover_space = (char *)(dirbuf + dirsize) - (char *)dirp;
- if (((mode == SANITY_CHECK_PASS) || (mode == UPDATE_INODE_NUMS)) &&
- (leftover_space <= 8) && prev_dirp) {
- /* This is a bug in an older version of make_ext4fs, where it
- * didn't properly include the rest of the block in rec_len.
- * Update rec_len on the previous entry to include the rest of
- * the block and exit the loop.
- */
- if (verbose) {
- printf("fixing up short rec_len for diretory entry for %s\n", name);
- }
- prev_dirp->rec_len += leftover_space;
- break;
- }
-
- if (dirp->inode == 0) {
- /* This is the last entry in the directory */
- break;
- }
-
- strncpy(name, dirp->name, dirp->name_len);
- name[dirp->name_len]='\0';
-
- /* Only recurse on pass UPDATE_INODE_NUMS if the high bit is set.
- * Otherwise, this inode entry has already been updated
- * and we'll do the wrong thing. Also don't recurse on . or ..,
- * and certainly not on non-directories!
- */
- /* Hrm, looks like filesystems made by fastboot on stingray set the file_type
- * flag, but the lost+found directory has the type set to Unknown, which
- * seems to imply I need to read the inode and get it.
- */
- is_dir = is_entry_dir(fd, dirp, mode);
- if ( is_dir && (strcmp(name, ".") && strcmp(name, "..")) &&
- ((mode == SANITY_CHECK_PASS) || (mode == MARK_INODE_NUMS) ||
- ((mode == UPDATE_INODE_NUMS) && (dirp->inode & 0x80000000))) ) {
- /* A directory! Recurse! */
- read_inode(fd, dirp->inode & 0x7fffffff, &tmp_inode);
-
- if (!S_ISDIR(tmp_inode.i_mode)) {
- critical_error("inode %d for name %s does not point to a directory\n",
- dirp->inode & 0x7fffffff, name);
- }
- if (verbose) {
- printf("inode %d %s use extents\n", dirp->inode & 0x7fffffff,
- (tmp_inode.i_flags & EXT4_EXTENTS_FL) ? "does" : "does not");
- }
-
- tmp_dirsize = tmp_inode.i_blocks_lo * INODE_BLOCK_SIZE;
- if (verbose) {
- printf("dir size = %d bytes\n", tmp_dirsize);
- }
-
- tmp_dirbuf = malloc(tmp_dirsize);
- if (tmp_dirbuf == 0) {
- critical_error("failed to allocate memory for tmp_dirbuf\n");
- }
-
- recurse_dir(fd, &tmp_inode, tmp_dirbuf, tmp_dirsize, mode);
-
- free(tmp_dirbuf);
- }
-
- if (verbose) {
- if (is_dir) {
- printf("Directory %s\n", name);
- } else {
- printf("Non-directory %s\n", name);
- }
- }
-
- /* Process entry based on current mode. Either set high bit or change inode number */
- if (mode == MARK_INODE_NUMS) {
- dirp->inode |= 0x80000000;
- } else if (mode == UPDATE_INODE_NUMS) {
- if (dirp->inode & 0x80000000) {
- dirp->inode = compute_new_inum(dirp->inode & 0x7fffffff);
- }
- }
-
- if ((bail_phase == mode) && (bail_loc == 1) && (bail_count == count)) {
- critical_error("Bailing at phase %d, loc 1 and count %d\n", mode, count);
- }
-
- /* Point dirp at the next entry */
- prev_dirp = dirp;
- dirp = (struct ext4_dir_entry_2*)((char *)dirp + dirp->rec_len);
- }
-
- /* Write out all the blocks for this directory */
- for (i = 0; i < num_blocks; i++) {
- write_block(fd, block_list[i], dirbuf + (i * info.block_size));
- if ((bail_phase == mode) && (bail_loc == 2) && (bail_count <= count)) {
- critical_error("Bailing at phase %d, loc 2 and count %d\n", mode, count);
- }
- }
-
- free(block_list);
-
- return 0;
-}
-
-int ext4fixup(char *fsdev)
-{
- return ext4fixup_internal(fsdev, 0, 0, 0, 0, 0);
-}
-
-int ext4fixup_internal(char *fsdev, int v_flag, int n_flag,
- int stop_phase, int stop_loc, int stop_count)
-{
- int fd;
- struct ext4_inode root_inode;
- unsigned int dirsize;
- char *dirbuf;
-
- if (setjmp(setjmp_env))
- return EXIT_FAILURE; /* Handle a call to longjmp() */
-
- verbose = v_flag;
- no_write = n_flag;
-
- bail_phase = stop_phase;
- bail_loc = stop_loc;
- bail_count = stop_count;
-
- fd = open(fsdev, O_RDWR);
-
- if (fd < 0)
- critical_error_errno("failed to open filesystem image");
-
- read_ext(fd, verbose);
-
- if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) {
- critical_error("Filesystem needs recovery first, mount and unmount to do that\n");
- }
-
- /* Clear the low bit which is set while this tool is in progress.
- * If the tool crashes, it will still be set when we restart.
- * The low bit is set to make the filesystem unmountable while
- * it is being fixed up. Also allow 0, which means the old ext2
- * size is in use.
- */
- if (((aux_info.sb->s_desc_size & ~1) != sizeof(struct ext2_group_desc)) &&
- ((aux_info.sb->s_desc_size & ~1) != 0))
- critical_error("error: bg_desc_size != sizeof(struct ext2_group_desc)\n");
-
- if ((info.feat_incompat & EXT4_FEATURE_INCOMPAT_FILETYPE) == 0) {
- critical_error("Expected filesystem to have filetype flag set\n");
- }
-
-#if 0 // If we have to fix the directory rec_len issue, we can't use this check
- /* Check to see if the inodes/group is copacetic */
- if (info.inodes_per_blockgroup % (info.block_size/info.inode_size) == 0) {
- /* This filesystem has either already been updated, or was
- * made correctly.
- */
- if (verbose) {
- printf("%s: filesystem correct, no work to do\n", me);
- }
- exit(0);
- }
-#endif
-
- /* Compute what the new value of inodes_per_blockgroup will be when we're done */
- new_inodes_per_group=EXT4_ALIGN(info.inodes_per_group,(info.block_size/info.inode_size));
-
- read_inode(fd, EXT4_ROOT_INO, &root_inode);
-
- if (!S_ISDIR(root_inode.i_mode)) {
- critical_error("root inode %d does not point to a directory\n", EXT4_ROOT_INO);
- }
- if (verbose) {
- printf("inode %d %s use extents\n", EXT4_ROOT_INO,
- (root_inode.i_flags & EXT4_EXTENTS_FL) ? "does" : "does not");
- }
-
- dirsize = root_inode.i_blocks_lo * INODE_BLOCK_SIZE;
- if (verbose) {
- printf("root dir size = %d bytes\n", dirsize);
- }
-
- dirbuf = malloc(dirsize);
- if (dirbuf == 0) {
- critical_error("failed to allocate memory for dirbuf\n");
- }
-
- /* Perform a sanity check pass first, try to catch any errors that will occur
- * before we actually change anything, so we don't leave a filesystem in a
- * corrupted, unrecoverable state. Set no_write, make it quiet, and do a recurse
- * pass and a update_superblock pass. Set flags back to requested state when done.
- * Only perform sanity check if the state is unset. If the state is _NOT_ unset,
- * then the tool has already been run and interrupted, and it presumably ran and
- * passed sanity checked before it got interrupted. It is _NOT_ safe to run sanity
- * check if state is unset because it assumes inodes are to be computed using the
- * old inodes/group, but some inode numbers may be updated to the new number.
- */
- if (get_fs_fixup_state(fd) == STATE_UNSET) {
- verbose = 0;
- no_write = 1;
- recurse_dir(fd, &root_inode, dirbuf, dirsize, SANITY_CHECK_PASS);
- update_superblocks_and_bg_desc(fd, STATE_UNSET);
- verbose = v_flag;
- no_write = n_flag;
-
- set_fs_fixup_state(fd, STATE_MARKING_INUMS);
- }
-
- if (get_fs_fixup_state(fd) == STATE_MARKING_INUMS) {
- count = 0; /* Reset debugging counter */
- if (!recurse_dir(fd, &root_inode, dirbuf, dirsize, MARK_INODE_NUMS)) {
- set_fs_fixup_state(fd, STATE_UPDATING_INUMS);
- }
- }
-
- if (get_fs_fixup_state(fd) == STATE_UPDATING_INUMS) {
- count = 0; /* Reset debugging counter */
- if (!recurse_dir(fd, &root_inode, dirbuf, dirsize, UPDATE_INODE_NUMS)) {
- set_fs_fixup_state(fd, STATE_UPDATING_SB);
- }
- }
-
- if (get_fs_fixup_state(fd) == STATE_UPDATING_SB) {
- /* set the new inodes/blockgroup number,
- * and sets the state back to 0.
- */
- if (!update_superblocks_and_bg_desc(fd, STATE_UPDATING_SB)) {
- set_fs_fixup_state(fd, STATE_UNSET);
- }
- }
-
- close(fd);
- free(dirbuf);
-
- return 0;
-}
diff --git a/ext4_utils/ext4fixup.h b/ext4_utils/ext4fixup.h
deleted file mode 100644
index 6ea2113..0000000
--- a/ext4_utils/ext4fixup.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-int ext4fixup(char *fsdev);
-int ext4fixup_internal(char *fsdev, int v_flag, int n_flag,
- int stop_phase, int stop_loc, int stop_count);
-
diff --git a/ext4_utils/ext4fixup_main.c b/ext4_utils/ext4fixup_main.c
deleted file mode 100644
index f4428cb..0000000
--- a/ext4_utils/ext4fixup_main.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "ext4fixup.h"
-
-static void usage(char *me)
-{
- fprintf(stderr, "%s: usage: %s [-vn] <image or block device>\n", me, me);
-}
-
-int main(int argc, char **argv)
-{
- int opt;
- int verbose = 0;
- int no_write = 0;
- char *fsdev;
- char *me;
- int stop_phase = 0, stop_loc = 0, stop_count = 0;
-
- me = basename(argv[0]);
-
- while ((opt = getopt(argc, argv, "vnd:")) != -1) {
- switch (opt) {
- case 'v':
- verbose = 1;
- break;
- case 'n':
- no_write = 1;
- break;
- case 'd':
- sscanf(optarg, "%d,%d,%d", &stop_phase, &stop_loc, &stop_count);
- break;
- }
- }
-
- if (optind >= argc) {
- fprintf(stderr, "expected image or block device after options\n");
- usage(me);
- exit(EXIT_FAILURE);
- }
-
- fsdev = argv[optind++];
-
- if (optind < argc) {
- fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
- usage(me);
- exit(EXIT_FAILURE);
- }
-
- return ext4fixup_internal(fsdev, verbose, no_write, stop_phase, stop_loc, stop_count);
-}
diff --git a/ext4_utils/include/ext4_utils/ext4_utils.h b/ext4_utils/include/ext4_utils/ext4_utils.h
index 17a8056..12d2c0c 100644
--- a/ext4_utils/include/ext4_utils/ext4_utils.h
+++ b/ext4_utils/include/ext4_utils/ext4_utils.h
@@ -162,14 +162,6 @@
typedef void (*fs_config_func_t)(const char *path, int dir, const char *target_out_path,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
-struct selabel_handle;
-
-int make_ext4fs_internal(int fd, const char *directory, const char *_target_out_directory,
- const char *mountpoint, fs_config_func_t fs_config_func, int gzip,
- int sparse, int crc, int wipe, int real_uuid,
- struct selabel_handle *sehnd, int verbose, time_t fixed_time,
- FILE* block_list_file, FILE* base_alloc_file_in, FILE* base_alloc_file_out);
-
int read_ext(int fd, int verbose);
#ifdef __cplusplus
diff --git a/ext4_utils/include/ext4_utils/make_ext4fs.h b/ext4_utils/include/ext4_utils/make_ext4fs.h
deleted file mode 100644
index 44e9481..0000000
--- a/ext4_utils/include/ext4_utils/make_ext4fs.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#ifndef _MAKE_EXT4FS_H_
-#define _MAKE_EXT4FS_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct selabel_handle;
-
-int make_ext4fs(const char *filename, long long len,
- const char *mountpoint, struct selabel_handle *sehnd);
-int make_ext4fs_directory_align(const char *filename, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory, unsigned eraseblk,
- unsigned logicalblk);
-int make_ext4fs_directory(const char *filename, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory);
-int make_ext4fs_sparse_fd(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd);
-int make_ext4fs_sparse_fd_directory(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory);
-int make_ext4fs_sparse_fd_align(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- unsigned eraseblk, unsigned logicalblk);
-int make_ext4fs_sparse_fd_directory_align(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory, unsigned eraseblk, unsigned logicalblk);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
deleted file mode 100644
index cadf55c..0000000
--- a/ext4_utils/make_ext4fs.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#include "ext4_utils/make_ext4fs.h"
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#include <assert.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <sparse/sparse.h>
-
-#include "allocate.h"
-#include "contents.h"
-#include "ext4_utils/ext4_utils.h"
-#include "ext4_utils/wipe.h"
-
-#ifdef _WIN32
-
-#include <winsock2.h>
-
-/* These match the Linux definitions of these flags.
- L_xx is defined to avoid conflicting with the win32 versions.
-*/
-#undef S_IRWXU
-#undef S_IRGRP
-#undef S_IWGRP
-#undef S_IXGRP
-#undef S_IRWXG
-#undef S_IROTH
-#undef S_IWOTH
-#undef S_IXOTH
-#undef S_IRWXO
-#undef S_ISUID
-#undef S_ISGID
-#undef S_ISVTX
-
-#define L_S_IRUSR 00400
-#define L_S_IWUSR 00200
-#define L_S_IXUSR 00100
-#define S_IRWXU (L_S_IRUSR | L_S_IWUSR | L_S_IXUSR)
-#define S_IRGRP 00040
-#define S_IWGRP 00020
-#define S_IXGRP 00010
-#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
-#define S_IROTH 00004
-#define S_IWOTH 00002
-#define S_IXOTH 00001
-#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
-#define S_ISUID 0004000
-#define S_ISGID 0002000
-#define S_ISVTX 0001000
-
-#else
-
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-
-#define O_BINARY 0
-
-#endif
-
-#undef MAX_PATH
-#define MAX_PATH 4096
-#define MAX_BLK_MAPPING_STR 1000
-
-const int blk_file_major_ver = 1;
-const int blk_file_minor_ver = 0;
-const char *blk_file_header_fmt = "Base EXT4 version %d.%d";
-
-/* TODO: Not implemented:
- Allocating blocks in the same block group as the file inode
- Hash or binary tree directories
- Special files: sockets, devices, fifos
- */
-
-static int filter_dot(const struct dirent *d)
-{
- return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
-}
-
-static u32 build_default_directory_structure(const char *dir_path,
- struct selabel_handle *sehnd)
-{
- u32 inode;
- u32 root_inode;
- struct dentry dentries = {
- .filename = "lost+found",
- .file_type = EXT4_FT_DIR,
- .mode = S_IRWXU,
- .uid = 0,
- .gid = 0,
- .mtime = 0,
- };
- root_inode = make_directory(0, 1, &dentries, 1);
- inode = make_directory(root_inode, 0, NULL, 0);
- *dentries.inode = inode;
- inode_set_permissions(inode, dentries.mode,
- dentries.uid, dentries.gid, dentries.mtime);
-
-#ifndef _WIN32
- if (sehnd) {
- char *path = NULL;
- char *secontext = NULL;
-
- asprintf(&path, "%slost+found", dir_path);
- if (selabel_lookup(sehnd, &secontext, path, S_IFDIR) < 0) {
- error("cannot lookup security context for %s", path);
- } else {
- inode_set_selinux(inode, secontext);
- freecon(secontext);
- }
- free(path);
- }
-#endif
-
- return root_inode;
-}
-
-#ifndef _WIN32
-/* Read a local directory and create the same tree in the generated filesystem.
- Calls itself recursively with each directory in the given directory.
- full_path is an absolute or relative path, with a trailing slash, to the
- directory on disk that should be copied, or NULL if this is a directory
- that does not exist on disk (e.g. lost+found).
- dir_path is an absolute path, with trailing slash, to the same directory
- if the image were mounted at the specified mount point */
-static u32 build_directory_structure(const char *full_path, const char *dir_path, const char *target_out_path,
- u32 dir_inode, fs_config_func_t fs_config_func,
- struct selabel_handle *sehnd, int verbose, time_t fixed_time)
-{
- int entries = 0;
- struct dentry *dentries;
- struct dirent **namelist = NULL;
- struct stat stat;
- int ret;
- int i, j;
- u32 inode;
- u32 entry_inode;
- u32 dirs = 0;
- bool needs_lost_and_found = false;
-
- if (full_path) {
- entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
- if (entries < 0) {
-#ifdef __GLIBC__
- /* The scandir function implemented in glibc has a bug that makes it
- erroneously fail with ENOMEM under certain circumstances.
- As a workaround we can retry the scandir call with the same arguments.
- GLIBC BZ: https://sourceware.org/bugzilla/show_bug.cgi?id=17804 */
- if (errno == ENOMEM)
- entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
-#endif
- if (entries < 0) {
- error_errno("scandir");
- return EXT4_ALLOCATE_FAILED;
- }
- }
- }
-
- if (dir_inode == 0) {
- /* root directory, check if lost+found already exists */
- for (i = 0; i < entries; i++)
- if (strcmp(namelist[i]->d_name, "lost+found") == 0)
- break;
- if (i == entries)
- needs_lost_and_found = true;
- }
-
- dentries = calloc(entries, sizeof(struct dentry));
- if (dentries == NULL)
- critical_error_errno("malloc");
-
- for (i = j = 0; i < entries; i++, j++) {
- dentries[i].filename = strdup(namelist[j]->d_name);
- if (dentries[i].filename == NULL)
- critical_error_errno("strdup");
-
- asprintf(&dentries[i].path, "%s%s", dir_path, namelist[j]->d_name);
- asprintf(&dentries[i].full_path, "%s%s", full_path, namelist[j]->d_name);
-
- free(namelist[j]);
-
- ret = lstat(dentries[i].full_path, &stat);
- if (ret < 0) {
- error_errno("lstat");
- free(dentries[i].filename);
- i--;
- continue;
- }
-
- dentries[i].size = stat.st_size;
- dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
- if (fixed_time == -1) {
- dentries[i].mtime = stat.st_mtime;
- } else {
- dentries[i].mtime = fixed_time;
- }
- uint64_t capabilities;
- if (fs_config_func != NULL) {
-#ifdef ANDROID
- unsigned int mode = 0;
- unsigned int uid = 0;
- unsigned int gid = 0;
- int dir = S_ISDIR(stat.st_mode);
- fs_config_func(dentries[i].path, dir, target_out_path, &uid, &gid, &mode, &capabilities);
- dentries[i].mode = mode;
- dentries[i].uid = uid;
- dentries[i].gid = gid;
- dentries[i].capabilities = capabilities;
-#else
- error("can't set android permissions - built without android support");
-#endif
- }
-#ifndef _WIN32
- if (sehnd) {
- if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) {
- error("cannot lookup security context for %s", dentries[i].path);
- }
-
- if (dentries[i].secon && verbose)
- printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon);
- }
-#endif
-
- if (S_ISREG(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_REG_FILE;
- } else if (S_ISDIR(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_DIR;
- dirs++;
- } else if (S_ISCHR(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_CHRDEV;
- } else if (S_ISBLK(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_BLKDEV;
- } else if (S_ISFIFO(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_FIFO;
- } else if (S_ISSOCK(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_SOCK;
- } else if (S_ISLNK(stat.st_mode)) {
- dentries[i].file_type = EXT4_FT_SYMLINK;
- dentries[i].link = calloc(info.block_size, 1);
- readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1);
- } else {
- error("unknown file type on %s", dentries[i].path);
- free(dentries[i].filename);
- i--;
- }
- }
- entries -= j - i;
- free(namelist);
-
- if (needs_lost_and_found) {
- /* insert a lost+found directory at the beginning of the dentries */
- struct dentry *tmp = calloc(entries + 1, sizeof(struct dentry));
- memset(tmp, 0, sizeof(struct dentry));
- memcpy(tmp + 1, dentries, entries * sizeof(struct dentry));
- dentries = tmp;
-
- dentries[0].filename = strdup("lost+found");
- asprintf(&dentries[0].path, "%slost+found", dir_path);
- dentries[0].full_path = NULL;
- dentries[0].size = 0;
- dentries[0].mode = S_IRWXU;
- dentries[0].file_type = EXT4_FT_DIR;
- dentries[0].uid = 0;
- dentries[0].gid = 0;
- if (sehnd) {
- if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0)
- error("cannot lookup security context for %s", dentries[0].path);
- }
- entries++;
- dirs++;
- }
-
- inode = make_directory(dir_inode, entries, dentries, dirs);
-
- for (i = 0; i < entries; i++) {
- if (dentries[i].file_type == EXT4_FT_REG_FILE) {
- entry_inode = make_file(dentries[i].full_path, dentries[i].size);
- } else if (dentries[i].file_type == EXT4_FT_DIR) {
- char *subdir_full_path = NULL;
- char *subdir_dir_path;
- if (dentries[i].full_path) {
- ret = asprintf(&subdir_full_path, "%s/", dentries[i].full_path);
- if (ret < 0)
- critical_error_errno("asprintf");
- }
- ret = asprintf(&subdir_dir_path, "%s/", dentries[i].path);
- if (ret < 0)
- critical_error_errno("asprintf");
- entry_inode = build_directory_structure(subdir_full_path, subdir_dir_path, target_out_path,
- inode, fs_config_func, sehnd, verbose, fixed_time);
- free(subdir_full_path);
- free(subdir_dir_path);
- } else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
- entry_inode = make_link(dentries[i].link);
- } else {
- error("unknown file type on %s", dentries[i].path);
- entry_inode = 0;
- }
- *dentries[i].inode = entry_inode;
-
- ret = inode_set_permissions(entry_inode, dentries[i].mode,
- dentries[i].uid, dentries[i].gid,
- dentries[i].mtime);
- if (ret)
- error("failed to set permissions on %s\n", dentries[i].path);
-
- /*
- * It's important to call inode_set_selinux() before
- * inode_set_capabilities(). Extended attributes need to
- * be stored sorted order, and we guarantee this by making
- * the calls in the proper order.
- * Please see xattr_assert_sane() in contents.c
- */
- ret = inode_set_selinux(entry_inode, dentries[i].secon);
- if (ret)
- error("failed to set SELinux context on %s\n", dentries[i].path);
- ret = inode_set_capabilities(entry_inode, dentries[i].capabilities);
- if (ret)
- error("failed to set capability on %s\n", dentries[i].path);
-
- free(dentries[i].path);
- free(dentries[i].full_path);
- free(dentries[i].link);
- free((void *)dentries[i].filename);
- free(dentries[i].secon);
- }
-
- free(dentries);
- return inode;
-}
-#endif
-
-static u32 compute_block_size()
-{
- return 4096;
-}
-
-static u32 compute_journal_blocks()
-{
- u32 journal_blocks = DIV_ROUND_UP(info.len, info.block_size) / 64;
- if (journal_blocks < 1024)
- journal_blocks = 1024;
- if (journal_blocks > 32768)
- journal_blocks = 32768;
- return journal_blocks;
-}
-
-static u32 compute_blocks_per_group()
-{
- return info.block_size * 8;
-}
-
-static u32 compute_inodes()
-{
- return DIV_ROUND_UP(info.len, info.block_size) / 4;
-}
-
-static u32 compute_inodes_per_group()
-{
- u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
- u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
- u32 inodes = DIV_ROUND_UP(info.inodes, block_groups);
- inodes = EXT4_ALIGN(inodes, (info.block_size / info.inode_size));
-
- /* After properly rounding up the number of inodes/group,
- * make sure to update the total inodes field in the info struct.
- */
- info.inodes = inodes * block_groups;
-
- return inodes;
-}
-
-static u32 compute_bg_desc_reserve_blocks()
-{
- u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
- u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
- u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
- info.block_size);
-
- u32 bg_desc_reserve_blocks =
- DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
- info.block_size) - bg_desc_blocks;
-
- if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
- bg_desc_reserve_blocks = info.block_size / sizeof(u32);
-
- return bg_desc_reserve_blocks;
-}
-
-void reset_ext4fs_info() {
- // Reset all the global data structures used by make_ext4fs so it
- // can be called again.
- memset(&info, 0, sizeof(info));
- memset(&aux_info, 0, sizeof(aux_info));
-
- if (ext4_sparse_file) {
- sparse_file_destroy(ext4_sparse_file);
- ext4_sparse_file = NULL;
- }
-}
-
-int make_ext4fs_sparse_fd(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd)
-{
- return make_ext4fs_sparse_fd_align(fd, len, mountpoint, sehnd, 0, 0);
-}
-
-int make_ext4fs_sparse_fd_align(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- unsigned eraseblk, unsigned logicalblk)
-{
- return make_ext4fs_sparse_fd_directory_align(fd, len, mountpoint, sehnd, NULL,
- eraseblk, logicalblk);
-}
-
-int make_ext4fs_sparse_fd_directory(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory)
-{
- return make_ext4fs_sparse_fd_directory_align(fd, len, mountpoint, sehnd, directory, 0, 0);
-}
-
-int make_ext4fs_sparse_fd_directory_align(int fd, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory, unsigned eraseblk, unsigned logicalblk)
-{
- reset_ext4fs_info();
- info.len = len;
- info.flash_erase_block_size = eraseblk;
- info.flash_logical_block_size = logicalblk;
-
- return make_ext4fs_internal(fd, directory, NULL, mountpoint, NULL,
- 0, 1, 0, 0, 0,
- sehnd, 0, -1, NULL, NULL, NULL);
-}
-
-int make_ext4fs(const char *filename, long long len,
- const char *mountpoint, struct selabel_handle *sehnd)
-{
- return make_ext4fs_directory(filename, len, mountpoint, sehnd, NULL);
-}
-
-int make_ext4fs_directory(const char *filename, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory)
-{
- return make_ext4fs_directory_align(filename, len, mountpoint, sehnd, directory, 0, 0);
-}
-
-int make_ext4fs_directory_align(const char *filename, long long len,
- const char *mountpoint, struct selabel_handle *sehnd,
- const char *directory, unsigned eraseblk,
- unsigned logicalblk)
-{
- int fd;
- int status;
-
- reset_ext4fs_info();
- info.len = len;
- info.flash_erase_block_size = eraseblk;
- info.flash_logical_block_size = logicalblk;
-
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (fd < 0) {
- error_errno("open");
- return EXIT_FAILURE;
- }
-
- status = make_ext4fs_internal(fd, directory, NULL, mountpoint, NULL,
- 0, 0, 0, 1, 0,
- sehnd, 0, -1, NULL, NULL, NULL);
- close(fd);
-
- return status;
-}
-
-/* return a newly-malloc'd string that is a copy of str. The new string
- is guaranteed to have a trailing slash. If absolute is true, the new string
- is also guaranteed to have a leading slash.
-*/
-static char *canonicalize_slashes(const char *str, bool absolute)
-{
- char *ret;
- int len = strlen(str);
- int newlen = len;
- char *ptr;
-
- if (len == 0) {
- if (absolute)
- return strdup("/");
- else
- return strdup("");
- }
-
- if (str[0] != '/' && absolute) {
- newlen++;
- }
- if (str[len - 1] != '/') {
- newlen++;
- }
- ret = malloc(newlen + 1);
- if (!ret) {
- critical_error("malloc");
- }
-
- ptr = ret;
- if (str[0] != '/' && absolute) {
- *ptr++ = '/';
- }
-
- strcpy(ptr, str);
- ptr += len;
-
- if (str[len - 1] != '/') {
- *ptr++ = '/';
- }
-
- if (ptr != ret + newlen) {
- critical_error("assertion failed\n");
- }
-
- *ptr = '\0';
-
- return ret;
-}
-
-static char *canonicalize_abs_slashes(const char *str)
-{
- return canonicalize_slashes(str, true);
-}
-
-static char *canonicalize_rel_slashes(const char *str)
-{
- return canonicalize_slashes(str, false);
-}
-
-static int compare_chunks(const void* chunk1, const void* chunk2) {
- struct region* c1 = (struct region*) chunk1;
- struct region* c2 = (struct region*) chunk2;
- return c1->block - c2->block;
-}
-
-static int get_block_group(u32 block) {
- unsigned int i, group = 0;
-
- for(i = 0; i < aux_info.groups; i++) {
- if (block >= aux_info.bgs[i].first_block)
- group = i;
- else
- break;
- }
- return group;
-}
-
-static void extract_base_fs_allocations(const char *directory, const char *mountpoint,
- FILE* base_alloc_file_in) {
-#define err_msg "base file badly formatted"
-#ifndef _WIN32
- // FORMAT Version 1.0: filename blk_mapping
- const char *base_alloc_file_in_format = "%s %s";
- const int base_file_format_param_count = 2;
-
- char stored_file_name[MAX_PATH], real_file_name[MAX_PATH], file_map[MAX_BLK_MAPPING_STR];
- struct block_allocation *fs_alloc;
- struct block_group_info *bgs = aux_info.bgs;
- int major_version = 0, minor_version = 0;
- unsigned int i;
- char *base_file_line = NULL;
- size_t base_file_line_len = 0;
-
- printf("[v%d.%d] Generating an Incremental EXT4 image\n",
- blk_file_major_ver, blk_file_minor_ver);
- if (base_fs_allocations == NULL)
- base_fs_allocations = create_allocation();
- fs_alloc = base_fs_allocations;
-
- fscanf(base_alloc_file_in, blk_file_header_fmt, &major_version, &minor_version);
- if (major_version == 0) {
- critical_error("Invalid base file");
- }
-
- if (major_version != blk_file_major_ver) {
- critical_error("Incompatible base file: version required is %d.X",
- blk_file_major_ver);
- }
-
- if (minor_version < blk_file_minor_ver) {
- critical_error("Incompatible base file: version required is %d.%d or above",
- blk_file_major_ver, blk_file_minor_ver);
- }
-
- while (getline(&base_file_line, &base_file_line_len, base_alloc_file_in) != -1) {
- if (sscanf(base_file_line, base_alloc_file_in_format, &stored_file_name, &file_map)
- != base_file_format_param_count) {
- continue;
- }
- if (strlen(stored_file_name) < strlen(mountpoint)) {
- continue;
- }
- snprintf(real_file_name, MAX_PATH, "%s%s", directory, stored_file_name + strlen(mountpoint));
- if (!access(real_file_name, R_OK)) {
- char *block_range, *end_string;
- int real_file_fd;
- int start_block, end_block;
- u32 block_file_size;
- u32 real_file_block_size;
- struct stat buf;
-
- if (lstat(real_file_name, &buf) == -1)
- critical_error(err_msg);
-
- if (!S_ISREG(buf.st_mode))
- continue;
-
- real_file_fd = open(real_file_name, O_RDONLY);
- if (real_file_fd == -1) {
- critical_error(err_msg);
- }
- real_file_block_size = get_file_size(real_file_fd);
- close(real_file_fd);
- real_file_block_size = DIV_ROUND_UP(real_file_block_size, info.block_size);
- fs_alloc->filename = strdup(real_file_name);
- block_range = strtok_r(file_map, ",", &end_string);
- while (block_range && real_file_block_size) {
- int block_group;
- char *range, *end_token = NULL;
- range = strtok_r(block_range, "-", &end_token);
- if (!range) {
- critical_error(err_msg);
- }
- start_block = parse_num(range);
- range = strtok_r(NULL, "-", &end_token);
- if (!range) {
- end_block = start_block;
- } else {
- end_block = parse_num(range);
- }
- // Assummption is that allocations are within the same block group
- block_group = get_block_group(start_block);
- if (block_group != get_block_group(end_block)) {
- critical_error("base file allocation's end block is in a different "
- "block group than start block. did you change fs params?");
- }
- block_range = strtok_r(NULL, ",", &end_string);
- int bg_first_block = bgs[block_group].first_block;
- int min_bg_bound = bgs[block_group].chunks[0].block + bgs[block_group].chunks[0].len;
- int max_bg_bound = bgs[block_group].chunks[bgs[block_group].chunk_count - 1].block;
-
- if (min_bg_bound >= start_block - bg_first_block ||
- max_bg_bound <= end_block - bg_first_block) {
- continue;
- }
- block_file_size = end_block - start_block + 1;
- if (block_file_size > real_file_block_size) {
- block_file_size = real_file_block_size;
- }
- append_region(fs_alloc, start_block, block_file_size, block_group);
- reserve_bg_chunk(block_group, start_block - bgs[block_group].first_block, block_file_size);
- real_file_block_size -= block_file_size;
- }
- if (reserve_blocks_for_allocation(fs_alloc) < 0)
- critical_error("failed to reserve base fs allocation");
- fs_alloc->next = create_allocation();
- fs_alloc = fs_alloc->next;
- }
- }
-
- for (i = 0; i < aux_info.groups; i++) {
- qsort(bgs[i].chunks, bgs[i].chunk_count, sizeof(struct region), compare_chunks);
- }
-
- free(base_file_line);
-
-#else
- return;
-#endif
-#undef err_msg
-}
-
-void generate_base_alloc_file_out(FILE* base_alloc_file_out, char* dir, char* mountpoint,
- struct block_allocation* p)
-{
- size_t dirlen = dir ? strlen(dir) : 0;
- fprintf(base_alloc_file_out, blk_file_header_fmt, blk_file_major_ver, blk_file_minor_ver);
- fputc('\n', base_alloc_file_out);
- while (p) {
- if (dir && strncmp(p->filename, dir, dirlen) == 0) {
- // substitute mountpoint for the leading directory in the filename, in the output file
- fprintf(base_alloc_file_out, "%s%s", mountpoint, p->filename + dirlen);
- } else {
- fprintf(base_alloc_file_out, "%s", p->filename);
- }
- print_blocks(base_alloc_file_out, p, ',');
- struct block_allocation* pn = p->next;
- p = pn;
- }
-}
-
-int make_ext4fs_internal(int fd, const char *_directory, const char *_target_out_directory,
- const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
- int sparse, int crc, int wipe, int real_uuid,
- struct selabel_handle *sehnd, int verbose, time_t fixed_time,
- FILE* block_list_file, FILE* base_alloc_file_in, FILE* base_alloc_file_out)
-{
- u32 root_inode_num;
- u16 root_mode;
- char *mountpoint;
- char *directory = NULL;
- char *target_out_directory = NULL;
- struct block_allocation* p;
-
- if (setjmp(setjmp_env))
- return EXIT_FAILURE; /* Handle a call to longjmp() */
-
- info.block_device = is_block_device_fd(fd);
-
- if (info.block_device && (sparse || gzip || crc)) {
- fprintf(stderr, "No sparse/gzip/crc allowed for block device\n");
- return EXIT_FAILURE;
- }
-
- if (_mountpoint == NULL) {
- mountpoint = strdup("");
- } else {
- mountpoint = canonicalize_abs_slashes(_mountpoint);
- }
-
- if (_directory) {
- directory = canonicalize_rel_slashes(_directory);
- }
-
- if (_target_out_directory) {
- target_out_directory = canonicalize_rel_slashes(_target_out_directory);
- }
-
- if (info.len <= 0)
- info.len = get_file_size(fd);
-
- if (info.block_size <= 0)
- info.block_size = compute_block_size();
-
- /* Round down the filesystem length to be a multiple of the block size */
- info.len &= ~((u64)info.block_size - 1);
-
- if (info.len <= 0) {
- fprintf(stderr, "filesystem size too small\n");
- free(mountpoint);
- return EXIT_FAILURE;
- }
-
- if (info.journal_blocks == 0)
- info.journal_blocks = compute_journal_blocks();
-
- if (info.no_journal == 0)
- info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
- else
- info.journal_blocks = 0;
-
- if (info.blocks_per_group <= 0)
- info.blocks_per_group = compute_blocks_per_group();
-
- if (info.inodes <= 0)
- info.inodes = compute_inodes();
-
- if (info.inode_size <= 0)
- info.inode_size = 256;
-
- if (info.label == NULL)
- info.label = "";
-
- info.inodes_per_group = compute_inodes_per_group();
-
- info.feat_compat |=
- EXT4_FEATURE_COMPAT_RESIZE_INODE |
- EXT4_FEATURE_COMPAT_EXT_ATTR;
-
- info.feat_ro_compat |=
- EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
- EXT4_FEATURE_RO_COMPAT_LARGE_FILE |
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
-
- info.feat_incompat |=
- EXT4_FEATURE_INCOMPAT_EXTENTS |
- EXT4_FEATURE_INCOMPAT_FILETYPE;
-
-
- info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
-
- printf("Creating filesystem with parameters:\n");
- printf(" Size: %"PRIu64"\n", info.len);
- printf(" Block size: %d\n", info.block_size);
- printf(" Blocks per group: %d\n", info.blocks_per_group);
- printf(" Inodes per group: %d\n", info.inodes_per_group);
- printf(" Inode size: %d\n", info.inode_size);
- printf(" Journal blocks: %d\n", info.journal_blocks);
- printf(" Label: %s\n", info.label);
-
- ext4_create_fs_aux_info();
-
- printf(" Blocks: %"PRIext4u64"\n", aux_info.len_blocks);
- printf(" Block groups: %d\n", aux_info.groups);
- printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
-
- ext4_sparse_file = sparse_file_new(info.block_size, info.len);
-
- block_allocator_init();
-
- ext4_fill_in_sb(real_uuid);
-
- if (base_alloc_file_in) {
- extract_base_fs_allocations(directory, mountpoint, base_alloc_file_in);
- }
- if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
- error("failed to reserve first 10 inodes");
-
- if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
- ext4_create_journal_inode();
-
- if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
- ext4_create_resize_inode();
-
-#ifdef _WIN32
- // Windows needs only 'create an empty fs image' functionality
- assert(!directory);
- root_inode_num = build_default_directory_structure(mountpoint, sehnd);
-#else
- if (directory)
- root_inode_num = build_directory_structure(directory, mountpoint, target_out_directory, 0,
- fs_config_func, sehnd, verbose, fixed_time);
- else
- root_inode_num = build_default_directory_structure(mountpoint, sehnd);
-#endif
-
- root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
- inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
-
-#ifndef _WIN32
- if (sehnd) {
- char *secontext = NULL;
-
- if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) {
- error("cannot lookup security context for %s", mountpoint);
- }
- if (secontext) {
- if (verbose) {
- printf("Labeling %s as %s\n", mountpoint, secontext);
- }
- inode_set_selinux(root_inode_num, secontext);
- }
- freecon(secontext);
- }
-#endif
-
- ext4_update_free();
-
- // TODO: Consider migrating the OTA tools to the new base alloc file format
- // used for generating incremental images (see go/incremental-ext4)
- if (block_list_file) {
- size_t dirlen = directory ? strlen(directory) : 0;
- struct block_allocation* p = get_saved_allocation_chain();
- while (p) {
- if (directory && strncmp(p->filename, directory, dirlen) == 0) {
- // substitute mountpoint for the leading directory in the filename, in the output file
- fprintf(block_list_file, "%s%s", mountpoint, p->filename + dirlen);
- } else {
- fprintf(block_list_file, "%s", p->filename);
- }
- print_blocks(block_list_file, p, ' ');
- struct block_allocation* pn = p->next;
- p = pn;
- }
- }
-
- if (base_alloc_file_out) {
- struct block_allocation* p = get_saved_allocation_chain();
- generate_base_alloc_file_out(base_alloc_file_out, directory, mountpoint, p);
- }
-
- printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
- aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
- aux_info.sb->s_inodes_count,
- aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
- aux_info.sb->s_blocks_count_lo);
-
- if (wipe && WIPE_IS_SUPPORTED) {
- wipe_block_device(fd, info.len);
- }
-
- write_ext4_image(fd, gzip, sparse, crc);
-
- sparse_file_destroy(ext4_sparse_file);
- ext4_sparse_file = NULL;
-
- p = get_saved_allocation_chain();
- while (p) {
- struct block_allocation* pn = p->next;
- free_alloc(p);
- p = pn;
- }
-
- free(mountpoint);
- free(directory);
-
- return 0;
-}
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
deleted file mode 100644
index 77930cd..0000000
--- a/ext4_utils/make_ext4fs_main.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-#include <fcntl.h>
-#include <libgen.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#if defined(__linux__)
-#include <linux/fs.h>
-#elif defined(__APPLE__) && defined(__MACH__)
-#include <sys/disk.h>
-#endif
-
-#ifdef ANDROID
-#include <private/android_filesystem_config.h>
-#include <private/canned_fs_config.h>
-#endif
-
-#ifndef _WIN32
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-#if !defined(HOST)
-#include <selinux/android.h>
-#endif
-#else
-struct selabel_handle;
-#endif
-
-#include "ext4_utils/ext4_utils.h"
-#include "ext4_utils/make_ext4fs.h"
-
-#ifndef _WIN32 /* O_BINARY is windows-specific flag */
-#define O_BINARY 0
-#endif
-
-extern struct fs_info info;
-
-
-static void usage(char *path)
-{
- fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
- fprintf(stderr, " [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
- fprintf(stderr, " [ -e <flash erase block size> ] [ -o <flash logical block size> ]\n");
- fprintf(stderr, " [ -L <label> ] [ -f ] [ -a <android mountpoint> ] [ -u ]\n");
- fprintf(stderr, " [ -S file_contexts ] [ -C fs_config ] [ -T timestamp ]\n");
- fprintf(stderr, " [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ] [ -B <block_list_file> ]\n");
- fprintf(stderr, " [ -d <base_alloc_file_in> ] [ -D <base_alloc_file_out> ]\n");
- fprintf(stderr, " <filename> [[<directory>] <target_out_directory>]\n");
-}
-
-int main(int argc, char **argv)
-{
- int opt;
- const char *filename = NULL;
- const char *directory = NULL;
- const char *target_out_directory = NULL;
- char *mountpoint = NULL;
- fs_config_func_t fs_config_func = NULL;
- const char *fs_config_file = NULL;
- int gzip = 0;
- int sparse = 0;
- int crc = 0;
- int wipe = 0;
- int real_uuid = 0;
- int fd;
- int exitcode;
- int verbose = 0;
- time_t fixed_time = -1;
- struct selabel_handle *sehnd = NULL;
- FILE* block_list_file = NULL;
- FILE* base_alloc_file_in = NULL;
- FILE* base_alloc_file_out = NULL;
-#ifndef _WIN32
- struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
-#endif
-
- while ((opt = getopt(argc, argv, "l:j:b:g:i:I:e:o:L:a:S:T:C:B:d:D:fwzJsctvu")) != -1) {
- switch (opt) {
- case 'l':
- info.len = parse_num(optarg);
- break;
- case 'j':
- info.journal_blocks = parse_num(optarg);
- break;
- case 'b':
- info.block_size = parse_num(optarg);
- break;
- case 'g':
- info.blocks_per_group = parse_num(optarg);
- break;
- case 'i':
- info.inodes = parse_num(optarg);
- break;
- case 'I':
- info.inode_size = parse_num(optarg);
- break;
- case 'e':
- info.flash_erase_block_size = parse_num(optarg);
- break;
- case 'o':
- info.flash_logical_block_size = parse_num(optarg);
- break;
- case 'L':
- info.label = optarg;
- break;
- case 'f':
- force = 1;
- break;
- case 'a':
-#ifdef ANDROID
- mountpoint = optarg;
-#else
- fprintf(stderr, "can't set android permissions - built without android support\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
-#endif
- break;
- case 'w':
- wipe = 1;
- break;
- case 'u':
- real_uuid = 1;
- break;
- case 'z':
- gzip = 1;
- break;
- case 'J':
- info.no_journal = 1;
- break;
- case 'c':
- crc = 1;
- break;
- case 's':
- sparse = 1;
- break;
- case 't':
- fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n");
- break;
- case 'S':
-#ifndef _WIN32
- seopts[0].value = optarg;
- sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
- if (!sehnd) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
-#endif
- break;
- case 'v':
- verbose = 1;
- break;
- case 'T':
- fixed_time = strtoll(optarg, NULL, 0);
- break;
- case 'C':
- fs_config_file = optarg;
- break;
- case 'B':
- block_list_file = fopen(optarg, "w");
- if (block_list_file == NULL) {
- fprintf(stderr, "failed to open block_list_file: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- break;
- case 'd':
- base_alloc_file_in = fopen(optarg, "r");
- if (base_alloc_file_in == NULL) {
- fprintf(stderr, "failed to open base_alloc_file_in: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- break;
- case 'D':
- base_alloc_file_out = fopen(optarg, "w");
- if (base_alloc_file_out == NULL) {
- fprintf(stderr, "failed to open base_alloc_file_out: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- break;
- default: /* '?' */
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- }
-
-#if !defined(HOST)
- // Use only if -S option not requested
- if (!sehnd && mountpoint) {
- sehnd = selinux_android_file_context_handle();
-
- if (!sehnd) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- }
-#endif
-
- if (fs_config_file) {
- if (load_canned_fs_config(fs_config_file) < 0) {
- fprintf(stderr, "failed to load %s\n", fs_config_file);
- exit(EXIT_FAILURE);
- }
- fs_config_func = canned_fs_config;
- } else if (mountpoint) {
- fs_config_func = fs_config;
- }
-
- if (wipe && sparse) {
- fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (wipe && gzip) {
- fprintf(stderr, "Cannot specifiy both wipe and gzip\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (optind >= argc) {
- fprintf(stderr, "Expected filename after options\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- filename = argv[optind++];
-
- if (optind < argc)
- directory = argv[optind++];
-
- if (optind < argc)
- target_out_directory = argv[optind++];
-
- if (optind < argc) {
- fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (strcmp(filename, "-")) {
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (fd < 0) {
- perror("open");
- return EXIT_FAILURE;
- }
- } else {
- fd = STDOUT_FILENO;
- }
-
- exitcode = make_ext4fs_internal(fd, directory, target_out_directory, mountpoint, fs_config_func, gzip,
- sparse, crc, wipe, real_uuid, sehnd, verbose, fixed_time,
- block_list_file, base_alloc_file_in, base_alloc_file_out);
- close(fd);
- if (block_list_file)
- fclose(block_list_file);
- if (base_alloc_file_out)
- fclose(base_alloc_file_out);
- if (base_alloc_file_in)
- fclose(base_alloc_file_in);
- if (exitcode && strcmp(filename, "-"))
- unlink(filename);
- return exitcode;
-}
diff --git a/ext4_utils/mke2fs.conf b/ext4_utils/mke2fs.conf
index db77173..abf0dae 100644
--- a/ext4_utils/mke2fs.conf
+++ b/ext4_utils/mke2fs.conf
@@ -12,7 +12,7 @@
features = has_journal
}
ext4 = {
- features = has_journal,extent,huge_file,flex_bg,dir_nlink,extra_isize,uninit_bg
+ features = has_journal,extent,huge_file,dir_nlink,extra_isize,uninit_bg
inode_size = 256
}
ext4dev = {
diff --git a/ext4_utils/mkuserimg.sh b/ext4_utils/mkuserimg.sh
deleted file mode 100755
index 06c68d4..0000000
--- a/ext4_utils/mkuserimg.sh
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/bin/bash
-#
-# To call this script, make sure make_ext4fs is somewhere in PATH
-
-function usage() {
-cat<<EOT
-Usage:
-mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [-j <journal_size>]
- [-T TIMESTAMP] [-C FS_CONFIG] [-D PRODUCT_OUT] [-B BLOCK_LIST_FILE]
- [-d BASE_ALLOC_FILE_IN ] [-A BASE_ALLOC_FILE_OUT ] [-L LABEL]
- [-i INODES ] [-e ERASE_BLOCK_SIZE] [-o FLASH_BLOCK_SIZE] [FILE_CONTEXTS]
-EOT
-}
-
-ENABLE_SPARSE_IMAGE=
-if [ "$1" = "-s" ]; then
- ENABLE_SPARSE_IMAGE="-s"
- shift
-fi
-
-if [ $# -lt 5 ]; then
- usage
- exit 1
-fi
-
-SRC_DIR=$1
-if [ ! -d $SRC_DIR ]; then
- echo "Can not find directory $SRC_DIR!"
- exit 2
-fi
-
-OUTPUT_FILE=$2
-EXT_VARIANT=$3
-MOUNT_POINT=$4
-SIZE=$5
-shift; shift; shift; shift; shift
-
-JOURNAL_FLAGS=
-if [ "$1" = "-j" ]; then
- if [ "$2" = "0" ]; then
- JOURNAL_FLAGS="-J"
- else
- JOURNAL_FLAGS="-j $2"
- fi
- shift; shift
-fi
-
-TIMESTAMP=-1
-if [[ "$1" == "-T" ]]; then
- TIMESTAMP=$2
- shift; shift
-fi
-
-FS_CONFIG=
-if [[ "$1" == "-C" ]]; then
- FS_CONFIG=$2
- shift; shift
-fi
-
-PRODUCT_OUT=
-if [[ "$1" == "-D" ]]; then
- PRODUCT_OUT=$2
- shift; shift
-fi
-
-BLOCK_LIST=
-if [[ "$1" == "-B" ]]; then
- BLOCK_LIST=$2
- shift; shift
-fi
-
-BASE_ALLOC_FILE_IN=
-if [[ "$1" == "-d" ]]; then
- BASE_ALLOC_FILE_IN=$2
- shift; shift
-fi
-
-BASE_ALLOC_FILE_OUT=
-if [[ "$1" == "-A" ]]; then
- BASE_ALLOC_FILE_OUT=$2
- shift; shift
-fi
-
-LABEL=
-if [[ "$1" == "-L" ]]; then
- LABEL=$2
- shift; shift
-fi
-
-INODES=
-if [[ "$1" == "-i" ]]; then
- INODES=$2
- shift; shift
-fi
-
-ERASE_SIZE=
-if [[ "$1" == "-e" ]]; then
- ERASE_SIZE=$2
- shift; shift
-fi
-
-FLASH_BLOCK_SIZE=
-if [[ "$1" == "-o" ]]; then
- FLASH_BLOCK_SIZE=$2
- shift; shift
-fi
-FC=$1
-
-case $EXT_VARIANT in
- ext4) ;;
- *) echo "Only ext4 is supported!"; exit 3 ;;
-esac
-
-if [ -z $MOUNT_POINT ]; then
- echo "Mount point is required"
- exit 2
-fi
-
-if [ -z $SIZE ]; then
- echo "Need size of filesystem"
- exit 2
-fi
-
-OPT=""
-if [ -n "$FC" ]; then
- OPT="$OPT -S $FC"
-fi
-if [ -n "$FS_CONFIG" ]; then
- OPT="$OPT -C $FS_CONFIG"
-fi
-if [ -n "$BLOCK_LIST" ]; then
- OPT="$OPT -B $BLOCK_LIST"
-fi
-if [ -n "$BASE_ALLOC_FILE_IN" ]; then
- OPT="$OPT -d $BASE_ALLOC_FILE_IN"
-fi
-if [ -n "$BASE_ALLOC_FILE_OUT" ]; then
- OPT="$OPT -D $BASE_ALLOC_FILE_OUT"
-fi
-if [ -n "$LABEL" ]; then
- OPT="$OPT -L $LABEL"
-fi
-if [ -n "$INODES" ]; then
- OPT="$OPT -i $INODES"
-fi
-if [ -n "$ERASE_SIZE" ]; then
- OPT="$OPT -e $ERASE_SIZE"
-fi
-if [ -n "$FLASH_BLOCK_SIZE" ]; then
- OPT="$OPT -o $FLASH_BLOCK_SIZE"
-fi
-
-MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE -T $TIMESTAMP $OPT -l $SIZE $JOURNAL_FLAGS -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR $PRODUCT_OUT"
-echo $MAKE_EXT4FS_CMD
-$MAKE_EXT4FS_CMD
-if [ $? -ne 0 ]; then
- exit 4
-fi
diff --git a/ext4_utils/setup_fs.c b/ext4_utils/setup_fs.c
deleted file mode 100644
index 802412d..0000000
--- a/ext4_utils/setup_fs.c
+++ /dev/null
@@ -1,86 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/reboot.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <cutils/android_reboot.h>
-#include <cutils/partition_utils.h>
-
-const char *mkfs = "/system/bin/make_ext4fs";
-
-int setup_fs(const char *blockdev)
-{
- char buf[256], path[128];
- pid_t child;
- int status, n;
- pid_t pid;
-
- /* we might be looking at an indirect reference */
- n = readlink(blockdev, path, sizeof(path) - 1);
- if (n > 0) {
- path[n] = 0;
- if (!memcmp(path, "/dev/block/", 11))
- blockdev = path + 11;
- }
-
- if (strchr(blockdev,'/')) {
- fprintf(stderr,"not a block device name: %s\n", blockdev);
- return 0;
- }
-
- snprintf(buf, sizeof(buf), "/sys/fs/ext4/%s", blockdev);
- if (access(buf, F_OK) == 0) {
- fprintf(stderr,"device %s already has a filesystem\n", blockdev);
- return 0;
- }
- snprintf(buf, sizeof(buf), "/dev/block/%s", blockdev);
-
- if (!partition_wiped(buf)) {
- fprintf(stderr,"device %s not wiped, probably encrypted, not wiping\n", blockdev);
- return 0;
- }
-
- fprintf(stderr,"+++\n");
-
- child = fork();
- if (child < 0) {
- fprintf(stderr,"error: setup_fs: fork failed\n");
- return 0;
- }
- if (child == 0) {
- execl(mkfs, mkfs, buf, NULL);
- exit(-1);
- }
-
- while ((pid=waitpid(-1, &status, 0)) != child) {
- if (pid == -1) {
- fprintf(stderr, "error: setup_fs: waitpid failed!\n");
- return 1;
- }
- }
-
- fprintf(stderr,"---\n");
- return 1;
-}
-
-
-int main(int argc, char **argv)
-{
- int need_reboot = 0;
-
- while (argc > 1) {
- if (strlen(argv[1]) < 128)
- need_reboot |= setup_fs(argv[1]);
- argv++;
- argc--;
- }
-
- if (need_reboot) {
- fprintf(stderr,"REBOOT!\n");
- android_reboot(ANDROID_RB_RESTART, 0, 0);
- exit(-1);
- }
- return 0;
-}
diff --git a/ext4_utils/test_ext4fixup b/ext4_utils/test_ext4fixup
deleted file mode 100755
index a920a59..0000000
--- a/ext4_utils/test_ext4fixup
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/bash
-
-typeset -i I ITERATIONS PHASE LOC COUNT MAXCOUNT
-
-ME=`basename $0`
-
-if [ "$#" -ne 3 ]
-then
- echo "$ME: Usage: $ME <iterations> <maxcount> <filesystem_image>" >&2
- exit 1;
-fi
-
-ITERATIONS="$1"
-MAXCOUNT="$2"
-ORIG_FS_IMAGE="$3"
-FIXED_FS_IMAGE="/tmp/fixedfsimage.$$"
-NEW_FS_IMAGE="/tmp/newfsimage.$$"
-
-if [ ! -f "$ORIG_FS_IMAGE" ]
-then
- echo "$ME: Filesystem image $NEW_FS_IMAGE does not exist" >&2
- exit 1
-fi
-
-trap "rm -f $NEW_FS_IMAGE $FIXED_FS_IMAGE" 0 1 2 3 15
-
-rm -f "$NEW_FS_IMAGE" "$FIXED_FS_IMAGE"
-
-# Create the fixed image to compare against
-cp "$ORIG_FS_IMAGE" "$FIXED_FS_IMAGE"
-ext4fixup "$FIXED_FS_IMAGE"
-
-if [ "$?" -ne 0 ]
-then
- echo "$ME: ext4fixup failed!\n"
- exit 1
-fi
-
-I=0
-while [ "$I" -lt "$ITERATIONS" ]
-do
- # There is also a phase 4, which is writing out the updated superblocks and
- # block group descriptors. Test the with a separate script.
- let PHASE="$RANDOM"%3 # 0 to 2
- let PHASE++ # 1 to 3
- let LOC="$RANDOM"%2 # 0 to 1
- let LOC++ # 1 to 2
- let COUNT="$RANDOM"%"$MAXCOUNT"
-
- # Make a copy of the original image to fixup
- cp "$ORIG_FS_IMAGE" "$NEW_FS_IMAGE"
-
- # Run the fixup tool, but die partway through to see if we can recover
- ext4fixup -d "$PHASE,$LOC,$COUNT" "$NEW_FS_IMAGE" 2>/dev/null
-
- # run it again without -d to have it finish the job
- ext4fixup "$NEW_FS_IMAGE"
-
- if cmp "$FIXED_FS_IMAGE" "$NEW_FS_IMAGE"
- then
- :
- else
- echo "$ME: test failed with parameters $PHASE, $LOC, $COUNT"
- exit 1
- fi
-
- rm -f "$NEW_FS_IMAGE"
-
- let I++
-done
-
diff --git a/partition_tools/Android.bp b/partition_tools/Android.bp
new file mode 100644
index 0000000..265ee66
--- /dev/null
+++ b/partition_tools/Android.bp
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_defaults {
+ name: "lp_defaults",
+ cflags: [
+ "-Werror",
+ "-Wextra",
+ ],
+ target: {
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+}
+
+cc_binary {
+ name: "lpdump",
+ defaults: ["lp_defaults"],
+ host_supported: true,
+ static_libs: [
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "liblog",
+ "liblp",
+ ],
+ srcs: [
+ "lpdump.cc",
+ ],
+}
+
+cc_binary {
+ name: "lpmake",
+ defaults: ["lp_defaults"],
+ host_supported: true,
+ static_libs: [
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "liblog",
+ "liblp",
+ ],
+ srcs: [
+ "lpmake.cc",
+ ],
+}
+
+cc_binary {
+ name: "lpflash",
+ defaults: ["lp_defaults"],
+ host_supported: true,
+ static_libs: [
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "liblog",
+ "liblp",
+ ],
+ srcs: [
+ "lpflash.cc",
+ ],
+}
diff --git a/partition_tools/lpdump.cc b/partition_tools/lpdump.cc
new file mode 100644
index 0000000..c54119a
--- /dev/null
+++ b/partition_tools/lpdump.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/parseint.h>
+#include <liblp/reader.h>
+
+using namespace android;
+using namespace android::fs_mgr;
+
+static int usage(int /* argc */, char* argv[]) {
+ fprintf(stderr,
+ "%s - command-line tool for dumping Android Logical Partition images.\n"
+ "\n"
+ "Usage:\n"
+ " %s [-s,--slot] file-or-device\n"
+ "\n"
+ "Options:\n"
+ " -s, --slot=N Slot number or suffix.\n",
+ argv[0], argv[0]);
+ return EX_USAGE;
+}
+
+static std::string BuildAttributeString(uint32_t attrs) {
+ return (attrs & LP_PARTITION_ATTR_READONLY) ? "readonly" : "none";
+}
+
+static bool IsBlockDevice(const char* file) {
+ struct stat s;
+ return !stat(file, &s) && S_ISBLK(s.st_mode);
+}
+
+int main(int argc, char* argv[]) {
+ struct option options[] = {
+ { "slot", required_argument, nullptr, 's' },
+ { "help", no_argument, nullptr, 'h' },
+ { nullptr, 0, nullptr, 0 },
+ };
+
+ int rv;
+ int index;
+ uint32_t slot = 0;
+ while ((rv = getopt_long_only(argc, argv, "s:h", options, &index)) != -1) {
+ switch (rv) {
+ case 'h':
+ return usage(argc, argv);
+ case 's':
+ if (!android::base::ParseUint(optarg, &slot)) {
+ slot = SlotNumberForSlotSuffix(optarg);
+ }
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ return usage(argc, argv);
+ }
+ const char* file = argv[optind++];
+
+ std::unique_ptr<LpMetadata> pt;
+ if (IsBlockDevice(file)) {
+ pt = ReadMetadata(file, slot);
+ } else {
+ pt = ReadFromImageFile(file);
+ }
+ if (!pt) {
+ fprintf(stderr, "Failed to read metadata.\n");
+ return EX_NOINPUT;
+ }
+
+ printf("Metadata version: %u.%u\n", pt->header.major_version, pt->header.minor_version);
+ printf("Metadata size: %u bytes\n", pt->header.header_size + pt->header.tables_size);
+ printf("Metadata max size: %u bytes\n", pt->geometry.metadata_max_size);
+ printf("Metadata slot count: %u\n", pt->geometry.metadata_slot_count);
+ printf("First logical sector: %" PRIu64 "\n", pt->geometry.first_logical_sector);
+ printf("Last logical sector: %" PRIu64 "\n", pt->geometry.last_logical_sector);
+ printf("Partition table:\n");
+ printf("------------------------\n");
+
+ for (const auto& partition : pt->partitions) {
+ std::string name = GetPartitionName(partition);
+ std::string guid = GetPartitionGuid(partition);
+ printf(" Name: %s\n", name.c_str());
+ printf(" GUID: %s\n", guid.c_str());
+ printf(" Attributes: %s\n", BuildAttributeString(partition.attributes).c_str());
+ printf(" Extents:\n");
+ uint64_t first_sector = 0;
+ for (size_t i = 0; i < partition.num_extents; i++) {
+ const LpMetadataExtent& extent = pt->extents[partition.first_extent_index + i];
+ printf(" %" PRIu64 " .. %" PRIu64 " ", first_sector,
+ (first_sector + extent.num_sectors - 1));
+ first_sector += extent.num_sectors;
+ if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
+ printf("linear %" PRIu64, extent.target_data);
+ } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
+ printf("zero");
+ }
+ printf("\n");
+ }
+ printf("------------------------\n");
+ }
+
+ return EX_OK;
+}
diff --git a/partition_tools/lpflash.cc b/partition_tools/lpflash.cc
new file mode 100644
index 0000000..83e5008
--- /dev/null
+++ b/partition_tools/lpflash.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <stdio.h>
+#include <sysexits.h>
+
+#include <string>
+
+#include <liblp/reader.h>
+#include <liblp/writer.h>
+
+using namespace android;
+using namespace android::fs_mgr;
+
+/* Prints program usage to |where|. */
+static int usage(int /* argc */, char* argv[]) {
+ fprintf(stderr,
+ "%s - command-line tool for dumping Android Logical Partition images.\n"
+ "\n"
+ "Usage:\n"
+ " %s [block-device] [img-file]\n",
+ argv[0], argv[0]);
+ return EX_USAGE;
+}
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ return usage(argc, argv);
+ }
+
+ std::unique_ptr<LpMetadata> pt = ReadFromImageFile(argv[2]);
+ if (!pt) {
+ printf("Failed to read image file.\n");
+ return EX_NOINPUT;
+ }
+
+ if (!WritePartitionTable(argv[1], *pt.get(), SyncMode::Flash, 0)) {
+ printf("Failed to flash partition table.\n");
+ return EX_SOFTWARE;
+ }
+ printf("Successfully flashed partition table.\n");
+ return EX_OK;
+}
diff --git a/partition_tools/lpmake.cc b/partition_tools/lpmake.cc
new file mode 100644
index 0000000..016b32d
--- /dev/null
+++ b/partition_tools/lpmake.cc
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <getopt.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sysexits.h>
+
+#include <memory>
+
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <liblp/builder.h>
+#include <liblp/writer.h>
+
+using namespace android;
+using namespace android::fs_mgr;
+
+/* Prints program usage to |where|. */
+static int usage(int /* argc */, char* argv[]) {
+ fprintf(stderr,
+ "%s - command-line tool for creating Android Logical Partition images.\n"
+ "\n"
+ "Usage:\n"
+ " %s [options]\n"
+ "\n"
+ "Required options:\n"
+ " -d,--device-size=SIZE Size of the block device for logical partitions.\n"
+ " -m,--metadata-size=SIZE Maximum size to reserve for partition metadata.\n"
+ " -s,--metadata-slots=COUNT Number of slots to store metadata copies.\n"
+ " -p,--partition=DATA Add a partition given the data, see below.\n"
+ " -o,--output=FILE Output file.\n"
+ "\n"
+ "Partition format:\n"
+ " <name>:<guid>:<attributes>:<size>\n"
+ " Attrs must be 'none' or 'readonly'.\n",
+ argv[0], argv[0]);
+ return EX_USAGE;
+}
+
+int main(int argc, char* argv[]) {
+ struct option options[] = {
+ { "device-size", required_argument, nullptr, 'd' },
+ { "metadata-size", required_argument, nullptr, 'm' },
+ { "metadata-slots", required_argument, nullptr, 's' },
+ { "partition", required_argument, nullptr, 'p' },
+ { "output", required_argument, nullptr, 'o' },
+ { "help", no_argument, nullptr, 'h' },
+ { nullptr, 0, nullptr, 0 },
+ };
+
+ uint64_t blockdevice_size = 0;
+ uint32_t metadata_size = 0;
+ uint32_t metadata_slots = 0;
+ std::string output_path;
+ std::vector<std::string> partitions;
+
+ int rv;
+ int index;
+ while ((rv = getopt_long_only(argc, argv, "d:m:s:p:o:h", options, &index)) != -1) {
+ switch (rv) {
+ case 'h':
+ return usage(argc, argv);
+ case 'd':
+ if (!android::base::ParseUint(optarg, &blockdevice_size)) {
+ fprintf(stderr, "Invalid argument to --device-size.\n");
+ return EX_USAGE;
+ }
+ break;
+ case 'm':
+ if (!android::base::ParseUint(optarg, &metadata_size)) {
+ fprintf(stderr, "Invalid argument to --metadata-size.\n");
+ return EX_USAGE;
+ }
+ break;
+ case 's':
+ if (!android::base::ParseUint(optarg, &metadata_slots)) {
+ fprintf(stderr, "Invalid argument to --metadata-slots.\n");
+ return EX_USAGE;
+ }
+ break;
+ case 'p':
+ partitions.push_back(optarg);
+ break;
+ case 'o':
+ output_path = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Check for empty arguments so we can print a more helpful message rather
+ // than error on each individual missing argument.
+ if (optind == 1) {
+ return usage(argc, argv);
+ }
+
+ if (!blockdevice_size) {
+ fprintf(stderr, "--device-size needs more than 0 bytes of disk space.\n");
+ return EX_USAGE;
+ }
+ if (!metadata_size) {
+ fprintf(stderr, "--metadata-size must be more than 0 bytes.\n");
+ return EX_USAGE;
+ }
+ if (!metadata_slots) {
+ fprintf(stderr, "--metadata-slots must be more than 0.\n");
+ return EX_USAGE;
+ }
+ if (output_path.empty()) {
+ fprintf(stderr, "--output must specify a valid path.\n");
+ return EX_USAGE;
+ }
+ if (partitions.empty()) {
+ fprintf(stderr, "Partition table must have at least one entry.\n");
+ return EX_USAGE;
+ }
+
+ std::unique_ptr<MetadataBuilder> builder =
+ MetadataBuilder::New(blockdevice_size, metadata_size, metadata_slots);
+
+ for (const auto& partition_info : partitions) {
+ std::vector<std::string> parts = android::base::Split(partition_info, ":");
+ if (parts.size() != 4) {
+ fprintf(stderr, "Partition info has invalid formatting.\n");
+ return EX_USAGE;
+ }
+
+ std::string name = parts[0];
+ if (!name.length()) {
+ fprintf(stderr, "Partition must have a valid name.\n");
+ return EX_USAGE;
+ }
+
+ uint64_t size;
+ if (!android::base::ParseUint(parts[3].c_str(), &size)) {
+ fprintf(stderr, "Partition must have a valid size.\n");
+ return EX_USAGE;
+ }
+
+ uint32_t attribute_flags = 0;
+ std::string attributes = parts[2];
+ if (attributes == "readonly") {
+ attribute_flags |= LP_PARTITION_ATTR_READONLY;
+ } else if (attributes != "none") {
+ fprintf(stderr, "Attribute not recognized: %s\n", attributes.c_str());
+ return EX_USAGE;
+ }
+
+ Partition* partition = builder->AddPartition(name, parts[1], attribute_flags);
+ if (!builder->GrowPartition(partition, size)) {
+ fprintf(stderr, "Not enough space on device for partition %s with size %" PRIu64 "\n",
+ name.c_str(), size);
+ return EX_SOFTWARE;
+ }
+ }
+
+ std::unique_ptr<LpMetadata> metadata = builder->Export();
+ if (!WriteToImageFile(output_path.c_str(), *metadata.get())) {
+ return EX_CANTCREAT;
+ }
+
+ return EX_OK;
+}
diff --git a/perfprofd/Android.bp b/perfprofd/Android.bp
index 7db4d49..ba66a4c 100644
--- a/perfprofd/Android.bp
+++ b/perfprofd/Android.bp
@@ -109,6 +109,36 @@
export_static_lib_headers: ["libquipper"],
}
+filegroup {
+ name: "perfprofd_config_proto",
+ srcs: [
+ "perfprofd_config.proto",
+ ],
+}
+
+cc_library_static {
+ name: "libperfprofd_proto_config",
+ defaults: [
+ "perfprofd_defaults",
+ ],
+ host_supported: true,
+
+ static_libs: [
+ "libprotobuf-cpp-lite",
+ ],
+ srcs: [
+ "perfprofd_counters.cc",
+ ":perfprofd_config_proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+
+ export_include_dirs: ["."], // Really only the -fwd.h.
+}
+
//
// Static library containing guts of AWP daemon.
//
@@ -136,6 +166,7 @@
"cpuconfig.cc",
"perfprofdcore.cc",
"perfprofd_cmdline.cc",
+ "perfprofd_perf.cc",
"symbolizer.cc"
],
@@ -179,6 +210,7 @@
static_libs: [
"libperfprofdcore",
"libperfprofd_binder",
+ "libperfprofd_proto_config",
"libsimpleperf_elf_read",
],
group_static_libs: true,
diff --git a/perfprofd/binder_interface/Android.bp b/perfprofd/binder_interface/Android.bp
index 25e6bf7..3cf7c2e 100644
--- a/perfprofd/binder_interface/Android.bp
+++ b/perfprofd/binder_interface/Android.bp
@@ -28,17 +28,13 @@
"libbase",
"libbinder",
"libperfprofdcore",
+ "libperfprofd_proto_config",
"libprotobuf-cpp-lite",
],
srcs: [
"perfprofd_binder.cc",
":perfprofd_aidl",
- ":perfprofd_config_proto",
],
-
- proto: {
- type: "lite",
- },
}
filegroup {
@@ -47,10 +43,3 @@
"aidl/android/os/IPerfProfd.aidl",
],
}
-
-filegroup {
- name: "perfprofd_config_proto",
- srcs: [
- "perfprofd_config.proto",
- ],
-}
diff --git a/perfprofd/binder_interface/perfprofd_config.proto b/perfprofd/binder_interface/perfprofd_config.proto
deleted file mode 100644
index cfd85ed..0000000
--- a/perfprofd/binder_interface/perfprofd_config.proto
+++ /dev/null
@@ -1,83 +0,0 @@
-
-syntax = "proto2";
-
-option java_package = "android.perfprofd";
-
-package android.perfprofd;
-
-// The configuration for a profiling session.
-message ProfilingConfig {
- // Average number of seconds between perf profile collections (if
- // set to 100, then over time we want to see a perf profile
- // collected every 100 seconds). The actual time within the interval
- // for the collection is chosen randomly.
- optional uint32 collection_interval_in_s = 1;
-
- // Use the specified fixed seed for random number generation (unit
- // testing)
- optional uint32 use_fixed_seed = 2;
-
- // Number of times to iterate through main
- // loop. Value of zero indicates that we should loop forever.
- optional uint32 main_loop_iterations = 3;
-
- // Destination directory (where to write profiles).
- optional string destination_directory = 4;
- // Config directory (where to read configs).
- optional string config_directory = 5;
- // Full path to 'perf' executable.
- optional string perf_path = 6;
-
- // Desired sampling period (passed to perf -c option). Small
- // sampling periods can perturb the collected profiles, so enforce
- // min/max. A value of 0 means perf default. sampling_frequency
- // takes priority.
- optional uint32 sampling_period = 7;
- // Desired sampling frequency (passed to perf -f option). A value of 0
- // means using sampling_period or default.
- optional uint32 sampling_frequency = 22;
- // Length of time to collect samples (number of seconds for 'perf
- // record -a' run).
- optional uint32 sample_duration_in_s = 8;
-
- // If this parameter is non-zero it will cause perfprofd to
- // exit immediately if the build type is not userdebug or eng.
- // Currently defaults to 1 (true).
- optional bool only_debug_build = 9;
-
- // If the "mpdecision" service is running at the point we are ready
- // to kick off a profiling run, then temporarily disable the service
- // and hard-wire all cores on prior to the collection run, provided
- // that the duration of the recording is less than or equal to the value of
- // 'hardwire_cpus_max_duration'.
- optional bool hardwire_cpus = 10;
- optional uint32 hardwire_cpus_max_duration_in_s = 11;
-
- // Maximum number of unprocessed profiles we can accumulate in the
- // destination directory. Once we reach this limit, we continue
- // to collect, but we just overwrite the most recent profile.
- optional uint32 max_unprocessed_profiles = 12;
-
- // If set to 1, pass the -g option when invoking 'perf' (requests
- // stack traces as opposed to flat profile).
- optional bool stack_profile = 13;
-
- // Control collection of various additional profile tags
- optional bool collect_cpu_utilization = 14;
- optional bool collect_charging_state = 15;
- optional bool collect_booting = 16;
- optional bool collect_camera_active = 17;
-
- // The pid of the process to profile. May be negative, in which case
- // the whole system will be profiled.
- optional int32 process = 18;
-
- // Whether to use a symbolizer on-device.
- optional bool use_elf_symbolizer = 19;
-
- // Whether to send the result to dropbox.
- optional bool send_to_dropbox = 20;
-
- // If true, use libz to compress the output proto.
- optional bool compress = 21;
-};
diff --git a/perfprofd/perfprofd_config.proto b/perfprofd/perfprofd_config.proto
new file mode 100644
index 0000000..8f65766
--- /dev/null
+++ b/perfprofd/perfprofd_config.proto
@@ -0,0 +1,1510 @@
+
+syntax = "proto2";
+
+option java_package = "android.perfprofd";
+
+package android.perfprofd;
+
+message CounterSet {
+
+ optional bool branch_load_misses = 1;
+ optional bool branch_loads = 2;
+ optional bool branch_store_misses = 3;
+ optional bool branch_stores = 4;
+ optional bool L1_dcache_load_misses = 5;
+ optional bool L1_dcache_loads = 6;
+ optional bool L1_dcache_store_misses = 7;
+ optional bool L1_dcache_stores = 8;
+ optional bool branch_misses = 9;
+ optional bool cache_misses = 10;
+ optional bool cache_references = 11;
+ optional bool cpu_cycles = 12;
+ optional bool instructions = 13;
+ optional bool raw_br_mis_pred = 14;
+ optional bool raw_br_mis_pred_retired = 15;
+ optional bool raw_br_pred = 16;
+ optional bool raw_br_retired = 17;
+ optional bool raw_bus_access = 18;
+ optional bool raw_cpu_cycles = 19;
+ optional bool raw_exception_return = 20;
+ optional bool raw_exception_taken = 21;
+ optional bool raw_inst_spec = 22;
+ optional bool raw_instruction_retired = 23;
+ optional bool raw_l1_dcache = 24;
+ optional bool raw_l1_dcache_allocate = 25;
+ optional bool raw_l1_dcache_refill = 26;
+ optional bool raw_l1_dtlb = 27;
+ optional bool raw_l1_dtlb_refill = 28;
+ optional bool raw_l1_icache = 29;
+ optional bool raw_l1_icache_refill = 30;
+ optional bool raw_l1_itlb_refill = 31;
+ optional bool raw_l2_dcache = 32;
+ optional bool raw_l2_dcache_allocate = 33;
+ optional bool raw_l2_dcache_refill = 34;
+ optional bool raw_l2_dcache_wb = 35;
+ optional bool raw_l2_icache_refill = 36;
+ optional bool raw_l2_itlb = 37;
+ optional bool raw_l3_dcache_allocate = 38;
+ optional bool raw_l3_dcache_refill = 39;
+ optional bool raw_mem_access = 40;
+ optional bool raw_stall_backend = 41;
+ optional bool raw_stall_frontend = 42;
+ optional bool raw_ttbr_write_retired = 43;
+ optional bool alignment_faults = 44;
+ optional bool context_switches = 45;
+ optional bool cpu_clock = 46;
+ optional bool cpu_migrations = 47;
+ optional bool emulation_faults = 48;
+ optional bool major_faults = 49;
+ optional bool minor_faults = 50;
+ optional bool page_faults = 51;
+ optional bool task_clock = 52;
+
+
+ message TracepointSet {
+
+
+ message Asoc {
+
+ optional bool snd_soc_bias_level_done = 1;
+ optional bool snd_soc_bias_level_start = 2;
+ optional bool snd_soc_cache_sync = 3;
+ optional bool snd_soc_dapm_connected = 4;
+ optional bool snd_soc_dapm_done = 5;
+ optional bool snd_soc_dapm_input_path = 6;
+ optional bool snd_soc_dapm_output_path = 7;
+ optional bool snd_soc_dapm_start = 8;
+ optional bool snd_soc_dapm_walk_done = 9;
+ optional bool snd_soc_dapm_widget_event_done = 10;
+ optional bool snd_soc_dapm_widget_event_start = 11;
+ optional bool snd_soc_dapm_widget_power = 12;
+ optional bool snd_soc_jack_irq = 13;
+ optional bool snd_soc_jack_notify = 14;
+ optional bool snd_soc_jack_report = 15;
+
+ };
+ optional Asoc asoc = 1;
+
+
+ message Binder {
+
+ optional bool binder_alloc_lru_end = 1;
+ optional bool binder_alloc_lru_start = 2;
+ optional bool binder_alloc_page_end = 3;
+ optional bool binder_alloc_page_start = 4;
+ optional bool binder_command = 5;
+ optional bool binder_free_lru_end = 6;
+ optional bool binder_free_lru_start = 7;
+ optional bool binder_ioctl = 8;
+ optional bool binder_ioctl_done = 9;
+ optional bool binder_lock = 10;
+ optional bool binder_locked = 11;
+ optional bool binder_read_done = 12;
+ optional bool binder_return = 13;
+ optional bool binder_set_priority = 14;
+ optional bool binder_transaction = 15;
+ optional bool binder_transaction_alloc_buf = 16;
+ optional bool binder_transaction_buffer_release = 17;
+ optional bool binder_transaction_failed_buffer_release = 18;
+ optional bool binder_transaction_fd = 19;
+ optional bool binder_transaction_node_to_ref = 20;
+ optional bool binder_transaction_received = 21;
+ optional bool binder_transaction_ref_to_node = 22;
+ optional bool binder_transaction_ref_to_ref = 23;
+ optional bool binder_unlock = 24;
+ optional bool binder_unmap_kernel_end = 25;
+ optional bool binder_unmap_kernel_start = 26;
+ optional bool binder_unmap_user_end = 27;
+ optional bool binder_unmap_user_start = 28;
+ optional bool binder_update_page_range = 29;
+ optional bool binder_wait_for_work = 30;
+ optional bool binder_write_done = 31;
+
+ };
+ optional Binder binder = 2;
+
+
+ message Block {
+
+ optional bool block_bio_backmerge = 1;
+ optional bool block_bio_bounce = 2;
+ optional bool block_bio_complete = 3;
+ optional bool block_bio_frontmerge = 4;
+ optional bool block_bio_queue = 5;
+ optional bool block_bio_remap = 6;
+ optional bool block_dirty_buffer = 7;
+ optional bool block_getrq = 8;
+ optional bool block_plug = 9;
+ optional bool block_rq_abort = 10;
+ optional bool block_rq_complete = 11;
+ optional bool block_rq_insert = 12;
+ optional bool block_rq_issue = 13;
+ optional bool block_rq_remap = 14;
+ optional bool block_rq_requeue = 15;
+ optional bool block_sleeprq = 16;
+ optional bool block_split = 17;
+ optional bool block_touch_buffer = 18;
+ optional bool block_unplug = 19;
+
+ };
+ optional Block block = 3;
+
+
+ message Cfg80211 {
+
+ optional bool cfg80211_cac_event = 1;
+ optional bool cfg80211_ch_switch_notify = 2;
+ optional bool cfg80211_chandef_dfs_required = 3;
+ optional bool cfg80211_cqm_pktloss_notify = 4;
+ optional bool cfg80211_cqm_rssi_notify = 5;
+ optional bool cfg80211_del_sta = 6;
+ optional bool cfg80211_ft_event = 7;
+ optional bool cfg80211_get_bss = 8;
+ optional bool cfg80211_gtk_rekey_notify = 9;
+ optional bool cfg80211_ibss_joined = 10;
+ optional bool cfg80211_inform_bss_frame = 11;
+ optional bool cfg80211_mgmt_tx_status = 12;
+ optional bool cfg80211_michael_mic_failure = 13;
+ optional bool cfg80211_new_sta = 14;
+ optional bool cfg80211_notify_new_peer_candidate = 15;
+ optional bool cfg80211_pmksa_candidate_notify = 16;
+ optional bool cfg80211_probe_status = 17;
+ optional bool cfg80211_radar_event = 18;
+ optional bool cfg80211_ready_on_channel = 19;
+ optional bool cfg80211_ready_on_channel_expired = 20;
+ optional bool cfg80211_reg_can_beacon = 21;
+ optional bool cfg80211_report_obss_beacon = 22;
+ optional bool cfg80211_report_wowlan_wakeup = 23;
+ optional bool cfg80211_return_bool = 24;
+ optional bool cfg80211_return_bss = 25;
+ optional bool cfg80211_return_u32 = 26;
+ optional bool cfg80211_return_uint = 27;
+ optional bool cfg80211_rx_mgmt = 28;
+ optional bool cfg80211_rx_mlme_mgmt = 29;
+ optional bool cfg80211_rx_spurious_frame = 30;
+ optional bool cfg80211_rx_unexpected_4addr_frame = 31;
+ optional bool cfg80211_rx_unprot_mlme_mgmt = 32;
+ optional bool cfg80211_scan_done = 33;
+ optional bool cfg80211_sched_scan_results = 34;
+ optional bool cfg80211_sched_scan_stopped = 35;
+ optional bool cfg80211_send_assoc_timeout = 36;
+ optional bool cfg80211_send_auth_timeout = 37;
+ optional bool cfg80211_send_rx_assoc = 38;
+ optional bool cfg80211_send_rx_auth = 39;
+ optional bool cfg80211_stop_iface = 40;
+ optional bool cfg80211_tdls_oper_request = 41;
+ optional bool cfg80211_tx_mlme_mgmt = 42;
+ optional bool rdev_abort_scan = 43;
+ optional bool rdev_add_key = 44;
+ optional bool rdev_add_mpath = 45;
+ optional bool rdev_add_station = 46;
+ optional bool rdev_add_tx_ts = 47;
+ optional bool rdev_add_virtual_intf = 48;
+ optional bool rdev_assoc = 49;
+ optional bool rdev_auth = 50;
+ optional bool rdev_cancel_remain_on_channel = 51;
+ optional bool rdev_change_beacon = 52;
+ optional bool rdev_change_bss = 53;
+ optional bool rdev_change_mpath = 54;
+ optional bool rdev_change_station = 55;
+ optional bool rdev_change_virtual_intf = 56;
+ optional bool rdev_channel_switch = 57;
+ optional bool rdev_connect = 58;
+ optional bool rdev_crit_proto_start = 59;
+ optional bool rdev_crit_proto_stop = 60;
+ optional bool rdev_deauth = 61;
+ optional bool rdev_del_key = 62;
+ optional bool rdev_del_mpath = 63;
+ optional bool rdev_del_pmksa = 64;
+ optional bool rdev_del_station = 65;
+ optional bool rdev_del_tx_ts = 66;
+ optional bool rdev_del_virtual_intf = 67;
+ optional bool rdev_disassoc = 68;
+ optional bool rdev_disconnect = 69;
+ optional bool rdev_dump_mpath = 70;
+ optional bool rdev_dump_station = 71;
+ optional bool rdev_dump_survey = 72;
+ optional bool rdev_flush_pmksa = 73;
+ optional bool rdev_get_antenna = 74;
+ optional bool rdev_get_channel = 75;
+ optional bool rdev_get_key = 76;
+ optional bool rdev_get_mesh_config = 77;
+ optional bool rdev_get_mpath = 78;
+ optional bool rdev_get_station = 79;
+ optional bool rdev_get_tx_power = 80;
+ optional bool rdev_join_ibss = 81;
+ optional bool rdev_join_mesh = 82;
+ optional bool rdev_leave_ibss = 83;
+ optional bool rdev_leave_mesh = 84;
+ optional bool rdev_libertas_set_mesh_channel = 85;
+ optional bool rdev_mgmt_frame_register = 86;
+ optional bool rdev_mgmt_tx = 87;
+ optional bool rdev_mgmt_tx_cancel_wait = 88;
+ optional bool rdev_probe_client = 89;
+ optional bool rdev_remain_on_channel = 90;
+ optional bool rdev_resume = 91;
+ optional bool rdev_return_chandef = 92;
+ optional bool rdev_return_int = 93;
+ optional bool rdev_return_int_cookie = 94;
+ optional bool rdev_return_int_int = 95;
+ optional bool rdev_return_int_mesh_config = 96;
+ optional bool rdev_return_int_mpath_info = 97;
+ optional bool rdev_return_int_station_info = 98;
+ optional bool rdev_return_int_survey_info = 99;
+ optional bool rdev_return_int_tx_rx = 100;
+ optional bool rdev_return_void = 101;
+ optional bool rdev_return_void_tx_rx = 102;
+ optional bool rdev_return_wdev = 103;
+ optional bool rdev_rfkill_poll = 104;
+ optional bool rdev_scan = 105;
+ optional bool rdev_sched_scan_start = 106;
+ optional bool rdev_sched_scan_stop = 107;
+ optional bool rdev_set_antenna = 108;
+ optional bool rdev_set_ap_chanwidth = 109;
+ optional bool rdev_set_bitrate_mask = 110;
+ optional bool rdev_set_cqm_rssi_config = 111;
+ optional bool rdev_set_cqm_txe_config = 112;
+ optional bool rdev_set_default_key = 113;
+ optional bool rdev_set_default_mgmt_key = 114;
+ optional bool rdev_set_mac_acl = 115;
+ optional bool rdev_set_monitor_channel = 116;
+ optional bool rdev_set_noack_map = 117;
+ optional bool rdev_set_pmksa = 118;
+ optional bool rdev_set_power_mgmt = 119;
+ optional bool rdev_set_qos_map = 120;
+ optional bool rdev_set_rekey_data = 121;
+ optional bool rdev_set_tx_power = 122;
+ optional bool rdev_set_txq_params = 123;
+ optional bool rdev_set_wakeup = 124;
+ optional bool rdev_set_wds_peer = 125;
+ optional bool rdev_set_wiphy_params = 126;
+ optional bool rdev_start_ap = 127;
+ optional bool rdev_start_p2p_device = 128;
+ optional bool rdev_stop_ap = 129;
+ optional bool rdev_stop_p2p_device = 130;
+ optional bool rdev_suspend = 131;
+ optional bool rdev_tdls_mgmt = 132;
+ optional bool rdev_tdls_oper = 133;
+ optional bool rdev_testmode_cmd = 134;
+ optional bool rdev_testmode_dump = 135;
+ optional bool rdev_update_connect_params = 136;
+ optional bool rdev_update_ft_ies = 137;
+ optional bool rdev_update_mesh_config = 138;
+
+ };
+ optional Cfg80211 cfg80211 = 4;
+
+
+ message Cma {
+
+ optional bool cma_alloc = 1;
+ optional bool cma_alloc_busy_retry = 2;
+ optional bool cma_alloc_start = 3;
+ optional bool cma_release = 4;
+
+ };
+ optional Cma cma = 5;
+
+
+ message Compaction {
+
+ optional bool mm_compaction_begin = 1;
+ optional bool mm_compaction_end = 2;
+ optional bool mm_compaction_isolate_freepages = 3;
+ optional bool mm_compaction_isolate_migratepages = 4;
+ optional bool mm_compaction_migratepages = 5;
+
+ };
+ optional Compaction compaction = 6;
+
+
+ message Cpufreq_interactive {
+
+ optional bool cpufreq_interactive_already = 1;
+ optional bool cpufreq_interactive_boost = 2;
+ optional bool cpufreq_interactive_cpuload = 3;
+ optional bool cpufreq_interactive_load_change = 4;
+ optional bool cpufreq_interactive_notyet = 5;
+ optional bool cpufreq_interactive_setspeed = 6;
+ optional bool cpufreq_interactive_target = 7;
+ optional bool cpufreq_interactive_unboost = 8;
+
+ };
+ optional Cpufreq_interactive cpufreq_interactive = 7;
+
+
+ message Cpufreq_sched {
+
+ optional bool cpufreq_sched_request_opp = 1;
+ optional bool cpufreq_sched_throttled = 2;
+ optional bool cpufreq_sched_update_capacity = 3;
+
+ };
+ optional Cpufreq_sched cpufreq_sched = 8;
+
+
+ message Devfreq {
+
+ optional bool devfreq_msg = 1;
+
+ };
+ optional Devfreq devfreq = 9;
+
+
+ message Dwc3 {
+
+ optional bool dwc3_alloc_request = 1;
+ optional bool dwc3_complete_trb = 2;
+ optional bool dwc3_ctrl_req = 3;
+ optional bool dwc3_ep0 = 4;
+ optional bool dwc3_ep_dequeue = 5;
+ optional bool dwc3_ep_queue = 6;
+ optional bool dwc3_event = 7;
+ optional bool dwc3_free_request = 8;
+ optional bool dwc3_gadget_ep_cmd = 9;
+ optional bool dwc3_gadget_generic_cmd = 10;
+ optional bool dwc3_gadget_giveback = 11;
+ optional bool dwc3_prepare_trb = 12;
+ optional bool dwc3_readl = 13;
+ optional bool dwc3_writel = 14;
+
+ };
+ optional Dwc3 dwc3 = 10;
+
+
+ message Emulation {
+
+ optional bool instruction_emulation = 1;
+
+ };
+ optional Emulation emulation = 11;
+
+
+ message Exception {
+
+ optional bool kernel_panic = 1;
+ optional bool kernel_panic_late = 2;
+ optional bool undef_instr = 3;
+ optional bool unhandled_abort = 4;
+ optional bool user_fault = 5;
+
+ };
+ optional Exception exception = 12;
+
+
+ message Ext4 {
+
+ optional bool ext4_alloc_da_blocks = 1;
+ optional bool ext4_allocate_blocks = 2;
+ optional bool ext4_allocate_inode = 3;
+ optional bool ext4_begin_ordered_truncate = 4;
+ optional bool ext4_collapse_range = 5;
+ optional bool ext4_da_release_space = 6;
+ optional bool ext4_da_reserve_space = 7;
+ optional bool ext4_da_update_reserve_space = 8;
+ optional bool ext4_da_write_begin = 9;
+ optional bool ext4_da_write_end = 10;
+ optional bool ext4_da_write_pages = 11;
+ optional bool ext4_da_write_pages_extent = 12;
+ optional bool ext4_direct_IO_enter = 13;
+ optional bool ext4_direct_IO_exit = 14;
+ optional bool ext4_discard_blocks = 15;
+ optional bool ext4_discard_preallocations = 16;
+ optional bool ext4_drop_inode = 17;
+ optional bool ext4_es_cache_extent = 18;
+ optional bool ext4_es_find_delayed_extent_range_enter = 19;
+ optional bool ext4_es_find_delayed_extent_range_exit = 20;
+ optional bool ext4_es_insert_extent = 21;
+ optional bool ext4_es_lookup_extent_enter = 22;
+ optional bool ext4_es_lookup_extent_exit = 23;
+ optional bool ext4_es_remove_extent = 24;
+ optional bool ext4_es_shrink = 25;
+ optional bool ext4_es_shrink_count = 26;
+ optional bool ext4_es_shrink_scan_enter = 27;
+ optional bool ext4_es_shrink_scan_exit = 28;
+ optional bool ext4_evict_inode = 29;
+ optional bool ext4_ext_convert_to_initialized_enter = 30;
+ optional bool ext4_ext_convert_to_initialized_fastpath = 31;
+ optional bool ext4_ext_handle_unwritten_extents = 32;
+ optional bool ext4_ext_in_cache = 33;
+ optional bool ext4_ext_load_extent = 34;
+ optional bool ext4_ext_map_blocks_enter = 35;
+ optional bool ext4_ext_map_blocks_exit = 36;
+ optional bool ext4_ext_put_in_cache = 37;
+ optional bool ext4_ext_remove_space = 38;
+ optional bool ext4_ext_remove_space_done = 39;
+ optional bool ext4_ext_rm_idx = 40;
+ optional bool ext4_ext_rm_leaf = 41;
+ optional bool ext4_ext_show_extent = 42;
+ optional bool ext4_fallocate_enter = 43;
+ optional bool ext4_fallocate_exit = 44;
+ optional bool ext4_find_delalloc_range = 45;
+ optional bool ext4_forget = 46;
+ optional bool ext4_free_blocks = 47;
+ optional bool ext4_free_inode = 48;
+ optional bool ext4_get_implied_cluster_alloc_exit = 49;
+ optional bool ext4_get_reserved_cluster_alloc = 50;
+ optional bool ext4_ind_map_blocks_enter = 51;
+ optional bool ext4_ind_map_blocks_exit = 52;
+ optional bool ext4_invalidatepage = 53;
+ optional bool ext4_journal_start = 54;
+ optional bool ext4_journal_start_reserved = 55;
+ optional bool ext4_journalled_invalidatepage = 56;
+ optional bool ext4_journalled_write_end = 57;
+ optional bool ext4_load_inode = 58;
+ optional bool ext4_load_inode_bitmap = 59;
+ optional bool ext4_mark_inode_dirty = 60;
+ optional bool ext4_mb_bitmap_load = 61;
+ optional bool ext4_mb_buddy_bitmap_load = 62;
+ optional bool ext4_mb_discard_preallocations = 63;
+ optional bool ext4_mb_new_group_pa = 64;
+ optional bool ext4_mb_new_inode_pa = 65;
+ optional bool ext4_mb_release_group_pa = 66;
+ optional bool ext4_mb_release_inode_pa = 67;
+ optional bool ext4_mballoc_alloc = 68;
+ optional bool ext4_mballoc_discard = 69;
+ optional bool ext4_mballoc_free = 70;
+ optional bool ext4_mballoc_prealloc = 71;
+ optional bool ext4_punch_hole = 72;
+ optional bool ext4_read_block_bitmap_load = 73;
+ optional bool ext4_readpage = 74;
+ optional bool ext4_releasepage = 75;
+ optional bool ext4_remove_blocks = 76;
+ optional bool ext4_request_blocks = 77;
+ optional bool ext4_request_inode = 78;
+ optional bool ext4_sync_file_enter = 79;
+ optional bool ext4_sync_file_exit = 80;
+ optional bool ext4_sync_fs = 81;
+ optional bool ext4_trim_all_free = 82;
+ optional bool ext4_trim_extent = 83;
+ optional bool ext4_truncate_enter = 84;
+ optional bool ext4_truncate_exit = 85;
+ optional bool ext4_unlink_enter = 86;
+ optional bool ext4_unlink_exit = 87;
+ optional bool ext4_write_begin = 88;
+ optional bool ext4_write_end = 89;
+ optional bool ext4_writepage = 90;
+ optional bool ext4_writepages = 91;
+ optional bool ext4_writepages_result = 92;
+ optional bool ext4_zero_range = 93;
+
+ };
+ optional Ext4 ext4 = 13;
+
+
+ message Fence {
+
+ optional bool fence_annotate_wait_on = 1;
+ optional bool fence_destroy = 2;
+ optional bool fence_emit = 3;
+ optional bool fence_enable_signal = 4;
+ optional bool fence_init = 5;
+ optional bool fence_signaled = 6;
+ optional bool fence_wait_end = 7;
+ optional bool fence_wait_start = 8;
+
+ };
+ optional Fence fence = 14;
+
+
+ message Filelock {
+
+ optional bool break_lease_block = 1;
+ optional bool break_lease_noblock = 2;
+ optional bool break_lease_unblock = 3;
+ optional bool generic_add_lease = 4;
+ optional bool generic_delete_lease = 5;
+ optional bool time_out_leases = 6;
+
+ };
+ optional Filelock filelock = 15;
+
+
+ message Filemap {
+
+ optional bool mm_filemap_add_to_page_cache = 1;
+ optional bool mm_filemap_delete_from_page_cache = 2;
+
+ };
+ optional Filemap filemap = 16;
+
+
+ message Gpio {
+
+ optional bool gpio_direction = 1;
+ optional bool gpio_value = 2;
+
+ };
+ optional Gpio gpio = 17;
+
+
+ message I2c {
+
+ optional bool i2c_read = 1;
+ optional bool i2c_reply = 2;
+ optional bool i2c_result = 3;
+ optional bool i2c_write = 4;
+ optional bool smbus_read = 5;
+ optional bool smbus_reply = 6;
+ optional bool smbus_result = 7;
+ optional bool smbus_write = 8;
+
+ };
+ optional I2c i2c = 18;
+
+
+ message Iommu {
+
+ optional bool add_device_to_group = 1;
+ optional bool attach_device_to_domain = 2;
+ optional bool detach_device_from_domain = 3;
+ optional bool io_page_fault = 4;
+ optional bool map = 5;
+ optional bool map_end = 6;
+ optional bool map_sg_end = 7;
+ optional bool map_sg_start = 8;
+ optional bool map_start = 9;
+ optional bool remove_device_from_group = 10;
+ optional bool unmap = 11;
+ optional bool unmap_end = 12;
+ optional bool unmap_start = 13;
+
+ };
+ optional Iommu iommu = 19;
+
+
+ message Ipa {
+
+ optional bool idle_sleep_enter = 1;
+ optional bool idle_sleep_exit = 2;
+ optional bool intr_to_poll = 3;
+ optional bool poll_to_intr = 4;
+ optional bool rmnet_ipa_netifni = 5;
+ optional bool rmnet_ipa_netifrx = 6;
+
+ };
+ optional Ipa ipa = 20;
+
+
+ message Ipi {
+
+ optional bool ipi_entry = 1;
+ optional bool ipi_exit = 2;
+ optional bool ipi_raise = 3;
+
+ };
+ optional Ipi ipi = 21;
+
+
+ message Irq {
+
+ optional bool irq_handler_entry = 1;
+ optional bool irq_handler_exit = 2;
+ optional bool softirq_entry = 3;
+ optional bool softirq_exit = 4;
+ optional bool softirq_raise = 5;
+
+ };
+ optional Irq irq = 22;
+
+
+ message Jbd2 {
+
+ optional bool jbd2_checkpoint = 1;
+ optional bool jbd2_checkpoint_stats = 2;
+ optional bool jbd2_commit_flushing = 3;
+ optional bool jbd2_commit_locking = 4;
+ optional bool jbd2_commit_logging = 5;
+ optional bool jbd2_drop_transaction = 6;
+ optional bool jbd2_end_commit = 7;
+ optional bool jbd2_handle_extend = 8;
+ optional bool jbd2_handle_start = 9;
+ optional bool jbd2_handle_stats = 10;
+ optional bool jbd2_lock_buffer_stall = 11;
+ optional bool jbd2_run_stats = 12;
+ optional bool jbd2_start_commit = 13;
+ optional bool jbd2_submit_inode_data = 14;
+ optional bool jbd2_update_log_tail = 15;
+ optional bool jbd2_write_superblock = 16;
+
+ };
+ optional Jbd2 jbd2 = 23;
+
+
+ message Kgsl {
+
+ optional bool adreno_cmdbatch_fault = 1;
+ optional bool adreno_cmdbatch_queued = 2;
+ optional bool adreno_cmdbatch_recovery = 3;
+ optional bool adreno_cmdbatch_retired = 4;
+ optional bool adreno_cmdbatch_submitted = 5;
+ optional bool adreno_cmdbatch_sync = 6;
+ optional bool adreno_drawctxt_invalidate = 7;
+ optional bool adreno_drawctxt_sleep = 8;
+ optional bool adreno_drawctxt_switch = 9;
+ optional bool adreno_drawctxt_wait_done = 10;
+ optional bool adreno_drawctxt_wait_start = 11;
+ optional bool adreno_drawctxt_wake = 12;
+ optional bool adreno_gpu_fault = 13;
+ optional bool adreno_hw_preempt_clear_to_trig = 14;
+ optional bool adreno_hw_preempt_comp_to_clear = 15;
+ optional bool adreno_hw_preempt_token_submit = 16;
+ optional bool adreno_hw_preempt_trig_to_comp = 17;
+ optional bool adreno_hw_preempt_trig_to_comp_int = 18;
+ optional bool adreno_preempt_done = 19;
+ optional bool adreno_preempt_trigger = 20;
+ optional bool adreno_sp_tp = 21;
+ optional bool dispatch_queue_context = 22;
+ optional bool kgsl_a3xx_irq_status = 23;
+ optional bool kgsl_a4xx_irq_status = 24;
+ optional bool kgsl_a5xx_irq_status = 25;
+ optional bool kgsl_active_count = 26;
+ optional bool kgsl_bus = 27;
+ optional bool kgsl_buslevel = 28;
+ optional bool kgsl_clk = 29;
+ optional bool kgsl_constraint = 30;
+ optional bool kgsl_context_create = 31;
+ optional bool kgsl_context_destroy = 32;
+ optional bool kgsl_context_detach = 33;
+ optional bool kgsl_fire_event = 34;
+ optional bool kgsl_gpubusy = 35;
+ optional bool kgsl_irq = 36;
+ optional bool kgsl_issueibcmds = 37;
+ optional bool kgsl_mem_alloc = 38;
+ optional bool kgsl_mem_free = 39;
+ optional bool kgsl_mem_map = 40;
+ optional bool kgsl_mem_mmap = 41;
+ optional bool kgsl_mem_sync_cache = 42;
+ optional bool kgsl_mem_sync_full_cache = 43;
+ optional bool kgsl_mem_timestamp_free = 44;
+ optional bool kgsl_mem_timestamp_queue = 45;
+ optional bool kgsl_mem_unmapped_area_collision = 46;
+ optional bool kgsl_mmu_pagefault = 47;
+ optional bool kgsl_msg = 48;
+ optional bool kgsl_pagetable_destroy = 49;
+ optional bool kgsl_popp_level = 50;
+ optional bool kgsl_popp_mod = 51;
+ optional bool kgsl_popp_nap = 52;
+ optional bool kgsl_pwr_request_state = 53;
+ optional bool kgsl_pwr_set_state = 54;
+ optional bool kgsl_pwrlevel = 55;
+ optional bool kgsl_pwrstats = 56;
+ optional bool kgsl_rail = 57;
+ optional bool kgsl_readtimestamp = 58;
+ optional bool kgsl_register_event = 59;
+ optional bool kgsl_regwrite = 60;
+ optional bool kgsl_retention_clk = 61;
+ optional bool kgsl_user_pwrlevel_constraint = 62;
+ optional bool kgsl_waittimestamp_entry = 63;
+ optional bool kgsl_waittimestamp_exit = 64;
+ optional bool syncpoint_fence = 65;
+ optional bool syncpoint_fence_expire = 66;
+ optional bool syncpoint_timestamp = 67;
+ optional bool syncpoint_timestamp_expire = 68;
+
+ };
+ optional Kgsl kgsl = 24;
+
+
+ message Kmem {
+
+ optional bool alloc_pages_iommu_end = 1;
+ optional bool alloc_pages_iommu_fail = 2;
+ optional bool alloc_pages_iommu_start = 3;
+ optional bool alloc_pages_sys_end = 4;
+ optional bool alloc_pages_sys_fail = 5;
+ optional bool alloc_pages_sys_start = 6;
+ optional bool dma_alloc_contiguous_retry = 7;
+ optional bool iommu_map_range = 8;
+ optional bool iommu_sec_ptbl_map_range_end = 9;
+ optional bool iommu_sec_ptbl_map_range_start = 10;
+ optional bool ion_alloc_buffer_end = 11;
+ optional bool ion_alloc_buffer_fail = 12;
+ optional bool ion_alloc_buffer_fallback = 13;
+ optional bool ion_alloc_buffer_start = 14;
+ optional bool ion_cp_alloc_retry = 15;
+ optional bool ion_cp_secure_buffer_end = 16;
+ optional bool ion_cp_secure_buffer_start = 17;
+ optional bool ion_prefetching = 18;
+ optional bool ion_secure_cma_add_to_pool_end = 19;
+ optional bool ion_secure_cma_add_to_pool_start = 20;
+ optional bool ion_secure_cma_allocate_end = 21;
+ optional bool ion_secure_cma_allocate_start = 22;
+ optional bool ion_secure_cma_shrink_pool_end = 23;
+ optional bool ion_secure_cma_shrink_pool_start = 24;
+ optional bool kfree = 25;
+ optional bool kmalloc = 26;
+ optional bool kmalloc_node = 27;
+ optional bool kmem_cache_alloc = 28;
+ optional bool kmem_cache_alloc_node = 29;
+ optional bool kmem_cache_free = 30;
+ optional bool migrate_pages_end = 31;
+ optional bool migrate_pages_start = 32;
+ optional bool migrate_retry = 33;
+ optional bool mm_page_alloc = 34;
+ optional bool mm_page_alloc_extfrag = 35;
+ optional bool mm_page_alloc_zone_locked = 36;
+ optional bool mm_page_free = 37;
+ optional bool mm_page_free_batched = 38;
+ optional bool mm_page_pcpu_drain = 39;
+
+ };
+ optional Kmem kmem = 25;
+
+
+ message Lowmemorykiller {
+
+ optional bool lowmemory_kill = 1;
+
+ };
+ optional Lowmemorykiller lowmemorykiller = 26;
+
+
+ message Mdss {
+
+ optional bool mdp_cmd_kickoff = 1;
+ optional bool mdp_cmd_pingpong_done = 2;
+ optional bool mdp_cmd_release_bw = 3;
+ optional bool mdp_cmd_wait_pingpong = 4;
+ optional bool mdp_commit = 5;
+ optional bool mdp_misr_crc = 6;
+ optional bool mdp_mixer_update = 7;
+ optional bool mdp_perf_prefill_calc = 8;
+ optional bool mdp_perf_set_ot = 9;
+ optional bool mdp_perf_set_panic_luts = 10;
+ optional bool mdp_perf_set_qos_luts = 11;
+ optional bool mdp_perf_set_wm_levels = 12;
+ optional bool mdp_perf_update_bus = 13;
+ optional bool mdp_sspp_change = 14;
+ optional bool mdp_sspp_set = 15;
+ optional bool mdp_trace_counter = 16;
+ optional bool mdp_video_underrun_done = 17;
+ optional bool rotator_bw_ao_as_context = 18;
+ optional bool tracing_mark_write = 19;
+
+ };
+ optional Mdss mdss = 27;
+
+
+ message Migrate {
+
+ optional bool mm_migrate_pages = 1;
+ optional bool mm_migrate_pages_start = 2;
+ optional bool mm_numa_migrate_ratelimit = 3;
+
+ };
+ optional Migrate migrate = 28;
+
+
+ message Module {
+
+ optional bool module_free = 1;
+ optional bool module_get = 2;
+ optional bool module_load = 3;
+ optional bool module_put = 4;
+ optional bool module_request = 5;
+
+ };
+ optional Module module = 29;
+
+
+ message Msm_bus {
+
+ optional bool bus_agg_bw = 1;
+ optional bool bus_avail_bw = 2;
+ optional bool bus_bimc_config_limiter = 3;
+ optional bool bus_bke_params = 4;
+ optional bool bus_client_status = 5;
+ optional bool bus_rules_matches = 6;
+ optional bool bus_update_request = 7;
+ optional bool bus_update_request_end = 8;
+
+ };
+ optional Msm_bus msm_bus = 30;
+
+
+ message Msm_low_power {
+
+ optional bool cluster_enter = 1;
+ optional bool cluster_exit = 2;
+ optional bool cpu_idle_enter = 3;
+ optional bool cpu_idle_exit = 4;
+ optional bool cpu_power_select = 5;
+ optional bool pre_pc_cb = 6;
+
+ };
+ optional Msm_low_power msm_low_power = 31;
+
+
+ message Msm_vidc {
+
+ optional bool msm_smem_buffer_iommu_op_end = 1;
+ optional bool msm_smem_buffer_iommu_op_start = 2;
+ optional bool msm_smem_buffer_ion_op_end = 3;
+ optional bool msm_smem_buffer_ion_op_start = 4;
+ optional bool msm_v4l2_vidc_buffer_event_end = 5;
+ optional bool msm_v4l2_vidc_buffer_event_start = 6;
+ optional bool msm_v4l2_vidc_close_end = 7;
+ optional bool msm_v4l2_vidc_close_start = 8;
+ optional bool msm_v4l2_vidc_fw_load_end = 9;
+ optional bool msm_v4l2_vidc_fw_load_start = 10;
+ optional bool msm_v4l2_vidc_open_end = 11;
+ optional bool msm_v4l2_vidc_open_start = 12;
+ optional bool msm_vidc_common_state_change = 13;
+ optional bool venus_hfi_var_done = 14;
+
+ };
+ optional Msm_vidc msm_vidc = 32;
+
+
+ message Napi {
+
+ optional bool napi_poll = 1;
+
+ };
+ optional Napi napi = 33;
+
+
+ message Net {
+
+ optional bool napi_gro_frags_entry = 1;
+ optional bool napi_gro_receive_entry = 2;
+ optional bool net_dev_queue = 3;
+ optional bool net_dev_start_xmit = 4;
+ optional bool net_dev_xmit = 5;
+ optional bool netif_receive_skb = 6;
+ optional bool netif_receive_skb_entry = 7;
+ optional bool netif_rx = 8;
+ optional bool netif_rx_entry = 9;
+ optional bool netif_rx_ni_entry = 10;
+
+ };
+ optional Net net = 34;
+
+
+ message Oom {
+
+ optional bool oom_score_adj_update = 1;
+
+ };
+ optional Oom oom = 35;
+
+
+ message Pagemap {
+
+ optional bool mm_lru_activate = 1;
+ optional bool mm_lru_insertion = 2;
+
+ };
+ optional Pagemap pagemap = 36;
+
+
+ message Perf_trace_counters {
+
+ optional bool perf_trace_user = 1;
+ optional bool sched_switch_with_ctrs = 2;
+
+ };
+ optional Perf_trace_counters perf_trace_counters = 37;
+
+
+ message Power {
+
+ optional bool bw_hwmon_meas = 1;
+ optional bool bw_hwmon_update = 2;
+ optional bool cache_hwmon_meas = 3;
+ optional bool cache_hwmon_update = 4;
+ optional bool clock_disable = 5;
+ optional bool clock_enable = 6;
+ optional bool clock_set_parent = 7;
+ optional bool clock_set_rate = 8;
+ optional bool clock_set_rate_complete = 9;
+ optional bool clock_state = 10;
+ optional bool core_ctl_eval_need = 11;
+ optional bool core_ctl_set_busy = 12;
+ optional bool cpu_capacity = 13;
+ optional bool cpu_frequency = 14;
+ optional bool cpu_frequency_limits = 15;
+ optional bool cpu_frequency_switch_end = 16;
+ optional bool cpu_frequency_switch_start = 17;
+ optional bool cpu_idle = 18;
+ optional bool cpu_mode_detect = 19;
+ optional bool cpufreq_freq_synced = 20;
+ optional bool cpufreq_sampling_event = 21;
+ optional bool dev_pm_qos_add_request = 22;
+ optional bool dev_pm_qos_remove_request = 23;
+ optional bool dev_pm_qos_update_request = 24;
+ optional bool device_pm_callback_end = 25;
+ optional bool device_pm_callback_start = 26;
+ optional bool memlat_dev_meas = 27;
+ optional bool memlat_dev_update = 28;
+ optional bool msmpower_max_ddr = 29;
+ optional bool perf_cl_peak_exit_timer_start = 30;
+ optional bool perf_cl_peak_exit_timer_stop = 31;
+ optional bool pm_qos_add_request = 32;
+ optional bool pm_qos_remove_request = 33;
+ optional bool pm_qos_update_flags = 34;
+ optional bool pm_qos_update_request = 35;
+ optional bool pm_qos_update_request_timeout = 36;
+ optional bool pm_qos_update_target = 37;
+ optional bool power_domain_target = 38;
+ optional bool pstate_sample = 39;
+ optional bool reevaluate_hotplug = 40;
+ optional bool set_max_cpus = 41;
+ optional bool single_cycle_exit_timer_start = 42;
+ optional bool single_cycle_exit_timer_stop = 43;
+ optional bool single_mode_timeout = 44;
+ optional bool suspend_resume = 45;
+ optional bool track_iowait = 46;
+ optional bool wakeup_source_activate = 47;
+ optional bool wakeup_source_deactivate = 48;
+
+ };
+ optional Power power = 38;
+
+
+ message Printk {
+
+ optional bool console = 1;
+
+ };
+ optional Printk printk = 39;
+
+
+ message Random {
+
+ optional bool add_device_randomness = 1;
+ optional bool add_disk_randomness = 2;
+ optional bool add_input_randomness = 3;
+ optional bool credit_entropy_bits = 4;
+ optional bool debit_entropy = 5;
+ optional bool extract_entropy = 6;
+ optional bool extract_entropy_user = 7;
+ optional bool get_random_bytes = 8;
+ optional bool get_random_bytes_arch = 9;
+ optional bool mix_pool_bytes = 10;
+ optional bool mix_pool_bytes_nolock = 11;
+ optional bool push_to_pool = 12;
+ optional bool random_read = 13;
+ optional bool urandom_read = 14;
+ optional bool xfer_secondary_pool = 15;
+
+ };
+ optional Random random = 40;
+
+
+ message Raw_syscalls {
+
+ optional bool sys_enter = 1;
+ optional bool sys_exit = 2;
+
+ };
+ optional Raw_syscalls raw_syscalls = 41;
+
+
+ message Rcu {
+
+ optional bool rcu_utilization = 1;
+
+ };
+ optional Rcu rcu = 42;
+
+
+ message Regmap {
+
+ optional bool regcache_drop_region = 1;
+ optional bool regcache_sync = 2;
+ optional bool regmap_async_complete_done = 3;
+ optional bool regmap_async_complete_start = 4;
+ optional bool regmap_async_io_complete = 5;
+ optional bool regmap_async_write_start = 6;
+ optional bool regmap_cache_bypass = 7;
+ optional bool regmap_cache_only = 8;
+ optional bool regmap_hw_read_done = 9;
+ optional bool regmap_hw_read_start = 10;
+ optional bool regmap_hw_write_done = 11;
+ optional bool regmap_hw_write_start = 12;
+ optional bool regmap_reg_read = 13;
+ optional bool regmap_reg_read_cache = 14;
+ optional bool regmap_reg_write = 15;
+
+ };
+ optional Regmap regmap = 43;
+
+
+ message Regulator {
+
+ optional bool regulator_disable = 1;
+ optional bool regulator_disable_complete = 2;
+ optional bool regulator_enable = 3;
+ optional bool regulator_enable_complete = 4;
+ optional bool regulator_enable_delay = 5;
+ optional bool regulator_set_voltage = 6;
+ optional bool regulator_set_voltage_complete = 7;
+
+ };
+ optional Regulator regulator = 44;
+
+
+ message Rmnet_data {
+
+ optional bool __rmnet_deliver_skb = 1;
+ optional bool rmnet_associate = 2;
+ optional bool rmnet_egress_handler = 3;
+ optional bool rmnet_end_deaggregation = 4;
+ optional bool rmnet_fc_map = 5;
+ optional bool rmnet_fc_qmi = 6;
+ optional bool rmnet_gro_downlink = 7;
+ optional bool rmnet_ingress_handler = 8;
+ optional bool rmnet_map_aggregate = 9;
+ optional bool rmnet_map_checksum_downlink_packet = 10;
+ optional bool rmnet_map_checksum_uplink_packet = 11;
+ optional bool rmnet_map_flush_packet_queue = 12;
+ optional bool rmnet_start_aggregation = 13;
+ optional bool rmnet_start_deaggregation = 14;
+ optional bool rmnet_unassociate = 15;
+ optional bool rmnet_unregister_cb_clear_lepcs = 16;
+ optional bool rmnet_unregister_cb_clear_vnds = 17;
+ optional bool rmnet_unregister_cb_entry = 18;
+ optional bool rmnet_unregister_cb_exit = 19;
+ optional bool rmnet_unregister_cb_unhandled = 20;
+ optional bool rmnet_vnd_start_xmit = 21;
+
+ };
+ optional Rmnet_data rmnet_data = 45;
+
+
+ message Rndis_ipa {
+
+ optional bool rndis_netif_ni = 1;
+ optional bool rndis_status_rcvd = 2;
+ optional bool rndis_tx_dp = 3;
+
+ };
+ optional Rndis_ipa rndis_ipa = 46;
+
+
+ message Rpm {
+
+ optional bool rpm_idle = 1;
+ optional bool rpm_resume = 2;
+ optional bool rpm_return_int = 3;
+ optional bool rpm_suspend = 4;
+
+ };
+ optional Rpm rpm = 47;
+
+
+ message Rpm_smd {
+
+ optional bool rpm_smd_ack_recvd = 1;
+ optional bool rpm_smd_interrupt_notify = 2;
+ optional bool rpm_smd_send_active_set = 3;
+ optional bool rpm_smd_send_sleep_set = 4;
+ optional bool rpm_smd_sleep_set = 5;
+
+ };
+ optional Rpm_smd rpm_smd = 48;
+
+
+ message Sched {
+
+ optional bool sched_blocked_reason = 1;
+ optional bool sched_boost_cpu = 2;
+ optional bool sched_boost_task = 3;
+ optional bool sched_contrib_scale_f = 4;
+ optional bool sched_energy_diff = 5;
+ optional bool sched_energy_perf_deltas = 6;
+ optional bool sched_kthread_stop = 7;
+ optional bool sched_kthread_stop_ret = 8;
+ optional bool sched_load_avg_cpu = 9;
+ optional bool sched_load_avg_task = 10;
+ optional bool sched_migrate_task = 11;
+ optional bool sched_move_numa = 12;
+ optional bool sched_overutilized = 13;
+ optional bool sched_pi_setprio = 14;
+ optional bool sched_process_exec = 15;
+ optional bool sched_process_exit = 16;
+ optional bool sched_process_fork = 17;
+ optional bool sched_process_free = 18;
+ optional bool sched_process_hang = 19;
+ optional bool sched_process_wait = 20;
+ optional bool sched_stat_blocked = 21;
+ optional bool sched_stat_iowait = 22;
+ optional bool sched_stat_runtime = 23;
+ optional bool sched_stat_sleep = 24;
+ optional bool sched_stat_wait = 25;
+ optional bool sched_stick_numa = 26;
+ optional bool sched_swap_numa = 27;
+ optional bool sched_switch = 28;
+ optional bool sched_tune_boostgroup_update = 29;
+ optional bool sched_tune_config = 30;
+ optional bool sched_tune_filter = 31;
+ optional bool sched_tune_tasks_update = 32;
+ optional bool sched_wait_task = 33;
+ optional bool sched_wake_idle_without_ipi = 34;
+ optional bool sched_wakeup = 35;
+ optional bool sched_wakeup_new = 36;
+ optional bool sched_waking = 37;
+ optional bool walt_migration_update_sum = 38;
+ optional bool walt_update_history = 39;
+ optional bool walt_update_task_ravg = 40;
+
+ };
+ optional Sched sched = 49;
+
+
+ message Scm {
+
+ optional bool scm_call_end = 1;
+ optional bool scm_call_start = 2;
+
+ };
+ optional Scm scm = 50;
+
+
+ message Scsi {
+
+ optional bool scsi_dispatch_cmd_done = 1;
+ optional bool scsi_dispatch_cmd_error = 2;
+ optional bool scsi_dispatch_cmd_start = 3;
+ optional bool scsi_dispatch_cmd_timeout = 4;
+ optional bool scsi_eh_wakeup = 5;
+
+ };
+ optional Scsi scsi = 51;
+
+
+ message Signal {
+
+ optional bool signal_deliver = 1;
+ optional bool signal_generate = 2;
+
+ };
+ optional Signal signal = 52;
+
+
+ message Skb {
+
+ optional bool consume_skb = 1;
+ optional bool kfree_skb = 2;
+ optional bool print_skb_gso = 3;
+ optional bool skb_copy_datagram_iovec = 4;
+
+ };
+ optional Skb skb = 53;
+
+
+ message Sock {
+
+ optional bool sock_exceed_buf_limit = 1;
+ optional bool sock_rcvqueue_full = 2;
+
+ };
+ optional Sock sock = 54;
+
+
+ message Spi {
+
+ optional bool spi_master_busy = 1;
+ optional bool spi_master_idle = 2;
+ optional bool spi_message_done = 3;
+ optional bool spi_message_start = 4;
+ optional bool spi_message_submit = 5;
+ optional bool spi_transfer_start = 6;
+ optional bool spi_transfer_stop = 7;
+
+ };
+ optional Spi spi = 55;
+
+
+ message Swiotlb {
+
+ optional bool swiotlb_bounced = 1;
+
+ };
+ optional Swiotlb swiotlb = 56;
+
+
+ message Sync {
+
+ optional bool sync_pt = 1;
+ optional bool sync_timeline = 2;
+ optional bool sync_wait = 3;
+
+ };
+ optional Sync sync = 57;
+
+
+ message Task {
+
+ optional bool task_newtask = 1;
+ optional bool task_rename = 2;
+
+ };
+ optional Task task = 58;
+
+
+ message Thermal {
+
+ optional bool bcl_hw_event = 1;
+ optional bool bcl_hw_mitigation = 2;
+ optional bool bcl_hw_mitigation_event = 3;
+ optional bool bcl_hw_reg_access = 4;
+ optional bool bcl_hw_sensor_reading = 5;
+ optional bool bcl_hw_state_event = 6;
+ optional bool bcl_sw_mitigation = 7;
+ optional bool bcl_sw_mitigation_event = 8;
+ optional bool cdev_update = 9;
+ optional bool thermal_post_core_offline = 10;
+ optional bool thermal_post_core_online = 11;
+ optional bool thermal_post_frequency_mit = 12;
+ optional bool thermal_power_cpu_get_power = 13;
+ optional bool thermal_power_cpu_limit = 14;
+ optional bool thermal_pre_core_offline = 15;
+ optional bool thermal_pre_core_online = 16;
+ optional bool thermal_pre_frequency_mit = 17;
+ optional bool thermal_temperature = 18;
+ optional bool thermal_zone_trip = 19;
+ optional bool tsens_read = 20;
+ optional bool tsens_threshold_clear = 21;
+ optional bool tsens_threshold_hit = 22;
+
+ };
+ optional Thermal thermal = 59;
+
+
+ message Timer {
+
+ optional bool hrtimer_cancel = 1;
+ optional bool hrtimer_expire_entry = 2;
+ optional bool hrtimer_expire_exit = 3;
+ optional bool hrtimer_init = 4;
+ optional bool hrtimer_start = 5;
+ optional bool itimer_expire = 6;
+ optional bool itimer_state = 7;
+ optional bool tick_stop = 8;
+ optional bool timer_cancel = 9;
+ optional bool timer_expire_entry = 10;
+ optional bool timer_expire_exit = 11;
+ optional bool timer_init = 12;
+ optional bool timer_start = 13;
+
+ };
+ optional Timer timer = 60;
+
+
+ message Tracer_pkt {
+
+ optional bool tracer_pkt_event = 1;
+
+ };
+ optional Tracer_pkt tracer_pkt = 61;
+
+
+ message Udp {
+
+ optional bool udp_fail_queue_rcv_skb = 1;
+
+ };
+ optional Udp udp = 62;
+
+
+ message Ufs {
+
+ optional bool ufshcd_auto_bkops_state = 1;
+ optional bool ufshcd_clk_gating = 2;
+ optional bool ufshcd_clk_scaling = 3;
+ optional bool ufshcd_command = 4;
+ optional bool ufshcd_hibern8_on_idle = 5;
+ optional bool ufshcd_init = 6;
+ optional bool ufshcd_profile_clk_gating = 7;
+ optional bool ufshcd_profile_clk_scaling = 8;
+ optional bool ufshcd_profile_hibern8 = 9;
+ optional bool ufshcd_runtime_resume = 10;
+ optional bool ufshcd_runtime_suspend = 11;
+ optional bool ufshcd_system_resume = 12;
+ optional bool ufshcd_system_suspend = 13;
+
+ };
+ optional Ufs ufs = 63;
+
+
+ message V4l2 {
+
+ optional bool v4l2_dqbuf = 1;
+ optional bool v4l2_qbuf = 2;
+
+ };
+ optional V4l2 v4l2 = 64;
+
+
+ message Vmscan {
+
+ optional bool mm_shrink_slab_end = 1;
+ optional bool mm_shrink_slab_start = 2;
+ optional bool mm_vmscan_direct_reclaim_begin = 3;
+ optional bool mm_vmscan_direct_reclaim_end = 4;
+ optional bool mm_vmscan_kswapd_sleep = 5;
+ optional bool mm_vmscan_kswapd_wake = 6;
+ optional bool mm_vmscan_lru_isolate = 7;
+ optional bool mm_vmscan_lru_shrink_inactive = 8;
+ optional bool mm_vmscan_memcg_isolate = 9;
+ optional bool mm_vmscan_memcg_reclaim_begin = 10;
+ optional bool mm_vmscan_memcg_reclaim_end = 11;
+ optional bool mm_vmscan_memcg_softlimit_reclaim_begin = 12;
+ optional bool mm_vmscan_memcg_softlimit_reclaim_end = 13;
+ optional bool mm_vmscan_wakeup_kswapd = 14;
+ optional bool mm_vmscan_writepage = 15;
+
+ };
+ optional Vmscan vmscan = 65;
+
+
+ message Workqueue {
+
+ optional bool workqueue_activate_work = 1;
+ optional bool workqueue_execute_end = 2;
+ optional bool workqueue_execute_start = 3;
+ optional bool workqueue_queue_work = 4;
+
+ };
+ optional Workqueue workqueue = 66;
+
+
+ message Writeback {
+
+ optional bool balance_dirty_pages = 1;
+ optional bool bdi_dirty_ratelimit = 2;
+ optional bool global_dirty_state = 3;
+ optional bool wbc_writepage = 4;
+ optional bool writeback_bdi_register = 5;
+ optional bool writeback_bdi_unregister = 6;
+ optional bool writeback_congestion_wait = 7;
+ optional bool writeback_dirty_inode = 8;
+ optional bool writeback_dirty_inode_start = 9;
+ optional bool writeback_dirty_page = 10;
+ optional bool writeback_exec = 11;
+ optional bool writeback_nowork = 12;
+ optional bool writeback_pages_written = 13;
+ optional bool writeback_queue = 14;
+ optional bool writeback_queue_io = 15;
+ optional bool writeback_sb_inodes_requeue = 16;
+ optional bool writeback_single_inode = 17;
+ optional bool writeback_single_inode_start = 18;
+ optional bool writeback_start = 19;
+ optional bool writeback_wait = 20;
+ optional bool writeback_wait_iff_congested = 21;
+ optional bool writeback_wake_background = 22;
+ optional bool writeback_write_inode = 23;
+ optional bool writeback_write_inode_start = 24;
+ optional bool writeback_written = 25;
+
+ };
+ optional Writeback writeback = 67;
+
+
+ message Xhci_hcd {
+
+ optional bool xhci_address_ctx = 1;
+ optional bool xhci_cmd_completion = 2;
+ optional bool xhci_dbg_address = 3;
+ optional bool xhci_dbg_cancel_urb = 4;
+ optional bool xhci_dbg_context_change = 5;
+ optional bool xhci_dbg_init = 6;
+ optional bool xhci_dbg_quirks = 7;
+ optional bool xhci_dbg_reset_ep = 8;
+ optional bool xhci_dbg_ring_expansion = 9;
+
+ };
+ optional Xhci_hcd xhci_hcd = 68;
+
+
+ };
+ optional TracepointSet tracepoints = 53;
+};
+
+message PerfConfigElement {
+ optional CounterSet counter_set = 1;
+ optional bool as_group = 2 [ default = false ];
+ optional uint32 sampling_period = 3;
+};
+
+// The configuration for a profiling session.
+message ProfilingConfig {
+ // Average number of seconds between perf profile collections (if
+ // set to 100, then over time we want to see a perf profile
+ // collected every 100 seconds). The actual time within the interval
+ // for the collection is chosen randomly.
+ optional uint32 collection_interval_in_s = 1;
+
+ // Use the specified fixed seed for random number generation (unit
+ // testing)
+ optional uint32 use_fixed_seed = 2;
+
+ // Number of times to iterate through main
+ // loop. Value of zero indicates that we should loop forever.
+ optional uint32 main_loop_iterations = 3;
+
+ // Destination directory (where to write profiles).
+ optional string destination_directory = 4;
+ // Config directory (where to read configs).
+ optional string config_directory = 5;
+ // Full path to 'perf' executable.
+ optional string perf_path = 6;
+
+ // Desired sampling period (passed to perf -c option). Small
+ // sampling periods can perturb the collected profiles, so enforce
+ // min/max. A value of 0 means perf default. sampling_frequency
+ // takes priority.
+ optional uint32 sampling_period = 7;
+ // Desired sampling frequency (passed to perf -f option). A value of 0
+ // means using sampling_period or default.
+ optional uint32 sampling_frequency = 22;
+ // Length of time to collect samples (number of seconds for 'perf
+ // record -a' run).
+ optional uint32 sample_duration_in_s = 8;
+
+ // If this parameter is non-zero it will cause perfprofd to
+ // exit immediately if the build type is not userdebug or eng.
+ // Currently defaults to 1 (true).
+ optional bool only_debug_build = 9;
+
+ // If the "mpdecision" service is running at the point we are ready
+ // to kick off a profiling run, then temporarily disable the service
+ // and hard-wire all cores on prior to the collection run, provided
+ // that the duration of the recording is less than or equal to the value of
+ // 'hardwire_cpus_max_duration'.
+ optional bool hardwire_cpus = 10;
+ optional uint32 hardwire_cpus_max_duration_in_s = 11;
+
+ // Maximum number of unprocessed profiles we can accumulate in the
+ // destination directory. Once we reach this limit, we continue
+ // to collect, but we just overwrite the most recent profile.
+ optional uint32 max_unprocessed_profiles = 12;
+
+ // If set to 1, pass the -g option when invoking 'perf' (requests
+ // stack traces as opposed to flat profile).
+ optional bool stack_profile = 13;
+
+ // Control collection of various additional profile tags
+ optional bool collect_cpu_utilization = 14;
+ optional bool collect_charging_state = 15;
+ optional bool collect_booting = 16;
+ optional bool collect_camera_active = 17;
+
+ // The pid of the process to profile. May be negative, in which case
+ // the whole system will be profiled.
+ optional int32 process = 18;
+
+ // Whether to use a symbolizer on-device.
+ optional bool use_elf_symbolizer = 19;
+
+ // Whether to send the result to dropbox.
+ optional bool send_to_dropbox = 20;
+
+ // If true, use libz to compress the output proto.
+ optional bool compress = 21;
+
+ repeated PerfConfigElement event_config = 23;
+};
diff --git a/perfprofd/perfprofd_counters.cc b/perfprofd/perfprofd_counters.cc
new file mode 100644
index 0000000..448ed0c
--- /dev/null
+++ b/perfprofd/perfprofd_counters.cc
@@ -0,0 +1,2243 @@
+/*
+ *
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "perfprofd_counters.h"
+
+#include "perfprofd_config.pb.h"
+
+namespace android {
+namespace perfprofd {
+
+std::vector<const char*> GenerateEventsString(const CounterSet& counter_set) {
+ std::vector<const char*> result;
+
+ if (counter_set.has_branch_load_misses() && counter_set.branch_load_misses())
+ result.push_back("branch-load-misses");
+ if (counter_set.has_branch_loads() && counter_set.branch_loads())
+ result.push_back("branch-loads");
+ if (counter_set.has_branch_store_misses() && counter_set.branch_store_misses())
+ result.push_back("branch-store-misses");
+ if (counter_set.has_branch_stores() && counter_set.branch_stores())
+ result.push_back("branch-stores");
+ if (counter_set.has_l1_dcache_load_misses() && counter_set.l1_dcache_load_misses())
+ result.push_back("L1-dcache-load-misses");
+ if (counter_set.has_l1_dcache_loads() && counter_set.l1_dcache_loads())
+ result.push_back("L1-dcache-loads");
+ if (counter_set.has_l1_dcache_store_misses() && counter_set.l1_dcache_store_misses())
+ result.push_back("L1-dcache-store-misses");
+ if (counter_set.has_l1_dcache_stores() && counter_set.l1_dcache_stores())
+ result.push_back("L1-dcache-stores");
+ if (counter_set.has_branch_misses() && counter_set.branch_misses())
+ result.push_back("branch-misses");
+ if (counter_set.has_cache_misses() && counter_set.cache_misses())
+ result.push_back("cache-misses");
+ if (counter_set.has_cache_references() && counter_set.cache_references())
+ result.push_back("cache-references");
+ if (counter_set.has_cpu_cycles() && counter_set.cpu_cycles())
+ result.push_back("cpu-cycles");
+ if (counter_set.has_instructions() && counter_set.instructions())
+ result.push_back("instructions");
+ if (counter_set.has_raw_br_mis_pred() && counter_set.raw_br_mis_pred())
+ result.push_back("raw-br-mis-pred");
+ if (counter_set.has_raw_br_mis_pred_retired() && counter_set.raw_br_mis_pred_retired())
+ result.push_back("raw-br-mis-pred-retired");
+ if (counter_set.has_raw_br_pred() && counter_set.raw_br_pred())
+ result.push_back("raw-br-pred");
+ if (counter_set.has_raw_br_retired() && counter_set.raw_br_retired())
+ result.push_back("raw-br-retired");
+ if (counter_set.has_raw_bus_access() && counter_set.raw_bus_access())
+ result.push_back("raw-bus-access");
+ if (counter_set.has_raw_cpu_cycles() && counter_set.raw_cpu_cycles())
+ result.push_back("raw-cpu-cycles");
+ if (counter_set.has_raw_exception_return() && counter_set.raw_exception_return())
+ result.push_back("raw-exception-return");
+ if (counter_set.has_raw_exception_taken() && counter_set.raw_exception_taken())
+ result.push_back("raw-exception-taken");
+ if (counter_set.has_raw_inst_spec() && counter_set.raw_inst_spec())
+ result.push_back("raw-inst-spec");
+ if (counter_set.has_raw_instruction_retired() && counter_set.raw_instruction_retired())
+ result.push_back("raw-instruction-retired");
+ if (counter_set.has_raw_l1_dcache() && counter_set.raw_l1_dcache())
+ result.push_back("raw-l1-dcache");
+ if (counter_set.has_raw_l1_dcache_allocate() && counter_set.raw_l1_dcache_allocate())
+ result.push_back("raw-l1-dcache-allocate");
+ if (counter_set.has_raw_l1_dcache_refill() && counter_set.raw_l1_dcache_refill())
+ result.push_back("raw-l1-dcache-refill");
+ if (counter_set.has_raw_l1_dtlb() && counter_set.raw_l1_dtlb())
+ result.push_back("raw-l1-dtlb");
+ if (counter_set.has_raw_l1_dtlb_refill() && counter_set.raw_l1_dtlb_refill())
+ result.push_back("raw-l1-dtlb-refill");
+ if (counter_set.has_raw_l1_icache() && counter_set.raw_l1_icache())
+ result.push_back("raw-l1-icache");
+ if (counter_set.has_raw_l1_icache_refill() && counter_set.raw_l1_icache_refill())
+ result.push_back("raw-l1-icache-refill");
+ if (counter_set.has_raw_l1_itlb_refill() && counter_set.raw_l1_itlb_refill())
+ result.push_back("raw-l1-itlb-refill");
+ if (counter_set.has_raw_l2_dcache() && counter_set.raw_l2_dcache())
+ result.push_back("raw-l2-dcache");
+ if (counter_set.has_raw_l2_dcache_allocate() && counter_set.raw_l2_dcache_allocate())
+ result.push_back("raw-l2-dcache-allocate");
+ if (counter_set.has_raw_l2_dcache_refill() && counter_set.raw_l2_dcache_refill())
+ result.push_back("raw-l2-dcache-refill");
+ if (counter_set.has_raw_l2_dcache_wb() && counter_set.raw_l2_dcache_wb())
+ result.push_back("raw-l2-dcache-wb");
+ if (counter_set.has_raw_l2_icache_refill() && counter_set.raw_l2_icache_refill())
+ result.push_back("raw-l2-icache-refill");
+ if (counter_set.has_raw_l2_itlb() && counter_set.raw_l2_itlb())
+ result.push_back("raw-l2-itlb");
+ if (counter_set.has_raw_l3_dcache_allocate() && counter_set.raw_l3_dcache_allocate())
+ result.push_back("raw-l3-dcache-allocate");
+ if (counter_set.has_raw_l3_dcache_refill() && counter_set.raw_l3_dcache_refill())
+ result.push_back("raw-l3-dcache-refill");
+ if (counter_set.has_raw_mem_access() && counter_set.raw_mem_access())
+ result.push_back("raw-mem-access");
+ if (counter_set.has_raw_stall_backend() && counter_set.raw_stall_backend())
+ result.push_back("raw-stall-backend");
+ if (counter_set.has_raw_stall_frontend() && counter_set.raw_stall_frontend())
+ result.push_back("raw-stall-frontend");
+ if (counter_set.has_raw_ttbr_write_retired() && counter_set.raw_ttbr_write_retired())
+ result.push_back("raw-ttbr-write-retired");
+ if (counter_set.has_alignment_faults() && counter_set.alignment_faults())
+ result.push_back("alignment-faults");
+ if (counter_set.has_context_switches() && counter_set.context_switches())
+ result.push_back("context-switches");
+ if (counter_set.has_cpu_clock() && counter_set.cpu_clock())
+ result.push_back("cpu-clock");
+ if (counter_set.has_cpu_migrations() && counter_set.cpu_migrations())
+ result.push_back("cpu-migrations");
+ if (counter_set.has_emulation_faults() && counter_set.emulation_faults())
+ result.push_back("emulation-faults");
+ if (counter_set.has_major_faults() && counter_set.major_faults())
+ result.push_back("major-faults");
+ if (counter_set.has_minor_faults() && counter_set.minor_faults())
+ result.push_back("minor-faults");
+ if (counter_set.has_page_faults() && counter_set.page_faults())
+ result.push_back("page-faults");
+ if (counter_set.has_task_clock() && counter_set.task_clock())
+ result.push_back("task-clock");
+
+ if (counter_set.has_tracepoints()) {
+ const auto& tracepoints = counter_set.tracepoints();
+
+
+ if (tracepoints.has_asoc()) {
+ const auto& asoc = tracepoints.asoc();
+
+ if (asoc.has_snd_soc_bias_level_done() && asoc.snd_soc_bias_level_done())
+ result.push_back("asoc:snd_soc_bias_level_done");
+ if (asoc.has_snd_soc_bias_level_start() && asoc.snd_soc_bias_level_start())
+ result.push_back("asoc:snd_soc_bias_level_start");
+ if (asoc.has_snd_soc_cache_sync() && asoc.snd_soc_cache_sync())
+ result.push_back("asoc:snd_soc_cache_sync");
+ if (asoc.has_snd_soc_dapm_connected() && asoc.snd_soc_dapm_connected())
+ result.push_back("asoc:snd_soc_dapm_connected");
+ if (asoc.has_snd_soc_dapm_done() && asoc.snd_soc_dapm_done())
+ result.push_back("asoc:snd_soc_dapm_done");
+ if (asoc.has_snd_soc_dapm_input_path() && asoc.snd_soc_dapm_input_path())
+ result.push_back("asoc:snd_soc_dapm_input_path");
+ if (asoc.has_snd_soc_dapm_output_path() && asoc.snd_soc_dapm_output_path())
+ result.push_back("asoc:snd_soc_dapm_output_path");
+ if (asoc.has_snd_soc_dapm_start() && asoc.snd_soc_dapm_start())
+ result.push_back("asoc:snd_soc_dapm_start");
+ if (asoc.has_snd_soc_dapm_walk_done() && asoc.snd_soc_dapm_walk_done())
+ result.push_back("asoc:snd_soc_dapm_walk_done");
+ if (asoc.has_snd_soc_dapm_widget_event_done() && asoc.snd_soc_dapm_widget_event_done())
+ result.push_back("asoc:snd_soc_dapm_widget_event_done");
+ if (asoc.has_snd_soc_dapm_widget_event_start() && asoc.snd_soc_dapm_widget_event_start())
+ result.push_back("asoc:snd_soc_dapm_widget_event_start");
+ if (asoc.has_snd_soc_dapm_widget_power() && asoc.snd_soc_dapm_widget_power())
+ result.push_back("asoc:snd_soc_dapm_widget_power");
+ if (asoc.has_snd_soc_jack_irq() && asoc.snd_soc_jack_irq())
+ result.push_back("asoc:snd_soc_jack_irq");
+ if (asoc.has_snd_soc_jack_notify() && asoc.snd_soc_jack_notify())
+ result.push_back("asoc:snd_soc_jack_notify");
+ if (asoc.has_snd_soc_jack_report() && asoc.snd_soc_jack_report())
+ result.push_back("asoc:snd_soc_jack_report");
+ }
+
+ if (tracepoints.has_binder()) {
+ const auto& binder = tracepoints.binder();
+
+ if (binder.has_binder_alloc_lru_end() && binder.binder_alloc_lru_end())
+ result.push_back("binder:binder_alloc_lru_end");
+ if (binder.has_binder_alloc_lru_start() && binder.binder_alloc_lru_start())
+ result.push_back("binder:binder_alloc_lru_start");
+ if (binder.has_binder_alloc_page_end() && binder.binder_alloc_page_end())
+ result.push_back("binder:binder_alloc_page_end");
+ if (binder.has_binder_alloc_page_start() && binder.binder_alloc_page_start())
+ result.push_back("binder:binder_alloc_page_start");
+ if (binder.has_binder_command() && binder.binder_command())
+ result.push_back("binder:binder_command");
+ if (binder.has_binder_free_lru_end() && binder.binder_free_lru_end())
+ result.push_back("binder:binder_free_lru_end");
+ if (binder.has_binder_free_lru_start() && binder.binder_free_lru_start())
+ result.push_back("binder:binder_free_lru_start");
+ if (binder.has_binder_ioctl() && binder.binder_ioctl())
+ result.push_back("binder:binder_ioctl");
+ if (binder.has_binder_ioctl_done() && binder.binder_ioctl_done())
+ result.push_back("binder:binder_ioctl_done");
+ if (binder.has_binder_lock() && binder.binder_lock())
+ result.push_back("binder:binder_lock");
+ if (binder.has_binder_locked() && binder.binder_locked())
+ result.push_back("binder:binder_locked");
+ if (binder.has_binder_read_done() && binder.binder_read_done())
+ result.push_back("binder:binder_read_done");
+ if (binder.has_binder_return() && binder.binder_return())
+ result.push_back("binder:binder_return");
+ if (binder.has_binder_set_priority() && binder.binder_set_priority())
+ result.push_back("binder:binder_set_priority");
+ if (binder.has_binder_transaction() && binder.binder_transaction())
+ result.push_back("binder:binder_transaction");
+ if (binder.has_binder_transaction_alloc_buf() && binder.binder_transaction_alloc_buf())
+ result.push_back("binder:binder_transaction_alloc_buf");
+ if (binder.has_binder_transaction_buffer_release() && binder.binder_transaction_buffer_release())
+ result.push_back("binder:binder_transaction_buffer_release");
+ if (binder.has_binder_transaction_failed_buffer_release() && binder.binder_transaction_failed_buffer_release())
+ result.push_back("binder:binder_transaction_failed_buffer_release");
+ if (binder.has_binder_transaction_fd() && binder.binder_transaction_fd())
+ result.push_back("binder:binder_transaction_fd");
+ if (binder.has_binder_transaction_node_to_ref() && binder.binder_transaction_node_to_ref())
+ result.push_back("binder:binder_transaction_node_to_ref");
+ if (binder.has_binder_transaction_received() && binder.binder_transaction_received())
+ result.push_back("binder:binder_transaction_received");
+ if (binder.has_binder_transaction_ref_to_node() && binder.binder_transaction_ref_to_node())
+ result.push_back("binder:binder_transaction_ref_to_node");
+ if (binder.has_binder_transaction_ref_to_ref() && binder.binder_transaction_ref_to_ref())
+ result.push_back("binder:binder_transaction_ref_to_ref");
+ if (binder.has_binder_unlock() && binder.binder_unlock())
+ result.push_back("binder:binder_unlock");
+ if (binder.has_binder_unmap_kernel_end() && binder.binder_unmap_kernel_end())
+ result.push_back("binder:binder_unmap_kernel_end");
+ if (binder.has_binder_unmap_kernel_start() && binder.binder_unmap_kernel_start())
+ result.push_back("binder:binder_unmap_kernel_start");
+ if (binder.has_binder_unmap_user_end() && binder.binder_unmap_user_end())
+ result.push_back("binder:binder_unmap_user_end");
+ if (binder.has_binder_unmap_user_start() && binder.binder_unmap_user_start())
+ result.push_back("binder:binder_unmap_user_start");
+ if (binder.has_binder_update_page_range() && binder.binder_update_page_range())
+ result.push_back("binder:binder_update_page_range");
+ if (binder.has_binder_wait_for_work() && binder.binder_wait_for_work())
+ result.push_back("binder:binder_wait_for_work");
+ if (binder.has_binder_write_done() && binder.binder_write_done())
+ result.push_back("binder:binder_write_done");
+ }
+
+ if (tracepoints.has_block()) {
+ const auto& block = tracepoints.block();
+
+ if (block.has_block_bio_backmerge() && block.block_bio_backmerge())
+ result.push_back("block:block_bio_backmerge");
+ if (block.has_block_bio_bounce() && block.block_bio_bounce())
+ result.push_back("block:block_bio_bounce");
+ if (block.has_block_bio_complete() && block.block_bio_complete())
+ result.push_back("block:block_bio_complete");
+ if (block.has_block_bio_frontmerge() && block.block_bio_frontmerge())
+ result.push_back("block:block_bio_frontmerge");
+ if (block.has_block_bio_queue() && block.block_bio_queue())
+ result.push_back("block:block_bio_queue");
+ if (block.has_block_bio_remap() && block.block_bio_remap())
+ result.push_back("block:block_bio_remap");
+ if (block.has_block_dirty_buffer() && block.block_dirty_buffer())
+ result.push_back("block:block_dirty_buffer");
+ if (block.has_block_getrq() && block.block_getrq())
+ result.push_back("block:block_getrq");
+ if (block.has_block_plug() && block.block_plug())
+ result.push_back("block:block_plug");
+ if (block.has_block_rq_abort() && block.block_rq_abort())
+ result.push_back("block:block_rq_abort");
+ if (block.has_block_rq_complete() && block.block_rq_complete())
+ result.push_back("block:block_rq_complete");
+ if (block.has_block_rq_insert() && block.block_rq_insert())
+ result.push_back("block:block_rq_insert");
+ if (block.has_block_rq_issue() && block.block_rq_issue())
+ result.push_back("block:block_rq_issue");
+ if (block.has_block_rq_remap() && block.block_rq_remap())
+ result.push_back("block:block_rq_remap");
+ if (block.has_block_rq_requeue() && block.block_rq_requeue())
+ result.push_back("block:block_rq_requeue");
+ if (block.has_block_sleeprq() && block.block_sleeprq())
+ result.push_back("block:block_sleeprq");
+ if (block.has_block_split() && block.block_split())
+ result.push_back("block:block_split");
+ if (block.has_block_touch_buffer() && block.block_touch_buffer())
+ result.push_back("block:block_touch_buffer");
+ if (block.has_block_unplug() && block.block_unplug())
+ result.push_back("block:block_unplug");
+ }
+
+ if (tracepoints.has_cfg80211()) {
+ const auto& cfg80211 = tracepoints.cfg80211();
+
+ if (cfg80211.has_cfg80211_cac_event() && cfg80211.cfg80211_cac_event())
+ result.push_back("cfg80211:cfg80211_cac_event");
+ if (cfg80211.has_cfg80211_ch_switch_notify() && cfg80211.cfg80211_ch_switch_notify())
+ result.push_back("cfg80211:cfg80211_ch_switch_notify");
+ if (cfg80211.has_cfg80211_chandef_dfs_required() && cfg80211.cfg80211_chandef_dfs_required())
+ result.push_back("cfg80211:cfg80211_chandef_dfs_required");
+ if (cfg80211.has_cfg80211_cqm_pktloss_notify() && cfg80211.cfg80211_cqm_pktloss_notify())
+ result.push_back("cfg80211:cfg80211_cqm_pktloss_notify");
+ if (cfg80211.has_cfg80211_cqm_rssi_notify() && cfg80211.cfg80211_cqm_rssi_notify())
+ result.push_back("cfg80211:cfg80211_cqm_rssi_notify");
+ if (cfg80211.has_cfg80211_del_sta() && cfg80211.cfg80211_del_sta())
+ result.push_back("cfg80211:cfg80211_del_sta");
+ if (cfg80211.has_cfg80211_ft_event() && cfg80211.cfg80211_ft_event())
+ result.push_back("cfg80211:cfg80211_ft_event");
+ if (cfg80211.has_cfg80211_get_bss() && cfg80211.cfg80211_get_bss())
+ result.push_back("cfg80211:cfg80211_get_bss");
+ if (cfg80211.has_cfg80211_gtk_rekey_notify() && cfg80211.cfg80211_gtk_rekey_notify())
+ result.push_back("cfg80211:cfg80211_gtk_rekey_notify");
+ if (cfg80211.has_cfg80211_ibss_joined() && cfg80211.cfg80211_ibss_joined())
+ result.push_back("cfg80211:cfg80211_ibss_joined");
+ if (cfg80211.has_cfg80211_inform_bss_frame() && cfg80211.cfg80211_inform_bss_frame())
+ result.push_back("cfg80211:cfg80211_inform_bss_frame");
+ if (cfg80211.has_cfg80211_mgmt_tx_status() && cfg80211.cfg80211_mgmt_tx_status())
+ result.push_back("cfg80211:cfg80211_mgmt_tx_status");
+ if (cfg80211.has_cfg80211_michael_mic_failure() && cfg80211.cfg80211_michael_mic_failure())
+ result.push_back("cfg80211:cfg80211_michael_mic_failure");
+ if (cfg80211.has_cfg80211_new_sta() && cfg80211.cfg80211_new_sta())
+ result.push_back("cfg80211:cfg80211_new_sta");
+ if (cfg80211.has_cfg80211_notify_new_peer_candidate() && cfg80211.cfg80211_notify_new_peer_candidate())
+ result.push_back("cfg80211:cfg80211_notify_new_peer_candidate");
+ if (cfg80211.has_cfg80211_pmksa_candidate_notify() && cfg80211.cfg80211_pmksa_candidate_notify())
+ result.push_back("cfg80211:cfg80211_pmksa_candidate_notify");
+ if (cfg80211.has_cfg80211_probe_status() && cfg80211.cfg80211_probe_status())
+ result.push_back("cfg80211:cfg80211_probe_status");
+ if (cfg80211.has_cfg80211_radar_event() && cfg80211.cfg80211_radar_event())
+ result.push_back("cfg80211:cfg80211_radar_event");
+ if (cfg80211.has_cfg80211_ready_on_channel() && cfg80211.cfg80211_ready_on_channel())
+ result.push_back("cfg80211:cfg80211_ready_on_channel");
+ if (cfg80211.has_cfg80211_ready_on_channel_expired() && cfg80211.cfg80211_ready_on_channel_expired())
+ result.push_back("cfg80211:cfg80211_ready_on_channel_expired");
+ if (cfg80211.has_cfg80211_reg_can_beacon() && cfg80211.cfg80211_reg_can_beacon())
+ result.push_back("cfg80211:cfg80211_reg_can_beacon");
+ if (cfg80211.has_cfg80211_report_obss_beacon() && cfg80211.cfg80211_report_obss_beacon())
+ result.push_back("cfg80211:cfg80211_report_obss_beacon");
+ if (cfg80211.has_cfg80211_report_wowlan_wakeup() && cfg80211.cfg80211_report_wowlan_wakeup())
+ result.push_back("cfg80211:cfg80211_report_wowlan_wakeup");
+ if (cfg80211.has_cfg80211_return_bool() && cfg80211.cfg80211_return_bool())
+ result.push_back("cfg80211:cfg80211_return_bool");
+ if (cfg80211.has_cfg80211_return_bss() && cfg80211.cfg80211_return_bss())
+ result.push_back("cfg80211:cfg80211_return_bss");
+ if (cfg80211.has_cfg80211_return_u32() && cfg80211.cfg80211_return_u32())
+ result.push_back("cfg80211:cfg80211_return_u32");
+ if (cfg80211.has_cfg80211_return_uint() && cfg80211.cfg80211_return_uint())
+ result.push_back("cfg80211:cfg80211_return_uint");
+ if (cfg80211.has_cfg80211_rx_mgmt() && cfg80211.cfg80211_rx_mgmt())
+ result.push_back("cfg80211:cfg80211_rx_mgmt");
+ if (cfg80211.has_cfg80211_rx_mlme_mgmt() && cfg80211.cfg80211_rx_mlme_mgmt())
+ result.push_back("cfg80211:cfg80211_rx_mlme_mgmt");
+ if (cfg80211.has_cfg80211_rx_spurious_frame() && cfg80211.cfg80211_rx_spurious_frame())
+ result.push_back("cfg80211:cfg80211_rx_spurious_frame");
+ if (cfg80211.has_cfg80211_rx_unexpected_4addr_frame() && cfg80211.cfg80211_rx_unexpected_4addr_frame())
+ result.push_back("cfg80211:cfg80211_rx_unexpected_4addr_frame");
+ if (cfg80211.has_cfg80211_rx_unprot_mlme_mgmt() && cfg80211.cfg80211_rx_unprot_mlme_mgmt())
+ result.push_back("cfg80211:cfg80211_rx_unprot_mlme_mgmt");
+ if (cfg80211.has_cfg80211_scan_done() && cfg80211.cfg80211_scan_done())
+ result.push_back("cfg80211:cfg80211_scan_done");
+ if (cfg80211.has_cfg80211_sched_scan_results() && cfg80211.cfg80211_sched_scan_results())
+ result.push_back("cfg80211:cfg80211_sched_scan_results");
+ if (cfg80211.has_cfg80211_sched_scan_stopped() && cfg80211.cfg80211_sched_scan_stopped())
+ result.push_back("cfg80211:cfg80211_sched_scan_stopped");
+ if (cfg80211.has_cfg80211_send_assoc_timeout() && cfg80211.cfg80211_send_assoc_timeout())
+ result.push_back("cfg80211:cfg80211_send_assoc_timeout");
+ if (cfg80211.has_cfg80211_send_auth_timeout() && cfg80211.cfg80211_send_auth_timeout())
+ result.push_back("cfg80211:cfg80211_send_auth_timeout");
+ if (cfg80211.has_cfg80211_send_rx_assoc() && cfg80211.cfg80211_send_rx_assoc())
+ result.push_back("cfg80211:cfg80211_send_rx_assoc");
+ if (cfg80211.has_cfg80211_send_rx_auth() && cfg80211.cfg80211_send_rx_auth())
+ result.push_back("cfg80211:cfg80211_send_rx_auth");
+ if (cfg80211.has_cfg80211_stop_iface() && cfg80211.cfg80211_stop_iface())
+ result.push_back("cfg80211:cfg80211_stop_iface");
+ if (cfg80211.has_cfg80211_tdls_oper_request() && cfg80211.cfg80211_tdls_oper_request())
+ result.push_back("cfg80211:cfg80211_tdls_oper_request");
+ if (cfg80211.has_cfg80211_tx_mlme_mgmt() && cfg80211.cfg80211_tx_mlme_mgmt())
+ result.push_back("cfg80211:cfg80211_tx_mlme_mgmt");
+ if (cfg80211.has_rdev_abort_scan() && cfg80211.rdev_abort_scan())
+ result.push_back("cfg80211:rdev_abort_scan");
+ if (cfg80211.has_rdev_add_key() && cfg80211.rdev_add_key())
+ result.push_back("cfg80211:rdev_add_key");
+ if (cfg80211.has_rdev_add_mpath() && cfg80211.rdev_add_mpath())
+ result.push_back("cfg80211:rdev_add_mpath");
+ if (cfg80211.has_rdev_add_station() && cfg80211.rdev_add_station())
+ result.push_back("cfg80211:rdev_add_station");
+ if (cfg80211.has_rdev_add_tx_ts() && cfg80211.rdev_add_tx_ts())
+ result.push_back("cfg80211:rdev_add_tx_ts");
+ if (cfg80211.has_rdev_add_virtual_intf() && cfg80211.rdev_add_virtual_intf())
+ result.push_back("cfg80211:rdev_add_virtual_intf");
+ if (cfg80211.has_rdev_assoc() && cfg80211.rdev_assoc())
+ result.push_back("cfg80211:rdev_assoc");
+ if (cfg80211.has_rdev_auth() && cfg80211.rdev_auth())
+ result.push_back("cfg80211:rdev_auth");
+ if (cfg80211.has_rdev_cancel_remain_on_channel() && cfg80211.rdev_cancel_remain_on_channel())
+ result.push_back("cfg80211:rdev_cancel_remain_on_channel");
+ if (cfg80211.has_rdev_change_beacon() && cfg80211.rdev_change_beacon())
+ result.push_back("cfg80211:rdev_change_beacon");
+ if (cfg80211.has_rdev_change_bss() && cfg80211.rdev_change_bss())
+ result.push_back("cfg80211:rdev_change_bss");
+ if (cfg80211.has_rdev_change_mpath() && cfg80211.rdev_change_mpath())
+ result.push_back("cfg80211:rdev_change_mpath");
+ if (cfg80211.has_rdev_change_station() && cfg80211.rdev_change_station())
+ result.push_back("cfg80211:rdev_change_station");
+ if (cfg80211.has_rdev_change_virtual_intf() && cfg80211.rdev_change_virtual_intf())
+ result.push_back("cfg80211:rdev_change_virtual_intf");
+ if (cfg80211.has_rdev_channel_switch() && cfg80211.rdev_channel_switch())
+ result.push_back("cfg80211:rdev_channel_switch");
+ if (cfg80211.has_rdev_connect() && cfg80211.rdev_connect())
+ result.push_back("cfg80211:rdev_connect");
+ if (cfg80211.has_rdev_crit_proto_start() && cfg80211.rdev_crit_proto_start())
+ result.push_back("cfg80211:rdev_crit_proto_start");
+ if (cfg80211.has_rdev_crit_proto_stop() && cfg80211.rdev_crit_proto_stop())
+ result.push_back("cfg80211:rdev_crit_proto_stop");
+ if (cfg80211.has_rdev_deauth() && cfg80211.rdev_deauth())
+ result.push_back("cfg80211:rdev_deauth");
+ if (cfg80211.has_rdev_del_key() && cfg80211.rdev_del_key())
+ result.push_back("cfg80211:rdev_del_key");
+ if (cfg80211.has_rdev_del_mpath() && cfg80211.rdev_del_mpath())
+ result.push_back("cfg80211:rdev_del_mpath");
+ if (cfg80211.has_rdev_del_pmksa() && cfg80211.rdev_del_pmksa())
+ result.push_back("cfg80211:rdev_del_pmksa");
+ if (cfg80211.has_rdev_del_station() && cfg80211.rdev_del_station())
+ result.push_back("cfg80211:rdev_del_station");
+ if (cfg80211.has_rdev_del_tx_ts() && cfg80211.rdev_del_tx_ts())
+ result.push_back("cfg80211:rdev_del_tx_ts");
+ if (cfg80211.has_rdev_del_virtual_intf() && cfg80211.rdev_del_virtual_intf())
+ result.push_back("cfg80211:rdev_del_virtual_intf");
+ if (cfg80211.has_rdev_disassoc() && cfg80211.rdev_disassoc())
+ result.push_back("cfg80211:rdev_disassoc");
+ if (cfg80211.has_rdev_disconnect() && cfg80211.rdev_disconnect())
+ result.push_back("cfg80211:rdev_disconnect");
+ if (cfg80211.has_rdev_dump_mpath() && cfg80211.rdev_dump_mpath())
+ result.push_back("cfg80211:rdev_dump_mpath");
+ if (cfg80211.has_rdev_dump_station() && cfg80211.rdev_dump_station())
+ result.push_back("cfg80211:rdev_dump_station");
+ if (cfg80211.has_rdev_dump_survey() && cfg80211.rdev_dump_survey())
+ result.push_back("cfg80211:rdev_dump_survey");
+ if (cfg80211.has_rdev_flush_pmksa() && cfg80211.rdev_flush_pmksa())
+ result.push_back("cfg80211:rdev_flush_pmksa");
+ if (cfg80211.has_rdev_get_antenna() && cfg80211.rdev_get_antenna())
+ result.push_back("cfg80211:rdev_get_antenna");
+ if (cfg80211.has_rdev_get_channel() && cfg80211.rdev_get_channel())
+ result.push_back("cfg80211:rdev_get_channel");
+ if (cfg80211.has_rdev_get_key() && cfg80211.rdev_get_key())
+ result.push_back("cfg80211:rdev_get_key");
+ if (cfg80211.has_rdev_get_mesh_config() && cfg80211.rdev_get_mesh_config())
+ result.push_back("cfg80211:rdev_get_mesh_config");
+ if (cfg80211.has_rdev_get_mpath() && cfg80211.rdev_get_mpath())
+ result.push_back("cfg80211:rdev_get_mpath");
+ if (cfg80211.has_rdev_get_station() && cfg80211.rdev_get_station())
+ result.push_back("cfg80211:rdev_get_station");
+ if (cfg80211.has_rdev_get_tx_power() && cfg80211.rdev_get_tx_power())
+ result.push_back("cfg80211:rdev_get_tx_power");
+ if (cfg80211.has_rdev_join_ibss() && cfg80211.rdev_join_ibss())
+ result.push_back("cfg80211:rdev_join_ibss");
+ if (cfg80211.has_rdev_join_mesh() && cfg80211.rdev_join_mesh())
+ result.push_back("cfg80211:rdev_join_mesh");
+ if (cfg80211.has_rdev_leave_ibss() && cfg80211.rdev_leave_ibss())
+ result.push_back("cfg80211:rdev_leave_ibss");
+ if (cfg80211.has_rdev_leave_mesh() && cfg80211.rdev_leave_mesh())
+ result.push_back("cfg80211:rdev_leave_mesh");
+ if (cfg80211.has_rdev_libertas_set_mesh_channel() && cfg80211.rdev_libertas_set_mesh_channel())
+ result.push_back("cfg80211:rdev_libertas_set_mesh_channel");
+ if (cfg80211.has_rdev_mgmt_frame_register() && cfg80211.rdev_mgmt_frame_register())
+ result.push_back("cfg80211:rdev_mgmt_frame_register");
+ if (cfg80211.has_rdev_mgmt_tx() && cfg80211.rdev_mgmt_tx())
+ result.push_back("cfg80211:rdev_mgmt_tx");
+ if (cfg80211.has_rdev_mgmt_tx_cancel_wait() && cfg80211.rdev_mgmt_tx_cancel_wait())
+ result.push_back("cfg80211:rdev_mgmt_tx_cancel_wait");
+ if (cfg80211.has_rdev_probe_client() && cfg80211.rdev_probe_client())
+ result.push_back("cfg80211:rdev_probe_client");
+ if (cfg80211.has_rdev_remain_on_channel() && cfg80211.rdev_remain_on_channel())
+ result.push_back("cfg80211:rdev_remain_on_channel");
+ if (cfg80211.has_rdev_resume() && cfg80211.rdev_resume())
+ result.push_back("cfg80211:rdev_resume");
+ if (cfg80211.has_rdev_return_chandef() && cfg80211.rdev_return_chandef())
+ result.push_back("cfg80211:rdev_return_chandef");
+ if (cfg80211.has_rdev_return_int() && cfg80211.rdev_return_int())
+ result.push_back("cfg80211:rdev_return_int");
+ if (cfg80211.has_rdev_return_int_cookie() && cfg80211.rdev_return_int_cookie())
+ result.push_back("cfg80211:rdev_return_int_cookie");
+ if (cfg80211.has_rdev_return_int_int() && cfg80211.rdev_return_int_int())
+ result.push_back("cfg80211:rdev_return_int_int");
+ if (cfg80211.has_rdev_return_int_mesh_config() && cfg80211.rdev_return_int_mesh_config())
+ result.push_back("cfg80211:rdev_return_int_mesh_config");
+ if (cfg80211.has_rdev_return_int_mpath_info() && cfg80211.rdev_return_int_mpath_info())
+ result.push_back("cfg80211:rdev_return_int_mpath_info");
+ if (cfg80211.has_rdev_return_int_station_info() && cfg80211.rdev_return_int_station_info())
+ result.push_back("cfg80211:rdev_return_int_station_info");
+ if (cfg80211.has_rdev_return_int_survey_info() && cfg80211.rdev_return_int_survey_info())
+ result.push_back("cfg80211:rdev_return_int_survey_info");
+ if (cfg80211.has_rdev_return_int_tx_rx() && cfg80211.rdev_return_int_tx_rx())
+ result.push_back("cfg80211:rdev_return_int_tx_rx");
+ if (cfg80211.has_rdev_return_void() && cfg80211.rdev_return_void())
+ result.push_back("cfg80211:rdev_return_void");
+ if (cfg80211.has_rdev_return_void_tx_rx() && cfg80211.rdev_return_void_tx_rx())
+ result.push_back("cfg80211:rdev_return_void_tx_rx");
+ if (cfg80211.has_rdev_return_wdev() && cfg80211.rdev_return_wdev())
+ result.push_back("cfg80211:rdev_return_wdev");
+ if (cfg80211.has_rdev_rfkill_poll() && cfg80211.rdev_rfkill_poll())
+ result.push_back("cfg80211:rdev_rfkill_poll");
+ if (cfg80211.has_rdev_scan() && cfg80211.rdev_scan())
+ result.push_back("cfg80211:rdev_scan");
+ if (cfg80211.has_rdev_sched_scan_start() && cfg80211.rdev_sched_scan_start())
+ result.push_back("cfg80211:rdev_sched_scan_start");
+ if (cfg80211.has_rdev_sched_scan_stop() && cfg80211.rdev_sched_scan_stop())
+ result.push_back("cfg80211:rdev_sched_scan_stop");
+ if (cfg80211.has_rdev_set_antenna() && cfg80211.rdev_set_antenna())
+ result.push_back("cfg80211:rdev_set_antenna");
+ if (cfg80211.has_rdev_set_ap_chanwidth() && cfg80211.rdev_set_ap_chanwidth())
+ result.push_back("cfg80211:rdev_set_ap_chanwidth");
+ if (cfg80211.has_rdev_set_bitrate_mask() && cfg80211.rdev_set_bitrate_mask())
+ result.push_back("cfg80211:rdev_set_bitrate_mask");
+ if (cfg80211.has_rdev_set_cqm_rssi_config() && cfg80211.rdev_set_cqm_rssi_config())
+ result.push_back("cfg80211:rdev_set_cqm_rssi_config");
+ if (cfg80211.has_rdev_set_cqm_txe_config() && cfg80211.rdev_set_cqm_txe_config())
+ result.push_back("cfg80211:rdev_set_cqm_txe_config");
+ if (cfg80211.has_rdev_set_default_key() && cfg80211.rdev_set_default_key())
+ result.push_back("cfg80211:rdev_set_default_key");
+ if (cfg80211.has_rdev_set_default_mgmt_key() && cfg80211.rdev_set_default_mgmt_key())
+ result.push_back("cfg80211:rdev_set_default_mgmt_key");
+ if (cfg80211.has_rdev_set_mac_acl() && cfg80211.rdev_set_mac_acl())
+ result.push_back("cfg80211:rdev_set_mac_acl");
+ if (cfg80211.has_rdev_set_monitor_channel() && cfg80211.rdev_set_monitor_channel())
+ result.push_back("cfg80211:rdev_set_monitor_channel");
+ if (cfg80211.has_rdev_set_noack_map() && cfg80211.rdev_set_noack_map())
+ result.push_back("cfg80211:rdev_set_noack_map");
+ if (cfg80211.has_rdev_set_pmksa() && cfg80211.rdev_set_pmksa())
+ result.push_back("cfg80211:rdev_set_pmksa");
+ if (cfg80211.has_rdev_set_power_mgmt() && cfg80211.rdev_set_power_mgmt())
+ result.push_back("cfg80211:rdev_set_power_mgmt");
+ if (cfg80211.has_rdev_set_qos_map() && cfg80211.rdev_set_qos_map())
+ result.push_back("cfg80211:rdev_set_qos_map");
+ if (cfg80211.has_rdev_set_rekey_data() && cfg80211.rdev_set_rekey_data())
+ result.push_back("cfg80211:rdev_set_rekey_data");
+ if (cfg80211.has_rdev_set_tx_power() && cfg80211.rdev_set_tx_power())
+ result.push_back("cfg80211:rdev_set_tx_power");
+ if (cfg80211.has_rdev_set_txq_params() && cfg80211.rdev_set_txq_params())
+ result.push_back("cfg80211:rdev_set_txq_params");
+ if (cfg80211.has_rdev_set_wakeup() && cfg80211.rdev_set_wakeup())
+ result.push_back("cfg80211:rdev_set_wakeup");
+ if (cfg80211.has_rdev_set_wds_peer() && cfg80211.rdev_set_wds_peer())
+ result.push_back("cfg80211:rdev_set_wds_peer");
+ if (cfg80211.has_rdev_set_wiphy_params() && cfg80211.rdev_set_wiphy_params())
+ result.push_back("cfg80211:rdev_set_wiphy_params");
+ if (cfg80211.has_rdev_start_ap() && cfg80211.rdev_start_ap())
+ result.push_back("cfg80211:rdev_start_ap");
+ if (cfg80211.has_rdev_start_p2p_device() && cfg80211.rdev_start_p2p_device())
+ result.push_back("cfg80211:rdev_start_p2p_device");
+ if (cfg80211.has_rdev_stop_ap() && cfg80211.rdev_stop_ap())
+ result.push_back("cfg80211:rdev_stop_ap");
+ if (cfg80211.has_rdev_stop_p2p_device() && cfg80211.rdev_stop_p2p_device())
+ result.push_back("cfg80211:rdev_stop_p2p_device");
+ if (cfg80211.has_rdev_suspend() && cfg80211.rdev_suspend())
+ result.push_back("cfg80211:rdev_suspend");
+ if (cfg80211.has_rdev_tdls_mgmt() && cfg80211.rdev_tdls_mgmt())
+ result.push_back("cfg80211:rdev_tdls_mgmt");
+ if (cfg80211.has_rdev_tdls_oper() && cfg80211.rdev_tdls_oper())
+ result.push_back("cfg80211:rdev_tdls_oper");
+ if (cfg80211.has_rdev_testmode_cmd() && cfg80211.rdev_testmode_cmd())
+ result.push_back("cfg80211:rdev_testmode_cmd");
+ if (cfg80211.has_rdev_testmode_dump() && cfg80211.rdev_testmode_dump())
+ result.push_back("cfg80211:rdev_testmode_dump");
+ if (cfg80211.has_rdev_update_connect_params() && cfg80211.rdev_update_connect_params())
+ result.push_back("cfg80211:rdev_update_connect_params");
+ if (cfg80211.has_rdev_update_ft_ies() && cfg80211.rdev_update_ft_ies())
+ result.push_back("cfg80211:rdev_update_ft_ies");
+ if (cfg80211.has_rdev_update_mesh_config() && cfg80211.rdev_update_mesh_config())
+ result.push_back("cfg80211:rdev_update_mesh_config");
+ }
+
+ if (tracepoints.has_cma()) {
+ const auto& cma = tracepoints.cma();
+
+ if (cma.has_cma_alloc() && cma.cma_alloc())
+ result.push_back("cma:cma_alloc");
+ if (cma.has_cma_alloc_busy_retry() && cma.cma_alloc_busy_retry())
+ result.push_back("cma:cma_alloc_busy_retry");
+ if (cma.has_cma_alloc_start() && cma.cma_alloc_start())
+ result.push_back("cma:cma_alloc_start");
+ if (cma.has_cma_release() && cma.cma_release())
+ result.push_back("cma:cma_release");
+ }
+
+ if (tracepoints.has_compaction()) {
+ const auto& compaction = tracepoints.compaction();
+
+ if (compaction.has_mm_compaction_begin() && compaction.mm_compaction_begin())
+ result.push_back("compaction:mm_compaction_begin");
+ if (compaction.has_mm_compaction_end() && compaction.mm_compaction_end())
+ result.push_back("compaction:mm_compaction_end");
+ if (compaction.has_mm_compaction_isolate_freepages() && compaction.mm_compaction_isolate_freepages())
+ result.push_back("compaction:mm_compaction_isolate_freepages");
+ if (compaction.has_mm_compaction_isolate_migratepages() && compaction.mm_compaction_isolate_migratepages())
+ result.push_back("compaction:mm_compaction_isolate_migratepages");
+ if (compaction.has_mm_compaction_migratepages() && compaction.mm_compaction_migratepages())
+ result.push_back("compaction:mm_compaction_migratepages");
+ }
+
+ if (tracepoints.has_cpufreq_interactive()) {
+ const auto& cpufreq_interactive = tracepoints.cpufreq_interactive();
+
+ if (cpufreq_interactive.has_cpufreq_interactive_already() && cpufreq_interactive.cpufreq_interactive_already())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_already");
+ if (cpufreq_interactive.has_cpufreq_interactive_boost() && cpufreq_interactive.cpufreq_interactive_boost())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_boost");
+ if (cpufreq_interactive.has_cpufreq_interactive_cpuload() && cpufreq_interactive.cpufreq_interactive_cpuload())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_cpuload");
+ if (cpufreq_interactive.has_cpufreq_interactive_load_change() && cpufreq_interactive.cpufreq_interactive_load_change())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_load_change");
+ if (cpufreq_interactive.has_cpufreq_interactive_notyet() && cpufreq_interactive.cpufreq_interactive_notyet())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_notyet");
+ if (cpufreq_interactive.has_cpufreq_interactive_setspeed() && cpufreq_interactive.cpufreq_interactive_setspeed())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_setspeed");
+ if (cpufreq_interactive.has_cpufreq_interactive_target() && cpufreq_interactive.cpufreq_interactive_target())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_target");
+ if (cpufreq_interactive.has_cpufreq_interactive_unboost() && cpufreq_interactive.cpufreq_interactive_unboost())
+ result.push_back("cpufreq_interactive:cpufreq_interactive_unboost");
+ }
+
+ if (tracepoints.has_cpufreq_sched()) {
+ const auto& cpufreq_sched = tracepoints.cpufreq_sched();
+
+ if (cpufreq_sched.has_cpufreq_sched_request_opp() && cpufreq_sched.cpufreq_sched_request_opp())
+ result.push_back("cpufreq_sched:cpufreq_sched_request_opp");
+ if (cpufreq_sched.has_cpufreq_sched_throttled() && cpufreq_sched.cpufreq_sched_throttled())
+ result.push_back("cpufreq_sched:cpufreq_sched_throttled");
+ if (cpufreq_sched.has_cpufreq_sched_update_capacity() && cpufreq_sched.cpufreq_sched_update_capacity())
+ result.push_back("cpufreq_sched:cpufreq_sched_update_capacity");
+ }
+
+ if (tracepoints.has_devfreq()) {
+ const auto& devfreq = tracepoints.devfreq();
+
+ if (devfreq.has_devfreq_msg() && devfreq.devfreq_msg())
+ result.push_back("devfreq:devfreq_msg");
+ }
+
+ if (tracepoints.has_dwc3()) {
+ const auto& dwc3 = tracepoints.dwc3();
+
+ if (dwc3.has_dwc3_alloc_request() && dwc3.dwc3_alloc_request())
+ result.push_back("dwc3:dwc3_alloc_request");
+ if (dwc3.has_dwc3_complete_trb() && dwc3.dwc3_complete_trb())
+ result.push_back("dwc3:dwc3_complete_trb");
+ if (dwc3.has_dwc3_ctrl_req() && dwc3.dwc3_ctrl_req())
+ result.push_back("dwc3:dwc3_ctrl_req");
+ if (dwc3.has_dwc3_ep0() && dwc3.dwc3_ep0())
+ result.push_back("dwc3:dwc3_ep0");
+ if (dwc3.has_dwc3_ep_dequeue() && dwc3.dwc3_ep_dequeue())
+ result.push_back("dwc3:dwc3_ep_dequeue");
+ if (dwc3.has_dwc3_ep_queue() && dwc3.dwc3_ep_queue())
+ result.push_back("dwc3:dwc3_ep_queue");
+ if (dwc3.has_dwc3_event() && dwc3.dwc3_event())
+ result.push_back("dwc3:dwc3_event");
+ if (dwc3.has_dwc3_free_request() && dwc3.dwc3_free_request())
+ result.push_back("dwc3:dwc3_free_request");
+ if (dwc3.has_dwc3_gadget_ep_cmd() && dwc3.dwc3_gadget_ep_cmd())
+ result.push_back("dwc3:dwc3_gadget_ep_cmd");
+ if (dwc3.has_dwc3_gadget_generic_cmd() && dwc3.dwc3_gadget_generic_cmd())
+ result.push_back("dwc3:dwc3_gadget_generic_cmd");
+ if (dwc3.has_dwc3_gadget_giveback() && dwc3.dwc3_gadget_giveback())
+ result.push_back("dwc3:dwc3_gadget_giveback");
+ if (dwc3.has_dwc3_prepare_trb() && dwc3.dwc3_prepare_trb())
+ result.push_back("dwc3:dwc3_prepare_trb");
+ if (dwc3.has_dwc3_readl() && dwc3.dwc3_readl())
+ result.push_back("dwc3:dwc3_readl");
+ if (dwc3.has_dwc3_writel() && dwc3.dwc3_writel())
+ result.push_back("dwc3:dwc3_writel");
+ }
+
+ if (tracepoints.has_emulation()) {
+ const auto& emulation = tracepoints.emulation();
+
+ if (emulation.has_instruction_emulation() && emulation.instruction_emulation())
+ result.push_back("emulation:instruction_emulation");
+ }
+
+ if (tracepoints.has_exception()) {
+ const auto& exception = tracepoints.exception();
+
+ if (exception.has_kernel_panic() && exception.kernel_panic())
+ result.push_back("exception:kernel_panic");
+ if (exception.has_kernel_panic_late() && exception.kernel_panic_late())
+ result.push_back("exception:kernel_panic_late");
+ if (exception.has_undef_instr() && exception.undef_instr())
+ result.push_back("exception:undef_instr");
+ if (exception.has_unhandled_abort() && exception.unhandled_abort())
+ result.push_back("exception:unhandled_abort");
+ if (exception.has_user_fault() && exception.user_fault())
+ result.push_back("exception:user_fault");
+ }
+
+ if (tracepoints.has_ext4()) {
+ const auto& ext4 = tracepoints.ext4();
+
+ if (ext4.has_ext4_alloc_da_blocks() && ext4.ext4_alloc_da_blocks())
+ result.push_back("ext4:ext4_alloc_da_blocks");
+ if (ext4.has_ext4_allocate_blocks() && ext4.ext4_allocate_blocks())
+ result.push_back("ext4:ext4_allocate_blocks");
+ if (ext4.has_ext4_allocate_inode() && ext4.ext4_allocate_inode())
+ result.push_back("ext4:ext4_allocate_inode");
+ if (ext4.has_ext4_begin_ordered_truncate() && ext4.ext4_begin_ordered_truncate())
+ result.push_back("ext4:ext4_begin_ordered_truncate");
+ if (ext4.has_ext4_collapse_range() && ext4.ext4_collapse_range())
+ result.push_back("ext4:ext4_collapse_range");
+ if (ext4.has_ext4_da_release_space() && ext4.ext4_da_release_space())
+ result.push_back("ext4:ext4_da_release_space");
+ if (ext4.has_ext4_da_reserve_space() && ext4.ext4_da_reserve_space())
+ result.push_back("ext4:ext4_da_reserve_space");
+ if (ext4.has_ext4_da_update_reserve_space() && ext4.ext4_da_update_reserve_space())
+ result.push_back("ext4:ext4_da_update_reserve_space");
+ if (ext4.has_ext4_da_write_begin() && ext4.ext4_da_write_begin())
+ result.push_back("ext4:ext4_da_write_begin");
+ if (ext4.has_ext4_da_write_end() && ext4.ext4_da_write_end())
+ result.push_back("ext4:ext4_da_write_end");
+ if (ext4.has_ext4_da_write_pages() && ext4.ext4_da_write_pages())
+ result.push_back("ext4:ext4_da_write_pages");
+ if (ext4.has_ext4_da_write_pages_extent() && ext4.ext4_da_write_pages_extent())
+ result.push_back("ext4:ext4_da_write_pages_extent");
+ if (ext4.has_ext4_direct_io_enter() && ext4.ext4_direct_io_enter())
+ result.push_back("ext4:ext4_direct_IO_enter");
+ if (ext4.has_ext4_direct_io_exit() && ext4.ext4_direct_io_exit())
+ result.push_back("ext4:ext4_direct_IO_exit");
+ if (ext4.has_ext4_discard_blocks() && ext4.ext4_discard_blocks())
+ result.push_back("ext4:ext4_discard_blocks");
+ if (ext4.has_ext4_discard_preallocations() && ext4.ext4_discard_preallocations())
+ result.push_back("ext4:ext4_discard_preallocations");
+ if (ext4.has_ext4_drop_inode() && ext4.ext4_drop_inode())
+ result.push_back("ext4:ext4_drop_inode");
+ if (ext4.has_ext4_es_cache_extent() && ext4.ext4_es_cache_extent())
+ result.push_back("ext4:ext4_es_cache_extent");
+ if (ext4.has_ext4_es_find_delayed_extent_range_enter() && ext4.ext4_es_find_delayed_extent_range_enter())
+ result.push_back("ext4:ext4_es_find_delayed_extent_range_enter");
+ if (ext4.has_ext4_es_find_delayed_extent_range_exit() && ext4.ext4_es_find_delayed_extent_range_exit())
+ result.push_back("ext4:ext4_es_find_delayed_extent_range_exit");
+ if (ext4.has_ext4_es_insert_extent() && ext4.ext4_es_insert_extent())
+ result.push_back("ext4:ext4_es_insert_extent");
+ if (ext4.has_ext4_es_lookup_extent_enter() && ext4.ext4_es_lookup_extent_enter())
+ result.push_back("ext4:ext4_es_lookup_extent_enter");
+ if (ext4.has_ext4_es_lookup_extent_exit() && ext4.ext4_es_lookup_extent_exit())
+ result.push_back("ext4:ext4_es_lookup_extent_exit");
+ if (ext4.has_ext4_es_remove_extent() && ext4.ext4_es_remove_extent())
+ result.push_back("ext4:ext4_es_remove_extent");
+ if (ext4.has_ext4_es_shrink() && ext4.ext4_es_shrink())
+ result.push_back("ext4:ext4_es_shrink");
+ if (ext4.has_ext4_es_shrink_count() && ext4.ext4_es_shrink_count())
+ result.push_back("ext4:ext4_es_shrink_count");
+ if (ext4.has_ext4_es_shrink_scan_enter() && ext4.ext4_es_shrink_scan_enter())
+ result.push_back("ext4:ext4_es_shrink_scan_enter");
+ if (ext4.has_ext4_es_shrink_scan_exit() && ext4.ext4_es_shrink_scan_exit())
+ result.push_back("ext4:ext4_es_shrink_scan_exit");
+ if (ext4.has_ext4_evict_inode() && ext4.ext4_evict_inode())
+ result.push_back("ext4:ext4_evict_inode");
+ if (ext4.has_ext4_ext_convert_to_initialized_enter() && ext4.ext4_ext_convert_to_initialized_enter())
+ result.push_back("ext4:ext4_ext_convert_to_initialized_enter");
+ if (ext4.has_ext4_ext_convert_to_initialized_fastpath() && ext4.ext4_ext_convert_to_initialized_fastpath())
+ result.push_back("ext4:ext4_ext_convert_to_initialized_fastpath");
+ if (ext4.has_ext4_ext_handle_unwritten_extents() && ext4.ext4_ext_handle_unwritten_extents())
+ result.push_back("ext4:ext4_ext_handle_unwritten_extents");
+ if (ext4.has_ext4_ext_in_cache() && ext4.ext4_ext_in_cache())
+ result.push_back("ext4:ext4_ext_in_cache");
+ if (ext4.has_ext4_ext_load_extent() && ext4.ext4_ext_load_extent())
+ result.push_back("ext4:ext4_ext_load_extent");
+ if (ext4.has_ext4_ext_map_blocks_enter() && ext4.ext4_ext_map_blocks_enter())
+ result.push_back("ext4:ext4_ext_map_blocks_enter");
+ if (ext4.has_ext4_ext_map_blocks_exit() && ext4.ext4_ext_map_blocks_exit())
+ result.push_back("ext4:ext4_ext_map_blocks_exit");
+ if (ext4.has_ext4_ext_put_in_cache() && ext4.ext4_ext_put_in_cache())
+ result.push_back("ext4:ext4_ext_put_in_cache");
+ if (ext4.has_ext4_ext_remove_space() && ext4.ext4_ext_remove_space())
+ result.push_back("ext4:ext4_ext_remove_space");
+ if (ext4.has_ext4_ext_remove_space_done() && ext4.ext4_ext_remove_space_done())
+ result.push_back("ext4:ext4_ext_remove_space_done");
+ if (ext4.has_ext4_ext_rm_idx() && ext4.ext4_ext_rm_idx())
+ result.push_back("ext4:ext4_ext_rm_idx");
+ if (ext4.has_ext4_ext_rm_leaf() && ext4.ext4_ext_rm_leaf())
+ result.push_back("ext4:ext4_ext_rm_leaf");
+ if (ext4.has_ext4_ext_show_extent() && ext4.ext4_ext_show_extent())
+ result.push_back("ext4:ext4_ext_show_extent");
+ if (ext4.has_ext4_fallocate_enter() && ext4.ext4_fallocate_enter())
+ result.push_back("ext4:ext4_fallocate_enter");
+ if (ext4.has_ext4_fallocate_exit() && ext4.ext4_fallocate_exit())
+ result.push_back("ext4:ext4_fallocate_exit");
+ if (ext4.has_ext4_find_delalloc_range() && ext4.ext4_find_delalloc_range())
+ result.push_back("ext4:ext4_find_delalloc_range");
+ if (ext4.has_ext4_forget() && ext4.ext4_forget())
+ result.push_back("ext4:ext4_forget");
+ if (ext4.has_ext4_free_blocks() && ext4.ext4_free_blocks())
+ result.push_back("ext4:ext4_free_blocks");
+ if (ext4.has_ext4_free_inode() && ext4.ext4_free_inode())
+ result.push_back("ext4:ext4_free_inode");
+ if (ext4.has_ext4_get_implied_cluster_alloc_exit() && ext4.ext4_get_implied_cluster_alloc_exit())
+ result.push_back("ext4:ext4_get_implied_cluster_alloc_exit");
+ if (ext4.has_ext4_get_reserved_cluster_alloc() && ext4.ext4_get_reserved_cluster_alloc())
+ result.push_back("ext4:ext4_get_reserved_cluster_alloc");
+ if (ext4.has_ext4_ind_map_blocks_enter() && ext4.ext4_ind_map_blocks_enter())
+ result.push_back("ext4:ext4_ind_map_blocks_enter");
+ if (ext4.has_ext4_ind_map_blocks_exit() && ext4.ext4_ind_map_blocks_exit())
+ result.push_back("ext4:ext4_ind_map_blocks_exit");
+ if (ext4.has_ext4_invalidatepage() && ext4.ext4_invalidatepage())
+ result.push_back("ext4:ext4_invalidatepage");
+ if (ext4.has_ext4_journal_start() && ext4.ext4_journal_start())
+ result.push_back("ext4:ext4_journal_start");
+ if (ext4.has_ext4_journal_start_reserved() && ext4.ext4_journal_start_reserved())
+ result.push_back("ext4:ext4_journal_start_reserved");
+ if (ext4.has_ext4_journalled_invalidatepage() && ext4.ext4_journalled_invalidatepage())
+ result.push_back("ext4:ext4_journalled_invalidatepage");
+ if (ext4.has_ext4_journalled_write_end() && ext4.ext4_journalled_write_end())
+ result.push_back("ext4:ext4_journalled_write_end");
+ if (ext4.has_ext4_load_inode() && ext4.ext4_load_inode())
+ result.push_back("ext4:ext4_load_inode");
+ if (ext4.has_ext4_load_inode_bitmap() && ext4.ext4_load_inode_bitmap())
+ result.push_back("ext4:ext4_load_inode_bitmap");
+ if (ext4.has_ext4_mark_inode_dirty() && ext4.ext4_mark_inode_dirty())
+ result.push_back("ext4:ext4_mark_inode_dirty");
+ if (ext4.has_ext4_mb_bitmap_load() && ext4.ext4_mb_bitmap_load())
+ result.push_back("ext4:ext4_mb_bitmap_load");
+ if (ext4.has_ext4_mb_buddy_bitmap_load() && ext4.ext4_mb_buddy_bitmap_load())
+ result.push_back("ext4:ext4_mb_buddy_bitmap_load");
+ if (ext4.has_ext4_mb_discard_preallocations() && ext4.ext4_mb_discard_preallocations())
+ result.push_back("ext4:ext4_mb_discard_preallocations");
+ if (ext4.has_ext4_mb_new_group_pa() && ext4.ext4_mb_new_group_pa())
+ result.push_back("ext4:ext4_mb_new_group_pa");
+ if (ext4.has_ext4_mb_new_inode_pa() && ext4.ext4_mb_new_inode_pa())
+ result.push_back("ext4:ext4_mb_new_inode_pa");
+ if (ext4.has_ext4_mb_release_group_pa() && ext4.ext4_mb_release_group_pa())
+ result.push_back("ext4:ext4_mb_release_group_pa");
+ if (ext4.has_ext4_mb_release_inode_pa() && ext4.ext4_mb_release_inode_pa())
+ result.push_back("ext4:ext4_mb_release_inode_pa");
+ if (ext4.has_ext4_mballoc_alloc() && ext4.ext4_mballoc_alloc())
+ result.push_back("ext4:ext4_mballoc_alloc");
+ if (ext4.has_ext4_mballoc_discard() && ext4.ext4_mballoc_discard())
+ result.push_back("ext4:ext4_mballoc_discard");
+ if (ext4.has_ext4_mballoc_free() && ext4.ext4_mballoc_free())
+ result.push_back("ext4:ext4_mballoc_free");
+ if (ext4.has_ext4_mballoc_prealloc() && ext4.ext4_mballoc_prealloc())
+ result.push_back("ext4:ext4_mballoc_prealloc");
+ if (ext4.has_ext4_punch_hole() && ext4.ext4_punch_hole())
+ result.push_back("ext4:ext4_punch_hole");
+ if (ext4.has_ext4_read_block_bitmap_load() && ext4.ext4_read_block_bitmap_load())
+ result.push_back("ext4:ext4_read_block_bitmap_load");
+ if (ext4.has_ext4_readpage() && ext4.ext4_readpage())
+ result.push_back("ext4:ext4_readpage");
+ if (ext4.has_ext4_releasepage() && ext4.ext4_releasepage())
+ result.push_back("ext4:ext4_releasepage");
+ if (ext4.has_ext4_remove_blocks() && ext4.ext4_remove_blocks())
+ result.push_back("ext4:ext4_remove_blocks");
+ if (ext4.has_ext4_request_blocks() && ext4.ext4_request_blocks())
+ result.push_back("ext4:ext4_request_blocks");
+ if (ext4.has_ext4_request_inode() && ext4.ext4_request_inode())
+ result.push_back("ext4:ext4_request_inode");
+ if (ext4.has_ext4_sync_file_enter() && ext4.ext4_sync_file_enter())
+ result.push_back("ext4:ext4_sync_file_enter");
+ if (ext4.has_ext4_sync_file_exit() && ext4.ext4_sync_file_exit())
+ result.push_back("ext4:ext4_sync_file_exit");
+ if (ext4.has_ext4_sync_fs() && ext4.ext4_sync_fs())
+ result.push_back("ext4:ext4_sync_fs");
+ if (ext4.has_ext4_trim_all_free() && ext4.ext4_trim_all_free())
+ result.push_back("ext4:ext4_trim_all_free");
+ if (ext4.has_ext4_trim_extent() && ext4.ext4_trim_extent())
+ result.push_back("ext4:ext4_trim_extent");
+ if (ext4.has_ext4_truncate_enter() && ext4.ext4_truncate_enter())
+ result.push_back("ext4:ext4_truncate_enter");
+ if (ext4.has_ext4_truncate_exit() && ext4.ext4_truncate_exit())
+ result.push_back("ext4:ext4_truncate_exit");
+ if (ext4.has_ext4_unlink_enter() && ext4.ext4_unlink_enter())
+ result.push_back("ext4:ext4_unlink_enter");
+ if (ext4.has_ext4_unlink_exit() && ext4.ext4_unlink_exit())
+ result.push_back("ext4:ext4_unlink_exit");
+ if (ext4.has_ext4_write_begin() && ext4.ext4_write_begin())
+ result.push_back("ext4:ext4_write_begin");
+ if (ext4.has_ext4_write_end() && ext4.ext4_write_end())
+ result.push_back("ext4:ext4_write_end");
+ if (ext4.has_ext4_writepage() && ext4.ext4_writepage())
+ result.push_back("ext4:ext4_writepage");
+ if (ext4.has_ext4_writepages() && ext4.ext4_writepages())
+ result.push_back("ext4:ext4_writepages");
+ if (ext4.has_ext4_writepages_result() && ext4.ext4_writepages_result())
+ result.push_back("ext4:ext4_writepages_result");
+ if (ext4.has_ext4_zero_range() && ext4.ext4_zero_range())
+ result.push_back("ext4:ext4_zero_range");
+ }
+
+ if (tracepoints.has_fence()) {
+ const auto& fence = tracepoints.fence();
+
+ if (fence.has_fence_annotate_wait_on() && fence.fence_annotate_wait_on())
+ result.push_back("fence:fence_annotate_wait_on");
+ if (fence.has_fence_destroy() && fence.fence_destroy())
+ result.push_back("fence:fence_destroy");
+ if (fence.has_fence_emit() && fence.fence_emit())
+ result.push_back("fence:fence_emit");
+ if (fence.has_fence_enable_signal() && fence.fence_enable_signal())
+ result.push_back("fence:fence_enable_signal");
+ if (fence.has_fence_init() && fence.fence_init())
+ result.push_back("fence:fence_init");
+ if (fence.has_fence_signaled() && fence.fence_signaled())
+ result.push_back("fence:fence_signaled");
+ if (fence.has_fence_wait_end() && fence.fence_wait_end())
+ result.push_back("fence:fence_wait_end");
+ if (fence.has_fence_wait_start() && fence.fence_wait_start())
+ result.push_back("fence:fence_wait_start");
+ }
+
+ if (tracepoints.has_filelock()) {
+ const auto& filelock = tracepoints.filelock();
+
+ if (filelock.has_break_lease_block() && filelock.break_lease_block())
+ result.push_back("filelock:break_lease_block");
+ if (filelock.has_break_lease_noblock() && filelock.break_lease_noblock())
+ result.push_back("filelock:break_lease_noblock");
+ if (filelock.has_break_lease_unblock() && filelock.break_lease_unblock())
+ result.push_back("filelock:break_lease_unblock");
+ if (filelock.has_generic_add_lease() && filelock.generic_add_lease())
+ result.push_back("filelock:generic_add_lease");
+ if (filelock.has_generic_delete_lease() && filelock.generic_delete_lease())
+ result.push_back("filelock:generic_delete_lease");
+ if (filelock.has_time_out_leases() && filelock.time_out_leases())
+ result.push_back("filelock:time_out_leases");
+ }
+
+ if (tracepoints.has_filemap()) {
+ const auto& filemap = tracepoints.filemap();
+
+ if (filemap.has_mm_filemap_add_to_page_cache() && filemap.mm_filemap_add_to_page_cache())
+ result.push_back("filemap:mm_filemap_add_to_page_cache");
+ if (filemap.has_mm_filemap_delete_from_page_cache() && filemap.mm_filemap_delete_from_page_cache())
+ result.push_back("filemap:mm_filemap_delete_from_page_cache");
+ }
+
+ if (tracepoints.has_gpio()) {
+ const auto& gpio = tracepoints.gpio();
+
+ if (gpio.has_gpio_direction() && gpio.gpio_direction())
+ result.push_back("gpio:gpio_direction");
+ if (gpio.has_gpio_value() && gpio.gpio_value())
+ result.push_back("gpio:gpio_value");
+ }
+
+ if (tracepoints.has_i2c()) {
+ const auto& i2c = tracepoints.i2c();
+
+ if (i2c.has_i2c_read() && i2c.i2c_read())
+ result.push_back("i2c:i2c_read");
+ if (i2c.has_i2c_reply() && i2c.i2c_reply())
+ result.push_back("i2c:i2c_reply");
+ if (i2c.has_i2c_result() && i2c.i2c_result())
+ result.push_back("i2c:i2c_result");
+ if (i2c.has_i2c_write() && i2c.i2c_write())
+ result.push_back("i2c:i2c_write");
+ if (i2c.has_smbus_read() && i2c.smbus_read())
+ result.push_back("i2c:smbus_read");
+ if (i2c.has_smbus_reply() && i2c.smbus_reply())
+ result.push_back("i2c:smbus_reply");
+ if (i2c.has_smbus_result() && i2c.smbus_result())
+ result.push_back("i2c:smbus_result");
+ if (i2c.has_smbus_write() && i2c.smbus_write())
+ result.push_back("i2c:smbus_write");
+ }
+
+ if (tracepoints.has_iommu()) {
+ const auto& iommu = tracepoints.iommu();
+
+ if (iommu.has_add_device_to_group() && iommu.add_device_to_group())
+ result.push_back("iommu:add_device_to_group");
+ if (iommu.has_attach_device_to_domain() && iommu.attach_device_to_domain())
+ result.push_back("iommu:attach_device_to_domain");
+ if (iommu.has_detach_device_from_domain() && iommu.detach_device_from_domain())
+ result.push_back("iommu:detach_device_from_domain");
+ if (iommu.has_io_page_fault() && iommu.io_page_fault())
+ result.push_back("iommu:io_page_fault");
+ if (iommu.has_map() && iommu.map())
+ result.push_back("iommu:map");
+ if (iommu.has_map_end() && iommu.map_end())
+ result.push_back("iommu:map_end");
+ if (iommu.has_map_sg_end() && iommu.map_sg_end())
+ result.push_back("iommu:map_sg_end");
+ if (iommu.has_map_sg_start() && iommu.map_sg_start())
+ result.push_back("iommu:map_sg_start");
+ if (iommu.has_map_start() && iommu.map_start())
+ result.push_back("iommu:map_start");
+ if (iommu.has_remove_device_from_group() && iommu.remove_device_from_group())
+ result.push_back("iommu:remove_device_from_group");
+ if (iommu.has_unmap() && iommu.unmap())
+ result.push_back("iommu:unmap");
+ if (iommu.has_unmap_end() && iommu.unmap_end())
+ result.push_back("iommu:unmap_end");
+ if (iommu.has_unmap_start() && iommu.unmap_start())
+ result.push_back("iommu:unmap_start");
+ }
+
+ if (tracepoints.has_ipa()) {
+ const auto& ipa = tracepoints.ipa();
+
+ if (ipa.has_idle_sleep_enter() && ipa.idle_sleep_enter())
+ result.push_back("ipa:idle_sleep_enter");
+ if (ipa.has_idle_sleep_exit() && ipa.idle_sleep_exit())
+ result.push_back("ipa:idle_sleep_exit");
+ if (ipa.has_intr_to_poll() && ipa.intr_to_poll())
+ result.push_back("ipa:intr_to_poll");
+ if (ipa.has_poll_to_intr() && ipa.poll_to_intr())
+ result.push_back("ipa:poll_to_intr");
+ if (ipa.has_rmnet_ipa_netifni() && ipa.rmnet_ipa_netifni())
+ result.push_back("ipa:rmnet_ipa_netifni");
+ if (ipa.has_rmnet_ipa_netifrx() && ipa.rmnet_ipa_netifrx())
+ result.push_back("ipa:rmnet_ipa_netifrx");
+ }
+
+ if (tracepoints.has_ipi()) {
+ const auto& ipi = tracepoints.ipi();
+
+ if (ipi.has_ipi_entry() && ipi.ipi_entry())
+ result.push_back("ipi:ipi_entry");
+ if (ipi.has_ipi_exit() && ipi.ipi_exit())
+ result.push_back("ipi:ipi_exit");
+ if (ipi.has_ipi_raise() && ipi.ipi_raise())
+ result.push_back("ipi:ipi_raise");
+ }
+
+ if (tracepoints.has_irq()) {
+ const auto& irq = tracepoints.irq();
+
+ if (irq.has_irq_handler_entry() && irq.irq_handler_entry())
+ result.push_back("irq:irq_handler_entry");
+ if (irq.has_irq_handler_exit() && irq.irq_handler_exit())
+ result.push_back("irq:irq_handler_exit");
+ if (irq.has_softirq_entry() && irq.softirq_entry())
+ result.push_back("irq:softirq_entry");
+ if (irq.has_softirq_exit() && irq.softirq_exit())
+ result.push_back("irq:softirq_exit");
+ if (irq.has_softirq_raise() && irq.softirq_raise())
+ result.push_back("irq:softirq_raise");
+ }
+
+ if (tracepoints.has_jbd2()) {
+ const auto& jbd2 = tracepoints.jbd2();
+
+ if (jbd2.has_jbd2_checkpoint() && jbd2.jbd2_checkpoint())
+ result.push_back("jbd2:jbd2_checkpoint");
+ if (jbd2.has_jbd2_checkpoint_stats() && jbd2.jbd2_checkpoint_stats())
+ result.push_back("jbd2:jbd2_checkpoint_stats");
+ if (jbd2.has_jbd2_commit_flushing() && jbd2.jbd2_commit_flushing())
+ result.push_back("jbd2:jbd2_commit_flushing");
+ if (jbd2.has_jbd2_commit_locking() && jbd2.jbd2_commit_locking())
+ result.push_back("jbd2:jbd2_commit_locking");
+ if (jbd2.has_jbd2_commit_logging() && jbd2.jbd2_commit_logging())
+ result.push_back("jbd2:jbd2_commit_logging");
+ if (jbd2.has_jbd2_drop_transaction() && jbd2.jbd2_drop_transaction())
+ result.push_back("jbd2:jbd2_drop_transaction");
+ if (jbd2.has_jbd2_end_commit() && jbd2.jbd2_end_commit())
+ result.push_back("jbd2:jbd2_end_commit");
+ if (jbd2.has_jbd2_handle_extend() && jbd2.jbd2_handle_extend())
+ result.push_back("jbd2:jbd2_handle_extend");
+ if (jbd2.has_jbd2_handle_start() && jbd2.jbd2_handle_start())
+ result.push_back("jbd2:jbd2_handle_start");
+ if (jbd2.has_jbd2_handle_stats() && jbd2.jbd2_handle_stats())
+ result.push_back("jbd2:jbd2_handle_stats");
+ if (jbd2.has_jbd2_lock_buffer_stall() && jbd2.jbd2_lock_buffer_stall())
+ result.push_back("jbd2:jbd2_lock_buffer_stall");
+ if (jbd2.has_jbd2_run_stats() && jbd2.jbd2_run_stats())
+ result.push_back("jbd2:jbd2_run_stats");
+ if (jbd2.has_jbd2_start_commit() && jbd2.jbd2_start_commit())
+ result.push_back("jbd2:jbd2_start_commit");
+ if (jbd2.has_jbd2_submit_inode_data() && jbd2.jbd2_submit_inode_data())
+ result.push_back("jbd2:jbd2_submit_inode_data");
+ if (jbd2.has_jbd2_update_log_tail() && jbd2.jbd2_update_log_tail())
+ result.push_back("jbd2:jbd2_update_log_tail");
+ if (jbd2.has_jbd2_write_superblock() && jbd2.jbd2_write_superblock())
+ result.push_back("jbd2:jbd2_write_superblock");
+ }
+
+ if (tracepoints.has_kgsl()) {
+ const auto& kgsl = tracepoints.kgsl();
+
+ if (kgsl.has_adreno_cmdbatch_fault() && kgsl.adreno_cmdbatch_fault())
+ result.push_back("kgsl:adreno_cmdbatch_fault");
+ if (kgsl.has_adreno_cmdbatch_queued() && kgsl.adreno_cmdbatch_queued())
+ result.push_back("kgsl:adreno_cmdbatch_queued");
+ if (kgsl.has_adreno_cmdbatch_recovery() && kgsl.adreno_cmdbatch_recovery())
+ result.push_back("kgsl:adreno_cmdbatch_recovery");
+ if (kgsl.has_adreno_cmdbatch_retired() && kgsl.adreno_cmdbatch_retired())
+ result.push_back("kgsl:adreno_cmdbatch_retired");
+ if (kgsl.has_adreno_cmdbatch_submitted() && kgsl.adreno_cmdbatch_submitted())
+ result.push_back("kgsl:adreno_cmdbatch_submitted");
+ if (kgsl.has_adreno_cmdbatch_sync() && kgsl.adreno_cmdbatch_sync())
+ result.push_back("kgsl:adreno_cmdbatch_sync");
+ if (kgsl.has_adreno_drawctxt_invalidate() && kgsl.adreno_drawctxt_invalidate())
+ result.push_back("kgsl:adreno_drawctxt_invalidate");
+ if (kgsl.has_adreno_drawctxt_sleep() && kgsl.adreno_drawctxt_sleep())
+ result.push_back("kgsl:adreno_drawctxt_sleep");
+ if (kgsl.has_adreno_drawctxt_switch() && kgsl.adreno_drawctxt_switch())
+ result.push_back("kgsl:adreno_drawctxt_switch");
+ if (kgsl.has_adreno_drawctxt_wait_done() && kgsl.adreno_drawctxt_wait_done())
+ result.push_back("kgsl:adreno_drawctxt_wait_done");
+ if (kgsl.has_adreno_drawctxt_wait_start() && kgsl.adreno_drawctxt_wait_start())
+ result.push_back("kgsl:adreno_drawctxt_wait_start");
+ if (kgsl.has_adreno_drawctxt_wake() && kgsl.adreno_drawctxt_wake())
+ result.push_back("kgsl:adreno_drawctxt_wake");
+ if (kgsl.has_adreno_gpu_fault() && kgsl.adreno_gpu_fault())
+ result.push_back("kgsl:adreno_gpu_fault");
+ if (kgsl.has_adreno_hw_preempt_clear_to_trig() && kgsl.adreno_hw_preempt_clear_to_trig())
+ result.push_back("kgsl:adreno_hw_preempt_clear_to_trig");
+ if (kgsl.has_adreno_hw_preempt_comp_to_clear() && kgsl.adreno_hw_preempt_comp_to_clear())
+ result.push_back("kgsl:adreno_hw_preempt_comp_to_clear");
+ if (kgsl.has_adreno_hw_preempt_token_submit() && kgsl.adreno_hw_preempt_token_submit())
+ result.push_back("kgsl:adreno_hw_preempt_token_submit");
+ if (kgsl.has_adreno_hw_preempt_trig_to_comp() && kgsl.adreno_hw_preempt_trig_to_comp())
+ result.push_back("kgsl:adreno_hw_preempt_trig_to_comp");
+ if (kgsl.has_adreno_hw_preempt_trig_to_comp_int() && kgsl.adreno_hw_preempt_trig_to_comp_int())
+ result.push_back("kgsl:adreno_hw_preempt_trig_to_comp_int");
+ if (kgsl.has_adreno_preempt_done() && kgsl.adreno_preempt_done())
+ result.push_back("kgsl:adreno_preempt_done");
+ if (kgsl.has_adreno_preempt_trigger() && kgsl.adreno_preempt_trigger())
+ result.push_back("kgsl:adreno_preempt_trigger");
+ if (kgsl.has_adreno_sp_tp() && kgsl.adreno_sp_tp())
+ result.push_back("kgsl:adreno_sp_tp");
+ if (kgsl.has_dispatch_queue_context() && kgsl.dispatch_queue_context())
+ result.push_back("kgsl:dispatch_queue_context");
+ if (kgsl.has_kgsl_a3xx_irq_status() && kgsl.kgsl_a3xx_irq_status())
+ result.push_back("kgsl:kgsl_a3xx_irq_status");
+ if (kgsl.has_kgsl_a4xx_irq_status() && kgsl.kgsl_a4xx_irq_status())
+ result.push_back("kgsl:kgsl_a4xx_irq_status");
+ if (kgsl.has_kgsl_a5xx_irq_status() && kgsl.kgsl_a5xx_irq_status())
+ result.push_back("kgsl:kgsl_a5xx_irq_status");
+ if (kgsl.has_kgsl_active_count() && kgsl.kgsl_active_count())
+ result.push_back("kgsl:kgsl_active_count");
+ if (kgsl.has_kgsl_bus() && kgsl.kgsl_bus())
+ result.push_back("kgsl:kgsl_bus");
+ if (kgsl.has_kgsl_buslevel() && kgsl.kgsl_buslevel())
+ result.push_back("kgsl:kgsl_buslevel");
+ if (kgsl.has_kgsl_clk() && kgsl.kgsl_clk())
+ result.push_back("kgsl:kgsl_clk");
+ if (kgsl.has_kgsl_constraint() && kgsl.kgsl_constraint())
+ result.push_back("kgsl:kgsl_constraint");
+ if (kgsl.has_kgsl_context_create() && kgsl.kgsl_context_create())
+ result.push_back("kgsl:kgsl_context_create");
+ if (kgsl.has_kgsl_context_destroy() && kgsl.kgsl_context_destroy())
+ result.push_back("kgsl:kgsl_context_destroy");
+ if (kgsl.has_kgsl_context_detach() && kgsl.kgsl_context_detach())
+ result.push_back("kgsl:kgsl_context_detach");
+ if (kgsl.has_kgsl_fire_event() && kgsl.kgsl_fire_event())
+ result.push_back("kgsl:kgsl_fire_event");
+ if (kgsl.has_kgsl_gpubusy() && kgsl.kgsl_gpubusy())
+ result.push_back("kgsl:kgsl_gpubusy");
+ if (kgsl.has_kgsl_irq() && kgsl.kgsl_irq())
+ result.push_back("kgsl:kgsl_irq");
+ if (kgsl.has_kgsl_issueibcmds() && kgsl.kgsl_issueibcmds())
+ result.push_back("kgsl:kgsl_issueibcmds");
+ if (kgsl.has_kgsl_mem_alloc() && kgsl.kgsl_mem_alloc())
+ result.push_back("kgsl:kgsl_mem_alloc");
+ if (kgsl.has_kgsl_mem_free() && kgsl.kgsl_mem_free())
+ result.push_back("kgsl:kgsl_mem_free");
+ if (kgsl.has_kgsl_mem_map() && kgsl.kgsl_mem_map())
+ result.push_back("kgsl:kgsl_mem_map");
+ if (kgsl.has_kgsl_mem_mmap() && kgsl.kgsl_mem_mmap())
+ result.push_back("kgsl:kgsl_mem_mmap");
+ if (kgsl.has_kgsl_mem_sync_cache() && kgsl.kgsl_mem_sync_cache())
+ result.push_back("kgsl:kgsl_mem_sync_cache");
+ if (kgsl.has_kgsl_mem_sync_full_cache() && kgsl.kgsl_mem_sync_full_cache())
+ result.push_back("kgsl:kgsl_mem_sync_full_cache");
+ if (kgsl.has_kgsl_mem_timestamp_free() && kgsl.kgsl_mem_timestamp_free())
+ result.push_back("kgsl:kgsl_mem_timestamp_free");
+ if (kgsl.has_kgsl_mem_timestamp_queue() && kgsl.kgsl_mem_timestamp_queue())
+ result.push_back("kgsl:kgsl_mem_timestamp_queue");
+ if (kgsl.has_kgsl_mem_unmapped_area_collision() && kgsl.kgsl_mem_unmapped_area_collision())
+ result.push_back("kgsl:kgsl_mem_unmapped_area_collision");
+ if (kgsl.has_kgsl_mmu_pagefault() && kgsl.kgsl_mmu_pagefault())
+ result.push_back("kgsl:kgsl_mmu_pagefault");
+ if (kgsl.has_kgsl_msg() && kgsl.kgsl_msg())
+ result.push_back("kgsl:kgsl_msg");
+ if (kgsl.has_kgsl_pagetable_destroy() && kgsl.kgsl_pagetable_destroy())
+ result.push_back("kgsl:kgsl_pagetable_destroy");
+ if (kgsl.has_kgsl_popp_level() && kgsl.kgsl_popp_level())
+ result.push_back("kgsl:kgsl_popp_level");
+ if (kgsl.has_kgsl_popp_mod() && kgsl.kgsl_popp_mod())
+ result.push_back("kgsl:kgsl_popp_mod");
+ if (kgsl.has_kgsl_popp_nap() && kgsl.kgsl_popp_nap())
+ result.push_back("kgsl:kgsl_popp_nap");
+ if (kgsl.has_kgsl_pwr_request_state() && kgsl.kgsl_pwr_request_state())
+ result.push_back("kgsl:kgsl_pwr_request_state");
+ if (kgsl.has_kgsl_pwr_set_state() && kgsl.kgsl_pwr_set_state())
+ result.push_back("kgsl:kgsl_pwr_set_state");
+ if (kgsl.has_kgsl_pwrlevel() && kgsl.kgsl_pwrlevel())
+ result.push_back("kgsl:kgsl_pwrlevel");
+ if (kgsl.has_kgsl_pwrstats() && kgsl.kgsl_pwrstats())
+ result.push_back("kgsl:kgsl_pwrstats");
+ if (kgsl.has_kgsl_rail() && kgsl.kgsl_rail())
+ result.push_back("kgsl:kgsl_rail");
+ if (kgsl.has_kgsl_readtimestamp() && kgsl.kgsl_readtimestamp())
+ result.push_back("kgsl:kgsl_readtimestamp");
+ if (kgsl.has_kgsl_register_event() && kgsl.kgsl_register_event())
+ result.push_back("kgsl:kgsl_register_event");
+ if (kgsl.has_kgsl_regwrite() && kgsl.kgsl_regwrite())
+ result.push_back("kgsl:kgsl_regwrite");
+ if (kgsl.has_kgsl_retention_clk() && kgsl.kgsl_retention_clk())
+ result.push_back("kgsl:kgsl_retention_clk");
+ if (kgsl.has_kgsl_user_pwrlevel_constraint() && kgsl.kgsl_user_pwrlevel_constraint())
+ result.push_back("kgsl:kgsl_user_pwrlevel_constraint");
+ if (kgsl.has_kgsl_waittimestamp_entry() && kgsl.kgsl_waittimestamp_entry())
+ result.push_back("kgsl:kgsl_waittimestamp_entry");
+ if (kgsl.has_kgsl_waittimestamp_exit() && kgsl.kgsl_waittimestamp_exit())
+ result.push_back("kgsl:kgsl_waittimestamp_exit");
+ if (kgsl.has_syncpoint_fence() && kgsl.syncpoint_fence())
+ result.push_back("kgsl:syncpoint_fence");
+ if (kgsl.has_syncpoint_fence_expire() && kgsl.syncpoint_fence_expire())
+ result.push_back("kgsl:syncpoint_fence_expire");
+ if (kgsl.has_syncpoint_timestamp() && kgsl.syncpoint_timestamp())
+ result.push_back("kgsl:syncpoint_timestamp");
+ if (kgsl.has_syncpoint_timestamp_expire() && kgsl.syncpoint_timestamp_expire())
+ result.push_back("kgsl:syncpoint_timestamp_expire");
+ }
+
+ if (tracepoints.has_kmem()) {
+ const auto& kmem = tracepoints.kmem();
+
+ if (kmem.has_alloc_pages_iommu_end() && kmem.alloc_pages_iommu_end())
+ result.push_back("kmem:alloc_pages_iommu_end");
+ if (kmem.has_alloc_pages_iommu_fail() && kmem.alloc_pages_iommu_fail())
+ result.push_back("kmem:alloc_pages_iommu_fail");
+ if (kmem.has_alloc_pages_iommu_start() && kmem.alloc_pages_iommu_start())
+ result.push_back("kmem:alloc_pages_iommu_start");
+ if (kmem.has_alloc_pages_sys_end() && kmem.alloc_pages_sys_end())
+ result.push_back("kmem:alloc_pages_sys_end");
+ if (kmem.has_alloc_pages_sys_fail() && kmem.alloc_pages_sys_fail())
+ result.push_back("kmem:alloc_pages_sys_fail");
+ if (kmem.has_alloc_pages_sys_start() && kmem.alloc_pages_sys_start())
+ result.push_back("kmem:alloc_pages_sys_start");
+ if (kmem.has_dma_alloc_contiguous_retry() && kmem.dma_alloc_contiguous_retry())
+ result.push_back("kmem:dma_alloc_contiguous_retry");
+ if (kmem.has_iommu_map_range() && kmem.iommu_map_range())
+ result.push_back("kmem:iommu_map_range");
+ if (kmem.has_iommu_sec_ptbl_map_range_end() && kmem.iommu_sec_ptbl_map_range_end())
+ result.push_back("kmem:iommu_sec_ptbl_map_range_end");
+ if (kmem.has_iommu_sec_ptbl_map_range_start() && kmem.iommu_sec_ptbl_map_range_start())
+ result.push_back("kmem:iommu_sec_ptbl_map_range_start");
+ if (kmem.has_ion_alloc_buffer_end() && kmem.ion_alloc_buffer_end())
+ result.push_back("kmem:ion_alloc_buffer_end");
+ if (kmem.has_ion_alloc_buffer_fail() && kmem.ion_alloc_buffer_fail())
+ result.push_back("kmem:ion_alloc_buffer_fail");
+ if (kmem.has_ion_alloc_buffer_fallback() && kmem.ion_alloc_buffer_fallback())
+ result.push_back("kmem:ion_alloc_buffer_fallback");
+ if (kmem.has_ion_alloc_buffer_start() && kmem.ion_alloc_buffer_start())
+ result.push_back("kmem:ion_alloc_buffer_start");
+ if (kmem.has_ion_cp_alloc_retry() && kmem.ion_cp_alloc_retry())
+ result.push_back("kmem:ion_cp_alloc_retry");
+ if (kmem.has_ion_cp_secure_buffer_end() && kmem.ion_cp_secure_buffer_end())
+ result.push_back("kmem:ion_cp_secure_buffer_end");
+ if (kmem.has_ion_cp_secure_buffer_start() && kmem.ion_cp_secure_buffer_start())
+ result.push_back("kmem:ion_cp_secure_buffer_start");
+ if (kmem.has_ion_prefetching() && kmem.ion_prefetching())
+ result.push_back("kmem:ion_prefetching");
+ if (kmem.has_ion_secure_cma_add_to_pool_end() && kmem.ion_secure_cma_add_to_pool_end())
+ result.push_back("kmem:ion_secure_cma_add_to_pool_end");
+ if (kmem.has_ion_secure_cma_add_to_pool_start() && kmem.ion_secure_cma_add_to_pool_start())
+ result.push_back("kmem:ion_secure_cma_add_to_pool_start");
+ if (kmem.has_ion_secure_cma_allocate_end() && kmem.ion_secure_cma_allocate_end())
+ result.push_back("kmem:ion_secure_cma_allocate_end");
+ if (kmem.has_ion_secure_cma_allocate_start() && kmem.ion_secure_cma_allocate_start())
+ result.push_back("kmem:ion_secure_cma_allocate_start");
+ if (kmem.has_ion_secure_cma_shrink_pool_end() && kmem.ion_secure_cma_shrink_pool_end())
+ result.push_back("kmem:ion_secure_cma_shrink_pool_end");
+ if (kmem.has_ion_secure_cma_shrink_pool_start() && kmem.ion_secure_cma_shrink_pool_start())
+ result.push_back("kmem:ion_secure_cma_shrink_pool_start");
+ if (kmem.has_kfree() && kmem.kfree())
+ result.push_back("kmem:kfree");
+ if (kmem.has_kmalloc() && kmem.kmalloc())
+ result.push_back("kmem:kmalloc");
+ if (kmem.has_kmalloc_node() && kmem.kmalloc_node())
+ result.push_back("kmem:kmalloc_node");
+ if (kmem.has_kmem_cache_alloc() && kmem.kmem_cache_alloc())
+ result.push_back("kmem:kmem_cache_alloc");
+ if (kmem.has_kmem_cache_alloc_node() && kmem.kmem_cache_alloc_node())
+ result.push_back("kmem:kmem_cache_alloc_node");
+ if (kmem.has_kmem_cache_free() && kmem.kmem_cache_free())
+ result.push_back("kmem:kmem_cache_free");
+ if (kmem.has_migrate_pages_end() && kmem.migrate_pages_end())
+ result.push_back("kmem:migrate_pages_end");
+ if (kmem.has_migrate_pages_start() && kmem.migrate_pages_start())
+ result.push_back("kmem:migrate_pages_start");
+ if (kmem.has_migrate_retry() && kmem.migrate_retry())
+ result.push_back("kmem:migrate_retry");
+ if (kmem.has_mm_page_alloc() && kmem.mm_page_alloc())
+ result.push_back("kmem:mm_page_alloc");
+ if (kmem.has_mm_page_alloc_extfrag() && kmem.mm_page_alloc_extfrag())
+ result.push_back("kmem:mm_page_alloc_extfrag");
+ if (kmem.has_mm_page_alloc_zone_locked() && kmem.mm_page_alloc_zone_locked())
+ result.push_back("kmem:mm_page_alloc_zone_locked");
+ if (kmem.has_mm_page_free() && kmem.mm_page_free())
+ result.push_back("kmem:mm_page_free");
+ if (kmem.has_mm_page_free_batched() && kmem.mm_page_free_batched())
+ result.push_back("kmem:mm_page_free_batched");
+ if (kmem.has_mm_page_pcpu_drain() && kmem.mm_page_pcpu_drain())
+ result.push_back("kmem:mm_page_pcpu_drain");
+ }
+
+ if (tracepoints.has_lowmemorykiller()) {
+ const auto& lowmemorykiller = tracepoints.lowmemorykiller();
+
+ if (lowmemorykiller.has_lowmemory_kill() && lowmemorykiller.lowmemory_kill())
+ result.push_back("lowmemorykiller:lowmemory_kill");
+ }
+
+ if (tracepoints.has_mdss()) {
+ const auto& mdss = tracepoints.mdss();
+
+ if (mdss.has_mdp_cmd_kickoff() && mdss.mdp_cmd_kickoff())
+ result.push_back("mdss:mdp_cmd_kickoff");
+ if (mdss.has_mdp_cmd_pingpong_done() && mdss.mdp_cmd_pingpong_done())
+ result.push_back("mdss:mdp_cmd_pingpong_done");
+ if (mdss.has_mdp_cmd_release_bw() && mdss.mdp_cmd_release_bw())
+ result.push_back("mdss:mdp_cmd_release_bw");
+ if (mdss.has_mdp_cmd_wait_pingpong() && mdss.mdp_cmd_wait_pingpong())
+ result.push_back("mdss:mdp_cmd_wait_pingpong");
+ if (mdss.has_mdp_commit() && mdss.mdp_commit())
+ result.push_back("mdss:mdp_commit");
+ if (mdss.has_mdp_misr_crc() && mdss.mdp_misr_crc())
+ result.push_back("mdss:mdp_misr_crc");
+ if (mdss.has_mdp_mixer_update() && mdss.mdp_mixer_update())
+ result.push_back("mdss:mdp_mixer_update");
+ if (mdss.has_mdp_perf_prefill_calc() && mdss.mdp_perf_prefill_calc())
+ result.push_back("mdss:mdp_perf_prefill_calc");
+ if (mdss.has_mdp_perf_set_ot() && mdss.mdp_perf_set_ot())
+ result.push_back("mdss:mdp_perf_set_ot");
+ if (mdss.has_mdp_perf_set_panic_luts() && mdss.mdp_perf_set_panic_luts())
+ result.push_back("mdss:mdp_perf_set_panic_luts");
+ if (mdss.has_mdp_perf_set_qos_luts() && mdss.mdp_perf_set_qos_luts())
+ result.push_back("mdss:mdp_perf_set_qos_luts");
+ if (mdss.has_mdp_perf_set_wm_levels() && mdss.mdp_perf_set_wm_levels())
+ result.push_back("mdss:mdp_perf_set_wm_levels");
+ if (mdss.has_mdp_perf_update_bus() && mdss.mdp_perf_update_bus())
+ result.push_back("mdss:mdp_perf_update_bus");
+ if (mdss.has_mdp_sspp_change() && mdss.mdp_sspp_change())
+ result.push_back("mdss:mdp_sspp_change");
+ if (mdss.has_mdp_sspp_set() && mdss.mdp_sspp_set())
+ result.push_back("mdss:mdp_sspp_set");
+ if (mdss.has_mdp_trace_counter() && mdss.mdp_trace_counter())
+ result.push_back("mdss:mdp_trace_counter");
+ if (mdss.has_mdp_video_underrun_done() && mdss.mdp_video_underrun_done())
+ result.push_back("mdss:mdp_video_underrun_done");
+ if (mdss.has_rotator_bw_ao_as_context() && mdss.rotator_bw_ao_as_context())
+ result.push_back("mdss:rotator_bw_ao_as_context");
+ if (mdss.has_tracing_mark_write() && mdss.tracing_mark_write())
+ result.push_back("mdss:tracing_mark_write");
+ }
+
+ if (tracepoints.has_migrate()) {
+ const auto& migrate = tracepoints.migrate();
+
+ if (migrate.has_mm_migrate_pages() && migrate.mm_migrate_pages())
+ result.push_back("migrate:mm_migrate_pages");
+ if (migrate.has_mm_migrate_pages_start() && migrate.mm_migrate_pages_start())
+ result.push_back("migrate:mm_migrate_pages_start");
+ if (migrate.has_mm_numa_migrate_ratelimit() && migrate.mm_numa_migrate_ratelimit())
+ result.push_back("migrate:mm_numa_migrate_ratelimit");
+ }
+
+ if (tracepoints.has_module()) {
+ const auto& module = tracepoints.module();
+
+ if (module.has_module_free() && module.module_free())
+ result.push_back("module:module_free");
+ if (module.has_module_get() && module.module_get())
+ result.push_back("module:module_get");
+ if (module.has_module_load() && module.module_load())
+ result.push_back("module:module_load");
+ if (module.has_module_put() && module.module_put())
+ result.push_back("module:module_put");
+ if (module.has_module_request() && module.module_request())
+ result.push_back("module:module_request");
+ }
+
+ if (tracepoints.has_msm_bus()) {
+ const auto& msm_bus = tracepoints.msm_bus();
+
+ if (msm_bus.has_bus_agg_bw() && msm_bus.bus_agg_bw())
+ result.push_back("msm_bus:bus_agg_bw");
+ if (msm_bus.has_bus_avail_bw() && msm_bus.bus_avail_bw())
+ result.push_back("msm_bus:bus_avail_bw");
+ if (msm_bus.has_bus_bimc_config_limiter() && msm_bus.bus_bimc_config_limiter())
+ result.push_back("msm_bus:bus_bimc_config_limiter");
+ if (msm_bus.has_bus_bke_params() && msm_bus.bus_bke_params())
+ result.push_back("msm_bus:bus_bke_params");
+ if (msm_bus.has_bus_client_status() && msm_bus.bus_client_status())
+ result.push_back("msm_bus:bus_client_status");
+ if (msm_bus.has_bus_rules_matches() && msm_bus.bus_rules_matches())
+ result.push_back("msm_bus:bus_rules_matches");
+ if (msm_bus.has_bus_update_request() && msm_bus.bus_update_request())
+ result.push_back("msm_bus:bus_update_request");
+ if (msm_bus.has_bus_update_request_end() && msm_bus.bus_update_request_end())
+ result.push_back("msm_bus:bus_update_request_end");
+ }
+
+ if (tracepoints.has_msm_low_power()) {
+ const auto& msm_low_power = tracepoints.msm_low_power();
+
+ if (msm_low_power.has_cluster_enter() && msm_low_power.cluster_enter())
+ result.push_back("msm_low_power:cluster_enter");
+ if (msm_low_power.has_cluster_exit() && msm_low_power.cluster_exit())
+ result.push_back("msm_low_power:cluster_exit");
+ if (msm_low_power.has_cpu_idle_enter() && msm_low_power.cpu_idle_enter())
+ result.push_back("msm_low_power:cpu_idle_enter");
+ if (msm_low_power.has_cpu_idle_exit() && msm_low_power.cpu_idle_exit())
+ result.push_back("msm_low_power:cpu_idle_exit");
+ if (msm_low_power.has_cpu_power_select() && msm_low_power.cpu_power_select())
+ result.push_back("msm_low_power:cpu_power_select");
+ if (msm_low_power.has_pre_pc_cb() && msm_low_power.pre_pc_cb())
+ result.push_back("msm_low_power:pre_pc_cb");
+ }
+
+ if (tracepoints.has_msm_vidc()) {
+ const auto& msm_vidc = tracepoints.msm_vidc();
+
+ if (msm_vidc.has_msm_smem_buffer_iommu_op_end() && msm_vidc.msm_smem_buffer_iommu_op_end())
+ result.push_back("msm_vidc:msm_smem_buffer_iommu_op_end");
+ if (msm_vidc.has_msm_smem_buffer_iommu_op_start() && msm_vidc.msm_smem_buffer_iommu_op_start())
+ result.push_back("msm_vidc:msm_smem_buffer_iommu_op_start");
+ if (msm_vidc.has_msm_smem_buffer_ion_op_end() && msm_vidc.msm_smem_buffer_ion_op_end())
+ result.push_back("msm_vidc:msm_smem_buffer_ion_op_end");
+ if (msm_vidc.has_msm_smem_buffer_ion_op_start() && msm_vidc.msm_smem_buffer_ion_op_start())
+ result.push_back("msm_vidc:msm_smem_buffer_ion_op_start");
+ if (msm_vidc.has_msm_v4l2_vidc_buffer_event_end() && msm_vidc.msm_v4l2_vidc_buffer_event_end())
+ result.push_back("msm_vidc:msm_v4l2_vidc_buffer_event_end");
+ if (msm_vidc.has_msm_v4l2_vidc_buffer_event_start() && msm_vidc.msm_v4l2_vidc_buffer_event_start())
+ result.push_back("msm_vidc:msm_v4l2_vidc_buffer_event_start");
+ if (msm_vidc.has_msm_v4l2_vidc_close_end() && msm_vidc.msm_v4l2_vidc_close_end())
+ result.push_back("msm_vidc:msm_v4l2_vidc_close_end");
+ if (msm_vidc.has_msm_v4l2_vidc_close_start() && msm_vidc.msm_v4l2_vidc_close_start())
+ result.push_back("msm_vidc:msm_v4l2_vidc_close_start");
+ if (msm_vidc.has_msm_v4l2_vidc_fw_load_end() && msm_vidc.msm_v4l2_vidc_fw_load_end())
+ result.push_back("msm_vidc:msm_v4l2_vidc_fw_load_end");
+ if (msm_vidc.has_msm_v4l2_vidc_fw_load_start() && msm_vidc.msm_v4l2_vidc_fw_load_start())
+ result.push_back("msm_vidc:msm_v4l2_vidc_fw_load_start");
+ if (msm_vidc.has_msm_v4l2_vidc_open_end() && msm_vidc.msm_v4l2_vidc_open_end())
+ result.push_back("msm_vidc:msm_v4l2_vidc_open_end");
+ if (msm_vidc.has_msm_v4l2_vidc_open_start() && msm_vidc.msm_v4l2_vidc_open_start())
+ result.push_back("msm_vidc:msm_v4l2_vidc_open_start");
+ if (msm_vidc.has_msm_vidc_common_state_change() && msm_vidc.msm_vidc_common_state_change())
+ result.push_back("msm_vidc:msm_vidc_common_state_change");
+ if (msm_vidc.has_venus_hfi_var_done() && msm_vidc.venus_hfi_var_done())
+ result.push_back("msm_vidc:venus_hfi_var_done");
+ }
+
+ if (tracepoints.has_napi()) {
+ const auto& napi = tracepoints.napi();
+
+ if (napi.has_napi_poll() && napi.napi_poll())
+ result.push_back("napi:napi_poll");
+ }
+
+ if (tracepoints.has_net()) {
+ const auto& net = tracepoints.net();
+
+ if (net.has_napi_gro_frags_entry() && net.napi_gro_frags_entry())
+ result.push_back("net:napi_gro_frags_entry");
+ if (net.has_napi_gro_receive_entry() && net.napi_gro_receive_entry())
+ result.push_back("net:napi_gro_receive_entry");
+ if (net.has_net_dev_queue() && net.net_dev_queue())
+ result.push_back("net:net_dev_queue");
+ if (net.has_net_dev_start_xmit() && net.net_dev_start_xmit())
+ result.push_back("net:net_dev_start_xmit");
+ if (net.has_net_dev_xmit() && net.net_dev_xmit())
+ result.push_back("net:net_dev_xmit");
+ if (net.has_netif_receive_skb() && net.netif_receive_skb())
+ result.push_back("net:netif_receive_skb");
+ if (net.has_netif_receive_skb_entry() && net.netif_receive_skb_entry())
+ result.push_back("net:netif_receive_skb_entry");
+ if (net.has_netif_rx() && net.netif_rx())
+ result.push_back("net:netif_rx");
+ if (net.has_netif_rx_entry() && net.netif_rx_entry())
+ result.push_back("net:netif_rx_entry");
+ if (net.has_netif_rx_ni_entry() && net.netif_rx_ni_entry())
+ result.push_back("net:netif_rx_ni_entry");
+ }
+
+ if (tracepoints.has_oom()) {
+ const auto& oom = tracepoints.oom();
+
+ if (oom.has_oom_score_adj_update() && oom.oom_score_adj_update())
+ result.push_back("oom:oom_score_adj_update");
+ }
+
+ if (tracepoints.has_pagemap()) {
+ const auto& pagemap = tracepoints.pagemap();
+
+ if (pagemap.has_mm_lru_activate() && pagemap.mm_lru_activate())
+ result.push_back("pagemap:mm_lru_activate");
+ if (pagemap.has_mm_lru_insertion() && pagemap.mm_lru_insertion())
+ result.push_back("pagemap:mm_lru_insertion");
+ }
+
+ if (tracepoints.has_perf_trace_counters()) {
+ const auto& perf_trace_counters = tracepoints.perf_trace_counters();
+
+ if (perf_trace_counters.has_perf_trace_user() && perf_trace_counters.perf_trace_user())
+ result.push_back("perf_trace_counters:perf_trace_user");
+ if (perf_trace_counters.has_sched_switch_with_ctrs() && perf_trace_counters.sched_switch_with_ctrs())
+ result.push_back("perf_trace_counters:sched_switch_with_ctrs");
+ }
+
+ if (tracepoints.has_power()) {
+ const auto& power = tracepoints.power();
+
+ if (power.has_bw_hwmon_meas() && power.bw_hwmon_meas())
+ result.push_back("power:bw_hwmon_meas");
+ if (power.has_bw_hwmon_update() && power.bw_hwmon_update())
+ result.push_back("power:bw_hwmon_update");
+ if (power.has_cache_hwmon_meas() && power.cache_hwmon_meas())
+ result.push_back("power:cache_hwmon_meas");
+ if (power.has_cache_hwmon_update() && power.cache_hwmon_update())
+ result.push_back("power:cache_hwmon_update");
+ if (power.has_clock_disable() && power.clock_disable())
+ result.push_back("power:clock_disable");
+ if (power.has_clock_enable() && power.clock_enable())
+ result.push_back("power:clock_enable");
+ if (power.has_clock_set_parent() && power.clock_set_parent())
+ result.push_back("power:clock_set_parent");
+ if (power.has_clock_set_rate() && power.clock_set_rate())
+ result.push_back("power:clock_set_rate");
+ if (power.has_clock_set_rate_complete() && power.clock_set_rate_complete())
+ result.push_back("power:clock_set_rate_complete");
+ if (power.has_clock_state() && power.clock_state())
+ result.push_back("power:clock_state");
+ if (power.has_core_ctl_eval_need() && power.core_ctl_eval_need())
+ result.push_back("power:core_ctl_eval_need");
+ if (power.has_core_ctl_set_busy() && power.core_ctl_set_busy())
+ result.push_back("power:core_ctl_set_busy");
+ if (power.has_cpu_capacity() && power.cpu_capacity())
+ result.push_back("power:cpu_capacity");
+ if (power.has_cpu_frequency() && power.cpu_frequency())
+ result.push_back("power:cpu_frequency");
+ if (power.has_cpu_frequency_limits() && power.cpu_frequency_limits())
+ result.push_back("power:cpu_frequency_limits");
+ if (power.has_cpu_frequency_switch_end() && power.cpu_frequency_switch_end())
+ result.push_back("power:cpu_frequency_switch_end");
+ if (power.has_cpu_frequency_switch_start() && power.cpu_frequency_switch_start())
+ result.push_back("power:cpu_frequency_switch_start");
+ if (power.has_cpu_idle() && power.cpu_idle())
+ result.push_back("power:cpu_idle");
+ if (power.has_cpu_mode_detect() && power.cpu_mode_detect())
+ result.push_back("power:cpu_mode_detect");
+ if (power.has_cpufreq_freq_synced() && power.cpufreq_freq_synced())
+ result.push_back("power:cpufreq_freq_synced");
+ if (power.has_cpufreq_sampling_event() && power.cpufreq_sampling_event())
+ result.push_back("power:cpufreq_sampling_event");
+ if (power.has_dev_pm_qos_add_request() && power.dev_pm_qos_add_request())
+ result.push_back("power:dev_pm_qos_add_request");
+ if (power.has_dev_pm_qos_remove_request() && power.dev_pm_qos_remove_request())
+ result.push_back("power:dev_pm_qos_remove_request");
+ if (power.has_dev_pm_qos_update_request() && power.dev_pm_qos_update_request())
+ result.push_back("power:dev_pm_qos_update_request");
+ if (power.has_device_pm_callback_end() && power.device_pm_callback_end())
+ result.push_back("power:device_pm_callback_end");
+ if (power.has_device_pm_callback_start() && power.device_pm_callback_start())
+ result.push_back("power:device_pm_callback_start");
+ if (power.has_memlat_dev_meas() && power.memlat_dev_meas())
+ result.push_back("power:memlat_dev_meas");
+ if (power.has_memlat_dev_update() && power.memlat_dev_update())
+ result.push_back("power:memlat_dev_update");
+ if (power.has_msmpower_max_ddr() && power.msmpower_max_ddr())
+ result.push_back("power:msmpower_max_ddr");
+ if (power.has_perf_cl_peak_exit_timer_start() && power.perf_cl_peak_exit_timer_start())
+ result.push_back("power:perf_cl_peak_exit_timer_start");
+ if (power.has_perf_cl_peak_exit_timer_stop() && power.perf_cl_peak_exit_timer_stop())
+ result.push_back("power:perf_cl_peak_exit_timer_stop");
+ if (power.has_pm_qos_add_request() && power.pm_qos_add_request())
+ result.push_back("power:pm_qos_add_request");
+ if (power.has_pm_qos_remove_request() && power.pm_qos_remove_request())
+ result.push_back("power:pm_qos_remove_request");
+ if (power.has_pm_qos_update_flags() && power.pm_qos_update_flags())
+ result.push_back("power:pm_qos_update_flags");
+ if (power.has_pm_qos_update_request() && power.pm_qos_update_request())
+ result.push_back("power:pm_qos_update_request");
+ if (power.has_pm_qos_update_request_timeout() && power.pm_qos_update_request_timeout())
+ result.push_back("power:pm_qos_update_request_timeout");
+ if (power.has_pm_qos_update_target() && power.pm_qos_update_target())
+ result.push_back("power:pm_qos_update_target");
+ if (power.has_power_domain_target() && power.power_domain_target())
+ result.push_back("power:power_domain_target");
+ if (power.has_pstate_sample() && power.pstate_sample())
+ result.push_back("power:pstate_sample");
+ if (power.has_reevaluate_hotplug() && power.reevaluate_hotplug())
+ result.push_back("power:reevaluate_hotplug");
+ if (power.has_set_max_cpus() && power.set_max_cpus())
+ result.push_back("power:set_max_cpus");
+ if (power.has_single_cycle_exit_timer_start() && power.single_cycle_exit_timer_start())
+ result.push_back("power:single_cycle_exit_timer_start");
+ if (power.has_single_cycle_exit_timer_stop() && power.single_cycle_exit_timer_stop())
+ result.push_back("power:single_cycle_exit_timer_stop");
+ if (power.has_single_mode_timeout() && power.single_mode_timeout())
+ result.push_back("power:single_mode_timeout");
+ if (power.has_suspend_resume() && power.suspend_resume())
+ result.push_back("power:suspend_resume");
+ if (power.has_track_iowait() && power.track_iowait())
+ result.push_back("power:track_iowait");
+ if (power.has_wakeup_source_activate() && power.wakeup_source_activate())
+ result.push_back("power:wakeup_source_activate");
+ if (power.has_wakeup_source_deactivate() && power.wakeup_source_deactivate())
+ result.push_back("power:wakeup_source_deactivate");
+ }
+
+ if (tracepoints.has_printk()) {
+ const auto& printk = tracepoints.printk();
+
+ if (printk.has_console() && printk.console())
+ result.push_back("printk:console");
+ }
+
+ if (tracepoints.has_random()) {
+ const auto& random = tracepoints.random();
+
+ if (random.has_add_device_randomness() && random.add_device_randomness())
+ result.push_back("random:add_device_randomness");
+ if (random.has_add_disk_randomness() && random.add_disk_randomness())
+ result.push_back("random:add_disk_randomness");
+ if (random.has_add_input_randomness() && random.add_input_randomness())
+ result.push_back("random:add_input_randomness");
+ if (random.has_credit_entropy_bits() && random.credit_entropy_bits())
+ result.push_back("random:credit_entropy_bits");
+ if (random.has_debit_entropy() && random.debit_entropy())
+ result.push_back("random:debit_entropy");
+ if (random.has_extract_entropy() && random.extract_entropy())
+ result.push_back("random:extract_entropy");
+ if (random.has_extract_entropy_user() && random.extract_entropy_user())
+ result.push_back("random:extract_entropy_user");
+ if (random.has_get_random_bytes() && random.get_random_bytes())
+ result.push_back("random:get_random_bytes");
+ if (random.has_get_random_bytes_arch() && random.get_random_bytes_arch())
+ result.push_back("random:get_random_bytes_arch");
+ if (random.has_mix_pool_bytes() && random.mix_pool_bytes())
+ result.push_back("random:mix_pool_bytes");
+ if (random.has_mix_pool_bytes_nolock() && random.mix_pool_bytes_nolock())
+ result.push_back("random:mix_pool_bytes_nolock");
+ if (random.has_push_to_pool() && random.push_to_pool())
+ result.push_back("random:push_to_pool");
+ if (random.has_random_read() && random.random_read())
+ result.push_back("random:random_read");
+ if (random.has_urandom_read() && random.urandom_read())
+ result.push_back("random:urandom_read");
+ if (random.has_xfer_secondary_pool() && random.xfer_secondary_pool())
+ result.push_back("random:xfer_secondary_pool");
+ }
+
+ if (tracepoints.has_raw_syscalls()) {
+ const auto& raw_syscalls = tracepoints.raw_syscalls();
+
+ if (raw_syscalls.has_sys_enter() && raw_syscalls.sys_enter())
+ result.push_back("raw_syscalls:sys_enter");
+ if (raw_syscalls.has_sys_exit() && raw_syscalls.sys_exit())
+ result.push_back("raw_syscalls:sys_exit");
+ }
+
+ if (tracepoints.has_rcu()) {
+ const auto& rcu = tracepoints.rcu();
+
+ if (rcu.has_rcu_utilization() && rcu.rcu_utilization())
+ result.push_back("rcu:rcu_utilization");
+ }
+
+ if (tracepoints.has_regmap()) {
+ const auto& regmap = tracepoints.regmap();
+
+ if (regmap.has_regcache_drop_region() && regmap.regcache_drop_region())
+ result.push_back("regmap:regcache_drop_region");
+ if (regmap.has_regcache_sync() && regmap.regcache_sync())
+ result.push_back("regmap:regcache_sync");
+ if (regmap.has_regmap_async_complete_done() && regmap.regmap_async_complete_done())
+ result.push_back("regmap:regmap_async_complete_done");
+ if (regmap.has_regmap_async_complete_start() && regmap.regmap_async_complete_start())
+ result.push_back("regmap:regmap_async_complete_start");
+ if (regmap.has_regmap_async_io_complete() && regmap.regmap_async_io_complete())
+ result.push_back("regmap:regmap_async_io_complete");
+ if (regmap.has_regmap_async_write_start() && regmap.regmap_async_write_start())
+ result.push_back("regmap:regmap_async_write_start");
+ if (regmap.has_regmap_cache_bypass() && regmap.regmap_cache_bypass())
+ result.push_back("regmap:regmap_cache_bypass");
+ if (regmap.has_regmap_cache_only() && regmap.regmap_cache_only())
+ result.push_back("regmap:regmap_cache_only");
+ if (regmap.has_regmap_hw_read_done() && regmap.regmap_hw_read_done())
+ result.push_back("regmap:regmap_hw_read_done");
+ if (regmap.has_regmap_hw_read_start() && regmap.regmap_hw_read_start())
+ result.push_back("regmap:regmap_hw_read_start");
+ if (regmap.has_regmap_hw_write_done() && regmap.regmap_hw_write_done())
+ result.push_back("regmap:regmap_hw_write_done");
+ if (regmap.has_regmap_hw_write_start() && regmap.regmap_hw_write_start())
+ result.push_back("regmap:regmap_hw_write_start");
+ if (regmap.has_regmap_reg_read() && regmap.regmap_reg_read())
+ result.push_back("regmap:regmap_reg_read");
+ if (regmap.has_regmap_reg_read_cache() && regmap.regmap_reg_read_cache())
+ result.push_back("regmap:regmap_reg_read_cache");
+ if (regmap.has_regmap_reg_write() && regmap.regmap_reg_write())
+ result.push_back("regmap:regmap_reg_write");
+ }
+
+ if (tracepoints.has_regulator()) {
+ const auto& regulator = tracepoints.regulator();
+
+ if (regulator.has_regulator_disable() && regulator.regulator_disable())
+ result.push_back("regulator:regulator_disable");
+ if (regulator.has_regulator_disable_complete() && regulator.regulator_disable_complete())
+ result.push_back("regulator:regulator_disable_complete");
+ if (regulator.has_regulator_enable() && regulator.regulator_enable())
+ result.push_back("regulator:regulator_enable");
+ if (regulator.has_regulator_enable_complete() && regulator.regulator_enable_complete())
+ result.push_back("regulator:regulator_enable_complete");
+ if (regulator.has_regulator_enable_delay() && regulator.regulator_enable_delay())
+ result.push_back("regulator:regulator_enable_delay");
+ if (regulator.has_regulator_set_voltage() && regulator.regulator_set_voltage())
+ result.push_back("regulator:regulator_set_voltage");
+ if (regulator.has_regulator_set_voltage_complete() && regulator.regulator_set_voltage_complete())
+ result.push_back("regulator:regulator_set_voltage_complete");
+ }
+
+ if (tracepoints.has_rmnet_data()) {
+ const auto& rmnet_data = tracepoints.rmnet_data();
+
+ if (rmnet_data.has___rmnet_deliver_skb() && rmnet_data.__rmnet_deliver_skb())
+ result.push_back("rmnet_data:__rmnet_deliver_skb");
+ if (rmnet_data.has_rmnet_associate() && rmnet_data.rmnet_associate())
+ result.push_back("rmnet_data:rmnet_associate");
+ if (rmnet_data.has_rmnet_egress_handler() && rmnet_data.rmnet_egress_handler())
+ result.push_back("rmnet_data:rmnet_egress_handler");
+ if (rmnet_data.has_rmnet_end_deaggregation() && rmnet_data.rmnet_end_deaggregation())
+ result.push_back("rmnet_data:rmnet_end_deaggregation");
+ if (rmnet_data.has_rmnet_fc_map() && rmnet_data.rmnet_fc_map())
+ result.push_back("rmnet_data:rmnet_fc_map");
+ if (rmnet_data.has_rmnet_fc_qmi() && rmnet_data.rmnet_fc_qmi())
+ result.push_back("rmnet_data:rmnet_fc_qmi");
+ if (rmnet_data.has_rmnet_gro_downlink() && rmnet_data.rmnet_gro_downlink())
+ result.push_back("rmnet_data:rmnet_gro_downlink");
+ if (rmnet_data.has_rmnet_ingress_handler() && rmnet_data.rmnet_ingress_handler())
+ result.push_back("rmnet_data:rmnet_ingress_handler");
+ if (rmnet_data.has_rmnet_map_aggregate() && rmnet_data.rmnet_map_aggregate())
+ result.push_back("rmnet_data:rmnet_map_aggregate");
+ if (rmnet_data.has_rmnet_map_checksum_downlink_packet() && rmnet_data.rmnet_map_checksum_downlink_packet())
+ result.push_back("rmnet_data:rmnet_map_checksum_downlink_packet");
+ if (rmnet_data.has_rmnet_map_checksum_uplink_packet() && rmnet_data.rmnet_map_checksum_uplink_packet())
+ result.push_back("rmnet_data:rmnet_map_checksum_uplink_packet");
+ if (rmnet_data.has_rmnet_map_flush_packet_queue() && rmnet_data.rmnet_map_flush_packet_queue())
+ result.push_back("rmnet_data:rmnet_map_flush_packet_queue");
+ if (rmnet_data.has_rmnet_start_aggregation() && rmnet_data.rmnet_start_aggregation())
+ result.push_back("rmnet_data:rmnet_start_aggregation");
+ if (rmnet_data.has_rmnet_start_deaggregation() && rmnet_data.rmnet_start_deaggregation())
+ result.push_back("rmnet_data:rmnet_start_deaggregation");
+ if (rmnet_data.has_rmnet_unassociate() && rmnet_data.rmnet_unassociate())
+ result.push_back("rmnet_data:rmnet_unassociate");
+ if (rmnet_data.has_rmnet_unregister_cb_clear_lepcs() && rmnet_data.rmnet_unregister_cb_clear_lepcs())
+ result.push_back("rmnet_data:rmnet_unregister_cb_clear_lepcs");
+ if (rmnet_data.has_rmnet_unregister_cb_clear_vnds() && rmnet_data.rmnet_unregister_cb_clear_vnds())
+ result.push_back("rmnet_data:rmnet_unregister_cb_clear_vnds");
+ if (rmnet_data.has_rmnet_unregister_cb_entry() && rmnet_data.rmnet_unregister_cb_entry())
+ result.push_back("rmnet_data:rmnet_unregister_cb_entry");
+ if (rmnet_data.has_rmnet_unregister_cb_exit() && rmnet_data.rmnet_unregister_cb_exit())
+ result.push_back("rmnet_data:rmnet_unregister_cb_exit");
+ if (rmnet_data.has_rmnet_unregister_cb_unhandled() && rmnet_data.rmnet_unregister_cb_unhandled())
+ result.push_back("rmnet_data:rmnet_unregister_cb_unhandled");
+ if (rmnet_data.has_rmnet_vnd_start_xmit() && rmnet_data.rmnet_vnd_start_xmit())
+ result.push_back("rmnet_data:rmnet_vnd_start_xmit");
+ }
+
+ if (tracepoints.has_rndis_ipa()) {
+ const auto& rndis_ipa = tracepoints.rndis_ipa();
+
+ if (rndis_ipa.has_rndis_netif_ni() && rndis_ipa.rndis_netif_ni())
+ result.push_back("rndis_ipa:rndis_netif_ni");
+ if (rndis_ipa.has_rndis_status_rcvd() && rndis_ipa.rndis_status_rcvd())
+ result.push_back("rndis_ipa:rndis_status_rcvd");
+ if (rndis_ipa.has_rndis_tx_dp() && rndis_ipa.rndis_tx_dp())
+ result.push_back("rndis_ipa:rndis_tx_dp");
+ }
+
+ if (tracepoints.has_rpm()) {
+ const auto& rpm = tracepoints.rpm();
+
+ if (rpm.has_rpm_idle() && rpm.rpm_idle())
+ result.push_back("rpm:rpm_idle");
+ if (rpm.has_rpm_resume() && rpm.rpm_resume())
+ result.push_back("rpm:rpm_resume");
+ if (rpm.has_rpm_return_int() && rpm.rpm_return_int())
+ result.push_back("rpm:rpm_return_int");
+ if (rpm.has_rpm_suspend() && rpm.rpm_suspend())
+ result.push_back("rpm:rpm_suspend");
+ }
+
+ if (tracepoints.has_rpm_smd()) {
+ const auto& rpm_smd = tracepoints.rpm_smd();
+
+ if (rpm_smd.has_rpm_smd_ack_recvd() && rpm_smd.rpm_smd_ack_recvd())
+ result.push_back("rpm_smd:rpm_smd_ack_recvd");
+ if (rpm_smd.has_rpm_smd_interrupt_notify() && rpm_smd.rpm_smd_interrupt_notify())
+ result.push_back("rpm_smd:rpm_smd_interrupt_notify");
+ if (rpm_smd.has_rpm_smd_send_active_set() && rpm_smd.rpm_smd_send_active_set())
+ result.push_back("rpm_smd:rpm_smd_send_active_set");
+ if (rpm_smd.has_rpm_smd_send_sleep_set() && rpm_smd.rpm_smd_send_sleep_set())
+ result.push_back("rpm_smd:rpm_smd_send_sleep_set");
+ if (rpm_smd.has_rpm_smd_sleep_set() && rpm_smd.rpm_smd_sleep_set())
+ result.push_back("rpm_smd:rpm_smd_sleep_set");
+ }
+
+ if (tracepoints.has_sched()) {
+ const auto& sched = tracepoints.sched();
+
+ if (sched.has_sched_blocked_reason() && sched.sched_blocked_reason())
+ result.push_back("sched:sched_blocked_reason");
+ if (sched.has_sched_boost_cpu() && sched.sched_boost_cpu())
+ result.push_back("sched:sched_boost_cpu");
+ if (sched.has_sched_boost_task() && sched.sched_boost_task())
+ result.push_back("sched:sched_boost_task");
+ if (sched.has_sched_contrib_scale_f() && sched.sched_contrib_scale_f())
+ result.push_back("sched:sched_contrib_scale_f");
+ if (sched.has_sched_energy_diff() && sched.sched_energy_diff())
+ result.push_back("sched:sched_energy_diff");
+ if (sched.has_sched_energy_perf_deltas() && sched.sched_energy_perf_deltas())
+ result.push_back("sched:sched_energy_perf_deltas");
+ if (sched.has_sched_kthread_stop() && sched.sched_kthread_stop())
+ result.push_back("sched:sched_kthread_stop");
+ if (sched.has_sched_kthread_stop_ret() && sched.sched_kthread_stop_ret())
+ result.push_back("sched:sched_kthread_stop_ret");
+ if (sched.has_sched_load_avg_cpu() && sched.sched_load_avg_cpu())
+ result.push_back("sched:sched_load_avg_cpu");
+ if (sched.has_sched_load_avg_task() && sched.sched_load_avg_task())
+ result.push_back("sched:sched_load_avg_task");
+ if (sched.has_sched_migrate_task() && sched.sched_migrate_task())
+ result.push_back("sched:sched_migrate_task");
+ if (sched.has_sched_move_numa() && sched.sched_move_numa())
+ result.push_back("sched:sched_move_numa");
+ if (sched.has_sched_overutilized() && sched.sched_overutilized())
+ result.push_back("sched:sched_overutilized");
+ if (sched.has_sched_pi_setprio() && sched.sched_pi_setprio())
+ result.push_back("sched:sched_pi_setprio");
+ if (sched.has_sched_process_exec() && sched.sched_process_exec())
+ result.push_back("sched:sched_process_exec");
+ if (sched.has_sched_process_exit() && sched.sched_process_exit())
+ result.push_back("sched:sched_process_exit");
+ if (sched.has_sched_process_fork() && sched.sched_process_fork())
+ result.push_back("sched:sched_process_fork");
+ if (sched.has_sched_process_free() && sched.sched_process_free())
+ result.push_back("sched:sched_process_free");
+ if (sched.has_sched_process_hang() && sched.sched_process_hang())
+ result.push_back("sched:sched_process_hang");
+ if (sched.has_sched_process_wait() && sched.sched_process_wait())
+ result.push_back("sched:sched_process_wait");
+ if (sched.has_sched_stat_blocked() && sched.sched_stat_blocked())
+ result.push_back("sched:sched_stat_blocked");
+ if (sched.has_sched_stat_iowait() && sched.sched_stat_iowait())
+ result.push_back("sched:sched_stat_iowait");
+ if (sched.has_sched_stat_runtime() && sched.sched_stat_runtime())
+ result.push_back("sched:sched_stat_runtime");
+ if (sched.has_sched_stat_sleep() && sched.sched_stat_sleep())
+ result.push_back("sched:sched_stat_sleep");
+ if (sched.has_sched_stat_wait() && sched.sched_stat_wait())
+ result.push_back("sched:sched_stat_wait");
+ if (sched.has_sched_stick_numa() && sched.sched_stick_numa())
+ result.push_back("sched:sched_stick_numa");
+ if (sched.has_sched_swap_numa() && sched.sched_swap_numa())
+ result.push_back("sched:sched_swap_numa");
+ if (sched.has_sched_switch() && sched.sched_switch())
+ result.push_back("sched:sched_switch");
+ if (sched.has_sched_tune_boostgroup_update() && sched.sched_tune_boostgroup_update())
+ result.push_back("sched:sched_tune_boostgroup_update");
+ if (sched.has_sched_tune_config() && sched.sched_tune_config())
+ result.push_back("sched:sched_tune_config");
+ if (sched.has_sched_tune_filter() && sched.sched_tune_filter())
+ result.push_back("sched:sched_tune_filter");
+ if (sched.has_sched_tune_tasks_update() && sched.sched_tune_tasks_update())
+ result.push_back("sched:sched_tune_tasks_update");
+ if (sched.has_sched_wait_task() && sched.sched_wait_task())
+ result.push_back("sched:sched_wait_task");
+ if (sched.has_sched_wake_idle_without_ipi() && sched.sched_wake_idle_without_ipi())
+ result.push_back("sched:sched_wake_idle_without_ipi");
+ if (sched.has_sched_wakeup() && sched.sched_wakeup())
+ result.push_back("sched:sched_wakeup");
+ if (sched.has_sched_wakeup_new() && sched.sched_wakeup_new())
+ result.push_back("sched:sched_wakeup_new");
+ if (sched.has_sched_waking() && sched.sched_waking())
+ result.push_back("sched:sched_waking");
+ if (sched.has_walt_migration_update_sum() && sched.walt_migration_update_sum())
+ result.push_back("sched:walt_migration_update_sum");
+ if (sched.has_walt_update_history() && sched.walt_update_history())
+ result.push_back("sched:walt_update_history");
+ if (sched.has_walt_update_task_ravg() && sched.walt_update_task_ravg())
+ result.push_back("sched:walt_update_task_ravg");
+ }
+
+ if (tracepoints.has_scm()) {
+ const auto& scm = tracepoints.scm();
+
+ if (scm.has_scm_call_end() && scm.scm_call_end())
+ result.push_back("scm:scm_call_end");
+ if (scm.has_scm_call_start() && scm.scm_call_start())
+ result.push_back("scm:scm_call_start");
+ }
+
+ if (tracepoints.has_scsi()) {
+ const auto& scsi = tracepoints.scsi();
+
+ if (scsi.has_scsi_dispatch_cmd_done() && scsi.scsi_dispatch_cmd_done())
+ result.push_back("scsi:scsi_dispatch_cmd_done");
+ if (scsi.has_scsi_dispatch_cmd_error() && scsi.scsi_dispatch_cmd_error())
+ result.push_back("scsi:scsi_dispatch_cmd_error");
+ if (scsi.has_scsi_dispatch_cmd_start() && scsi.scsi_dispatch_cmd_start())
+ result.push_back("scsi:scsi_dispatch_cmd_start");
+ if (scsi.has_scsi_dispatch_cmd_timeout() && scsi.scsi_dispatch_cmd_timeout())
+ result.push_back("scsi:scsi_dispatch_cmd_timeout");
+ if (scsi.has_scsi_eh_wakeup() && scsi.scsi_eh_wakeup())
+ result.push_back("scsi:scsi_eh_wakeup");
+ }
+
+ if (tracepoints.has_signal()) {
+ const auto& signal = tracepoints.signal();
+
+ if (signal.has_signal_deliver() && signal.signal_deliver())
+ result.push_back("signal:signal_deliver");
+ if (signal.has_signal_generate() && signal.signal_generate())
+ result.push_back("signal:signal_generate");
+ }
+
+ if (tracepoints.has_skb()) {
+ const auto& skb = tracepoints.skb();
+
+ if (skb.has_consume_skb() && skb.consume_skb())
+ result.push_back("skb:consume_skb");
+ if (skb.has_kfree_skb() && skb.kfree_skb())
+ result.push_back("skb:kfree_skb");
+ if (skb.has_print_skb_gso() && skb.print_skb_gso())
+ result.push_back("skb:print_skb_gso");
+ if (skb.has_skb_copy_datagram_iovec() && skb.skb_copy_datagram_iovec())
+ result.push_back("skb:skb_copy_datagram_iovec");
+ }
+
+ if (tracepoints.has_sock()) {
+ const auto& sock = tracepoints.sock();
+
+ if (sock.has_sock_exceed_buf_limit() && sock.sock_exceed_buf_limit())
+ result.push_back("sock:sock_exceed_buf_limit");
+ if (sock.has_sock_rcvqueue_full() && sock.sock_rcvqueue_full())
+ result.push_back("sock:sock_rcvqueue_full");
+ }
+
+ if (tracepoints.has_spi()) {
+ const auto& spi = tracepoints.spi();
+
+ if (spi.has_spi_master_busy() && spi.spi_master_busy())
+ result.push_back("spi:spi_master_busy");
+ if (spi.has_spi_master_idle() && spi.spi_master_idle())
+ result.push_back("spi:spi_master_idle");
+ if (spi.has_spi_message_done() && spi.spi_message_done())
+ result.push_back("spi:spi_message_done");
+ if (spi.has_spi_message_start() && spi.spi_message_start())
+ result.push_back("spi:spi_message_start");
+ if (spi.has_spi_message_submit() && spi.spi_message_submit())
+ result.push_back("spi:spi_message_submit");
+ if (spi.has_spi_transfer_start() && spi.spi_transfer_start())
+ result.push_back("spi:spi_transfer_start");
+ if (spi.has_spi_transfer_stop() && spi.spi_transfer_stop())
+ result.push_back("spi:spi_transfer_stop");
+ }
+
+ if (tracepoints.has_swiotlb()) {
+ const auto& swiotlb = tracepoints.swiotlb();
+
+ if (swiotlb.has_swiotlb_bounced() && swiotlb.swiotlb_bounced())
+ result.push_back("swiotlb:swiotlb_bounced");
+ }
+
+ if (tracepoints.has_sync()) {
+ const auto& sync = tracepoints.sync();
+
+ if (sync.has_sync_pt() && sync.sync_pt())
+ result.push_back("sync:sync_pt");
+ if (sync.has_sync_timeline() && sync.sync_timeline())
+ result.push_back("sync:sync_timeline");
+ if (sync.has_sync_wait() && sync.sync_wait())
+ result.push_back("sync:sync_wait");
+ }
+
+ if (tracepoints.has_task()) {
+ const auto& task = tracepoints.task();
+
+ if (task.has_task_newtask() && task.task_newtask())
+ result.push_back("task:task_newtask");
+ if (task.has_task_rename() && task.task_rename())
+ result.push_back("task:task_rename");
+ }
+
+ if (tracepoints.has_thermal()) {
+ const auto& thermal = tracepoints.thermal();
+
+ if (thermal.has_bcl_hw_event() && thermal.bcl_hw_event())
+ result.push_back("thermal:bcl_hw_event");
+ if (thermal.has_bcl_hw_mitigation() && thermal.bcl_hw_mitigation())
+ result.push_back("thermal:bcl_hw_mitigation");
+ if (thermal.has_bcl_hw_mitigation_event() && thermal.bcl_hw_mitigation_event())
+ result.push_back("thermal:bcl_hw_mitigation_event");
+ if (thermal.has_bcl_hw_reg_access() && thermal.bcl_hw_reg_access())
+ result.push_back("thermal:bcl_hw_reg_access");
+ if (thermal.has_bcl_hw_sensor_reading() && thermal.bcl_hw_sensor_reading())
+ result.push_back("thermal:bcl_hw_sensor_reading");
+ if (thermal.has_bcl_hw_state_event() && thermal.bcl_hw_state_event())
+ result.push_back("thermal:bcl_hw_state_event");
+ if (thermal.has_bcl_sw_mitigation() && thermal.bcl_sw_mitigation())
+ result.push_back("thermal:bcl_sw_mitigation");
+ if (thermal.has_bcl_sw_mitigation_event() && thermal.bcl_sw_mitigation_event())
+ result.push_back("thermal:bcl_sw_mitigation_event");
+ if (thermal.has_cdev_update() && thermal.cdev_update())
+ result.push_back("thermal:cdev_update");
+ if (thermal.has_thermal_post_core_offline() && thermal.thermal_post_core_offline())
+ result.push_back("thermal:thermal_post_core_offline");
+ if (thermal.has_thermal_post_core_online() && thermal.thermal_post_core_online())
+ result.push_back("thermal:thermal_post_core_online");
+ if (thermal.has_thermal_post_frequency_mit() && thermal.thermal_post_frequency_mit())
+ result.push_back("thermal:thermal_post_frequency_mit");
+ if (thermal.has_thermal_power_cpu_get_power() && thermal.thermal_power_cpu_get_power())
+ result.push_back("thermal:thermal_power_cpu_get_power");
+ if (thermal.has_thermal_power_cpu_limit() && thermal.thermal_power_cpu_limit())
+ result.push_back("thermal:thermal_power_cpu_limit");
+ if (thermal.has_thermal_pre_core_offline() && thermal.thermal_pre_core_offline())
+ result.push_back("thermal:thermal_pre_core_offline");
+ if (thermal.has_thermal_pre_core_online() && thermal.thermal_pre_core_online())
+ result.push_back("thermal:thermal_pre_core_online");
+ if (thermal.has_thermal_pre_frequency_mit() && thermal.thermal_pre_frequency_mit())
+ result.push_back("thermal:thermal_pre_frequency_mit");
+ if (thermal.has_thermal_temperature() && thermal.thermal_temperature())
+ result.push_back("thermal:thermal_temperature");
+ if (thermal.has_thermal_zone_trip() && thermal.thermal_zone_trip())
+ result.push_back("thermal:thermal_zone_trip");
+ if (thermal.has_tsens_read() && thermal.tsens_read())
+ result.push_back("thermal:tsens_read");
+ if (thermal.has_tsens_threshold_clear() && thermal.tsens_threshold_clear())
+ result.push_back("thermal:tsens_threshold_clear");
+ if (thermal.has_tsens_threshold_hit() && thermal.tsens_threshold_hit())
+ result.push_back("thermal:tsens_threshold_hit");
+ }
+
+ if (tracepoints.has_timer()) {
+ const auto& timer = tracepoints.timer();
+
+ if (timer.has_hrtimer_cancel() && timer.hrtimer_cancel())
+ result.push_back("timer:hrtimer_cancel");
+ if (timer.has_hrtimer_expire_entry() && timer.hrtimer_expire_entry())
+ result.push_back("timer:hrtimer_expire_entry");
+ if (timer.has_hrtimer_expire_exit() && timer.hrtimer_expire_exit())
+ result.push_back("timer:hrtimer_expire_exit");
+ if (timer.has_hrtimer_init() && timer.hrtimer_init())
+ result.push_back("timer:hrtimer_init");
+ if (timer.has_hrtimer_start() && timer.hrtimer_start())
+ result.push_back("timer:hrtimer_start");
+ if (timer.has_itimer_expire() && timer.itimer_expire())
+ result.push_back("timer:itimer_expire");
+ if (timer.has_itimer_state() && timer.itimer_state())
+ result.push_back("timer:itimer_state");
+ if (timer.has_tick_stop() && timer.tick_stop())
+ result.push_back("timer:tick_stop");
+ if (timer.has_timer_cancel() && timer.timer_cancel())
+ result.push_back("timer:timer_cancel");
+ if (timer.has_timer_expire_entry() && timer.timer_expire_entry())
+ result.push_back("timer:timer_expire_entry");
+ if (timer.has_timer_expire_exit() && timer.timer_expire_exit())
+ result.push_back("timer:timer_expire_exit");
+ if (timer.has_timer_init() && timer.timer_init())
+ result.push_back("timer:timer_init");
+ if (timer.has_timer_start() && timer.timer_start())
+ result.push_back("timer:timer_start");
+ }
+
+ if (tracepoints.has_tracer_pkt()) {
+ const auto& tracer_pkt = tracepoints.tracer_pkt();
+
+ if (tracer_pkt.has_tracer_pkt_event() && tracer_pkt.tracer_pkt_event())
+ result.push_back("tracer_pkt:tracer_pkt_event");
+ }
+
+ if (tracepoints.has_udp()) {
+ const auto& udp = tracepoints.udp();
+
+ if (udp.has_udp_fail_queue_rcv_skb() && udp.udp_fail_queue_rcv_skb())
+ result.push_back("udp:udp_fail_queue_rcv_skb");
+ }
+
+ if (tracepoints.has_ufs()) {
+ const auto& ufs = tracepoints.ufs();
+
+ if (ufs.has_ufshcd_auto_bkops_state() && ufs.ufshcd_auto_bkops_state())
+ result.push_back("ufs:ufshcd_auto_bkops_state");
+ if (ufs.has_ufshcd_clk_gating() && ufs.ufshcd_clk_gating())
+ result.push_back("ufs:ufshcd_clk_gating");
+ if (ufs.has_ufshcd_clk_scaling() && ufs.ufshcd_clk_scaling())
+ result.push_back("ufs:ufshcd_clk_scaling");
+ if (ufs.has_ufshcd_command() && ufs.ufshcd_command())
+ result.push_back("ufs:ufshcd_command");
+ if (ufs.has_ufshcd_hibern8_on_idle() && ufs.ufshcd_hibern8_on_idle())
+ result.push_back("ufs:ufshcd_hibern8_on_idle");
+ if (ufs.has_ufshcd_init() && ufs.ufshcd_init())
+ result.push_back("ufs:ufshcd_init");
+ if (ufs.has_ufshcd_profile_clk_gating() && ufs.ufshcd_profile_clk_gating())
+ result.push_back("ufs:ufshcd_profile_clk_gating");
+ if (ufs.has_ufshcd_profile_clk_scaling() && ufs.ufshcd_profile_clk_scaling())
+ result.push_back("ufs:ufshcd_profile_clk_scaling");
+ if (ufs.has_ufshcd_profile_hibern8() && ufs.ufshcd_profile_hibern8())
+ result.push_back("ufs:ufshcd_profile_hibern8");
+ if (ufs.has_ufshcd_runtime_resume() && ufs.ufshcd_runtime_resume())
+ result.push_back("ufs:ufshcd_runtime_resume");
+ if (ufs.has_ufshcd_runtime_suspend() && ufs.ufshcd_runtime_suspend())
+ result.push_back("ufs:ufshcd_runtime_suspend");
+ if (ufs.has_ufshcd_system_resume() && ufs.ufshcd_system_resume())
+ result.push_back("ufs:ufshcd_system_resume");
+ if (ufs.has_ufshcd_system_suspend() && ufs.ufshcd_system_suspend())
+ result.push_back("ufs:ufshcd_system_suspend");
+ }
+
+ if (tracepoints.has_v4l2()) {
+ const auto& v4l2 = tracepoints.v4l2();
+
+ if (v4l2.has_v4l2_dqbuf() && v4l2.v4l2_dqbuf())
+ result.push_back("v4l2:v4l2_dqbuf");
+ if (v4l2.has_v4l2_qbuf() && v4l2.v4l2_qbuf())
+ result.push_back("v4l2:v4l2_qbuf");
+ }
+
+ if (tracepoints.has_vmscan()) {
+ const auto& vmscan = tracepoints.vmscan();
+
+ if (vmscan.has_mm_shrink_slab_end() && vmscan.mm_shrink_slab_end())
+ result.push_back("vmscan:mm_shrink_slab_end");
+ if (vmscan.has_mm_shrink_slab_start() && vmscan.mm_shrink_slab_start())
+ result.push_back("vmscan:mm_shrink_slab_start");
+ if (vmscan.has_mm_vmscan_direct_reclaim_begin() && vmscan.mm_vmscan_direct_reclaim_begin())
+ result.push_back("vmscan:mm_vmscan_direct_reclaim_begin");
+ if (vmscan.has_mm_vmscan_direct_reclaim_end() && vmscan.mm_vmscan_direct_reclaim_end())
+ result.push_back("vmscan:mm_vmscan_direct_reclaim_end");
+ if (vmscan.has_mm_vmscan_kswapd_sleep() && vmscan.mm_vmscan_kswapd_sleep())
+ result.push_back("vmscan:mm_vmscan_kswapd_sleep");
+ if (vmscan.has_mm_vmscan_kswapd_wake() && vmscan.mm_vmscan_kswapd_wake())
+ result.push_back("vmscan:mm_vmscan_kswapd_wake");
+ if (vmscan.has_mm_vmscan_lru_isolate() && vmscan.mm_vmscan_lru_isolate())
+ result.push_back("vmscan:mm_vmscan_lru_isolate");
+ if (vmscan.has_mm_vmscan_lru_shrink_inactive() && vmscan.mm_vmscan_lru_shrink_inactive())
+ result.push_back("vmscan:mm_vmscan_lru_shrink_inactive");
+ if (vmscan.has_mm_vmscan_memcg_isolate() && vmscan.mm_vmscan_memcg_isolate())
+ result.push_back("vmscan:mm_vmscan_memcg_isolate");
+ if (vmscan.has_mm_vmscan_memcg_reclaim_begin() && vmscan.mm_vmscan_memcg_reclaim_begin())
+ result.push_back("vmscan:mm_vmscan_memcg_reclaim_begin");
+ if (vmscan.has_mm_vmscan_memcg_reclaim_end() && vmscan.mm_vmscan_memcg_reclaim_end())
+ result.push_back("vmscan:mm_vmscan_memcg_reclaim_end");
+ if (vmscan.has_mm_vmscan_memcg_softlimit_reclaim_begin() && vmscan.mm_vmscan_memcg_softlimit_reclaim_begin())
+ result.push_back("vmscan:mm_vmscan_memcg_softlimit_reclaim_begin");
+ if (vmscan.has_mm_vmscan_memcg_softlimit_reclaim_end() && vmscan.mm_vmscan_memcg_softlimit_reclaim_end())
+ result.push_back("vmscan:mm_vmscan_memcg_softlimit_reclaim_end");
+ if (vmscan.has_mm_vmscan_wakeup_kswapd() && vmscan.mm_vmscan_wakeup_kswapd())
+ result.push_back("vmscan:mm_vmscan_wakeup_kswapd");
+ if (vmscan.has_mm_vmscan_writepage() && vmscan.mm_vmscan_writepage())
+ result.push_back("vmscan:mm_vmscan_writepage");
+ }
+
+ if (tracepoints.has_workqueue()) {
+ const auto& workqueue = tracepoints.workqueue();
+
+ if (workqueue.has_workqueue_activate_work() && workqueue.workqueue_activate_work())
+ result.push_back("workqueue:workqueue_activate_work");
+ if (workqueue.has_workqueue_execute_end() && workqueue.workqueue_execute_end())
+ result.push_back("workqueue:workqueue_execute_end");
+ if (workqueue.has_workqueue_execute_start() && workqueue.workqueue_execute_start())
+ result.push_back("workqueue:workqueue_execute_start");
+ if (workqueue.has_workqueue_queue_work() && workqueue.workqueue_queue_work())
+ result.push_back("workqueue:workqueue_queue_work");
+ }
+
+ if (tracepoints.has_writeback()) {
+ const auto& writeback = tracepoints.writeback();
+
+ if (writeback.has_balance_dirty_pages() && writeback.balance_dirty_pages())
+ result.push_back("writeback:balance_dirty_pages");
+ if (writeback.has_bdi_dirty_ratelimit() && writeback.bdi_dirty_ratelimit())
+ result.push_back("writeback:bdi_dirty_ratelimit");
+ if (writeback.has_global_dirty_state() && writeback.global_dirty_state())
+ result.push_back("writeback:global_dirty_state");
+ if (writeback.has_wbc_writepage() && writeback.wbc_writepage())
+ result.push_back("writeback:wbc_writepage");
+ if (writeback.has_writeback_bdi_register() && writeback.writeback_bdi_register())
+ result.push_back("writeback:writeback_bdi_register");
+ if (writeback.has_writeback_bdi_unregister() && writeback.writeback_bdi_unregister())
+ result.push_back("writeback:writeback_bdi_unregister");
+ if (writeback.has_writeback_congestion_wait() && writeback.writeback_congestion_wait())
+ result.push_back("writeback:writeback_congestion_wait");
+ if (writeback.has_writeback_dirty_inode() && writeback.writeback_dirty_inode())
+ result.push_back("writeback:writeback_dirty_inode");
+ if (writeback.has_writeback_dirty_inode_start() && writeback.writeback_dirty_inode_start())
+ result.push_back("writeback:writeback_dirty_inode_start");
+ if (writeback.has_writeback_dirty_page() && writeback.writeback_dirty_page())
+ result.push_back("writeback:writeback_dirty_page");
+ if (writeback.has_writeback_exec() && writeback.writeback_exec())
+ result.push_back("writeback:writeback_exec");
+ if (writeback.has_writeback_nowork() && writeback.writeback_nowork())
+ result.push_back("writeback:writeback_nowork");
+ if (writeback.has_writeback_pages_written() && writeback.writeback_pages_written())
+ result.push_back("writeback:writeback_pages_written");
+ if (writeback.has_writeback_queue() && writeback.writeback_queue())
+ result.push_back("writeback:writeback_queue");
+ if (writeback.has_writeback_queue_io() && writeback.writeback_queue_io())
+ result.push_back("writeback:writeback_queue_io");
+ if (writeback.has_writeback_sb_inodes_requeue() && writeback.writeback_sb_inodes_requeue())
+ result.push_back("writeback:writeback_sb_inodes_requeue");
+ if (writeback.has_writeback_single_inode() && writeback.writeback_single_inode())
+ result.push_back("writeback:writeback_single_inode");
+ if (writeback.has_writeback_single_inode_start() && writeback.writeback_single_inode_start())
+ result.push_back("writeback:writeback_single_inode_start");
+ if (writeback.has_writeback_start() && writeback.writeback_start())
+ result.push_back("writeback:writeback_start");
+ if (writeback.has_writeback_wait() && writeback.writeback_wait())
+ result.push_back("writeback:writeback_wait");
+ if (writeback.has_writeback_wait_iff_congested() && writeback.writeback_wait_iff_congested())
+ result.push_back("writeback:writeback_wait_iff_congested");
+ if (writeback.has_writeback_wake_background() && writeback.writeback_wake_background())
+ result.push_back("writeback:writeback_wake_background");
+ if (writeback.has_writeback_write_inode() && writeback.writeback_write_inode())
+ result.push_back("writeback:writeback_write_inode");
+ if (writeback.has_writeback_write_inode_start() && writeback.writeback_write_inode_start())
+ result.push_back("writeback:writeback_write_inode_start");
+ if (writeback.has_writeback_written() && writeback.writeback_written())
+ result.push_back("writeback:writeback_written");
+ }
+
+ if (tracepoints.has_xhci_hcd()) {
+ const auto& xhci_hcd = tracepoints.xhci_hcd();
+
+ if (xhci_hcd.has_xhci_address_ctx() && xhci_hcd.xhci_address_ctx())
+ result.push_back("xhci-hcd:xhci_address_ctx");
+ if (xhci_hcd.has_xhci_cmd_completion() && xhci_hcd.xhci_cmd_completion())
+ result.push_back("xhci-hcd:xhci_cmd_completion");
+ if (xhci_hcd.has_xhci_dbg_address() && xhci_hcd.xhci_dbg_address())
+ result.push_back("xhci-hcd:xhci_dbg_address");
+ if (xhci_hcd.has_xhci_dbg_cancel_urb() && xhci_hcd.xhci_dbg_cancel_urb())
+ result.push_back("xhci-hcd:xhci_dbg_cancel_urb");
+ if (xhci_hcd.has_xhci_dbg_context_change() && xhci_hcd.xhci_dbg_context_change())
+ result.push_back("xhci-hcd:xhci_dbg_context_change");
+ if (xhci_hcd.has_xhci_dbg_init() && xhci_hcd.xhci_dbg_init())
+ result.push_back("xhci-hcd:xhci_dbg_init");
+ if (xhci_hcd.has_xhci_dbg_quirks() && xhci_hcd.xhci_dbg_quirks())
+ result.push_back("xhci-hcd:xhci_dbg_quirks");
+ if (xhci_hcd.has_xhci_dbg_reset_ep() && xhci_hcd.xhci_dbg_reset_ep())
+ result.push_back("xhci-hcd:xhci_dbg_reset_ep");
+ if (xhci_hcd.has_xhci_dbg_ring_expansion() && xhci_hcd.xhci_dbg_ring_expansion())
+ result.push_back("xhci-hcd:xhci_dbg_ring_expansion");
+ }
+
+ }
+
+ return result;
+}
+
+} // namespace perfprofd
+} // namespace android
diff --git a/perfprofd/perfprofd_counters.h b/perfprofd/perfprofd_counters.h
new file mode 100644
index 0000000..6cbcc7d
--- /dev/null
+++ b/perfprofd/perfprofd_counters.h
@@ -0,0 +1,33 @@
+/*
+ *
+ * Copyright 2018, 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.
+ */
+
+#ifndef SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_COUNTERS_H_
+#define SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_COUNTERS_H_
+
+#include <vector>
+
+namespace android {
+namespace perfprofd {
+
+class CounterSet;
+
+std::vector<const char*> GenerateEventsString(const CounterSet& counter_set);
+
+} // namespace perfprofd
+} // namespace android
+
+#endif // SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_COUNTERS_H_
diff --git a/perfprofd/perfprofd_perf.cc b/perfprofd/perfprofd_perf.cc
new file mode 100644
index 0000000..0e7b595
--- /dev/null
+++ b/perfprofd/perfprofd_perf.cc
@@ -0,0 +1,188 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "perfprofd_perf.h"
+
+
+#include <assert.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "config.h"
+
+namespace android {
+namespace perfprofd {
+
+//
+// Invoke "perf record". Return value is OK_PROFILE_COLLECTION for
+// success, or some other error code if something went wrong.
+//
+PerfResult InvokePerf(Config& config,
+ const std::string &perf_path,
+ const char *stack_profile_opt,
+ unsigned duration,
+ const std::string &data_file_path,
+ const std::string &perf_stderr_path)
+{
+ std::vector<std::string> argv_backing;
+ std::vector<const char*> argv_vector;
+
+ {
+ auto add = [&argv_backing](auto arg) {
+ argv_backing.push_back(arg);
+ };
+
+ add(perf_path);
+ add("record");
+
+ // -o perf.data
+ add("-o");
+ add(data_file_path);
+
+ // -c/f N
+ std::string p_str;
+ if (config.sampling_frequency > 0) {
+ add("-f");
+ add(android::base::StringPrintf("%u", config.sampling_frequency));
+ } else if (config.sampling_period > 0) {
+ add("-c");
+ add(android::base::StringPrintf("%u", config.sampling_period));
+ }
+
+ // -g if desired
+ if (stack_profile_opt != nullptr) {
+ add(stack_profile_opt);
+ add("-m");
+ add("8192");
+ }
+
+ if (config.process < 0) {
+ // system wide profiling
+ add("-a");
+ } else {
+ add("-p");
+ add(std::to_string(config.process));
+ }
+
+ // no need for kernel or other symbols
+ add("--no-dump-kernel-symbols");
+ add("--no-dump-symbols");
+
+ // sleep <duration>
+ add("--duration");
+ add(android::base::StringPrintf("%u", duration));
+
+
+ // Now create the char* buffer.
+ argv_vector.resize(argv_backing.size() + 1, nullptr);
+ std::transform(argv_backing.begin(),
+ argv_backing.end(),
+ argv_vector.begin(),
+ [](const std::string& in) { return in.c_str(); });
+ }
+
+ pid_t pid = fork();
+
+ if (pid == -1) {
+ PLOG(ERROR) << "Fork failed";
+ return PerfResult::kForkFailed;
+ }
+
+ if (pid == 0) {
+ // child
+
+ // Open file to receive stderr/stdout from perf
+ FILE *efp = fopen(perf_stderr_path.c_str(), "w");
+ if (efp) {
+ dup2(fileno(efp), STDERR_FILENO);
+ dup2(fileno(efp), STDOUT_FILENO);
+ } else {
+ PLOG(WARNING) << "unable to open " << perf_stderr_path << " for writing";
+ }
+
+ // record the final command line in the error output file for
+ // posterity/debugging purposes
+ fprintf(stderr, "perf invocation (pid=%d):\n", getpid());
+ for (unsigned i = 0; argv_vector[i] != nullptr; ++i) {
+ fprintf(stderr, "%s%s", i ? " " : "", argv_vector[i]);
+ }
+ fprintf(stderr, "\n");
+
+ // exec
+ execvp(argv_vector[0], const_cast<char* const*>(argv_vector.data()));
+ fprintf(stderr, "exec failed: %s\n", strerror(errno));
+ exit(1);
+
+ } else {
+ // parent
+
+ // Try to sleep.
+ config.Sleep(duration);
+
+ // We may have been woken up to stop profiling.
+ if (config.ShouldStopProfiling()) {
+ // Send SIGHUP to simpleperf to make it stop.
+ kill(pid, SIGHUP);
+ }
+
+ // Wait for the child, so it's reaped correctly.
+ int st = 0;
+ pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
+
+ auto print_perferr = [&perf_stderr_path]() {
+ std::string tmp;
+ if (android::base::ReadFileToString(perf_stderr_path, &tmp)) {
+ LOG(WARNING) << tmp;
+ } else {
+ PLOG(WARNING) << "Could not read " << perf_stderr_path;
+ }
+ };
+
+ if (reaped == -1) {
+ PLOG(WARNING) << "waitpid failed";
+ } else if (WIFSIGNALED(st)) {
+ if (WTERMSIG(st) == SIGHUP && config.ShouldStopProfiling()) {
+ // That was us...
+ return PerfResult::kOK;
+ }
+ LOG(WARNING) << "perf killed by signal " << WTERMSIG(st);
+ print_perferr();
+ } else if (WEXITSTATUS(st) != 0) {
+ LOG(WARNING) << "perf bad exit status " << WEXITSTATUS(st);
+ print_perferr();
+ } else {
+ return PerfResult::kOK;
+ }
+ }
+
+ return PerfResult::kRecordFailed;
+}
+
+} // namespace perfprofd
+} // namespace android
diff --git a/perfprofd/perfprofd_perf.h b/perfprofd/perfprofd_perf.h
new file mode 100644
index 0000000..8cc9d50
--- /dev/null
+++ b/perfprofd/perfprofd_perf.h
@@ -0,0 +1,50 @@
+/*
+**
+** Copyright 2018, 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.
+*/
+
+#ifndef SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_PERF_H_
+#define SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_PERF_H_
+
+#include <string>
+
+struct Config;
+
+namespace android {
+namespace perfprofd {
+
+
+
+enum PerfResult {
+ kOK,
+ kForkFailed,
+ kRecordFailed,
+};
+
+//
+// Invoke "perf record". Return value is PerfResult::kOK for
+// success, or some other error code if something went wrong.
+//
+PerfResult InvokePerf(Config& config,
+ const std::string &perf_path,
+ const char *stack_profile_opt,
+ unsigned duration,
+ const std::string &data_file_path,
+ const std::string &perf_stderr_path);
+
+} // namespace perfprofd
+} // namespace android
+
+#endif // SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_PERF_H_
diff --git a/perfprofd/perfprofdcore.cc b/perfprofd/perfprofdcore.cc
index a152111..067745f 100644
--- a/perfprofd/perfprofdcore.cc
+++ b/perfprofd/perfprofdcore.cc
@@ -50,6 +50,7 @@
#include "perf_data_converter.h"
#include "perfprofdcore.h"
#include "perfprofd_io.h"
+#include "perfprofd_perf.h"
#include "symbolizer.h"
//
@@ -452,135 +453,6 @@
}
//
-// Invoke "perf record". Return value is OK_PROFILE_COLLECTION for
-// success, or some other error code if something went wrong.
-//
-static PROFILE_RESULT invoke_perf(Config& config,
- const std::string &perf_path,
- const char *stack_profile_opt,
- unsigned duration,
- const std::string &data_file_path,
- const std::string &perf_stderr_path)
-{
- pid_t pid = fork();
-
- if (pid == -1) {
- return ERR_FORK_FAILED;
- }
-
- if (pid == 0) {
- // child
-
- // Open file to receive stderr/stdout from perf
- FILE *efp = fopen(perf_stderr_path.c_str(), "w");
- if (efp) {
- dup2(fileno(efp), STDERR_FILENO);
- dup2(fileno(efp), STDOUT_FILENO);
- } else {
- PLOG(WARNING) << "unable to open " << perf_stderr_path << " for writing";
- }
-
- // marshall arguments
- constexpr unsigned max_args = 17;
- const char *argv[max_args];
- unsigned slot = 0;
- argv[slot++] = perf_path.c_str();
- argv[slot++] = "record";
-
- // -o perf.data
- argv[slot++] = "-o";
- argv[slot++] = data_file_path.c_str();
-
- // -c/f N
- std::string p_str;
- if (config.sampling_frequency > 0) {
- argv[slot++] = "-f";
- p_str = android::base::StringPrintf("%u", config.sampling_frequency);
- argv[slot++] = p_str.c_str();
- } else if (config.sampling_period > 0) {
- argv[slot++] = "-c";
- p_str = android::base::StringPrintf("%u", config.sampling_period);
- argv[slot++] = p_str.c_str();
- }
-
- // -g if desired
- if (stack_profile_opt) {
- argv[slot++] = stack_profile_opt;
- argv[slot++] = "-m";
- argv[slot++] = "8192";
- }
-
- std::string pid_str;
- if (config.process < 0) {
- // system wide profiling
- argv[slot++] = "-a";
- } else {
- argv[slot++] = "-p";
- pid_str = std::to_string(config.process);
- argv[slot++] = pid_str.c_str();
- }
-
- // no need for kernel or other symbols
- argv[slot++] = "--no-dump-kernel-symbols";
- argv[slot++] = "--no-dump-symbols";
-
- // sleep <duration>
- argv[slot++] = "--duration";
- std::string d_str = android::base::StringPrintf("%u", duration);
- argv[slot++] = d_str.c_str();
-
- // terminator
- argv[slot++] = nullptr;
- assert(slot < max_args);
-
- // record the final command line in the error output file for
- // posterity/debugging purposes
- fprintf(stderr, "perf invocation (pid=%d):\n", getpid());
- for (unsigned i = 0; argv[i] != nullptr; ++i) {
- fprintf(stderr, "%s%s", i ? " " : "", argv[i]);
- }
- fprintf(stderr, "\n");
-
- // exec
- execvp(argv[0], (char * const *)argv);
- fprintf(stderr, "exec failed: %s\n", strerror(errno));
- exit(1);
-
- } else {
- // parent
-
- // Try to sleep.
- config.Sleep(duration);
-
- // We may have been woken up to stop profiling.
- if (config.ShouldStopProfiling()) {
- // Send SIGHUP to simpleperf to make it stop.
- kill(pid, SIGHUP);
- }
-
- // Wait for the child, so it's reaped correctly.
- int st = 0;
- pid_t reaped = TEMP_FAILURE_RETRY(waitpid(pid, &st, 0));
-
- if (reaped == -1) {
- PLOG(WARNING) << "waitpid failed";
- } else if (WIFSIGNALED(st)) {
- if (WTERMSIG(st) == SIGHUP && config.ShouldStopProfiling()) {
- // That was us...
- return OK_PROFILE_COLLECTION;
- }
- LOG(WARNING) << "perf killed by signal " << WTERMSIG(st);
- } else if (WEXITSTATUS(st) != 0) {
- LOG(WARNING) << "perf bad exit status " << WEXITSTATUS(st);
- } else {
- return OK_PROFILE_COLLECTION;
- }
- }
-
- return ERR_PERF_RECORD_FAILED;
-}
-
-//
// Remove all files in the destination directory during initialization
//
static void cleanup_destination_dir(const std::string& dest_dir)
@@ -664,13 +536,14 @@
(config.stack_profile ? "-g" : nullptr);
const std::string& perf_path = config.perf_path;
- PROFILE_RESULT ret = invoke_perf(config,
- perf_path,
- stack_profile_opt,
- duration,
- data_file_path,
- perf_stderr_path);
- if (ret != OK_PROFILE_COLLECTION) {
+ android::perfprofd::PerfResult invoke_res =
+ android::perfprofd::InvokePerf(config,
+ perf_path,
+ stack_profile_opt,
+ duration,
+ data_file_path,
+ perf_stderr_path);
+ if (invoke_res != android::perfprofd::PerfResult::kOK) {
return nullptr;
}
diff --git a/perfprofd/scripts/perf_config_proto.py b/perfprofd/scripts/perf_config_proto.py
index 461f17f..c94910f 100644
--- a/perfprofd/scripts/perf_config_proto.py
+++ b/perfprofd/scripts/perf_config_proto.py
@@ -46,6 +46,7 @@
('send_to_dropbox', 'b'),
]
+
def collect_and_write(filename):
config = perfprofd_config_pb2.ProfilingConfig()
@@ -75,6 +76,7 @@
f.write(config.SerializeToString())
f.close()
+
def read_and_print(filename):
config = perfprofd_config_pb2.ProfilingConfig()
@@ -84,6 +86,7 @@
print config
+
if sys.argv[1] == 'read':
read_and_print(sys.argv[2])
elif sys.argv[1] == 'write':
diff --git a/perfprofd/scripts/perf_proto_json2sqlite.py b/perfprofd/scripts/perf_proto_json2sqlite.py
index 5725424..b0d74c8 100644
--- a/perfprofd/scripts/perf_proto_json2sqlite.py
+++ b/perfprofd/scripts/perf_proto_json2sqlite.py
@@ -19,6 +19,7 @@
import json
import sqlite3
+
class SqliteWriter(object):
def __init__(self):
self.sample_count = 0
@@ -53,7 +54,7 @@
primary key (sample_id, depth))
''')
except sqlite3.OperationalError:
- pass # ignore
+ pass # ignore
def close(self):
self._conn.commit()
@@ -78,7 +79,7 @@
def write_sqlite_index_table(self, table_dict, table_name):
for key, value in table_dict.iteritems():
- self._c.execute("insert into {tn} values (?,?)".format(tn=table_name), (value,key))
+ self._c.execute("insert into {tn} values (?,?)".format(tn=table_name), (value, key))
def flush(self):
self.write_sqlite_index_table(self.pid_tmp_map, 'pids')
diff --git a/perfprofd/scripts/perf_proto_stack.py b/perfprofd/scripts/perf_proto_stack.py
index 9287b87..2b0c310 100644
--- a/perfprofd/scripts/perf_proto_stack.py
+++ b/perfprofd/scripts/perf_proto_stack.py
@@ -24,17 +24,13 @@
from datetime import datetime
import itertools
import json
-
import logging
-logging.basicConfig(format = "%(message)s")
-
from multiprocessing.dummy import Pool as ThreadPool
import os.path
from sorted_collection import SortedCollection
import subprocess
from threading import Timer
-
# Generate with:
# aprotoc -I=external/perf_data_converter/src/quipper \
# --python_out=system/extras/perfprofd/scripts \
@@ -50,23 +46,27 @@
import symbol
from symbol import SymbolInformation
+logging.basicConfig(format='%(message)s')
+
# This is wrong. But then the symbol module is a bad quagmire.
# TODO: Check build IDs.
symbol.SetAbi(["ABI: 'arm64'"])
+
class MmapState(object):
+
def __init__(self):
- self._list = SortedCollection((), lambda x : x[0])
+ self._list = SortedCollection((), lambda x: x[0])
def add_map(self, start, length, pgoff, name):
- tuple = (start, length, pgoff, name)
- self._list.insert(tuple)
+ map_tuple = (start, length, pgoff, name)
+ self._list.insert(map_tuple)
def find(self, addr):
try:
- tuple = self._list.find_le(addr)
- if addr < tuple[0] + tuple[1]:
- return tuple
+ map_tuple = self._list.find_le(addr)
+ if addr < map_tuple[0] + map_tuple[1]:
+ return map_tuple
return None
except ValueError:
return None
@@ -77,13 +77,15 @@
return ret
def __str__(self):
- return "MmapState: " + self._list.__str__()
+ return 'MmapState: ' + self._list.__str__()
+
def __repr__(self):
return self.__str__()
+
class SymbolMap(object):
def __init__(self, min_v):
- self._list = SortedCollection((), lambda x : x[0])
+ self._list = SortedCollection((), lambda x: x[0])
self._min_vaddr = min_v
def add_symbol(self, start, length, name):
@@ -106,12 +108,15 @@
def __str__(self):
return "SymbolMap: " + self._list.__str__()
+
def __repr__(self):
return self.__str__()
+
def intern_uni(u):
return intern(u.encode('ascii', 'replace'))
+
def collect_tid_names(perf_data):
tid_name_map = {}
for event in perf_data.events:
@@ -119,9 +124,10 @@
tid_name_map[event.comm_event.tid] = intern_uni(event.comm_event.comm)
return tid_name_map
+
def create_symbol_maps(profile):
symbol_maps = {}
-# if profile.HasExtension(perfprofd_record_pb2.symbol_info):
+
for si in profile.Extensions[perfprofd_record_pb2.symbol_info]:
map = SymbolMap(si.min_vaddr)
symbol_maps[si.filename] = map
@@ -129,6 +135,7 @@
map.add_symbol(sym.addr, sym.size, intern_uni(sym.name))
return symbol_maps
+
def update_mmap_states(event, state_map):
if event.HasField('mmap_event'):
mmap_event = event.mmap_event
@@ -136,23 +143,26 @@
if mmap_event.tid == 0:
return
# Create new map, if necessary.
- if not mmap_event.pid in state_map:
+ if mmap_event.pid not in state_map:
state_map[mmap_event.pid] = MmapState()
state_map[mmap_event.pid].add_map(mmap_event.start, mmap_event.len, mmap_event.pgoff,
- intern_uni(mmap_event.filename))
+ intern_uni(mmap_event.filename))
elif event.HasField('fork_event'):
fork_event = event.fork_event
# Skip threads
if fork_event.pid == fork_event.ppid:
return
+
if fork_event.ppid not in state_map:
logging.warn("fork from %d without map", fork_event.ppid)
return
state_map[fork_event.pid] = state_map[fork_event.ppid].copy()
+
skip_dso = set()
vaddr = {}
+
def find_vaddr(vaddr_map, filename):
if filename in vaddr_map:
return vaddr_map[filename]
@@ -169,7 +179,9 @@
lines = res.split("\n")
reading_headers = False
min_vaddr = None
- min_fn = lambda x, y: y if x is None else min(x, y)
+
+ def min_fn(x, y):
+ return y if x is None else min(x, y)
# Using counting loop for access to next line.
for i in range(0, len(lines) - 1):
line = lines[i].strip()
@@ -199,11 +211,15 @@
vaddr_map[filename] = min_vaddr
except subprocess.CalledProcessError:
logging.warn('Error finding min_vaddr for %s', filename)
+
vaddr_map[filename] = 0
return vaddr_map[filename]
+
unwind_symbols_cache = {}
unwind_symbols_warn_missing_cache = set()
+
+
def run_unwind_symbols(filename, offset_hex):
path = "%s/%s" % (symbol.SYMBOLS_DIR, filename)
if not os.path.isfile(path):
@@ -237,7 +253,7 @@
# TODO C++ demangling necessary.
logging.debug('unwind_symbols: %s %s -> %s +%d', filename, offset_hex, parts[1],
- offset)
+ offset)
sym = intern(parts[1])
unwind_symbols_cache[(path, offset_hex)] = (sym, offset)
return [(sym, offset, filename)]
@@ -256,7 +272,7 @@
i = s.rfind('+')
if i > 0:
try:
- off = int(s[i+1:])
+ off = int(s[i + 1:])
return (s[0:i], off)
except ValueError:
pass
@@ -267,6 +283,7 @@
if object_symbol_with_offset is not None:
pair = parse_symbol_lib_output(object_symbol_with_offset)
ret.append((intern(pair[0]), pair[1], name))
+
if source_symbol is not None:
iterinfo = iter(info)
next(iterinfo)
@@ -279,6 +296,7 @@
return ret
return None
+
def decode_addr(addr, mmap_state, device_symbols):
"""Try to decode the given address against the current mmap table and device symbols.
@@ -347,6 +365,7 @@
pid_name = "kernel (0)"
else:
pid_name = "unknown (%d)" % (sample[0])
+
if sample[1] in tid_name_map:
tid_name = "%s (%d)" % (tid_name_map[sample[1]], sample[1])
elif sample[1] == 0:
@@ -354,15 +373,18 @@
else:
tid_name = "unknown (%d)" % (sample[1])
print " %s - %s:" % (pid_name, tid_name)
+
for sym in sample[2]:
print " %s +%d (%s)" % (sym[0], sym[1], sym[2])
+
def print_samples(samples, tid_name_map):
for sample in samples:
print_sample(sample, tid_name_map)
-def symbolize_events(perf_data, device_symbols, tid_name_map, printSamples = False,
- removeKernelTop = False):
+
+def symbolize_events(perf_data, device_symbols, tid_name_map, printSamples=False,
+ removeKernelTop=False):
samples = []
mmap_states = {}
for event in perf_data.events:
@@ -388,7 +410,7 @@
samples.append((0, sample_ev.tid, [("[kernel]", 0, "[kernel]")]))
elif sample_ev.pid in tid_name_map:
samples.append((sample_ev.pid, sample_ev.tid, [(tid_name_map[sample_ev.pid], 0,
- None)]))
+ None)]))
else:
samples.append((sample_ev.pid, sample_ev.tid, [("[unknown]", 0, None)]))
if new_sample is not None:
@@ -397,35 +419,39 @@
print_sample(new_sample, tid_name_map)
return samples
+
def count_key_reduce_function(x, y, key_fn):
key = key_fn(y)
if key not in x:
x[key] = 0
- x[key] = x[key] + 1
+ x[key] += 1
return x
+
def print_histogram(samples, reduce_key_fn, label_key_fn, size):
# Create a sorted list of top samples.
sorted_count_list = sorted(
reduce(lambda x, y: count_key_reduce_function(x, y, reduce_key_fn), samples, {}).
- iteritems(),
- cmp=lambda x,y: cmp(x[1], y[1]),
+ iteritems(),
+ cmp=lambda x, y: cmp(x[1], y[1]),
reverse=True)
sorted_count_topX = list(itertools.islice(sorted_count_list, size))
# Print top-size samples.
print 'Histogram top-%d:' % (size)
for i in xrange(0, len(sorted_count_topX)):
- print ' %d: %s (%s)' % (i+1, label_key_fn(sorted_count_topX[i][0]),
- sorted_count_topX[i][1])
+ print ' %d: %s (%s)' % (i + 1, label_key_fn(sorted_count_topX[i][0]),
+ sorted_count_topX[i][1])
-def get_name(pid):
+
+def get_name(pid, tid_name_map):
if pid in tid_name_map:
return tid_name_map[pid]
if pid == 0:
return "[kernel]"
return "[unknown]"
+
def create_cmd(args, f):
ret = ['python', '-u', 'system/extras/perfprofd/scripts/perf_proto_stack.py']
if args.syms is not None:
@@ -439,42 +465,52 @@
if args.print_sym_histogram is not None:
ret.append('--print-sym-histogram')
if args.print_dso_histogram is not None:
+
ret.append('--print-dso-histogram')
ret.extend(['--json-out', '%s.json' % (f)])
ret.append(f)
return ret
+
def run_cmd(x):
+
args = x[0]
f = x[1]
- cmd = create_cmd(args,f)
+ cmd = create_cmd(args, f)
logging.warn('Running on %s', f)
success = False
logging.debug('%r', cmd)
err_out = open('%s.err' % (f), 'w')
- kill = lambda process: process.kill()
+
+ def kill(process):
+ process.kill()
start = datetime.now()
+
p = subprocess.Popen(cmd, stderr=err_out)
kill_timer = Timer(3600, kill, [p])
try:
kill_timer.start()
- stdout, stderr = p.communicate()
+ p.communicate()
success = True
+
finally:
kill_timer.cancel()
err_out.close()
end = datetime.now()
- logging.warn('Ended %s (%s)', f, str(end-start))
+ logging.warn('Ended %s (%s)', f, str(end - start))
return '%s: %r' % (f, success)
+
def parallel_runner(args):
pool = ThreadPool(args.parallel)
map_args = map(lambda f: (args, f), args.file)
+
result = pool.map(run_cmd, map_args)
pool.close()
pool.join()
print result
+
def run(args):
if args.syms is not None:
symbol.SYMBOLS_DIR = args.syms[0]
@@ -484,6 +520,7 @@
# TODO: accept argument for parsing.
file = open(args.file[0], 'rb')
data = file.read()
+
file.close()
profile = perf_data_pb2.PerfDataProto()
@@ -498,10 +535,10 @@
symbol_maps = create_symbol_maps(profile)
samples = symbolize_events(perf_data, symbol_maps, tid_name_map, printSamples=print_symbols,
- removeKernelTop=skip_kernel_syms)
+ removeKernelTop=skip_kernel_syms)
if args.print_pid_histogram is not None:
- print_histogram(samples, lambda x: x[0], lambda x: get_name(x), 25)
+ print_histogram(samples, lambda x: x[0], lambda x: get_name(x, tid_name_map), 25)
if args.print_sym_histogram is not None:
print_histogram(samples, lambda x: x[2][0][0], lambda x: x, 100)
if args.print_dso_histogram is not None:
@@ -509,10 +546,11 @@
if args.json_out is not None:
json_file = open(args.json_out[0], 'w')
- json_data = { 'samples': samples, 'names': tid_name_map }
+ json_data = {'samples': samples, 'names': tid_name_map}
json.dump(json_data, json_file)
json_file.close()
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Process a perfprofd record.')
@@ -521,13 +559,13 @@
parser.add_argument('--json-out', help='output file for JSON', nargs=1)
parser.add_argument('--print-samples', help='print samples', action='store_const', const=True)
parser.add_argument('--skip-kernel-syms', help='skip kernel symbols at the top of stack',
- action='store_const', const=True)
+ action='store_const', const=True)
parser.add_argument('--print-pid-histogram', help='print a top-25 histogram of processes',
- action='store_const', const=True)
+ action='store_const', const=True)
parser.add_argument('--print-sym-histogram', help='print a top-100 histogram of symbols',
- action='store_const', const=True)
+ action='store_const', const=True)
parser.add_argument('--print-dso-histogram', help='print a top-25 histogram of maps',
- action='store_const', const=True)
+ action='store_const', const=True)
parser.add_argument('--parallel', help='run parallel jobs', type=int)
args = parser.parse_args()
diff --git a/perfprofd/scripts/perf_proto_stack_sqlite_flame.py b/perfprofd/scripts/perf_proto_stack_sqlite_flame.py
index 82555af..3eb2379 100644
--- a/perfprofd/scripts/perf_proto_stack_sqlite_flame.py
+++ b/perfprofd/scripts/perf_proto_stack_sqlite_flame.py
@@ -21,6 +21,7 @@
import itertools
import sqlite3
+
class Callsite(object):
def __init__(self, dso_id, sym_id):
self.dso_id = dso_id
@@ -66,6 +67,7 @@
# Functions for flamegraph compatibility.
callsite_counter = 0
+
@classmethod
def _get_next_callsite_id(cls):
cls.callsite_counter += 1
@@ -97,6 +99,7 @@
return max([c.get_max_depth() for c in self.child_map.itervalues()]) + 1
return 1
+
class SqliteReader(object):
def __init__(self):
self.root = Callsite("root", "root")
@@ -202,9 +205,8 @@
return script_f.read()
return None
-
def print_svg(self, filename, depth):
- from svg_renderer import renderSVG
+ from svg_renderer import render_svg
self.root.svgrenderer_compat(self.dsos, self.syms)
self.root.generate_offset(0)
f = open(filename, 'w')
@@ -218,9 +220,9 @@
class FakeProcess:
def __init__(self):
- self.props = { 'trace_offcpu': False }
+ self.props = {'trace_offcpu': False}
fake_process = FakeProcess()
- renderSVG(fake_process, self.root, f, 'hot')
+ render_svg(fake_process, self.root, f, 'hot')
f.write('''
</div>
@@ -241,6 +243,7 @@
''')
f.close()
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='''Translate a perfprofd database into a flame
representation''')
diff --git a/perfprofd/scripts/simpleperf_events_to_config_proto.py b/perfprofd/scripts/simpleperf_events_to_config_proto.py
new file mode 100755
index 0000000..a967f92
--- /dev/null
+++ b/perfprofd/scripts/simpleperf_events_to_config_proto.py
@@ -0,0 +1,154 @@
+#!/usr/bin/python
+#
+# 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.
+
+import logging
+import subprocess
+
+logging.basicConfig(format='%(message)s')
+
+class SimpleperfEvents:
+ def __init__(self, reg, cats):
+ self.categories = cats
+ self.regular = reg
+
+def parse_simpleperf_events(str):
+ regular = []
+ tracepoints = []
+ scan_tracepoints = False
+
+ for line in str.splitlines():
+ if line == 'List of tracepoint events:':
+ scan_tracepoints = True
+ elif not line.startswith(' '):
+ scan_tracepoints = False
+
+ if line.startswith(' '):
+ # Trim the line, including comments.
+ comment_index = line.find('#')
+ if comment_index >= 0:
+ line = line[:comment_index]
+ line = line.strip()
+ if line is not '' and line != 'inplace-sampler':
+ (tracepoints if scan_tracepoints else regular).append(line)
+
+ subcategories = {}
+ for event in tracepoints:
+ colon_index = event.find(':')
+ if colon_index > 0:
+ cat = event[:colon_index]
+ name = event[colon_index+1:]
+ if cat not in subcategories:
+ subcategories[cat] = []
+ subcategories[cat].append(name)
+ else:
+ print 'Warning: unrecognized tracepoint %s' % (event)
+
+ return SimpleperfEvents(regular, subcategories)
+
+events = parse_simpleperf_events(subprocess.check_output(['adb', 'shell', 'simpleperf list']))
+
+field_count = 1
+
+print """
+option java_package = "android.perfprofd";
+
+package android.perfprofd;
+
+message CounterSet {
+"""
+
+for event in events.regular:
+ print ' optional bool %s = %d;' % (event.replace('-', '_'), field_count)
+ field_count += 1
+
+print ''
+
+print """
+ message TracepointSet {
+"""
+
+def FirstUpper(str):
+ return str[0:1].upper() + str[1:]
+
+cat_count = 1;
+
+for cat in sorted(events.categories):
+ print """
+ message %s {
+""" % (FirstUpper(cat.replace('-', '_')))
+
+ cat_field_count = 1
+ for name in events.categories[cat]:
+ print " optional bool %s = %d;" % (name.replace('-', '_'), cat_field_count)
+ cat_field_count += 1
+
+ print """
+ };
+ optional %s %s = %d;
+""" % (FirstUpper(cat.replace('-', '_')), cat.replace('-', '_'), cat_count)
+ cat_count += 1
+
+print """
+ };
+ optional TracePointSet tracepoints = %d;
+};
+
+message PerfConfigElement {
+ optional CounterSet counter_set = 1;
+ optional bool as_group = 2 [ default = false ];
+ optional uint32 sampling_period = 3;
+};
+
+""" % (field_count)
+
+# Generate C code for names.
+
+print """
+std::vector<const char*> GetEvents(const ::android::perfprofd::CounterSet& counter_set) {
+ std::vector<const char*> result;
+"""
+
+for event in events.regular:
+ proto_name = event.replace('-', '_').lower();
+ print ' if (counter_set.has_%s() && counter_set.%s())' % (proto_name, proto_name)
+ print ' result.push_back("%s");' % (event)
+
+print """
+ if (counter_set.has_tracepoints()) {
+ const auto& tracepoints = counter_set.tracepoints();
+"""
+
+for cat in sorted(events.categories):
+ cat_proto_name = cat.replace('-', '_').lower()
+
+ print """
+ if (tracepoints.has_%s()) {
+ const auto& %s = tracepoints.%s();
+""" % (cat_proto_name, cat_proto_name, cat_proto_name)
+
+ for name in events.categories[cat]:
+ name_proto_name = name.replace('-', '_').lower()
+ print ' if (%s.has_%s() && %s.%s())' % (cat_proto_name, name_proto_name, cat_proto_name, name_proto_name)
+ print ' result.push_back("%s:%s");' % (cat, name)
+
+ print ' }'
+
+print """
+ }
+
+ return result;
+}
+"""
\ No newline at end of file
diff --git a/perfprofd/scripts/sorted_collection.py b/perfprofd/scripts/sorted_collection.py
index 315f7c8..46622e2 100644
--- a/perfprofd/scripts/sorted_collection.py
+++ b/perfprofd/scripts/sorted_collection.py
@@ -21,6 +21,7 @@
from bisect import bisect_left, bisect_right
+
class SortedCollection(object):
def __init__(self, iterable=(), key=None):
self._given_key = key
diff --git a/perfprofd/tests/perfprofd_test.cc b/perfprofd/tests/perfprofd_test.cc
index 8712f0c..13e2d4b 100644
--- a/perfprofd/tests/perfprofd_test.cc
+++ b/perfprofd/tests/perfprofd_test.cc
@@ -202,9 +202,8 @@
// match, e.g. if we see the expected excerpt anywhere in the
// result, it's a match (for exact match, set exact to true)
//
- void CompareLogMessages(const std::string& expected,
- const char* testpoint,
- bool exactMatch = false) {
+ ::testing::AssertionResult CompareLogMessages(const std::string& expected,
+ bool exactMatch = false) {
std::string sqexp = squeezeWhite(expected, "expected");
// Strip out JIT errors.
@@ -216,17 +215,18 @@
std::string sqact = squeezeWhite(test_logger.JoinTestLog(" ", strip_jit), "actual");
if (exactMatch) {
- EXPECT_STREQ(sqexp.c_str(), sqact.c_str());
- } else {
- std::size_t foundpos = sqact.find(sqexp);
- bool wasFound = true;
- if (foundpos == std::string::npos) {
- std::cerr << testpoint << ": expected result not found\n";
- std::cerr << " Actual: \"" << sqact << "\"\n";
- std::cerr << " Expected: \"" << sqexp << "\"\n";
- wasFound = false;
+ if (sqexp == sqact) {
+ return ::testing::AssertionSuccess() << sqexp << " is equal to " << sqact;
}
- EXPECT_TRUE(wasFound);
+ return ::testing::AssertionFailure() << "Expected:" << std::endl << sqexp << std::endl
+ << "Received:" << std::endl << sqact;
+ } else {
+ if (sqact.find(sqexp) == std::string::npos) {
+ return ::testing::AssertionFailure()
+ << "Expected to find:" << std::endl << sqexp << std::endl
+ << "in:" << std::endl << sqact;
+ }
+ return ::testing::AssertionSuccess() << sqexp << " was found in " << sqact;
}
}
@@ -482,7 +482,7 @@
);
// check to make sure entire log matches
- CompareLogMessages(expected, "MissingGMS");
+ EXPECT_TRUE(CompareLogMessages(expected));
}
@@ -518,7 +518,7 @@
I: profile collection skipped (missing config directory)
);
// check to make sure log excerpt matches
- CompareLogMessages(expected, "MissingOptInSemaphoreFile");
+ EXPECT_TRUE(CompareLogMessages(expected));
}
TEST_F(PerfProfdTest, MissingPerfExecutable)
@@ -555,7 +555,7 @@
I: profile collection skipped (missing 'perf' executable)
);
// check to make sure log excerpt matches
- CompareLogMessages(expected, "MissingPerfExecutable");
+ EXPECT_TRUE(CompareLogMessages(expected));
}
TEST_F(PerfProfdTest, BadPerfRun)
@@ -590,14 +590,16 @@
// Check return code from daemon
EXPECT_EQ(0, daemon_main_return_code);
- // Verify log contents
- const std::string expected = RAW_RESULT(
- W: perf bad exit status 1
- W: profile collection failed
- );
+ // Verify log contents. Because of perferr logging containing pids and test paths,
+ // it is easier to have three expected parts.
+ const std::string expected1 = "W: perf bad exit status 1";
+ const std::string expected2 = "bin/false record";
+ const std::string expected3 = "W: profile collection failed";
// check to make sure log excerpt matches
- CompareLogMessages(expected, "BadPerfRun");
+ EXPECT_TRUE(CompareLogMessages(expected1));
+ EXPECT_TRUE(CompareLogMessages(expected2));
+ EXPECT_TRUE(CompareLogMessages(expected3));
}
TEST_F(PerfProfdTest, ConfigFileParsing)
@@ -631,7 +633,7 @@
);
// check to make sure log excerpt matches
- CompareLogMessages(expected, "ConfigFileParsing");
+ EXPECT_TRUE(CompareLogMessages(expected));
}
TEST_F(PerfProfdTest, ProfileCollectionAnnotations)
@@ -1110,7 +1112,7 @@
I: finishing Android Wide Profiling daemon
);
// check to make sure log excerpt matches
- CompareLogMessages(expandVars(expected), "BasicRunWithLivePerf", true);
+ EXPECT_TRUE(CompareLogMessages(expandVars(expected), true));
}
TEST_F(PerfProfdTest, MultipleRunWithLivePerf)
@@ -1183,7 +1185,7 @@
I: finishing Android Wide Profiling daemon
);
// check to make sure log excerpt matches
- CompareLogMessages(expandVars(expected), "BasicRunWithLivePerf", true);
+ EXPECT_TRUE(CompareLogMessages(expandVars(expected), true));
}
TEST_F(PerfProfdTest, CallChainRunWithLivePerf)
@@ -1240,7 +1242,7 @@
I: finishing Android Wide Profiling daemon
);
// check to make sure log excerpt matches
- CompareLogMessages(expandVars(expected), "CallChainRunWithLivePerf", true);
+ EXPECT_TRUE(CompareLogMessages(expandVars(expected), true));
// Check that we have at least one SampleEvent with a callchain.
SampleEventIterator samples(encodedProfile);
diff --git a/simpleperf/IOEventLoop.cpp b/simpleperf/IOEventLoop.cpp
index 01f2acd..92d3afe 100644
--- a/simpleperf/IOEventLoop.cpp
+++ b/simpleperf/IOEventLoop.cpp
@@ -24,11 +24,13 @@
struct IOEvent {
IOEventLoop* loop;
event* e;
+ timeval timeout;
std::function<bool()> callback;
bool enabled;
IOEvent(IOEventLoop* loop, const std::function<bool()>& callback)
- : loop(loop), e(nullptr), callback(callback), enabled(false) {}
+ : loop(loop), e(nullptr), timeout({}), callback(callback), enabled(false) {
+ }
~IOEvent() {
if (e != nullptr) {
@@ -138,9 +140,8 @@
return true;
}
-bool IOEventLoop::AddPeriodicEvent(timeval duration,
- const std::function<bool()>& callback) {
- return AddEvent(-1, EV_PERSIST, &duration, callback) != nullptr;
+IOEventRef IOEventLoop::AddPeriodicEvent(timeval duration, const std::function<bool()>& callback) {
+ return AddEvent(-1, EV_PERSIST, &duration, callback);
}
IOEventRef IOEventLoop::AddEvent(int fd_or_sig, short events, timeval* timeout,
@@ -158,6 +159,9 @@
LOG(ERROR) << "event_add() failed";
return nullptr;
}
+ if (timeout != nullptr) {
+ e->timeout = *timeout;
+ }
e->enabled = true;
events_.push_back(std::move(e));
return events_.back().get();
@@ -200,7 +204,9 @@
bool IOEventLoop::EnableEvent(IOEventRef ref) {
if (!ref->enabled) {
- if (event_add(ref->e, nullptr) != 0) {
+ timeval* timeout = (ref->timeout.tv_sec != 0 || ref->timeout.tv_usec != 0) ?
+ &ref->timeout : nullptr;
+ if (event_add(ref->e, timeout) != 0) {
LOG(ERROR) << "event_add() failed";
return false;
}
diff --git a/simpleperf/IOEventLoop.h b/simpleperf/IOEventLoop.h
index 4a84197..3a15d05 100644
--- a/simpleperf/IOEventLoop.h
+++ b/simpleperf/IOEventLoop.h
@@ -57,8 +57,7 @@
// Register a periodic Event, so [callback] is called periodically every
// [duration].
- bool AddPeriodicEvent(timeval duration,
- const std::function<bool()>& callback);
+ IOEventRef AddPeriodicEvent(timeval duration, const std::function<bool()>& callback);
// Run a loop polling for Events. It only exits when ExitLoop() is called
// in a callback function of registered Events.
diff --git a/simpleperf/IOEventLoop_test.cpp b/simpleperf/IOEventLoop_test.cpp
index cf231ba..2a3fa96 100644
--- a/simpleperf/IOEventLoop_test.cpp
+++ b/simpleperf/IOEventLoop_test.cpp
@@ -216,6 +216,32 @@
close(fd[1]);
}
+TEST(IOEventLoop, disable_enable_periodic_event) {
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 200000;
+ IOEventLoop loop;
+ IOEventRef wait_ref = loop.AddPeriodicEvent(tv, [&]() { return loop.ExitLoop(); });
+ ASSERT_TRUE(wait_ref != nullptr);
+ ASSERT_TRUE(loop.DisableEvent(wait_ref));
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ size_t periodic_count = 0;
+ IOEventRef ref = loop.AddPeriodicEvent(tv, [&]() {
+ if (!loop.DisableEvent(ref)) {
+ return false;
+ }
+ periodic_count++;
+ if (periodic_count < 2u) {
+ return loop.EnableEvent(ref);
+ }
+ return loop.EnableEvent(wait_ref);
+ });
+ ASSERT_TRUE(loop.RunLoop());
+ ASSERT_EQ(2u, periodic_count);
+}
+
TEST(IOEventLoop, exit_before_loop) {
IOEventLoop loop;
ASSERT_TRUE(loop.ExitLoop());
diff --git a/simpleperf/JITDebugReader.cpp b/simpleperf/JITDebugReader.cpp
index 23f4ccd..7377799 100644
--- a/simpleperf/JITDebugReader.cpp
+++ b/simpleperf/JITDebugReader.cpp
@@ -36,14 +36,18 @@
namespace simpleperf {
-// To avoid too long time reading the jit/dex linked list, set an uplimit of entries read from the
-// linked list.
-static constexpr size_t MAX_LINKLED_LIST_LENGTH = 1024u;
-
// If the size of a symfile is larger than EXPECTED_MAX_SYMFILE_SIZE, we don't want to read it
// remotely.
static constexpr size_t MAX_JIT_SYMFILE_SIZE = 1024 * 1024u;
+// It takes about 30us-130us on Pixel (depending on the cpu frequency) to check if the descriptors
+// have been updated (most time spent in process_vm_preadv). We want to know if the JIT debug info
+// changed as soon as possible, while not wasting too much time checking for updates. So use a
+// period of 100 ms.
+// In system wide profiling, we may need to check JIT debug info changes for many processes, to
+// avoid spending all time checking, wait 100 ms between any two checks.
+static constexpr size_t kUpdateJITDebugInfoIntervalInMs = 100;
+
// Match the format of JITDescriptor in art/runtime/jit/debugger_itnerface.cc.
template <typename ADDRT>
struct JITDescriptor {
@@ -114,27 +118,117 @@
#endif
static_assert(sizeof(JITCodeEntry64) == 40, "");
-JITDebugReader::JITDebugReader(pid_t pid, bool keep_symfiles)
- : pid_(pid),
- keep_symfiles_(keep_symfiles),
- initialized_(false) {
- TryInit();
+bool JITDebugReader::RegisterSymFileCallback(IOEventLoop* loop,
+ const symfile_callback_t& callback) {
+ symfile_callback_ = callback;
+ read_event_ = loop->AddPeriodicEvent(SecondToTimeval(kUpdateJITDebugInfoIntervalInMs / 1000.0),
+ [this]() { return ReadAllProcesses(); });
+ return (read_event_ != nullptr && IOEventLoop::DisableEvent(read_event_));
}
-void JITDebugReader::ReadUpdate(std::vector<JITSymFile>* new_jit_symfiles,
- std::vector<DexSymFile>* new_dex_symfiles) {
- if (!TryInit()) {
+bool JITDebugReader::MonitorProcess(pid_t pid) {
+ if (processes_.find(pid) == processes_.end()) {
+ processes_[pid].pid = pid;
+ LOG(DEBUG) << "Start monitoring process " << pid;
+ if (processes_.size() == 1u) {
+ if (!IOEventLoop::EnableEvent(read_event_)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool IsArtLib(const std::string& filename) {
+ return android::base::EndsWith(filename, "libart.so") ||
+ android::base::EndsWith(filename, "libartd.so");
+}
+
+bool JITDebugReader::UpdateRecord(const Record* record) {
+ if (record->type() == PERF_RECORD_MMAP) {
+ auto r = static_cast<const MmapRecord*>(record);
+ if (IsArtLib(r->filename)) {
+ pids_with_art_lib_.emplace(r->data->pid, false);
+ }
+ } else if (record->type() == PERF_RECORD_MMAP2) {
+ auto r = static_cast<const Mmap2Record*>(record);
+ if (IsArtLib(r->filename)) {
+ pids_with_art_lib_.emplace(r->data->pid, false);
+ }
+ } else if (record->type() == PERF_RECORD_FORK) {
+ auto r = static_cast<const ForkRecord*>(record);
+ if (r->data->pid != r->data->ppid &&
+ pids_with_art_lib_.find(r->data->ppid) != pids_with_art_lib_.end()) {
+ pids_with_art_lib_.emplace(r->data->pid, false);
+ }
+ } else if (record->type() == PERF_RECORD_SAMPLE) {
+ auto r = static_cast<const SampleRecord*>(record);
+ auto it = pids_with_art_lib_.find(r->tid_data.pid);
+ if (it != pids_with_art_lib_.end() && !it->second) {
+ it->second = true;
+ if (!MonitorProcess(r->tid_data.pid)) {
+ return false;
+ }
+ return ReadProcess(r->tid_data.pid);
+ }
+ }
+ return true;
+}
+
+bool JITDebugReader::ReadAllProcesses() {
+ if (!IOEventLoop::DisableEvent(read_event_)) {
+ return false;
+ }
+ std::vector<JITSymFile> jit_symfiles;
+ std::vector<DexSymFile> dex_symfiles;
+ for (auto it = processes_.begin(); it != processes_.end();) {
+ Process& process = it->second;
+ ReadProcess(process, &jit_symfiles, &dex_symfiles);
+ if (process.died) {
+ LOG(DEBUG) << "Stop monitoring process " << process.pid;
+ it = processes_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ if (!jit_symfiles.empty() || !dex_symfiles.empty()) {
+ if (!symfile_callback_(jit_symfiles, dex_symfiles, true)) {
+ return false;
+ }
+ }
+ if (!processes_.empty()) {
+ return IOEventLoop::EnableEvent(read_event_);
+ }
+ return true;
+}
+
+bool JITDebugReader::ReadProcess(pid_t pid) {
+ auto it = processes_.find(pid);
+ if (it != processes_.end()) {
+ std::vector<JITSymFile> jit_symfiles;
+ std::vector<DexSymFile> dex_symfiles;
+ ReadProcess(it->second, &jit_symfiles, &dex_symfiles);
+ if (!jit_symfiles.empty() || !dex_symfiles.empty()) {
+ return symfile_callback_(jit_symfiles, dex_symfiles, false);
+ }
+ }
+ return true;
+}
+
+void JITDebugReader::ReadProcess(Process& process, std::vector<JITSymFile>* jit_symfiles,
+ std::vector<DexSymFile>* dex_symfiles) {
+ if (process.died || (!process.initialized && !InitializeProcess(process))) {
return;
}
// 1. Read descriptors.
Descriptor jit_descriptor;
Descriptor dex_descriptor;
- if (!ReadDescriptors(&jit_descriptor, &dex_descriptor)) {
+ if (!ReadDescriptors(process, &jit_descriptor, &dex_descriptor)) {
return;
}
// 2. Return if descriptors are not changed.
- if (jit_descriptor.action_seqlock == last_jit_descriptor_.action_seqlock &&
- dex_descriptor.action_seqlock == last_dex_descriptor_.action_seqlock) {
+ if (jit_descriptor.action_seqlock == process.last_jit_descriptor.action_seqlock &&
+ dex_descriptor.action_seqlock == process.last_dex_descriptor.action_seqlock) {
return;
}
@@ -142,7 +236,7 @@
auto check_descriptor = [&](Descriptor& descriptor, bool is_jit) {
Descriptor tmp_jit_descriptor;
Descriptor tmp_dex_descriptor;
- if (!ReadDescriptors(&tmp_jit_descriptor, &tmp_dex_descriptor)) {
+ if (!ReadDescriptors(process, &tmp_jit_descriptor, &tmp_dex_descriptor)) {
return false;
}
if (is_jit) {
@@ -155,82 +249,93 @@
bool is_jit) {
bool has_update = new_descriptor.action_seqlock != old_descriptor.action_seqlock &&
(new_descriptor.action_seqlock & 1) == 0;
+ LOG(DEBUG) << (is_jit ? "JIT" : "Dex") << " symfiles of pid " << process.pid
+ << ": old seqlock " << old_descriptor.action_seqlock
+ << ", new seqlock " << new_descriptor.action_seqlock;
if (!has_update) {
return false;
}
std::vector<CodeEntry> new_entries;
- if (!ReadNewCodeEntries(new_descriptor, old_descriptor.action_timestamp, &new_entries)) {
+ // Adding or removing one code entry will make two increments of action_seqlock. So we should
+ // not read more than (seqlock_diff / 2) new entries.
+ uint32_t read_entry_limit = (new_descriptor.action_seqlock - old_descriptor.action_seqlock) / 2;
+ if (!ReadNewCodeEntries(process, new_descriptor, old_descriptor.action_timestamp,
+ read_entry_limit, &new_entries)) {
return false;
}
// Check if the descriptor was changed while we were reading new entries.
if (!check_descriptor(new_descriptor, is_jit)) {
return false;
}
+ LOG(DEBUG) << (is_jit ? "JIT" : "Dex") << " symfiles of pid " << process.pid
+ << ": read " << new_entries.size() << " new entries";
if (new_entries.empty()) {
return true;
}
if (is_jit) {
- ReadJITSymFiles(new_entries, new_jit_symfiles);
+ ReadJITSymFiles(process, new_entries, jit_symfiles);
} else {
- ReadDexSymFiles(new_entries, new_dex_symfiles);
- }
- // Check if the descriptor was changed while we were reading symfiles.
- if (!check_descriptor(new_descriptor, is_jit)) {
- if (is_jit) {
- new_jit_symfiles->clear();
- } else {
- new_dex_symfiles->clear();
- }
- return false;
+ ReadDexSymFiles(process, new_entries, dex_symfiles);
}
return true;
};
- if (read_new_symfiles(jit_descriptor, last_jit_descriptor_, true)) {
- last_jit_descriptor_ = jit_descriptor;
+ if (read_new_symfiles(jit_descriptor, process.last_jit_descriptor, true)) {
+ process.last_jit_descriptor = jit_descriptor;
}
- if (read_new_symfiles(dex_descriptor, last_dex_descriptor_, false)) {
- last_dex_descriptor_ = dex_descriptor;
+ if (read_new_symfiles(dex_descriptor, process.last_dex_descriptor, false)) {
+ process.last_dex_descriptor = dex_descriptor;
}
}
-bool JITDebugReader::TryInit() {
- if (initialized_) {
- return true;
- }
+bool JITDebugReader::InitializeProcess(Process& process) {
// 1. Read map file to find the location of libart.so.
std::vector<ThreadMmap> thread_mmaps;
- if (!GetThreadMmapsInProcess(pid_, &thread_mmaps)) {
+ if (!GetThreadMmapsInProcess(process.pid, &thread_mmaps)) {
+ process.died = true;
return false;
}
std::string art_lib_path;
+ uint64_t min_vaddr_in_memory;
for (auto& map : thread_mmaps) {
- if (android::base::EndsWith(map.name, "libart.so")) {
+ if (map.executable && IsArtLib(map.name)) {
art_lib_path = map.name;
+ min_vaddr_in_memory = map.start_addr;
break;
}
}
if (art_lib_path.empty()) {
return false;
}
- is_64bit_ = art_lib_path.find("lib64") != std::string::npos;
+ process.is_64bit = art_lib_path.find("lib64") != std::string::npos;
// 2. Read libart.so to find the addresses of __jit_debug_descriptor and __dex_debug_descriptor.
+ const DescriptorsLocation* location = GetDescriptorsLocation(art_lib_path, process.is_64bit);
+ if (location == nullptr) {
+ return false;
+ }
+ process.descriptors_addr = location->relative_addr + min_vaddr_in_memory;
+ process.descriptors_size = location->size;
+ process.jit_descriptor_offset = location->jit_descriptor_offset;
+ process.dex_descriptor_offset = location->dex_descriptor_offset;
+ process.initialized = true;
+ return true;
+}
+
+const JITDebugReader::DescriptorsLocation* JITDebugReader::GetDescriptorsLocation(
+ const std::string& art_lib_path, bool is_64bit) {
+ auto it = descriptors_location_cache_.find(art_lib_path);
+ if (it != descriptors_location_cache_.end()) {
+ return it->second.relative_addr == 0u ? nullptr : &it->second;
+ }
+ DescriptorsLocation& location = descriptors_location_cache_[art_lib_path];
+
+ // Read libart.so to find the addresses of __jit_debug_descriptor and __dex_debug_descriptor.
uint64_t min_vaddr_in_file;
ElfStatus status = ReadMinExecutableVirtualAddressFromElfFile(art_lib_path, BuildId(),
- &min_vaddr_in_file);
+ &min_vaddr_in_file);
if (status != ElfStatus::NO_ERROR) {
LOG(ERROR) << "ReadMinExecutableVirtualAddress failed, status = " << status;
- return false;
- }
- uint64_t min_vaddr_in_memory = 0u;
- for (auto& map : thread_mmaps) {
- if (map.executable && map.name == art_lib_path) {
- min_vaddr_in_memory = map.start_addr;
- break;
- }
- }
- if (min_vaddr_in_memory == 0u) {
- return false;
+ return nullptr;
}
const char* jit_str = "__jit_debug_descriptor";
const char* dex_str = "__dex_debug_descriptor";
@@ -239,68 +344,74 @@
auto callback = [&](const ElfFileSymbol& symbol) {
if (symbol.name == jit_str) {
- jit_addr = symbol.vaddr - min_vaddr_in_file + min_vaddr_in_memory;
+ jit_addr = symbol.vaddr - min_vaddr_in_file;
} else if (symbol.name == dex_str) {
- dex_addr = symbol.vaddr - min_vaddr_in_file + min_vaddr_in_memory;
+ dex_addr = symbol.vaddr - min_vaddr_in_file;
}
};
if (ParseDynamicSymbolsFromElfFile(art_lib_path, callback) != ElfStatus::NO_ERROR) {
- return false;
+ return nullptr;
}
if (jit_addr == 0u || dex_addr == 0u) {
- return false;
+ return nullptr;
}
- descriptors_addr_ = std::min(jit_addr, dex_addr);
- descriptors_size_ = std::max(jit_addr, dex_addr) +
- (is_64bit_ ? sizeof(JITDescriptor64) : sizeof(JITDescriptor32)) - descriptors_addr_;
- if (descriptors_size_ >= 4096u) {
- PLOG(WARNING) << "The descriptors_size is unexpected large: " << descriptors_size_;
+ location.relative_addr = std::min(jit_addr, dex_addr);
+ location.size = std::max(jit_addr, dex_addr) +
+ (is_64bit ? sizeof(JITDescriptor64) : sizeof(JITDescriptor32)) - location.relative_addr;
+ if (location.size >= 4096u) {
+ PLOG(WARNING) << "The descriptors_size is unexpected large: " << location.size;
}
- descriptors_buf_.resize(descriptors_size_);
- jit_descriptor_offset_ = jit_addr - descriptors_addr_;
- dex_descriptor_offset_ = dex_addr - descriptors_addr_;
- initialized_ = true;
- return true;
+ if (descriptors_buf_.size() < location.size) {
+ descriptors_buf_.resize(location.size);
+ }
+ location.jit_descriptor_offset = jit_addr - location.relative_addr;
+ location.dex_descriptor_offset = dex_addr - location.relative_addr;
+ return &location;
}
-bool JITDebugReader::ReadRemoteMem(uint64_t remote_addr, uint64_t size, void* data) {
+bool JITDebugReader::ReadRemoteMem(Process& process, uint64_t remote_addr, uint64_t size,
+ void* data) {
iovec local_iov;
local_iov.iov_base = data;
local_iov.iov_len = size;
iovec remote_iov;
remote_iov.iov_base = reinterpret_cast<void*>(static_cast<uintptr_t>(remote_addr));
remote_iov.iov_len = size;
- ssize_t result = process_vm_readv(pid_, &local_iov, 1, &remote_iov, 1, 0);
+ ssize_t result = process_vm_readv(process.pid, &local_iov, 1, &remote_iov, 1, 0);
if (static_cast<size_t>(result) != size) {
- PLOG(DEBUG) << "ReadRemoteMem(" << " pid " << pid_ << ", addr " << std::hex
+ PLOG(DEBUG) << "ReadRemoteMem(" << " pid " << process.pid << ", addr " << std::hex
<< remote_addr << ", size " << size << ") failed";
+ process.died = true;
return false;
}
return true;
}
-bool JITDebugReader::ReadDescriptors(Descriptor* jit_descriptor, Descriptor* dex_descriptor) {
- if (!ReadRemoteMem(descriptors_addr_, descriptors_size_, descriptors_buf_.data())) {
+bool JITDebugReader::ReadDescriptors(Process& process, Descriptor* jit_descriptor,
+ Descriptor* dex_descriptor) {
+ if (!ReadRemoteMem(process, process.descriptors_addr, process.descriptors_size,
+ descriptors_buf_.data())) {
return false;
}
- return LoadDescriptor(descriptors_buf_.data() + jit_descriptor_offset_, jit_descriptor) &&
- LoadDescriptor(descriptors_buf_.data() + dex_descriptor_offset_, dex_descriptor);
+ return LoadDescriptor(process.is_64bit, &descriptors_buf_[process.jit_descriptor_offset],
+ jit_descriptor) &&
+ LoadDescriptor(process.is_64bit, &descriptors_buf_[process.dex_descriptor_offset],
+ dex_descriptor);
}
-bool JITDebugReader::LoadDescriptor(const char* data, Descriptor* descriptor) {
- if (is_64bit_) {
- return LoadDescriptorImpl<JITDescriptor64>(data, descriptor);
+bool JITDebugReader::LoadDescriptor(bool is_64bit, const char* data, Descriptor* descriptor) {
+ if (is_64bit) {
+ return LoadDescriptorImpl<JITDescriptor64, JITCodeEntry64>(data, descriptor);
}
- return LoadDescriptorImpl<JITDescriptor32>(data, descriptor);
+ return LoadDescriptorImpl<JITDescriptor32, JITCodeEntry32>(data, descriptor);
}
-template <typename DescriptorT>
+template <typename DescriptorT, typename CodeEntryT>
bool JITDebugReader::LoadDescriptorImpl(const char* data, Descriptor* descriptor) {
DescriptorT raw_descriptor;
MoveFromBinaryFormat(raw_descriptor, data);
if (!raw_descriptor.Valid() || sizeof(raw_descriptor) != raw_descriptor.sizeof_descriptor ||
- (is_64bit_ ? sizeof(JITCodeEntry64) : sizeof(JITCodeEntry32)) != raw_descriptor.sizeof_entry
- ) {
+ sizeof(CodeEntryT) != raw_descriptor.sizeof_entry) {
return false;
}
descriptor->action_seqlock = raw_descriptor.action_seqlock;
@@ -312,33 +423,32 @@
// Read new code entries with timestamp > last_action_timestamp.
// Since we don't stop the app process while reading code entries, it is possible we are reading
// broken data. So return false once we detect that the data is broken.
-bool JITDebugReader::ReadNewCodeEntries(const Descriptor& descriptor,
- uint64_t last_action_timestamp,
+bool JITDebugReader::ReadNewCodeEntries(Process& process, const Descriptor& descriptor,
+ uint64_t last_action_timestamp, uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries) {
- if (is_64bit_) {
- return ReadNewCodeEntriesImpl<JITDescriptor64, JITCodeEntry64>(descriptor,
- last_action_timestamp,
- new_code_entries);
+ if (process.is_64bit) {
+ return ReadNewCodeEntriesImpl<JITDescriptor64, JITCodeEntry64>(
+ process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
}
- return ReadNewCodeEntriesImpl<JITDescriptor32, JITCodeEntry32>(descriptor,
- last_action_timestamp,
- new_code_entries);
+ return ReadNewCodeEntriesImpl<JITDescriptor32, JITCodeEntry32>(
+ process, descriptor, last_action_timestamp, read_entry_limit, new_code_entries);
}
template <typename DescriptorT, typename CodeEntryT>
-bool JITDebugReader::ReadNewCodeEntriesImpl(const Descriptor& descriptor,
+bool JITDebugReader::ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor,
uint64_t last_action_timestamp,
+ uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries) {
uint64_t current_entry_addr = descriptor.first_entry_addr;
uint64_t prev_entry_addr = 0u;
std::unordered_set<uint64_t> entry_addr_set;
- for (size_t i = 0u; i < MAX_LINKLED_LIST_LENGTH && current_entry_addr != 0u; ++i) {
+ for (size_t i = 0u; i < read_entry_limit && current_entry_addr != 0u; ++i) {
if (entry_addr_set.find(current_entry_addr) != entry_addr_set.end()) {
// We enter a loop, which means a broken linked list.
return false;
}
CodeEntryT entry;
- if (!ReadRemoteMem(current_entry_addr, sizeof(entry), &entry)) {
+ if (!ReadRemoteMem(process, current_entry_addr, sizeof(entry), &entry)) {
return false;
}
if (entry.prev_addr != prev_entry_addr || !entry.Valid()) {
@@ -362,7 +472,7 @@
return true;
}
-void JITDebugReader::ReadJITSymFiles(const std::vector<CodeEntry>& jit_entries,
+void JITDebugReader::ReadJITSymFiles(Process& process, const std::vector<CodeEntry>& jit_entries,
std::vector<JITSymFile>* jit_symfiles) {
std::vector<char> data;
for (auto& jit_entry : jit_entries) {
@@ -372,7 +482,7 @@
if (data.size() < jit_entry.symfile_size) {
data.resize(jit_entry.symfile_size);
}
- if (!ReadRemoteMem(jit_entry.symfile_addr, jit_entry.symfile_size, data.data())) {
+ if (!ReadRemoteMem(process, jit_entry.symfile_addr, jit_entry.symfile_size, data.data())) {
continue;
}
if (!IsValidElfFileMagic(data.data(), jit_entry.symfile_size)) {
@@ -398,18 +508,15 @@
if (keep_symfiles_) {
tmp_file->DoNotRemove();
}
- JITSymFile symfile;
- symfile.addr = min_addr;
- symfile.len = max_addr - min_addr;
- symfile.file_path = tmp_file->path;
- jit_symfiles->push_back(symfile);
+ jit_symfiles->emplace_back(process.pid, min_addr, max_addr - min_addr, tmp_file->path);
}
}
-void JITDebugReader::ReadDexSymFiles(const std::vector<CodeEntry>& dex_entries,
+void JITDebugReader::ReadDexSymFiles(Process& process, const std::vector<CodeEntry>& dex_entries,
std::vector<DexSymFile>* dex_symfiles) {
std::vector<ThreadMmap> thread_mmaps;
- if (!GetThreadMmapsInProcess(pid_, &thread_mmaps)) {
+ if (!GetThreadMmapsInProcess(process.pid, &thread_mmaps)) {
+ process.died = true;
return;
}
auto comp = [](const ThreadMmap& map, uint64_t addr) {
diff --git a/simpleperf/JITDebugReader.h b/simpleperf/JITDebugReader.h
index dbf5b76..8561461 100644
--- a/simpleperf/JITDebugReader.h
+++ b/simpleperf/JITDebugReader.h
@@ -22,18 +22,27 @@
#include <functional>
#include <memory>
#include <stack>
+#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <android-base/logging.h>
#include <android-base/test_utils.h>
+#include "IOEventLoop.h"
+#include "record.h"
+
namespace simpleperf {
struct JITSymFile {
+ pid_t pid; // The process having the JITed code
uint64_t addr; // The start addr of the JITed code
uint64_t len; // The length of the JITed code
std::string file_path; // The path of a temporary ELF file storing debug info of the JITed code
+
+ JITSymFile() {}
+ JITSymFile(pid_t pid, uint64_t addr, uint64_t len, const std::string& file_path)
+ : pid(pid), addr(addr), len(len), file_path(file_path) {}
};
struct DexSymFile {
@@ -45,16 +54,23 @@
: dex_file_offset(dex_file_offset), file_path(file_path) {}
};
+// JITDebugReader reads debug info of JIT code and dex files of processes using ART. The
+// corresponding debug interface in ART is at art/runtime/jit/debugger_interface.cc.
class JITDebugReader {
public:
- JITDebugReader(pid_t pid, bool keep_symfiles);
+ JITDebugReader(bool keep_symfiles) : keep_symfiles_(keep_symfiles) {}
- pid_t Pid() const {
- return pid_;
- }
+ typedef std::function<bool(const std::vector<JITSymFile>&, const std::vector<DexSymFile>&, bool)>
+ symfile_callback_t;
+ bool RegisterSymFileCallback(IOEventLoop* loop, const symfile_callback_t& callback);
- void ReadUpdate(std::vector<JITSymFile>* new_jit_symfiles,
- std::vector<DexSymFile>* new_dex_symfiles);
+ // There are two ways to select which processes to monitor. One is using MonitorProcess(), the
+ // other is finding all processes having libart.so using records.
+ bool MonitorProcess(pid_t pid);
+ bool UpdateRecord(const Record* record);
+
+ // Read new debug info from all monitored processes.
+ bool ReadAllProcesses();
private:
@@ -73,42 +89,69 @@
uint64_t timestamp; // CLOCK_MONOTONIC time of last action
};
- bool TryInit();
- bool ReadRemoteMem(uint64_t remote_addr, uint64_t size, void* data);
- bool ReadDescriptors(Descriptor* jit_descriptor, Descriptor* dex_descriptor);
- bool LoadDescriptor(const char* data, Descriptor* descriptor);
- template <typename DescriptorT>
+ struct Process {
+ pid_t pid = -1;
+ bool initialized = false;
+ bool died = false;
+ bool is_64bit = false;
+ // The jit descriptor and dex descriptor can be read in one process_vm_readv() call.
+ uint64_t descriptors_addr = 0;
+ uint64_t descriptors_size = 0;
+ // offset relative to descriptors_addr
+ uint64_t jit_descriptor_offset = 0;
+ // offset relative to descriptors_addr
+ uint64_t dex_descriptor_offset = 0;
+
+ // The state we know about the remote jit debug descriptor.
+ Descriptor last_jit_descriptor;
+ // The state we know about the remote dex debug descriptor.
+ Descriptor last_dex_descriptor;
+ };
+
+ // The location of descriptors in libart.so.
+ struct DescriptorsLocation {
+ uint64_t relative_addr = 0;
+ uint64_t size = 0;
+ uint64_t jit_descriptor_offset = 0;
+ uint64_t dex_descriptor_offset = 0;
+ };
+
+ bool ReadProcess(pid_t pid);
+ void ReadProcess(Process& process, std::vector<JITSymFile>* jit_symfiles,
+ std::vector<DexSymFile>* dex_symfiles);
+ bool InitializeProcess(Process& process);
+ const DescriptorsLocation* GetDescriptorsLocation(const std::string& art_lib_path,
+ bool is_64bit);
+ bool ReadRemoteMem(Process& process, uint64_t remote_addr, uint64_t size, void* data);
+ bool ReadDescriptors(Process& process, Descriptor* jit_descriptor, Descriptor* dex_descriptor);
+ bool LoadDescriptor(bool is_64bit, const char* data, Descriptor* descriptor);
+ template <typename DescriptorT, typename CodeEntryT>
bool LoadDescriptorImpl(const char* data, Descriptor* descriptor);
- bool ReadNewCodeEntries(const Descriptor& descriptor, uint64_t last_action_timestamp,
+ bool ReadNewCodeEntries(Process& process, const Descriptor& descriptor,
+ uint64_t last_action_timestamp, uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries);
template <typename DescriptorT, typename CodeEntryT>
- bool ReadNewCodeEntriesImpl(const Descriptor& descriptor, uint64_t last_action_timestamp,
+ bool ReadNewCodeEntriesImpl(Process& process, const Descriptor& descriptor,
+ uint64_t last_action_timestamp, uint32_t read_entry_limit,
std::vector<CodeEntry>* new_code_entries);
- void ReadJITSymFiles(const std::vector<CodeEntry>& jit_entries,
+ void ReadJITSymFiles(Process& process, const std::vector<CodeEntry>& jit_entries,
std::vector<JITSymFile>* jit_symfiles);
- void ReadDexSymFiles(const std::vector<CodeEntry>& dex_entries,
+ void ReadDexSymFiles(Process& process, const std::vector<CodeEntry>& dex_entries,
std::vector<DexSymFile>* dex_symfiles);
- pid_t pid_;
- bool keep_symfiles_;
- bool initialized_;
- bool is_64bit_;
+ bool keep_symfiles_ = false;
+ IOEventRef read_event_ = nullptr;
+ symfile_callback_t symfile_callback_;
- // The jit descriptor and dex descriptor can be read in one process_vm_readv() call.
- uint64_t descriptors_addr_;
- uint64_t descriptors_size_;
+ // Keys are pids of processes having libart.so, values show whether a process has been monitored.
+ std::unordered_map<pid_t, bool> pids_with_art_lib_;
+
+ // All monitored processes
+ std::unordered_map<pid_t, Process> processes_;
+ std::unordered_map<std::string, DescriptorsLocation> descriptors_location_cache_;
std::vector<char> descriptors_buf_;
- // offset relative to descriptors_addr
- uint64_t jit_descriptor_offset_;
- // offset relative to descriptors_addr
- uint64_t dex_descriptor_offset_;
-
- // The state we know about the remote jit debug descriptor.
- Descriptor last_jit_descriptor_;
- // The state we know about the remote dex debug descriptor.
- Descriptor last_dex_descriptor_;
};
} //namespace simpleperf
diff --git a/simpleperf/cmd_debug_unwind.cpp b/simpleperf/cmd_debug_unwind.cpp
index edfad9f..b819196 100644
--- a/simpleperf/cmd_debug_unwind.cpp
+++ b/simpleperf/cmd_debug_unwind.cpp
@@ -338,7 +338,7 @@
sr.UpdateUserCallChain(ips);
return writer_->WriteRecord(sr);
};
- return reader->ReadDataSection(record_callback, false);
+ return reader->ReadDataSection(record_callback);
}
bool DebugUnwindCommand::WriteFeatureSections() {
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index d55b723..d7b70d2 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -215,7 +215,7 @@
}
return true;
};
- return record_file_reader_->ReadDataSection(record_callback, false);
+ return record_file_reader_->ReadDataSection(record_callback);
}
bool DumpRecordCommand::DumpFeatureSection() {
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 98cbcb4..01a2c9f 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -259,7 +259,8 @@
bool SaveRecordForPostUnwinding(Record* record);
bool SaveRecordAfterUnwinding(Record* record);
bool SaveRecordWithoutUnwinding(Record* record);
- bool UpdateJITDebugInfo();
+ bool ProcessJITDebugInfo(const std::vector<JITSymFile>& jit_symfiles,
+ const std::vector<DexSymFile>& dex_symfiles, bool sync_kernel_records);
void UpdateRecordForEmbeddedPath(Record* record);
bool UnwindRecord(SampleRecord& r);
@@ -416,21 +417,12 @@
need_to_check_targets = true;
}
// Profiling JITed/interpreted Java code is supported starting from Android P.
- if (!system_wide_collection_ && !app_package_name_.empty() &&
- GetAndroidVersion() >= kAndroidVersionP) {
- pid_t app_pid = 0;
- // TODO: support a JITDebugReader for each app process?
- if (!event_selection_set_.GetMonitoredProcesses().empty()) {
- app_pid = *event_selection_set_.GetMonitoredProcesses().begin();
- } else if (!event_selection_set_.GetMonitoredThreads().empty()) {
- app_pid = *event_selection_set_.GetMonitoredThreads().begin();
- }
- CHECK_NE(app_pid, 0);
+ if (GetAndroidVersion() >= kAndroidVersionP) {
// JIT symfiles are stored in temporary files, and are deleted after recording. But if
// `-g --no-unwind` option is used, we want to keep symfiles to support unwinding in
// the debug-unwind cmd.
bool keep_symfiles = dwarf_callchain_sampling_ && !unwind_dwarf_callchain_;
- jit_debug_reader_.reset(new JITDebugReader(app_pid, keep_symfiles));
+ jit_debug_reader_.reset(new JITDebugReader(keep_symfiles));
// To profile java code, need to dump maps containing vdex files, which are not executable.
event_selection_set_.SetRecordNotExecutableMaps(true);
}
@@ -478,18 +470,29 @@
}
}
if (jit_debug_reader_) {
- // Update JIT info at the beginning of recording.
- if (!UpdateJITDebugInfo()) {
+ auto callback = [this](const std::vector<JITSymFile>& jit_symfiles,
+ const std::vector<DexSymFile>& dex_symfiles, bool sync_kernel_records) {
+ return ProcessJITDebugInfo(jit_symfiles, dex_symfiles, sync_kernel_records);
+ };
+ if (!jit_debug_reader_->RegisterSymFileCallback(loop, callback)) {
return false;
}
- // It takes about 30us-130us on Pixel (depending on the cpu frequency) to check update when
- // no update happens (most time spent in process_vm_preadv). We want to know the JIT debug
- // info change as soon as possible, while not wasting too much time checking updates. So use
- // a period of 100 ms.
- const double kUpdateJITDebugInfoPeriodInSecond = 0.1;
- if (!loop->AddPeriodicEvent(SecondToTimeval(kUpdateJITDebugInfoPeriodInSecond),
- [&]() { return UpdateJITDebugInfo(); })) {
- return false;
+ if (!app_package_name_.empty()) {
+ std::set<pid_t> pids = event_selection_set_.GetMonitoredProcesses();
+ for (pid_t tid : event_selection_set_.GetMonitoredThreads()) {
+ pid_t pid;
+ if (GetProcessForThread(tid, &pid)) {
+ pids.insert(pid);
+ }
+ }
+ for (pid_t pid : pids) {
+ if (!jit_debug_reader_->MonitorProcess(pid)) {
+ return false;
+ }
+ }
+ if (!jit_debug_reader_->ReadAllProcesses()) {
+ return false;
+ }
}
}
return true;
@@ -1048,7 +1051,10 @@
return event_selection_set_.GetIOEventLoop()->ExitLoop();
}
}
- last_record_timestamp_ = record->Timestamp();
+ if (jit_debug_reader_ && !jit_debug_reader_->UpdateRecord(record)) {
+ return false;
+ }
+ last_record_timestamp_ = std::max(last_record_timestamp_, record->Timestamp());
if (unwind_dwarf_callchain_) {
if (post_unwind_) {
return SaveRecordForPostUnwinding(record);
@@ -1139,16 +1145,12 @@
return record_file_writer_->WriteRecord(*record);
}
-bool RecordCommand::UpdateJITDebugInfo() {
- std::vector<JITSymFile> jit_symfiles;
- std::vector<DexSymFile> dex_symfiles;
- jit_debug_reader_->ReadUpdate(&jit_symfiles, &dex_symfiles);
- if (jit_symfiles.empty() && dex_symfiles.empty()) {
- return true;
- }
+bool RecordCommand::ProcessJITDebugInfo(const std::vector<JITSymFile>& jit_symfiles,
+ const std::vector<DexSymFile>& dex_symfiles,
+ bool sync_kernel_records) {
EventAttrWithId attr_id = event_selection_set_.GetEventAttrWithId()[0];
for (auto& symfile : jit_symfiles) {
- Mmap2Record record(*attr_id.attr, false, jit_debug_reader_->Pid(), jit_debug_reader_->Pid(),
+ Mmap2Record record(*attr_id.attr, false, symfile.pid, symfile.pid,
symfile.addr, symfile.len, 0, map_flags::PROT_JIT_SYMFILE_MAP,
symfile.file_path, attr_id.ids[0], last_record_timestamp_);
if (!ProcessRecord(&record)) {
@@ -1162,7 +1164,7 @@
// generated after them. So process existing samples each time generating new JIT maps. We prefer
// to process samples after processing JIT maps. Because some of the samples may hit the new JIT
// maps, and we want to report them properly.
- if (!event_selection_set_.ReadMmapEventData()) {
+ if (sync_kernel_records && !event_selection_set_.ReadMmapEventData()) {
return false;
}
return true;
@@ -1175,6 +1177,13 @@
return;
}
std::string filename = r.filename;
+ bool name_changed = false;
+ // Some vdex files in map files are marked with deleted flag, but they exist in the file system.
+ // It may be because a new file is used to replace the old one, but still worth to try.
+ if (android::base::EndsWith(filename, " (deleted)")) {
+ filename.resize(filename.size() - 10);
+ name_changed = true;
+ }
if (r.data->pgoff != 0) {
// For the case of a shared library "foobar.so" embedded
// inside an APK, we rewrite the original MMAP from
@@ -1198,8 +1207,12 @@
std::string zip_path;
std::string entry_name;
if (ParseExtractedInMemoryPath(filename, &zip_path, &entry_name)) {
+ filename = GetUrlInApk(zip_path, entry_name);
+ name_changed = true;
+ }
+ if (name_changed) {
auto data = *r.data;
- r.SetDataAndFilename(data, GetUrlInApk(zip_path, entry_name));
+ r.SetDataAndFilename(data, filename);
}
}
@@ -1260,7 +1273,7 @@
auto callback = [this](std::unique_ptr<Record> record) {
return SaveRecordAfterUnwinding(record.get());
};
- return reader->ReadDataSection(callback, false);
+ return reader->ReadDataSection(callback);
}
bool RecordCommand::JoinCallChains() {
@@ -1308,7 +1321,7 @@
sr.UpdateUserCallChain(ips);
return record_file_writer_->WriteRecord(sr);
};
- return reader->ReadDataSection(record_callback, false);
+ return reader->ReadDataSection(record_callback);
}
bool RecordCommand::DumpAdditionalFeatures(
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 4ef591f..fa4bab9 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -57,9 +57,13 @@
return RecordCmd()->Run(v);
}
-TEST(record_cmd, no_options) { ASSERT_TRUE(RunRecordCmd({})); }
+TEST(record_cmd, no_options) {
+ TEST_REQUIRE_HW_COUNTER();
+ ASSERT_TRUE(RunRecordCmd({}));
+}
TEST(record_cmd, system_wide_option) {
+ TEST_REQUIRE_HW_COUNTER();
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a"})));
}
@@ -86,6 +90,7 @@
}
TEST(record_cmd, sample_period_option) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-c", "100000"}, tmpfile.path));
CheckEventType(tmpfile.path, "cpu-cycles", 100000u, 0);
@@ -96,6 +101,7 @@
}
TEST(record_cmd, freq_option) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-f", "99"}, tmpfile.path));
CheckEventType(tmpfile.path, "cpu-cycles", 0, 99u);
@@ -105,6 +111,7 @@
}
TEST(record_cmd, multiple_freq_or_sample_period_option) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-f", "99", "-e", "cpu-cycles", "-c", "1000000", "-e",
"cpu-clock"}, tmpfile.path));
@@ -113,11 +120,13 @@
}
TEST(record_cmd, output_file_option) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "sleep", SLEEP_SEC}));
}
TEST(record_cmd, dump_kernel_mmap) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader =
@@ -141,6 +150,7 @@
}
TEST(record_cmd, dump_build_id_feature) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader =
@@ -157,6 +167,7 @@
}
TEST(record_cmd, rN_event) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
size_t event_number;
if (GetBuildArch() == ARCH_ARM64 || GetBuildArch() == ARCH_ARM) {
@@ -183,6 +194,7 @@
}
TEST(record_cmd, branch_sampling) {
+ TEST_REQUIRE_HW_COUNTER();
if (IsBranchSamplingSupported()) {
ASSERT_TRUE(RunRecordCmd({"-b"}));
ASSERT_TRUE(RunRecordCmd({"-j", "any,any_call,any_ret,ind_call"}));
@@ -196,14 +208,17 @@
}
TEST(record_cmd, event_modifier) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"-e", "cpu-cycles:u"}));
}
TEST(record_cmd, fp_callchain_sampling) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"--call-graph", "fp"}));
}
TEST(record_cmd, fp_callchain_sampling_warning_on_arm) {
+ TEST_REQUIRE_HW_COUNTER();
if (GetBuildArch() != ARCH_ARM) {
GTEST_LOG_(INFO) << "This test does nothing as it only tests on arm arch.";
return;
@@ -216,6 +231,7 @@
}
TEST(record_cmd, system_wide_fp_callchain_sampling) {
+ TEST_REQUIRE_HW_COUNTER();
TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a", "--call-graph", "fp"})));
}
@@ -242,7 +258,25 @@
return in_native_abi == 1;
}
+bool HasHardwareCounter() {
+ static int has_hw_counter = -1;
+ if (has_hw_counter == -1) {
+ has_hw_counter = 1;
+#if defined(__arm__)
+ std::string cpu_info;
+ if (android::base::ReadFileToString("/proc/cpuinfo", &cpu_info)) {
+ std::string hardware = GetHardwareFromCpuInfo(cpu_info);
+ if (std::regex_search(hardware, std::regex(R"(i\.MX6.*Quad)"))) {
+ has_hw_counter = 0;
+ }
+ }
+#endif
+ }
+ return has_hw_counter == 1;
+}
+
TEST(record_cmd, dwarf_callchain_sampling) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
std::vector<std::unique_ptr<Workload>> workloads;
@@ -255,12 +289,14 @@
}
TEST(record_cmd, system_wide_dwarf_callchain_sampling) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
TEST_IN_ROOT(RunRecordCmd({"-a", "--call-graph", "dwarf"}));
}
TEST(record_cmd, no_unwind_option) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf", "--no-unwind"}));
@@ -268,6 +304,7 @@
}
TEST(record_cmd, post_unwind_option) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
std::vector<std::unique_ptr<Workload>> workloads;
@@ -279,6 +316,7 @@
}
TEST(record_cmd, existing_processes) {
+ TEST_REQUIRE_HW_COUNTER();
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
std::string pid_list = android::base::StringPrintf(
@@ -287,6 +325,7 @@
}
TEST(record_cmd, existing_threads) {
+ TEST_REQUIRE_HW_COUNTER();
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(2, &workloads);
// Process id can also be used as thread id in linux.
@@ -296,6 +335,7 @@
}
TEST(record_cmd, no_monitored_threads) {
+ TEST_REQUIRE_HW_COUNTER();
ScopedAppPackageName scoped_package_name("");
TemporaryFile tmpfile;
ASSERT_FALSE(RecordCmd()->Run({"-o", tmpfile.path}));
@@ -303,11 +343,13 @@
}
TEST(record_cmd, more_than_one_event_types) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"-e", "cpu-cycles,cpu-clock"}));
ASSERT_TRUE(RunRecordCmd({"-e", "cpu-cycles", "-e", "cpu-clock"}));
}
TEST(record_cmd, mmap_page_option) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"-m", "1"}));
ASSERT_FALSE(RunRecordCmd({"-m", "0"}));
ASSERT_FALSE(RunRecordCmd({"-m", "7"}));
@@ -332,6 +374,7 @@
}
TEST(record_cmd, kernel_symbol) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols"}, tmpfile.path));
bool success;
@@ -383,6 +426,7 @@
}
TEST(record_cmd, no_dump_symbols) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
bool success;
@@ -405,6 +449,7 @@
}
TEST(record_cmd, dump_kernel_symbols) {
+ TEST_REQUIRE_HW_COUNTER();
if (!IsRoot()) {
GTEST_LOG_(INFO) << "Test requires root privilege";
return;
@@ -432,15 +477,20 @@
}
TEST(record_cmd, group_option) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"--group", "cpu-cycles,cpu-clock", "-m", "16"}));
ASSERT_TRUE(RunRecordCmd({"--group", "cpu-cycles,cpu-clock", "--group",
"cpu-cycles:u,cpu-clock:u", "--group",
"cpu-cycles:k,cpu-clock:k", "-m", "16"}));
}
-TEST(record_cmd, symfs_option) { ASSERT_TRUE(RunRecordCmd({"--symfs", "/"})); }
+TEST(record_cmd, symfs_option) {
+ TEST_REQUIRE_HW_COUNTER();
+ ASSERT_TRUE(RunRecordCmd({"--symfs", "/"}));
+}
TEST(record_cmd, duration_option) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"--duration", "1.2", "-p",
std::to_string(getpid()), "-o", tmpfile.path, "--in-app"}));
@@ -458,6 +508,7 @@
}
TEST(record_cmd, handle_SIGHUP) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
int pipefd[2];
ASSERT_EQ(0, pipe(pipefd));
@@ -477,6 +528,7 @@
}
TEST(record_cmd, stop_when_no_more_targets) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
std::atomic<int> tid(0);
std::thread thread([&]() {
@@ -489,6 +541,7 @@
}
TEST(record_cmd, donot_stop_when_having_targets) {
+ TEST_REQUIRE_HW_COUNTER();
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(1, &workloads);
std::string pid = std::to_string(workloads[0]->GetPid());
@@ -500,6 +553,7 @@
}
TEST(record_cmd, start_profiling_fd_option) {
+ TEST_REQUIRE_HW_COUNTER();
int pipefd[2];
ASSERT_EQ(0, pipe(pipefd));
int read_fd = pipefd[0];
@@ -518,6 +572,7 @@
}
TEST(record_cmd, record_meta_info_feature) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
@@ -543,6 +598,7 @@
}
TEST(record_cmd, dump_regs_for_tracepoint_events) {
+ TEST_REQUIRE_HW_COUNTER();
TEST_REQUIRE_HOST_ROOT();
OMIT_TEST_ON_NON_NATIVE_ABIS();
// Check if the kernel can dump registers for tracepoint events.
@@ -552,6 +608,7 @@
}
TEST(record_cmd, trace_offcpu_option) {
+ TEST_REQUIRE_HW_COUNTER();
// On linux host, we need root privilege to read tracepoint events.
TEST_REQUIRE_HOST_ROOT();
OMIT_TEST_ON_NON_NATIVE_ABIS();
@@ -566,10 +623,12 @@
}
TEST(record_cmd, exit_with_parent_option) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"--exit-with-parent"}));
}
TEST(record_cmd, clockid_option) {
+ TEST_REQUIRE_HW_COUNTER();
if (!IsSettingClockIdSupported()) {
ASSERT_FALSE(RunRecordCmd({"--clockid", "monotonic"}));
} else {
@@ -584,6 +643,7 @@
}
TEST(record_cmd, generate_samples_by_hw_counters) {
+ TEST_REQUIRE_HW_COUNTER();
std::vector<std::string> events = {"cpu-cycles", "instructions"};
for (auto& event : events) {
TemporaryFile tmpfile;
@@ -602,16 +662,19 @@
}
TEST(record_cmd, callchain_joiner_options) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(RunRecordCmd({"--no-callchain-joiner"}));
ASSERT_TRUE(RunRecordCmd({"--callchain-joiner-min-matching-nodes", "2"}));
}
TEST(record_cmd, dashdash) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmpfile;
ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "--", "sleep", "1"}));
}
TEST(record_cmd, size_limit_option) {
+ TEST_REQUIRE_HW_COUNTER();
std::vector<std::unique_ptr<Workload>> workloads;
CreateProcesses(1, &workloads);
std::string pid = std::to_string(workloads[0]->GetPid());
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index 3eb3c91..03a67bd 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -478,7 +478,7 @@
bool found = false;
for (auto& line : lines) {
if (line.find("SleepFunction") != std::string::npos) {
- ASSERT_NE(line.find("38.77%"), std::string::npos);
+ ASSERT_NE(line.find("38.76%"), std::string::npos);
found = true;
break;
}
@@ -499,6 +499,7 @@
}
TEST_F(ReportCommandTest, dwarf_callgraph) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
std::vector<std::unique_ptr<Workload>> workloads;
@@ -521,6 +522,7 @@
}
TEST_F(ReportCommandTest, exclude_kernel_callchain) {
+ TEST_REQUIRE_HW_COUNTER();
TEST_REQUIRE_HOST_ROOT();
OMIT_TEST_ON_NON_NATIVE_ABIS();
std::vector<std::unique_ptr<Workload>> workloads;
diff --git a/simpleperf/cmd_stat_test.cpp b/simpleperf/cmd_stat_test.cpp
index 7bb9e37..4a68b00 100644
--- a/simpleperf/cmd_stat_test.cpp
+++ b/simpleperf/cmd_stat_test.cpp
@@ -53,6 +53,7 @@
}
TEST(stat_cmd, rN_event) {
+ TEST_REQUIRE_HW_COUNTER();
OMIT_TEST_ON_NON_NATIVE_ABIS();
size_t event_number;
if (GetBuildArch() == ARCH_ARM64 || GetBuildArch() == ARCH_ARM) {
@@ -72,6 +73,7 @@
}
TEST(stat_cmd, event_modifier) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(
StatCmd()->Run({"-e", "cpu-cycles:u,cpu-cycles:k", "sleep", "1"}));
}
@@ -127,6 +129,7 @@
}
TEST(stat_cmd, group_option) {
+ TEST_REQUIRE_HW_COUNTER();
ASSERT_TRUE(
StatCmd()->Run({"--group", "cpu-clock,page-faults", "sleep", "1"}));
ASSERT_TRUE(StatCmd()->Run({"--group", "cpu-cycles,instructions", "--group",
@@ -135,6 +138,7 @@
}
TEST(stat_cmd, auto_generated_summary) {
+ TEST_REQUIRE_HW_COUNTER();
TemporaryFile tmp_file;
ASSERT_TRUE(StatCmd()->Run({"--group", "instructions:u,instructions:k", "-o",
tmp_file.path, "sleep", "1"}));
@@ -214,6 +218,7 @@
}
TEST(stat_cmd, sample_speed_should_be_zero) {
+ TEST_REQUIRE_HW_COUNTER();
EventSelectionSet set(true);
ASSERT_TRUE(set.AddEventType("cpu-cycles"));
set.AddMonitoredProcesses({getpid()});
@@ -228,6 +233,7 @@
}
TEST(stat_cmd, calculating_cpu_frequency) {
+ TEST_REQUIRE_HW_COUNTER();
CaptureStdout capture;
ASSERT_TRUE(capture.Start());
ASSERT_TRUE(StatCmd()->Run({"--csv", "--group", "task-clock,cpu-cycles", "sleep", "1"}));
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index 223866d..a9c86f4 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -333,7 +333,12 @@
: Dso(DSO_DEX_FILE, path, debug_file_path) {}
void AddDexFileOffset(uint64_t dex_file_offset) override {
- dex_file_offsets_.push_back(dex_file_offset);
+ auto it = std::lower_bound(dex_file_offsets_.begin(), dex_file_offsets_.end(),
+ dex_file_offset);
+ if (it != dex_file_offsets_.end() && *it == dex_file_offset) {
+ return;
+ }
+ dex_file_offsets_.insert(it, dex_file_offset);
}
const std::vector<uint64_t>* DexFileOffsets() override {
diff --git a/simpleperf/dso_test.cpp b/simpleperf/dso_test.cpp
index 75d4c85..a1d005a 100644
--- a/simpleperf/dso_test.cpp
+++ b/simpleperf/dso_test.cpp
@@ -92,6 +92,15 @@
#endif // defined(__linux__)
}
+TEST(dso, dex_file_offsets) {
+ std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_DEX_FILE, "");
+ ASSERT_TRUE(dso);
+ for (uint64_t offset : {0x3, 0x1, 0x5, 0x4, 0x2, 0x4, 0x3}) {
+ dso->AddDexFileOffset(offset);
+ }
+ ASSERT_EQ(*dso->DexFileOffsets(), std::vector<uint64_t>({0x1, 0x2, 0x3, 0x4, 0x5}));
+}
+
TEST(dso, embedded_elf) {
const std::string file_path = GetUrlInApk(GetTestData(APK_FILE), NATIVELIB_IN_APK);
std::unique_ptr<Dso> dso = Dso::CreateDso(DSO_ELF_FILE, file_path);
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index 0a0a72c..092e3ea 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -727,3 +727,16 @@
#endif // defined(__ANDROID__)
return 0;
}
+
+std::string GetHardwareFromCpuInfo(const std::string& cpu_info) {
+ for (auto& line : android::base::Split(cpu_info, "\n")) {
+ size_t pos = line.find(':');
+ if (pos != std::string::npos) {
+ std::string key = android::base::Trim(line.substr(0, pos));
+ if (key == "Hardware") {
+ return android::base::Trim(line.substr(pos + 1));
+ }
+ }
+ }
+ return "";
+}
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index 8d3945f..b8289cc 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -125,4 +125,6 @@
constexpr int kAndroidVersionP = 9;
+std::string GetHardwareFromCpuInfo(const std::string& cpu_info);
+
#endif // SIMPLE_PERF_ENVIRONMENT_H_
diff --git a/simpleperf/environment_test.cpp b/simpleperf/environment_test.cpp
index 5b7c81e..e61108d 100644
--- a/simpleperf/environment_test.cpp
+++ b/simpleperf/environment_test.cpp
@@ -44,3 +44,10 @@
ASSERT_TRUE(dso != nullptr);
ASSERT_NE(dso->GetDebugFilePath(), "[vdso]");
}
+
+TEST(environment, GetHardwareFromCpuInfo) {
+ std::string cpu_info = "CPU revision : 10\n\n"
+ "Hardware : Symbol i.MX6 Freeport_Plat Quad/DualLite (Device Tree)\n";
+ ASSERT_EQ("Symbol i.MX6 Freeport_Plat Quad/DualLite (Device Tree)",
+ GetHardwareFromCpuInfo(cpu_info));
+}
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 1f949c1..afbe03d 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -1286,84 +1286,3 @@
auto header = reinterpret_cast<const perf_event_header*>(p);
return ReadRecordFromBuffer(attr, header->type, p);
}
-
-bool RecordCache::RecordWithSeq::IsHappensBefore(
- const RecordWithSeq& other) const {
- bool is_sample = (record->type() == PERF_RECORD_SAMPLE);
- bool is_other_sample = (other.record->type() == PERF_RECORD_SAMPLE);
- uint64_t time = record->Timestamp();
- uint64_t other_time = other.record->Timestamp();
- // The record with smaller time happens first.
- if (time != other_time) {
- return time < other_time;
- }
- // If happening at the same time, make non-sample records before sample
- // records, because non-sample records may contain useful information to
- // parse sample records.
- if (is_sample != is_other_sample) {
- return is_sample ? false : true;
- }
- // Otherwise, use the same order as they enter the cache.
- return seq < other.seq;
-}
-
-bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
- const RecordWithSeq& r2) {
- return r2.IsHappensBefore(r1);
-}
-
-RecordCache::RecordCache(bool has_timestamp, size_t min_cache_size,
- uint64_t min_time_diff_in_ns)
- : has_timestamp_(has_timestamp),
- min_cache_size_(min_cache_size),
- min_time_diff_in_ns_(min_time_diff_in_ns),
- last_time_(0),
- cur_seq_(0),
- queue_(RecordComparator()) {}
-
-RecordCache::~RecordCache() { PopAll(); }
-
-void RecordCache::Push(std::unique_ptr<Record> record) {
- if (has_timestamp_) {
- last_time_ = std::max(last_time_, record->Timestamp());
- }
- queue_.push(RecordWithSeq(cur_seq_++, record.release()));
-}
-
-void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) {
- for (auto& r : records) {
- Push(std::move(r));
- }
-}
-
-std::unique_ptr<Record> RecordCache::Pop() {
- if (queue_.size() < min_cache_size_) {
- return nullptr;
- }
- Record* r = queue_.top().record;
- if (has_timestamp_) {
- if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) {
- return nullptr;
- }
- }
- queue_.pop();
- return std::unique_ptr<Record>(r);
-}
-
-std::vector<std::unique_ptr<Record>> RecordCache::PopAll() {
- std::vector<std::unique_ptr<Record>> result;
- while (!queue_.empty()) {
- result.emplace_back(queue_.top().record);
- queue_.pop();
- }
- return result;
-}
-
-std::unique_ptr<Record> RecordCache::ForcedPop() {
- if (queue_.empty()) {
- return nullptr;
- }
- Record* r = queue_.top().record;
- queue_.pop();
- return std::unique_ptr<Record>(r);
-}
diff --git a/simpleperf/record.h b/simpleperf/record.h
index 5e9f1aa..1ece4b8 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -573,53 +573,4 @@
// own the buffer.
std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, char* p);
-// RecordCache is a cache used when receiving records from the kernel.
-// It sorts received records based on type and timestamp, and pops records
-// in sorted order. Records from the kernel need to be sorted because
-// records may come from different cpus at the same time, and it is affected
-// by the order in which we collect records from different cpus.
-// RecordCache pushes records and pops sorted record online. It uses two checks
-// to help ensure that records are popped in order. Each time we pop a record A,
-// it is the earliest record among all records in the cache. In addition, we
-// have checks for min_cache_size and min_time_diff. For min_cache_size check,
-// we check if the cache size >= min_cache_size, which is based on the
-// assumption that if we have received (min_cache_size - 1) records after
-// record A, we are not likely to receive a record earlier than A. For
-// min_time_diff check, we check if record A is generated min_time_diff ns
-// earlier than the latest record, which is based on the assumption that if we
-// have received a record for time t, we are not likely to receive a record for
-// time (t - min_time_diff) or earlier.
-class RecordCache {
- public:
- explicit RecordCache(bool has_timestamp, size_t min_cache_size = 1000u,
- uint64_t min_time_diff_in_ns = 1000000u);
- ~RecordCache();
- void Push(std::unique_ptr<Record> record);
- void Push(std::vector<std::unique_ptr<Record>> records);
- std::unique_ptr<Record> Pop();
- std::vector<std::unique_ptr<Record>> PopAll();
- std::unique_ptr<Record> ForcedPop();
-
- private:
- struct RecordWithSeq {
- uint32_t seq;
- Record* record;
-
- RecordWithSeq(uint32_t seq, Record* record) : seq(seq), record(record) {}
- bool IsHappensBefore(const RecordWithSeq& other) const;
- };
-
- struct RecordComparator {
- bool operator()(const RecordWithSeq& r1, const RecordWithSeq& r2);
- };
-
- bool has_timestamp_;
- size_t min_cache_size_;
- uint64_t min_time_diff_in_ns_;
- uint64_t last_time_;
- uint32_t cur_seq_;
- std::priority_queue<RecordWithSeq, std::vector<RecordWithSeq>,
- RecordComparator> queue_;
-};
-
#endif // SIMPLE_PERF_RECORD_H_
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index 4ec6c31..185862a 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -130,13 +130,12 @@
// is by calling ReadRecord() in a loop.
// If sorted is true, sort records before passing them to callback function.
- bool ReadDataSection(const std::function<bool(std::unique_ptr<Record>)>& callback,
- bool sorted = true);
+ bool ReadDataSection(const std::function<bool(std::unique_ptr<Record>)>& callback);
// Read next record. If read successfully, set [record] and return true.
// If there is no more records, set [record] to nullptr and return true.
// Otherwise return false.
- bool ReadRecord(std::unique_ptr<Record>& record, bool sorted = true);
+ bool ReadRecord(std::unique_ptr<Record>& record);
size_t GetAttrIndexOfRecord(const Record* record);
@@ -183,7 +182,6 @@
size_t event_id_pos_in_sample_records_;
size_t event_id_reverse_pos_in_non_sample_records_;
- std::unique_ptr<RecordCache> record_cache_;
uint64_t read_record_size_;
DISALLOW_COPY_AND_ASSIGN(RecordFileReader);
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
index 9b68c65..46b7266 100644
--- a/simpleperf/record_file_reader.cpp
+++ b/simpleperf/record_file_reader.cpp
@@ -206,9 +206,9 @@
}
bool RecordFileReader::ReadDataSection(
- const std::function<bool(std::unique_ptr<Record>)>& callback, bool sorted) {
+ const std::function<bool(std::unique_ptr<Record>)>& callback) {
std::unique_ptr<Record> record;
- while (ReadRecord(record, sorted)) {
+ while (ReadRecord(record)) {
if (record == nullptr) {
return true;
}
@@ -219,24 +219,15 @@
return false;
}
-bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record,
- bool sorted) {
+bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record) {
if (read_record_size_ == 0) {
if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
PLOG(ERROR) << "fseek() failed";
return false;
}
- bool has_timestamp = true;
- for (const auto& attr : file_attrs_) {
- if (!IsTimestampSupported(attr.attr)) {
- has_timestamp = false;
- break;
- }
- }
- record_cache_.reset(new RecordCache(has_timestamp));
}
record = nullptr;
- while (read_record_size_ < header_.data.size && record == nullptr) {
+ if (read_record_size_ < header_.data.size) {
record = ReadRecord(&read_record_size_);
if (record == nullptr) {
return false;
@@ -258,13 +249,6 @@
r->callchain_data.ip_nr = i;
}
}
- if (sorted) {
- record_cache_->Push(std::move(record));
- record = record_cache_->Pop();
- }
- }
- if (record == nullptr) {
- record = record_cache_->ForcedPop();
}
return true;
}
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index 530611e..daa6ea8 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -99,41 +99,6 @@
ASSERT_TRUE(reader->Close());
}
-TEST_F(RecordFileTest, records_sorted_by_time) {
- // Write to a record file.
- std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
- ASSERT_TRUE(writer != nullptr);
-
- // Write attr section.
- AddEventType("cpu-cycles");
- attrs_[0]->sample_id_all = 1;
- attrs_[0]->sample_type |= PERF_SAMPLE_TIME;
- ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
-
- // Write data section.
- MmapRecord r1(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
- attr_ids_[0].ids[0], 2);
- MmapRecord r2(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
- attr_ids_[0].ids[0], 1);
- MmapRecord r3(*(attr_ids_[0].attr), true, 1, 1, 0x100, 0x2000, 0x3000, "mmap_record1",
- attr_ids_[0].ids[0], 3);
- ASSERT_TRUE(writer->WriteRecord(r1));
- ASSERT_TRUE(writer->WriteRecord(r2));
- ASSERT_TRUE(writer->WriteRecord(r3));
- ASSERT_TRUE(writer->Close());
-
- // Read from a record file.
- std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
- ASSERT_TRUE(reader != nullptr);
- std::vector<std::unique_ptr<Record>> records = reader->DataSection();
- ASSERT_EQ(3u, records.size());
- CheckRecordEqual(r2, *records[0]);
- CheckRecordEqual(r1, *records[1]);
- CheckRecordEqual(r3, *records[2]);
-
- ASSERT_TRUE(reader->Close());
-}
-
TEST_F(RecordFileTest, record_more_than_one_attr) {
// Write to a record file.
std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp
index 5430f7b..b2e72b8 100644
--- a/simpleperf/record_test.cpp
+++ b/simpleperf/record_test.cpp
@@ -59,89 +59,6 @@
CheckRecordMatchBinary(record);
}
-TEST_F(RecordTest, RecordCache_smoke) {
- event_attr.sample_id_all = 1;
- event_attr.sample_type |= PERF_SAMPLE_TIME;
- RecordCache cache(true, 2, 2);
-
- // Push r1.
- MmapRecord* r1 = new MmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300,
- "mmap_record1", 0, 3);
- cache.Push(std::unique_ptr<Record>(r1));
- ASSERT_EQ(nullptr, cache.Pop());
-
- // Push r2.
- MmapRecord* r2 = new MmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300,
- "mmap_record1", 0, 1);
- cache.Push(std::unique_ptr<Record>(r2));
- // Pop r2.
- std::unique_ptr<Record> popped_r = cache.Pop();
- ASSERT_TRUE(popped_r != nullptr);
- ASSERT_EQ(r2, popped_r.get());
- ASSERT_EQ(nullptr, cache.Pop());
-
- // Push r3.
- MmapRecord* r3 = new MmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300,
- "mmap_record1", 0, 4);
- cache.Push(std::unique_ptr<Record>(r3));
- ASSERT_EQ(nullptr, cache.Pop());
-
- // Push r4.
- MmapRecord* r4 = new MmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300,
- "mmap_record1", 0, 6);
- cache.Push(std::unique_ptr<Record>(r4));
- // Pop r1.
- popped_r = cache.Pop();
- ASSERT_TRUE(popped_r != nullptr);
- ASSERT_EQ(r1, popped_r.get());
- // Pop r3.
- popped_r = cache.Pop();
- ASSERT_TRUE(popped_r != nullptr);
- ASSERT_EQ(r3, popped_r.get());
- ASSERT_EQ(nullptr, cache.Pop());
- // Pop r4.
- std::vector<std::unique_ptr<Record>> last_records = cache.PopAll();
- ASSERT_EQ(1u, last_records.size());
- ASSERT_EQ(r4, last_records[0].get());
-}
-
-TEST_F(RecordTest, RecordCache_FIFO) {
- event_attr.sample_id_all = 1;
- event_attr.sample_type |= PERF_SAMPLE_TIME;
- RecordCache cache(true, 2, 2);
- std::vector<MmapRecord*> records;
- for (size_t i = 0; i < 10; ++i) {
- records.push_back(new MmapRecord(event_attr, true, 1, i, 0x100, 0x200,
- 0x300, "mmap_record1", 0));
- cache.Push(std::unique_ptr<Record>(records.back()));
- }
- std::vector<std::unique_ptr<Record>> out_records = cache.PopAll();
- ASSERT_EQ(records.size(), out_records.size());
- for (size_t i = 0; i < records.size(); ++i) {
- ASSERT_EQ(records[i], out_records[i].get());
- }
-}
-
-TEST_F(RecordTest, RecordCache_PushRecordVector) {
- event_attr.sample_id_all = 1;
- event_attr.sample_type |= PERF_SAMPLE_TIME;
- RecordCache cache(true, 2, 2);
- MmapRecord* r1 = new MmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300,
- "mmap_record1", 0, 1);
- MmapRecord* r2 = new MmapRecord(event_attr, true, 1, 1, 0x100, 0x200, 0x300,
- "mmap_record1", 0, 3);
- std::vector<std::unique_ptr<Record>> records;
- records.push_back(std::unique_ptr<Record>(r1));
- records.push_back(std::unique_ptr<Record>(r2));
- cache.Push(std::move(records));
- std::unique_ptr<Record> popped_r = cache.Pop();
- ASSERT_TRUE(popped_r != nullptr);
- ASSERT_EQ(r1, popped_r.get());
- std::vector<std::unique_ptr<Record>> last_records = cache.PopAll();
- ASSERT_EQ(1u, last_records.size());
- ASSERT_EQ(r2, last_records[0].get());
-}
-
TEST_F(RecordTest, SampleRecord_exclude_kernel_callchain) {
SampleRecord r(event_attr, 0, 1, 0, 0, 0, 0, 0, {});
ASSERT_EQ(0u, r.ExcludeKernelCallChain());
diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp
index 0b2870c..5607383 100644
--- a/simpleperf/report_lib_interface.cpp
+++ b/simpleperf/report_lib_interface.cpp
@@ -26,6 +26,7 @@
#include "event_type.h"
#include "record_file.h"
#include "thread_tree.h"
+#include "tracing.h"
#include "utils.h"
class ReportLib;
@@ -45,8 +46,23 @@
uint64_t period;
};
+struct TracingFieldFormat {
+ const char* name;
+ uint32_t offset;
+ uint32_t elem_size;
+ uint32_t elem_count;
+ uint32_t is_signed;
+};
+
+struct TracingDataFormat {
+ uint32_t size;
+ uint32_t field_count;
+ TracingFieldFormat* fields;
+};
+
struct Event {
const char* name;
+ TracingDataFormat tracing_data_format;
};
struct Mapping {
@@ -97,14 +113,21 @@
Event* GetEventOfCurrentSample(ReportLib* report_lib) EXPORT;
SymbolEntry* GetSymbolOfCurrentSample(ReportLib* report_lib) EXPORT;
CallChain* GetCallChainOfCurrentSample(ReportLib* report_lib) EXPORT;
+const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) EXPORT;
const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) EXPORT;
FeatureSection* GetFeatureSection(ReportLib* report_lib, const char* feature_name) EXPORT;
}
-struct EventAttrWithName {
+struct EventInfo {
perf_event_attr attr;
std::string name;
+
+ struct TracingInfo {
+ TracingDataFormat data_format;
+ std::vector<std::string> field_names;
+ std::vector<TracingFieldFormat> fields;
+ } tracing_info;
};
class ReportLib {
@@ -136,13 +159,15 @@
Event* GetEventOfCurrentSample() { return ¤t_event_; }
SymbolEntry* GetSymbolOfCurrentSample() { return current_symbol_; }
CallChain* GetCallChainOfCurrentSample() { return ¤t_callchain_; }
+ const char* GetTracingDataOfCurrentSample() { return current_tracing_data_; }
const char* GetBuildIdForPath(const char* path);
FeatureSection* GetFeatureSection(const char* feature_name);
private:
void SetCurrentSample();
- void SetEventOfCurrentSample();
+ const EventInfo* FindEventOfCurrentSample();
+ void CreateEvents();
bool OpenRecordFileIfNecessary();
Mapping* AddMapping(const MapEntry& map);
@@ -157,16 +182,18 @@
Event current_event_;
SymbolEntry* current_symbol_;
CallChain current_callchain_;
+ const char* current_tracing_data_;
std::vector<std::unique_ptr<Mapping>> current_mappings_;
std::vector<CallChainEntry> callchain_entries_;
std::string build_id_string_;
- std::vector<EventAttrWithName> event_attrs_;
+ std::vector<EventInfo> events_;
std::unique_ptr<ScopedEventTypes> scoped_event_types_;
bool trace_offcpu_;
std::unordered_map<pid_t, std::unique_ptr<SampleRecord>> next_sample_cache_;
FeatureSection feature_section_;
std::vector<char> feature_section_data_;
bool show_art_frames_;
+ std::unique_ptr<Tracing> tracing_;
};
bool ReportLib::SetLogSeverity(const char* log_level) {
@@ -241,6 +268,10 @@
}
current_record_.reset(static_cast<SampleRecord*>(record.release()));
break;
+ } else if (record->type() == PERF_RECORD_TRACING_DATA ||
+ record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
+ const auto& r = *static_cast<TracingDataRecord*>(record.get());
+ tracing_.reset(new Tracing(std::vector<char>(r.data, r.data + r.data_size)));
}
}
SetCurrentSample();
@@ -312,18 +343,20 @@
current_symbol_ = &(callchain_entries_[0].symbol);
current_callchain_.nr = callchain_entries_.size() - 1;
current_callchain_.entries = &callchain_entries_[1];
- SetEventOfCurrentSample();
+ const EventInfo* event = FindEventOfCurrentSample();
+ current_event_.name = event->name.c_str();
+ current_event_.tracing_data_format = event->tracing_info.data_format;
+ if (current_event_.tracing_data_format.size > 0u && (r.sample_type & PERF_SAMPLE_RAW)) {
+ CHECK_GE(r.raw_data.size, current_event_.tracing_data_format.size);
+ current_tracing_data_ = r.raw_data.data;
+ } else {
+ current_tracing_data_ = nullptr;
+ }
}
-void ReportLib::SetEventOfCurrentSample() {
- if (event_attrs_.empty()) {
- std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
- for (const auto& attr_with_id : attrs) {
- EventAttrWithName attr;
- attr.attr = *attr_with_id.attr;
- attr.name = GetEventNameByAttr(attr.attr);
- event_attrs_.push_back(attr);
- }
+const EventInfo* ReportLib::FindEventOfCurrentSample() {
+ if (events_.empty()) {
+ CreateEvents();
}
size_t attr_index;
if (trace_offcpu_) {
@@ -332,7 +365,43 @@
} else {
attr_index = record_file_reader_->GetAttrIndexOfRecord(current_record_.get());
}
- current_event_.name = event_attrs_[attr_index].name.c_str();
+ return &events_[attr_index];
+}
+
+void ReportLib::CreateEvents() {
+ std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
+ events_.resize(attrs.size());
+ for (size_t i = 0; i < attrs.size(); ++i) {
+ events_[i].attr = *attrs[i].attr;
+ events_[i].name = GetEventNameByAttr(events_[i].attr);
+ EventInfo::TracingInfo& tracing_info = events_[i].tracing_info;
+ if (events_[i].attr.type == PERF_TYPE_TRACEPOINT && tracing_) {
+ TracingFormat format = tracing_->GetTracingFormatHavingId(events_[i].attr.config);
+ tracing_info.field_names.resize(format.fields.size());
+ tracing_info.fields.resize(format.fields.size());
+ for (size_t i = 0; i < format.fields.size(); ++i) {
+ tracing_info.field_names[i] = format.fields[i].name;
+ TracingFieldFormat& field = tracing_info.fields[i];
+ field.name = tracing_info.field_names[i].c_str();
+ field.offset = format.fields[i].offset;
+ field.elem_size = format.fields[i].elem_size;
+ field.elem_count = format.fields[i].elem_count;
+ field.is_signed = format.fields[i].is_signed;
+ }
+ if (tracing_info.fields.empty()) {
+ tracing_info.data_format.size = 0;
+ } else {
+ TracingFieldFormat& field = tracing_info.fields.back();
+ tracing_info.data_format.size = field.offset + field.elem_size * field.elem_count;
+ }
+ tracing_info.data_format.field_count = tracing_info.fields.size();
+ tracing_info.data_format.fields = &tracing_info.fields[0];
+ } else {
+ tracing_info.data_format.size = 0;
+ tracing_info.data_format.field_count = 0;
+ tracing_info.data_format.fields = nullptr;
+ }
+ }
}
Mapping* ReportLib::AddMapping(const MapEntry& map) {
@@ -420,6 +489,10 @@
return report_lib->GetCallChainOfCurrentSample();
}
+const char* GetTracingDataOfCurrentSample(ReportLib* report_lib) {
+ return report_lib->GetTracingDataOfCurrentSample();
+}
+
const char* GetBuildIdForPath(ReportLib* report_lib, const char* path) {
return report_lib->GetBuildIdForPath(path);
}
diff --git a/simpleperf/scripts/annotate.py b/simpleperf/scripts/annotate.py
index 066e14e..30cfce1 100644
--- a/simpleperf/scripts/annotate.py
+++ b/simpleperf/scripts/annotate.py
@@ -24,14 +24,15 @@
import os.path
import shutil
import subprocess
-import sys
-from simpleperf_report_lib import *
-from utils import *
+from simpleperf_report_lib import ReportLib
+from utils import log_info, log_warning, log_exit, log_fatal
+from utils import bytes_to_str, extant_dir, find_tool_path, flatten_arg_list, is_windows
+from utils import ReadElf, str_to_bytes
class SourceLine(object):
- def __init__(self, file, function, line):
- self.file = file
+ def __init__(self, file_id, function, line):
+ self.file = file_id
self.function = function
self.line = line
@@ -56,31 +57,30 @@
"""collect information of how to map [dso_name,vaddr] to [source_file:line].
"""
def __init__(self, ndk_path, symfs_dir=None):
- self.dso_dict = dict()
+ self.dso_dict = {}
self.addr2line_path = find_tool_path('addr2line', ndk_path)
if self.addr2line_path is None:
log_exit("Can't find addr2line. Please set ndk path with --ndk-path option.")
self.readelf = ReadElf(ndk_path)
self.symfs_dir = symfs_dir
+ # store a list of source files
+ self.file_list = []
+ # map from file to id with file_list[id] == file
+ self.file_dict = {}
def add_addr(self, dso_name, addr):
dso = self.dso_dict.get(dso_name)
if dso is None:
- self.dso_dict[dso_name] = dso = dict()
+ self.dso_dict[dso_name] = dso = {}
if addr not in dso:
dso[addr] = None
-
def convert_addrs_to_lines(self):
- # store a list of source files
- self.file_list = []
- # map from file to id with file_list[id] == file
- self.file_dict = {}
self.file_list.append('')
self.file_dict[''] = 0
- for dso_name in self.dso_dict.keys():
+ for dso_name in self.dso_dict:
self._convert_addrs_to_lines(dso_name, self.dso_dict[dso_name])
self._combine_source_files()
@@ -121,30 +121,30 @@
items = stdoutdata[out_pos].rsplit(':', 1)
if len(items) != 2:
continue
- (file, line) = items
+ (file_path, line) = items
line = line.split()[0] # Remove comments after line number
out_pos += 1
- if '?' in file:
- file = 0
+ if '?' in file_path:
+ file_id = 0
else:
- file = self._get_file_id(file)
+ file_id = self._get_file_id(file_path)
if '?' in line:
line = 0
else:
line = int(line)
- source_lines.append(SourceLine(file, function, line))
+ source_lines.append(SourceLine(file_id, function, line))
dso[addrs[addr_pos]] = source_lines
addr_pos += 1
assert addr_pos == len(addrs)
- def _get_file_id(self, file):
- id = self.file_dict.get(file)
- if id is None:
- id = len(self.file_list)
- self.file_list.append(file)
- self.file_dict[file] = id
- return id
+ def _get_file_id(self, file_path):
+ file_id = self.file_dict.get(file_path)
+ if file_id is None:
+ file_id = len(self.file_list)
+ self.file_list.append(file_path)
+ self.file_dict[file_path] = file_id
+ return file_id
def _combine_source_files(self):
"""It is possible that addr2line gives us different names for the same
@@ -155,29 +155,29 @@
source files with no conflicts in path.
"""
# Collect files having the same filename.
- filename_dict = dict()
- for file in self.file_list:
- index = max(file.rfind('/'), file.rfind(os.sep))
- filename = file[index+1:]
+ filename_dict = {}
+ for file_path in self.file_list:
+ index = max(file_path.rfind('/'), file_path.rfind(os.sep))
+ filename = file_path[index+1:]
entry = filename_dict.get(filename)
if entry is None:
filename_dict[filename] = entry = []
- entry.append(file)
+ entry.append(file_path)
# Combine files having the same filename and having no conflicts in path.
- for filename in filename_dict.keys():
+ for filename in filename_dict:
files = filename_dict[filename]
if len(files) == 1:
continue
- for file in files:
- to_file = file
+ for file_path in files:
+ to_file = file_path
# Test if we can merge files[i] with another file having longer
# path.
for f in files:
- if len(f) > len(to_file) and f.find(file) != -1:
+ if len(f) > len(to_file) and f.find(file_path) != -1:
to_file = f
- if to_file != file:
- from_id = self.file_dict[file]
+ if to_file != file_path:
+ from_id = self.file_dict[file_path]
to_id = self.file_dict[to_file]
self.file_list[from_id] = self.file_list[to_id]
@@ -239,8 +239,8 @@
class FilePeriod(object):
"""Period for each source file"""
- def __init__(self, file):
- self.file = file
+ def __init__(self, file_id):
+ self.file = file_id
self.period = Period()
# Period for each line in the file.
self.line_dict = {}
@@ -283,12 +283,6 @@
kallsyms = 'binary_cache/kallsyms'
if not os.path.isfile(kallsyms):
kallsyms = None
- source_dirs = config['source_dirs']
- for dir in source_dirs:
- if not os.path.isdir(dir):
- log_exit('[source_dirs] "%s" is not a dir' % dir)
- if not config['source_dirs']:
- log_exit('Please set source directories.')
# init member variables
self.config = config
@@ -312,6 +306,10 @@
os.makedirs(output_dir)
self.addr2line = Addr2Line(self.config['ndk_path'], symfs_dir)
+ self.period = 0
+ self.dso_periods = {}
+ self.file_periods = {}
+ self.source_file_dict = {}
def annotate(self):
@@ -380,9 +378,6 @@
"""read perf.data, collect Period for all types:
binaries, source files, functions, lines.
"""
- self.period = 0
- self.dso_periods = dict()
- self.file_periods = dict()
for perf_data in self.config['perf_data_list']:
lib = ReportLib()
lib.SetRecordFile(perf_data)
@@ -397,49 +392,52 @@
break
if not self._filter_sample(sample):
continue
- symbols = []
- symbols.append(lib.GetSymbolOfCurrentSample())
- callchain = lib.GetCallChainOfCurrentSample()
- for i in range(callchain.nr):
- symbols.append(callchain.entries[i].symbol)
- # Each sample has a callchain, but its period is only used once
- # to add period for each function/source_line/source_file/binary.
- # For example, if more than one entry in the callchain hits a
- # function, the event count of that function is only increased once.
- # Otherwise, we may get periods > 100%.
- is_sample_used = False
- used_dso_dict = dict()
- used_file_dict = dict()
- used_function_dict = dict()
- used_line_dict = dict()
- period = Period(sample.period, sample.period)
- for i in range(len(symbols)):
- symbol = symbols[i]
- if i == 1:
- period = Period(0, sample.period)
- if not self._filter_symbol(symbol):
- continue
- is_sample_used = True
- # Add period to dso.
- self._add_dso_period(symbol.dso_name, period, used_dso_dict)
- # Add period to source file.
- sources = self.addr2line.get_sources(symbol.dso_name, symbol.vaddr_in_file)
- for source in sources:
- if source.file:
- self._add_file_period(source, period, used_file_dict)
- # Add period to line.
- if source.line:
- self._add_line_period(source, period, used_line_dict)
- # Add period to function.
- sources = self.addr2line.get_sources(symbol.dso_name, symbol.symbol_addr)
- for source in sources:
- if source.file:
- self._add_file_period(source, period, used_file_dict)
- if source.function:
- self._add_function_period(source, period, used_function_dict)
+ self._generate_periods_for_sample(lib, sample)
- if is_sample_used:
- self.period += sample.period
+
+ def _generate_periods_for_sample(self, lib, sample):
+ symbols = []
+ symbols.append(lib.GetSymbolOfCurrentSample())
+ callchain = lib.GetCallChainOfCurrentSample()
+ for i in range(callchain.nr):
+ symbols.append(callchain.entries[i].symbol)
+ # Each sample has a callchain, but its period is only used once
+ # to add period for each function/source_line/source_file/binary.
+ # For example, if more than one entry in the callchain hits a
+ # function, the event count of that function is only increased once.
+ # Otherwise, we may get periods > 100%.
+ is_sample_used = False
+ used_dso_dict = {}
+ used_file_dict = {}
+ used_function_dict = {}
+ used_line_dict = {}
+ period = Period(sample.period, sample.period)
+ for j, symbol in enumerate(symbols):
+ if j == 1:
+ period = Period(0, sample.period)
+ if not self._filter_symbol(symbol):
+ continue
+ is_sample_used = True
+ # Add period to dso.
+ self._add_dso_period(symbol.dso_name, period, used_dso_dict)
+ # Add period to source file.
+ sources = self.addr2line.get_sources(symbol.dso_name, symbol.vaddr_in_file)
+ for source in sources:
+ if source.file:
+ self._add_file_period(source, period, used_file_dict)
+ # Add period to line.
+ if source.line:
+ self._add_line_period(source, period, used_line_dict)
+ # Add period to function.
+ sources = self.addr2line.get_sources(symbol.dso_name, symbol.symbol_addr)
+ for source in sources:
+ if source.file:
+ self._add_file_period(source, period, used_file_dict)
+ if source.function:
+ self._add_function_period(source, period, used_function_dict)
+
+ if is_sample_used:
+ self.period += sample.period
def _add_dso_period(self, dso_name, period, used_dso_dict):
@@ -521,20 +519,19 @@
def _collect_source_files(self):
- self.source_file_dict = dict()
source_file_suffix = ['h', 'c', 'cpp', 'cc', 'java', 'kt']
for source_dir in self.config['source_dirs']:
for root, _, files in os.walk(source_dir):
- for file in files:
- if file[file.rfind('.')+1:] in source_file_suffix:
- entry = self.source_file_dict.get(file)
+ for filename in files:
+ if filename[filename.rfind('.')+1:] in source_file_suffix:
+ entry = self.source_file_dict.get(filename)
if entry is None:
- entry = self.source_file_dict[file] = []
- entry.append(os.path.join(root, file))
+ entry = self.source_file_dict[filename] = []
+ entry.append(os.path.join(root, filename))
- def _find_source_file(self, file):
- filename = file[file.rfind(os.sep)+1:]
+ def _find_source_file(self, file_path):
+ filename = file_path[file_path.rfind(os.sep)+1:]
source_files = self.source_file_dict.get(filename)
if source_files is None:
return None
@@ -542,7 +539,7 @@
best_path = None
best_suffix_len = 0
for path in source_files:
- suffix_len = len(os.path.commonprefix((path[::-1], file[::-1])))
+ suffix_len = len(os.path.commonprefix((path[::-1], file_path[::-1])))
if suffix_len > best_suffix_len:
best_suffix_len = suffix_len
best_path = path
@@ -550,7 +547,7 @@
elif suffix_len == best_suffix_len:
best_path_count += 1
if best_path_count > 1:
- log_warning('multiple source for %s, select %s' % (file, best_path))
+ log_warning('multiple source for %s, select %s' % (file_path, best_path))
return best_path
@@ -560,7 +557,7 @@
2. Annotate c++ source files.
"""
dest_dir = self.config['annotate_dest_dir']
- for key in self.file_periods.keys():
+ for key in self.file_periods:
is_java = False
if key.startswith('$JAVA_SRC_ROOT/'):
path = key[len('$JAVA_SRC_ROOT/'):]
@@ -601,7 +598,7 @@
with open(from_path, 'r') as rf:
lines = rf.readlines()
- annotates = dict()
+ annotates = {}
for line in file_period.line_dict.keys():
annotates[line] = self._get_percentage_str(file_period.line_dict[line], True)
for func_name in file_period.function_dict.keys():
@@ -613,7 +610,7 @@
annotates[1] = '[file] ' + self._get_percentage_str(file_period.period, True)
max_annotate_cols = 0
- for key in annotates.keys():
+ for key in annotates:
max_annotate_cols = max(max_annotate_cols, len(annotates[key]))
empty_annotate = ' ' * (max_annotate_cols + 6)
@@ -636,22 +633,22 @@
wf.write(lines[line-1])
def main():
- parser = argparse.ArgumentParser(description=
-"""Annotate source files based on profiling data. It reads line information from
-binary_cache generated by app_profiler.py or binary_cache_builder.py, and
-generate annotated source files in annotated_files directory.""")
- parser.add_argument('-i', '--perf_data_list', nargs='+', action='append', help=
-"""The paths of profiling data. Default is perf.data.""")
- parser.add_argument('-s', '--source_dirs', nargs='+', action='append', help=
-"""Directories to find source files.""")
- parser.add_argument('--comm', nargs='+', action='append', help=
-"""Use samples only in threads with selected names.""")
- parser.add_argument('--pid', nargs='+', action='append', help=
-"""Use samples only in processes with selected process ids.""")
- parser.add_argument('--tid', nargs='+', action='append', help=
-"""Use samples only in threads with selected thread ids.""")
- parser.add_argument('--dso', nargs='+', action='append', help=
-"""Use samples only in selected binaries.""")
+ parser = argparse.ArgumentParser(description="""
+ Annotate source files based on profiling data. It reads line information from binary_cache
+ generated by app_profiler.py or binary_cache_builder.py, and generate annotated source
+ files in annotated_files directory.""")
+ parser.add_argument('-i', '--perf_data_list', nargs='+', action='append', help="""
+ The paths of profiling data. Default is perf.data.""")
+ parser.add_argument('-s', '--source_dirs', type=extant_dir, nargs='+', action='append', help="""
+ Directories to find source files.""")
+ parser.add_argument('--comm', nargs='+', action='append', help="""
+ Use samples only in threads with selected names.""")
+ parser.add_argument('--pid', nargs='+', action='append', help="""
+ Use samples only in processes with selected process ids.""")
+ parser.add_argument('--tid', nargs='+', action='append', help="""
+ Use samples only in threads with selected thread ids.""")
+ parser.add_argument('--dso', nargs='+', action='append', help="""
+ Use samples only in selected binaries.""")
parser.add_argument('--ndk_path', type=extant_dir, help='Set the path of a ndk release.')
args = parser.parse_args()
diff --git a/simpleperf/scripts/bin/android/arm/simpleperf b/simpleperf/scripts/bin/android/arm/simpleperf
index b41318b..09b6f85 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 4df1f31..041eb61 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 2c6edab..ea9cd09 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 bd24729..6b7c664 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 bf28205..2707d8a 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 f0cdf21..bf0549c 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 8625e0d..24c56cf 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 1dad615..67e857e 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 ebf36b3..d026e10 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 3ce5fed..d273fbc 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 db141fb..73b19aa 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 1f532c9..d972713 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 7cf8ec9..c4cd5b7 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/simpleperf.exe b/simpleperf/scripts/bin/windows/x86/simpleperf.exe
index 9e1d378..4a6ce41 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 23b289a..628e71d 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/simpleperf.exe b/simpleperf/scripts/bin/windows/x86_64/simpleperf.exe
index 9e1d378..4a6ce41 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 deb312a..b5a53da 100644
--- a/simpleperf/scripts/binary_cache_builder.py
+++ b/simpleperf/scripts/binary_cache_builder.py
@@ -23,14 +23,10 @@
import argparse
import os
import os.path
-import re
import shutil
-import subprocess
-import sys
-import time
-from simpleperf_report_lib import *
-from utils import *
+from simpleperf_report_lib import ReportLib
+from utils import AdbHelper, flatten_arg_list, log_info, log_warning, log_exit, ReadElf
class BinaryCacheBuilder(object):
@@ -53,6 +49,7 @@
self.binary_cache_dir = 'binary_cache'
if not os.path.isdir(self.binary_cache_dir):
os.makedirs(self.binary_cache_dir)
+ self.binaries = {}
def build_binary_cache(self):
@@ -65,7 +62,7 @@
def _collect_used_binaries(self):
"""read perf.data, collect all used binaries and their build id (if available)."""
# A dict mapping from binary name to build_id
- binaries = dict()
+ binaries = {}
lib = ReportLib()
lib.SetRecordFile(self.perf_data_path)
lib.SetLogSeverity('error')
@@ -99,7 +96,7 @@
# and same build_id.
# Map from filename to binary paths.
- filename_dict = dict()
+ filename_dict = {}
for binary in self.binaries:
index = binary.rfind('/')
filename = binary[index+1:]
@@ -111,17 +108,19 @@
# Walk through all files in symfs_dirs, and copy matching files to build_cache.
for symfs_dir in self.symfs_dirs:
for root, _, files in os.walk(symfs_dir):
- for file in files:
- paths = filename_dict.get(file)
- if paths is not None:
- build_id = self._read_build_id(os.path.join(root, file))
- if not build_id:
- continue
- for binary in paths:
- expected_build_id = self.binaries.get(binary)
- if expected_build_id == build_id:
- self._copy_to_binary_cache(os.path.join(root, file),
- expected_build_id, binary)
+ for filename in files:
+ paths = filename_dict.get(filename)
+ if not paths:
+ continue
+ build_id = self._read_build_id(os.path.join(root, filename))
+ if not build_id:
+ continue
+ for binary in paths:
+ expected_build_id = self.binaries.get(binary)
+ if expected_build_id == build_id:
+ self._copy_to_binary_cache(os.path.join(root, filename),
+ expected_build_id, binary)
+ break
def _copy_to_binary_cache(self, from_path, expected_build_id, target_file):
@@ -129,10 +128,8 @@
target_file = target_file[1:]
target_file = target_file.replace('/', os.sep)
target_file = os.path.join(self.binary_cache_dir, target_file)
- if (os.path.isfile(target_file) and self._read_build_id(target_file) == expected_build_id
- and self._file_has_symbol_table(target_file)):
- # The existing file in binary_cache can provide more information, so no
- # need to copy.
+ if not self._need_to_copy(target_file, expected_build_id):
+ # The existing file in binary_cache can provide more information, so no need to copy.
return
target_dir = os.path.dirname(target_file)
if not os.path.isdir(target_dir):
@@ -141,6 +138,16 @@
shutil.copy(from_path, target_file)
+ def _need_to_copy(self, target_file, expected_build_id):
+ if not os.path.isfile(target_file):
+ return True
+ if self._read_build_id(target_file) != expected_build_id:
+ return True
+ if not self._file_has_symbol_table(target_file):
+ return True
+ return False
+
+
def _pull_binaries_from_device(self):
"""pull binaries needed in perf.data to binary_cache."""
for binary in self.binaries:
@@ -176,14 +183,14 @@
log_info('use current file in binary_cache: %s' % binary_cache_file)
- def _read_build_id(self, file):
+ def _read_build_id(self, file_path):
"""read build id of a binary on host."""
- return self.readelf.get_build_id(file)
+ return self.readelf.get_build_id(file_path)
- def _file_has_symbol_table(self, file):
+ def _file_has_symbol_table(self, file_path):
"""Test if an elf file has symbol table section."""
- return '.symtab' in self.readelf.get_sections(file)
+ return '.symtab' in self.readelf.get_sections(file_path)
def _pull_file_from_device(self, device_path, host_path):
@@ -193,7 +200,7 @@
# Instead, we can first copy the file to /data/local/tmp, then pull it.
filename = device_path[device_path.rfind('/')+1:]
if (self.adb.run(['shell', 'cp', device_path, '/data/local/tmp']) and
- self.adb.run(['pull', '/data/local/tmp/' + filename, host_path])):
+ self.adb.run(['pull', '/data/local/tmp/' + filename, host_path])):
self.adb.run(['shell', 'rm', '/data/local/tmp/' + filename])
return True
log_warning('failed to pull %s from device' % device_path)
@@ -201,24 +208,23 @@
def _pull_kernel_symbols(self):
- file = os.path.join(self.binary_cache_dir, 'kallsyms')
- if os.path.isfile(file):
- os.remove(file)
+ file_path = os.path.join(self.binary_cache_dir, 'kallsyms')
+ if os.path.isfile(file_path):
+ os.remove(file_path)
if self.adb.switch_to_root():
self.adb.run(['shell', '"echo 0 >/proc/sys/kernel/kptr_restrict"'])
- self.adb.run(['pull', '/proc/kallsyms', file])
+ self.adb.run(['pull', '/proc/kallsyms', file_path])
def main():
- parser = argparse.ArgumentParser(description=
-"""Pull binaries needed by perf.data from device to binary_cache directory.""")
- parser.add_argument('-i', '--perf_data_path', default='perf.data', help=
-"""The path of profiling data.""")
- parser.add_argument('-lib', '--native_lib_dir', nargs='+', help=
-"""Path to find debug version of native shared libraries used in the app.""",
- action='append')
- parser.add_argument('--disable_adb_root', action='store_true', help=
-"""Force adb to run in non root mode.""")
+ parser = argparse.ArgumentParser(description="""
+ Pull binaries needed by perf.data from device to binary_cache directory.""")
+ parser.add_argument('-i', '--perf_data_path', default='perf.data', help="""
+ The path of profiling data.""")
+ parser.add_argument('-lib', '--native_lib_dir', nargs='+', help="""
+ Path to find debug version of native shared libraries used in the app.""", action='append')
+ parser.add_argument('--disable_adb_root', action='store_true', help="""
+ Force adb to run in non root mode.""")
parser.add_argument('--ndk_path', nargs=1, help='Find tools in the ndk path.')
args = parser.parse_args()
config = {}
@@ -232,4 +238,4 @@
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
diff --git a/simpleperf/scripts/debug_unwind_reporter.py b/simpleperf/scripts/debug_unwind_reporter.py
index 56b5176..83faa6c 100644
--- a/simpleperf/scripts/debug_unwind_reporter.py
+++ b/simpleperf/scripts/debug_unwind_reporter.py
@@ -44,7 +44,8 @@
import re
import subprocess
-from utils import *
+from utils import log_exit, log_fatal
+from utils import get_host_binary_path
class MapEntry(object):
@@ -122,7 +123,7 @@
class UnwindingMemConsumption(object):
- def __init___(self):
+ def __init__(self):
self.before_unwinding = None
self.after_unwinding = None
@@ -341,13 +342,14 @@
elif items[0] == 'callchain:':
in_callchain = True
elif in_callchain:
- # "dalvik-jit-code-cache (deleted)[+346c] (/dev/ashmem/dalvik-jit-code-cache (deleted)[+346c])"
+ # "dalvik-jit-code-cache (deleted)[+346c] (/dev/ashmem/dalvik-jit-code-cache
+ # (deleted)[+346c])"
if re.search(r'\)\[\+\w+\]\)$', line):
break_pos = line.rfind('(', 0, line.rfind('('))
else:
break_pos = line.rfind('(')
if break_pos > 0:
- m = re.match('(.+)\[\+(\w+)\]\)', line[break_pos + 1:])
+ m = re.match(r'(.+)\[\+(\w+)\]\)', line[break_pos + 1:])
if m:
function_names.append(line[:break_pos].strip())
filenames.append(m.group(1))
diff --git a/simpleperf/scripts/inferno/data_types.py b/simpleperf/scripts/inferno/data_types.py
index 17af700..deb9f51 100644
--- a/simpleperf/scripts/inferno/data_types.py
+++ b/simpleperf/scripts/inferno/data_types.py
@@ -15,14 +15,14 @@
#
-class CallSite:
+class CallSite(object):
def __init__(self, method, dso):
self.method = method
self.dso = dso
-class Thread:
+class Thread(object):
def __init__(self, tid, pid):
self.tid = tid
@@ -48,7 +48,7 @@
self.flamegraph.add_callchain(chain, sample.period)
-class Process:
+class Process(object):
def __init__(self, name, pid):
self.name = name
@@ -77,7 +77,7 @@
self.num_events += sample.period
-class FlameGraphCallSite:
+class FlameGraphCallSite(object):
callsite_counter = 0
@classmethod
@@ -85,7 +85,7 @@
cls.callsite_counter += 1
return cls.callsite_counter
- def __init__(self, method, dso, id):
+ def __init__(self, method, dso, callsite_id):
# map from (dso, method) to FlameGraphCallSite. Used to speed up add_callchain().
self.child_dict = {}
self.children = []
@@ -93,7 +93,7 @@
self.dso = dso
self.num_events = 0
self.offset = 0 # Offset allows position nodes in different branches.
- self.id = id
+ self.id = callsite_id
def weight(self):
return float(self.num_events)
@@ -102,15 +102,15 @@
self.num_events += num_events
current = self
for callsite in chain:
- current = current._get_child(callsite)
+ current = current.get_child(callsite)
current.num_events += num_events
- def _get_child(self, callsite):
+ def get_child(self, callsite):
key = (callsite.dso, callsite.method)
child = self.child_dict.get(key)
if child is None:
child = self.child_dict[key] = FlameGraphCallSite(callsite.method, callsite.dso,
- self._get_next_callsite_id())
+ self._get_next_callsite_id())
return child
def trim_callchain(self, min_num_events):
diff --git a/simpleperf/scripts/inferno/inferno.py b/simpleperf/scripts/inferno/inferno.py
index e0035d8..517b742 100644
--- a/simpleperf/scripts/inferno/inferno.py
+++ b/simpleperf/scripts/inferno/inferno.py
@@ -35,18 +35,19 @@
import subprocess
import sys
-scripts_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-sys.path.append(scripts_path)
+# pylint: disable=wrong-import-position
+SCRIPTS_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+sys.path.append(SCRIPTS_PATH)
from simpleperf_report_lib import ReportLib
from utils import log_exit, log_info, AdbHelper, open_report_in_browser
-from data_types import *
-from svg_renderer import *
+from data_types import Process
+from svg_renderer import get_proper_scaled_time_string, render_svg
def collect_data(args):
""" Run app_profiler.py to generate record file. """
- app_profiler_args = [sys.executable, os.path.join(scripts_path, "app_profiler.py"), "-nb"]
+ app_profiler_args = [sys.executable, os.path.join(SCRIPTS_PATH, "app_profiler.py"), "-nb"]
if args.app:
app_profiler_args += ["-p", args.app]
elif args.native_program:
@@ -106,10 +107,10 @@
process.cmd = lib.GetRecordCmd()
product_props = lib.MetaInfo().get("product_props")
if product_props:
- tuple = product_props.split(':')
- process.props['ro.product.manufacturer'] = tuple[0]
- process.props['ro.product.model'] = tuple[1]
- process.props['ro.product.name'] = tuple[2]
+ manufacturer, model, name = product_props.split(':')
+ process.props['ro.product.manufacturer'] = manufacturer
+ process.props['ro.product.model'] = model
+ process.props['ro.product.name'] = name
if lib.MetaInfo().get('trace_offcpu') == 'true':
process.props['trace_offcpu'] = True
if args.one_flamegraph:
@@ -163,7 +164,7 @@
if not args.embedded_flamegraph:
f.write("<html><body>")
f.write("<div id='flamegraph_id' style='font-family: Monospace; %s'>" % (
- "display: none;" if args.embedded_flamegraph else ""))
+ "display: none;" if args.embedded_flamegraph else ""))
f.write("""<style type="text/css"> .s { stroke:black; stroke-width:0.5; cursor:pointer;}
</style>""")
f.write('<style type="text/css"> .t:hover { cursor:pointer; } </style>')
@@ -177,7 +178,7 @@
event_entry = 'Event count: %s<br/>' % ("{:,}".format(process.num_events))
# TODO: collect capture duration info from perf.data.
duration_entry = ("Duration: %s seconds<br/>" % args.capture_duration
- ) if args.capture_duration else ""
+ ) if args.capture_duration else ""
f.write("""<div style='display:inline-block;'>
<font size='8'>
Inferno Flamegraph Report%s</font><br/><br/>
@@ -186,14 +187,13 @@
Threads : %d <br/>
Samples : %d<br/>
%s
- %s""" % (
- (': ' + args.title) if args.title else '',
- process_entry,
- datetime.datetime.now().strftime("%Y-%m-%d (%A) %H:%M:%S"),
- len(process.threads),
- process.num_samples,
- event_entry,
- duration_entry))
+ %s""" % ((': ' + args.title) if args.title else '',
+ process_entry,
+ datetime.datetime.now().strftime("%Y-%m-%d (%A) %H:%M:%S"),
+ len(process.threads),
+ process.num_samples,
+ event_entry,
+ duration_entry))
if 'ro.product.model' in process.props:
f.write(
"Machine : %s (%s) by %s<br/>" %
@@ -212,8 +212,8 @@
# Sort threads by the event count in a thread.
for thread in sorted(process.threads.values(), key=lambda x: x.num_events, reverse=True):
f.write("<br/><br/><b>Thread %d (%s) (%d samples):</b><br/>\n\n\n\n" % (
- thread.tid, thread.name, thread.num_samples))
- renderSVG(process, thread.flamegraph, f, args.color)
+ thread.tid, thread.name, thread.num_samples))
+ render_svg(process, thread.flamegraph, f, args.color)
f.write("</div>")
if not args.embedded_flamegraph:
@@ -224,7 +224,7 @@
def generate_threads_offsets(process):
for thread in process.threads.values():
- thread.flamegraph.generate_offset(0)
+ thread.flamegraph.generate_offset(0)
def collect_machine_info(process):
@@ -305,7 +305,7 @@
if result:
try:
process.pid = int(output)
- except:
+ except ValueError:
process.pid = 0
collect_machine_info(process)
else:
@@ -313,7 +313,7 @@
sample_filter_fn = None
if args.one_flamegraph:
- def filter_fn(sample, symbol, callchain):
+ def filter_fn(sample, _symbol, _callchain):
sample.pid = sample.tid = process.pid
return True
sample_filter_fn = filter_fn
diff --git a/simpleperf/scripts/inferno/svg_renderer.py b/simpleperf/scripts/inferno/svg_renderer.py
index fd0096d..0627bc6 100644
--- a/simpleperf/scripts/inferno/svg_renderer.py
+++ b/simpleperf/scripts/inferno/svg_renderer.py
@@ -34,21 +34,21 @@
return hash(string) / float(sys.maxsize)
-def getLegacyColor(method):
+def get_legacy_color(method):
r = 175 + int(50 * hash_to_float(reversed(method)))
g = 60 + int(180 * hash_to_float(method))
b = 60 + int(55 * hash_to_float(reversed(method)))
return (r, g, b)
-def getDSOColor(method):
+def get_dso_color(method):
r = 170 + int(80 * hash_to_float(reversed(method)))
g = 180 + int(70 * hash_to_float((method)))
b = 170 + int(80 * hash_to_float(reversed(method)))
return (r, g, b)
-def getHeatColor(callsite, total_weight):
+def get_heat_color(callsite, total_weight):
r = 245 + 10 * (1 - callsite.weight() / total_weight)
g = 110 + 105 * (1 - callsite.weight() / total_weight)
b = 100
@@ -63,7 +63,7 @@
return '%.3f us' % (value / 1e3)
return '%.0f ns' % value
-def createSVGNode(process, callsite, depth, f, total_weight, height, color_scheme, nav):
+def create_svg_node(process, callsite, depth, f, total_weight, height, color_scheme, nav):
x = float(callsite.offset) / total_weight * 100
y = height - (depth + 1) * SVG_NODE_HEIGHT
width = callsite.weight() / total_weight * 100
@@ -73,11 +73,11 @@
return
if color_scheme == "dso":
- r, g, b = getDSOColor(callsite.dso)
+ r, g, b = get_dso_color(callsite.dso)
elif color_scheme == "legacy":
- r, g, b = getLegacyColor(method)
+ r, g, b = get_legacy_color(method)
else:
- r, g, b = getHeatColor(callsite, total_weight)
+ r, g, b = get_heat_color(callsite, total_weight)
r_border, g_border, b_border = [max(0, color - 50) for color in [r, g, b]]
@@ -119,7 +119,7 @@
FONT_SIZE))
-def renderSVGNodes(process, flamegraph, depth, f, total_weight, height, color_scheme):
+def render_svg_nodes(process, flamegraph, depth, f, total_weight, height, color_scheme):
for i, child in enumerate(flamegraph.children):
# Prebuild navigation target for wasd
@@ -138,12 +138,12 @@
# up, left, down, right
nav = [up_index, left_index, flamegraph.id, right_index]
- createSVGNode(process, child, depth, f, total_weight, height, color_scheme, nav)
+ create_svg_node(process, child, depth, f, total_weight, height, color_scheme, nav)
# Recurse down
- renderSVGNodes(process, child, depth + 1, f, total_weight, height, color_scheme)
+ render_svg_nodes(process, child, depth + 1, f, total_weight, height, color_scheme)
-def renderSearchNode(f):
+def render_search_node(f):
f.write(
"""<rect id="search_rect" style="stroke:rgb(0,0,0);" onclick="search(this);" class="t"
rx="10" ry="10" x="%d" y="10" width="%d" height="30" fill="rgb(255,255,255)""/>
@@ -151,7 +151,7 @@
""" % (SEARCH_NODE_ORIGIN_X, SEARCH_NODE_WIDTH, SEARCH_NODE_ORIGIN_X + RECT_TEXT_PADDING))
-def renderUnzoomNode(f):
+def render_unzoom_node(f):
f.write(
"""<rect id="zoom_rect" style="display:none;stroke:rgb(0,0,0);" class="t"
onclick="unzoom(this);" rx="10" ry="10" x="%d" y="10" width="%d" height="30"
@@ -161,7 +161,7 @@
""" % (UNZOOM_NODE_ORIGIN_X, UNZOOM_NODE_WIDTH, UNZOOM_NODE_ORIGIN_X + RECT_TEXT_PADDING))
-def renderInfoNode(f):
+def render_info_node(f):
f.write(
"""<clipPath id="info_clip_path"> <rect id="info_rect" style="stroke:rgb(0,0,0);"
rx="10" ry="10" x="%d" y="10" width="%d" height="30" fill="rgb(255,255,255)"/>
@@ -173,7 +173,7 @@
INFO_NODE_ORIGIN_X + RECT_TEXT_PADDING))
-def renderPercentNode(f):
+def render_percent_node(f):
f.write(
"""<rect id="percent_rect" style="stroke:rgb(0,0,0);"
rx="10" ry="10" x="%d" y="10" width="%d" height="30" fill="rgb(255,255,255)"/>
@@ -182,7 +182,7 @@
PERCENT_NODE_ORIGIN_X + PERCENT_NODE_WIDTH - RECT_TEXT_PADDING))
-def renderSVG(process, flamegraph, f, color_scheme):
+def render_svg(process, flamegraph, f, color_scheme):
height = (flamegraph.get_max_depth() + 2) * SVG_NODE_HEIGHT
f.write("""<div class="flamegraph_block" style="width:100%%; height:%dpx;">
""" % height)
@@ -196,9 +196,9 @@
</linearGradient> </defs>""")
f.write("""<rect x="0.0" y="0" width="100%" height="100%" fill="url(#background_gradiant)" />
""")
- renderSVGNodes(process, flamegraph, 0, f, flamegraph.weight(), height, color_scheme)
- renderSearchNode(f)
- renderUnzoomNode(f)
- renderInfoNode(f)
- renderPercentNode(f)
+ render_svg_nodes(process, flamegraph, 0, f, flamegraph.weight(), height, color_scheme)
+ render_search_node(f)
+ render_unzoom_node(f)
+ render_info_node(f)
+ render_percent_node(f)
f.write("</svg></div><br/>\n\n")
diff --git a/simpleperf/scripts/pprof_proto_generator.py b/simpleperf/scripts/pprof_proto_generator.py
index fcca090..19f5257 100644
--- a/simpleperf/scripts/pprof_proto_generator.py
+++ b/simpleperf/scripts/pprof_proto_generator.py
@@ -28,22 +28,16 @@
import argparse
import os
import os.path
-import re
-import shutil
-import sys
-import time
from annotate import Addr2Line
-from simpleperf_report_lib import *
-from utils import *
-
+from simpleperf_report_lib import ReportLib
+from utils import log_info, log_exit
+from utils import extant_dir, find_tool_path, flatten_arg_list
try:
- import google.protobuf
-except:
+ import profile_pb2
+except ImportError:
log_exit('google.protobuf module is missing. Please install it first.')
-import profile_pb2
-
def load_pprof_profile(filename):
profile = profile_pb2.Profile()
with open(filename, "rb") as f:
@@ -165,15 +159,8 @@
print('%sfilename: %s' % (space, self.string(function.filename)))
print('%sstart_line: %d' % (space, function.start_line))
- def show_label(self, label, space=''):
- print('%sLabel(%s =', space, self.string(label.key), end='')
- if label.HasField('str'):
- print('%s)' % self.get_string(label.str))
- else:
- print('%d)' % label.num)
-
- def string(self, id):
- return self.string_table[id]
+ def string(self, string_id):
+ return self.string_table[string_id]
class Sample(object):
@@ -185,13 +172,12 @@
def add_location_id(self, location_id):
self.location_ids.append(location_id)
- def add_value(self, id, value):
- self.values[id] = self.values.get(id, 0) + value
+ def add_value(self, sample_type_id, value):
+ self.values[sample_type_id] = self.values.get(sample_type_id, 0) + value
def add_values(self, values):
- for id in values.keys():
- value = values[id]
- self.add_value(id, value)
+ for sample_type_id, value in values.items():
+ self.add_value(sample_type_id, value)
@property
def key(self):
@@ -254,6 +240,7 @@
return (self.name_id, self.dso_name_id)
+# pylint: disable=no-member
class PprofProfileGenerator(object):
def __init__(self, config):
@@ -280,8 +267,6 @@
else:
self.tid_filter = None
self.dso_filter = set(config['dso_filters']) if config.get('dso_filters') else None
-
- def gen(self):
self.profile = profile_pb2.Profile()
self.profile.string_table.append('')
self.string_table = {}
@@ -295,6 +280,7 @@
self.function_map = {}
self.function_list = []
+ def gen(self):
# 1. Process all samples in perf.data, aggregate samples.
while True:
report_sample = self.lib.GetNextSample()
@@ -356,33 +342,33 @@
return True
return False
- def get_string_id(self, str):
- if len(str) == 0:
+ def get_string_id(self, str_value):
+ if not str_value:
return 0
- id = self.string_table.get(str)
- if id is not None:
- return id
- id = len(self.string_table) + 1
- self.string_table[str] = id
- self.profile.string_table.append(str)
- return id
+ str_id = self.string_table.get(str_value)
+ if str_id is not None:
+ return str_id
+ str_id = len(self.string_table) + 1
+ self.string_table[str_value] = str_id
+ self.profile.string_table.append(str_value)
+ return str_id
- def get_string(self, string_id):
- return self.profile.string_table[string_id]
+ def get_string(self, str_id):
+ return self.profile.string_table[str_id]
def get_sample_type_id(self, name):
- id = self.sample_types.get(name)
- if id is not None:
- return id
- id = len(self.profile.sample_type)
+ sample_type_id = self.sample_types.get(name)
+ if sample_type_id is not None:
+ return sample_type_id
+ sample_type_id = len(self.profile.sample_type)
sample_type = self.profile.sample_type.add()
sample_type.type = self.get_string_id('event_' + name + '_samples')
sample_type.unit = self.get_string_id('count')
sample_type = self.profile.sample_type.add()
sample_type.type = self.get_string_id('event_' + name + '_count')
sample_type.unit = self.get_string_id('count')
- self.sample_types[name] = id
- return id
+ self.sample_types[name] = sample_type_id
+ return sample_type_id
def get_location_id(self, ip, symbol):
mapping_id = self.get_mapping_id(symbol.mapping[0], symbol.dso_name)
@@ -485,7 +471,7 @@
if source_id == 0:
# Clear default line info
location.lines = []
- location.lines.append(self.add_line(source, dso_name, function_id))
+ location.lines.append(self.add_line(source, function_id))
source_id += 1
for function in self.function_list:
@@ -498,7 +484,7 @@
if source.line:
function.start_line = source.line
- def add_line(self, source, dso_name, function_id):
+ def add_line(self, source, function_id):
line = Line()
function = self.get_function(function_id)
function.source_filename_id = self.get_string_id(source.file)
@@ -511,8 +497,8 @@
profile_sample.location_id.extend(sample.location_ids)
sample_type_count = len(self.sample_types) * 2
values = [0] * sample_type_count
- for id in sample.values.keys():
- values[id] = sample.values[id]
+ for sample_type_id in sample.values:
+ values[sample_type_id] = sample.values[sample_type_id]
profile_sample.value.extend(values)
def gen_profile_mapping(self, mapping):
@@ -554,18 +540,18 @@
def main():
parser = argparse.ArgumentParser(description='Generate pprof profile data in pprof.profile.')
parser.add_argument('--show', nargs='?', action='append', help='print existing pprof.profile.')
- parser.add_argument('-i', '--perf_data_path', default='perf.data', help=
-"""The path of profiling data.""")
- parser.add_argument('-o', '--output_file', default='pprof.profile', help=
-"""The path of generated pprof profile data.""")
- parser.add_argument('--comm', nargs='+', action='append', help=
-"""Use samples only in threads with selected names.""")
- parser.add_argument('--pid', nargs='+', action='append', help=
-"""Use samples only in processes with selected process ids.""")
- parser.add_argument('--tid', nargs='+', action='append', help=
-"""Use samples only in threads with selected thread ids.""")
- parser.add_argument('--dso', nargs='+', action='append', help=
-"""Use samples only in selected binaries.""")
+ parser.add_argument('-i', '--perf_data_path', default='perf.data', help="""
+ The path of profiling data.""")
+ parser.add_argument('-o', '--output_file', default='pprof.profile', help="""
+ The path of generated pprof profile data.""")
+ parser.add_argument('--comm', nargs='+', action='append', help="""
+ Use samples only in threads with selected names.""")
+ parser.add_argument('--pid', nargs='+', action='append', help="""
+ Use samples only in processes with selected process ids.""")
+ parser.add_argument('--tid', nargs='+', action='append', help="""
+ Use samples only in threads with selected thread ids.""")
+ parser.add_argument('--dso', nargs='+', action='append', help="""
+ Use samples only in selected binaries.""")
parser.add_argument('--ndk_path', type=extant_dir, help='Set the path of a ndk release.')
args = parser.parse_args()
diff --git a/simpleperf/scripts/pylintrc b/simpleperf/scripts/pylintrc
index aeb022e..2801acb 100644
--- a/simpleperf/scripts/pylintrc
+++ b/simpleperf/scripts/pylintrc
@@ -7,3 +7,6 @@
function-rgx=[a-z_][a-z0-9_]{2,50}$
method-rgx=[a-z_][a-z0-9_]{2,50}$
variable-rgx=[a-z_][a-z0-9_]{0,30}$
+attr-rgx=[a-z_][a-z0-9_]{0,30}$
+argument-rgx=[a-z_][a-z0-9_]{0,30}$
+max-module-lines=5000
\ No newline at end of file
diff --git a/simpleperf/scripts/report_html.py b/simpleperf/scripts/report_html.py
index b52a8d1..73ea166 100644
--- a/simpleperf/scripts/report_html.py
+++ b/simpleperf/scripts/report_html.py
@@ -24,7 +24,8 @@
import tempfile
from simpleperf_report_lib import ReportLib
-from utils import *
+from utils import log_info, log_warning, log_exit
+from utils import Addr2Nearestline, get_script_dir, Objdump, open_report_in_browser, remove
class HtmlWriter(object):
@@ -81,9 +82,16 @@
result['eventName'] = self.name
result['eventCount'] = self.event_count
result['processes'] = [process.get_sample_info(gen_addr_hit_map)
- for process in self.processes.values()]
+ for process in self.processes.values()]
return result
+ @property
+ def libraries(self):
+ for process in self.processes.values():
+ for thread in process.threads.values():
+ for lib in thread.libs.values():
+ yield lib
+
class ProcessScope(object):
@@ -107,7 +115,7 @@
result['pid'] = self.pid
result['eventCount'] = self.event_count
result['threads'] = [thread.get_sample_info(gen_addr_hit_map)
- for thread in self.threads.values()]
+ for thread in self.threads.values()]
return result
@@ -123,8 +131,7 @@
""" callstack is a list of tuple (lib_id, func_id, addr).
For each i > 0, callstack[i] calls callstack[i-1]."""
hit_func_ids = set()
- for i in range(len(callstack)):
- lib_id, func_id, addr = callstack[i]
+ for i, (lib_id, func_id, addr) in enumerate(callstack):
# When a callstack contains recursive function, only add for each function once.
if func_id in hit_func_ids:
continue
@@ -157,7 +164,7 @@
result['tid'] = self.tid
result['eventCount'] = self.event_count
result['libs'] = [lib.gen_sample_info(gen_addr_hit_map)
- for lib in self.libs.values()]
+ for lib in self.libs.values()]
return result
@@ -179,7 +186,7 @@
result['libId'] = self.lib_id
result['eventCount'] = self.event_count
result['functions'] = [func.gen_sample_info(gen_addr_hit_map)
- for func in self.functions.values()]
+ for func in self.functions.values()]
return result
@@ -399,17 +406,7 @@
class SourceFileSearcher(object):
-
- SOURCE_FILE_EXTS = {'.h', '.hh', '.H', '.hxx', '.hpp', '.h++',
- '.c', '.cc', '.C', '.cxx', '.cpp', '.c++',
- '.java', '.kt'}
-
- @classmethod
- def is_source_filename(cls, filename):
- ext = os.path.splitext(filename)[1]
- return ext in cls.SOURCE_FILE_EXTS
-
- """" Find source file paths in the file system.
+ """ Find source file paths in the file system.
The file paths reported by addr2line are the paths stored in debug sections
of shared libraries. And we need to convert them to file paths in the file
system. It is done in below steps:
@@ -424,6 +421,16 @@
2.1 Find all real paths with the same file name as the abstract path.
2.2 Select the real path having the longest common suffix with the abstract path.
"""
+
+ SOURCE_FILE_EXTS = {'.h', '.hh', '.H', '.hxx', '.hpp', '.h++',
+ '.c', '.cc', '.C', '.cxx', '.cpp', '.c++',
+ '.java', '.kt'}
+
+ @classmethod
+ def is_source_filename(cls, filename):
+ ext = os.path.splitext(filename)[1]
+ return ext in cls.SOURCE_FILE_EXTS
+
def __init__(self, source_dirs):
# Map from filename to a list of reversed directory path containing filename.
self.filename_to_rparents = {}
@@ -594,30 +601,25 @@
thread.add_callstack(raw_sample.period, callstack, self.build_addr_hit_map)
for event in self.events.values():
- for process in event.processes.values():
- for thread in process.threads.values():
- for lib in thread.libs.values():
- for func_id in lib.functions:
- function = lib.functions[func_id]
- function.update_subtree_event_count()
+ for lib in event.libraries:
+ for func_id in lib.functions:
+ function = lib.functions[func_id]
+ function.update_subtree_event_count()
def limit_percents(self, min_func_percent, min_callchain_percent):
hit_func_ids = set()
for event in self.events.values():
min_limit = event.event_count * min_func_percent * 0.01
- for process in event.processes.values():
- for thread in process.threads.values():
- for lib in thread.libs.values():
- to_del_func_ids = []
- for func_id in lib.functions:
- function = lib.functions[func_id]
- if function.call_graph.subtree_event_count < min_limit:
- to_del_func_ids.append(func_id)
- else:
- function.limit_callchain_percent(min_callchain_percent,
- hit_func_ids)
- for func_id in to_del_func_ids:
- del lib.functions[func_id]
+ for lib in event.libraries:
+ to_del_func_ids = []
+ for func_id in lib.functions:
+ function = lib.functions[func_id]
+ if function.call_graph.subtree_event_count < min_limit:
+ to_del_func_ids.append(func_id)
+ else:
+ function.limit_callchain_percent(min_callchain_percent, hit_func_ids)
+ for func_id in to_del_func_ids:
+ del lib.functions[func_id]
self.functions.trim_functions(hit_func_ids)
def _get_event(self, event_name):
@@ -642,15 +644,12 @@
function.start_addr + function.addr_len - 1)
# Request line for each addr in FunctionScope.addr_hit_map.
for event in self.events.values():
- for process in event.processes.values():
- for thread in process.threads.values():
- for lib in thread.libs.values():
- lib_name = self.libs.get_lib_name(lib.lib_id)
- for function in lib.functions.values():
- func_addr = self.functions.id_to_func[
- function.call_graph.func_id].start_addr
- for addr in function.addr_hit_map:
- addr2line.add_addr(lib_name, func_addr, addr)
+ for lib in event.libraries:
+ lib_name = self.libs.get_lib_name(lib.lib_id)
+ for function in lib.functions.values():
+ func_addr = self.functions.id_to_func[function.call_graph.func_id].start_addr
+ for addr in function.addr_hit_map:
+ addr2line.add_addr(lib_name, func_addr, addr)
addr2line.convert_addrs_to_lines()
# Set line range for each function.
@@ -659,8 +658,7 @@
continue
dso = addr2line.get_dso(self.libs.get_lib_name(function.lib_id))
start_source = addr2line.get_addr_source(dso, function.start_addr)
- end_source = addr2line.get_addr_source(dso,
- function.start_addr + function.addr_len - 1)
+ end_source = addr2line.get_addr_source(dso, function.start_addr + function.addr_len - 1)
if not start_source or not end_source:
continue
start_file_path, start_line = start_source[-1]
@@ -673,22 +671,20 @@
# Build FunctionScope.line_hit_map.
for event in self.events.values():
- for process in event.processes.values():
- for thread in process.threads.values():
- for lib in thread.libs.values():
- dso = addr2line.get_dso(self.libs.get_lib_name(lib.lib_id))
- for function in lib.functions.values():
- for addr in function.addr_hit_map:
- source = addr2line.get_addr_source(dso, addr)
- if not source:
- continue
- for file_path, line in source:
- source_file = self.source_files.get_source_file(file_path)
- # Show [line - 5, line + 5] of the line hit by a sample.
- source_file.request_lines(line - 5, line + 5)
- count_info = function.addr_hit_map[addr]
- function.build_line_hit_map(source_file.file_id, line,
- count_info[0], count_info[1])
+ for lib in event.libraries:
+ dso = addr2line.get_dso(self.libs.get_lib_name(lib.lib_id))
+ for function in lib.functions.values():
+ for addr in function.addr_hit_map:
+ source = addr2line.get_addr_source(dso, addr)
+ if not source:
+ continue
+ for file_path, line in source:
+ source_file = self.source_files.get_source_file(file_path)
+ # Show [line - 5, line + 5] of the line hit by a sample.
+ source_file.request_lines(line - 5, line + 5)
+ count_info = function.addr_hit_map[addr]
+ function.build_line_hit_map(source_file.file_id, line, count_info[0],
+ count_info[1])
# Collect needed source code in SourceFileSet.
self.source_files.load_source_code(source_dirs)
@@ -771,7 +767,7 @@
def _gen_sample_info(self):
return [event.get_sample_info(self.gen_addr_hit_map_in_record_info)
- for event in self.events.values()]
+ for event in self.events.values()]
def _gen_source_files(self):
source_files = sorted(self.source_files.path_to_source_files.values(),
@@ -799,22 +795,23 @@
self.hw.open_tag('html')
self.hw.open_tag('head')
self.hw.open_tag('link', rel='stylesheet', type='text/css',
- href='https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css'
- ).close_tag()
+ href='https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css'
+ ).close_tag()
self.hw.open_tag('link', rel='stylesheet', type='text/css',
- href='https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css'
- ).close_tag()
+ href='https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css'
+ ).close_tag()
self.hw.open_tag('script', src='https://www.gstatic.com/charts/loader.js').close_tag()
self.hw.open_tag('script').add(
"google.charts.load('current', {'packages': ['corechart', 'table']});").close_tag()
self.hw.open_tag('script', src='https://code.jquery.com/jquery-3.2.1.js').close_tag()
- self.hw.open_tag('script', src='https://code.jquery.com/ui/1.12.1/jquery-ui.js'
- ).close_tag()
+ self.hw.open_tag('script', src='https://code.jquery.com/ui/1.12.1/jquery-ui.js').close_tag()
self.hw.open_tag('script',
- src='https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js').close_tag()
+ src='https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js'
+ ).close_tag()
self.hw.open_tag('script',
- src='https://cdn.datatables.net/1.10.16/js/dataTables.jqueryui.min.js').close_tag()
+ src='https://cdn.datatables.net/1.10.16/js/dataTables.jqueryui.min.js'
+ ).close_tag()
self.hw.open_tag('style', type='text/css').add("""
.colForLine { width: 50px; }
.colForCount { width: 100px; }
diff --git a/simpleperf/scripts/report_sample.py b/simpleperf/scripts/report_sample.py
index 45e884a..bbe9008 100644
--- a/simpleperf/scripts/report_sample.py
+++ b/simpleperf/scripts/report_sample.py
@@ -20,11 +20,10 @@
from __future__ import print_function
import argparse
-import sys
-from simpleperf_report_lib import *
+from simpleperf_report_lib import ReportLib
-def report_sample(record_file, symfs_dir, kallsyms_file=None):
+def report_sample(record_file, symfs_dir, kallsyms_file, show_tracing_data):
""" read record_file, and print each sample"""
lib = ReportLib()
@@ -54,15 +53,26 @@
for i in range(callchain.nr):
entry = callchain.entries[i]
print('%16x\t%s (%s)' % (entry.ip, entry.symbol.symbol_name, entry.symbol.dso_name))
+ if show_tracing_data:
+ data = lib.GetTracingDataOfCurrentSample()
+ if data:
+ print('\ttracing data:')
+ for key, value in data.items():
+ print('\t\t%s : %s' % (key, value))
print('')
-if __name__ == '__main__':
+def main():
parser = argparse.ArgumentParser(description='Report samples in perf.data.')
parser.add_argument('--symfs',
help='Set the path to find binaries with symbols and debug info.')
parser.add_argument('--kallsyms', help='Set the path to find kernel symbols.')
parser.add_argument('record_file', nargs='?', default='perf.data',
help='Default is perf.data.')
+ parser.add_argument('--show_tracing_data', action='store_true', help='print tracing data.')
args = parser.parse_args()
- report_sample(args.record_file, args.symfs, args.kallsyms)
+ report_sample(args.record_file, args.symfs, args.kallsyms, args.show_tracing_data)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/simpleperf/scripts/run_simpleperf_on_device.py b/simpleperf/scripts/run_simpleperf_on_device.py
index 37155bc..9732d6d 100644
--- a/simpleperf/scripts/run_simpleperf_on_device.py
+++ b/simpleperf/scripts/run_simpleperf_on_device.py
@@ -21,7 +21,7 @@
"""
import subprocess
import sys
-from utils import *
+from utils import AdbHelper, disable_debug_log, get_target_binary_path
def main():
disable_debug_log()
@@ -34,4 +34,4 @@
sys.exit(subprocess.call([adb.adb_path, 'shell', shell_cmd]))
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py
index 2eff83e..d2bc2d3 100644
--- a/simpleperf/scripts/simpleperf_report_lib.py
+++ b/simpleperf/scripts/simpleperf_report_lib.py
@@ -20,12 +20,10 @@
"""
+import collections
import ctypes as ct
-import os
-import subprocess
-import sys
-import unittest
-from utils import *
+import struct
+from utils import bytes_to_str, get_host_binary_path, is_windows, str_to_bytes
def _get_native_lib():
@@ -45,6 +43,10 @@
def _char_pt_to_str(char_pt):
return bytes_to_str(char_pt)
+def _check(cond, failmsg):
+ if not cond:
+ raise RuntimeError(failmsg)
+
class SampleStruct(ct.Structure):
""" Instance of a sample in perf.data.
@@ -63,16 +65,90 @@
_fields_ = [('ip', ct.c_uint64),
('pid', ct.c_uint32),
('tid', ct.c_uint32),
- ('thread_comm', ct.c_char_p),
+ ('_thread_comm', ct.c_char_p),
('time', ct.c_uint64),
('in_kernel', ct.c_uint32),
('cpu', ct.c_uint32),
('period', ct.c_uint64)]
+ @property
+ def thread_comm(self):
+ return _char_pt_to_str(self._thread_comm)
+
+
+class TracingFieldFormatStruct(ct.Structure):
+ """Format of a tracing field.
+ name: name of the field.
+ offset: offset of the field in tracing data.
+ elem_size: size of the element type.
+ elem_count: the number of elements in this field, more than one if the field is an array.
+ is_signed: whether the element type is signed or unsigned.
+ """
+ _fields_ = [('_name', ct.c_char_p),
+ ('offset', ct.c_uint32),
+ ('elem_size', ct.c_uint32),
+ ('elem_count', ct.c_uint32),
+ ('is_signed', ct.c_uint32)]
+
+ _unpack_key_dict = {1: 'b', 2: 'h', 4: 'i', 8: 'q'}
+
+ @property
+ def name(self):
+ return _char_pt_to_str(self._name)
+
+ def parse_value(self, data):
+ """ Parse value of a field in a tracepoint event.
+ The return value depends on the type of the field, and can be an int value, a string,
+ an array of int values, etc. If the type can't be parsed, return a byte array or an
+ array of byte arrays.
+ """
+ if self.elem_count > 1 and self.elem_size == 1 and self.is_signed == 0:
+ # The field is a string.
+ length = 0
+ while length < self.elem_count and data[self.offset + length] != '\x00':
+ length += 1
+ return bytes_to_str(data[self.offset : self.offset + length])
+ unpack_key = self._unpack_key_dict.get(self.elem_size)
+ if unpack_key:
+ if not self.is_signed:
+ unpack_key = unpack_key.upper()
+ value = struct.unpack('%d%s' % (self.elem_count, unpack_key),
+ data[self.offset:self.offset + self.elem_count * self.elem_size])
+ else:
+ # Since we don't know the element type, just return the bytes.
+ value = []
+ offset = self.offset
+ for _ in range(self.elem_count):
+ value.append(data[offset : offset + self.elem_size])
+ offset += self.elem_size
+ if self.elem_count == 1:
+ value = value[0]
+ return value
+
+
+class TracingDataFormatStruct(ct.Structure):
+ """Format of tracing data of a tracepoint event, like
+ https://www.kernel.org/doc/html/latest/trace/events.html#event-formats.
+ size: total size of all fields in the tracing data.
+ field_count: the number of fields.
+ fields: an array of fields.
+ """
+ _fields_ = [('size', ct.c_uint32),
+ ('field_count', ct.c_uint32),
+ ('fields', ct.POINTER(TracingFieldFormatStruct))]
+
class EventStruct(ct.Structure):
- """ Name of the event. """
- _fields_ = [('name', ct.c_char_p)]
+ """Event type of a sample.
+ name: name of the event type.
+ tracing_data_format: only available when it is a tracepoint event.
+ """
+ _fields_ = [('_name', ct.c_char_p),
+ ('tracing_data_format', TracingDataFormatStruct)]
+
+ @property
+ def name(self):
+ return _char_pt_to_str(self._name)
class MappingStruct(ct.Structure):
@@ -95,13 +171,21 @@
symbol_len: length of the function in the shared library.
mapping: the mapping area hit by the instruction.
"""
- _fields_ = [('dso_name', ct.c_char_p),
+ _fields_ = [('_dso_name', ct.c_char_p),
('vaddr_in_file', ct.c_uint64),
- ('symbol_name', ct.c_char_p),
+ ('_symbol_name', ct.c_char_p),
('symbol_addr', ct.c_uint64),
('symbol_len', ct.c_uint64),
('mapping', ct.POINTER(MappingStruct))]
+ @property
+ def dso_name(self):
+ return _char_pt_to_str(self._dso_name)
+
+ @property
+ def symbol_name(self):
+ return _char_pt_to_str(self._symbol_name)
+
class CallChainEntryStructure(ct.Structure):
""" A callchain entry of a sample.
@@ -134,51 +218,11 @@
('data_size', ct.c_uint32)]
-# convert char_p to str for python3.
-class SampleStructUsingStr(object):
- def __init__(self, sample):
- self.ip = sample.ip
- self.pid = sample.pid
- self.tid = sample.tid
- self.thread_comm = _char_pt_to_str(sample.thread_comm)
- self.time = sample.time
- self.in_kernel = sample.in_kernel
- self.cpu = sample.cpu
- self.period = sample.period
-
-
-class EventStructUsingStr(object):
- def __init__(self, event):
- self.name = _char_pt_to_str(event.name)
-
-
-class SymbolStructUsingStr(object):
- def __init__(self, symbol):
- self.dso_name = _char_pt_to_str(symbol.dso_name)
- self.vaddr_in_file = symbol.vaddr_in_file
- self.symbol_name = _char_pt_to_str(symbol.symbol_name)
- self.symbol_addr = symbol.symbol_addr
- self.mapping = symbol.mapping
-
-
-class CallChainEntryStructureUsingStr(object):
- def __init__(self, entry):
- self.ip = entry.ip
- self.symbol = SymbolStructUsingStr(entry.symbol)
-
-
-class CallChainStructureUsingStr(object):
- def __init__(self, callchain):
- self.nr = callchain.nr
- self.entries = []
- for i in range(self.nr):
- self.entries.append(CallChainEntryStructureUsingStr(callchain.entries[i]))
-
-
class ReportLibStructure(ct.Structure):
_fields_ = []
+# pylint: disable=invalid-name
class ReportLib(object):
def __init__(self, native_lib_path=None):
@@ -203,8 +247,9 @@
self._GetSymbolOfCurrentSampleFunc = self._lib.GetSymbolOfCurrentSample
self._GetSymbolOfCurrentSampleFunc.restype = ct.POINTER(SymbolStruct)
self._GetCallChainOfCurrentSampleFunc = self._lib.GetCallChainOfCurrentSample
- self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(
- CallChainStructure)
+ self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(CallChainStructure)
+ self._GetTracingDataOfCurrentSampleFunc = self._lib.GetTracingDataOfCurrentSample
+ self._GetTracingDataOfCurrentSampleFunc.restype = ct.POINTER(ct.c_char)
self._GetBuildIdForPathFunc = self._lib.GetBuildIdForPath
self._GetBuildIdForPathFunc.restype = ct.c_char_p
self._GetFeatureSection = self._lib.GetFeatureSection
@@ -212,7 +257,6 @@
self._instance = self._CreateReportLibFunc()
assert not _is_null(self._instance)
- self.convert_to_str = (sys.version_info >= (3, 0))
self.meta_info = None
self.current_sample = None
self.record_cmd = None
@@ -231,17 +275,17 @@
def SetLogSeverity(self, log_level='info'):
""" Set log severity of native lib, can be verbose,debug,info,error,fatal."""
cond = self._SetLogSeverityFunc(self.getInstance(), _char_pt(log_level))
- self._check(cond, 'Failed to set log level')
+ _check(cond, 'Failed to set log level')
def SetSymfs(self, symfs_dir):
""" Set directory used to find symbols."""
cond = self._SetSymfsFunc(self.getInstance(), _char_pt(symfs_dir))
- self._check(cond, 'Failed to set symbols directory')
+ _check(cond, 'Failed to set symbols directory')
def SetRecordFile(self, record_file):
""" Set the path of record file, like perf.data."""
cond = self._SetRecordFileFunc(self.getInstance(), _char_pt(record_file))
- self._check(cond, 'Failed to set record file')
+ _check(cond, 'Failed to set record file')
def ShowIpForUnknownSymbol(self):
self._ShowIpForUnknownSymbolFunc(self.getInstance())
@@ -253,15 +297,14 @@
def SetKallsymsFile(self, kallsym_file):
""" Set the file path to a copy of the /proc/kallsyms file (for off device decoding) """
cond = self._SetKallsymsFileFunc(self.getInstance(), _char_pt(kallsym_file))
- self._check(cond, 'Failed to set kallsyms file')
+ _check(cond, 'Failed to set kallsyms file')
def GetNextSample(self):
psample = self._GetNextSampleFunc(self.getInstance())
if _is_null(psample):
self.current_sample = None
else:
- sample = psample[0]
- self.current_sample = SampleStructUsingStr(sample) if self.convert_to_str else sample
+ self.current_sample = psample[0]
return self.current_sample
def GetCurrentSample(self):
@@ -270,24 +313,29 @@
def GetEventOfCurrentSample(self):
event = self._GetEventOfCurrentSampleFunc(self.getInstance())
assert not _is_null(event)
- if self.convert_to_str:
- return EventStructUsingStr(event[0])
return event[0]
def GetSymbolOfCurrentSample(self):
symbol = self._GetSymbolOfCurrentSampleFunc(self.getInstance())
assert not _is_null(symbol)
- if self.convert_to_str:
- return SymbolStructUsingStr(symbol[0])
return symbol[0]
def GetCallChainOfCurrentSample(self):
callchain = self._GetCallChainOfCurrentSampleFunc(self.getInstance())
assert not _is_null(callchain)
- if self.convert_to_str:
- return CallChainStructureUsingStr(callchain[0])
return callchain[0]
+ def GetTracingDataOfCurrentSample(self):
+ data = self._GetTracingDataOfCurrentSampleFunc(self.getInstance())
+ if _is_null(data):
+ return None
+ event = self.GetEventOfCurrentSample()
+ result = collections.OrderedDict()
+ for i in range(event.tracing_data_format.field_count):
+ field = event.tracing_data_format.fields[i]
+ result[field.name] = field.parse_value(data)
+ return result
+
def GetBuildIdForPath(self, path):
build_id = self._GetBuildIdForPathFunc(self.getInstance(), _char_pt(path))
assert not _is_null(build_id)
@@ -364,7 +412,3 @@
if self._instance is None:
raise Exception('Instance is Closed')
return self._instance
-
- def _check(self, cond, failmsg):
- if not cond:
- raise Exception(failmsg)
diff --git a/simpleperf/scripts/test.py b/simpleperf/scripts/test.py
index 1b80964..99404aa 100644
--- a/simpleperf/scripts/test.py
+++ b/simpleperf/scripts/test.py
@@ -34,42 +34,41 @@
Test using both `adb root` and `adb unroot`.
"""
-
+from __future__ import print_function
import os
import re
import shutil
import signal
+import subprocess
import sys
-import tempfile
import time
+import types
import unittest
from app_profiler import NativeLibDownloader
from simpleperf_report_lib import ReportLib
-from utils import *
+from utils import log_info, log_fatal
+from utils import AdbHelper, Addr2Nearestline, get_script_dir, is_windows, Objdump, ReadElf, remove
-has_google_protobuf = True
try:
+ # pylint: disable=unused-import
import google.protobuf
-except:
- has_google_protobuf = False
+ HAS_GOOGLE_PROTOBUF = True
+except ImportError:
+ HAS_GOOGLE_PROTOBUF = False
-inferno_script = os.path.join(get_script_dir(), "inferno.bat" if is_windows() else "./inferno.sh")
+INFERNO_SCRIPT = os.path.join(get_script_dir(), "inferno.bat" if is_windows() else "./inferno.sh")
-support_trace_offcpu = None
+def get_device_features():
+ adb = AdbHelper()
+ adb.check_run_and_return_output(['push',
+ 'bin/android/%s/simpleperf' % adb.get_device_arch(),
+ '/data/local/tmp'])
+ adb.check_run_and_return_output(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf'])
+ return adb.check_run_and_return_output(['shell', '/data/local/tmp/simpleperf', 'list',
+ '--show-features'])
-def is_trace_offcpu_supported():
- global support_trace_offcpu
- if support_trace_offcpu is None:
- adb = AdbHelper()
- adb.check_run_and_return_output(['push',
- 'bin/android/%s/simpleperf' % adb.get_device_arch(),
- "/data/local/tmp"])
- adb.check_run_and_return_output(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf'])
- output = adb.check_run_and_return_output(['shell', '/data/local/tmp/simpleperf', 'list',
- '--show-features'])
- support_trace_offcpu = 'trace-offcpu' in output
- return support_trace_offcpu
+SUPPORT_TRACE_OFFCPU = 'trace-offcpu' in get_device_features()
def build_testdata():
""" Collect testdata from ../testdata and ../demo. """
@@ -77,7 +76,7 @@
from_demo_path = os.path.join('..', 'demo')
from_script_testdata_path = 'script_testdata'
if (not os.path.isdir(from_testdata_path) or not os.path.isdir(from_demo_path) or
- not from_script_testdata_path):
+ not from_script_testdata_path):
return
copy_testdata_list = ['perf_with_symbols.data', 'perf_with_trace_offcpu.data',
'perf_with_tracepoint_event.data', 'perf_with_interpreter_frames.data']
@@ -106,11 +105,12 @@
subproc = subprocess.Popen(args, stdout=subprocess.PIPE, shell=use_shell)
(output_data, _) = subproc.communicate()
returncode = subproc.returncode
- except:
+ except OSError:
returncode = None
self.assertEqual(returncode, 0, msg="failed to run cmd: %s" % args)
if return_output:
return output_data
+ return ''
class TestExampleBase(TestBase):
@@ -145,7 +145,7 @@
cls.use_compiled_java_code = android_version <= 8
def setUp(self):
- if self.id().find('TraceOffCpu') != -1 and not is_trace_offcpu_supported():
+ if self.id().find('TraceOffCpu') != -1 and not SUPPORT_TRACE_OFFCPU:
self.skipTest('trace-offcpu is not supported on device')
cls = self.__class__
if not cls.has_perf_data_for_report:
@@ -193,28 +193,28 @@
if not self.adb_root:
args.append("--disable_adb_root")
self.run_cmd(args)
- self.check_exist(file="perf.data")
+ self.check_exist(filename="perf.data")
if build_binary_cache:
- self.check_exist(dir="binary_cache")
+ self.check_exist(dirname="binary_cache")
- def check_exist(self, file=None, dir=None):
- if file:
- self.assertTrue(os.path.isfile(file), file)
- if dir:
- self.assertTrue(os.path.isdir(dir), dir)
+ def check_exist(self, filename=None, dirname=None):
+ if filename:
+ self.assertTrue(os.path.isfile(filename), filename)
+ if dirname:
+ self.assertTrue(os.path.isdir(dirname), dirname)
- def check_file_under_dir(self, dir, file):
- self.check_exist(dir=dir)
- for _, _, files in os.walk(dir):
+ def check_file_under_dir(self, dirname, filename):
+ self.check_exist(dirname=dirname)
+ for _, _, files in os.walk(dirname):
for f in files:
- if f == file:
+ if f == filename:
return
- self.fail("Failed to call check_file_under_dir(dir=%s, file=%s)" % (dir, file))
+ self.fail("Failed to call check_file_under_dir(dir=%s, file=%s)" % (dirname, filename))
- def check_strings_in_file(self, file, strings):
- self.check_exist(file=file)
- with open(file, 'r') as fh:
+ def check_strings_in_file(self, filename, strings):
+ self.check_exist(filename=filename)
+ with open(filename, 'r') as fh:
self.check_strings_in_content(fh.read(), strings)
def check_strings_in_content(self, content, strings):
@@ -226,17 +226,15 @@
This function checks for each entry, if the line containing [name]
has at least required accumulated_period and period.
"""
- self.check_exist(file=summary_file)
+ self.check_exist(filename=summary_file)
with open(summary_file, 'r') as fh:
summary = fh.read()
fulfilled = [False for x in check_entries]
- if not hasattr(self, "summary_check_re"):
- self.summary_check_re = re.compile(r'accumulated_period:\s*([\d.]+)%.*period:\s*([\d.]+)%')
+ summary_check_re = re.compile(r'accumulated_period:\s*([\d.]+)%.*period:\s*([\d.]+)%')
for line in summary.split('\n'):
- for i in range(len(check_entries)):
- (name, need_acc_period, need_period) = check_entries[i]
+ for i, (name, need_acc_period, need_period) in enumerate(check_entries):
if not fulfilled[i] and name in line:
- m = self.summary_check_re.search(line)
+ m = summary_check_re.search(line)
if m:
acc_period = float(m.group(1))
period = float(m.group(2))
@@ -244,9 +242,9 @@
fulfilled[i] = True
self.assertEqual(len(fulfilled), sum([int(x) for x in fulfilled]), fulfilled)
- def check_inferno_report_html(self, check_entries, file="report.html"):
- self.check_exist(file=file)
- with open(file, 'r') as fh:
+ def check_inferno_report_html(self, check_entries, filename="report.html"):
+ self.check_exist(filename=filename)
+ with open(filename, 'r') as fh:
data = fh.read()
fulfilled = [False for _ in check_entries]
for line in data.split('\n'):
@@ -258,7 +256,7 @@
if m and float(m.group(1)) >= entry[1]:
fulfilled[i] = True
break
- self.assertEqual(fulfilled, [True for x in check_entries])
+ self.assertEqual(fulfilled, [True for _ in check_entries])
def common_test_app_profiler(self):
self.run_cmd(["app_profiler.py", "-h"])
@@ -269,7 +267,7 @@
if not self.adb_root:
args.append("--disable_adb_root")
self.run_cmd(args)
- self.check_exist(dir="binary_cache")
+ self.check_exist(dirname="binary_cache")
remove("binary_cache")
self.run_app_profiler(build_binary_cache=True)
self.run_app_profiler()
@@ -280,13 +278,13 @@
self.run_cmd(["report.py"])
self.run_cmd(["report.py", "-i", "perf.data"])
self.run_cmd(["report.py", "-g"])
- self.run_cmd(["report.py", "--self-kill-for-testing", "-g", "--gui"])
+ self.run_cmd(["report.py", "--self-kill-for-testing", "-g", "--gui"])
def common_test_annotate(self):
self.run_cmd(["annotate.py", "-h"])
remove("annotated_files")
self.run_cmd(["annotate.py", "-s", self.example_path])
- self.check_exist(dir="annotated_files")
+ self.check_exist(dirname="annotated_files")
def common_test_report_sample(self, check_strings):
self.run_cmd(["report_sample.py", "-h"])
@@ -296,37 +294,36 @@
def common_test_pprof_proto_generator(self, check_strings_with_lines,
check_strings_without_lines):
- if not has_google_protobuf:
+ if not HAS_GOOGLE_PROTOBUF:
log_info('Skip test for pprof_proto_generator because google.protobuf is missing')
return
self.run_cmd(["pprof_proto_generator.py", "-h"])
self.run_cmd(["pprof_proto_generator.py"])
remove("pprof.profile")
self.run_cmd(["pprof_proto_generator.py", "-i", "perf.data", "-o", "pprof.profile"])
- self.check_exist(file="pprof.profile")
+ self.check_exist(filename="pprof.profile")
self.run_cmd(["pprof_proto_generator.py", "--show"])
output = self.run_cmd(["pprof_proto_generator.py", "--show", "pprof.profile"],
return_output=True)
- self.check_strings_in_content(output, check_strings_with_lines +
- ["has_line_numbers: True"])
+ self.check_strings_in_content(output, check_strings_with_lines + ["has_line_numbers: True"])
remove("binary_cache")
self.run_cmd(["pprof_proto_generator.py"])
output = self.run_cmd(["pprof_proto_generator.py", "--show", "pprof.profile"],
return_output=True)
self.check_strings_in_content(output, check_strings_without_lines +
- ["has_line_numbers: False"])
+ ["has_line_numbers: False"])
def common_test_inferno(self):
- self.run_cmd([inferno_script, "-h"])
+ self.run_cmd([INFERNO_SCRIPT, "-h"])
remove("perf.data")
append_args = [] if self.adb_root else ["--disable_adb_root"]
- self.run_cmd([inferno_script, "-p", self.package_name, "-t", "3"] + append_args)
- self.check_exist(file="perf.data")
- self.run_cmd([inferno_script, "-p", self.package_name, "-f", "1000", "-du", "-t", "1"] +
+ self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-t", "3"] + append_args)
+ self.check_exist(filename="perf.data")
+ self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-f", "1000", "-du", "-t", "1"] +
append_args)
- self.run_cmd([inferno_script, "-p", self.package_name, "-e", "100000 cpu-cycles",
+ self.run_cmd([INFERNO_SCRIPT, "-p", self.package_name, "-e", "100000 cpu-cycles",
"-t", "1"] + append_args)
- self.run_cmd([inferno_script, "-sc"])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
def common_test_report_html(self):
self.run_cmd(['report_html.py', '-h'])
@@ -353,9 +350,9 @@
def test_app_profiler_profile_from_launch(self):
self.run_app_profiler(start_activity=True, build_binary_cache=False)
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+ "__start_thread"])
def test_app_profiler_multiprocesses(self):
self.adb.check_run(['shell', 'am', 'force-stop', self.package_name])
@@ -396,20 +393,20 @@
def test_report(self):
self.common_test_report()
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+ "__start_thread"])
def test_profile_with_process_id(self):
self.adb.check_run(['shell', 'am', 'start', '-n', self.package_name + '/.MainActivity'])
time.sleep(1)
- pid = self.adb.check_run_and_return_output(['shell', 'pidof',
- 'com.example.simpleperf.simpleperfexamplepurejava']).strip()
+ pid = self.adb.check_run_and_return_output([
+ 'shell', 'pidof', 'com.example.simpleperf.simpleperfexamplepurejava']).strip()
self.run_app_profiler(start_activity=False, record_arg='-g --duration 10 -p ' + pid)
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
+ "__start_thread"])
def test_annotate(self):
self.common_test_annotate()
@@ -418,15 +415,15 @@
return
self.check_file_under_dir("annotated_files", "MainActivity.java")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("MainActivity.java", 80, 80),
- ("run", 80, 0),
- ("callFunction", 0, 0),
- ("line 23", 80, 0)])
+ self.check_annotation_summary(summary_file, [
+ ("MainActivity.java", 80, 80),
+ ("run", 80, 0),
+ ("callFunction", 0, 0),
+ ("line 23", 80, 0)])
def test_report_sample(self):
self.common_test_report_sample(
- ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()",
+ ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run",
"__start_thread"])
def test_pprof_proto_generator(self):
@@ -437,18 +434,18 @@
"run"]
self.common_test_pprof_proto_generator(
check_strings_with_lines=check_strings_with_lines,
- check_strings_without_lines=
- ["com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()"])
+ check_strings_without_lines=[
+ "com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run"])
def test_inferno(self):
self.common_test_inferno()
self.run_app_profiler()
- self.run_cmd([inferno_script, "-sc"])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
self.check_inferno_report_html(
- [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()', 80)])
- self.run_cmd([inferno_script, "-sc", "-o", "report2.html"])
+ [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)])
+ self.run_cmd([INFERNO_SCRIPT, "-sc", "-o", "report2.html"])
self.check_inferno_report_html(
- [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run()', 80)],
+ [('com.example.simpleperf.simpleperfexamplepurejava.MainActivity$1.run', 80)],
"report2.html")
remove("report2.html")
@@ -460,8 +457,8 @@
os.chdir(test_dir)
self.run_cmd(['python', os.path.join(saved_dir, 'app_profiler.py'),
'--app', self.package_name, '-r', '-e task-clock:u -g --duration 3'])
- self.check_exist(file="perf.data")
- self.run_cmd([inferno_script, "-sc"])
+ self.check_exist(filename="perf.data")
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
os.chdir(saved_dir)
remove(test_dir)
@@ -475,7 +472,7 @@
self.adb.check_run(['kill-server'])
time.sleep(3)
self.run_cmd(['run_simpleperf_without_usb_connection.py', 'stop'])
- self.check_exist(file="perf.data")
+ self.check_exist(filename="perf.data")
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
@@ -501,25 +498,25 @@
def test_smoke(self):
self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run",
- "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction",
- "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction"
- ])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run",
+ "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction",
+ "com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.SleepFunction"
+ ])
remove("annotated_files")
self.run_cmd(["annotate.py", "-s", self.example_path])
- self.check_exist(dir="annotated_files")
+ self.check_exist(dirname="annotated_files")
if self.use_compiled_java_code:
self.check_file_under_dir("annotated_files", "SleepActivity.java")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("SleepActivity.java", 80, 20),
+ self.check_annotation_summary(summary_file, [
+ ("SleepActivity.java", 80, 20),
("run", 80, 0),
("RunFunction", 20, 20),
("SleepFunction", 20, 0),
("line 24", 20, 0),
("line 32", 20, 0)])
- self.run_cmd([inferno_script, "-sc"])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
self.check_inferno_report_html(
[('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.run', 80),
('com.example.simpleperf.simpleperfexamplepurejava.SleepActivity$1.RunFunction',
@@ -541,25 +538,21 @@
def test_app_profiler_profile_from_launch(self):
self.run_app_profiler(start_activity=True, build_binary_cache=False)
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["BusyLoopThread",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
def test_report(self):
self.common_test_report()
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["BusyLoopThread",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", ["BusyLoopThread", "__start_thread"])
def test_annotate(self):
self.common_test_annotate()
self.check_file_under_dir("annotated_files", "native-lib.cpp")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("native-lib.cpp", 20, 0),
- ("BusyLoopThread", 20, 0),
- ("line 46", 20, 0)])
+ self.check_annotation_summary(summary_file, [
+ ("native-lib.cpp", 20, 0),
+ ("BusyLoopThread", 20, 0),
+ ("line 46", 20, 0)])
def test_report_sample(self):
self.common_test_report_sample(
@@ -568,16 +561,13 @@
def test_pprof_proto_generator(self):
self.common_test_pprof_proto_generator(
- check_strings_with_lines=
- ["native-lib.cpp",
- "BusyLoopThread"],
- check_strings_without_lines=
- ["BusyLoopThread"])
+ check_strings_with_lines=["native-lib.cpp", "BusyLoopThread"],
+ check_strings_without_lines=["BusyLoopThread"])
def test_inferno(self):
self.common_test_inferno()
self.run_app_profiler()
- self.run_cmd([inferno_script, "-sc"])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
self.check_inferno_report_html([('BusyLoopThread', 20)])
def test_report_html(self):
@@ -606,23 +596,23 @@
def test_smoke(self):
self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
self.run_cmd(["report.py", "-g", "--comms", "SleepThread", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["SleepThread(void*)",
- "RunFunction()",
- "SleepFunction(unsigned long long)"])
+ self.check_strings_in_file("report.txt", [
+ "SleepThread(void*)",
+ "RunFunction()",
+ "SleepFunction(unsigned long long)"])
remove("annotated_files")
self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "SleepThread"])
- self.check_exist(dir="annotated_files")
+ self.check_exist(dirname="annotated_files")
self.check_file_under_dir("annotated_files", "native-lib.cpp")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("native-lib.cpp", 80, 20),
- ("SleepThread", 80, 0),
- ("RunFunction", 20, 20),
- ("SleepFunction", 20, 0),
- ("line 73", 20, 0),
- ("line 83", 20, 0)])
- self.run_cmd([inferno_script, "-sc"])
+ self.check_annotation_summary(summary_file, [
+ ("native-lib.cpp", 80, 20),
+ ("SleepThread", 80, 0),
+ ("RunFunction", 20, 20),
+ ("SleepFunction", 20, 0),
+ ("line 73", 20, 0),
+ ("line 83", 20, 0)])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
self.check_inferno_report_html([('SleepThread', 80),
('RunFunction', 20),
('SleepFunction', 20)])
@@ -638,28 +628,26 @@
def test_smoke(self):
self.run_app_profiler()
self.run_cmd(["report.py", "-g", "--comms", "BusyThread", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["void com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run()",
- "int com.example.simpleperf.simpleperfexamplewithnative.MixActivity.callFunction(int)",
- "Java_com_example_simpleperf_simpleperfexamplewithnative_MixActivity_callFunction"])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run",
+ "com.example.simpleperf.simpleperfexamplewithnative.MixActivity.callFunction",
+ "Java_com_example_simpleperf_simpleperfexamplewithnative_MixActivity_callFunction"])
remove("annotated_files")
self.run_cmd(["annotate.py", "-s", self.example_path, "--comm", "BusyThread"])
- self.check_exist(dir="annotated_files")
+ self.check_exist(dirname="annotated_files")
self.check_file_under_dir("annotated_files", "native-lib.cpp")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("native-lib.cpp", 5, 0),
- ("line 40", 5, 0)])
+ self.check_annotation_summary(summary_file, [("native-lib.cpp", 5, 0), ("line 40", 5, 0)])
if self.use_compiled_java_code:
self.check_file_under_dir("annotated_files", "MixActivity.java")
- self.check_annotation_summary(summary_file,
- [("MixActivity.java", 80, 0),
- ("run", 80, 0),
- ("line 26", 20, 0),
- ("native-lib.cpp", 5, 0),
- ("line 40", 5, 0)])
+ self.check_annotation_summary(summary_file, [
+ ("MixActivity.java", 80, 0),
+ ("run", 80, 0),
+ ("line 26", 20, 0),
+ ("native-lib.cpp", 5, 0),
+ ("line 40", 5, 0)])
- self.run_cmd([inferno_script, "-sc"])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
class TestExampleWithNativeForceArm(TestExampleWithNative):
@@ -703,16 +691,16 @@
def test_app_profiler_profile_from_launch(self):
self.run_app_profiler(start_activity=True, build_binary_cache=False)
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1.run()",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
+ "run", "__start_thread"])
def test_report(self):
self.common_test_report()
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1.run()",
- "__start_thread"])
+ self.check_strings_in_file("report.txt", [
+ "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
+ "run", "__start_thread"])
def test_annotate(self):
if not self.use_compiled_java_code:
@@ -720,17 +708,17 @@
self.common_test_annotate()
self.check_file_under_dir("annotated_files", "MainActivity.kt")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("MainActivity.kt", 80, 80),
- ("run", 80, 0),
- ("callFunction", 0, 0),
- ("line 19", 80, 0),
- ("line 25", 0, 0)])
+ self.check_annotation_summary(summary_file, [
+ ("MainActivity.kt", 80, 80),
+ ("run", 80, 0),
+ ("callFunction", 0, 0),
+ ("line 19", 80, 0),
+ ("line 25", 0, 0)])
def test_report_sample(self):
- self.common_test_report_sample(
- ["com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1.run()",
- "__start_thread"])
+ self.common_test_report_sample([
+ "com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1." +
+ "run", "__start_thread"])
def test_pprof_proto_generator(self):
check_strings_with_lines = []
@@ -740,16 +728,15 @@
"run"]
self.common_test_pprof_proto_generator(
check_strings_with_lines=check_strings_with_lines,
- check_strings_without_lines=
- ["com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1.run()"])
+ check_strings_without_lines=["com.example.simpleperf.simpleperfexampleofkotlin." +
+ "MainActivity$createBusyThread$1.run"])
def test_inferno(self):
self.common_test_inferno()
self.run_app_profiler()
- self.run_cmd([inferno_script, "-sc"])
- self.check_inferno_report_html(
- [('com.example.simpleperf.simpleperfexampleofkotlin.MainActivity$createBusyThread$1.run()',
- 80)])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
+ self.check_inferno_report_html([('com.example.simpleperf.simpleperfexampleofkotlin.' +
+ 'MainActivity$createBusyThread$1.run', 80)])
def test_report_html(self):
self.common_test_report_html()
@@ -777,33 +764,32 @@
def test_smoke(self):
self.run_app_profiler(record_arg="-g -f 1000 --duration 10 -e cpu-cycles:u --trace-offcpu")
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.check_strings_in_file("report.txt",
- ["com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.run",
- "com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.RunFunction",
- "com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.SleepFunction"
- ])
+ function_prefix = "com.example.simpleperf.simpleperfexampleofkotlin." + \
+ "SleepActivity$createRunSleepThread$1."
+ self.check_strings_in_file("report.txt", [
+ function_prefix + "run",
+ function_prefix + "RunFunction",
+ function_prefix + "SleepFunction"
+ ])
if self.use_compiled_java_code:
remove("annotated_files")
self.run_cmd(["annotate.py", "-s", self.example_path])
- self.check_exist(dir="annotated_files")
+ self.check_exist(dirname="annotated_files")
self.check_file_under_dir("annotated_files", "SleepActivity.kt")
summary_file = os.path.join("annotated_files", "summary")
- self.check_annotation_summary(summary_file,
- [("SleepActivity.kt", 80, 20),
- ("run", 80, 0),
- ("RunFunction", 20, 20),
- ("SleepFunction", 20, 0),
- ("line 24", 20, 0),
- ("line 32", 20, 0)])
+ self.check_annotation_summary(summary_file, [
+ ("SleepActivity.kt", 80, 20),
+ ("run", 80, 0),
+ ("RunFunction", 20, 20),
+ ("SleepFunction", 20, 0),
+ ("line 24", 20, 0),
+ ("line 32", 20, 0)])
- self.run_cmd([inferno_script, "-sc"])
- self.check_inferno_report_html(
- [('com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.run',
- 80),
- ('com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.RunFunction',
- 20),
- ('com.example.simpleperf.simpleperfexampleofkotlin.SleepActivity$createRunSleepThread$1.SleepFunction',
- 20)])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
+ self.check_inferno_report_html([
+ (function_prefix + 'run', 80),
+ (function_prefix + 'RunFunction', 20),
+ (function_prefix + 'SleepFunction', 20)])
class TestProfilingCmd(TestBase):
@@ -819,8 +805,8 @@
if adb.switch_to_root():
self.run_cmd(["app_profiler.py", "-np", "surfaceflinger"])
self.run_cmd(["report.py", "-g", "-o", "report.txt"])
- self.run_cmd([inferno_script, "-sc"])
- self.run_cmd([inferno_script, "-np", "surfaceflinger"])
+ self.run_cmd([INFERNO_SCRIPT, "-sc"])
+ self.run_cmd([INFERNO_SCRIPT, "-np", "surfaceflinger"])
class TestReportLib(unittest.TestCase):
@@ -838,7 +824,6 @@
def test_symbol(self):
found_func2 = False
while self.report_lib.GetNextSample():
- sample = self.report_lib.GetCurrentSample()
symbol = self.report_lib.GetSymbolOfCurrentSample()
if symbol.symbol_name == 'func2(int, int)':
found_func2 = True
@@ -883,7 +868,8 @@
def test_record_cmd(self):
self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_trace_offcpu.data'))
self.assertEqual(self.report_lib.GetRecordCmd(),
- "/data/local/tmp/simpleperf record --trace-offcpu --duration 2 -g ./simpleperf_runtest_run_and_sleep64")
+ "/data/local/tmp/simpleperf record --trace-offcpu --duration 2 -g " +
+ "./simpleperf_runtest_run_and_sleep64")
def test_offcpu(self):
self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_trace_offcpu.data'))
@@ -927,6 +913,22 @@
report_lib.ShowArtFrames(True)
self.assertTrue(has_art_frame(report_lib))
+ def test_tracing_data(self):
+ self.report_lib.SetRecordFile(os.path.join('testdata', 'perf_with_tracepoint_event.data'))
+ has_tracing_data = False
+ while self.report_lib.GetNextSample():
+ event = self.report_lib.GetEventOfCurrentSample()
+ tracing_data = self.report_lib.GetTracingDataOfCurrentSample()
+ if event.name == 'sched:sched_switch':
+ self.assertIsNotNone(tracing_data)
+ self.assertIn('prev_pid', tracing_data)
+ self.assertIn('next_comm', tracing_data)
+ if tracing_data['prev_pid'] == 9896 and tracing_data['next_comm'] == 'swapper/4':
+ has_tracing_data = True
+ else:
+ self.assertIsNone(tracing_data)
+ self.assertTrue(has_tracing_data)
+
class TestRunSimpleperfOnDevice(TestBase):
def test_smoke(self):
@@ -1010,8 +1012,7 @@
actual_source = addr2line.get_addr_source(dso, test_addr['addr'])
self.assertTrue(actual_source is not None)
self.assertEqual(len(actual_source), len(expected_source))
- for i in range(len(expected_source)):
- actual_file_path, actual_line = actual_source[i]
+ for i, (actual_file_path, actual_line) in enumerate(expected_source):
self.assertEqual(actual_file_path, expected_source[i][0])
self.assertEqual(actual_line, expected_source[i][1])
@@ -1066,28 +1067,28 @@
def test_readelf(self):
test_map = {
- '/simpleperf_runtest_two_functions_arm64': {
- 'arch': 'arm64',
- 'build_id': '0xe8ecb3916d989dbdc068345c30f0c24300000000',
- 'sections': ['.interp', '.note.android.ident', '.note.gnu.build-id', '.dynsym',
- '.dynstr', '.gnu.hash', '.gnu.version', '.gnu.version_r', '.rela.dyn',
- '.rela.plt', '.plt', '.text', '.rodata', '.eh_frame', '.eh_frame_hdr',
- '.preinit_array', '.init_array', '.fini_array', '.dynamic', '.got',
- '.got.plt', '.data', '.bss', '.comment', '.debug_str', '.debug_loc',
- '.debug_abbrev', '.debug_info', '.debug_ranges', '.debug_macinfo',
- '.debug_pubnames', '.debug_pubtypes', '.debug_line',
- '.note.gnu.gold-version', '.symtab', '.strtab', '.shstrtab'],
- },
- '/simpleperf_runtest_two_functions_arm': {
- 'arch': 'arm',
- 'build_id': '0x718f5b36c4148ee1bd3f51af89ed2be600000000',
- },
- '/simpleperf_runtest_two_functions_x86_64': {
- 'arch': 'x86_64',
- },
- '/simpleperf_runtest_two_functions_x86': {
- 'arch': 'x86',
- }
+ '/simpleperf_runtest_two_functions_arm64': {
+ 'arch': 'arm64',
+ 'build_id': '0xe8ecb3916d989dbdc068345c30f0c24300000000',
+ 'sections': ['.interp', '.note.android.ident', '.note.gnu.build-id', '.dynsym',
+ '.dynstr', '.gnu.hash', '.gnu.version', '.gnu.version_r', '.rela.dyn',
+ '.rela.plt', '.plt', '.text', '.rodata', '.eh_frame', '.eh_frame_hdr',
+ '.preinit_array', '.init_array', '.fini_array', '.dynamic', '.got',
+ '.got.plt', '.data', '.bss', '.comment', '.debug_str', '.debug_loc',
+ '.debug_abbrev', '.debug_info', '.debug_ranges', '.debug_macinfo',
+ '.debug_pubnames', '.debug_pubtypes', '.debug_line',
+ '.note.gnu.gold-version', '.symtab', '.strtab', '.shstrtab'],
+ },
+ '/simpleperf_runtest_two_functions_arm': {
+ 'arch': 'arm',
+ 'build_id': '0x718f5b36c4148ee1bd3f51af89ed2be600000000',
+ },
+ '/simpleperf_runtest_two_functions_x86_64': {
+ 'arch': 'x86_64',
+ },
+ '/simpleperf_runtest_two_functions_x86': {
+ 'arch': 'x86',
+ }
}
readelf = ReadElf(None)
for dso_path in test_map:
@@ -1105,10 +1106,14 @@
class TestNativeLibDownloader(unittest.TestCase):
def test_smoke(self):
- self.adb = AdbHelper()
+ adb = AdbHelper()
+
+ def is_lib_on_device(path):
+ return adb.run(['shell', 'ls', path])
+
# Sync all native libs on device.
- self.adb.run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
- downloader = NativeLibDownloader(None, 'arm64', self.adb)
+ adb.run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
+ downloader = NativeLibDownloader(None, 'arm64', adb)
downloader.collect_native_libs_on_host(os.path.join(
'testdata', 'SimpleperfExampleWithNative', 'app', 'build', 'intermediates', 'cmake',
'profiling'))
@@ -1127,36 +1132,46 @@
downloader.sync_natives_libs_on_device()
downloader.collect_native_libs_on_device()
self.assertEqual(len(downloader.device_build_id_map), sync_count)
- for i in range(len(lib_list)):
- build_id = lib_list[i][0]
- name = lib_list[i][1].name
+ for i, item in enumerate(lib_list):
+ build_id = item[0]
+ name = item[1].name
if i < sync_count:
self.assertTrue(build_id in downloader.device_build_id_map)
self.assertEqual(name, downloader.device_build_id_map[build_id])
- self.assertTrue(self._is_lib_on_device(downloader.dir_on_device + name))
+ self.assertTrue(is_lib_on_device(downloader.dir_on_device + name))
else:
self.assertTrue(build_id not in downloader.device_build_id_map)
- self.assertFalse(self._is_lib_on_device(downloader.dir_on_device + name))
+ self.assertFalse(is_lib_on_device(downloader.dir_on_device + name))
if sync_count == 1:
- self.adb.run(['pull', '/data/local/tmp/native_libs/build_id_list',
- 'build_id_list'])
+ adb.run(['pull', '/data/local/tmp/native_libs/build_id_list', 'build_id_list'])
with open('build_id_list', 'rb') as fh:
self.assertEqual(fh.read(), '{}={}\n'.format(lib_list[0][0],
lib_list[0][1].name))
remove('build_id_list')
- self.adb.run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
+ adb.run(['shell', 'rm', '-rf', '/data/local/tmp/native_libs'])
- def _is_lib_on_device(self, path):
- return self.adb.run(['shell', 'ls', path])
+
+def list_tests():
+ tests = []
+ for name, value in globals().items():
+ if isinstance(value, type) and issubclass(value, unittest.TestCase):
+ test_methods = [x for x, y in value.__dict__.items()
+ if isinstance(y, types.FunctionType) and x.startswith('test')]
+ for method in test_methods:
+ tests.append(name + '.' + method)
+ print(' '.join(sorted(tests)))
def main():
+ if len(sys.argv) == 2 and sys.argv[1] == '--list-tests':
+ list_tests()
+ return
os.chdir(get_script_dir())
build_testdata()
if AdbHelper().get_android_version() < 7:
log_info("Skip tests on Android version < N.")
sys.exit(0)
- unittest.main(failfast=True)
+ unittest.main(failfast=True, verbosity=2)
if __name__ == '__main__':
main()
diff --git a/simpleperf/scripts/update.py b/simpleperf/scripts/update.py
index 53ac74f..65281aa 100644
--- a/simpleperf/scripts/update.py
+++ b/simpleperf/scripts/update.py
@@ -34,7 +34,7 @@
self.need_strip = need_strip
-install_list = [
+INSTALL_LIST = [
# simpleperf on device
InstallEntry('sdk_arm64-sdk', 'simpleperf', 'android/arm64/simpleperf'),
InstallEntry('sdk_arm64-sdk', 'simpleperf32', 'android/arm/simpleperf'),
@@ -51,18 +51,24 @@
InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86/simpleperf.exe', True),
# libsimpleperf_report.so on host
- InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report.so', 'linux/x86_64/libsimpleperf_report.so', True),
- InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report32.so', 'linux/x86/libsimpleperf_report.so', True),
- InstallEntry('sdk_mac', 'libsimpleperf_report.dylib', 'darwin/x86_64/libsimpleperf_report.dylib'),
+ InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report.so', 'linux/x86_64/libsimpleperf_report.so',
+ True),
+ InstallEntry('sdk_arm64-sdk', 'libsimpleperf_report32.so', 'linux/x86/libsimpleperf_report.so',
+ True),
+ InstallEntry('sdk_mac', 'libsimpleperf_report.dylib',
+ 'darwin/x86_64/libsimpleperf_report.dylib'),
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_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),
+ 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),
]
@@ -123,7 +129,7 @@
def install_new_release(branch, build, install_dir):
"""Installs the new release."""
- for entry in install_list:
+ for entry in INSTALL_LIST:
install_entry(branch, build, install_dir, entry)
@@ -139,9 +145,9 @@
os.chmod(name, exe_stat.st_mode | stat.S_IEXEC)
if need_strip:
check_call(['strip', name])
- dir = os.path.dirname(install_path)
- if not os.path.isdir(dir):
- os.makedirs(dir)
+ dirname = os.path.dirname(install_path)
+ if not os.path.isdir(dirname):
+ os.makedirs(dirname)
shutil.move(name, install_path)
@@ -185,4 +191,4 @@
if __name__ == '__main__':
- main()
\ No newline at end of file
+ main()
diff --git a/simpleperf/scripts/utils.py b/simpleperf/scripts/utils.py
index b224ce8..e14436f 100644
--- a/simpleperf/scripts/utils.py
+++ b/simpleperf/scripts/utils.py
@@ -69,17 +69,17 @@
def disable_debug_log():
logging.getLogger().setLevel(logging.WARN)
-def str_to_bytes(str):
+def str_to_bytes(str_value):
if not is_python3():
- return str
+ return str_value
# 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_value.encode('utf-8')
-def bytes_to_str(bytes):
+def bytes_to_str(bytes_value):
if not is_python3():
- return bytes
- return bytes.decode('utf-8')
+ return bytes_value
+ return bytes_value.decode('utf-8')
def get_target_binary_path(arch, binary_name):
if arch == 'aarch64':
@@ -94,21 +94,21 @@
def get_host_binary_path(binary_name):
- dir = os.path.join(get_script_dir(), 'bin')
+ dirname = os.path.join(get_script_dir(), 'bin')
if is_windows():
if binary_name.endswith('.so'):
binary_name = binary_name[0:-3] + '.dll'
elif '.' not in binary_name:
binary_name += '.exe'
- dir = os.path.join(dir, 'windows')
+ dirname = os.path.join(dirname, 'windows')
elif sys.platform == 'darwin': # OSX
if binary_name.endswith('.so'):
binary_name = binary_name[0:-3] + '.dylib'
- dir = os.path.join(dir, 'darwin')
+ dirname = os.path.join(dirname, 'darwin')
else:
- dir = os.path.join(dir, 'linux')
- dir = os.path.join(dir, 'x86_64' if sys.maxsize > 2 ** 32 else 'x86')
- binary_path = os.path.join(dir, binary_name)
+ dirname = os.path.join(dirname, 'linux')
+ dirname = os.path.join(dirname, 'x86_64' if sys.maxsize > 2 ** 32 else 'x86')
+ binary_path = os.path.join(dirname, binary_name)
if not os.path.isfile(binary_path):
log_fatal("can't find binary: %s" % binary_path)
return binary_path
@@ -121,7 +121,7 @@
stderr=subprocess.PIPE)
subproc.communicate()
return subproc.returncode == 0
- except:
+ except OSError:
return False
DEFAULT_NDK_PATH = {
@@ -304,6 +304,7 @@
if '86' in output:
return 'x86'
log_fatal('unsupported architecture: %s' % output.strip())
+ return ''
def get_android_version(self):
@@ -342,18 +343,14 @@
try:
subprocess.check_call(['open', report_path])
return
- except:
+ except subprocess.CalledProcessError:
pass
import webbrowser
try:
# Try to open the report with Chrome
- browser_key = ''
- for key, _ in webbrowser._browsers.items():
- if 'chrome' in key:
- browser_key = key
- browser = webbrowser.get(browser_key)
+ browser = webbrowser.get('google-chrome')
browser.open(report_path, new=0, autoraise=True)
- except:
+ except webbrowser.Error:
# webbrowser.get() doesn't work well on darwin/windows.
webbrowser.open_new_tab(report_path)
@@ -490,7 +487,7 @@
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(stdoutdata, _) = subproc.communicate(str_to_bytes(addr_request))
stdoutdata = bytes_to_str(stdoutdata)
- except:
+ except OSError:
return
addr_map = {}
cur_line_list = None
@@ -591,7 +588,7 @@
subproc = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(stdoutdata, _) = subproc.communicate()
stdoutdata = bytes_to_str(stdoutdata)
- except:
+ except OSError:
return None
if not stdoutdata:
diff --git a/simpleperf/test_util.h b/simpleperf/test_util.h
index 9508d96..006ae2f 100644
--- a/simpleperf/test_util.h
+++ b/simpleperf/test_util.h
@@ -61,6 +61,15 @@
} \
} while (0)
+bool HasHardwareCounter();
+#define TEST_REQUIRE_HW_COUNTER() \
+ do { \
+ if (!HasHardwareCounter()) { \
+ GTEST_LOG_(INFO) << "Skip this test as the machine doesn't have hardware PMU counters."; \
+ return; \
+ } \
+ } while (0)
+
class CaptureStdout {
public:
CaptureStdout() : started_(false) {}