ECLIC中断流程及实际应用 —— RISC-V中断机制(二)
在长期的嵌入式开发实践中,对中断机制的理解始终停留在表面层次,特别当开发者长期局限于纯软件抽象层面时,对中断机制的理解极易陷入"知其然而不知其所以然"的困境,这种认知的局限更为明显;随着工作需要不断深入底层技术,对硬件机制的了解逐渐加深,并积累了大量的学习笔记。借此机会,我将这些零散的知识进行系统化梳理,既是对自身知识的复盘,也希望能为相关领域的开发者提供些许帮助和参考。关于RISC-V中断机制的分析,本文将从硬件实现原理和软件应用以下两个方面来展开介绍:
RISC-V CLINT、PLIC及芯来ECLIC中断机制分析 —— RISC-V中断机制(一)
ECLIC中断流程及实际应用 —— RISC-V中断机制(二)
背景
中断(Interrupt)机制,即处理器内核在顺序执行程序指令流的过程中突然被别的请求打断而中止执行当前的程序,转而去处理别的事情,待其处理完了别的事情,然后重新回到之前程序中断的点继续执行之前的程序指令流。
中断相关的基本知识要点:
- 打断处理器执行的“别的请求”便称之为中断请求(Interrupt Request),“别的请求”的来源便称之为中断源(Interrupt Source),中断源通常来自于内核外部(称之为外部中断源),也可以来自于内核内部(成为内部中断源)。
- 处理器转而去处理的“别的事情”便称之为中断服务程序(Interrupt Service Routine,ISR)。
- 中断处理是一种正常的机制,而非一种错误情形。处理器收到中断请求之后,需要保存当前程序的现场,简称为“保存现场”。等到处理完中断服务程序后,处理器需要恢复之前的现场,从而继续执行之前被打断的程序,简称为“恢复现场”。
- 可能存在多个中断源同时向处理器发起请求的情形,需要对这些中断源进行仲裁,从而选择哪个中断源被优先处理。此种情况称为“中断仲裁”,同时可以给不同的中断分配级别和优先级以便于仲裁,因此中断存在着“中断级别”和“中断优先级”的概念。
芯来N级别处理器内核实现了一个“改进型内核中断控制器(Enhanced Core Local Interrupt Controller,ECLIC)”,可用于多个中断源的管理。N级别处理器内核中的所有类型(除了调试中断之外)的中断都由ECLIC统一进行管理。
1 寄存器
有详细介绍说过ECLIC相关的寄存器,下面介绍中断处理流程使用的CSR寄存器:用来保存控制信息。
1.1 硬件自动填写的寄存器
-
mepc(Machine Exception Program Counter)
保存发生异常或中断时的PC值。
如果中断处理需要恢复到异常指令后一条指令进行执行,就需要正确判断将 pc 寄存器加上多少字节。 -
mcause(Machine Cause Register)
记录中断是否是硬件中断,以及具体的中断原因,如:- Interrupt Bit(最高位):1 表示中断,0 表示异常。
- Exception Code(低 31 位):具体原因编码(如 0x0B 表示外部中断)。
异常编码表:
-
mtval(Machine Trap Value Register)
存储与异常相关的附加信息(如非法地址、非法指令编码)。- 非法地址异常:mtval 记录访问的非法地址。
- 非法指令异常:mtval 存储非法指令的二进制编码。
- 对于中断(非异常),mtval 通常无意义,可能保留为 0
1.2 指示硬件处理中断的寄存器
- mtvec(Machine Trap Vector Base Address Register)
设置机器模式(M-mode)下中断和异常的入口地址基址。存储了一个基址 BASE 和模式 MODE:- MODE 为 0 表示 直接模式,即遇到中断便跳转至 同一入口地址(mtvec.BASE)。
- MODE 为 1 表示 向量模式,中断跳转到 mtvec.BASE + 4 * cause,异常仍使用统一入口。
以上是官方中断入口,芯来的eclic是基于clic,这里是有改动的,正常情况下mtvec是作为异常处理入口的,中断入口是由mtvt2定义。芯来mtvec定义如下:
-
mstatus(Machine Status Register)
控制全局中断使能及特权模式切换;如:- MIE(Machine Interrupt Enable):全局中断开关。若为 0,所有中断被屏蔽。
- MPP(Machine Previous Privilege):记录中断前的特权模式(如 M/S/U-mode),用于 mret 返回。
-
mie(Machine Interrupt Enable Register)
用来控制具体类型中断的使能,如:- MEIE(Machine External Interrupt Enable):外部中断(如 PLIC/ECLIC 中断)使能。
- MTIE(Machine Timer Interrupt Enable):定时器中断使能。
- MSIE(Machine Software Interrupt Enable):软件中断使能。
-
mip(Machine Interrupt Pending Register)
和 mie 相对应,标记中断的挂起状态(Pending Bits)- MEIP(Machine External Interrupt Pending):外部中断挂起位。
- MTIP(Machine Timer Interrupt Pending):定时器中断挂起位。
- MSIP(Machine Software Interrupt Pending):软件中断挂起位。
-
mtvt
寄存器保存中断向量表的基址(在CLIC模式下),基址至少对齐64字节边界 -
mtvt2
用于指示所有ECLIC中断共享的公共基处理程序的入口地址
-
mscratch
寄存器的用处会在实现线程时起到作用,在中断处理开始时,将当前线程的上下文指针保存到 mscratch,再从 mscratch 加载中断栈指针;感兴趣可以自行学习下。 -
msubm
芯来自定义的CSR msubm寄存器保存当前机器子模式和当前陷阱之前的机器子模式
- jalmnxti
芯来自定义的CSR jalmnxti,用来减少中断延迟并加速中断尾部链接。
jalmnxti包括mnxti(Next Interrupt Handler Address and Interrupt-Enable CSR)的所有功能,此外还包括启用中断、处理下一个中断、跳转到下一个中断入口地址以及跳转到中断处理程序。(感兴趣可以自行继续深入学习下)
实际通过修改jalmnxti和ra的地址的值,在中断嵌套和咬尾时,可以节省保存上下文(CSR和通用寄存器)的开销,
1.4 临时寄存器
- pushmepc
- pushmsubm
- pushmcause
芯来自定义了通过CSR指令csrrwi将msubm、mepc、mcause的值存储在以SP为基址的内存空间中,该指令将CSR寄存器的值存储在SP+1*4地址中。
2 ECLIC中断处理流程
2.1 整体流程(主要以非向量中断为例)
当一个hart发生中断时,整个中断流程需要软硬协作完成,下图是eclic中断处理,包括:进入以及推出全部流程流程
-
硬件接收到中断信号,硬件自动更新CSR寄存器
- 更新内核退出中断时的返回地址,存储在mepc(1、该地址就是中断打断的PC值(在中断结束之后,回到被停止执行的程序点), 2、mepc软件可以显示修改)
- ①、mcause.EXCCODE存放中断ID,以便软件查询;②、如果当前中断抢占了低优先级中断,mcause.MPIL将更新为minstatus.MIL的值,处理中断后,将使用mcause.MPIL的值来恢复mintcause.MIL的值;③、如果是向量模式中断,mcause.minhv的值将更新为1,在完成从中断向量表中取出存储的目标地址,然后再跳转到目标地址中去后,mcause.minhv域的值清除为0
- ①、mstatus.MPIE更新为mstatus.MIE的值,mstatus.MIE置0(屏蔽所有中断);②、处理器的当前特权模式(Privilege Mode)切换到机器模式(Machine Mode)mstatus.MPP从特权模式将切换到机器模式;
- ①、msubm.PTYP域的值被更新为中断发生前的Machine Sub-Mode(msubm.TYP域的值)②、msubm.TYP域的值则被更新为“中断处理模式”(反映当前的模式已经是“中断处理模式”)
- 更新内核退出中断时的返回地址,存储在mepc(1、该地址就是中断打断的PC值(在中断结束之后,回到被停止执行的程序点), 2、mepc软件可以显示修改)
-
跳转到共享中断入口地址,保存中断上下文(非向量中断)(寄存器clicintattr[i]的shv域决定中断是向量中断还是非向量中断)
- 跳入到mtvt2.CMMON-CODE-ENTRY(mtvt2.MTVT2EN = 1);
- 将一些通用寄存器(ra/tp/t0-t6/a0-a7)(保存中断上下文)保存到堆栈中;
- 将CSR mepc、mcause、msubm保存到堆栈中,确保后续的抢占中断可以被正确处理;
- 如果被配置成为向量处理模式,则该中断被处理器内核响应后,处理器直接跳入该中断的向量入口(Vector Table Entry)存储的目标地址(ISR地址)
- 如果被配置成为非向量处理模式,则该中断被处理器内核响应后,处理器直接跳入所有中断共享的入口地址
-
执行Nuclei自定义指令“
csrrw ra,CSR_JALMNXTI,ra
”,如果没有待处理的中断,则该指令将被视为空操作;否则进入下面步骤- 直接跳入该中断的向量入口(Vector Table Entry)存储的目标地址,即该中断源的中断服务程序**(Interrupt Service Routine,ISR)**中去
- 硬件置位全局中断使能位mstatus.MIE,此时可以接受新中断,以形成中断嵌套。
- 把当前PC(csrrw ra,CSR_JALMNXTI,ra)写入返回地址ra寄存器,达到JAL(Jump and Link)的效果,即:在执行完中断handle之后,将再次执行该指令“
csrrw ra,CSR_JALMNXTI,ra
”,进而重新判断是否有还未处理的中断(pending),进而形成中断咬尾
-
从中断服务函数中返回后,软件来恢复中断上下文
- mstatus.MIE置0,屏蔽所有中断,确保操作的原子性
- 从堆栈中恢复中断前
CSR寄存器(msubm、mepc、mcause)
以及通用寄存器(ra/tp/t0-t6/a0-a7/sp)
的值
-
软件执行mret退出中断处理程序,硬件将自动更新CSR寄存器
- ①、mcause.MPIL的值恢复minstatus.MIL的值,minstatus.MIL的值会被恢复到中断前的原始值;②、使用mcause.MPIE的值恢复minstatus.MIE的值,minstatus.MIE的值会被恢复到触发中断前的值;③、mcause.MPP特权模式从中断模式退出,恢复为中断前的模式,(同样也会更新mstatus.MPIE和mcause.MPP的值,见最后NOTE)。
- 硬件将处理器Machine Sub-Mode的值恢复为msubm.PTYP域的值
- 跳转到mepc定义的PC,继续执行之前被中止的程序流。
NOTE:
mstatus.MPIE域和mstatus.MPP域的值与mcause.MPIE域和mcause.MPP域的值是镜像关系,即,在正常情况下,mstatus.MPIE域的值与mcause.MPIE域的值总是完全一样,mstatus.MPP域的值与mcause.MPP域的值总是完全一样。
2.2 向量中断与非向量中断
ECLIC的每个中断源均可以设置成向量或者非向量处理(通过寄存器clicintattr[i]的shv域
),向量处理模式和非向量处理模式二者有较大的差别
2.1章节主要是以非向量中断为例介绍的中断处理流程,这里把前面的一些和向量中断不同的点再总结下,方便和向量中断做对比
2.2.1 非向量中断处理模式
1、非向量处理模式,则该中断被处理器内核响应后,处理器会直接跳入到所有非向量中断共享的入口地址,该入口地址可以通过软件进行设置
-
如果配置CSR寄存器
mtvt2的最低位为0
(上电复位默认值),则所有非向量中断共享的入口地址由CSR寄存器mtvec的值(忽略最低2位的值)指定。由于mtvec寄存器的值也指定异常的入口地址,因此,意味着在这种情况下,异常和所有非向量中断共享入口地址。 -
如果配置CSR寄存器
mtvt2的最低位为1
(芯来SDK的bootloader里配置为1了,将异常和非向量中断入口分开,不用判断是中断还是异常了,提升效率),则所有非向量中断共享的入口地址由CSR寄存器mtvt2的值(忽略最低2位的值)指定。
2、如2.1章节步骤二描述,进入所有非向量中断共享的入口地址之后,处理器会开始执行一段共有的软件代码
- 首先保存CSR寄存器
mepc、mcause、msubm
入堆栈。保存这几个CSR寄存器是为了保证后续的中断嵌套能够功能正确,因为新的中断响应会重新覆盖mepc、mcause、msubm的值,因此需要将它们先保存入堆栈 - 保存若干通用寄存器(处理器的上下文)入堆栈
- 然后执行一条特殊的指令“
csrrw ra, CSR_JALMNXTI, ra
”。如果没有中断在等待(Pending),则该指令相当于是个Nop指令不做任何操作;如果有中断在等待(Pending),执行该指令后处理器会:- 直接跳入该中断的向量入口(Vector Table Entry)存储的目标地址,即该中断源的中断服务程序(Interrupt Service Routine,ISR)中去。
- 在跳入中断服务程序的同时,硬件也会同时打开中断的全局使能,即,设置mstatus寄存器的MIE域为1。打开中断全局使能后,新的中断便可以被响应,从而达到中断嵌套的效果。
- 在跳入中断服务程序的同时,“csrrw ra, CSR_JALMNXTI, ra”指令还会达到JAL(Jump and Link)的效果,硬件同时更新Link寄存器的值为该指令的PC自身作为函数调用的返回地址。因此,从中断服务程序函数返回后会回到该“csrrw ra, CSR_JALMNXTI, ra”指令重新执行,重新判断是否还有中断在等待(Pending),从而达到中断咬尾的效果。
- 在中断服务程序的结尾处同样需要添加对应的恢复上下文出栈操作。并且在CSR寄存器mepc、mcause、msubm出堆栈之前,需要将中断全局使能再次关闭,以保证mepc、mcause、msubm恢复操作的原子性(不被新的中断所打断)。
2.2.2 向量中断的处理
1、如果被配置成为向量处理模式,则该中断被处理器内核响应后,处理器会**直接跳入该中断的向量入口(Vector Table Entry)**存储的目标地址,即该中断源的中断服务程序(Interrupt Service Routine,ISR)
2、向量处理模式具有如下特点:
-
向量处理模式时处理器会直接跳到中断服务程序,并没有进行上下文的保存,因此,中断响应延迟非常之短,从中断源拉高到处理器开始执行中断服务程序中的第一条指令,基本上只需要硬件进行查表和跳转的时间开销,理想情况下约6个时钟周期。
-
对于向量处理模式的中断服务程序函数,一定要使用特殊的
__attribute__((interrupt))
来修饰中断服务程序函数。 -
向量处理模式时,由于在跳入中断服务程序之前,处理器并没有进行上下文的保存,因此,理论上中断服务程序函数本身不能够进行子函数的调用。
-
如果不小心调用了其他子函数,只要使用了
__attribute__((interrupt))
来修饰中断复位函数,编译器就会自动插入一段代码进行上下文的保存。(实际使用中不推荐调用子函数) -
处理器在响应向量中断后,mstatus寄存器中的MIE域将会被硬件自动更新成为0(中断被全局关闭,从而无法响应新的中断)。因此向量处理模式默认是不支持中断嵌套的,为了达到向量处理模式且又能够中断嵌套的效果,可以在中断服务例程里依次加入以下操作来实现中断嵌套效果。
- 保存CSR寄存器mepc、mcause、msubm入堆栈。
- 重新打开中断的全局使能(mstatus.MIE置1)
- 执行中断程序内容
- 关闭中断全局使能,恢复上下文出栈操作
3、对于向量处理模式的中断而言,由于在跳入中断服务程序之前,处理器并没有进行上下文的保存,因此进行“中断咬尾”的意义不大,因此,向量处理模式的中断,没有“中断咬尾”处理能力。(除非在向量中断复位函数里进行中断上下文以及返回地址的处理,但这样不如一开始就注册为非向量中断)
2.2.3 二者区别
这里就简单总结对比下:
对比项 | 向量中断(Vectored Interrupt) | 非向量中断(Non-Vectored Interrupt) |
---|---|---|
入口地址 | 每个中断有独立的入口地址(由向量表定义)。 | 所有中断共享统一入口地址。 |
开销 | 低(硬件自动跳转IRQ,无需软件处理中断上下文)。 | 高(需要从统一入口进入,需要软件处理中断上下文)。 |
中断嵌套 | 支持(需要在中断服务例程中手动处理上下文来支持) | 支持 |
中断咬尾 | 不支持 | 支持 |
IRQ定义 | void __INTERRUPT isr_uart() { ... } | void isr_uart() { ... } |
应用场景 | 需要快速响应的高优先级外设 | 低优先级或非实时外设 |
NOTE:
非向量模式的中断处理函数,中断函数前面一定不要加__INTERRUPT
这个关键字描述,否则编译器会用mret 指令,导致中断提前返回了中断前的代码,而不是返回到common_entry 这里
而向量中断需要使用__attribute__((interrupt))
来修饰,让编译器来处理该服务例程
2.3 中断抢占和中断咬尾
实际上通过前面的前面的介绍,对于中断抢占和中断咬尾,基本上已经能了解个七七八八了,这里再简单总结下,并举例说明下。
2.3.1 基本概念
1、中断嵌套
处理器内核正在处理某个中断的过程中,可能有一个级别更高的新中断请求到来,处理器可以中止当前的中断服务程序,转而开始响应新的中断,并执行其“中断服务程序”,如此便形成了中断嵌套(即前一个中断还没响应完,又开始响应新的中断),并且嵌套的层次可以有很多层。
2、中断咬尾
处理器内核正在处理某个中断的过程中,可能有新中断请求到来,但是**“新中断的级别”低于或者等于“当前正在处理的中断级别”**,因此,新中断不能够打断当前正在处理的中断(因此不会形成嵌套)
2.3.2 中断嵌套处理流程
1、非向量中断
假设中断源30、31、32这三个中断源先后到来,且“中断源32的级别” > “中断源31的级别”> “中断源30的级别”,那么后来的中断便会打断之前正在处理的中断形成中断嵌套
2、向量中断
假设中断源30、31、32这三个中断源先后到来,且“中断源32的级别” > “中断源31的级别”> “中断源30的级别”,那么后来的中断便会打断之前正在处理的中断形成中断嵌套。
向量中断不同点是,1、中断入口不一致(中断的服务函数地址),2、中断服务函数里软件实现中断上下文处理
2.3.3 中断咬尾处理流程
假设中断源30、29、28这三个中断源先后到来,且“中断源30的级别” >= “中断源29的级别”>= “中断源28的级别”,那么后来的中断不会打断之前正在处理的中断(不会形成中断嵌套),但是会被置于等待(Pending)状态。当中断源30完成处理后,将会直接开始中断源29的中断处理,省掉中间的“恢复上下文”和“保存上下文”过程。
2.3.4 总结
非向量中断总是能够支持中断嵌套和中断咬尾的;
向量中断则是可以通过在中断服务程序中通过软件处理来支持中断嵌套,但不支持中断咬尾。
另外,并未给出向量中断和非向量中断相互嵌套的例子,不过大家可以自行分析下。
3 实际应用
这里结合芯来开源SDK中demo_eclic代码及qemu(RISC-V汇编学习(四)—— RISCV QEMU平台搭建(基于芯来平台))来演示下,向量中断与非向量中断以及中断的嵌套。
中断注册、入口初始化及共享中断入口流程代码,自行参考芯来开源sdk中的驱动及BootLoader学习(参考下面源码链接)。
3.1、源码分析
芯来提供了一个软件中断和timer中断的示例,源码点击链接即可查看:
Gitee: https://gitee.com/Nuclei-Software/nuclei-sdk/blob/master/application/baremetal/demo_eclic/demo_eclic.c
Github: https://github.com/Nuclei-Software/nuclei-sdk/blob/master/application/baremetal/demo_eclic/demo_eclic.c.
源码执行结果,展示部分打印:
-------------------
[IN TIMER INTERRUPT]timer interrupt hit 0 times
[IN TIMER INTERRUPT]trigger software interrupt
[IN TIMER INTERRUPT]software interrupt will run when timer interrupt finished
[IN TIMER INTERRUPT]timer interrupt end
[IN SOFTWARE INTERRUPT]software interrupt hit 0 times
[IN SOFTWARE INTERRUPT]software interrupt end
-------------------
[IN TIMER INTERRUPT]timer interrupt hit 1 times
[IN TIMER INTERRUPT]trigger software interrupt
[IN TIMER INTERRUPT]software interrupt will run when timer interrupt finished
[IN TIMER INTERRUPT]timer interrupt end
[IN SOFTWARE INTERRUPT]software interrupt hit 1 times
[IN SOFTWARE INTERRUPT]software interrupt end
分析
- 程序中分别注册了:
- 1、timer中断:高优先级、非向量中断
- 2、软件中断:低优先级、向量中断
timer_intlevel = HIGHER_INTLEVEL;
swirq_intlevel = LOWER_INTLEVEL;// initialize timer
setup_timer();
// initialize software interrupt as vector interrupt
returnCode = ECLIC_Register_IRQ(SysTimerSW_IRQn, ECLIC_VECTOR_INTERRUPT,ECLIC_LEVEL_TRIGGER, swirq_intlevel, 0, eclic_msip_handler);
// inital timer interrupt as non-vector interrupt
returnCode = ECLIC_Register_IRQ(SysTimer_IRQn, ECLIC_NON_VECTOR_INTERRUPT,ECLIC_LEVEL_TRIGGER, timer_intlevel, 0, eclic_mtip_handler);
- 实现:
通过设置core内部的MTIMERCMP寄存器,来触发timer中断,之后在timer中断服务例程里配置MSIP来触发软件中断
根据打印可以发现程序这里实现了中断咬尾效果,即:
1、低优先级中断无法打断高优先级中断
2、每次都会先触发非向量中断(timer中断),然后再触发向量中断(soft中断)
3、在高优先级的非向量中断退出后再次执行"csrrw ra, CSR_JALMNXTI, ra
",此时还有低优先级的中断在pending中,就会继续执行低优先级的软件中断,从而形成中断咬尾
另外,这里把软件中断配置成非向量中断(记得去掉IRQ的__INTERRUPT
修饰)效果也是一样的,
但是把timer中断换成向量中断(不支持中断咬尾)是不行的。(第一个触发的中断是非向量中断可以实现中断咬尾)
3.2 中断嵌套实现
我们在芯来提供的demo_eclic基础上来做些修改:
只需要打开#define SWIRQ_INTLEVEL_HIGHER 1
,就会从新定义优先级: soft中断>timer中断
执行代码,部分打印如下:
-------------------
[IN TIMER INTERRUPT]timer interrupt hit 0 times
[IN TIMER INTERRUPT]trigger software interrupt
[IN TIMER INTERRUPT]software interrupt will run during timer interrupt
[IN SOFTWARE INTERRUPT]software interrupt hit 0 times
[IN SOFTWARE INTERRUPT]software interrupt end
[IN TIMER INTERRUPT]timer interrupt end
-------------------
[IN TIMER INTERRUPT]timer interrupt hit 1 times
[IN TIMER INTERRUPT]trigger software interrupt
[IN TIMER INTERRUPT]software interrupt will run during timer interrupt
[IN SOFTWARE INTERRUPT]software interrupt hit 1 times
[IN SOFTWARE INTERRUPT]software interrupt end
[IN TIMER INTERRUPT]timer interrupt end
可以看到在低优先级timer中断执行时,将被高优先级soft中断打断,从而形成中断嵌套。
这里把软件中断配置成非向量中断(记得去掉IRQ的__INTERRUPT
修饰)效果也是一样的,
后者把timer中断换成向量中断也是可行的(1、IRQ加上的__INTERRUPT
修饰 2、IRQ里开始加上SAVE_IRQ_CSR_CONTEXT();
,结束加上RESTORE_IRQ_CSR_CONTEXT();
)。
以上就是芯来eclic中断相关的内容,如有纰漏,还请各位看官大佬予以指出
参考:
芯来科技N级别指令集架构
相关文章:

ECLIC中断流程及实际应用 —— RISC-V中断机制(二)
在长期的嵌入式开发实践中,对中断机制的理解始终停留在表面层次,特别当开发者长期局限于纯软件抽象层面时,对中断机制的理解极易陷入"知其然而不知其所以然"的困境,这种认知的局限更为明显;随着工作需要不断…...

【网络分析工具】网络工具wireshark、TCPdump、iperf使用详解
这里写目录标题 1. wireshark1.1. 过滤包1.2. 常见分析 2. tcpdump3. iperf 1. wireshark **ip.dst eq 10.0.0.21** 是用于网络流量分析工具(例如 Wireshark 或 tcpdump)的过滤器表达式。 它的作用是筛选出所有目标IP地址为 10.0.0.21 的数据包 IP.add…...

debian中笔记本的省电选择auto-cpufreq
在reddit中,看评论区出现这个软件,于是打算尝试一下,应该能对不使用电源时笔记本的省电起到一定的作用。 https://github.com/AdnanHodzic/auto-cpufreq?tabreadme-ov-file#why-do-i-need-auto-cpufreq 作用 One of the problems with Linux…...

力扣热题100之环形链表 II
题目 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使…...

【记录】HunyuanVideo 文生视频工作流
HunyuanVideo 文生视频工作流指南 概述 本指南详细介绍如何在ComfyUI中使用腾讯混元HunyuanVideo模型进行文本到视频生成的全流程操作,包含环境配置、模型安装和工作流使用说明。 参考:https://comfyui-wiki.com/zh/install/install-comfyui/install-c…...

SpringCloud之Ribbon基础认识-服务负载均衡
0、Ribbon基本认识 Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端 负载均衡的工具。 Ribbon 主要功能是提供客户端负载均衡算法和服务调用 Ribbon 客户端组件提供一系列完善的配置项如连接超时,重试等。 Ribbon 会基于某种规则(如简单…...
[Java实战]Spring Boot 静态资源配置(十三)
[Java实战]Spring Boot 静态资源配置(十三) 引言 静态资源(如 HTML、CSS、JavaScript、图片等)是 Web 应用的基石。Spring Boot 通过自动化配置简化了静态资源管理,但面对复杂场景(如多模块项目、CDN 集成…...

重生之我在2024学Fine-tuning
一、Fine-tuning(微调)概述 Fine-tuning(微调)是机器学习和深度学习中的一个重要概念,特别是在预训练模型的应用上。它指的是在模型已经通过大量数据训练得到一个通用的预训练模型后,再针对特定的任务或数据…...

Selenium Web自动化测试学习笔记(一)
自动化测试 技术手段模拟人工,执行重复性任务,准确率100%,高于人工 selenium 可通过浏览器驱动控制浏览器,通过元素定位模拟人工,实现web自动化,没有焦点(把浏览器放在最小化依然可以&#x…...

2025年5月15日前 免费考试了! Oracle AI 矢量搜索专业认证
2025年5月5日前 免费考试了! Oracle AI 矢量搜索专业认证 立刻预约吧 文章目录 2025年5月5日前 免费考试了! Oracle AI 矢量搜索专业认证立刻预约吧🔍 探索 AI 向量搜索的强大功能!🎯 学习路径目标Ὦ…...
服务器不备案有影响吗
在当今数字化的时代,服务器成为了众多企业和个人开展业务、展示自我的重要工具。然而,有一个问题常常被忽视,那就是服务器不备案到底有没有影响? 答案是肯定的!服务器不备案,影响可不小。据相关数据显示&a…...

EasyRTC嵌入式音视频通话SDK驱动智能硬件音视频应用新发展
一、引言 在数字化浪潮下,智能硬件蓬勃发展,从智能家居到工业物联网,深刻改变人们的生活与工作。音视频通讯作为智能硬件交互与协同的核心,重要性不言而喻。但嵌入式设备硬件资源受限,传统音视频方案集成困难。EasyRT…...
力扣-21.合并两个有序链表
题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 class Solution { public:ListNode *mergeTwoLists(ListNode *list1, ListNode *list2) {ListNode *l new ListNode(-1);ListNode *p l;while (list1 &&…...
多线服务器具有什么优势
在当今数字化飞速发展的时代,多线服务器宛如一位低调的幕后英雄,默默为我们的网络世界提供着强大的支持。那么,多线服务器到底具有哪些令人瞩目的优势呢 首先,多线服务器的最大优势之一就是网络访问的高速与稳定。想象一下&#x…...
ESP32 PWM音频应用及场景说明
ESP32芯片的PWM(脉冲宽度调制)功能在音频应用中具有广泛用途,尤其是在低成本、低功耗的场景中。以下是具体的应用举例和应用场景说明: 一、ESP32 PWM音频应用举例 1. 简单音频播放 实现方式:通过PWM生成模拟音频信号&…...
C++.变量与数据类型
C++变量与数据类型 1. C++变量与数据类型1.1 基本数据类型1.2 复合数据类型2.1 定义方式2.2 常量类型3.1 数据类型修饰符3.2 存储类修饰符3.3 类访问修饰符4.1 算术运算符4.2 关系运算符4.3 逻辑运算符4.4 赋值运算符4.5 条件运算符4.6 位运算符5. 总结5.1 变量与数据类型5.2 常…...
Compose笔记(二十二)--NavController
这一节主要了解一下Compose中的NavController,它是实现导航功能的核心组件,提供了强大而灵活的页面管理能力,用于管理导航图中的目的地和执行导航操作。 API navigate(route: String) 含义:导航到指定路由的目的地。 作用&#x…...
SQL:SELF JOIN(自连接)与CROSS JOIN(交叉连接)
目录 SELF JOIN(自连接) CROSS JOIN(交叉连接 / 笛卡尔积) 示例: SELF JOIN CROSS JOIN 如果没有 DATEDIFF() 函数怎么办? 🔍 SELF JOIN vs CROSS JOIN 对比总结 SELF JOIN(自…...
互联网大厂Java求职面试:基于RAG的智能问答系统设计与实现-1
互联网大厂Java求职面试:基于RAG的智能问答系统设计与实现-1 场景背景 在某互联网大厂的技术面试中,技术总监张总正在面试一位名为郑薪苦的求职者。郑薪苦虽然对技术充满热情,但回答问题时总是带着幽默感,有时甚至让人哭笑不得。…...

Ubuntu 22.04.5 LTS 基于 kubesphere 安装 cube studio
Ubuntu 22.04.5 LTS 基于 kubesphere 安装 cube studio 前置条件 已经成功安装 kubesphere v4.3.1 参考教程: https://github.com/data-infra/cube-studio/wiki/%E5%9C%A8-kubesphere-%E4%B8%8A%E6%90%AD%E5%BB%BA-cube-studio 1. 安装基础依赖 # ubuntu安装基础依赖 apt insta…...

1.短信登录
1.0 问题记录 1.0.1 redis 重复 token 问题 每次用户登录时,后端会创建一个新的 token 并存入 Redis,但之前登录的 token 还没有过期。这可能会导致以下问题: 1. Redis 中存在大量未过期但实际已不使用的 token2. 同一用户可能有多个有效 …...

Linux-Ubuntu安装Stable Diffusion Forge
SD Forge在Win上配置起来相对简单且教程丰富,而在Linux平台的配置则稍有门槛且教程较少。本文提供一个基于Ubuntu24.04发行版(对其他Linux以及SD分支亦有参考价值)的Stable Diffusion ForgeUI安装配置教程,希望有所帮助 本教程以N…...

MixTeX - 支持CPU推理的多模态LaTeX OCR
文章目录 一、项目概览相关资源核心特性技术特点 二、安装三、使用说明环境要求 四、版本更新五、当前限制 一、项目概览 MixTeX是一款创新的多模态LaTeX识别小程序,支持本地离线环境下的高效CPU推理。 无论是LaTeX公式、表格还是混合文本,MixTeX都能轻…...
生成了一个AI算法
import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms # 1. 数据预处理 transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) # MNIST单通道归一化 ]) train_da…...

23、DeepSeek-V2论文笔记
DeepSeek-V2 1、背景2、KV缓存优化2.0 KV缓存(Cache)的核心原理2.1 KV缓存优化2.2 性能对比2.3 架构2.4多头注意力 (MHA)2.5 多头潜在注意力 (MLA)2.5.1 低秩键值联合压缩 (Low-Rank Key-Value …...
关键字where
C# 中的 where 关键字主要用在泛型约束(Generic Constraints)中,目的是对泛型类型参数限制其必须满足的条件,从而保证类型参数具备特定的能力或特性,增强类型安全和代码可读性。 约束写法说明适用场景举例C#版本要求w…...

【算法专题十一】字符串
文章目录 1. leetcode.14.最长公共前缀1.1 题目1.2 思路1.3 代码 2. leetcode.5.最长回文字串2.1 题目2.2 思路2.3 代码 3. leetcode.67.二进制求和3.1 题目3.2 思路3.3 代码 4. leetcode.43.字符串相乘4.1 题目4.2 思路4.3 代码 1. leetcode.14.最长公共前缀 1.1 题目 题目链…...

美化IDEA注释:Idea 中快捷键 Ctrl + / 自动注释的缩进(避免添加注释自动到行首)以及 Ctrl + Alt + l 全局格式化代码的注释缩进
打开 Settings 界面,依次选择 Editor -> Code Style -> Java,选择 Code Generation, 取消 Line comment at first column 和 Block comment at first column 的勾选即可, 1、Line comment at first column (行注释在第一列…...
如何为APP应用程序选择合适的服务器
搭建一个成功的APP应用程序,服务器选择是至关重要的决策之一。合适的服务器不仅能确保应用流畅运行,还能节省成本并保障安全性。本文将为您详细解析如何为APP选择最佳服务器方案。 一、了解您的APP需求 在选择服务器前,首先需要明确您的应用…...

赛灵思 XCZU11EG-2FFVC1760I XilinxFPGAZynq UltraScale+ MPSoC EG
XCZU11EG-2FFVC1760I 是 Zynq UltraScale MPSoC EG 系列中性能最强的器件之一,集成了四核 ARM Cortex-A53 应用处理器、双核 Cortex-R5 实时处理器与 Mali-400 MP2 GPU,并结合了 653,100 个逻辑单元与丰富的片上存储资源,可满足高性能计算、A…...