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).
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 */
_______________________________________________
Gnucap-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/gnucap-devel

Reply via email to