一文掌握Ascend C孿生調試

1? What,什么是孿生調試

Ascend C提供孿生調試方法,即CPU域模擬NPU域的行為,相同的算子代碼可以在CPU域調試精度,NPU域調試性能。孿生調試的整體方案如下:開發者通過調用Ascend C類庫編寫Ascend C算子kernel側源碼,kernel側源碼通過通用的GCC編譯器進行編譯,編譯生成通用的CPU域的二進制,可以通過gdb通用調試工具等調試手段進行調試;kernel側源碼通過畢昇編譯器進行編譯,編譯生成NPU域的二進制文件,可以通過msprof工具進行性能數據采集等方式進行調試。

針對NPU域的調試來講,根據依賴和調用動態庫的不同,分為NPU域仿真調試和NPU域上板調試。NPU域仿真調試,依賴和調用的是model仿真器指定的庫文件,運行model仿真不需要使用真實的NPU環境;上板調試,依賴和調用的是真實NPU環境上的庫文件,進行上板調試需要真實的NPU環境。

CPU域調試用于定位邏輯錯誤、內存錯誤等功能問題; NPU域調試不僅可以通過數據打印的方式定位功能問題,也可以用于定位性能問題、算子同步問題。

本文將從功能調試的角度出發,介紹CPU域和NPU域的調試方法,并通過具體的調試樣例來幫助大家快速掌握;性能調試的方法將在后續的文章中介紹。

2? HOW,如何進行調試

2.1? CPU域

本節介紹CPU域調試的兩種方法:gdb調試、使用printf打印命令打印。

2.1.1? gdb調試

gdb調試相信大家并不陌生,首先我們先來回顧幾個常用的調試命令,更多內容可以前往https://sourceware.org/gdb/深入學習。

命令

功能

step

執行下一行語句,?如語句為函數調用,?進入函數中

next

執行下一行語句,?如語句為函數調用,?不進入函數中

continue

從當前位置繼續運行程序

run

從頭開始運行程序

quit

退出程序

print

輸出變量值、調用函數、通過表達式改變變量值

list

查看當前位置代碼

backtrace

查看各級堆棧的函數調用及參數

break?N

在第N行上設置斷點

display

每次停下來時,顯示設置的變量var的值

這里稍微復雜一點的是,因為我們程序是多核執行程序,cpu調測將其轉為多進程調試,每個核都會拉起獨立的子進程,故gdb需要轉換成子進程調試的方式。下面介紹子進程調試的方法。

  1. 調試單獨一個子進程

在gdb啟動后,首先設置跟蹤子進程,之后再打斷點,就會停留在子進程中,設置的命令為:

set follow-fork-mode child

但是這種方式只會停留在遇到斷點的第一個子進程中,其余子進程和主進程會繼續執行直到退出。涉及到核間同步的算子無法使用這種方法進行調試。

如下是調試一個單獨子進程的調試命令樣例:

gdb --args add_custom_cpu

set follow-fork-mode child

break add_custom.cpp:45

run

list

backtrace

print i

break add_custom.cpp:56

continue

display xLocal

quit

  1. 調試多個子進程

如果涉及到核間同步,那么需要能同時調試多個子進程。

在gdb啟動后,首先設置調試模式為只調試一個進程,掛起其他進程。設置的命令如下:

(gdb) set detach-on-fork off

查看當前調試模式的命令為:

??????(gdb) show detach-on-fork

中斷gdb程序的方式要使用捕捉事件的方式,即gdb程序監控fork這一事件并中斷。這樣在每一次起子進程時就可以中斷gdb程序。設置的命令為:

(gdb) catch fork

當執行r后,可以查看當前的進程信息:

(gdb) info inferiors

??Num ?Description

* 1 ???process 19613

可以看到,當第一次執行fork的時候,程序斷在了主進程fork的位置,子進程還未生成。

執行c后,再次查看info inferiors,可以看到此時第一個子進程已經啟動。

(gdb) info inferiors

??Num ?Description

* 1 ???process 19613

??2 ???process 19626

這個時候可以使用切換到第二個進程,也就是第一個子進程,再打上斷點進行調試,此時主進程是暫停狀態:

(gdb) inferior 2

[Switching to inferior 2 [process 19626] ($HOME/demo)]

(gdb) info inferiors

??Num ?Description

??1 ???process 19613

* 2 ???process 19626

請注意,inferior后跟的數字是進程的序號,而不是進程號。

如果遇到同步阻塞,可以切換回主進程繼續生成子進程,然后再切換到新的子進程進行調試,等到同步條件完成后,再切回第一個子進程繼續執行。

2.1.2? printf打印命令

printf則更為簡單,直接使用printf打印命令printf(...)來觀察數值的輸出。需要注意的是:NPU模式下目前不支持打印語句,所以需要添加內置宏__CCE_KT_TEST__予以區分。樣例代碼如下:

printf("xLocal size: %d\n", xLocal.GetSize());

printf("tileLength: %d\n", tileLength);

2.2? NPU域????????

2.2.1? 上板數據打印(DumpTensor、PRINTF)

功能包括DumpTensor、PRINTF兩種,其中DumpTensor用于打印指定Tensor的數據,PRINTF主要用于打印標量和字符串信息。

具體的使用方法如下:

1. 設置打開DUMP開關的環境變量

export ACL_DUMP_DATA=1

修改Dump信息配置文件acl.json。單算子調用應用開發場景下,新建acl.json放在應用開發的工程目錄下,在調用aclInit接口時傳入;Pytorch調用場景下,放在Pytorch腳本執行目錄下,由框架自行讀取。配置樣例如下:其中dump_path表示dump數據文件存儲到運行環境的目錄,支持配置絕對路徑或相對路徑;dump_mode表示dump的模式,配置成input/output/all有效模式均可以;dump_op_switch表示單算子dump數據開關,需要配置成on,開啟單算子dump模式;dump_debug為預留參數,開發者無需關注,直接配置成off即可。

{

????"dump":{

????????"dump_path":"/dump",

????????"dump_mode": "all",

????????"dump_debug": "off",

????????"dump_op_switch": "on"

?????}

}

2. 增加算子工程編譯選項-DASCENDC_DUMP:修改算子工程op_kernel目錄下的CMakeLists.txt文件,首行增加編譯選項,打開DUMP開關,樣例如下:

add_ops_compile_options(ALL OPTIONS -DASCENDC_DUMP)

3.?在算子kernel側實現代碼中需要輸出日志信息的地方調用DumpTensor接口或者PRINTF接口打印相關內容

a)?DumpTensor示例,srcLocal表示待打印的Tensor;5表示用戶的自定義附加信息,比如當前的代碼行號;dataLen表示元素個數。

DumpTensor(srcLocal,5, dataLen);

Dump時,每個block核的dump信息前會增加對應信息頭DumpHead(32字節大小),用于記錄核號和資源使用信息;每次Dump的Tensor數據前也會添加信息頭DumpTensorHead(32字節大小),用于記錄Tensor的相關信息。如下圖所示,展示了多核打印場景下的打印信息結構。

DumpHead的具體信息如下:

  • block_id:當前運行的核號;
  • total_block_num:此次dump的核數;
  • block_remain_len:當前核剩余可用的dump的空間;
  • block_initial_space:當前核初始分配的dump空間;
  • magic:內存校驗魔術字。

DumpTensorHead的具體信息如下:

  • desc:用戶自定義附加信息;
  • addr:Tensor的地址;
  • data_type:Tensor的數據類型;
  • position:表示Tensor所在的物理存儲位置。

打印結果的樣例如下:

DumpHead: block_id=0, total_block_num=16, block_remain_len=1048448, block_initial_space=1048576, magic=5aa5bccd

DumpTensor: desc=5, addr=0, data_type=DT_FLOAT16, position=UB

[40, 82, 60, 11, 24, 55, 52, 60, 31, 86, 53, 61, 47, 54, 34, 62, 84, 29, 48, 95, 16, 0, 20, 77, 3, 55, 69, 73, 75, 40, 35, 13]

DumpHead: block_id=1, total_block_num=16, block_remain_len=1048448, block_initial_space=1048576, magic=5aa5bccd

DumpTensor: desc=5, addr=0, data_type=DT_FLOAT16, position=UB

[58, 84, 22, 54, 41, 93, 1, 45, 50, 9, 72, 81, 23, 96, 86, 45, 36, 9, 36, 34, 78, 7, 2, 29, 47, 26, 13, 24, 27, 55, 90, 5]

...

DumpHead: block_id=7, total_block_num=16, block_remain_len=1048448, block_initial_space=1048576, magic=5aa5bccd

DumpTensor: desc=5, addr=0, data_type=DT_FLOAT16, position=UB

[28, 27, 79, 39, 86, 5, 23, 97, 89, 5, 65, 69, 59, 13, 49, 2, 34, 6, 52, 38, 4, 90, 11, 11, 61, 50, 71, 98, 19, 54, 54, 99]

b)?PRINTF示例如下:

PRINTF("fmt string %d", 0x123);

3? Example,調試樣例

下面通過具體的樣例來實戰一下吧!

3.1? CPU域調試樣例

在進行調試之前我們需要獲取一個精度有問題的算子樣例

1. 通過如下的樣例鏈接獲取正確的樣例。(CPU調試當前僅適用于通過內核調用符調用算子的程序調試,所以這里我們獲取KernelLaunch的代碼樣例)

https://gitee.com/ascend/samples/tree/master/operator/AddCustomSample/KernelLaunch

2. 將AddKernelInvocation / add_custom.cpp中的Init函數替換成如下有bug的代碼。

__aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z)

????{

????????xGm.SetGlobalBuffer((__gm__ half*)x + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH);

????????yGm.SetGlobalBuffer((__gm__ half*)y + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH);

????????zGm.SetGlobalBuffer((__gm__ half*)z + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH);

????????pipe.InitBuffer(inQueueX, BUFFER_NUM, TILE_LENGTH);

????????pipe.InitBuffer(inQueueY, BUFFER_NUM, TILE_LENGTH);

????????pipe.InitBuffer(outQueueZ, BUFFER_NUM, TILE_LENGTH);

}

3. 參考樣例readme,跑一下樣例,樣例出現如下報錯:

[ERROR] result error

下面我們一起開始debug之旅吧。

  1. 觀察日志報錯。

觀察是否有打屏日志報錯,可搜索關鍵詞"failed"。下圖的報錯示例指示,錯誤出現在代碼中調用Add接口的地方。

add_cpu: /usr/local/Ascend/ascend-toolkit/7.0.RC1.alpha003/x86_64-linux/tikcpp/tikcfw/interface/kernel_operator_vec_binary_intf.h:79:?void AscendC::Add(const AscendC::LocalTensor<T>&, const AscendC::LocalTensor<T>&, const AscendC::LocalTensor<T>&, const int32_t&) [with T = float16::Fp16T; int32_t = int]: Assertion `false && "check vadd instr failed"' failed.

通過上述報錯日志,一般只能定位到框架報錯的代碼行,無法明確具體錯誤,接下來需要通過gdb調試的方式或者printf打印的方式進一步精確定位。

2. gdb調試。下面的樣例展示了拉起Add算子CPU側運行程序的樣例,該樣例程序會直接拋出異常,直接gdb運行,查看調用棧信息分析定位即可。其他場景下您可以使用gdb打斷點等基本操作進行調試。

????????1) 使用gdb拉起待調試程序,進入gdb界面進行debug。

gdb add_cpu

? ? ? ? 2) 單獨調試一個子進程。

(gdb) set follow-fork-mode child

? ? ? ? 3) 運行程序。

(gdb) r

? ? ? ? 4) 通過bt查看程序調用棧。

(gdb) bt

? ? ? ? 5) 查看具體層的堆棧信息,打印具體變量的值。本示例中,查看報錯代碼的上一層第5層的堆棧,打印了TILE_LENGTH為128,該程序中表示需要處理128個half類型的數,大小為128*sizeof(half)=256字節;同時打印了輸入Tensor xLocal的值,其中dataLen表示LocalTensor的size大小為128字節,只能計算128字節的數據。可以看出兩者的長度不匹配,由此可以繼續檢查代碼內存分配時傳入長度是否有誤,從而定位到Init函數中InitBuffer的問題。同理,大家可以自行打印yLocal和zLocal的值。

(gdb) f 5

#5 ?0x0000555555560638 in KernelAdd::Compute (this=0x7fffffffd360, progress=0)

????at /samples-master/operator/AddCustomSample/KernelLaunch/AddKernelImpl/add.cpp:54

54 ?????????????Add(zLocal, xLocal, yLocal, TILE_LENGTH); (gdb) p TILE_LENGTH

$1 = 128

(gdb) p xLocal

$3 = {<AscendC::BaseTensor<float16::Fp16T>> = {<No data fields>}, address_ = {logicPos = 9 '\t', bufferHandle = 0x7fffffffd460 "\003\005\377\377\200", dataLen = 128,

bufferAddr = 0,absAddr = …}

3. printf打印。在調用報錯代碼行之前的位置增加變量打印。樣例代碼如下:

__aicore__ inline void Compute(int32_t progress)

????{

????????LocalTensor<half> xLocal = inQueueX.DeQue<half>();

????????LocalTensor<half> yLocal = inQueueY.DeQue<half>();

????????LocalTensor<half> zLocal = outQueueZ.AllocTensor<half>();

????????#ifdef __CCE_KT_TEST__

????????printf("xLocal size: %d\n", xLocal.GetSize());

printf("tileLength: %d\n", TILE_LENGTH);

#endif

????????Add(zLocal, xLocal, yLocal, TILE_LENGTH);

????????outQueueZ.EnQue<half>(zLocal);

????????inQueueX.FreeTensor(xLocal);

????????inQueueY.FreeTensor(yLocal);

????}

可以看到有如下打屏日志輸出,打印了tileLength為128,該程序中表示需要處理128個half類型的數;輸入Tensor xLocal的size大小,為64,表示只能計算64個half類型的數。可以看出兩者的長度不匹配,由此可以繼續檢查代碼內存分配時傳入長度是否有誤,從而定位到Init函數中InitBuffer的問題。

xLocal size: 64

tileLength: 128

3.2? NPU域調試樣例

在進行調試之前我們需要獲取一個精度有問題的算子樣例

  1. 通過如下的樣例鏈接獲取正確的樣例。(上板數據打印調試當前適用于單算子調用程序(aclnn接口)調試,所以這里我們獲取算子工程和aclnn單算子調用的代碼樣例)

???????samples: CANN Samples - Gitee.com

2. 將AddCustom / op_kernel / add_custom.cpp中的Init函數替換成如下有bug的代碼。

__aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z, uint32_t totalLength, uint32_t tileNum)

????{

????????ASSERT(GetBlockNum() != 0 && "block dim can not be zero!");

????????this->blockLength = totalLength / GetBlockNum();

????????this->tileNum = tileNum;

????????ASSERT(tileNum != 0 && "tile num can not be zero!");

????????this->tileLength = this->blockLength / tileNum / BUFFER_NUM;

????????xGm.SetGlobalBuffer((__gm__ half*)x + this->blockLength * GetBlockIdx(), this->blockLength);

????????yGm.SetGlobalBuffer((__gm__ half*)y + this->blockLength * GetBlockIdx(), this->blockLength);

????????zGm.SetGlobalBuffer((__gm__ half*)z + this->blockLength * GetBlockIdx(), this->blockLength);

????????pipe.InitBuffer(inQueueX, BUFFER_NUM, this->tileLength);

????????pipe.InitBuffer(inQueueY, BUFFER_NUM, this->tileLength);

????????pipe.InitBuffer(outQueueZ, BUFFER_NUM, this->tileLength);

????}

3. 參考樣例readme,跑一下算子的編譯部署以及aclnn調用樣例,aclnn調用樣例出現如下報錯:

[ERROR] result error

下面我們一起開始debug之旅吧。

在AddCustom / op_kernel / add_custom.cpp中關鍵的流程中增加數據打印

比如如下的示例代碼分別在計算前和計算后增加對zLocalTensor的數據打印,同時打印參與計算的元素個數。

DumpTensor(zLocal, __LINE__, zLocal.GetSize());

????????PRINTF("The data Length involved in calculation is %d.\n", this->tileLength);

????????Add(zLocal, xLocal, yLocal, this->tileLength);

????????DumpTensor(zLocal, __LINE__, zLocal.GetSize());

參考上文的上板數據打印流程進行環境變量、cmake文件等配置,運行aclnn單算子調用樣例,可以看到屏幕有如下打印:

DumpTensor: desc=54, addr=512, data_type=DT_FLOAT16, position=UB

[59.1875, 66.625, 53.4375, 52.0625, 80.3125, 10.5234, 21.3594, 43.2188, 1.15039, 50.625, 7.88672, 60.0625, 63.9062, 28.2812, 6.72266, 66.3125, 38.9062, 7.9375, 37.8125, 38.9062, 57.0938, 14.2266, 66.625, 62.3125, 5.17969, 1.63477, 45.2812, 68.1875, 59.9375, 23.8281, 71.8125,

45.1875, 59.2188, 53.875, 77.25, 47.5625, 75, 38.1875, 61.2812, 63.125, 58.5312, 83.6875, 44.5312, 57.125, 2.74609, 32.8438, 27.1094, 20.9219, 70.3125, 62.7188, 20, 6.90625, 30.5312, 91.75, 17.3125, 29.8125, 68.9375, 83.125, 23.4375, 58.8125, 62.6875,

69.9375, 19.9531, 46.25]

The data Length involved in calculation is 128.

DumpTensor: desc=57, addr=512, data_type=DT_FLOAT16, position=UB

[151.75, 158, 48.125, 96.25, 158, 74.125, 101.375, 34, 36.2812, 112.375, 109.125, 95.25, 142.75, 44.75, 176.375, 130.125, 68.3125, 70.3125, 102.375, 92.75, 139.25, 55.4375, 87, 102.75, 177.375, 118.875, 113.375, 25.6562, 101.125, 107.75, 165.5,

72.5, 17.5625, 52.4688, 167.125, 132.75, 171.375, 98.75, 133.375, 107.5, 119.375, 149.25, 161.625, 146.375, 162.25, 88.8125, 119.375, 88.9375, 170.5, 91.625, 72.9375, 131.875, 71.5625, 44.6562, 57.0625, 101.5, 150.125, 71.75, 126.625, 113.688, 139.75,

107.938, 79.5625, 132.875]

觀察得到tensor的長度為64,但是設置的計算長度為128 兩者不匹配,進一步定位可以確定問題為Init時初始化buffer的長度錯誤。

通過本篇內容 大家可以了解Ascend?C孿生調試的概念,并可以參照實際樣例進行實戰練習。更多相關內容請參考:

《Ascend C 官方教程》

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

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

相關文章

Spring boot 發送郵箱

一、簡介 Spring 提供了非常好用的 JavaMailSender 接口實現郵件發送。在 SpringBoot 的 Starter 模塊中也為此提供了自動化配置。下面通過實例看看如何在 SpringBoot 中使用 JavaMailSender 發送郵件。 org.springframework.mail 是Spring Framework對郵件支持的基礎包&#x…

云計算大屏,可視化云計算分析平臺(云實時數據大屏PSD源文件)

大屏組件可以讓UI設計師的工作更加便捷&#xff0c;使其更高效快速的完成設計任務。現分享可視化云分析系統、可視化云計算分析平臺、云實時數據大屏的大屏Photoshop源文件&#xff0c;開箱即用&#xff01; 若需 更多行業 相關的大屏&#xff0c;請移步小7的另一篇文章&#…

mapstruct個人學習記錄

mapstruct核心技術學習 簡介入門案例maven依賴 IDEA插件單一對象轉換測試結果 mapping屬性Spring注入的方式測試 集合的映射set類型的映射測試map類型的映射測試 MapMappingkeyDateFormatvalueDateFormat 枚舉映射基礎入門 簡介 在工作中&#xff0c;我們經常要進行各種對象之…

非標識性參數—手機運營商

2.2 非標識性參數 2.2.1 手機運營商 IMSI&#xff1a; 國際移動用戶識別碼&#xff0c;共有15位&#xff0c;儲存在SIM卡中&#xff0c;由MCC、MNC&#xff0c;MSIN組成。 MCC&#xff1a; (國家)移動國家號碼&#xff0c;由3位數字組成&#xff0c;唯一的識別移動客戶所屬的…

【rabbitMQ】rabbitMQ用戶,虛擬機地址(添加,修改,刪除操作)

rabbitMQ的下載&#xff0c;安裝和配置 https://blog.csdn.net/m0_67930426/article/details/134892759?spm1001.2014.3001.5502 rabbitMQ控制臺模擬收發消息 https://blog.csdn.net/m0_67930426/article/details/134904365?spm1001.2014.3001.5502 目錄 用戶 添加用戶…

MyBatis 四大核心組件之 StatementHandler 源碼解析

&#x1f680; 作者主頁&#xff1a; 有來技術 &#x1f525; 開源項目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 倉庫主頁&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 歡迎點贊…

CPU設計——Triumphcore——MP_work版本

該版本用作系統寄存器的實現&#xff0c;M/S/U狀態的實現與切換&#xff0c;以及load/store的虛實地址轉換 設計指標 2023.12.8 2023.12.9 不實現mideleg和medeleg&#xff0c;因此一旦出現異常&#xff0c;直接切換至M態&#xff0c; 調試記錄 到存儲區中取PTE要額外至少…

airserver mac 7.27官方破解版2024最新安裝激活圖文教程

airserver mac 7.27官方破解版是一款好用的airplay投屏工具&#xff0c;可以輕松將ios熒幕鏡像&#xff08;airplay&#xff09;至mac上&#xff0c;在mac平臺上實現視頻、音頻、幻燈片等文件資源的接收及投放演示操作&#xff0c;解決iphone或ipad的屏幕錄像問題&#xff0c;滿…

SpringBootAdmin設置郵件通知

如果你想要在Spring Boot Admin中配置郵件通知&#xff0c;可以按照以下步驟進行操作&#xff1a; 添加郵件通知的依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId> </dep…

Linux C/C++ 從內存轉儲中恢復64位ELF可執行文件

ELF&#xff08;Executable and Linking Format&#xff09;是一種對象文件的格式&#xff0c;它主要用于定義ELF&#xff08;Executable and Linking Format&#xff09;是一種對象文件的格式&#xff0c;它主要用于定義不同類型的對象文件中的內容以及它們的存儲方式。一個EL…

作業調度算法(含詳細計算過程)和進程調度算法淺析

一.作業調度 作業調度算法需要知道以下公式 周轉時間完成時間 - 到達時間 帶權周轉時間周轉時間/運行時間 注&#xff1a;帶權周轉時間越大&#xff0c;作業&#xff08;或進程&#xff09;越短&#xff1b;帶權周轉時間越小&#xff0c;作業&#xff08;或進程&#xff09;越…

[git] 遠程刪除分支

[git] 遠程刪除分支 1. git刪除遠程分支 git push origin --delete [branch_name]2. 刪除本地分支區別 git branch -d 會在刪除前檢查merge狀態&#xff08;其與上游分支或者與head&#xff09;。git branch -D 是git branch --delete --force的簡寫&#xff0c;它會直接刪除…

Redis生產實戰-Redis集群故障探測以及降級方案設計

Redis 集群故障探測 在生產環境中&#xff0c;如果 Redis 集群崩潰了&#xff0c;那么會導致大量的請求打到數據庫中&#xff0c;會導致整個系統都崩潰&#xff0c;所以系統需要可以識別緩存故障&#xff0c;限流保護數據庫&#xff0c;并且啟動接口的降級機制 降級方案設計 …

《C++20設計模式》---原型模式學習筆記代碼

C20設計模式 第 4 章 原型模式學習筆記筆記代碼 第 4 章 原型模式 學習筆記 筆記代碼 #include<iostream> #include<string>// #define VALUE_OF_ADDRESS // PP_4_2_1 (no define: PP_4_2_2) namespace PP_4_2 {class Address{public:std::string street;std::st…

《C++20設計模式》學習筆記---原型模式

C20設計模式 第 4 章 原型模式4.1 對象構建4.2 普通拷貝4.3 通過拷貝構造函數進行拷貝4.4 “虛”構造函數4.5 序列化4.6 原型工廠4.7 總結4.8 代碼 第 4 章 原型模式 考慮一下我們日常使用的東西&#xff0c;比如汽車或手機。它們并不是從零開始設計的&#xff0c;相反&#x…

超過 50% 的內部攻擊使用特權提升漏洞

特權提升漏洞是企業內部人員在網絡上進行未經授權的活動時最常見的漏洞&#xff0c;無論是出于惡意目的還是以危險的方式下載有風險的工具。 Crowdstrike 根據 2021 年 1 月至 2023 年 4 月期間收集的數據發布的一份報告顯示&#xff0c;內部威脅正在上升&#xff0c;而利用權…

基于SSM的劇本殺預約系統的設計與實現

末尾獲取源碼 開發語言&#xff1a;Java Java開發工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 數據庫&#xff1a;MySQL5.7和Navicat管理工具結合 服務器&#xff1a;Tomcat8.5 開發軟件&#xff1a;IDEA / Eclipse 是否Maven項目&#xff1a;是 目錄…

【第三屆】:“玄鐵杯”RISC-V應用創新大賽(基于yolov5和OpenCv算法 — 智能警戒哨兵)

文章目錄 前言 一、智能警戒哨兵是什么&#xff1f; 二、方案流程圖 三、硬件方案 四、軟件方案 五、演示視頻鏈接 總結 前言 最近參加了第三屆“玄鐵杯”RISC-V應用創新大賽&#xff0c;我的創意題目是基于 yolov5和OpenCv算法 — 智能警戒哨兵 先介紹一下比賽&#xf…

docker容器配置MySQL與遠程連接設置(純步驟)

以下為ubuntu20.04環境&#xff0c;默認已安裝docker&#xff0c;沒安裝的網上隨便找個教程就好了 拉去mysql鏡像 docker pull mysql這樣是默認拉取最新的版本latest 這樣是指定版本拉取 docker pull mysql:5.7查看已安裝的mysql鏡像 docker images通過鏡像生成容器 docke…

大數據HCIE成神之路之數據預處理(1)——缺失值處理

缺失值處理 1.1 刪除1.1.1 實驗任務1.1.1.1 實驗背景1.1.1.2 實驗目標1.1.1.3 實驗數據解析 1.1.2 實驗思路1.1.3 實驗操作步驟1.1.4 結果驗證 1.2 填充1.2.1 實驗任務1.2.1.1 實驗背景1.2.1.2 實驗目標1.2.1.3 實驗數據解析 1.2.2 實驗思路1.2.3 實驗操作步驟1.2.4 結果驗證 1…