RISC-V異常機制和異常定位

不少人在調試RISC-V core時,面對異常的出現不知所措,不知道如何定位代碼問題。這里將從RISC-V異常機制以及幾個異常實例學習下。

1 異常機制

1.1 什么是異常

異常是軟件程序員不得不要深入了解的,首先在學習異常機制前,對異常要有一個明確的理解。

狹義上來說異常和中斷的最大區別在于:中斷往往是外部原因導致,而異常則是因為處理器內部原因或者程序執行引起,譬如硬件故障、程序故障,或者執行系統調用引起,簡而言之異常來源于內因。

實際上,廣義上來說,中斷也是異常的一種,站在處理器的角度來看,無論是異常還是中斷發生時,處理器都會暫停當前執行的程序,轉而去處理中斷或者異常的程序,處理完成之后視情況恢復之前被暫停的程序。
處理器廣義上的異常,通常只分為同步異常(Synchronous Exception)異步異常(Asynchronous Exception)

  • 同步異常
    同步異常時由于執行程序指令流或者試圖執行程序指令流造成的異常。這種異常能夠通過異常指令(PC)直接定位到,另外這種異常時穩定復現的。(比如指令非對齊、非法指令或者訪問地址屬性出錯等)
  • 異步異常
    異步異常是由“外因”引起,比如“外部中斷”,或者執行程序時堆棧溢出,導致的異常。另外對于異步異常可以分為兩種:
    • 精確異步異常( Precise Asynchronous Exception),指令在響應異常后,處理器狀態能夠精確反應為某一條指令的邊界,比如中斷。
    • 非精確異步異常( Imprecise Asynchronous Exception ),指令在響應異常后,處理器狀態無法精確反應為某一條指令的邊界,比如讀寫存儲器異常。

當然,一般現在商用的CPU很難說用戶發現了硬件異常,因為發布之前已經都做了充分的驗證了,一般用戶拿到,常見的都是因為軟件原因造成的。

通常情況下,對于軟件工程師來說,理論上可以把中斷當作異常的來看,但實際上各廠家的設計中斷一般還是異常分開處理的,所以使用上還是基于狹義上的異常概念來區分異常和中斷,前面有講過RISC-V的中斷機制和應用:
RISC-V CLINT、PLIC及芯來ECLIC中斷機制分析 —— RISC-V中斷機制(一)
ECLIC中斷流程及實際應用 —— RISC-V中斷機制(二)

1.2 相關CSR

RISC-V有四種特權模式:M/H/S/U,之前有介紹過 RISC-V特權模式及切換_risc-v 模式,感興趣的可以移步學習,RISC-V提供了M模式和S模式下分別的異常處理相關寄存器。

  • **??M模式 (Machine Mode)**?? 是最高特權級別,所有 RISC-V 處理器都必須實現。它提供了一整套以 ‘m’ 開頭的異常寄存器(如 mtvec, mepc, mcause, mstatus, mie, mip, mtval, mscratch),用于處理最底層的硬件異常和中斷。此模式是系統啟動和初始化的默認環境,簡單嵌入式系統可能僅運行于此模式。

  • **??S模式 (Supervisor Mode)**?? 旨在支持運行類 Unix 等現代操作系統。它配備了一套以 ‘s’ 開頭的異常寄存器(如 stvec, sepc, scause, sstatus, sie, sip, stval, sscratch),其功能與 M 模式下的相應寄存器類似,但用于操作系統內核的異常處理。

默認情況下,所有異常首先由 M 模式處理。但通過 ??異常委托機制??(使用 medeleg 和 mideleg 寄存器),可以選擇性地將部分中斷和同步異常委托給 S 模式處理,從而減少特權模式切換的開銷,提升操作系統的處理效率,這里也以M模式下異常處理機制為例介紹。

1.2.1 mcause(Machine Exception Cause)

RISC-V標準的mcause格式如下:其中最高bit Interrupt用來指示當前是中斷還是異常,位bit用來記錄異常code。
在這里插入圖片描述
異常code
在這里插入圖片描述
另外,如果一條指令引發多個同步異常,下面圖示指明了mcause異常code的優先順序。

在這里插入圖片描述
另外之前在中斷時有介紹過RISC-V官方還未將CLIC中斷納入標準,但是有些業界RISC-V設計公司是基于CLIC做了設計,比如芯來科技的ECLIC,支持中斷嵌套和中斷咬尾,對mcause進行了修改,如下:
在這里插入圖片描述
EXCCODE字段在異常時為異常編碼,中斷時為中斷號,其他位域不再詳細說明,可以參見中斷相關博客。

1.2.2 mtvec(Machine Trap-Vector Base-Address Register)

該寄存器用于保存異常向量地址,由向量基址和向量模式組成
在這里插入圖片描述
向量模式字段,其中非向量中模式,全部異常指向同一地址,而非向量模式,異步中斷地址指向BASE+4xcause(中斷號)
在這里插入圖片描述
另外,要求異常的BASE地址必須4字節對齊,前面也有介紹過芯來科技中斷架構,也是對mtvec做了修改。
具體時如何實現向量和非向量中斷的,同樣參考中斷相關博客。
在這里插入圖片描述

1.2.3 mepc (Machine Exception Program Counter)

機器模式異常程序計數器,它指向發生異常的指令。對于同步異常,mepc 指向導致異常的指令;對于中斷,它指向中斷處理后應該恢復執行的位置。
另外,值得注意的是,雖然 mepc 寄存器會在異常發生時自動被硬件更新,但是 mepc 寄存器本身也是一個(在 Machine Mode 下)可讀可寫的寄存器,因此軟件也可以直接寫該寄存器以修改它的值。
在這里插入圖片描述

1.2.4 mie(Machine Interrupt Enable)和mip(Machine Interrupt Pending)

MEIE/MEIP、MTIE/MTIP、MSIE/MSIE,分別對應M模式下的外部中斷、timer中斷、軟中斷的enable和pending。

在這里插入圖片描述
在這里插入圖片描述
如果使用芯來的ECLIC,是不需要使用mie和mip的,具體參考中斷相關博客

1.2.5 mstatus(Machine Status)

機器模式(M-mode)下的一個核心??控制與狀態寄存器??(CSR)。它主要負責全局中斷管理、特權模式切換及處理器狀態監控。
在這里插入圖片描述
SD:status dirty 狀態臟位,
MIE/SIE:機器/監督者模式全局中斷使能
MPIE/SPIE:發生異常前MIE/SIE的使能狀態,會被保存到這里。(P:previous)
MPP/SPP:發生異常時,硬件將異常前的特權模式保持到這里。執行mret或者sret,處理器將恢復為MPP/SPP所指定的模式。
FS/XS/VS:浮點單元狀態/擴展單元狀態/向量單元狀態(RVV擴展)
UBE:字節序控制。0表示小端,1表示大端。通常固定為小端。
SUM:允許S模式下訪問U模式的頁面(用于操作系統讀寫用戶程序數據)
MXR:使能可執行讀取,置1表示所有可讀頁表變為可執行
TSR/TW/TVM/MPRV筆者還沒有使用過,不在列舉,可以自行搜索了解。

1.2.6 mtval(Machine Trap Value Register)

在異常發生時,由硬件自動更新的??控制狀態寄存器??(CSR)。它的主要作用是??提供與異常相關的附加信息??,幫助軟件診斷和處理異常。
在這里插入圖片描述
mtval 提供的是??輔助信息??,確定異常的根本原因主要還需結合 ??mcause??(異常原因寄存器)和 ??mepc??(異常程序計數器)的值,另外mtval的具體行為??取決于硬件實現??,并非所有異常或所有芯片都一定會填充有效值

1.2.7 mscratch(Machine Scratch)

mscratch 的具體使用方式??很大程度上取決于軟件的實現??,比如:可以在異常時暫存某些通用寄存器的值,防止關鍵數據被破壞;還可以在調試時利用mscratch里存儲臨時調試信息或者斷點信息等

1.3 異常處理流程

前面說中斷也是異常的一種,所以異常的處理流程和中斷一樣。在bootloader階段,軟件初始化了mtvec寄存器,把異常handler的地址初始化到mtvec。然后軟件配合硬件來完成異常處理,具體流程如下:
在這里插入圖片描述
當異常發生時,處理過程分為??硬件自動執行??和??軟件處理??兩大部分:

  • 第一階段:硬件自動響應(處理器單元)
    一旦檢測到異常,硬件會??自動且立即??執行以下操作
  1. 關鍵信息保存??:
    • 將當前 PC 值存入 ??mepc??,作為返回地址。
    • 將異常原因寫入 ??mcause??。
    • 將異常相關的附加信息(如出錯的地址或指令)寫入 ??mtval??。
  2. ?狀態切換??:
    • 將當前權限模式保存到 ??mstatus.MPP??,然后切換到 ??M 模式??(Machine Mode)。
    • 將當前全局中斷使能位 ??mstatus.MIE?? 保存到 ??mstatus.MPIE??,然后??清除 MIE(關閉全局中斷)??,防止處理過程被新的中斷打斷。
  3. ??跳轉執行??:
    • 處理器從 ??mtvec?? 寄存器指向的地址開始取指執行,即跳轉到預先設置好的異常處理程序。
  • 第二階段:軟件處理(操作系統/固件)
    這是操作系統或固件編寫者需要實現的代碼邏輯,主要步驟包括:
  1. ??保存執行上下文??:
    • 硬件??不會自動保存??通用寄存器(x0-x31)。??軟件必須??首先將所有的通用寄存器壓入棧(通常是內核棧)中,以防止破壞被中斷程序的現場。
  2. 診斷異常原因??:
    • 軟件讀取 ??mcause?? 寄存器,根據其中的異常編碼判斷具體的異常或中斷類型。
  3. ?執行處理程序??:
    • 根據異常類型,跳轉到相應的處理例程(如系統調用處理、中斷服務程序等)。
  4. 恢復現場并返回??:
    • 處理完成后,從棧中??恢復所有通用寄存器??的原始值。
    • 執行 ??mret?? 指令。

最后,mret指令會觸發硬件:

  • 將 ??mepc?? 中的值載入 PC,從而返回到原來的執行流。
  • 根據 ??mstatus?? 中保存的信息(MPIE, MPP)恢復之前的權限模式和中斷使能狀態。

這里有幾點需要注意:

  • 1、RISC-V標準中,中斷和異常硬件處理是一樣的,處理函數入口都是在mtvec,軟件根據mcause Interrupt字段的值來區分異常中斷
  • 2、但這里效率不高,社區開源的CLIC對這塊進行了優化,把中斷和異常分開處理,mtvec自作為異常的處理入口,中斷單獨定義一組寄存器,可以參考我之前的博客:
  • 3、一般出現異常時,我們就會在異常服務函數里dump出來一些關鍵信息,然后把core給停掉(已經異常了,要去debug異常問題去了,在跑下去也沒什么意義的),所以就不會有后面的流程(恢復寄存器狀態、推出異常處理流程等),比如跑linux時經常會看見oops一堆的打印,就是內核在異常時系統拋出的信息,以方便定位問題。

2 異常定位

RISC-V異常機制是很直接的,前面有提到會在異常處理函數時打印出來關鍵信息方便分析定位問題,下面就針對常見的幾種異常舉例說明。
我這里使用的芯來科技的QEMU來實現的異常,平臺搭建可以參考:
RISC-V匯編學習(四)—— RISCV QEMU平臺搭建(基于芯來平臺)

2.1 異常處理函數

可以看到在進入異常之后,會把異常相關的CSR、通用寄存器和堆棧信息打印出來。

/*** \brief      System Default Exception Handler* \details* This function provides a default exception and NMI handler for all exception ids.* By default, It will just print some information for debug, Vendor can customize it according to its requirements.* \param [in]  mcause    code indicating the reason that caused the trap in machine mode* \param [in]  sp        stack pointer*/static void system_default_exception_handler(unsigned long mcause, unsigned long sp)
{/* TODO: Uncomment this if you have implement printf function */printf("MCAUSE : 0x%lx\r\n", mcause);printf("MDCAUSE: 0x%lx\r\n", __RV_CSR_READ(CSR_MDCAUSE));printf("MEPC   : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));printf("MTVAL  : 0x%lx\r\n", __RV_CSR_READ(CSR_MTVAL));printf("HARTID : %u\r\n", (unsigned int)__get_hart_id());Exception_DumpFrame(sp, PRV_M);
#if defined(SIMULATION_MODE)extern void simulation_exit(int status);simulation_exit(1);
#else#ifdef CFG_SIMULATIONsimulation_fail();#endifwhile (1);
#endif
}/*** \brief      Dump Exception Frame* \details* This function provided feature to dump exception frame stored in stack.* \param [in]  sp    stackpoint* \param [in]  mode  privileged mode to decide whether to dump msubm CSR*/
void Exception_DumpFrame(unsigned long sp, uint8_t mode)
{EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
#ifndef __riscv_32eprintf("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx, t3: 0x%lx, t4: 0x%lx, t5: 0x%lx, t6: 0x%lx\n"            "a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx, a6: 0x%lx, a7: 0x%lx\n"            "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0,            exc_frame->t1, exc_frame->t2, exc_frame->t3, exc_frame->t4, exc_frame->t5, exc_frame->t6,            exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, exc_frame->a4, exc_frame->a5,            exc_frame->a6, exc_frame->a7, exc_frame->cause, exc_frame->epc);
#elseprintf("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx\n"            "a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx\n"            "cause: 0x%lx, epc: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0,            exc_frame->t1, exc_frame->t2, exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3,            exc_frame->a4, exc_frame->a5, exc_frame->cause, exc_frame->epc);
#endifif (PRV_M == mode) {/* msubm is exclusive to machine mode */printf("msubm: 0x%lx\n", exc_frame->msubm);}
}

2.2 讀寫訪問異常定位

該異常發生時,異常打印如下,我們來分析定位下:
在這里插入圖片描述
當然一開始我們并不清楚是什么異常,并且是哪里,什么造成的原因造成的這種異常;接下來就來分析下。
mcause:最高bit是Interrupt域,值為0,表明當前是一個異常,EXCODE=5,一個load access 異常,也就是說程序里讀了一個非法地址(最高byte 0x3是MPP表示中斷前就是在M模式)
mdcause:這個是芯來科技RISC-V core自定義的CSR,用來進一步查看異常的原因(該興趣自行找資料了解下)
在這里插入圖片描述
mepc:0x8800120e,異常地址,但讀寫異常時非精確的異常,該地址并不能精確定位異常位置(一般異常位置在該地址之前)。
mtval:0xff00b000,異常地址,該地址可以正確反映到異常訪問地址的,說明我們讀了一個0xff00b000的非法地址。
ra是返回地址,當前執行結束之后會跳到該地址,也就是說在ra前出現了訪問異常。

當然到這里已經很清晰了,實際就是我們讀了一個非法地址,這里故意讀了下0xff00b000,

uint32_t addr_load_test(void)
{uint32_t * test_addr = (uint32_t *) 0xff00b000;uint32_t value = REG32( test_addr);
}

匯編:

880011f8 <addr_load_test>:
880011f8:	1101                	add	sp,sp,-32
880011fa:	ce06                	sw	ra,28(sp)
880011fc:	cc22                	sw	s0,24(sp)
880011fe:	1000                	add	s0,sp,32
88001200:	ff00b7b7          	lui	a5,0xff00b
88001204:	fef42623          	sw	a5,-20(s0)
88001208:	fec42783          	lw	a5,-20(s0)
8800120c:	439c                	lw	a5,0(a5)
8800120e:	fef42423          	sw	a5,-24(s0)
88001212:	0001                	nop
88001214:	853e                	mv	a0,a5
88001216:	40f2                	lw	ra,28(sp)
88001218:	4462                	lw	s0,24(sp)
8800121a:	6105                	add	sp,sp,32
8800121c:	8082                	ret

mepc是0x8800120e,實際是上一條 8800120c: 439c lw a5,0(a5) 執行報錯,這里從內存地址 a5 + 0(0xff00b000)處讀取一個 32 位的字(4 字節),并將其寫入寄存器 a5。

這里通用寄存器是可以正確反映異常前的信息的,如果想要從通用寄存器來定位,就需要直到RISC-V的abi規則了,后面會展示下。

當然寫異常也是一樣的。
只需要修改下代碼,向非法地址0xff00b000中寫入數據即可。

uint32_t addr_load_test(void)
{uint32_t * test_addr = (uint32_t *) 0xff00b000;REG32( test_addr) = 0x1;
}

運行代碼將會出現下面為store非法地址異常打印:
在這里插入圖片描述
讀寫異常當然并非一定是訪問了非法地址,比如訪問的IP模塊沒有時鐘或者復位被拉住,此時訪問IP內部的寄存器或者memory一樣會產生讀寫異常。

2.3 非法指令異常

2.3.1 text段被異常改寫

在這里插入圖片描述
異常前后的匯編:

88001274:	301027f3          	csrr	a5,misa
88001278:	fcf42e23          	sw	a5,-36(s0)
8800127c:	fdc42783          	lw	a5,-36(s0)
88001280:	fef42023          	sw	a5,-32(s0)

通過gdb來讀取異常地址處的指令值,如下:
0x88001274處期望的指令0x301027f3被改寫為了0x00001234
在這里插入圖片描述
接下來可以通過watchpoint來監控0x88001274地址的改動,便可以發現有代碼(這里故意修改)修改了text段的代碼(當然也是我們故意造的異常點)
在這里插入圖片描述

2.3.2 棧幀被異常修改

一般我們會故意修改text段代碼,但有時間,軟件代碼不合理,造成了棧溢出、數據污染等也會造成指令異常。
在這里插入圖片描述
查看上面的異常打印,通過CSR寄存器mcause知道是指令異常,但如何其他CSR比如MEPC,MTVAL都不是預期的(不在正常的內存分配地址),可能很多人看到這里無從下手,不好定位異常位置,當然原因是,不熟悉RISCV abi規則,對通用寄存器使用不熟悉的。

我之前在
RISC-V匯編學習(五)—— 匯編實戰、GCC內聯匯編(基于芯來平臺)的博客中有深入分析過riscv的abi規則,可以移步學習。

如果調試經驗多的話,容易分析,當前可能是因為堆棧溢出,導致了數據污染。我們可以看到打印里已經有很多寄存器包括ra,tp等寄存器的值已經不真實了,還有哪些是可信的呢?s0-sp表示當前使用的棧幀(RISC-V用s0和sp來填充棧幀)。
此時通過gdb回到異常現場,讀取s0和sp的值:
在這里插入圖片描述
注意異常入口必須把軟件處理部分干掉,不然此時將會進入異常的棧幀,并可能破壞掉當前異常的棧幀。
在這里插入圖片描述
同樣可以用watchpoint來定位軟件code,發現有兩處用到了該棧地址。
在這里插入圖片描述
很容易就可以定位到問題代碼的位置,實際上是我們定義了一個10個無符號整形變量,但初始化15個地址,棧幀溢出,導致地址踩臟。實際代碼如下:

void test(void)
{uint32_t test_data[10] = {0};for(int i = 0; i < 15;i++){test_data[i] = i;}
}

把上面代碼修改正確查看下該函數棧幀內容,如下:
在這里插入圖片描述
這里是把返回地址和上一個棧頂指針地址覆蓋了,導致了指令異常。

當然異常場景還有不少,這里僅展示幾個常見的;實際無論什么樣的異常都是可以從軟硬件的角度,去分析問題,前提是對ISA相對比較熟悉;另外一般裸機或者簡單rtos下的代碼量比較小時,通過異常機制可以幫忙快速定位問題;如果時linux下多線程任務的異常,當然也可以用,只是定位會相對會比較麻煩很多,如果有trance來dump指令流,將會事半功倍。

參考:
手把手教你設計CPU——RISC-V處理器篇(胡振波)
RISC-V匯編學習(五)—— 匯編實戰、GCC內聯匯編(基于芯來平臺)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/98204.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/98204.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/98204.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++中導出函數調用約定為__stdcall類型函數并指定導出函數名稱

開發環境在Visual studio 2022版本下&#xff0c;為防止編譯器重命名函數名稱&#xff08;會加上8等等亂七八糟的東西&#xff09;&#xff0c;我們對函數名稱進行指定&#xff1a;一、新建.def文件&#xff0c;名稱須與dll名稱相同&#xff0c;并放在與cpp文件相同文件夾下&am…

Vision Transformer (ViT) :Transformer在computer vision領域的應用(二)

METHOD,論文主要部分 In model design we follow the original Transformer (Vaswani et al., 2017) as closely as possible. An advantage of this intentionally simple setup is that scalable NLP Transformer architectures – and their efficient implementations –…

AI 論文周報丨紅隊測試語言模型/多視角 3D 點追蹤方法/蛋白質表示學習框架/密碼學漏洞檢測新框架……

近年來&#xff0c;已有若干方法嘗試從單目視頻實現 3D 點跟蹤&#xff0c;然而由于在遮擋和復雜運動等挑戰性場景中難以準確估計 3D 信息&#xff0c;這些方法的性能仍難以滿足實際應用對高精度與魯棒性的要求。 基于此&#xff0c;蘇黎世聯邦理工學院、卡內基梅隆大學聯合提出…

STM32 通過USB的Mass Storage Class讀寫掛載的SD卡出現卡死問題

問題描述&#xff1a;使用stm32cubemx生成的sdio和usb Mass Storage Class的代碼后&#xff0c;在USB_DEVICE\App\usbd_storage_if.c文件里面的接口調用以下函數出現卡死問題&#xff1a; SD_Driver.disk_initialize(0); SD_Driver.disk_read(lun, buf, blk_addr, blk_len) SD_…

Go語言中 error 接口與自定義錯誤類型的深入解析

在 Go 語言開發中&#xff0c;我們經常需要處理各種錯誤情況。Go 語言通過 error 接口提供了一套簡潔而強大的錯誤處理機制。然而&#xff0c;當涉及到自定義錯誤類型時&#xff0c;許多開發者會遇到一些令人困惑的問題。本文將通過一個實際案例來深入探討這個問題。 問題背景 …

字幕編輯工具推薦,Subtitle Edit v4.0.13發布:增強語音識別+優化翻譯功能

大家好呀&#xff0c;不知道大家有沒有做自媒體相關工作的呢&#xff0c;你們是不是也覺得剪輯視頻時最頭疼的往往不是畫面而是字幕&#xff0c;時間軸對不上、格式不兼容、需要手動翻譯&#xff0c;這些瑣碎工作消耗的精力甚至超過剪輯本身。 當你試遍各種在線工具卻發現要么…

【Java后端】Spring Boot 集成雪花算法唯一 ID

Spring Boot 實現基于雪花算法的分布式唯一 ID 生成器在分布式系統中&#xff0c;我們經常需要生成 全局唯一 ID&#xff0c;比如用戶 ID、訂單號、消息 ID 等。常見的方式有&#xff1a;數據庫自增主鍵、UUID、Redis/Zookeeper 分布式 ID 服務、百度 UidGenerator、美團 Leaf …

C語言初嘗試——洛谷

一、C數組&#xff1a;C 語言支持數組數據結構&#xff0c;它可以存儲一個固定大小的相同類型元素的順序集合。數組是用來存儲一系列數據&#xff0c;但它往往被認為是一系列相同類型的變量。聲明數組在 C 中要聲明一個數組&#xff0c;需要指定元素的類型和元素的數量&#xf…

C++八大排序

C排序算法一、概覽二、代碼實現1.冒泡排序2.插入排序3.希爾排序4.堆排序5.選擇排序6.快速排序7.歸并排序三、排序時間、空間復雜度總結排序&#xff0c;是C各大算法當中非常常見的一個步驟&#xff08;過程&#xff09;&#xff0c;通常我們使用便捷的algorithmalgorithmalgori…

每天五分鐘深度學習:深層神經網絡的優勢

本文重點 在人工智能領域,深層神經網絡(DNN)的崛起標志著技術范式的根本性轉變。相較于傳統淺層神經網絡(如單層感知機、線性回歸模型),深層網絡通過引入多層隱藏層,實現了對復雜數據模式的深度解析與高效建模。 深層神經網絡 神經網絡中輸入層表示神經網絡的第0層,…

相機幾何 空間點到像素平面轉換

一個空間中點到像素平面轉換&#xff0c;需要經過1. 空間坐標系轉換到相機坐標系2. 相機坐標系下3D點到相機平面轉換3. 相機平面到像素平面轉換相機三維空間到像素平面轉換1. 3D點到相機平面轉換2. 相機平面到像素平面轉換涉及到單位的轉換&#xff0c;和像素原點到相機平面原點…

webpack5 vue3同一倉庫,不同命令切換項目

技術方案&#xff1a;手動輸入不同的命令&#xff0c;啟動不同項目。實現這種能力本篇文章是通過不同路由劃分&#xff0c;進而實現不同項目的劃分。所以簡單來說就是通過輸入不同命令行在webpack中找到不同項目的路由&#xff0c;進而打不同項目的包&#xff0c;實現項目隔離。…

PowerBI實戰-制作帶有同比及趨勢線的雙柱狀圖

一、引言 今天的PowerBI報表的制作相對有一點復雜&#xff0c;我們直接根據最終展示圖來講解&#xff1a; 可以看到&#xff0c;我們今天要制作的圖像需要包括以下幾點&#xff1a;時間維度的趨勢、兩種不同維度的數據對比、不同數據標簽的展示、不同年份間環比的標簽展示以及…

物聯網智能網關配置教程:實現注塑機數據經基恩士PLC上傳至云平臺

一、項目背景隨著制造業向智能化、信息化方向快速發展&#xff0c;注塑車間作為塑料制品制造的核心環節&#xff0c;面臨著設備協議多樣、數據孤島嚴重、系統集成困難等問題。某大型注塑企業計劃對其老舊車間進行數字化改造&#xff0c;實現設備數據采集、遠程監控與MES系統對接…

【實戰】預警算法--噪聲添加機制

1. 背景 在多變量自聯想預測或異常檢測場景中&#xff0c;我們常使用帶噪自編碼器&#xff08;Denoising AutoEncoder&#xff0c;DAE&#xff09;來訓練模型&#xff0c;使模型能夠從帶噪輸入中重構原始數據。噪聲的添加方式對訓練效果、穩定性以及模型用途有顯著影響。 2. 兩…

ChromaDB探索

關于 ChromaDB、向量與 RAG 系統的核心知識問答總結 ??Q1: ChromaDB 是什么&#xff1f;它在數據庫領域中扮演什么角色&#xff1f;????A:?? ChromaDB 是一款開源的??向量數據庫??。它的核心角色是專門為 AI 應用&#xff08;如語義搜索、推薦系統、RAG&#xff09…

C# 基于halcon的視覺工作流-章33-矩狀測量

C# 基于halcon的視覺工作流-章33-矩狀測量 本章目標&#xff1a; 一、gen_measure_rectangle2準備提取垂直于矩形的直邊&#xff1b; 二、measure_pos 提取垂直于矩形或環形弧的直線邊緣&#xff1b; 三、measure_pairs提取垂直于矩形或環形弧長軸的直邊對&#xff1b; 四、匹配…

Day05_蒼穹外賣——Redis店鋪營業狀態設置

目錄1.1 Redis簡介1.2 Redis下載與安裝1.2.1 Redis下載1.2.2 Redis安裝1.3 Redis服務啟動與停止1.3.1 服務啟動命令1.3.2 客戶端連接命令1.3.3 修改Redis配置文件1.3.4 Redis客戶端圖形工具2. Redis數據類型2.1 五種常用數據類型介紹2.2 各種數據類型特點3. Redis常用命令3.1 字…

雙指針:字符串

題目&#xff1a;字符串 題目概述&#xff1a;找包含所有小寫字母的最短字符串。 重點思路&#xff1a; right是 < len-1字符 - ‘26’轉換成整形再判斷&#xff08;寫字符a也可以&#xff0c;更準確&#xff09;。 #include <iostream> #include <algorithm>…

HarmonyOS 應用開發深度實踐:精通 Stage 模型與 UIAbility 生命周期

好的&#xff0c;請看這篇關于 HarmonyOS Stage 模型與 UIAbility 深度實踐的技術文章。 HarmonyOS 應用開發深度實踐&#xff1a;精通 Stage 模型與 UIAbility 生命周期 引言 隨著 HarmonyOS 4、5 的廣泛部署和 HarmonyOS NEXT (API 12) 的發布&#xff0c;華為的分布式操作系…