gnugo-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: speedups (was: Re: [gnugo-devel] Timing data)


From: Gunnar Farneback
Subject: Re: speedups (was: Re: [gnugo-devel] Timing data)
Date: Tue, 26 Feb 2002 17:31:04 +0100
User-agent: EMH/1.14.1 SEMI/1.14.3 (Ushinoya) FLIM/1.14.2 (Yagi-Nishiguchi) APEL/10.3 Emacs/20.7 (sparc-sun-solaris2.7) (with unibyte mode)

Arend wrote:
> My intention was just to single out patterns whose constraint does not
> contain any call to a reading function.

There's still the problem of maintaining this for new and revised
patterns. 

> As the owl_safe_move gets cached and is very likely to get used
> again, I'd guess that a single call to a reading functions will on
> average make the constraint more expensive than owl_safe_move.

Agreed.

> I agree that all your suggestions could make a lot of sense; however, I
> don't know whether there is a good way to guess the constraint complexity.
> attack(*) could have very different expected time consumption, depending
> on the pattern.

The good way is to do profiling and try to estimate average values.
However, this doesn't have to be all that accurate to be useful. I
think something like this would be good enough:

cost    functions
   1    Anything only requiring a table lookup, like lib(),
        owl_escape_value() etc.
   5    Approxlib calls, e.g. olib() and xlib()
 100    Basic reading, e.g. [ox]play_attack(), [ox]defend_against()
 300    Complex reading, e.g. [ox]play_defend_both()
 500    Extra complex reading, e.g. [ox]play_break_through()
1000    Connection reading, e.g. [ox]play_connect

(It might be better to use float values and normalize basic reading at
1.0.)

> push_owl(...)
> {
>   owl_stack_pointer++;
>   owl_stack[owl_stack_pointer] = owl_stack[owl_stack_pointer];
> }
> 
> (no save here) and
> 
> static void
> pop_owl(...)
> {
>   (...)
>   owl_stack_pointer--;
> }
> 
> (No need to copy anything here.)

Ok, this is a reasonable and straightforward optimization.

> Then "owl" can be replaced by "&owl_stack[owl_stack_pointer]" everywhere
> in do_owl_attack/defend.

But this is kind of unwieldy. It can be solved by a macro

#define OWL &owl_stack[owl_stack_pointer]

of course but a simpler approach might be to pass a pointer to owl to
push_owl() and pop_owl() and let them update it, i.e. something like

> static void
> pop_owl(struct local_owl_data **owl)
> {
>   (...)
>   owl_stack_pointer--;
>   *owl = &owl_stack[owl_stack_pointer];
> }

With either approach it's necessary to also revise the initialization
of the owl data in the external callers of do_owl_attack() and
do_owl_defend().

Incidentally we should have written an init_owl() function long ago
since there's lot of duplicated code. Fixed by the patch below.

- new function init_owl() in owl.c

/Gunnar

Index: engine/owl.c
===================================================================
RCS file: /cvsroot/gnugo/gnugo/engine/owl.c,v
retrieving revision 1.66
diff -u -r1.66 owl.c
--- engine/owl.c        24 Feb 2002 17:40:10 -0000      1.66
+++ engine/owl.c        26 Feb 2002 13:57:05 -0000
@@ -249,6 +249,9 @@
 static int matches_found;
 static char found_matches[BOARDMAX];
 
+static void init_owl(struct local_owl_data *owl, int target1, int target2,
+                    int move);
+
 static struct local_owl_data *owl_stack = NULL;
 static int owl_stack_size = 0;
 static int owl_stack_pointer = 0;
@@ -284,16 +287,14 @@
   owl_phase = owl;
   count_variations = 1;
   TRACE("owl_analyze_semeai: %1m vs. %1m\n", apos, bpos);
-  owla.lunches_are_current = 0;
-  owlb.lunches_are_current = 0;
   if (owl) {
-    owl_mark_dragon(apos, NO_MOVE, &owla);
-    owl_mark_dragon(bpos, NO_MOVE, &owlb);
-    compute_owl_escape_values(&owla);
-    compute_owl_escape_values(&owlb);
+    init_owl(&owla, apos, NO_MOVE, NO_MOVE);
+    init_owl(&owlb, bpos, NO_MOVE, NO_MOVE);
     owl_make_domains(&owla, &owlb);
   }
   else {
+    owla.local_owl_node_counter        = 0;
+    owlb.local_owl_node_counter        = 0;
     owl_mark_worm(apos, NO_MOVE, &owla);
     owl_mark_worm(bpos, NO_MOVE, &owlb);
   }
@@ -1118,11 +1119,9 @@
 
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
-  owl.local_owl_node_counter = 0;
+  
   TRACE("owl_attack %1m\n", target);
-  owl.lunches_are_current = 0;
-  owl_mark_dragon(target, NO_MOVE, &owl);
-  compute_owl_escape_values(&owl);
+  init_owl(&owl, target, NO_MOVE, NO_MOVE);
   owl_make_domains(&owl, NULL);
   result = do_owl_attack(target, &move, &owl, EMPTY, 0);
   tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
@@ -1639,13 +1638,10 @@
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
   
-  owl.local_owl_node_counter = 0;
   gg_assert(stackp == 0);
   TRACE("owl_threaten_attack %1m\n", target);
-  owl.lunches_are_current = 0;
-  owl_mark_dragon(target, NO_MOVE, &owl);
+  init_owl(&owl, target, NO_MOVE, NO_MOVE);
   memcpy(saved_boundary, owl.boundary, sizeof(saved_boundary));
-  compute_owl_escape_values(&owl);
   owl_make_domains(&owl, NULL);
 #if PATTERN_CHECK_ON_DEMAND
   owl_shapes(&shape_patterns, moves, other, &owl, &owl_attackpat_db);
@@ -1767,11 +1763,8 @@
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
 
-  owl.local_owl_node_counter = 0;
   TRACE("owl_defend %1m\n", target);
-  owl.lunches_are_current = 0;
-  owl_mark_dragon(target, NO_MOVE, &owl);
-  compute_owl_escape_values(&owl);
+  init_owl(&owl, target, NO_MOVE, NO_MOVE);
   owl_make_domains(&owl, NULL);
   result = do_owl_defend(target, &move, &owl, EMPTY, 0);
   tactical_nodes = get_reading_node_counter() - reading_nodes_when_called;
@@ -2226,12 +2219,10 @@
 
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
-  owl.local_owl_node_counter = 0;
+
   TRACE("owl_threaten_defense %1m\n", target);
-  owl.lunches_are_current = 0;
-  owl_mark_dragon(target, NO_MOVE, &owl);
+  init_owl(&owl, target, NO_MOVE, NO_MOVE);
   memcpy(saved_goal, owl.goal, sizeof(saved_goal));
-  compute_owl_escape_values(&owl);
   owl_make_domains(&owl, NULL);
 #if PATTERN_CHECK_ON_DEMAND
   owl_shapes(&shape_patterns, moves, color, &owl, &owl_defendpat_db);
@@ -3570,7 +3561,6 @@
   int origin;
   int acode;
   double start = 0;
-  owl.local_owl_node_counter = 0;
 
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
@@ -3593,13 +3583,9 @@
       return 3 - result;
     }
     
-    owl.lunches_are_current = 0;
-    owl_mark_dragon(target, NO_MOVE, &owl);
-    owl_update_goal(move, 1, &owl);
-    compute_owl_escape_values(&owl);
+    init_owl(&owl, target, NO_MOVE, move);
     acode = do_owl_attack(target, NULL, &owl, EMPTY, 0);
     result = 3 - acode;
-    owl.lunches_are_current = 0;
     popgo();
   }
   else
@@ -3639,7 +3625,6 @@
   int origin;
   int defense = 0;
   double start = 0.;
-  owl.local_owl_node_counter = 0;
 
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
@@ -3665,13 +3650,9 @@
        return 0;
     }
     
-    owl.lunches_are_current = 0;
-    owl_mark_dragon(target, NO_MOVE, &owl);
-    owl_update_goal(move, 1, &owl);
-    compute_owl_escape_values(&owl);
+    init_owl(&owl, target, NO_MOVE, move);
     if (!do_owl_attack(target, &defense, &owl, EMPTY, 0))
       result = WIN;
-    owl.lunches_are_current = 0;
     popgo();
   }
   else
@@ -3714,7 +3695,6 @@
   int origin;
   int dcode;
   double start = 0.;
-  owl.local_owl_node_counter = 0;
 
   if (debug & DEBUG_OWL_PERFORMANCE)
     start = gg_cputime();
@@ -3734,9 +3714,7 @@
    * some stones of the goal dragon from the board.
    */
 #if 1
-    owl.lunches_are_current = 0;
-    owl_mark_dragon(target, NO_MOVE, &owl);
-    compute_owl_escape_values(&owl);
+    init_owl(&owl, target, NO_MOVE, NO_MOVE);
 #endif
 
     if (trymove(move, other, "owl_does_attack", target, EMPTY, 0)) {
@@ -3748,6 +3726,7 @@
     }
 
 #if 0
+    owl.local_owl_node_counter = 0;
     owl.lunches_are_current = 0;
     owl_mark_dragon(target, NO_MOVE, &owl);
 #endif
@@ -3814,10 +3793,7 @@
                                  target2, &result, NULL, NULL, NULL))
     return result;
 
-  owl.local_owl_node_counter = 0;
-  owl.lunches_are_current = 0;
-  owl_mark_dragon(target1, target2, &owl);
-  compute_owl_escape_values(&owl);
+  init_owl(&owl, target1, target2, NO_MOVE);
 
   if (trymove(move, color, "owl_connection_defends", target1, EMPTY, 0)) {
     owl_update_goal(move, 1, &owl);
@@ -4182,6 +4158,7 @@
   
   if (liberties > MAX_SUBSTANTIAL_LIBS)
     return 0;
+  
   for (m = 0; m < board_size; m++)
     for (n = 0; n < board_size; n++)
       owl.goal[POS(m, n)] = 0;
@@ -4234,6 +4211,9 @@
       }
     }
   }
+  /* FIXME: We would want to use init_owl() here too, but it doesn't
+   * fit very well with the construction of the goal array above.
+   */
   compute_owl_escape_values(&owl);
   owl_mark_boundary(&owl);
   owl.lunches_are_current = 0;
@@ -4549,6 +4529,22 @@
 owl_escape_route(struct local_owl_data *owl)
 {
   return dragon_escape(owl->goal, owl->color, owl->escape_values);
+}
+
+
+/****************************
+ * Initialization of owl data
+ ****************************/
+
+static void
+init_owl(struct local_owl_data *owl, int target1, int target2, int move)
+{
+  owl->local_owl_node_counter = 0;
+  owl->lunches_are_current = 0;
+  owl_mark_dragon(target1, target2, owl);
+  if (move != NO_MOVE)
+    owl_update_goal(move, 1, owl);
+  compute_owl_escape_values(owl);
 }
 
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]