LinuxTracingSystem浅析和eBPF开发经验分享

原创 Linux阅码场 2022-05-27 08:00

Ftrace公开课火热报名中:Ftrace公开课:站在设计者的角度来理解ftrace(限50人)。课程第一期报名已截止且已开课,第二期报名请咨询客服(小月微信:linuxer2016)。



个人介绍:

许庆伟,云安全公司内核技术专家,主要关注Linux Kernel & 容器的SecurityPerformance 


说明背景:

本文为主题分享《Linux Tracing System浅析 & eBPF框架开发分享》的会议整理和补充。主讲人杨润青,博士毕业于浙江大学,目前从事网络安全研究,研究方向包括高级威胁检测,攻击溯源与响应。


视频回放地址:

https://oxz.h5.xeknow.com/sl/JV1XI


PPT地址:

https://gitee.com/linuxkerneltravel/LearningLinuxKernel/tree/master/files/Linux%20Tracing%20System%20&&%20eBPF


一、讲座内容简要描述


本次讲座内容分为两部分


1) Linux Tracing System浅析 

当初学者接触到Linux平台的tracing系统时,常常被各种词语弄得晕头转向:比如 Kprobe,Tracepoint,Linux Auditing subsystem(auditd),systemtap,LTTng,perf,trace-cmd,eBPF,bpftrace,BCC等等。初学者往往会有以下疑问:这些专业词语是什么意思?它们之间有什么关系?每种tracing技术的优缺点是什么?应该选择哪种技术?为什么eBPF从中脱颖而出,近年来得到广泛关注?

 

本次讲座尝试从统一的视角来梳理和对比这些技术的异同点,并尝试回答这些问题。

 

2) eBPF开发经验分享

eBPF目前正在高速发展,很多坑和解决办法缺乏官方文档。本次讲座主要介绍主讲人在eBPF开发实践中经常遇到的问题,包括开发框架的选择,多内核版本兼容性问题,如何为低版本内核生成BTF文件,eBPF验证机制与编译器优化机制的不一致问题,eBPF在ARM架构遇到的问题等等。


二、Linux Tracing System浅析

 

对于Linux Tracing System尤其是目前最火的eBPF技术来说,主要是通过探针技术,实现特定事件的追踪和采样,达到增强内核行为可观测性、优化系统性能、动态监测网络和加固系统安全的目的。如下图所示,我将Linux Tracing System细分为三个维度,包括1)数据源(内核态),负责提供数据地来源;2)Tracing框架(内核态),负责对接数据源,采集解析发送数据,并对用户态提供接口;3)以及前端工具/库(用户态)对接Tracing内核框架,直接与用户交互,负责采集配置和数据分析

下面将从这三个维度自下而上地对Linux Tracing System进行梳理和分析。

 

 

  • 1.1. 数据源(内核态)介绍

 

如下图所示,从数据提供方的角度来看,数据源可以分成硬件探针、软件探针(又分为动态探针以及静态探针),也就是获取底层数据源的方式和手段。顾名思义,硬件探针技术就是通过在硬件设备上(比如芯片)插入探针,捕获硬件层次行为;而软件探针技术则是通过软件的方式插入探针,捕获软件层次的行为。这些探针技术负责提供数据,上层的Tracing工具和框架则基于这些探针技术来采集数据,并对数据进一步整理、分析、和展现给用户。

 


  • 硬件探针

  • HPC: Hardware Performance Counter 是CPU硬件提供的一种常见的数据源,如下图所示,它能够监控CPU级别的事件,比如执行的 指令数,跳转指令数,Cache Miss等等,被广泛应用于性能调试(Vtune, Perf)、攻击检测等等


       1) HPC事件列表

 


        2)HPC数据案例

        对于此类硬件数据,我们通常使用用户态工具perf来进行采集,下图展示了一个具体的案例。



  • LBR: Last Branch Record CPU硬件提供的另一种特性,它能够记录每条分支(跳转)指令的源地址和目的地址。基于LBR硬件特性,可实现调用栈信息的记录


在系统性能优化领域以及调试程序时经常使用的性能分析利器:火焰图(Flame Graph)也可以基于LBR的数据生成,使用命令perf record -F 99 -a --call-graph lbr即可得到完整直观的火焰图数据。

 

 

火焰图示例

 

  • 软件探针(静态探针):

    静态内核探针指的内核运行之前,在内核源代码或者二进制中插入预先设置好的钩子函数,内核运行时触发生效的探针方案。

  • Tracepoint: Tracepoint是一种典型的静态探针。它通过在内核源代码中插入预先定义的静态钩子函数来实现内核行为的监控。简单地来看,大家可以把Tracepoint的原理等同于调试程序时加入的printf函数。

下图展示了2012年,内核引入sched_process_exec Tracepoint时的commit,可以看到,首先用TRACE_EVENT宏定义了新增Tracepoint的名字和参数等信息,然后在内核函数exec_binprm的源代码中加入了钩子函数trace_sched_process_exec。每当程序执行二进制时,都会触发exec_binprm函数,继而触发trace_sched_process_exec钩子函数。Tracing工具和框架将自定义的函数挂载到该钩子函数上,来采集程序执行行为日志。



  • 静态探针的优点:

        稳定(内核开发者会负责维护该函数的稳定性)

        性能好

  • 静态探针的缺点

        需要修改内核代码来添加新的静态探针

        内核支持的静态探针数量有限

  • 软件探针(动态探针):

有了静态探针,为什么还需要动态探针呢?主要原因是静态探针都是人工添加的,支持的数量有限,而动态探针就是为了解决这个问题,它能够支持Hook几乎所有的内核函数。

  • KprobesKprobe是一个典型的动态探针,如下图所示,在内核运行时,Kprobe技术将需要监控的内核函数的指令动态替换,使得该函数的控制流跳转到用户自定义的处理函数上。当内核执行到该监控函数时,相应的用户自定义处理函数被执行,然后继续执行正常的代码路径。

 


  • 动态探针的优点:

 可以Hook几乎所有的内核函数 

  • 动态探针的缺点

 不稳定(函数的变更、编译器的优化等都可能导致采集程序的失效)

 性能相对较差

 

  • 软件探针(动/静态探针):

静态探针性能好,但支持的数量有限,动态探针支持的数量多,但不稳定、性能相对较差,那么是否存在一种技术,能同时兼顾静态和动态的优势呢?答案是动静态结合的探针方案。

  • Function Hooks(Ftrace): Function HooksFtrace引入一种动静态结合的探针方案 如下图所示,静态指的是它通过gcc编译器,在内核编译阶段,在内核函数的入口处插入了预留的特定指令,当内核运行时,它会将预留的特定指令替换为跳转指令(call ftrace_caller),使得内核函数的控制流跳转到用户自定义函数上,达到数据监控的目的。

 


 FtraceFunction Tracer

 

  • Function Hooks(Ftrace)的优点

相比于Tracepoint和Kprobe,Function Hooks最显著的功能性特点是它能够方便地监控内核函数的调用关系,如下图所示,监控了内核函数exec_binprm的所有子函数调用关系。



上面分析完各种动态和静态探针的方案和优缺点后,从开发者代码多功能可控的角度出发,建议优先使用静态探针方案。

 

  • 1.2. Linux Tracing System 发展历程

 

2004年4月,Linux Auditing subsystem(auditd)被引入内核2.6.6-rc1

2005年4月,Kprobe被引入内核2.6.11.7

2006年,LTTng发布(至今没有合入内核)

2008年10月 ,Kernel Tracepoint 被引入内核(v2.6.28)。

2008年,Ftrace被引入内核(包括compile time function hooks)。

2009年,perf被引入内核

2009年,SystemTap发布(至今没有合入内核)

2014年Alexei Starovoitov将eBPF引入内核


  • 1.3. Linux Tracing 框架方案对比

 


eBPF的优势对比:

稳定:通过验证器,防止用户编写的程序导致内核崩溃

免安装:eBPF内置于linux内核,无需安装额外以来

内核编程:支持开发者插入自定义的代码逻辑(包括数据采集、分析和过滤)到内核中运行

 

2. eBPF框架开发分析

 

  • 2.1 eBPF基础架构


eBPF程序分为两部分: 用户态和内核态代码。


eBPF内核代码:

  • 这个代码首先需要经过编译器(比如LLVM)编译成eBPF字节码,然后字节码会被加载到内核执行。所以 这部分代码理论上用什么语言编写都可以,只要编译器支持将该语言编译为eBPF字节码即可。

  • 目前绝大多数工具都是用的C语言来编写eBPF内核代码,包括BCC。

  • bpftrace提供了一种易用的脚本语言来帮助用户快速高效的使用eBPF功能,其背后的原理还是利用LLVM 将脚本转为eBPF字节码。

eBPF用户态代码: 

  • 这部分代码负责将eBPF内核程序加载到内核,与eBPF MAP交互,以及接收eBPF内核程序发送出来的数据。这个功能的本质上是通过Linux OS提供的syscall(bpf syscall + perf_event_open syscall)完成的,因此这 部分代码你可以用任何语言实现。比如BCC使用python,libbpf使用c或者c++,TRACEE使用Go等等。

 


  • 2.2 eBPF数据源

 

性能分析大师Brendan Gregg(Intel Fellow)总结的Linux BPF Tracing Tools上展示了丰富多彩的eBPF钩子类型,这些钩子类型提供了可以加载BPF程序的范围。

fentry/fexit

Tracepoints

network devices (tc/xdp)

network routes

TCP congestion algorithms

sockets (data level)

kernel functions (kprobes)

userspace functions (uprobes)

system calls 



  • 2.3 eBPF框架的发展历程

 

2014年9月 引入了bpf() syscall,将eBPF引入用户态空间。

自带迷你libbpf库,简单对bpf()进行了封装,功能是将eBPF字节码加载到内核。

2015年2月份 Kernel 3.19 引入bpf_load.c/h文件,对上述迷你libbpf库再进行封装,功能是将eBPF elf二进制文件加载到内核(目前已过时,不建议使用)。

2015年4月 BCC项目创建,提供了eBPF一站式编程。

1. 创建之初,基于上述迷你libbpf库来加载eBPF字节码。

2. 提供了Python接口。

2015年11月 Kernel 4.3 引入标准库 libbpf

1. 该标准库由Huawei 2012 OS内核实验室的王楠提交。

2018年 为解决BCC的缺陷,CO-RE(Compile Once, Run Everywhere)的想法被提出并实现,最后达成共识:libbpf + BTF + CO-RE代表了eBPF的未来,BCC底层实现逐步转向libbpf。


  • 2.4 eBPF可移植性痛点和解决方案


  • 技术痛点

在内核版本A上编译的eBPF程序,无法直接在另外一个内核版本B上运行。造成可以执行差的根本原因在于eBPF程序访问的内核数据结构(内存空间)是不稳定的,经常随内核版本更迭而变化。

目前使用BCC的方案通过在部署机器上动态编译eBPF源代码可以来解决移植性问题。每一次eBPF程序运行都需要进行一次编译,而且需要在部署机器上按照上百兆大小的依赖,如编译器和头文件Clang/LLVM + Linux headers等。同时在Clang/LLVM编译过程中需要消耗大量的资源(CPU/内存),对业务性能也会造成很大影响。


  • 解决方案(CO-RE Compile OnceRun Everywhere):


1) BTF:将内核数据结构信息高效压缩和存储(相比于DWARF,可达到超过100倍的 压缩比)

2) LLVM/Clang编译器:编译eBPF代码的时候记录下relocation相关的信息

3) Libbpf:基于BTF和编译器提供的信息,动态relocate数据结构

 

其中BTF为重要组成部分,Linux Kernel 5.2及以上版本自带BTF文件,低版本需要手动移植。

 

通过分析内核源码,可以发现BTF文件的生成并不需要改动内核,只依赖:

  • 带有debug info的vmlinux image

  • pahole

  • LLVM

这意味着,我们可以自己为低版本内核生产BTF文件,以此让低内核版本支持CORE。


  • 低版本内核BTF文件


准备工作

 ·安装pahole软件(1.16+)

 ·https://git.kernel.org/pub/scm/devel/pahole/pahole.git

 ·安装LLVM(11+)

 ·获取目标低版本内核的vmlinux文件(带有debug info),文件保存在{vmlinux_file_path}

 ·通过源下载

·比如对于CentOS,通过yum install kernel-debuginfo可以下载vmlinux

 ·源码编译内核,获取vmlinux

 

生成BTF: 

 ·利用pahole在vmlinux文件中生成BTF信息,执行以下命令:

·pahole -J {vmlinux_file_path}

 ·将BTF信息单独输出到新文件{BTF_file_path},执行以下命令:

 ·llvm-objcopy --only-section=.BTF --set-section-flags .BTF=alloc,readonly --strip- all {vmlinux_file_path} {BTF_file_path}

 ·去除非必要的符号信息,降低BTF文件的大小,得到最终的BTF文件(大小约2~3MB):

 ·strip -x {BTF_file_path}

 

  • 2.5 eBPF程序实例分析(一个Print引发的惨案)

 

eBPF程序会被LLVM编译为eBPF字节码,eBPF字节码需要通过eBPF Verifier的(静态)验证后,才能真正运行。边界检查是eBPF Verifier的重点工作,目的是为了防止eBPF程序内存越界访问。接下来通过在eBPF程序中简单的增加、删减print打印信息触发不同原因的几种边界检查异常导致验证失败的例子,进一步讲解深层的原理。

 

  • 程序实验环境:

1) LLVM 11

2) Linux Kernel 5.8

3) Libbpf commit @9c44c8a

 

  • 边界检查案例:

1) 内存越界:


SEC("kprobe/do_unlinkat")int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name){  // 获取一个数组指针array(数组MAX_SIZE为16个字节)  u32 key = 0;  char *array = bpf_map_lookup_elem(&array_map, &key);  if (array == NULL)    return 0;  // 获取当前运行程序的CPU编号(当前机器的CPU有16个核)  unsigned int pos = bpf_get_smp_processor_id();       // 根据下表修改数组的值      array[pos] = 1;      return 0;}


上述代码编译运行后,提示Verifier失败,然后使用objdump命令来看一下具体的字节码,通过以下字节码程序,可以看到Verifier失败的原因在于第14行R6寄存器(变量pos)没有进行边界检查导致。

  • Root Cause:

  • 当eBPF Verifier走到第14行的时候尝试去访问array数组,但是此时数组的下标pos是来自bpf_get_smp_processor_id获取到的unsigned int 类型的动态变量,此时Verifier无法判断变量的具体数值,所以会保守认为可能会达到最大值,这样的话就会超出array数组的范围,造成内存越界。

 

0000000000000000 :;int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name) 0:r1 = 0;  u32 key = 0;1:  *(u32 *)(r10 - 4) = r12:  r2 = r103:  r2 += -4;      char *array = bpf_map_lookup_elem(&array_map, &key); 4:r1 = 0 ll6:  call 17:  r6 = r0;  if (array == NULL)8:  if r6 == 0 goto +6 ;      unsigned int pos = bpf_get_smp_processor_id();; 9:call 8;      array[pos] = 1; 10:r0 <<= 3211:  r0 >>= 3212:  r6 += r013:  r1 = 1;    array[pos] = 1;14:  *(u8 *)(r6 + 0) = r1

 

  • 解决方案:

 添加边界检查代码

if (pos < MAX_SIZE)   if r0 > 15 goto +3 


2) Verifier验证机制和编译器优化机制不一致导致边界检查不通过

 

① 使用错误寄存器做边界检查:


SEC("kprobe/do_unlinkat")
int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name){ // 获取一个数组指针array(数组MAX_SIZE为16个字节) u32 key = 0; char *array = bpf_map_lookup_elem(&array_map, &key); if (array == NULL) return 0; // 获取当前运行程序的CPU编号(当前机器的CPU有16个核) unsigned int pos = bpf_get_smp_processor_id();; // 修改数值 if (pos < MAX_SIZE){ array[pos] = 1; pos += 1; } // debug代码,输出一些上下文信息 bpf_printk("debug %d %d %d\n", bpf_get_current_pid_tgid() >> 32, bpf_get_current_pid_tgid(), array[1]); // 修改数值 if (pos < MAX_SIZE) array[pos] = 1; return 0;}

 

编译这个代码后Verifier验证通过,可以正常运行。但是此时如果把bpf_printk打印信息删掉,竟然提示Verifier验证失败,原因是R0寄存器(变量pos)没有通过边界检查,但是明明已经加了边界检查代码,怎么还会出现问题,这么神奇!

  • Root Cause:



由于编译器的优化策略,导致删减bpf_printk后编译生成的eBPF字节码使用寄存器r1(表示pos变量)来进行边界检查,但是却用r0+1(同样表示pos变量)来访问数组array。

相比之下,从eBPF verifier的角度来看,由于在编译过程中,r1和r0+1的关联性丢失了,导致eBPF verifier无法知道pos变量已经通过了检查,因此错误的认为pos变量没有进行边界检查,不允许程序运行。


②寄存器溢出或重新加载后,状态丢失:


SEC("kprobe/do_unlinkat")
int BPF_KPROBE(do_unlinkat, int dfd, struct filename *name){  // 获取一个数组指针array(数组MAX_SIZE为16个字节) u32 key = 0; char *array = bpf_map_lookup_elem(&array_map, &key); if (array == NULL) return 0; // 获取当前运行程序的CPU编号(当前机器的CPU有16个核) unsigned long pos = bpf_get_smp_processor_id();; // 修改数值 if (pos < MAX_SIZE){ for (unsigned long i = 0; i < MAX_SIZE; i++) bpf_printk("debug %d %d %d\n", bpf_get_current_pid_tgid() >> 32, \ bpf_get_current_pid_tgid(), array[i]); array[pos] = 1; } return 0;}

 

在上述边界检查代码中添加一段print调试打印信息后编译验证又会出现Verifier失败,通过排查发现不是已知的两类问题,依然使用objdump查看添加后的字节码信息。


  • Root Cause:



加入bpf_printk后通过字节码可以看到,代码先使用R0(表示pos变量)进行边界检查。由于当前寄存器数量不足,编译器决定将将R0临时保存到栈上的空间(R10-16,在eBPF字节码中,R10存储存放着 eBPF 栈空间的栈帧指针的地址),这样R0就可以空闲出来,留给其他代码使用,我们称这种行为为寄存器溢出(register spill)。当真正需要使用pos变量的时候,编译器会从栈上(R10-16)将之前保存的内容取出来赋给R1(也表示pos变量),然后使用R1对数组array进行访问。但神奇的是,当寄存器溢出发生时,pos变量的状态丢失了,eBPF忘记了该变量曾经进行了边界检查,导致程序无法通过验证。

 

  • 解决方案:

在源码中加入 &= 操作符,引导编译器生成理想的eBPF字节码

array[pos &= MAX_SIZE - 1] = 1;

如果上述方法失效,无法引导编译器,那么针对出错的部分源代码人工编写eBPF字节码,替代编译器生成的字节码

#define STR(s) #s #define XSTR(s) STR(s)#define asm_variable_bound_check(variable)\({\  asm volatile (\    "%[tmp] &= " XSTR(MAX_SIZE - 1) " \n"  \    :[tmp]"+&r"(variable)\  );\})asm_check(pos);array[pos] = 1;

 

3. 总结

 

  本文总结了从动静态探针的角度梳理分析Linux Tracing System以及实例解决eBPF程序中遇到的问题。eBPF目前正在高速发展,很多坑和解决办法缺乏官方文档。本文在以下几点上做了自己的分析和分享,希望对大家更清晰的认识Linux Tracing System和eBPF有所帮助。

 

1. 自下而上的方式分析动静态探针

2. 各种场景下动静态探针的选择

3. BPF开发框架的选择

4. 多内核版本兼容性问题

5. 如何为低版本内核生成BTF文件

6. eBPF边界检查问题分析

7. eBPF Verifier验证机制与编译器优化机制不一致问题



往期精华文章:【精华】Linux阅码场原创精华文章汇总



阅码场付费会员专业交流群

会员招募:各专业群会员费为88元/季度,权益包含群内提问,线下活动8折,全年不定期群技术分享(普通用户直播免费,分享后每次点播价为19元/次),有意加入请私信客服小月(小月微信号:linuxer2016)


专业群介绍:

彭伟林-阅码场内核性能与稳定性
本群定位内核性能与稳定性技术交流,覆盖云/网/车/机/芯领域资深内核专家,由阅码场资深讲师彭伟林主持。


甄建勇-性能优化与体系结构

本群定位Perf、cache和CPU架构技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师甄建勇主持。


李春良-Xenomai与实时优化

本群定位Xenomai与实时优化技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师李春良和彭伟林共同主持。


周贺贺-Tee和ARM架构

本群定位Tee和ARM架构技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师周贺贺主持。


谢欢-Linux tracers

本群定位Linux tracers技术交流,覆盖云/网/车/机/芯领域资深用户,由阅码场资深讲师谢欢主持。



Linux阅码场 专业的Linux技术社区和Linux操作系统学习平台,内容涉及Linux内核,Linux内存管理,Linux进程管理,Linux文件系统和IO,Linux性能调优,Linux设备驱动以及Linux虚拟化和云计算等各方各面.
评论
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 58浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 120浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 68浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 73浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 102浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 116浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 111浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 87浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 103浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 119浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦