faster queueing

Felix Salfelder <[email protected]>
Newsgroups gmane.comp.gnu.gnucap.devel
Message-ID <[email protected]>
Hi Al.

As you had pointed out, CARD_LIST::tr_queue_eval iterates over the whole
circuit instead of over all the non-constant components.

to work around that, i have added another list to CARD_LIST holding the
pointers to the components that are not constant (during precalc_last).
using this list instead of the full list decreases tr simulation time by
a factor of almost two (eq4-9217.tran.ckt).

the changes involve one uglyness, that i think you are already aware
of... the dc sweep pointer-hacks elements and sets them non-constant, so
they are queued. this non-const setting comes after the non-const queue
has been set up (too late). my current workaround adds these elements to
the evaluation queue of the top level circuit.

i have attached a patch, it is against -uf. i think it transports the
idea, and gives some numbers on the speed impact. i will backport as
soon as i know a proper way to deal with the dc-hack.

cheers
felix

PS: yes, i tried to do this with plugins, overload/change BASE_SUBCKT
functions only. it turned out to be a dead end (too many devices to
change).

_______________________________________________
Gnucap-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/gnucap-devel
fastq (text/plain, 8.1 KB)
commit 38a4958211d3701aa3f51309a5da6ccba0226857
Author: Felix Salfelder <[email protected]>
Date:   Sun Feb 21 20:14:02 2016 +0100

    faster queueing
    
    constant components are never queued, hence tr_queue_eval is redundant.
    this adds another container to CARD_LIST for the non-constant ones.
    
    making dc sweeps work involves some uglier hacking (on top of the
    pointer_hack).

diff --git a/lib/e_cardlist.cc b/lib/e_cardlist.cc
index 10c9392..9cedc03 100644
--- a/lib/e_cardlist.cc
+++ b/lib/e_cardlist.cc
@@ -217,9 +217,15 @@ CARD_LIST& CARD_LIST::precalc_first()
 /*--------------------------------------------------------------------------*/
 CARD_LIST& CARD_LIST::precalc_last()
 {
+  _eq.clear();
   for (iterator ci=begin(); ci!=end(); ++ci) {
     trace_func_comp();
     (**ci).precalc_last();
+    if(!OPT::prequeue){ itested();
+    }else if((*ci)->is_constant()){ itested();
+    }else{ itested();
+      _eq.push_back(*ci);
+    }
   }
   return *this;
 }
@@ -405,7 +411,13 @@ CARD_LIST& CARD_LIST::do_forall( void (CARD::*thing)( int ), int i  )
  */
 CARD_LIST& CARD_LIST::tr_advance()
 {
-  for (iterator ci=begin(); ci!=end(); ++ci) {
+  std::list<CARD*>* Q;
+  if(!OPT::prequeue) { itested();
+    Q = &_cl;
+  }else{ itested();
+    Q = &_eq;
+  }
+  for (iterator ci=Q->begin(); ci!=Q->end(); ++ci) {
     trace_func_comp();
     (**ci).tr_advance();
   }
@@ -468,9 +480,19 @@ bool CARD_LIST::tr_needs_eval()const
  */
 CARD_LIST& CARD_LIST::tr_queue_eval()
 {
-  for (iterator ci=begin(); ci!=end(); ++ci) {
+  std::list<CARD*>* Q;
+  if(!OPT::prequeue) { itested();
+    Q = &_cl;
+  }else{ itested();
+    Q = &_eq;
+  }
+  for (iterator ci=Q->begin(); ci!=Q->end(); ++ci) {
     trace_func_comp();
-    (**ci).tr_queue_eval();
+    if((*ci)->is_constant() ){
+      assert(!OPT::prequeue);
+    }else{
+      (**ci).tr_queue_eval();
+    }
   }
   return *this;
 }
@@ -551,7 +573,13 @@ TIME_PAIR CARD_LIST::tr_review()
 {
   TIME_PAIR time_by(NEVER,NEVER);
 
-  for (iterator ci=begin(); ci!=end(); ++ci) {
+  std::list<CARD*>* Q;
+  if(!OPT::prequeue) { itested();
+    Q = &_cl;
+  }else{ itested();
+    Q = &_eq;
+  }
+  for (iterator ci=Q->begin(); ci!=Q->end(); ++ci) {
     trace_func_comp();
     time_by.min((**ci).tr_review());
   }
@@ -814,6 +842,21 @@ void CARD_LIST::map_subckt_nodes(const CARD* model, const CARD* here)
   }
 }
 /*--------------------------------------------------------------------------*/
+void CARD_LIST::q_hack(CARD* x)
+{ itested();
+
+#ifndef NDEBUG
+  for (iterator i=card_list._eq.begin(); i!=card_list._eq.end(); ++i){
+    if(*i == x){ unreachable();
+      trace1("already toplevel queued", x->long_label());
+      exit(1);
+    }
+  }
+#endif
+
+  card_list._eq.push_front(x);
+}
+/*--------------------------------------------------------------------------*/
 ///ADP_NODE* CARD_LIST::new_adp_node{
 ///  assert(d);
 ///  assert(d->scope());
diff --git a/lib/e_elemnt.cc b/lib/e_elemnt.cc
index f21c147..e10e14f 100644
--- a/lib/e_elemnt.cc
+++ b/lib/e_elemnt.cc
@@ -197,7 +197,9 @@ void ELEMENT::tr_restore()
   }
 
   //assert(_time[0] == _sim->_time0);
-  if (_time[0] != _sim->_time0) {
+  if (is_constant()){ untested();
+
+  }else if (_time[0] != _sim->_time0) {
     error(bDANGER, "//BUG// %s restore time mismatch.  t0=%.12f, s->t=%.12f\n", long_label().c_str(),
         _time[0], _sim->_time0);
 
diff --git a/lib/u_opt1.cc b/lib/u_opt1.cc
index 2f12fd1..0d11760 100644
--- a/lib/u_opt1.cc
+++ b/lib/u_opt1.cc
@@ -86,6 +86,7 @@ order_t	OPT::order = oAUTO;
 smode_t	OPT::mode = moMIXED;
 int	OPT::transits = 2;
 bool	OPT::dupcheck = false;
+bool	OPT::prequeue = getenv("GNUCAP_PREQ");
 bool	OPT::bypass = true;
 bool	OPT::incmode = true;
 bool	OPT::lcbypass = true;
diff --git a/lib/u_opt2.cc b/lib/u_opt2.cc
index 5f2e19d..9c595d3 100644
--- a/lib/u_opt2.cc
+++ b/lib/u_opt2.cc
@@ -152,6 +152,7 @@ bool OPT::set_values(CS& cmd)
 	   || cmd.warn(bWARNING, "need analog, digital, or mixed")))
       || Get(cmd, "tr{ansits}",    &transits)
       || Get(cmd, "dup{check}",    &dupcheck)
+      || Get(cmd, "preq{ueue}",    &prequeue)
       || Get(cmd, "byp{ass}",	   &bypass)
       || Get(cmd, "inc{mode}",	   &incmode)
       || Get(cmd, "lcb{ypass}",    &lcbypass)
diff --git a/src/e_card.h b/src/e_card.h
index b359f39..53938d4 100644
--- a/src/e_card.h
+++ b/src/e_card.h
@@ -83,6 +83,7 @@ public:	// dc-tran
 
   virtual bool	 tr_needs_eval()const	{return false;}
   virtual void	 tr_queue_eval()	{} // not const, would need mutable iteration_tag
+  virtual void	 tr_prequeue_eval()	{}
   virtual bool	 do_tr()		{return true;}
   virtual bool	 do_tr_last()		{return true;}
   virtual void	 tr_load()		{}
diff --git a/src/e_cardlist.h b/src/e_cardlist.h
index e238f9d..06fc224 100644
--- a/src/e_cardlist.h
+++ b/src/e_cardlist.h
@@ -51,9 +51,11 @@ private:
   mutable PARAM_LIST* _params;
   LANGUAGE* _language;
   std::list<CARD*> _cl;
+  std::list<CARD*> _eq; // eval queue
   const CARD* _owner;       // stupid hack
   const CARD_LIST* _origin; // even more stupid hack
 public:
+  static void q_hack(CARD* x);
   // internal types
   typedef std::list<CARD*>::iterator iterator;
   typedef std::list<CARD*>::const_iterator const_iterator;
diff --git a/src/e_subckt.h b/src/e_subckt.h
index 69fb3e0..4a7fab0 100644
--- a/src/e_subckt.h
+++ b/src/e_subckt.h
@@ -77,6 +77,7 @@ protected:
   bool	  tr_needs_eval()const
 	{
 		assert(subckt()); return subckt()->tr_needs_eval();}
+public:
   void	  tr_queue_eval() {assert(subckt()); subckt()->tr_queue_eval();}
   bool	  do_tr() {
 		assert(subckt());set_converged(subckt()->do_tr());return converged();}
diff --git a/src/s_dc.cc b/src/s_dc.cc
index cc5ca51..09bc9ee 100644
--- a/src/s_dc.cc
+++ b/src/s_dc.cc
@@ -385,6 +385,13 @@ void DCOP::sweep()
   set_step_cause(scUSER);
   _converged = false;
   _ever_converged = false;
+  for (int ii = 0; ii < _n_sweeps; ++ii) {itested();
+    if (!_zap[ii]) { itested();
+    }else if (_zap[ii]->is_constant()) { itested();
+      CARD_LIST::card_list.q_hack(_zap[ii]);
+    }else{ untested();
+    }
+  }
   sweep_recursive(_n_sweeps-1);
   _sim->pop_voltages();
   _sim->keep_voltages();
@@ -442,6 +449,11 @@ void DCOP::sweep_recursive(int Nest)
 	incomplete();
       }
     }else{ // leaf
+      for (int ii = 0;  ii < _n_sweeps;  ++ii) {
+	if (_zap[ii]) {
+	  _zap[ii]->do_tr();
+	}
+      }
       _converged = solve_with_homotopy(itl,_trace);
       _ever_converged |= _converged;
       ++::status.hidden_steps;
@@ -543,9 +555,13 @@ void DCOP::first(int Nest)
 
   _val_by_user_request[Nest] = _start[Nest];
   _sweepdamp[Nest] = 1;
-  if (ELEMENT* c = dynamic_cast<ELEMENT*>(_zap[Nest])) {
-  c->set_constant(false); // because of extra precalc_last
-                          // obsolete, once pointer hack is fixed
+  if (ELEMENT* c = dynamic_cast<ELEMENT*>(_zap[Nest])) { itested();
+    // because of extra precalc_last
+    // obsolete, once pointer hack is fixed
+    c->set_constant(false);
+    trace1("zapq", _zap[Nest]->long_label());
+//    CARD_LIST::card_list.q_hack(_zap[Nest]);
+  }else{ untested();
   }
   _reverse[Nest] = false;
   if (_reverse_in[Nest]) {
diff --git a/src/u_opt.h b/src/u_opt.h
index 7d24e3d..0e56c7f 100644
--- a/src/u_opt.h
+++ b/src/u_opt.h
@@ -156,6 +156,7 @@ public:
   static smode_t mode;	    // mixed-mode mode preference
   static int transits;	    // number of good transitions for digital
   static bool dupcheck;	    // check for duplicates on read
+  static bool prequeue;	    // prequeue model evaluation
   static bool bypass;	    // bypass model evaluation, if appropriate
   static bool incmode;	    // make incremental changes to the matrix
   static bool lcbypass;	    // bypass L and C evaluation when appropriate
diff --git a/src/u_sim_data.h b/src/u_sim_data.h
index 4de18d4..fa37964 100644
--- a/src/u_sim_data.h
+++ b/src/u_sim_data.h
@@ -137,6 +137,7 @@ public:
   std::vector<CARD*> _loadq;
   std::vector<CARD*> _acceptq;
   std::vector<CARD*> _tt_acceptq;
+  std::deque<CARD*>  _pre_evalq; /* candidates for evaluation */
   std::deque<CARD*>  _evalq1; /* evaluate queues -- alternate between */
   std::deque<CARD*>  _evalq2; /* build one while other is processed */
   std::deque<CARD*>  _late_evalq; /* eval after everything else */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.