Jump to content
Aaron Yang

SC_METHOD performance improvement discussion

Recommended Posts

Hey Guys, 

I am kinda new to this language so bear with me if question sounds naive.

I am building cycle accurate system C model. When I run performance profiler, some process triggered by clk consume a lot resources(clk is always running).

So I am looking for tricks to improve the performance:

Original code:

SC_METHOD(process_output);
sensitive << reset;
sensitive << clk.pos();
...
void fir::process_output()
{
    if (reset.read() == 0) {
		//reset sequence
    }
    else {
      	if(enable.read()) {
    		//normal operation
        }
    }
}

One way to avoid triggered the process every time clk toggles is that create a event:

void fir::enable_event()
{
	if (enable.read()) {
		enable_rise.notify();
	}
}
...
void fir::process_output()
{
    if (reset.read() == 0) {
		//reset seq
    }
    else
    {
		if (enable.read() == 0) {
			next_trigger(enable_rise);//Correct me if I am wrong, based on my understanding, next_trigger() overrides the static sensitivity list.
        }
   	   else {
   			next_trigger();
      		//normal op
       }
    }
}
		

 

The other way is to use .suspend() and .resume();

SC_THREAD(monitor_trig_event);
sensitive << reset << enable;
...
void fir::monitor_trig_event() {
	sc_spawn_options opt;
	opt.set_sensitivity(&clk.pos());
	sc_process_handle handle = sc_spawn(sc_bind(&fir::process_output, this), "run_fir", &opt);
	handle.suspend();
	while (1) {
		wait();
		if (!reset) reset();
		else {
			if (enable.read()) {
				handle.resume();
				break;
			}
			else if (enable.read() == 0) {
				handle.suspend();
			}
		}
	}

In this case, process output won't have next_trigger() statement anymore.

For those two methods above, which one is more recommended? Or is there any clean and straightforward way to implement the improvement?

 

Thank you all in advance.

Share this post


Link to post
Share on other sites

Are you only looking at disabling  process_output from getting triggered when reset is on? In that case, it is as simple as:

void fir::process_output()
{
   if (reset.read() == 0) {
      //reset sequence
      next_trigger(reset.pos());
   }
   else if (clk.read() == 0) {
      //Ignore the trigger just after reset is de-asserted and 
      //sync to next clock edge
      next_trigger(clk.pos());
      // Note: will work even if we comment out line above, due to static sensitivity
   }
   else {
      if(enable.read()) {
         //normal operation
      }
   }
}

But this may not really get you a significant improvement in itself. You may want to check what is going on in "normal operation" - and see if you can optimize that.

Share this post


Link to post
Share on other sites

I would stick with the two methods where the one calls enable() and disable() for the second mehtod. Why enable()/disable()? The LRM says (section 5.6.6):

Quote
  1. The distinction between suspend/resume and disable/enable lies in the sensitivity of the target process during the period while it is suspended or disabled. With suspend, the kernel keeps track of the sensitivity of the target process while it is suspended such that a relevant event notification or time-out while suspended would cause the process to become runnable immediately when resume is called. With disable, the sensitivity of the target process is nullified while it is suspended such that the process is not made runnable by the call to enable, but only on the next relevant event notification or time-out subsequent to the call to enable. In other words, with suspend/resume, the kernel keeps a record of whether the target process would have awoken while in fact being suspended, whereas with disable/enable, the kernel entirely ignores the sensitivity of the target process while disabled. Also see 5.2.12 regarding clocked thread processes.

So with suspend() you still have the sensitivity handling in place while with disable() you don't. Moreover if there is an event while being supended it becomes immediately runnable. So falling edge of reset implies a process activation although there is not rising edge on clock.

An implementation could look like:

 // class declaration:
sc_core::sc_process_handle process_output_hndl;

// constructor body:
    SC_METHOD(process_output);
    sensitive<<clk.pos()<<reset;
    SC_METHOD(process_output_enable);
    sensitive<<enable;

// function implementation:
void fir::process_output()
{
    if(!process_output_hndl.valid()) process_output_hndl = sc_process_handle(sc_get_current_process_handle());
    if (reset.read() == 0) {
        //reset sequence
    }
    else {
        //normal operation
    }
}

void fir::process_output_enable()
{
    if (enable.read()) {
        if(process_output_hndl.valid()) process_output_hndl.enable();
    } 
    else {
        if(process_output_hndl.valid()) process_output_hndl.disable();
    }  
}

BR

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×