【验证小白】只有SV+modelsim学验证(4)——想办法合理的结束仿真后,准备好了所有代码

2023-11-14

前言

把checker加入到环境中后,环境组件基本就搭建完成了,试着跑了跑出了发现之前的pkt_data有一些问题外,还发现仿真结束机制太不合理了,过于简单粗暴。于是把结束仿真的行为梳理一下,做的更合理一些。

参考了VMM的思路,做一个漏洞百出的结束机制:所有的组件维护各自的idle状态,当所有的组件都进入了idle状态后,则判定仿真可以结束;同时设置一个“看门狗”进行计时,如果数据总线上已经长时间没有动作而组件又不进入idle状态的话,则报仿真超时推出退出仿真。

之前相关博文:

【验证小白】只有SV+modelsim学验证(1)——把平台搭起来_尼德兰的喵的博客-CSDN博客_modelsim sv

【验证小白】只有SV+modelsim学验证(2)——加monitor到环境中_尼德兰的喵的博客-CSDN博客_sv中的monitor

【验证小白】只有SV+modelsim学验证(3)——加checker到环境中_尼德兰的喵的博客-CSDN博客

env_cfg

为了便于配置与管理,添加env_cfg类型数据在env中例化,并将其传入所有组件。

`ifndef ENV_CFG_SV
`define ENV_CFG_SV

class env_cfg;
	bit chk_idle;
	bit gen_idle;
	bit drv_idle;
	bit mon_idle;
	
	int env_wait_pkt_time = 10000;
	int mon_wait_pkt_time = 1000;
	int drv_wait_pkt_time = 1000;
	int chk_wait_pkt_time = 1000;
endclass:env_cfg

`endif

env_cfg中维护四个idle状态,分别由gen/drv/mon/chk来进行置位表征自己组件已经工作结束,同意结束仿真。

下面的wait_time为组件允许空转时间,一旦超过这个空转时间的话,组件就可以对xxx_idle进行职位。

env_wait_pkt_time为env中“看门狗”等待时间,超过这个时间不喂狗的话,仿真报超市退出。

env_cfg在env中例化,并且传入每一个组件(最后会附所有完整代码)。

	gen = new(cfg, gen2drv_chan, gen2chk_chan);
	drv = new(cfg, dif, gen2drv_chan);
	mon = new(cfg, mif, mon2chk_chan);
	chk = new(cfg, gen2chk_chan, mon2chk_chan);

gen结束仿真

gen结束仿真的机制最为简单,只要把所有要发的包都放进到chan中了那么就是完成了工作,代码如下。

task pkt_gen::run();
	pkt_data send_pkt;
	pkt_data chk_pkt;
	
	$display("At %0t, [GEN NOTE]: send_num = %0d", $time, send_num);
	repeat(send_num) begin
		assert(pkt.randomize());
		$cast(send_pkt, pkt.copy());
		$cast(chk_pkt, pkt.copy());
		gen2drv_chan.put(send_pkt);
		gen2chk_chan.put(chk_pkt);
	end
	
	this.cfg.gen_idle = 1;
	//$display("At %0t, [GEN NOTE]: gen over pkt", $time);
endtask

drv结束仿真

drv应该在把所有从gen中接收到的包发送出去后就可以结束仿真,但问题是drv并不止都一共要发多少包不知道会不会还有下一个包到来。因此我只好把drv的结束仿真机制设置为一段时间内drv总线上没有驱动新的数据,那么则判定drv工作已经完成(实际上我认为应该再加一条gen2drv_chan已经空了,不过我没加)。实现代码如下。

task pkt_drv::set_idle();
	while(1)begin
		@(negedge top.clk);
		if(this.dif.vld == 1) idle_cnt = 0;
		else idle_cnt++;
		if(idle_cnt > this.cfg.drv_wait_pkt_time) this.cfg.drv_idle = 1;
		else this.cfg.drv_idle = 0;
	end
endtask:set_idle

mon结束仿真

mon结束仿真的方式和drv实现类似,其监视的总线上如果长时间没有动作,那么判定可以结束仿真。

			else begin
				wait_time++;
				if(wait_time <= wait_pkt_time) begin
					wait_time++;
				end
				else break;
			end
		end
		this.cfg.mon_idle = 1;

chk结束仿真

chk结束仿真的思路是,每一拍都将idle_cnt加1,而如果两个chan中任意一个有收到数据,就将idle_cnt置0。这样当两个chan长时间没有没有新数据到来的话,就判定仿真结束。

task pkt_chk::set_idle();
	while(1)begin
		@(negedge top.clk);
		idle_cnt++;
		if(idle_cnt > this.cfg.chk_wait_pkt_time) this.cfg.chk_idle = 1;
		else this.cfg.chk_idle = 0;
	end
endtask:set_idle

“看门狗”结束仿真

如果仿真真的出现了问题,比如mon始终收不全一个包或者丢失了一个包导致组件始终无法结束仿真,那么就需要“看门狗”来动手结束仿真。实现的代码如下。

	#100;
	fork
		begin
			wait(cfg.gen_idle);
			wait(cfg.drv_idle);
			wait(cfg.mon_idle);
			wait(cfg.chk_idle);
			$display("At %0t, [ENV NOTE]: normal finish", $time);
		end
		begin
			while(1)begin
				@(negedge top.clk);
				if(this.dif.vld) wait_time = 0;
				else wait_time++;
				if(wait_time > this.cfg.env_wait_pkt_time) break;
			end
			$display("At %0t, [ENV ERROR]: time out!!!!!", $time);
		end		
	join_any

结束仿真的两个线程,一个线程是所有组件同意结束,另外的线程是看门狗杀死仿真,通过fork-join_any的方式实现二者有其一就可以结束仿真。当数据总线上有信元驱动时进行喂狗,否则看门狗持续加1。

不过这样做目前还是有很大问题的,比如drv真的做错了,一个包持续驱动vld始终不能降下来,那么环境就挂死在这里了事实上监控channel是更为合理的。因此之后这里的结束仿真机制可能是要再进行调整的,容我慢慢想下怎么才能在现有简陋条件下尽量完备些。

?,目前的结束仿真机制就是这样的,到此环境搭建的挺好的了,看一下仿真效果:

run 100000ns
# At 0, [ENV NOTE]: environment::build() start!
# At 0, [ENV NOTE]: environment::build() over!
# At 0, [GEN NOTE]: send_num = 100
# At 42570, [ENV NOTE]: normal finish
# At 43570, [ENV NOTE]: report start
# ----------------------------------------------------------------------------------------------------
# [CHECKER REPORT]expect pkt_num=100, actual pkt_num=100, match pkt_num=100, not match pkt_num=0
# ----------------------------------------------------------------------------------------------------
# At 44070, [ENV NOTE]: report over
# At 44070, [TESt NOTE]: simulation finish~~~~~~~~~~~~~~~~~~
# ** Note: $finish    : C:/Users/gaoji/Desktop/sv test/test.sv(17)
#    Time: 44070 ns  Iteration: 1  Instance: /top/u_test

非常完美!

下一步准备加入覆盖率。

附目前为止所有文件

module top();
	
	logic clk;
	logic rst_n;
	
	initial begin
       		#0ns clk = 0;
		forever #5ns clk = ~clk;
	end
		
	initial begin
		#0ns rst_n = 0;
		#225ns rst_n = 1;	
	end

	pkt_if u_if(clk, rst_n);
	test u_test(u_if, u_if, clk, rst_n);
	
endmodule
`ifndef PKT_DATA_SV
`define PKT_DATA_SV

class pkt_data;

	rand bit [7:0]   payload_q[$];
	rand int         interval;
	rand int		 pkt_len;
	
	bit				 send_over;
	
	bit [10:0] data[$];
	
	constraint data_size_cons{
		payload_q.size() == pkt_len;
	};

	constraint pkt_len_cons{
		pkt_len inside {[1:50]};
		//pkt_len == 5;
	};
	
	constraint interval_cons{
		interval inside {[3:6]};
	};
	
	extern function new();
	extern virtual function string psprintf(string preset = "");
	extern virtual function bit compare(pkt_data to);
	extern virtual function void pack();
	extern virtual function void unpack();
	extern virtual function pkt_data copy(pkt_data to=null);
	
endclass

function pkt_data::new();

endfunction

function bit pkt_data::compare(pkt_data to);
	bit match = 1;
	if(this.pkt_len != to.pkt_len) match = 0;
	foreach(payload_q[i]) if(this.payload_q[i] != to.payload_q[i])
		match = 0;
	return match;
endfunction:compare

function void pkt_data::pack();
	foreach (this.payload_q[i]) begin
		if (i==0 & i==pkt_len-1) //modify!!!!!
			this.data.push_back({1'b1, 1'b1, 1'b1, payload_q[i]});
		else if (i==0)
			this.data.push_back({1'b1, 1'b1, 1'b0, payload_q[i]});		
		else if (i==pkt_len-1)
			this.data.push_back({1'b1, 1'b0, 1'b1, payload_q[i]});
		else
			this.data.push_back({1'b1, 1'b0, 1'b0, payload_q[i]});		
	end
	for(int i=0; i<interval; i++)begin
	    this.data.push_front({'0});
	end
endfunction

function string pkt_data::psprintf(string preset = "");
	psprintf = {preset, $psprintf("pkt_len = %0d", pkt_len)};
	foreach(payload_q[i])
		psprintf = {psprintf, ",", $psprintf("payload[%0d] = 'h%0h", i, payload_q[i])};
endfunction

function pkt_data pkt_data::copy(pkt_data to=null);
	pkt_data tmp;
	if (to == null)
		tmp = new();
	else
		$cast(tmp, to);
	tmp.interval = this.interval;
	tmp.pkt_len  = this.pkt_len;
	tmp.send_over= this.send_over;
	foreach(this.payload_q[i])begin
		tmp.payload_q.push_back(this.payload_q[i]);
	end
	return tmp;
endfunction

function void pkt_data::unpack();
	this.pkt_len = payload_q.size();
endfunction

`endif
`ifndef ENV_CFG_SV
`define ENV_CFG_SV

class env_cfg;
	bit chk_idle;
	bit gen_idle;
	bit drv_idle;
	bit mon_idle;
	
	int env_wait_pkt_time = 10000;
	int mon_wait_pkt_time = 1000;
	int drv_wait_pkt_time = 1000;
	int chk_wait_pkt_time = 1000;
endclass:env_cfg

`endif
`include "pkt_if.sv"
`include "environment.sv"
program automatic test(
	pkt_if.pkt_drv dif,
	pkt_if.pkt_mon mif,
	input clk, rst_n
	);
	
	environment env;
	
	initial begin
		env = new(dif, mif);
		env.build();
		env.gen.send_num = 100;
		env.run();
		$display("At %0t, [TESt NOTE]: simulation finish~~~~~~~~~~~~~~~~~~", $time);
		$finish;
	end	
endprogram
`ifndef ENV_SV
`define ENV_SV

`include "pkt_gen.sv"
`include "pkt_drv.sv"
`include "pkt_mon.sv"
`include "pkt_chk.sv"
`include "pkt_if.sv"
`include "env_cfg.sv"

class environment;
	pkt_gen gen;
	pkt_drv drv;
	pkt_mon mon;
	pkt_chk chk;
	env_cfg cfg;
	mailbox gen2drv_chan;
	mailbox gen2chk_chan;
	mailbox mon2chk_chan;
	vdrv dif;	
	vmon mif;
	int send_pkt_num;
	
	//for finish fimu
	int wait_time;

	extern function new(input vdrv dif,
						input vmon mif
						);
	extern virtual task build();
	extern virtual task run();
	extern virtual task report();	
endclass

function environment::new(input vdrv dif,
						  input vmon mif
						 );
	this.dif = dif;
	this.mif = mif;
	this.cfg = new();
endfunction

task environment::build();
	$display("At %0t, [ENV NOTE]: environment::build() start!", $time);
	gen2drv_chan = new(1);
	gen2chk_chan = new(1);
	mon2chk_chan = new(1);
	gen = new(cfg, gen2drv_chan, gen2chk_chan);
	drv = new(cfg, dif, gen2drv_chan);
	mon = new(cfg, mif, mon2chk_chan);
	chk = new(cfg, gen2chk_chan, mon2chk_chan);
	$display("At %0t, [ENV NOTE]: environment::build() over!", $time);
endtask
	
task environment::run();
	
	fork
		drv.run();
		gen.run();
		mon.run();
		chk.run();
	join_none
	
	#100;
	fork
		begin
			wait(cfg.gen_idle);
			wait(cfg.drv_idle);
			wait(cfg.mon_idle);
			wait(cfg.chk_idle);
			$display("At %0t, [ENV NOTE]: normal finish", $time);
		end
		begin
			while(1)begin
				@(negedge top.clk);
				if(this.dif.vld) wait_time = 0;
				else wait_time++;
				if(wait_time > this.cfg.env_wait_pkt_time) break;
			end
			$display("At %0t, [ENV ERROR]: time out!!!!!", $time);
		end		
	join_any
	
	#1000;	
	report();
endtask

task environment::report();	
	$display("At %0t, [ENV NOTE]: report start", $time);
	repeat(100) @top.clk;
	chk.report();
	$display("At %0t, [ENV NOTE]: report over", $time);
endtask
`endif
`ifndef PKT_GEN_SV
`define PKT_GEN_SV
`include "pkt_data.sv"
`include "env_cfg.sv"

class pkt_gen;
	env_cfg cfg;
	mailbox gen2drv_chan;
	mailbox gen2chk_chan;
	pkt_data pkt;
	int send_num;
	
	extern function new(env_cfg cfg, mailbox gen2drv_chan, mailbox gen2chk_chan);
	extern virtual task run();
	
endclass

function pkt_gen::new(env_cfg cfg, mailbox gen2drv_chan, mailbox gen2chk_chan);
	this.cfg = cfg;
	this.gen2drv_chan  = gen2drv_chan;
	this.gen2chk_chan  = gen2chk_chan;
	this.pkt      = new();
endfunction

task pkt_gen::run();
	pkt_data send_pkt;
	pkt_data chk_pkt;
	
	$display("At %0t, [GEN NOTE]: send_num = %0d", $time, send_num);
	repeat(send_num) begin
		assert(pkt.randomize());
		$cast(send_pkt, pkt.copy());
		$cast(chk_pkt, pkt.copy());
		gen2drv_chan.put(send_pkt);
		gen2chk_chan.put(chk_pkt);
	end
	
	this.cfg.gen_idle = 1;
	//$display("At %0t, [GEN NOTE]: gen over pkt", $time);
endtask

`endif
`ifndef PKT_DRV_SV
`define PKT_DRV_SV
`include "pkt_data.sv"
`include "pkt_if.sv"
`include "env_cfg.sv"

class pkt_drv;
	env_cfg cfg;
	mailbox gen2drv_chan;
	vdrv dif;
	
	//for finish simu	
	int idle_cnt;
	
	int get_num;
	
	extern function new(env_cfg cfg,
						vdrv dif,
						mailbox gen2drv_chan
						);
	extern virtual task run();
	extern virtual task my_run();
	extern virtual task rst_sig();
	extern virtual task pkt_send(input pkt_data pkt);
	extern virtual task set_idle();

endclass

function pkt_drv::new(env_cfg cfg,
				      vdrv dif,
					  mailbox gen2drv_chan
					 );
	this.cfg = cfg;
	this.dif = dif;
	this.gen2drv_chan = gen2drv_chan;
	this.get_num = 0;
endfunction

task pkt_drv::run();
	fork
		my_run();
		set_idle();
	join_none
endtask

task pkt_drv::my_run();
	pkt_data send_pkt;
	
	//$display("At %0t, [DRV NOTE]: pkt_drv run start!", $time);
	rst_sig();
	//$display("At %0t, [DRV NOTE]: after rst_n", $time);
	while(1) begin
		gen2drv_chan.peek(send_pkt);
		//$display("At %0t, [DRV NOTE]: get no.%0d pkt from gen", $time, this.get_num++);		
		send_pkt.pack();
		pkt_send(send_pkt);
		gen2drv_chan.get(send_pkt);
		rst_sig();
	end
endtask:my_run

task pkt_drv::rst_sig();
	wait(top.rst_n == 1'b1);
	@(posedge top.clk);
	this.dif.vld <= '0;
	this.dif.sop <= '0;
	this.dif.eop <= '0;
	this.dif.data<= '0;
endtask

task pkt_drv::pkt_send(input pkt_data pkt);
	foreach(pkt.data[i]) begin
		@(posedge top.clk);
		this.dif.vld <= pkt.data[i][10];
		this.dif.sop <= pkt.data[i][9];
		this.dif.eop <= pkt.data[i][8];
		this.dif.data<= pkt.data[i][7:0];
	end	
endtask

task pkt_drv::set_idle();
	while(1)begin
		@(negedge top.clk);
		if(this.dif.vld == 1) idle_cnt = 0;
		else idle_cnt++;
		if(idle_cnt > this.cfg.drv_wait_pkt_time) this.cfg.drv_idle = 1;
		else this.cfg.drv_idle = 0;
	end
endtask:set_idle

`endif
`ifndef PKT_MON_SV
`define PKT_MON_SV

`include "pkt_data.sv"
`include "pkt_if.sv"
`include "env_cfg.sv"

class pkt_mon;
	env_cfg cfg;
	vmon mif;
	mailbox mon2chk_chan;
	bit rec_status;//0:wait sop, 1:wait eop
	int wait_pkt_time = 1000;
	
	extern function new(env_cfg cfg,
						vmon mif,
						mailbox mon2chk_chan);
	extern virtual task run();
	extern virtual task send_chk(pkt_data pkt);
endclass

function pkt_mon::new(env_cfg cfg,
					  vmon mif,
					  mailbox mon2chk_chan
					 );
	this.cfg = cfg;
	this.mif = mif;
	this.mon2chk_chan = mon2chk_chan;
	this.wait_pkt_time = cfg.mon_wait_pkt_time;
	this.rec_status = 0;
endfunction : new

task pkt_mon::run();
	pkt_data  rec_pkt;
	int 	  wait_time;
	int		  i = 0;
	
	//$display("At %0t, [MON NOTE]: run start!", $time);
	while(1) begin
		while(1) begin
			@(posedge top.clk);
			if(mif.vld == 1)begin
				wait_time = 0;
				if(rec_status == 0) begin//wait sop
					rec_pkt = new();
					if(mif.sop == 0) begin
						$display("At %0t, [MON ERROR]: ERROR! The first pkt cycle is not sop!", $time);
						break;
					end
					else begin
						rec_pkt.payload_q.push_back(mif.data);
						if(mif.eop == 1) begin
							rec_status = 0;
							//$display("At %0t, [MON NOTE]: get no.%0d pkt!", $time, i++);
							send_chk(rec_pkt);
						end
						else
							rec_status = 1;
					end
				end
				else if(rec_status == 1) begin//wait eop
					if(mif.sop == 1) begin
						$display("At %0t, [MON ERROR]: ERROR! SOP????", $time);
						break;
					end
					else begin
						rec_pkt.payload_q.push_back(mif.data);
						if(mif.eop == 1) begin
							rec_status = 0;
							//$display("At %0t, [MON NOTE]: get no.%0d pkt!", $time, i++);
							send_chk(rec_pkt);
						end
						else
							rec_status = 1;
					end
				end
			end
			else begin
				wait_time++;
				if(wait_time <= wait_pkt_time) begin
					wait_time++;
				end
				else break;
			end
		end
		this.cfg.mon_idle = 1;
		//$display("At %0t, [MON NOTE]: mon run over!", $time);
		break;
	end
endtask : run
	
task pkt_mon::send_chk(pkt_data pkt);
	pkt.unpack();
	mon2chk_chan.put(pkt);
endtask : send_chk	
`endif







`ifndef PKT_CHK_SV
`define PKT_CHK_SV

`include "pkt_data.sv"
`include "env_cfg.sv"

class pkt_chk;
	env_cfg cfg;
	pkt_data expect_q[$];
	int in_expect, in_actual;
	int match, not_match;
	mailbox gen2chk_chan;
	mailbox mon2chk_chan;
	
	//for finish simu
	int idle_cnt;
	
	extern function new(env_cfg cfg, 
						mailbox gen2chk_chan, 
						mailbox mon2chk_chan);
	extern virtual task run();
	extern virtual task expect_gain();
	extern virtual task actual_gain();
	extern virtual task set_idle();
	extern virtual function report();

endclass:pkt_chk

function pkt_chk::new(env_cfg cfg, 
					  mailbox gen2chk_chan, 
					  mailbox mon2chk_chan);
	this.cfg = cfg;
	this.gen2chk_chan = gen2chk_chan;
	this.mon2chk_chan = mon2chk_chan;
endfunction:new

task pkt_chk::run();
	fork
		expect_gain();
		actual_gain();
		set_idle();
	join_none
endtask:run

task pkt_chk::expect_gain();
	pkt_data expect_data;
	while(1) begin
		gen2chk_chan.get(expect_data);
		this.expect_q.push_back(expect_data);
		in_expect++;
		idle_cnt = 0;
		//$display("At %0t, [CHK NOTE]: get a expect pkt", $time);
	end
endtask:expect_gain

task pkt_chk::actual_gain();
	pkt_data expect_data;
	pkt_data actual_data;
	while(1) begin
		mon2chk_chan.get(actual_data);
		in_actual++;
		idle_cnt = 0;
		if(this.expect_q.size == 0) $display("At %0t, [CHK ERROR]: expect_q==0???", $time);
		else begin
			expect_data = expect_q[0];
			if(!expect_data.compare(actual_data)) begin
				$display("At %0t, [CHK ERROR]: no match, \nexpect data:%s \nactual data:%s ", $time, expect_data.psprintf(), actual_data.psprintf());
				expect_q.pop_front();
				not_match++;
			end
			else begin
				expect_q.pop_front();
				//$display("At %0t, [CHK NOTE]: match, \nexpect data:%s \nactual data:%s ", $time, expect_data.psprintf(), actual_data.psprintf());
				match++;
			end
		end
	end
endtask:actual_gain

task pkt_chk::set_idle();
	while(1)begin
		@(negedge top.clk);
		idle_cnt++;
		if(idle_cnt > this.cfg.chk_wait_pkt_time) this.cfg.chk_idle = 1;
		else this.cfg.chk_idle = 0;
	end
endtask:set_idle

function pkt_chk::report();
	$display("----------------------------------------------------------------------------------------------------");
	$display("[CHECKER REPORT]expect pkt_num=%0d, actual pkt_num=%0d, match pkt_num=%0d, not match pkt_num=%0d", in_expect, in_actual, match, not_match);
	$display("----------------------------------------------------------------------------------------------------");
endfunction:report

`endif
`ifndef PKT_IF_SV
`define PKT_IF_SV

interface pkt_if(input clk, rst_n);
		
	logic [7:0] data;
	logic 	    sop;
	logic		eop;
	logic		vld;
	
	clocking drv @(posedge clk);
		output 	data;
		output	sop, eop, vld;
	endclocking : drv
	modport pkt_drv (clocking drv);
	
	clocking mon @(posedge clk);
		input 	data;
		input	sop, eop, vld;
	endclocking : mon
	modport pkt_mon (clocking mon);
	
endinterface

typedef virtual pkt_if.drv vdrv;
typedef virtual pkt_if.mon vmon;

`endif

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【验证小白】只有SV+modelsim学验证(4)——想办法合理的结束仿真后,准备好了所有代码 的相关文章

随机推荐

  • CentOS一键配置rsync服务器脚本

    1 保存下面的代码为一个文件 上传到服务器端 名称为rsync sh bin bash rsync Written by zhumaohai For more information please visit http www centos
  • JavaSE的复习:Java基本语法

    1 变量 变量的分类 按数据类型 对于每一种数据都定义了明确的具体数据类型 强类型语言 在内存中分配了不同大小的内存空间 弱类型语言则不用明确指明数据类型 例如js var 变量的分类 按声明的位置的不同 在方法体外 类体内声明的变量称为成
  • Oracle安装 在注册表中没有找到指定的主目录名 的解决方案

    在安装数据库的时候 报了个错 在注册表中没有找到指定的主目录名 解决方案就是 忽略 此错误并不影响Oracle的正常使用 亲测可行 也不排除不可用的情况 如果谁遇到了请告知 我将继续补充
  • vue-cli3配置proxy解决前后端域名/端口不一致引起的跨域问题

    错误代码 前端 import axios from axios import VueAxios from vue axios Vue use VueAxios axios this axios post http localhost 808
  • (一)JMeter性能测试,完整入门篇:性能测试操作步骤

    原文转自 https blog csdn net lovesoo article details 78579547 1 Jmeter简介 Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件 相比Loadrunn
  • sentinel

    文章目录 1 sentinel简介 1 1 sentinel解决的问题 1 2 服务保护技术对比 2 微服务整合sentinel 2 1 引入sentinel依赖 2 2 配置控制台地址 3 限流规则 3 1 流控模式 3 2 流控效果 4
  • 华为路由交换学习篇-ACL

    目录 ACL访问控制列表 基本ACL 高级ACL 实验一 ACL访问控制列表 ACL的分类 按照功能来分 可以分为基本ACL 高级ACL 基于接口的ACL 二层ACL 自定义的ACL 基于MPLS的ACL 基本ACL6 高级ACL6 基本A
  • 考研:研究生考试(十五天学完)之研究生学霸重点知识点总结之考研必知(考研时间/科目/必备物件)、【考研政治】/【考研英语】/【考研数学】经验总结(历年规律分析、技巧总结、经验分享)

    考研 研究生考试 十五天学完 之研究生学霸重点知识点总结之考研必知 考研时间 科目 必备物件 考研政治 考研英语 考研数学 经验总结 历年规律分析 技巧总结 经验分享 文章转自 考研 研究生考试 十五天学完 之研究生学霸重点知识点总结之考研
  • Guava学习笔记之Maps(1):Maps.uniqueIndex(Iterable, Function)

    Guava官方文档 https github com google guava wiki CollectionUtilitiesExplained 官方文档这样描述 Maps uniqueIndex Iterable Function ht
  • 【JavaWeb】四个Scope

    英文科普 scope 范围 域 1 page里的变量没法从index jsp传递到test jsp 只要页面跳转了 它们就不见了 以页面为单位 2 request里的变量可以跨越forward前后的两页 但是只要刷新页面 它们就重新计算了
  • Java中对象的比较

    目录 一 基本数据类型的比较 二 引用数据类型比较 1 equals 方法 1 实现Comparable接口 2 传比较器 一 基本数据类型的比较 我们在比较基本类型的数据时 通常用 来判断 也比较简单 int a 3 int b 5 Sy
  • 谈谈我对服务熔断、服务降级的理解

    伴随着微服务架构被宣传得如火如荼 一些概念也被推到了我们面前 管你接受不接受 其实大多数概念以前就有 但很少被提的这么频繁 现在好像不提及都不好意思交流了 想起有人总结的一句话 微服务架构的特点就是 一解释就懂 一问就不知 一讨论就吵架 其
  • 机器学习 数据的采集和清洗

    本人找到了一条路 不知道对错的路 采集训练的 数据和清理数据 第一步 采集 涉及到如何利用爬虫采集网页csv文件 数据是在UCI 上的 UCI官网如下http archive ics uci edu ml index php 就拿里面最热门
  • java字典树(前缀树) - Kaiqisan

    大家好 都吃晚饭了吗 我是Kaiqisan 是一个已经走出社恐的一般生徒 这一篇文章咱来讲讲字典树把 之前在给别人代答辩数据结构的时候初次了解到这个概念 今天在刷算法课的时候右看到了 所以就有了这个视频 首先还是明确一个概念 什么是字典树
  • 微软Hyper-V虚拟机复制实现双机备份过程

    这个方案是通过hyper v的虚拟机复制功能实现 该方案需要至少两台安装了hyper v功能的服务器 只需在其中一台安装虚拟机系统 另一台虚拟机服务器作为副本接收服务器 部署过程如下 1 比如有两台pc 下面称为pc1 pc2 pc1上面的
  • NodeJS的os模块

    附录 常用HTTP响应头和请求头信息对照表 Node简介 第一个node程序 module 模块系统 npm包管理器 模块系统优先级 认识http内置模块 url内置模块 path内置模块 fs内置模块 http模块服务端进阶 http报文
  • 区块链学习笔记(四)【Merkle树】

    一 字典树 字典树的三个基本特征 1 根节点不包含字符 为空 除根节点外每一个节点只包含一个字符 2 从根节点到某一个节点 路径上经过的字符连接起来 就是该节点对应的字符串 3 每个节点包含的所有子节点的字符都不相同 优势 相比较于哈希表
  • 云计算基础教程(第2版)笔记——基础篇与技术篇介绍

    文章目录 前言 第一篇 基础篇 一 绪论 1 1 云计算的概念以及特征 1 1 1云计算的基本概念 1 1 2云计算的基本特征 1 2 云计算发展简史 1 3 三种业务模式介绍 1 基础设施即服务 IaaS 2 平台即服务 PaaS 3 软
  • leetcode-每日一题2022.3.17 词典中最长的单词

    题目 力扣 思路 模拟 先把words中的字符串放到哈希表里 再遍历words的每一个字符串 判断它从0开始的每一个子串是否存在于哈希表里 代码 class Solution public string longestWord vector
  • 【验证小白】只有SV+modelsim学验证(4)——想办法合理的结束仿真后,准备好了所有代码

    前言 把checker加入到环境中后 环境组件基本就搭建完成了 试着跑了跑出了发现之前的pkt data有一些问题外 还发现仿真结束机制太不合理了 过于简单粗暴 于是把结束仿真的行为梳理一下 做的更合理一些 参考了VMM的思路 做一个漏洞百