为raspberrypi编译bpftrace调试工具
基于eBPF的嵌入式应用调试
笔者之前写过几篇有关于使用eBPF调试Linux内核和应用的博客,其中提到,在嵌入式设备上使用BCC或bpftrace是不可行的;主要原因在于嵌入式设备的资源有限,而这两个调试工具依赖python
/clang
/llvm
等库,需要将脚本编译为eBPF
字节码加载入Linux内核来执行。然而,随着嵌入式设备的性能越来越强,板载资源越来越多,在嵌入式设备上运行bpftrace
工具已成为可能。本文整理了笔者为raspberrypi 4
设备编译bpftrace
工具的过程,按照这些操作,笔者为工作中的嵌入式设备也制作了可用的bpftrace
调试工具。
另外,22.04版本的Ubuntu
系统自带的bpftrace
已经不能用了,主要的原因是它不带符号表(strip -s
);本文的内容也可用于PC
端的bpftrace
工具编译构建:
root@ubuntu:/usr/sbin# uname -a
Linux ubuntu 5.15.0-97-generic #107-Ubuntu SMP Wed Feb 7 13:26:48 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
root@ubuntu:/usr/sbin# ./execsnoop.bt
Attaching 3 probes...
ERROR: Could not resolve symbol: /proc/self/exe:BEGIN_trigger
编译使用的设备
首先,笔者使用的raspberrypi 4
可插入两张TF卡,两张卡分别安装了debian
系统和笔者编译的openwrt
系统,二者的Linux内核版本大致相同,均为6.1版本。其次,树莓派设备的内存大小为2GB,这一点非常重要;因为bcc/bpftrace
是由C++编写的,编译过程非常耗内存(笔者使用clang编译器构建)。最后,笔者是为了在openwrt
系统中使用bpftrace
,因此要求在构建openwrt
系统时,选择glibc库。
零,安装clang编译器
编译在是树莓派的debian系统上完成的。需要按照apt.llvm.org的说明操作来安装,笔者选择了安装clang-10
编译器:
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
./llvm.sh 10
之后,我们需要在debian安装其他依赖库(而不编译所有的依赖库,否则耗时太久了)。以下需要安装的库,是在raspberrypi/openwrt
系统上缺少的,后面会直接复制到安装有openwrt
系统的TF卡上:
sudo apt install flex bison zlib1g-dev liblzma-dev libbz2-dev cmake \libzstd-dev dwarves build-essential python3-setuptools libpython3-dev
一,编译elfutils
笔者下载了最新版本的elfutils,它提供了libelf
依赖库,该软件包的配置、编译操作如下:
../configure --prefix=/opt/bpftrace CC=clang-10 CXX=clang++-10 \CFLAGS='-Wall -fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -Wno-unused-parameter' \CXXFLAGS='-Wall -fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -Wno-unused-parameter' \--disable-nls --enable-libdebuginfod=dummy --disable-debuginfod --with-zlib --with-lzma \--with-bzlib --with-zstd LDFLAGS='-Wl,-rpath=/opt/bpftrace/lib'
make && sudo make install
以上配置完成后,再执行make && sudo make install
即可安装。
二,编译libbpf库
这里需要强调的是,依笔者的经验,libbpf
库以及bcc、bpftrace版本的选择,不能任意;一定要根据Linux内核版本来选择。例如,树苺派的Linux内核版本为6.1,那么确认该版本内核的(初始)发布日期(是2023年初发布的),然后选择时间上相近的libbpf
库。这里笔者选择的版本为libbpf-1.2.2
。然而工作中,笔者因使用的嵌入式设备比较老,使用的版本为0.1.1
。
该库的编译操作如下:
cd $HOME ; tar -zxf libbpf-1.2.2.tar.gz
cd libbpf-1.2.2/src
make V=1 PREFIX=/opt/bpftrace CC=clang-10 CFLAGS='-fPIC -O2 -ggdb -Wall -fno-omit-frame-pointer -I/opt/bpftrace/include' LDFLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib'
sudo make V=1 PREFIX=/opt/bpftrace CC=clang-10 CFLAGS='-fPIC -O2 -ggdb -Wall -fno-omit-frame-pointer -I/opt/bpftrace/include' LDFLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' install
注意,以上编译的库在debian/arm64
系统下会被安装到/opt/bpftrace/lib64
路径下,需要移到/opt/bpftrace/lib
路径下,并修改/opt/bpftrace/lib/pkgconfig/libbpf.pc
文件。
三,安装cereal头文件
早期的bpftrace
工具不依赖该库,但现在是需要了,笔者选择了cereal-1.3.2.tar.gz
版本:
mkdir -p build_aarch64 && cd build_aarch64
cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/bpftrace \-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 \-DCMAKE_C_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer' \-DCMAKE_CXX_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer' \-DBUILD_DOC=OFF -DBUILD_SANDBOX=OFF -DSKIP_PERFORMANCE_COMPARISON=ON -DBUILD_TESTS=OFF ..
sudo make install
注意,该库以头文件的形式提供,以上不会有动态库编译生成。
四,编译bcc
bcc的版本为v0.27.0,笔者已验证最新版本的bcc
编译得到的bpftrace
存在异常。需要注意的是,笔者下载的源代码文件名为bcc-src-with-submodule.tar.gz
。以下是配置、编译安装的操作:
mkdir -p build_aarch64 && cd build_aarch64
cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/bpftrace \-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 \-DCMAKE_C_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include' \-DCMAKE_CXX_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include' \-DCMAKE_EXE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_MODULE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_SHARED_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DENABLE_LLVM_SHARED=ON -DENABLE_TESTS=OFF -DRUN_LUA_TESTS=OFF -DENABLE_LIBDEBUGINFOD=OFF ..
make && sudo make install
编译完成后,笔者删除了所有的静态库(因为笔者希望所有的库是动态链接的):sudo rm -rf /opt/bpftrace/lib/*.a
。注意,这个编译过程比较耗时,大约持继在一小时以上。因rasbperrypi 4
内存有2GB,上面可以make -j2
来编译加速。
五,编译bpftrace
笔者选择的bpftrace
版本为v0.17.1
(正如上面提到的,笔者验证最新版本的bpftrace
在arm64/linux-6.1
系统下运行不正常。配置、编译安装的操作如下:
mkdir -p build_aarch64 && cd build_aarch64
cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/bpftrace \-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 \-DCMAKE_C_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include -I${HOME}/libbpf-1.2.2/include -I${HOME}/libbpf-1.2.2/include/uapi' \-DCMAKE_CXX_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include -I${HOME}/libbpf-1.2.2/include -I${HOME}/libbpf-1.2.2/include/uapi' \-DCMAKE_EXE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_MODULE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_SHARED_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DUSE_SYSTEM_BPF_BCC=ON -DSTATIC_LINKING=OFF -DALLOW_UNSAFE_PROBE=ON -DBUILD_TESTING=OFF ..
make && sudo make install
需要注意的是,上面的编译选项,直接指定了libbpf-1.2.2
头文件包含的路径。至此,笔者的编译就结束了,接下来将编译结果复制到安装有openwrt
系统的TF卡中。
在raspberrypi/openwrt系统下使用bpftrace
首先,除了/opt/bpftrace
外,笔者从树莓派的debian系统中复制了以下库到openwrt
系统:
root@OpenWrt:/lib/aarch64-linux-gnu# ls -lh -t | head -n 8
-rw-r--r-- 1 root root 64.8M Sep 9 22:40 libLLVM-10.so.1
-rw-r--r-- 1 root root 65.0K Sep 9 22:42 libbz2.so.1.0
-rw-r--r-- 1 root root 27.7M Sep 9 22:41 libclang-10.so.1
-rw-r--r-- 1 root root 179.1K Sep 9 22:43 libedit.so.2
-rw-r--r-- 1 root root 30.2K Sep 9 22:42 libffi.so.6
-rw-r--r-- 1 root root 130.2K Sep 9 22:41 liblzma.so.5
-rw-r--r-- 1 root root 158.6K Sep 9 22:43 libtinfo.so.5
-rw-r--r-- 1 root root 405.8K Sep 9 22:41 libzstd.so.1
然后,笔者为树莓派的内核使能了相关的内核选项,详见此处的详细说明。还有,bpftrace
的正常运行,可能还需要访问内核的头文件,这就需要使能CONFIG_IKHEADERS=m
,在树莓派启动后,手动加载该内核模块:insmod kheaders.ko
。最后,笔者在树莓派的openwrt
系统下使用bpftrace
的结果如下:
root@OpenWrt:~# insmod kheaders.ko
module is already loaded - kheaders
root@OpenWrt:~# uname -a
Linux OpenWrt 6.1.50 #0 SMP Fri Sep 1 21:45:47 2023 aarch64 GNU/Linux
root@OpenWrt:~# /opt/bpftrace/bin/bpftrace --info
SystemOS: Linux 6.1.50 #0 SMP Fri Sep 1 21:45:47 2023Arch: aarch64Buildversion: v0.17.1LLVM: 10.0.1unsafe uprobe: nobfd: nolibdw (DWARF support): yeslibbpf: failed to find valid kernel BTF
Kernel helpersprobe_read: yesprobe_read_str: yesprobe_read_user: yesprobe_read_user_str: yesprobe_read_kernel: yesprobe_read_kernel_str: yesget_current_cgroup_id: yessend_signal: yesoverride_return: noget_boot_ns: yesdpath: noskboutput: noKernel featuresInstruction limit: 1000000Loop support: yesbtf: nomap batch: yesuprobe refcount (depends on Build:bcc bpf_attach_uprobe refcount): yesMap typeshash: yespercpu hash: yesarray: yespercpu array: yesstack_trace: yesperf_event_array: yesProbe typeskprobe: yestracepoint: yesperf_event: yeskfunc: noiter:task: noiter:task_file: nokprobe_multi: noraw_tp_special: yesroot@OpenWrt:~# cd /opt/bpftrace/share/bpftrace/tools/
root@OpenWrt:/opt/bpftrace/share/bpftrace/tools# ls
bashreadline.bt gethostlatency.bt runqlen.bt tcpdrop.bt
biolatency.bt killsnoop.bt setuids.bt tcplife.bt
biosnoop.bt loads.bt ssllatency.bt tcpretrans.bt
biostacks.bt mdflush.bt sslsnoop.bt tcpsynbl.bt
bitesize.bt naptime.bt statsnoop.bt threadsnoop.bt
capable.bt old swapin.bt undump.bt
cpuwalk.bt oomkill.bt syncsnoop.bt vfscount.bt
dcsnoop.bt opensnoop.bt syscount.bt vfsstat.bt
doc pidpersec.bt tcpaccept.bt writeback.bt
execsnoop.bt runqlat.bt tcpconnect.bt xfsdist.bt
root@OpenWrt:/opt/bpftrace/share/bpftrace/tools# /opt/bpftrace/bin/bpftrace ./execsnoop.bt
libbpf: failed to find valid kernel BTF
libbpf: failed to find valid kernel BTF
Attaching 3 probes...
TIME(ms) PID ARGS
26138 2490 /etc/init.d/firewall reload
26168 2502 readlink /etc/init.d/firewall
26170 2503 basename /etc/init.d/firewall
26172 2504 flock -n 1000
26174 2505 flock 1000
26178 2506 readlink /etc/init.d/firewall
26181 2507 readlink /etc/init.d/firewall
26183 2508 basename /etc/init.d/firewall
26186 2509 flock -n 1000
26188 2510 fw4 reload
26191 2511 flock -x 1000
26193 2512 rm -f /var/run/fw4.state
26195 2513 utpl -S /usr/share/firewall4/main.uc
26195 2514 nft -f /dev/stdin
26303 2515 sh -c /usr/sbin/nft --terse --json list flowtables inet
26305 2515 /usr/sbin/nft --terse --json list flowtables inet
26393 2516 utpl -S /usr/share/firewall4/main.uc
29341 2517 /etc/init.d/firewall status
29371 2529 readlink /etc/init.d/firewall
29373 2530 basename /etc/init.d/firewall
29375 2531 flock -n 1000
29377 2532 flock 1000
29381 2533 readlink /etc/init.d/firewall
29384 2534 basename /etc/init.d/firewall
29387 2537 jsonfilter -e @["firewall"]
29388 2539 jshn -w
29391 2540 ubus call service list { "name": "firewall" }
29397 2543 jsonfilter -e $.instances
63078 2544 /etc/init.d/network status
63108 2556 readlink /etc/init.d/network
63110 2557 basename /etc/init.d/network
63112 2558 flock -n 1000
63114 2559 flock 1000
63118 2560 readlink /etc/init.d/network
63121 2561 basename /etc/init.d/network
63124 2564 jsonfilter -e @["network"]
63125 2566 jshn -w
63128 2567 ubus call service list { "name": "network" }
63134 2570 jsonfilter -e $.instances
63137 2571 jsonfilter -s { "instance1": { "running": true, "pid": 769, "command": [ "\/sbin\/netifd" ], "term_timeout": 5,
"limits": { "core": "unlimited" }, "respawn": { "threshold": 3600, "timeout": 5, "retry": 5 } } } -e $[*].running
^C
root@OpenWrt:/opt/bpftrace/share/bpftrace/tools#
至此,可以说明我们编译的bpftrace
工具可以正常工作了。
相关文章:

为raspberrypi编译bpftrace调试工具
基于eBPF的嵌入式应用调试 笔者之前写过几篇有关于使用eBPF调试Linux内核和应用的博客,其中提到,在嵌入式设备上使用BCC或bpftrace是不可行的;主要原因在于嵌入式设备的资源有限,而这两个调试工具依赖python/clang/llvm等库&…...

分段线性化问题探析
目录 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 4 matlab测试结果说明 5 分段线性化应用 1 使用0-1变量将分段函数转换为线性约束 2 连续函数采用分段线性化示例 3 matlab程序测试 clc;clear all; gn10;tn1; x_pfsdpvar(1, t…...

从零学算法2917
2917.给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 nums 中的 K-or 是一个满足以下条件的非负整数: 只有在 nums 中,至少存在 k 个元素的第 i 位值为 1 ,那么 K-or 中的第 i 位的值才是 1 。 返回 nums 的 K-or 值。 注意 …...

[HackMyVM] 靶场 Wave
kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…...

云渲染平台都开始涨价了?2024年性价比高的云渲染平台推荐
最近部分云渲染平台开始涨价,不论是通过调整机器性能,还是直接提价,都会对成本产生影响。这对已经习惯了平台价格的用户来说,并不是一件好事。这里举一些例子: 比如平台A,原“首小时渲染0.66元模式”已经下…...

搜索-BFS Meteor Shower S(流星雨)
Meteor Shower S(流星雨) 题目连接 题目描述 贝茜听说一场特别的流星雨即将到来:这些流星会撞向地球,并摧毁它们所撞击的任何东西。她为自己的安全感到焦虑,发誓要找到一个安全的地方(一个永远不会被流星…...

RabbitMQ实战:Springboot集成RabbitMQ并验证五种消息模型
这目录 一、添加依赖二、配置文件中添加RabbitMQ访问配置三、消息生产者代码四、消息消费者代码五、验证参考资料 一、添加依赖 <!--AMQP依赖,包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>s…...

配置与管理防火墙
配置与管理防火墙 1,概念:设置在不同网络或网络安全域之间的一系列部件的组合。 2,功能:保护内网中易手攻击的服务;控制内外网之间网络系统的访问;隐藏内网的IP地址及结构的细节,提高网络保护…...

【SpringBoot】-- 实现本地文件/图片上传到服务器生成url地址
在java项目中你可能会有以下需求:用户上传本地图片,然后展示在网页上。本篇文章将使用阿里云oss实现上传图片到oss,oss生成url。 一、准备工作 首先进入阿里云,按如下操作 进入创建页面,修改读写权限为公共读 然后进…...

计算机基础专升本笔记十四-计算机网络基础(一)
计算机基础专升本笔记十四-计算机网络基础(一) 一、计算机网络的发展历程 第一代计算机网络(数据通信) 以数据通信为主的第一代计算机网络。主要是指美国军方用于防控系统的一种联机系统。它只是计算机网络的雏形。 第二代计算…...

【华为OD机试】转盘寿司【C卷|100分】
【华为OD机试】-真题 !!点这里!! 【华为OD机试】真题考点分类 !!点这里 !! 题目描述 寿司店周年庆,正在举办优惠活动回馈新老客户。 寿司转盘上总共有 n 盘寿司,prices[i] 是第 i 盘寿司的价格, 如果客户选择了第 i 盘寿司,寿司店免费赠送客户距离第 i 盘寿司最近的下一…...

使用Node JS获取WI-FI密码
演示效果 全局安装wifi-password-cli依赖 shell 复制代码 npm install wifi-password-cli -g # or npx wifi-password-cli 使用 shell 复制代码 $ wifi-password [network-name] $ wifi-password 12345678 $ wifi-password 办公室wifi a1234b2345 觉得Node.js很神奇是…...

先缓存第二集抖音接入 ,最近加班猛,就分享简单的知识,如何使用:关于使用replace的用法正则表达式
1、需求:比如在cocos creator策划让你制作一个预制体,标题要读取配置,然后中间显示的内容要滚动的,要做成一个通用的,然后给到的配置表是这样子的: 配置表:假设字段是这样子的 content "内容标题&…...

企微hook源码
企微hook源码已经在QQ群内开源。速度进群下载,避免和谐。 QQ群:649480745...

vsphere虚拟机迁移是灰色如何解决
vsphere虚拟机迁移是灰色如何解决 问题描述: 在vsphere中,迁移虚拟机时迁移按钮是灰色,无法迁移,关机之后也无法迁移 虚拟机按钮为灰色 找到虚拟机存储对应的位置,查询是否有.vmx虚拟机文件 查询中发现有.vmx文件存…...

swift 闭包捕获列表
以下函数会打印出什么? var car "Benz" let closure { [car] in print("I drive \(car)") } car "Tesla" closure() 因为 clousre 已经申明将 car 复制进去了([car]),此时clousre 里的 car…...

JavaWeb04-Request,Response
目录 一、Request(请求) 1.作用 2.继承体系 3.获取请求数据 (1)请求行 (2)请求头 (3)请求体(POST) (5)Request通用方式获取请求…...

使用 Docker 部署 Fiora 在线聊天室平台
一、Fiora 介绍 Fiora 简介 Fiora 是一款开源免费的在线聊天系统。 GitHub:https://github.com/yinxin630/fiora Fiora 功能 注册账号并登录,可以长久保存你的数据加入现有群组或者创建自己的群组,来和大家交流和任意人私聊,并添…...

Unity Samples和帧动画的问题
拖动序列帧图片和自己创建clip的帧率不同 我今天在创建帧动画的时候用了两种方式第一种是直接拖动序列帧图片到Hierachy,然后生成的第二种是这样我发现两者播放的动画速率不一样最后查了半天查不到原因。最后发现是Samples的原因,而且Unity把Samples这个…...

几何工具的使用
Geometry - Creation 创建几何 CogCreateCircleTool:创建圆CogCreateEllipseTool:创建椭圆CogCreateLineBisectPointsTool:带有两个点的平行线CogCreateLineParallelTool:在某一点创建某条线的平行线CogCreateLinePerpendicularTool:在某一点创建某条线…...

sudo command not found
文章目录 一句话Intro其他操作 一句话 sudo 某命令 改成 sudo -i 某命令 试试。 -i 会把当前用户的环境变量带过去,这样在sudo的时候,有更高的权限,有本用户的环境变量(下的程序命令)。 -i, --login run login shell as the target user; a …...

1.【Labview白话系列】Labview数组精讲
题主经过写文章一段时间的发现,许多同学对该软件的理解和编程能力是不太一样的,有些知识相对一些同学较为简单,但是有些同学提问就比较困难。那么针对这个问题,题主打算出一期说白话系列的专栏,在该栏目中用最通俗的大…...

ANTLR4规则解析生成器(三):遍历语法分析树
文章目录 1 词法分析2 语法分析3 遍历语法分析树3.1 Listener3.2 Visitor 4 总结 1 词法分析 词法分析就是对给定的字符串进行分割,提取出其中的单词。 在antlr4中,词法规则的名称的首字母需要大写,右侧必须是终结符,通常将词法…...

OpenCV实现目标追踪
目录 准备工作 语言: 软件包: 效果演示 代码解读 (1)导入OpenCV库 (2)使用 cv2.VideoCapture 打开指定路径的视频文件 (3)使用 vid.read() 读取视频的第一帧,ret…...

【剑指offer--C/C++】JZ6 从尾到头打印链表
一、题目 二、本人思路及代码 直接在链表里进行翻转不太方便操作,但是数组就可以通过下标进行操作,于是, 思路1、 先遍历链表,以此存到vector中,然后再从后往前遍历这vector,存入到一个新的vector,就完成…...

算法-买卖股票的最佳时机
1、题目来源 121. 买卖股票的最佳时机 - 力扣(LeetCode) 2、题目描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖…...

【大数据】Flink SQL 语法篇(十):EXPLAIN、USE、LOAD、SET、SQL Hints
《Flink SQL 语法篇》系列,共包含以下 10 篇文章: Flink SQL 语法篇(一):CREATEFlink SQL 语法篇(二):WITH、SELECT & WHERE、SELECT DISTINCTFlink SQL 语法篇(三&…...

Java中List接口常见的实现类
目录 ArrayList实现类 数据存储 构造器 成员方法:CRUD Vector实现类 数据存储 构造器方法 成员方法 LinkedList实现类 数据存储 构造器方法 成员方法CRUD List总结 ArrayList:数组实现,随机访问速度快,增删慢&#x…...

SPI通信
SPI通信: 四根通信线:SCK,MOSI,MISO,SS(从机选择线) 同步时钟,全双工 支持总线挂载多个设备,一主多从 SPI相对IIC传输更快,最简单,最快速 SPI没有接收和应答机制,发送就发…...

【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 数论 区间合并 LeetCode3041. 修改数组后最大化数组中的连续元素数目 给你一个下标从 0 开始只包含 正 整数的数组 nums 。 一开始,你可以将数组中 任意数量 元素增加 至多 1 。 修改后,你可以从…...