当前位置: 首页 > news >正文

RISC-V hardfault分析工具,RTTHREAD-RVBACKTRACE

RV BACKTRACE

简介

本文主要讲述RV BACKTRACE 的内部主要原理

没有接触过rvbacktrace可以看下面两篇文章,理解一下如何使用RVBACKTRACE

RVBacktrace RISC-V极简栈回溯组件:https://club.rt-thread.org/ask/article/64bfe06feb7b3e29.html

RVBacktrace RISC-V极简栈回溯组件V1.2:https://club.rt-thread.org/ask/article/09737357e4a95b06.html

RVBACKTRACE

https://github.com/Yaochenger/RvBacktrace

rvbacktrace更多的利用RISCV的一些特性

组件支持两种方式栈回溯,默认使用配置简单的方式一。

方式一:不添加编译参数,通过调用栈结构进行栈回溯,默认是方式一。

优点:不额外占用系统寄存器 缺点:增加代码空间,效率较方式二较低

方式二:通过添加编译参数的方式,基于FP寄存器进行栈回溯。

优点:几乎不增加代码空间 缺点:占用s0寄存器,

rvbacktrace有两种方法,一种是编译器编译的时候,添加-fno-omit-frame-pointer, 另一个是编译器在默认情况下,会优化frame-pointer。

我们来理解一下什么是-fno-omit-frame-pointer

  • -fno-omit-frame-pointer: 这里有个no-omit 大概意思是,不要忽略,或者不要优化,frame-pointer是一个寄存器,代表是帧指针寄存器。
  • 默认情况下是-fomit-frame-pointer: 这里是忽略帧指针。

先讲下两个配置,类似于一个是优化掉帧指针(代码中不保存帧指针),一个是-fno-omit-frame-pointer 不优化帧指针。

我们来看下优化和不优化的区别:

这个是加了-fno-omit-frame-pointer的函数:

void rvbacktrace_fno()
{
8000e02c:	1141                	addi	sp,sp,-16
8000e02e:	c606                	sw	ra,12(sp)
8000e030:	c422                	sw	s0,8(sp)
8000e032:	c226                	sw	s1,4(sp)
8000e034:	0800                	addi	s0,sp,16

这个是没有加-fno-omit-frame-pointer的函数:

void rvbacktrace_fno()
{
8000d7c6:	1141                	addi	sp,sp,-16
8000d7c8:	c606                	sw	ra,12(sp)
8000d7ca:	c422                	sw	s0,8(sp)

差异是什么呢?多了两条指令

8000e032:	c226                	sw	s1,4(sp)
8000e034:	0800                	addi	s0,sp,16

来讲下大概原理:

加了-fno-omit-frame-pointer 之后,s0寄存器就不能用来通用功能了,只能用来作为fp使用,用来保存sp的初始值(即进函数之前的值)

在这里插入图片描述

帧指针就是用来保存上一次的SP的地址,然后该地址可以用来读到上一次函数的地址。ra地址就是类似于ARM中的LR的地址,就是返回的函数的地址。

从下面这张图中可以看到,加了-fno-omit-frame-pointer 之后,默认当前代码的S0就是进该函数刚进来的时候SP值,然后固定下面两个寄存器保存的是RA和FP这个位置没有变
在这里插入图片描述

所以对于rv_backtrace_fno.c中的核心函数,就可以按照下面的写法写。

        sp = (unsigned long) _backtrace_threadn->sp;fp = ((rt_ubase_t *) (_backtrace_threadn->sp))[BACKTRACE_FP_POS]; // get current frame pointerwhile (1){frame = (struct stackframe *) (fp - BACKTRACE_LEN); //   get frame pointerif ((uint32_t *) frame > (uint32_t *) (uintptr_t) _rt_eusrstack){rvstack_frame_len = num;rvbacktrace_addr2line((uint32_t *) &rvstack_frame[0]);num = 0;break;}sp = fp;  // get stack pointerfp = frame->s_fp; // get frame pointerra = frame->s_ra; // get return addresspc = frame->s_ra - 4; // get program counter//  print stack interval, return address, program counterBACKTRACE_PRINTF("[%d]Stack interval :[0x%016lx - 0x%016lx]  ra 0x%016lx pc 0x%016lx\n", num, sp, fp, ra, pc);rvstack_frame[num] = pc; // save stack frame addressnum++;}

RVBACKTRACE的通用改法

在编译器还没有加-fno-omit-frame-pointer 代码中需要从PC往上找

这里第一步就是找到1141这条指令,然后计算出立即数16,根据当前的SP值,然后计算出进函数之前的SP值。

void rvbacktrace_fno()
{
8000d7c6:	1141                	addi	sp,sp,-16
8000d7c8:	c606                	sw	ra,12(sp)
8000d7ca:	c422                	sw	s0,8(sp)

在函数riscv_backtraceFromStack 中就是计算SP值,计算也是为了适配64bit和32bit的RISCV,计算出SP的原始值,然后再往上继续找对应的函数,保存下来。

   /* 1. scan code, find lr pushed */for (i = 0; i < BT_FUNC_LIMIT;) {/* FIXME: not accurate from bottom to up. how to judge 2 or 4byte inst *///CodeAddr = (char *)(((long)PC & (~0x3)) - i);//非对齐访问CodeAddr = (char *)(PC - i);ins32 = *(unsigned int *)(CodeAddr);if ((ins32 & 0x3) == 0x3) {ins16 = *(unsigned short *)(CodeAddr - 2);if ((ins16 & 0x3) != 0x3) {i += 4;framesize = riscv_backtrace_framesize_get1(ins32);if (framesize >= 0) {CodeAddr += 4;break;}continue;}}i += 2;ins16 = (ins32 >> 16) & 0xffff;framesize = riscv_backtrace_framesize_get(ins16);if (framesize >= 0) {CodeAddr += 2;break;}}if (i == BT_FUNC_LIMIT) {/* error branch */#ifdef BACKTRACE_PRINTFBACKTRACE_PRINTF("Backtrace fail!\r\n");#endifreturn -1;}/* 2. scan code, find ins: sd ra,24(sp) or sd ra,552(sp) */for (i = 0; CodeAddr + i < PC;) {ins32 = *(unsigned int *)(CodeAddr + i);if ((ins32 & 0x3) == 0x3) {i += 4;offset = riscv_backtrace_ra_offset_get1(ins32);if (offset >= 0) {break;}} else {i += 2;ins16 = ins32 & 0xffff;offset = riscv_backtrace_ra_offset_get(ins16);if (offset >= 0) {break;}}}

这段代码,根据当前的PC值,知道当前的函数的进来的时候SP开启的地址。计算每次SP开始的地址和结束地址,然后找到上一次的PC值,然后再往上一个函数查找。

RVBACKTRACE的加-fno-omit-frame-pointer的用法

加了编译参数-fno-omit-frame-pointer 之后,进函数之前就会记录当前的SP的值,经过验证,大部分的RISCV64平台的这个选项是默认打开的,所以RISCV64可以用这个方法,估计RISCV64平台一般都比较大。这个时候我们就要用rv_backtrace_fno.c 这个文件来处理栈回溯了。

在RVBACKTRACE中就要开启BACKTRACE_USE_FP 这个宏

void rvbacktrace_fno()
{
8000e02c:	1141                	addi	sp,sp,-16
8000e02e:	c606                	sw	ra,12(sp)
8000e030:	c422                	sw	s0,8(sp)
8000e032:	c226                	sw	s1,4(sp)
8000e034:	0800                	addi	s0,sp,16

S0的值就是保存的栈信息。默认这个寄存器就给栈回溯用。

主要实现函数如下,获取fp的值为__builtin_frame_address 这是一个libc的库函数

    fp = (unsigned long)__builtin_frame_address(0); //  get current frame pointerwhile (1){frame = (struct stackframe *)(fp - BACKTRACE_LEN); //   get frame pointerif ((uint32_t *)frame > (uint32_t *)(uintptr_t)_rt_eusrstack){rvstack_frame_len = num;return;}sp = fp;  // get stack pointerfp = frame->s_fp; // get frame pointerra = frame->s_ra; // get return addresspc = frame->s_ra - 4; // get program counter//  print stack interval, return address, program counterBACKTRACE_PRINTF("[%d]Stack interval :[0x%016lx - 0x%016lx]  ra 0x%016lx pc 0x%016lx\n", num, sp, fp, ra, pc);rvstack_frame[num] = pc; // save stack frame addressnum++;}

看下反汇编

 36           fp = (unsigned long)__builtin_frame_address(0); //  get current frame pointer
8000b09c:   mv      s2,s0

其实就是读取s0的值。

因为有s0保存了进入函数的时候的栈地址,就很容易找到SP进来的时候初始地址,然后也比较方便找到上一次的RA和S0。代码实现起来就比较方便,不需要一直解析反汇编。

其他的线程回溯的方法也是类似的。

汇编指令过滤方法

知道了上面的两种方法之后,比较难的其实是第一种,没有编译选项的时候,如何根据PC指针找到栈的地址。

void rvbacktrace_fno()
{
8000d7c6:	1141                	addi	sp,sp,-16
8000d7c8:	c606                	sw	ra,12(sp)
8000d7ca:	c422                	sw	s0,8(sp

例如上面的函数,我们就要知道两个命令addi sp,sp,-16sw ra,12(sp)

我们翻阅RISCV手册之后,看到如下的命令:
在这里插入图片描述

当然这个是压缩命令

主要的是计算出它的立即数,imm

参考链接如下:
https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_integer_register_immediate_instructions

static int riscv_backtrace_framesize_get1(unsigned int inst)
{unsigned int imm = 0;/* addi sp, sp, -im* example* d1010113             addi    sp,sp,-752* from spec addi FROM https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_integer_register_immediate_instructions* bit[31:20] = imm[11:0]* bit[19:15] = 00010* bit[14:12] = 000* bit[11:7]  = 00010* bit[6:0]  = 0010011*/if ((inst & 0x800FFFFF) == 0x80010113) {imm = (inst >> 20) & 0x7FF;imm = (~imm & 0x7FF) + 1;
#if __riscv_xlen == 64return imm >> 3; // RV64: 以 8 字节为单位
#elsereturn imm >> 2;  // RV32: 以 4 字节为单位
#endif}return -1;
}

CM BACKTRACE

https://github.com/armink-rtt-pkgs/CmBacktrace

CM backtrace 核心代码:

            /* first depth is PC */buffer[depth++] = regs.saved.pc;/* fix the LR address in thumb mode */pc = regs.saved.lr - 1;if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)&& (depth < size)) {buffer[depth++] = pc;regs_saved_lr_is_valid = true;}size_t cm_backtrace_call_stack_any(uint32_t *buffer, size_t size, uint32_t sp, uint32_t stack_start_addr, uint32_t stack_size)
{uint32_t pc;size_t depth = 0;/* copy called function address */for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t)) {/* the *sp value may be LR, so need decrease a word to PC */pc = *((uint32_t *) sp) - sizeof(size_t);/* the Cortex-M using thumb instruction, so the pc must be an odd number */if (pc % 2 == 0) {continue;}/* fix the PC address in thumb mode */pc = *((uint32_t *) sp) - 1;if ((pc >= code_start_addr + sizeof(size_t)) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)/* check the the instruction before PC address is 'BL' or 'BLX' */&& disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < size)) {/* the second depth function may be already saved, so need ignore repeat */buffer[depth++] = pc;}}return depth;
}
static bool disassembly_ins_is_bl_blx(uint32_t addr) {uint16_t ins1 = *((uint16_t *)addr);uint16_t ins2 = *((uint16_t *)(addr + 2));#define BL_INS_MASK         0xF800
#define BL_INS_HIGH         0xF800
#define BL_INS_LOW          0xF000
#define BLX_INX_MASK        0xFF00
#define BLX_INX             0x4700if ((ins2 & BL_INS_MASK) == BL_INS_HIGH && (ins1 & BL_INS_MASK) == BL_INS_LOW) {return true;} else if ((ins2 & BLX_INX_MASK) == BLX_INX) {return true;} else {return false;}
}

用一个数组buffer[] 用来存放对应的PC和回溯的地址

然后从LR往上进行检查PC的值-1 之后,判断PC是否在代码开始段和结束段

如果在,则放到回溯的地址里面。

总结

RVBACKTRACE很好的帮助大家进行栈回溯,大家如果试用觉得有用的话,欢迎帮忙仓库点个star。
如果有建议也可以提issue和PR。

https://github.com/Yaochenger/RvBacktrace

相关文章:

RISC-V hardfault分析工具,RTTHREAD-RVBACKTRACE

RV BACKTRACE 简介 本文主要讲述RV BACKTRACE 的内部主要原理 没有接触过rvbacktrace可以看下面两篇文章&#xff0c;理解一下如何使用RVBACKTRACE RVBacktrace RISC-V极简栈回溯组件&#xff1a;https://club.rt-thread.org/ask/article/64bfe06feb7b3e29.html RVBacktra…...

c语言if else语句格式(非常详细)

在C语言中&#xff0c;if else 语句是一种常用的条件控制结构&#xff0c;用于根据不同条件执行不同的代码块。 if-else 语句的基本格式 if-else 语句的基本格式如下&#xff1a; if (条件) { // 如果条件为真&#xff0c;执行这里的代码 } else { // 如果条件为假&a…...

Logback官方文档翻译章节目录

Logback官方文档翻译章节目录 第一章 Logback简介 第二章 Logback的架构&#xff08;一&#xff09; Logback的架构&#xff08;二&#xff09; Logback的架构&#xff08;三&#xff09; 持续更新中…...

按摩椅的机芯类型和材质

按摩椅的机芯类型和材质是影响其按摩效果、使用寿命以及舒适度的重要因素。下面我将从这两个方面详细为你解析&#xff1a; 一、按摩椅机芯类型 按摩椅的“机芯”相当于它的“心脏”&#xff0c;决定了按摩手法、力度、覆盖范围等关键性能。 常见机芯类型&#xff08;按技术发…...

HarmonyOS-hdc远程网络方式连接设备

hdc工具使用手册 1 hdc简介 hdc&#xff08;OpenHarmony Device Connector&#xff09;是为开发人员提供的用于设备连接调试的命令行工具&#xff0c;pc端开发机使用命令行工具hdc&#xff0c;该工具需支持部署在Windows/Linux/Mac等系统上与OpenHarmony设备&#xff08;或模…...

秋招准备——2.跨时钟相关

格雷码异步FIFO跨时钟域处理 格雷码 一、格雷码规律 相邻性&#xff1a;相邻两个数的格雷码只有一位不同&#xff0c;例如&#xff1a; 0000 → 0001&#xff08;仅最低位变化&#xff09;0001 → 0011&#xff08;仅次低位变化&#xff09;0011 → 0010&#xff08;仅最低位…...

【开源版】likeshop上门家政系统PHP版全开源+uniapp前端

一.系统介绍 likeshop_上门家政系统&#xff0c;PHP版本更新至2.1.1最新版&#xff0c;全开源&#xff0c;适用于上门家政场景&#xff0c;系统拥有用户端、师傅端、无论运营还是二开都是性价比极高的100%开源家政系统。 二.搭建环境-教程 系统环境&#xff1a;CentOS、 运行…...

Memgraph 的安装教程

目录 Memgraph 安装步骤1. 使用 Docker 安装 Memgraph2. 使用 Memgraph Lab3. 使用 Python 客户端连接 Memgraph Memgraph 安装步骤 1. 使用 Docker 安装 Memgraph Memgraph 可以通过 Docker 快速安装和运行。以下是使用 Docker 安装 Memgraph 的步骤&#xff1a; 安装 Docke…...

华为网路设备学习-21 路由过滤(filter-policy)

一、路由过滤&#xff08;filter-policy&#xff09; 1、用于控制路由更新、接收的一个工具 2、只能过滤路由信息&#xff0c;无法过滤LSA 二、路由过滤&#xff08;filter-policy&#xff09;与动态路由协议 1、距离矢量路由协议 RIP动态路由协议 交换的是路由表&#xff0…...

Mac 平台 字体Unicode范围分析器

字体Unicode范围分析器 #include <CoreText/CoreText.h> // CoreText框架头文件&#xff0c;用于字体处理 #include <CoreFoundation/CoreFoundation.h> // CoreFoundation框架头文件 #include <stdio.h> // 标准输入输出 #include…...

Android不能下载Gradle,解决方法Could not install Gradle distribution from.......

外网下载速度太慢导致失败&#xff0c;换成国内镜像&#xff0c;可加速下载&#xff1a; 官网地址&#xff1a;https://services.gradle.org/distributions/ 腾讯云镜像 Gradle下载地址&#xff1a;https://mirrors.cloud.tencent.com/gradle/ 阿里云镜像 Gradle下载地址&…...

树状数组的操作问题--Python

树状数组的操作问题 一、问题引入二、解题步骤1.思维导图2.解题步骤 三、代码实现1.代码2.复杂度分析 四、个人总结 一、问题引入 请编写程序&#xff0c;实现树状数组区间求前缀和、单点修改的操作。 输入格式&#xff1a; 输入首先给出一个正整数 n&#xff08;2≤n<10^…...

FEKO许可限制

随着科技的飞速发展&#xff0c;电磁仿真软件在多个领域发挥着越来越重要的作用。FEKO作为一款业界领先的电磁仿真软件&#xff0c;广泛应用于通信、雷达、航空航天、电子对抗等领域。然而&#xff0c;为了确保软件使用的合规性与高效性&#xff0c;FEKO设定了相应的许可限制。…...

第5章 深度学习和卷积神经网络

深度学习是人工智能的一种实现方法。本章我们将考察作为深度学习的代表的卷积神经网络的数学结构。 5-1小恶魔来讲解卷积神经网络的结构 深度学习是重叠了很多层的隐藏层&#xff08;中间层&#xff09;的神经网络。这样的神经网络使隐藏层具有一定的结构&#xff0c;从而更加…...

window 显示驱动开发-处理内存段(一)

视频内存管理器 (VidMm) 负责管理 GPU 的地址空间。 在此之前&#xff0c;内核模式显示微型端口驱动程序 (KMD) 必须通过使用内存段将 GPU 的地址空间描述为 VidMm。 KMD 创建内存段以概括和虚拟化视频内存资源。 它可以根据硬件支持的存储器类型&#xff08;例如&#xff0c;…...

QT实现曲线图缩放、拖拽以及框选放大

.h文件 protected: void saveAxisRange();void wheelEvent(QWheelEvent *event) override;void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;private:QPoint m_…...

龙虎榜——20250508

上证假阴包阳的走势&#xff0c;量能较昨天有萎缩&#xff0c;在前期压力附近~ 深证这两天假阴包阳的走势&#xff0c;60分钟未突破昨天的高点&#xff0c;缺口也未补等待明天的选择~ 2025年5月8日龙虎榜行业方向分析 一、核心行业方向 军工航天&#xff08;政策催化地缘驱动…...

SEMI E40-0200 STANDARD FOR PROCESSING MANAGEMENT(加工管理标准)-(三)完结

10 消息服务详情 10.1 本章定义实现加工管理概念所需的消息服务。这些消息已在第8.1节中初步介绍。 协议无关性&#xff1a;这些服务独立于所使用的消息协议&#xff0c;可映射至SECS-II&#xff08;SEMI E5&#xff09;或其他类似协议。 10.1.1 消息服务定义内容包括&#…...

算法竞赛进阶指南.次小生成树

目录 题目算法标签: K r u s k a l Kruskal Kruskal, M S T MST MST, 倍增优化, l c a lca lca思路代码*警示后人 题目 356. 次小生成树 算法标签: K r u s k a l Kruskal Kruskal, M S T MST MST, 倍增优化, l c a lca lca 思路 因为要求的是严格次小生成树, 假设最…...

ElasticSearch基本概念

为什么要使用ElasticSearch Elasticsearch 主要为系统提供搜索功能&#xff0c; MySQL 这类传统关系型数据库主要为系统提供数据存储功能 Elasticsearch 的优势 &#xff1a; 支持多种数据类型&#xff0c;非结构化&#xff0c;数值&#xff0c;地理信息。简单的 RESTful AP…...

普通IT的股票交易成长史--20250508晚复盘

声明&#xff1a;本文章的内容只是自己学习的总结&#xff0c;不构成投资建议。价格行为理论学习可参考简介中的几位&#xff0c;感谢他们的无私奉献。 送给自己的话&#xff1a; 仓位就是生命&#xff0c;绝对不能满仓&#xff01;&#xff01;&#xff01;&#xff01;&…...

SAP 交货单行项目含税金额计算报cx_sy_zerodivide处理

业务背景&#xff1a;SAP交货单只有数量&#xff0c;没有金额&#xff0c;所以开发报表从订单的价格按数量计算交货单的金额。 用户反馈近期报表出现异常&#xff1a; ****2012/12/12 清风雅雨 规格变更 Chg 修改开始 ** 修改原因:由于余数为0时&#xff0c;可能会报错溢出。…...

基于译码器和锁存器的运行逻辑的简易算法

74HC138 def decoder_74hc138(E1, E2, E3, A0, A1, A2):output [1] * 8 # 默认全高电平# 检查使能条件&#xff1a;E1和E2低电平&#xff0c;E3高电平if E1 0 and E2 0 and E3 1:# 计算地址索引&#xff08;A2为高位&#xff0c;A0为低位&#xff09;index (A2 <<…...

用电信息采集中的天线种类

一、4G/3G/2G 频率范围“698-960/1710-2700MHz 输入阻抗&#xff1a;50Ω 电压驻波比&#xff1a;<3.0 增益&#xff1a;5dBi/7dBi/9dBi&#xff1b; 824MHz&#xff5e;960MHz频段本体增益≥3.0dBi 1710MHz&#xff5e;2700MHz频段本体增益≥5.0dBi 天线长度225*30mm…...

2025年4月AI算力领域热点事件全景报告

目录 一、政策要闻 01欧洲央行召开会议讨论AI影响 02中国生成式AI备案制落地 03多国政府公布AI基础设施投资计划 04香港发布生成式AI技术及应用指引 05美国出口管制政策影响 06欧盟《人工智能法案》落地 07中国 “东数西算” 工程深化 08美国CHIPS法案争议 09中国发…...

数据结构-非线性结构-二叉树

概述 /** * 术语 * 根节点&#xff08;root node&#xff09;&#xff1a;位于二叉树顶层的节点&#xff0c;没有父节点。 * 叶节点&#xff08;leaf node&#xff09;&#xff1a;没有子节点的节点&#xff0c;其两个指针均指向 None 。 * 边&#xff08;edge&#xff09;&…...

Android开发补充内容

Android开发补充内容 fragment通信生命周期 Okhttp基本使用websocket Retrofit基本使用 RxJava基本使用定时任务 Hilt基本使用进阶使用例子 组件库Material ComponentsJetpack Compose fragment 通信 fragment于activity通信的一种原生方法是使用Bundle&#xff1a; Bundle …...

Go主要里程碑版本及其新增特性

Go 语言自 2009 年诞生以来&#xff0c;经历了多个里程碑版本的迭代&#xff0c;每个版本都引入了重要特性和改进。以下是 Go 语言的主要版本及其关键特性&#xff1a; Go 1.0 (2012-03-28) 首个稳定版&#xff0c;承诺向后兼容&#xff08;Go 1 兼容性保证&#xff09;。核心…...

Cut video with ffmpeg

To cut a snippet from a video based on timestamps like 02:52 to 04:20, the best tool is FFmpeg, which is fast, free, and doesn’t re-encode the video (so it keeps original quality if you don’t want re-encoding). Here’s the command you can run in a termi…...

无刷电机控制算法策略

目录 一、基础控制算法 二、高性能算法 三、无感算法 四、智能算法 五、特殊场景算法 无刷电机的核心控制算法主要包括以下类型&#xff1a; 一、基础控制算法 六步换向法&#xff08;梯形控制&#xff09; 通过霍尔传感器检测转子位置&#xff0c;按固定顺序切换…...

LeetCode算法题(Go语言实现)_61

题目 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 给定一个代表每个房屋存放金…...

Kafka消息不丢失处理

kafka作为消息中间件&#xff0c;吞吐量大&#xff08;至于为啥吞吐量大&#xff0c;本文不做介绍&#xff09;&#xff0c;所以大家用的多。涉及到异构数据库更换&#xff0c;以及数据预处理后的迁移&#xff0c;基本想到的都是通过kafka。 概览图 我先画个图 生产者到kafka…...

Python+ffmpeg 实现给视频添加字幕

创作灵感 孩子学校经常留作业&#xff0c;需要提交一段录制的视频&#xff0c;视频上要求添加学校、班级、姓名等信息的字幕&#xff0c;手机自带的相机软件字幕添加位置要么只能添加在视频正中&#xff0c;要么无法添加多行文本&#xff0c;要么只能添加在片头或者片尾&#…...

QMK键盘固件自定义指南 - 打造你的专属键盘体验

QMK键盘固件自定义指南 - 打造你的专属键盘体验 &#x1f680; 前言 在机械键盘的世界里&#xff0c;QMK固件让你的键盘不再只是简单的输入设备&#xff0c;而是可以按照你的意愿定制的强大工具。本文将深入浅出地介绍如何自定义QMK键盘的行为&#xff0c;从基础概念到高级应…...

Linux-openeuler更换yum镜像源

将 openEuler 系统镜像源更换为华为镜像 以openEuler 24.03 LTS SP1 为例。操作前建议备份原配置文件&#xff0c;并确保系统已联网。 一、确认系统版本与架构 查看系统版本&#xff1a; [rooteulerzy yum.repos.d]# cat /etc/os-releaseNAME"openEuler"VERSION&qu…...

手势、鼠标滑动实现界面切换

手势&#xff1a; #include <QApplication> #include "mainwindow.h"int main(int argc, char *argv[]) {QApplication app(argc, argv);MainWindow window;window.show();return app.exec(); }#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainW…...

什么是变量提升?(形象的比喻)

当然&#xff01;可以用几个生活中的比喻来形象地解释变量提升&#xff1a; ​​1. 书架的占位符​​ 想象你有一个书架&#xff0c;但还没放书。 • 变量提升&#xff08;var&#xff09;&#xff1a; 你先在书架上贴了一个标签&#xff08;比如写“我的书”&#xff09;&…...

趣味编程:答案之书

概述&#xff1a;该篇博客主要介绍的是曾经一度风靡全网的答案之书小程序。 目录 1. 效果展示 2. 源码展示 3. 代码逻辑详解 3.1 头文件与全局变量 3.2 main函数 3.3 主循环 3. 4 绘制界面 4. 运行问题 5.小结 1. 效果展示 该小程序是动态的效果&#xff0c; 因此实…...

用kompose将docker-compose文件转换为K8S资源清单

一、什么是kompose Kompose 是什么&#xff1f;它是一个转换工具&#xff0c;可将 Compose &#xff08;即 Docker Compose&#xff09;所组装的所有内容转换成容器编排器&#xff08;Kubernetes 或 OpenShift&#xff09;可识别的形式。 更多信息请参考 Kompose 官网 Kompos…...

Linux中的防火墙

概述 防火墙通过一系列规则来过滤网络数据包&#xff0c;决定哪些数据包可以进入或离开系统&#xff0c;哪些数据包将被阻止&#xff0c;以此来保护系统免受未经授权的访问、恶意攻击和潜在的安全威胁。 常见的防火墙软件 iptables&#xff1a;是 Linux 系统中常用的防火墙工…...

AI开发跃迁指南(第三章:第四维度1——Milvus、weaviate、redis等向量数据库介绍及对比选型)

1.向量数据库简介 向量数据库&#xff08;Vector Database&#xff09;是专门为存储和查询高维向量数据而设计的数据库&#xff0c;主要用于处理由机器学习模型生成的嵌入向量&#xff08;Embeddings&#xff09;。它在人工智能&#xff08;AI&#xff09;、自然语言处理&…...

深度学习笔记41_调用Gensim库训练Word2Vec模型

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 一、我的环境 1.语言环境&#xff1a;Python 3.8 2.编译器&#xff1a;Pycharm 3.深度学习环境&#xff1a; torch1.12.1cu113torchvision…...

Windows Server 2025 安装AMD显卡驱动

运行显卡驱动安装程序&#xff0c;会提示出问题。但是此时资源已经解压 来到驱动路径 C:\AMD\AMD-Software-Installer\Packages\Drivers\Display\WT6A_INF 打开配置文件&#xff0c;把这两行替换掉 %ATI% ATI.Mfg, NTamd64.10.0...16299, NTamd64.10.0, NTamd64.6.0, NTamd64.…...

debian安装docker

debian安装docker <在Debian上安装Docker的步骤》 在Debian上安装Docker通常涉及几个步骤&#xff0c;以确保你能够顺利运行Docker容器。下面是一份详细的指南&#xff0c;帮助你在Debian系统上安装Docker。 1. 更新你的包列表 首先&#xff0c;更新你的包列表以确保所有…...

uniapp上架苹果APP Store踩雷和部分流程注意事项(非完整流程)

本文是uniapp打包成ios上架到苹果商店一系列踩雷和部分流程介绍 1.打包需要俩个证书 需要xx..mobileprovision和xx.p12证书并且ios打包一天最多5次&#xff0c;超出需要2元/1次付费打包&#xff0c;证书需要使用苹果电脑生成&#xff0c;以下为证书生成教程iOS证书(.p12)和描述…...

【吃透 Elasticsearch 的核心原理】学习步骤

要真正&#xff0c;需深入以下关键机制&#xff08;结合最新技术演进&#xff09;&#xff1a; 一、倒排索引机制 核心三要素 Term Index&#xff1a;FST 结构加速前缀匹配&#xff08;如 ap* 查询&#xff09;Term Dictionary&#xff1a;存储所有 token 及统计信息&#xff…...

springboot使用mybatisPlus进行数据库增删改查

springboot使用mybatisPlus进行数据库增删改查 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是springboot的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#xff1a;每个…...

移动端前端开发中常用的css

在开发移动端项目的时候&#xff0c;很多样式都是相同的&#xff0c;比如说图标大小&#xff0c;头像大小&#xff0c;页面底部保存(添加按钮&#xff09;&#xff0c;项目主体颜色等等&#xff0c;对于这些在项目中常用到的&#xff0c;通常都会写在公共样式中&#xff08;pub…...

C/C++内存分布

内存分布示意图&#xff1a; 内存分布各区域详解&#xff1a; 内核空间&#xff1a; 放置操作系统相关的代码和数据。&#xff08;用户不能直接进行操作 ------ 可以通过调用系统提供的 api 函数&#xff09; 栈区&#xff1a; 又叫堆栈&#xff0c;非静态局部变量/函数参数/…...

Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0.

版本: 原因 在 Dart Sass 3.0.0 中, @import 规则将被弃用,推荐使用 @use 和 @forward 规则来替代。 1.@use替代@import @use 规则允许你引入其他 Sass 文件中的变量、混合器和函数,并且可以避免命名冲突。 示例: style.scss @use variables;body {color: variables.$pr…...