Jump to content

SC_METHOD performance improvement discussion


Aaron Yang

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.

Link to comment
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.

Link to comment
Share on other sites

  • 2 weeks later...

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

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...