关于安卓手机 的调试

adb管理手机

1 当前设备

手机开发者模式,在cmd下 输入adb devices

2 当前手机架构

adb shell
cat /proc/cpuinfo

关于安卓手机 的调试_第1张图片

3 手机时间获取

以下部分为引用 原址为
引用原网页
在x86架构中,我们对Time Stamp Counter (TSC) 寄存器非常熟悉,通过这个寄存器对代码执行时间的衡量可精确到CPU Cycle级别。但在ARM/ARMv8/aarch64架构中,并没有与x86 TSC对应的寄存器和直接对应的汇编指令 rdtsc

若想在ARMv8架构中,统计计算代码执行时间达到CPU Cycle级别,也需要读取类似x86的TSC寄存器。在ARMv8中,有Performance Monitors Control Register系列寄存器,其中PMCCNTR_EL0就类似于x86的TSC寄存器。以下介绍Linux下读取ARM TSC方法。
读取这个PMCCNTR_EL0寄存器值,就可以知道当前CPU已运行了多少Cycle。但在ARM下读取CPU Cycle和x86有所不同:

1、x86用户态代码可以随便读取TSC值。但在ARM,默认情况是用户态是不可以读的,需要在内核态使能后,用户态才能读取。

开关在由寄存器PMCR_EL0控制。实际上这个寄存器控制整个PMU寄存器在用户态是否可读写,不仅仅是PMCCNTR_EL0。

在内核态使能,可以是编写单独内核模块,也可以在内核代码任意被执行的位置加上设置使能PMU寄存器代码即可。Linux下使能(Enable)用户态访问PMU内核模块代码:

/*                                                                             
 * Enable user-mode ARM performance counter access.                            
 */                                                                           
#include                                                       
#include                                                       
#include                                                          


#define PERF_DEF_OPTS       (1 | 16)                                                                       
#define PERF_OPT_RESET_CYCLES   (2 | 4)                                                                  
#define PERF_OPT_DIV64      (8)                                                                          
#define ARMV8_PMCR_MASK         0x3f                                                                    
#define ARMV8_PMCR_E            (1 << 0) /* Enable all counters */                                      
#define ARMV8_PMCR_P            (1 << 1) /* Reset all counters */                                       
#define ARMV8_PMCR_C            (1 << 2) /* Cycle counter reset */                                      
#define ARMV8_PMCR_D            (1 << 3) /* CCNT counts every 64th cpu cycle */                         
#define ARMV8_PMCR_X            (1 << 4) /* Export to ETM */                                            
#define ARMV8_PMCR_DP           (1 << 5) /* Disable CCNT if non-invasive debug*/                        
#define ARMV8_PMCR_LC           (1 << 6) /* Cycle Counter 64bit overflow*/
#define ARMV8_PMCR_N_SHIFT      11       /* Number of counters supported */                             
#define ARMV8_PMCR_N_MASK       0x1f                                                                    

#define ARMV8_PMUSERENR_EN_EL0  (1 << 0) /* EL0 access enable */                                        
#define ARMV8_PMUSERENR_CR      (1 << 2) /* Cycle counter read enable */                                
#define ARMV8_PMUSERENR_ER      (1 << 3) /* Event counter read enable */                                

static inline u32 armv8pmu_pmcr_read(void)                                                              
{                                                                                                       
        u64 val=0;                                                                                      
        asm volatile("mrs %0, pmcr_el0" : "=r" (val));                                                  
        return (u32)val;                                                                                
}                                                                                                       
static inline void armv8pmu_pmcr_write(u32 val)                                                         
{                                                                                                       
        val &= ARMV8_PMCR_MASK;                                                                         
        isb();                                                                                          
        asm volatile("msr pmcr_el0, %0" : : "r" ((u64)val));                                            
}       

static inline  long long armv8_read_CNTPCT_EL0(void)
{
   long long val;
   asm volatile("mrs %0, CNTVCT_EL0" : "=r" (val));

   return val;
}


static void                                                                                            
enable_cpu_counters(void* data)                                                                         
{                                                                                                       
    u32 val=0;                                                         
    asm volatile("msr pmuserenr_el0, %0" : : "r"(0xf));
    armv8pmu_pmcr_write(ARMV8_PMCR_LC|ARMV8_PMCR_E);                                                      
        asm volatile("msr PMCNTENSET_EL0, %0" :: "r" ((u32)(1<<31)));
    armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_E|ARMV8_PMCR_LC);   
        printk("\nCPU:%d ", smp_processor_id());
}                                                                                                       

static void                                                                                            
disable_cpu_counters(void* data)                                                                        
{                                                                                                       
    u32 val=0;                                                                                             
    printk(KERN_INFO "\ndisabling user-mode PMU access on CPU #%d",                       
    smp_processor_id());                                                                                   

    /* Program PMU and disable all counters */                                                            
        armv8pmu_pmcr_write(armv8pmu_pmcr_read() |~ARMV8_PMCR_E);                                              
    asm volatile("msr pmuserenr_el0, %0" : : "r"((u64)0));                                                 

}                                                                                                       

static int __init                                                                                       
init(void)                                                                                              
{                                                                       
    u64 cval;
        u32 val;

        isb();
        asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(cval));
        printk("\nCPU Cycle count:%llu \n", cval);
        asm volatile("mrs %0, PMCNTENSET_EL0" : "=r"(val));
        printk("PMCNTENSET_EL0:%lX ", val);
        asm volatile("mrs %0, PMCR_EL0" : "=r"(val));
        printk("\nPMCR_EL0 Register:%lX ", val);

        on_each_cpu(enable_cpu_counters, NULL, 1);                                                             
        printk(KERN_INFO "Enable Access PMU Initialized");                                                       
    return 0;                                                                                              
}                                                                                                       

static void __exit                                                                                      
fini(void)                                                                                              
{                                                                                                       
    on_each_cpu(disable_cpu_counters, NULL, 1);                                                            
    printk(KERN_INFO "Access PMU Disabled");                                                          
}                                                                                                       

module_init(init);                                                                                      
module_exit(fini);

2、x86下TSC的值,在CPU上电后就开始累加,且是只读寄存器。但在ARM中,只有使能PMCCNTR_EL0后, TSC才开始累加计数,且PMCCNTR_EL0寄存器可清零,相当于计时器。

用户态读取ARMv8 PMU寄存器代码:
#include 
#include 
#include 

/* All counters, including PMCCNTR_EL0, are disabled/enabled */

#define QUADD_ARMV8_PMCR_E      (1 << 0)
/* Reset all event counters, not including PMCCNTR_EL0, to 0 */
#define QUADD_ARMV8_PMCR_P      (1 << 1)
/* Reset PMCCNTR_EL0 to 0 */
#define QUADD_ARMV8_PMCR_C      (1 << 2)
/* Clock divider: PMCCNTR_EL0 counts every clock cycle/every 64 clock cycles */
#define QUADD_ARMV8_PMCR_D      (1 << 3)
/* Export of events is disabled/enabled */
#define QUADD_ARMV8_PMCR_X      (1 << 4)
/* Disable cycle counter, PMCCNTR_EL0 when event counting is prohibited */
#define QUADD_ARMV8_PMCR_DP     (1 << 5)
/* Long cycle count enable */
#define QUADD_ARMV8_PMCR_LC     (1 << 6)

#define ARMV8_PMCR_MASK     0x3f     /* Mask for writable bits */

static inline unsigned int armv8_pmu_pmcr_read(void)
{
        unsigned int val;
        /* Read Performance Monitors Control Register */
        asm volatile("mrs %0, pmcr_el0" : "=r" (val));
        return val;
}
static inline void armv8_pmu_pmcr_write(unsigned int val)
{
    asm volatile("msr pmcr_el0, %0" : :"r" (val & ARMV8_PMCR_MASK));
}


static inline  long long armv8_read_CNTPCT_EL0(void)
{
   long long val;
   asm volatile("mrs %0, CNTVCT_EL0" : "=r" (val));

   return val;
}

static void enable_all_counters(void)
{

    return;
    unsigned int val;
    /* Enable all counters */
    val = armv8_pmu_pmcr_read();
    val |= QUADD_ARMV8_PMCR_E | QUADD_ARMV8_PMCR_X;
    armv8_pmu_pmcr_write(val);
}

static void reset_all_counters(void)
{

   return ; 
   unsigned int val;
    val = armv8_pmu_pmcr_read();
    val |= QUADD_ARMV8_PMCR_P | QUADD_ARMV8_PMCR_C;
    armv8_pmu_pmcr_write(val);
}

static unsigned int enabled=0;

unsigned int readticks(unsigned int *result)
{
    struct timeval t;
    unsigned int cc;
    unsigned int val;
    if (!enabled) {
        reset_all_counters();
        enable_all_counters();
        enabled = 1;
    }
    cc = armv8_pmu_pmcr_read();
    gettimeofday(&t,(struct timezone *) 0);
    result[0] = cc;
    result[1] = t.tv_usec;
    result[2] = t.tv_sec;

    return cc;
}


static inline unsigned int armv8pmu_pmcr_read(void)
{
    unsigned int val;
    asm volatile("mrs %0, pmcr_el0" : "=r" (val));
    return val;
}

#define u32 unsigned int
#define u64 unsigned long long
#define isb()       asm volatile("isb" : : : "memory")

static inline u64 arch_counter_get_cntpct(void)
{
    u64 cval;

    isb();
        asm volatile("mrs %0, PMCCNTR_EL0" : "+r"(cval));
    return cval;
}

int main()
{

  unsigned int start,end;
  unsigned int result[3]; 
  unsigned long long timer;
  u32 pmcr_el;

  pmcr_el = armv8pmu_pmcr_read();
  printf("\nPMCR_EL0 Register:%lX ", pmcr_el);
  timer = arch_counter_get_cntpct();
  printf("\nCPU Cycle Count:0x%llX ",timer);  
  sleep(5);
  timer = arch_counter_get_cntpct();
  printf("\nCPU Cycle Count:0x%llX \n",timer);
  asm volatile("mrs %0, PMOVSCLR_EL0" : "=r"(pmcr_el));
  printf(" Register PMOVSCLR_EL0:0x%lX \n", pmcr_el); 

  asm volatile("mrs %0, pmuserenr_el0" : "=r"(pmcr_el));
  printf(" Register pmuserenr_el0:0x%lX \n", pmcr_el);

  asm volatile("mrs %0, PMCNTENSET_EL0" : "=r"(pmcr_el));
  printf(" Register PMCNTENSET_EL0:0x%lX \n", pmcr_el);

  asm volatile("mrs %0, PMCCFILTR_EL0" : "=r"(pmcr_el));
  printf(" Register PMCCFILTR_EL0:0x%lX \n", pmcr_el);

  asm volatile("mrs %0, PMCNTENCLR_EL0" : "=r"(pmcr_el));
  printf(" Register PMCNTENCLR_EL0:0x%lX \n", pmcr_el);

  asm volatile("mrs %0, PMOVSSET_EL0" : "=r"(pmcr_el));
  printf(" Register PMOVSSET_EL0:0x%lX \n", pmcr_el);

  return 0;

}

相关参数含义如下
ram架构相关参数
关于安卓手机 的调试_第2张图片
关于安卓手机 的调试_第3张图片
关于安卓手机 的调试_第4张图片
关于安卓手机 的调试_第5张图片
The PMCR_EL0 can be accessed through the internal memory-mapped interface and the external debug interface, offset 0xE04

3测试结果

测试结果:
Linux linux 3.16.0+ #111 SMP Sat Mar 28 09:09:43 CST 2015 aarch64 aarch64 aarch64 GNU/Linux
linux:/home/hw-1020 # ./tsc_1
PMCR_EL0 Register:41013001
CPU Cycle Count:0x1364512659B
CPU Cycle Count:0x136C23FE71D

Register PMOVSCLR_EL0:0x80000000
Register pmuserenr_el0:0xF
Register PMCNTENSET_EL0:0x80000000
Register PMCCFILTR_EL0:0x8000000
Register PMCNTENCLR_EL0:0x80000000
Register PMOVSSET_EL0:0x80000000
linux:/home/hw-1020 # ./tsc_3

PMCR_EL0 Register:41013001
CPU Cycle Count:0x1399B0D6576
CPU Cycle Count:0x13B1291DDE0
Register PMOVSCLR_EL0:0x80000000
Register pmuserenr_el0:0xF
Register PMCNTENSET_EL0:0x80000000
Register PMCCFILTR_EL0:0x8000000
Register PMCNTENCLR_EL0:0x80000000
Register PMOVSSET_EL0:0x80000000
linux:/home/hw-1020 # ./tsc_5

PMCR_EL0 Register:41013001
CPU Cycle Count:0x13C2DF8BFAA
CPU Cycle Count:0x13E9FD420AB
Register PMOVSCLR_EL0:0x80000000
Register pmuserenr_el0:0xF
Register PMCNTENSET_EL0:0x80000000
Register PMCCFILTR_EL0:0x8000000
Register PMCNTENCLR_EL0:0x80000000
Register PMOVSSET_EL0:0x80000000
linux:/home/hw-1020 #
示例代码
相关源代码

时间获取函数 java

System.nanoTime

转载地址
为了拿到更精确地数值,没有使用System.currentTimeMillis(),而是贸然地使用System.nanoTime()来统计时间,后来分析服务器上的数据,发现 竟然有10-15%的数据数值竟然超过了 10的13次方。
原因:
System.currentTimeMillis() 起始时间是基于 1970.1.1 0:00:00 这个确定的时间的,而System.nanoTime()是基于cpu核心的时钟周期来计时,它的开始时间是不确定的。(有篇文章说是更加cpu核心的启动时间开始计算的)
但是在多核处理器上,由于每个核心的开始时间不确定,但是在多核处理器上,
java代码

long start = System.nanoTime();  
    String ip = Utilities.getIpByUrl(url);  
    long cost = System.nanoTime() - start; 

这段代码有可能会运行在两个不同的cpu核心上,从而导致得到的结果完全不符逻辑。
Returns the current timestamp of the most precise timer available on the local system, in nanoseconds. Equivalent to Linux’s CLOCK_MONOTONIC.
This timestamp should only be used to measure a duration by comparing it against another timestamp from the same process on the same device. Values returned by this method do not have a defined correspondence to wall clock times; the zero value is typically whenever the device last booted. Use currentTimeMillis() if you want to know what time it is.
只可以是单核条件下,且是测量时间差可用,虽然测量精度是纳秒级,但是多核条件无法不保证。

System.currentTimeMillis():

Returns the current time in milliseconds. Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
不保证精度,与操作系统有关。

探测时间函数 amgeddon

libflush、armv8、timing.h
inline uint64_t
arm_v8_get_timing(void)
{
uint64_t result = 0;

asm volatile(“MRS %0, PMCCNTR_EL0” : “=r” (result));

return result;
}

你可能感兴趣的:(获取精确时间,android,开发人员,架构)