ARM PMU

PMU单元概览

ARM PMU概要
PMU作为一个扩展功能,是一种非侵入式的调试组件。
对PMU寄存器的访问可以通过CP15协处理器指令和Memory-Mapped地址。

基于PMUv2架构,A7处理器在运行时可以收集关于处理器和内存的各种统计信息。对于处理器来说这些统计信息中的事件非常有用,你可以利用它们来调试或者剖析代码。

更详细内容参考:
《Arm CoreSight Performance Monitoring Unit Architecture》:关于PMU架构介绍,包括寄存器解释、规格、安全等等。
《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》:介绍了PMU在Armv7-A/R中的实现。
《Chapter C12 The Performance Monitors Extension》:PMU基本功能介绍
《Appendix D2 Recommended Memory-mapped and External Debug Interfaces for the Performance Monitors》:PMU寄存器介绍。

在这里插入图片描述

PMU 配置流程

PMU有两个主流版本PMUv2和PMUv3,其中大部分32位ARM的处理器使用的PMUv2,大部分64位ARM的处理器使用的PMUv3。两者的主要区别是读取相关寄存器的汇编命令不一样,PMUv2 寄存器是通过CP15 协处理器和外部APB接口来编程,PMUv3则是可以直接使用寄存器的名字来通过mrs和msr命令来读取。

设置和使用事件计数器
本节概述了在Cortex-A15(Armv7-A)上设置和使用事件计数器所需的步骤。Armv8-A处理器的步骤相似,尽管可能会有一些细微的变化。

您可以选择不激活周期计数器(标记为可选的步骤)。这不会影响事件计数器,因为它们独立于周期计数器。如果不需要读出周期数,则可以关闭计数器,这将减少PMU对系统的性能影响。

(不是必需的)启用PMU用户态访问(即允许在EL0操作PMU相关寄存器),如果你要测的代码是在用户态,那么你必须要把性能监视器用户启用寄存器(PMUSERENR)中的EN,bit [0]设置为1。如果仅在内核态使用(即EL1)则不必设置PMUSERENR寄存器。
启用PMU–在性能监视器控制寄存器(PMCR)中,将E,bit [0]设置为1。 配置事件计数器
在性能监视器事件计数器选择寄存器(PMSELR)中,将计数器编号(0-5)写入您要配置的SEL位[4:0],即选用那个计数器。
在性能监视器事件类型选择寄存器(PMXEVTYPER)中,将事件编号(从event事件列表中,见上表)写入evtCount,bits [7:0],以便选择计数器正在监视的事件。
启用已配置的事件计数器 -在性能监视器计数启用设置寄存器 (PMCNTENSET)中,将Px,bit[x](其中x对应于要启用的计数器0-5)设置为1。
(可选)启用周期计数器(CCNT) -在性能监视器计数启用设置寄存器(PMCNTENSET)中,将C,bit [31]设置为1。
(可选)重置周期计数器(CCNT) -在性能监视器控制寄存器(PMCR)中,将C,bit [2]设置为1。
重置事件计数器 -在性能监视器控制寄存器(PMCR)中,将P,bit [1]设置为1。
现在配置了计数器,并将在执行继续时监视感兴趣的事件。

(可选)禁用周期计数器(CCNT)-在性能监视器计数启用清除寄存器(PMCNTENCLR)中,将C,bit [31]设置为1。
禁用事件计数器 -在性能监视器计数启用清除寄存器(PMCNTENCLR)中,将Px,bit
[x](其中x对应于要禁用的计数器0-5)设置为1。 读取事件计数器的值
在性能监视器事件计数器选择寄存器(PMSELR)中,将计数器号(0-5)写入到您要读取的SEL位[4:0]。
所选计数器的值存储在性能监视器所选事件计数寄存器(PMXEVCNTR)中。
(可选)读取周期计数器(CCNT)的值-周期计数器的值存储在性能监视器周期计数寄存器(PMCCNTR)中。

PMU驱动的实现 纯汇编版本

pmu_v7.S

/*------------------------------------------------------------
Performance Monitor Block
------------------------------------------------------------*/
    .arm @ Make sure we are in ARM mode.
    .text
    .align 2
    .global getPMN @ export this function for the linker

/* Returns the number of progammable counters uint32_t getPMN(void) */

getPMN:
  MRC p15, 0, r0, c9, c12, 0 /* Read PMNC Register */
  MOV r0, r0, LSR #11 /* Shift N field down to bit 0 */
  AND r0, r0, #0x1F /* Mask to leave just the 5 N bits */
  BX lr

  

    .global pmn_config @ export this function for the linker
  /* Sets the event for a programmable counter to record */
  /* void pmn_config(unsigned counter, uint32_t event) */
  /* counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1) */
  /* event = r1 = The event code */
pmn_config:
  AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
  MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
  MCR p15, 0, r1, c9, c13, 1 /* Write EVTSELx Register */
  BX lr

  

    .global ccnt_divider @ export this function for the linker
  /* Enables/disables the divider (1/64) on CCNT */
  /* void ccnt_divider(int divider) */
  /* divider = r0 = If 0 disable divider, else enable dvider */
ccnt_divider:
  MRC p15, 0, r1, c9, c12, 0 /* Read PMNC */

  CMP r0, #0x0 /* IF (r0 == 0) */
  BICEQ r1, r1, #0x08 /* THEN: Clear the D bit (disables the divisor) */
  ORRNE r1, r1, #0x08 /* ELSE: Set the D bit (enables the divisor) */

  MCR p15, 0, r1, c9, c12, 0 /* Write PMNC */
  BX lr
 

  /* --------------------------------------------------------------- */
  /* Enable/Disable */
  /* --------------------------------------------------------------- */

    .global enable_pmu @ export this function for the linker
  /* Global PMU enable */
  /* void enable_pmu(void) */
enable_pmu:
  MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  ORR r0, r0, #0x01 /* Set E bit */
  MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  BX lr
 


    .global disable_pmu @ export this function for the linker
  /* Global PMU disable */
  /* void disable_pmu(void) */
disable_pmu:
  MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  BIC r0, r0, #0x01 /* Clear E bit */
  MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  BX lr
 
  

    .global enable_ccnt @ export this function for the linker
  /* Enable the CCNT */
  /* void enable_ccnt(void) */
enable_ccnt:
  MOV r0, #0x80000000 /* Set C bit */
  MCR p15, 0, r0, c9, c12, 1 /* Write CNTENS Register */
  BX lr
 
  

    .global disable_ccnt @ export this function for the linker
  /* Disable the CCNT */
  /* void disable_ccnt(void) */
disable_ccnt:
  MOV r0, #0x80000000 /* Clear C bit */
  MCR p15, 0, r0, c9, c12, 2 /* Write CNTENC Register */
  BX lr
 
  

    .global enable_pmn @ export this function for the linker
  /* Enable PMN{n} */
  /* void enable_pmn(uint32_t counter) */
  /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1) */
enable_pmn:
  MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  MOV r1, r1, LSL r0

  MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
  BX lr

  

    .global disable_pmn @ export this function for the linker
  /* Enable PMN{n} */
  /* void disable_pmn(uint32_t counter) */
  /* counter = r0 = The counter to enable (e.g. 0 for PMN0, 1 for PMN1) */
disable_pmn:
  MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  MOV r1, r1, LSL r0

  MCR p15, 0, r1, c9, c12, 1 /* Write CNTENS Register */
  BX lr
 
  
  
    .global enable_pmu_user_access @ export this function for the linker
  /* Enables User mode access to the PMU (must be called in a priviledged mode) */
  /* void enable_pmu_user_access(void) */
enable_pmu_user_access:
  MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
  ORR r0, r0, #0x01 /* Set EN bit (bit 0) */
  MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
  BX lr
  
  
  
    .global disable_pmu_user_access @ export this function for the linker
  /* Disables User mode access to the PMU (must be called in a priviledged mode) */
  /* void disable_pmu_user_access(void) */
disable_pmu_user_access:
  MRC p15, 0, r0, c9, c14, 0 /* Read PMUSERENR Register */
  BIC r0, r0, #0x01 /* Clear EN bit (bit 0) */
  MCR p15, 0, r0, c9, c14, 0 /* Write PMUSERENR Register */
  BX lr


  /* --------------------------------------------------------------- */
  /* Counter read registers */
  /* --------------------------------------------------------------- */

    .global read_ccnt @ export this function for the linker
  /* Returns the value of CCNT */
  /* uint32_t read_ccnt(void) */
read_ccnt:
  MRC p15, 0, r0, c9, c13, 0 /* Read CCNT Register */
  BX lr


    .global read_pmn @ export this function for the linker
  /* Returns the value of PMN{n} */
  /* uint32_t read_pmn(uint32_t counter) */
  /* counter = r0 = The counter to read (e.g. 0 for PMN0, 1 for PMN1) */
read_pmn:
  AND r0, r0, #0x1F /* Mask to leave only bits 4:0 */
  MCR p15, 0, r0, c9, c12, 5 /* Write PMNXSEL Register */
  MRC p15, 0, r0, c9, c13, 2 /* Read current PMNx Register */
  BX lr
  
  
  /* --------------------------------------------------------------- */
  /* Software Increment */
  /* --------------------------------------------------------------- */

    .global pmu_software_increment @ export this function for the linker
        /* Writes to software increment register */
        /* void pmu_software_increment(uint32_t counter) */
        /* counter = r0 = The counter to increment (e.g. 0 for PMN0, 1 for PMN1) */
pmu_software_increment:
  MOV r1, #0x01
  MOV r1, r1, LSL r0
  MCR p15, 0, r1, c9, c12, 4 /* Write SWINCR Register */
  BX lr

  /* --------------------------------------------------------------- */
  /* Overflow & Interrupt Generation */
  /* --------------------------------------------------------------- */

    .global read_flags @ export this function for the linker
  /* Returns the value of the overflow flags */
  /* uint32_t read_flags(void) */
read_flags:
  MRC p15, 0, r0, c9, c12, 3 /* Read FLAG Register */
  BX lr
  

    .global write_flags @ export this function for the linker
  /* Writes the overflow flags */
  /* void write_flags(uint32_t flags) */
write_flags:
  MCR p15, 0, r0, c9, c12, 3 /* Write FLAG Register */
  BX lr
  

    .global enable_ccnt_irq @ export this function for the linker
  /* Enables interrupt generation on overflow of the CCNT */
  /* void enable_ccnt_irq(void) */
enable_ccnt_irq:
  MOV r0, #0x80000000
  MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
  BX lr

    .global disable_ccnt_irq @ export this function for the linker
  /* Disables interrupt generation on overflow of the CCNT */
  /* void disable_ccnt_irq(void) */
disable_ccnt_irq:
  MOV r0, #0x80000000
  MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
  BX lr
  

    .global enable_pmn_irq @ export this function for the linker
  /* Enables interrupt generation on overflow of PMN{x} */
  /* void enable_pmn_irq(uint32_t counter) */
  /* counter = r0 = The counter to enable the interrupt for (e.g. 0 for PMN0, 1 for PMN1) */
enable_pmn_irq:
  MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  MOV r0, r1, LSL r0
  MCR p15, 0, r0, c9, c14, 1 /* Write INTENS Register */
  BX lr

    .global disable_pmn_irq @ export this function for the linker
  /* Disables interrupt generation on overflow of PMN{x} */
  /* void disable_pmn_irq(uint32_t counter) */
  /* counter = r0 = The counter to disable the interrupt for (e.g. 0 for PMN0, 1 for PMN1) */
disable_pmn_irq:
  MOV r1, #0x1 /* Use arg (r0) to set which counter to disable */
  MOV r0, r1, LSL r0
  MCR p15, 0, r0, c9, c14, 2 /* Write INTENC Register */
  BX lr

  /* --------------------------------------------------------------- */
  /* Reset Functions */
  /* --------------------------------------------------------------- */

    .global reset_pmn @ export this function for the linker
  /* Resets the programmable counters */
  /* void reset_pmn(void) */
reset_pmn:
  MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  ORR r0, r0, #0x02 /* Set P bit (Event Counter Reset) */
  MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  BX lr


        .global reset_ccnt @ export this function for the linker
  /* Resets the CCNT */
  /* void reset_ccnt(void) */
reset_ccnt:
  MRC p15, 0, r0, c9, c12, 0 /* Read PMNC */
  ORR r0, r0, #0x04 /* Set C bit (Event Counter Reset) */
  MCR p15, 0, r0, c9, c12, 0 /* Write PMNC */
  BX lr

 
    .end @end of code, this line is optional.
/* ------------------------------------------------------------ */
/* End of v7_pmu.s */
/* ------------------------------------------------------------ */

pmu_v7.h

// ------------------------------------------------------------
// PMU for Cortex-A/R (v7-A/R)
// ------------------------------------------------------------

#ifndef _V7_PMU_H
#define _V7_PMU_H

// Returns the number of progammable counters
unsigned int getPMN(void);

// Sets the event for a programmable counter to record
// counter = r0 = Which counter to program (e.g. 0 for PMN0, 1 for PMN1)
// event = r1 = The event code (from appropiate TRM or ARM Architecture Reference Manual)
void pmn_config(unsigned int counter, unsigned int event);

// Enables/disables the divider (1/64) on CCNT
// divider = r0 = If 0 disable divider, else enable dvider
void ccnt_divider(int divider);

//
// Enables and disables
//

// Global PMU enable
// On ARM11 this enables the PMU, and the counters start immediately
// On Cortex this enables the PMU, there are individual enables for the counters
void enable_pmu(void);

// Global PMU disable
// On Cortex, this overrides the enable state of the individual counters
void disable_pmu(void);

// Enable the CCNT
void enable_ccnt(void);

// Disable the CCNT
void disable_ccnt(void);

// Enable PMN{n}
// counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
void enable_pmn(unsigned int counter);

// Enable PMN{n}
// counter = The counter to enable (e.g. 0 for PMN0, 1 for PMN1)
void disable_pmn(unsigned int counter);

//
// Read counter values
//

// Returns the value of CCNT
unsigned int read_ccnt(void);

// Returns the value of PMN{n}
// counter = The counter to read (e.g. 0 for PMN0, 1 for PMN1)
unsigned int read_pmn(unsigned int counter);

//
// Overflow and interrupts
//

// Returns the value of the overflow flags
unsigned int read_flags(void);

// Writes the overflow flags
void write_flags(unsigned int flags);

// Enables interrupt generation on overflow of the CCNT
void enable_ccnt_irq(void);

// Disables interrupt generation on overflow of the CCNT
void disable_ccnt_irq(void);

// Enables interrupt generation on overflow of PMN{x}
// counter = The counter to enable the interrupt for (e.g. 0 for PMN0, 1 for PMN1)
void enable_pmn_irq(unsigned int counter);

// Disables interrupt generation on overflow of PMN{x}
// counter = r0 = The counter to disable the interrupt for (e.g. 0 for PMN0, 1 for PMN1)
void disable_pmn_irq(unsigned int counter);

//
// Counter reset functions
//

// Resets the programmable counters
void reset_pmn(void);

// Resets the CCNT
void reset_ccnt(void);

//
// Software Increment

// Writes to software increment register
// counter = The counter to increment (e.g. 0 for PMN0, 1 for PMN1)
void pmu_software_increment(unsigned int counter);

//
// User mode access
//

// Enables User mode access to the PMU (must be called in a priviledged mode)
void enable_pmu_user_access(void);

// Disables User mode access to the PMU (must be called in a priviledged mode)
void disable_pmu_user_access(void);

#endif
// ------------------------------------------------------------
// End of v7_pmu.h
// ------------------------------------------------------------

使用demo

#include "v7_pmu.h"
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int random_range(int max);
void pmu_start(unsigned int event0,unsigned int event1,unsigned int event2,unsigned int event3,unsigned int event4,unsigned int event5);
void pmu_stop(void);

int main ( int argc, char *argv[] ){
int matrix_size;
int i,j,k,z;



// To access CPU time
clock_t start, end;
double cpu_time_used;

  if ( argc != 2 ) {
    fputs ( "usage: $prog n", stderr );
    exit ( EXIT_FAILURE );
        }

    matrix_size = (int)strtol(argv[1],NULL,10);


printf("square matrix size = %dn", matrix_size);


/*Using time function output for seed value*/
        unsigned int seed = (unsigned int)time(NULL);
        srand(seed);

/* Initialize square matrix with command line input value */
int a[matrix_size][matrix_size], b[matrix_size][matrix_size], c[matrix_size][matrix_size];

/* Intialize both A[][] and B[][] with random values between 0-5 and set C[][] to zero*/
        for(i=0;i<matrix_size;i++){
                for(j=0;j<matrix_size;j++){
                a[i][j]=random_range(6);
                b[i][j]=random_range(6);
                c[i][j]=0;
                }
        }

/* Multiply A[][] and B[][] and store into C[][]*/
 start = clock();



for(z=0;z<7;z++){
        if(z==0)
        pmu_start(0x01,0x02,0x03,0x04,0x05,0x06);
        if(z==1)
        pmu_start(0x07,0x08,0x09,0x0A,0x0B,0x0C);
        if(z==2)
        pmu_start(0x0D,0x0E,0x0F,0x10,0x11,0x12);
        if(z==3)
        pmu_start(0x50,0x51,0x60,0x61,0x62,0x63);
        if(z==4)
        pmu_start(0x64,0x65,0x66,0x67,0x68,0x6E);
        if(z==5)
        pmu_start(0x70,0x71,0x72,0x73,0x74,0x81);
        if(z==6)
        pmu_start(0x82,0x83,0x84,0x85,0x86,0x8A);

   for(i=0; i<matrix_size; i++)
   {
         for(j=0; j<matrix_size; j++)
         {
            for(k=0; k<matrix_size; k++)
            {
                  /* c[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]; */
                  c[i][j] += a[i][k]*b[k][j];
            }
         }
  }

        pmu_stop();

}
    end = clock();
    cpu_time_used = (end - start) / ((double) CLOCKS_PER_SEC);

printf("CPU time used = %.4lfn",cpu_time_used);
printf("square matrix size = %dn", matrix_size);


  return 0;
}

int random_range(int max){
    return ((rand()%(max-1)) +1);
}



void pmu_start(unsigned int event0,unsigned int event1,unsigned int event2,unsigned int event3,unsigned int event4,unsigned int event5){

  enable_pmu(); // Enable the PMU
  reset_ccnt(); // Reset the CCNT (cycle counter)
  reset_pmn(); // Reset the configurable counters
  pmn_config(0, event0); // Configure counter 0 to count event code 0x03
  pmn_config(1, event1); // Configure counter 1 to count event code 0x03
  pmn_config(2, event2); // Configure counter 2 to count event code 0x03
  pmn_config(3, event3); // Configure counter 3 to count event code 0x03
  pmn_config(4, event4); // Configure counter 4 to count event code 0x03
  pmn_config(5, event5); // Configure counter 5 to count event code 0x03

  enable_ccnt(); // Enable CCNT
  enable_pmn(0); // Enable counter
  enable_pmn(1); // Enable counter
  enable_pmn(2); // Enable counter
  enable_pmn(3); // Enable counter
  enable_pmn(4); // Enable counter
  enable_pmn(5); // Enable counter

  printf("CountEvent0=0x%x,CountEvent1=0x%x,CountEvent2=0x%x,CountEvent3=0x%x,CountEvent4=0x%x,CountEvent5=0x%xn", event0,event1,event2,event3,event4,event5);
}

void pmu_stop(void){
  unsigned int cycle_count, overflow, counter0, counter1, counter2, counter3, counter4, counter5;

  disable_ccnt(); // Stop CCNT
  disable_pmn(0); // Stop counter 0
  disable_pmn(1); // Stop counter 1
  disable_pmn(2); // Stop counter 2
  disable_pmn(3); // Stop counter 3
  disable_pmn(4); // Stop counter 4
  disable_pmn(5); // Stop counter 5

  counter0 = read_pmn(0); // Read counter 0
  counter1 = read_pmn(1); // Read counter 1
  counter2 = read_pmn(2); // Read counter 2
  counter3 = read_pmn(3); // Read counter 3
  counter4 = read_pmn(4); // Read counter 4
  counter5 = read_pmn(5); // Read counter 5

  cycle_count = read_ccnt(); // Read CCNT
  overflow=read_flags(); //Check for overflow flag

  printf("Counter0=%d,Counter1=%d,Counter2=%d,Counter3=%d,Counter4=%d,Counter5=%dn", counter0, counter1,counter2,counter3,counter4,counter5);
  printf("Overflow flag: = %d, Cycle Count: = %d nn", overflow,cycle_count);
}

ARMv8 支持的事件列表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ARMv7 支持的事件

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

参考文档

https://blog.csdn.net/qq1798831241/article/details/108188200: ARM PMU详解及使用
https://blog.csdn.net/chichi123137/article/details/80145914: ARM CPU 之 PMU部件(性能监控单元)
arm文档:Using the PMU and the Event Counters in DS-5
https://zhuanlan.zhihu.com/p/276680818: perf_event框架之:ARM PMU硬件
https://github.com/afrojer/armperf/blob/master/v7_pmu.S :PMU PERF
http://t.csdnimg.cn/g5a8k

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/144016.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Moto edge s pro手机 WIFI和蓝牙连接不上 解决方法分享

2021年12月入手一台Moto Edge S Pro 12256版&#xff0c;看着性价比很高&#xff0c;越用越垃圾。屏幕显示没有vivo亮丽/APP图标很丑/屏幕上一点点水就失灵/拍照片边缘是模糊的/系统几乎不更新。 以上都可以忍受&#xff0c;但是&#xff1a; 用一年不到&#xff0c;蓝牙不能…

【数据结构】深入了解栈

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、栈的基本概念二、栈实现方法的分析与选择2.1 引入2.2 顺序表实现2.3 链表实现2.3.1…

全国犯罪人数大数据可视化平台【可视化项目案例-08】

🎉🎊🎉 你的技术旅程将在这里启航! 🚀🚀 本文选自专栏:可视化技术专栏100例 可视化技术专栏100例,包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章底部可下载对应案例源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不…

将铜互连扩展到2nm的研究

晶体管尺寸在3nm时达到临界点&#xff0c;纳米片FET可能会取代finFET来满足性能、功耗、面积和成本目标。同样&#xff0c;正在评估2nm铜互连的重大架构变化&#xff0c;此举将重新配置向晶体管传输电力的方式。 芯片制造商也可能会在2nm节点开始用钌或钼在一定程度上取代铜。…

网上第一批购买大王卡的用户都怎么样了?

近日&#xff0c;小编看到有网友在网上发帖询问&#xff0c;网上第一批购买大王卡的用户都怎么样了&#xff1f;一时间得到纷纷得到回应。 小编也汇总了一些回复&#xff0c;大家可以看一看&#xff1a; 因为大王卡是一张定向流量卡&#xff0c;所以在使用时很多软件都是需要额…

列出目录内最大十个文件并排序

在Linux中&#xff0c;可以使用以下命令列出目录内最大的十个文件并排序&#xff1a; find ./ -type f -print0 | xargs -0 du -h | sort -rh | head -n 10 find ./ -type f -print0: find命令用于在指定目录下查找文件。这里&#xff0c;我们在当前目录下查找所有的文件&…

在AI时代提升个人晋升力的策略

✍️作者简介&#xff1a;沫小北/码农小北&#xff08;专注于Android、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a;沫小北/码农小北 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&…

Java map 详解 - 用法、遍历、排序、常用API等

概要&#xff1a; java.util 中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。 Map 提供了一个更通用的元素存储方法。Map 集合类用于存储元素对&#xff08;称作“键”和“值”&#xff09;&#xff0c;其中每个键映射到一个值。 本文主要介绍java m…

cesium 自定义顶点属性

// 创建平面const planeGeometry new Cesium.PlaneGeometry({vertexFormat: Cesium.VertexFormat.POSITION_AND_ST, // 位置和UV});const geometry Cesium.PlaneGeometry.createGeometry(planeGeometry);// [3]-----[2]// | |// [0]-----[1]geometry.attributes.color…

Echart 极坐标 方位距离图 图标符号旋转以及大小 颜色渐变

背景&#xff1a; 参与一个交互式图表项目&#xff0c;客户有一个极坐标对比需求&#xff0c;展示不同方位不同距离的不同类型的指标数据。具体到属性字段则是&#xff1a; 来源、距离、方位、ID、旋转角度、大小 先看效果图&#xff1a; 技术点&#xff1a; 图例说明&#…

二、服务拆分及远程调用

目录 一、注意事项&#xff1a; 1.单一职责: 2.数据独立: 3.面向服务&#xff1a; 二、服务拆分例子&#xff1a; 三、远程调用例子&#xff1a; 微服务调用方式&#xff1a; 四、提供者与消费者 服务调用关系&#xff1a; 一、注意事项&#xff1a; 1.单一职责: 不同…

新用户可一次性买3年的优惠云服务器,看到价格泪奔了!

本文将综合介绍腾讯云主推的4款云服务器配置及其价格&#xff0c;并重点强调其特点和优势。其中两款3年的优惠云服务器&#xff0c;非常值得新用户选择&#xff01; 一、入门级配置&#xff1a;2核4G 5M带宽&#xff0c;一年166元 这款入门级配置适合初学者或者对资源需求不高…

淘宝API接口开发系列,获取商品详情,按关键词搜索商品,拍立淘,商品评论销量商品类目,买家卖家订单接口等演示案例

关键词推荐API接口通过提供相关的关键词推荐&#xff0c;能够帮助用户更快捷地搜索、改善用户体验&#xff0c;同时也对于SEO优化、广告投放、内容创作和个性化推荐等方面有着重要的作用。 item_search-按关键字搜索淘宝商品 公共参数 名称类型必须描述keyString是调用key&am…

一文简单聊聊protobuf

目录 基本介绍 原理 同类对比 为什么要使用protobuf? 基本介绍 protobuf的全称是Protocol Buffer&#xff0c;是Google提供的一种数据序列化协议。Protocol Buffers 是一种轻便高效的结构化数据存储格式&#xff0c;可以用于结构化数据序列化&#xff0c;很适合做数据存储…

Vue 3.0 + vite + axios+PHP跨域问题的解决办法

最后一个Web项目&#xff0c;采用前后端分离。 前端&#xff1a;Vue 3.0 viteelement plus 后端&#xff1a;PHP 运行时前端和后端是两个程序&#xff0c;前端需要时才向后端请求数据。由于是两个程序&#xff0c;这就会出现跨域问题。 比如前端某个地方需要请求的接口如下…

2023年度实用Figma插件大放送!

根据统计&#xff0c;自2018年以来&#xff0c;Sketch的使用率已经从42%下降到31%&#xff0c;而Figma的使用率已经从12%上升到26%。为什么Figma如此受欢迎&#xff1f;为什么有越来越多的设计师倾向于使用Figma做设计&#xff1f;其实Figma现在除了给用户带来的丝滑的操作体验…

KT148A语音芯片的下载用的是串口,测试可以直接串口发指令控制吗

一、问题简介 KT148A语音芯片的下载用的是串口&#xff0c;那我实际测试是不是可以直接串口发指令测试控制&#xff1f;就不用单独写程序去模拟一线串口的时序了 详细描述 首先看一下KT148A芯片的参考设计原理图&#xff1a;其中芯片的2脚和3脚就是串口&#xff0c;注意下载语…

跨国企业在数据跨境传输中应该知道的五大要点

随着全球化的加速和数字化经济的蓬勃发展&#xff0c;数据跨境传输已经成为跨国企业日常业务运营中的重要环节。然而&#xff0c;在数据跨境传输过程中&#xff0c;企业需要关注一系列问题&#xff0c;以确保遵守法律法规、保障数据安全、提高传输效率并降低风险。本文将探讨数…

Office LTSC 2021 v16.80

Office 2021 for Mac是一款针对Mac用户推出的办公软件套装&#xff0c;包括了Word、Excel、PowerPoint、Outlook等常用的办公软件。相比于之前的版本&#xff0c;Office 2021 for Mac也进行了一些更新和改进&#xff0c;以提高用户的使用体验和效率。 以下是Office 2021 for M…

Python使用Mechanize库完成自动化爬虫程序

Mechanize是一个Python第三方库&#xff0c;它可以模拟浏览器的行为&#xff0c;实现自动化的网页访问、表单填写、提交等操作。下面是一个使用Mechanize库编写的爬虫的例子&#xff0c;它可以爬取百度搜索结果页面的标题和链接&#xff1a; import mechanize from bs4 import …