Subversion Repositories Games.Chess Giants

Rev

Rev 108 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "chess.h"
  2. #include "data.h"
  3. /* last modified 08/26/15 */
  4. /*
  5.  *******************************************************************************
  6.  *                                                                             *
  7.  *   AutoTune() is used to tune the parallel search parameters and optimize    *
  8.  *   them for the current hardware and a specific time per move target.  The   *
  9.  *   syntax of the command is                                                  *
  10.  *                                                                             *
  11.  *         autotune time accuracy                                              *
  12.  *                                                                             *
  13.  *   "time" is the target time to optimize for.  Longer time limits require    *
  14.  *   somewhat different tuning values, so this should be set to the typical    *
  15.  *   time per move.  The default is 30 seconds per move if not specified.      *
  16.  *                                                                             *
  17.  *   "accuracy" is normally set to 4.  Since SMP search results and times are  *
  18.  *   non-deterministic, running tests 1 time can be inaccurate.  This value is *
  19.  *   used to determine how many times to run each test.  If you set it to two, *
  20.  *   the entire test will take 1/2 as long.  Bigger numbers are better, but    *
  21.  *   it is easy to make the test run for hours if you go too far.  A big value *
  22.  *   will work best if allowed to run overnight.  Crafty will display a time   *
  23.  *   estimate after determining the optimal benchmark settings.  If this time  *
  24.  *   is excessive, a ^C will let you re-start Crafty and pick a more           *
  25.  *   reasonable time/accuracy setting.                                         *
  26.  *                                                                             *
  27.  *   AutoTune() will tune the primary SMP controls, namely the values set by   *
  28.  *   the commands smpgroup, smpmin, smpsd and smppsl.  It will NEVER change    *
  29.  *   smpmt (max threads), smproot (split at root) and smpaffinity.  those are  *
  30.  *   user choices and in general the default is optimal.  In general the       *
  31.  *   values have min and max settings defined in data.c (search for autotune), *
  32.  *   and this code will try multiple values in the given range to find an      *
  33.  *   optimal setting.  For some of the values, it will test each value in the  *
  34.  *   interval, but for values with a large range it will try reasonable        *
  35.  *   (again, see data.c and the "tune" array) intervals.  If desired, the      *
  36.  *   low/high limits can be changed along with the interval between samples,   *
  37.  *   by modifying the autotune data in data.c.                                 *
  38.  *                                                                             *
  39.  *   Note that this command is best used before you go to eat or something as  *
  40.  *   it will run a while.  If you ramp up the accuracy setting, it will take   *
  41.  *   multiples of accuracy times longer.  Best results are likely obtained     *
  42.  *   with a larger accuracy setting, but it needs to run overnight.            *
  43.  *                                                                             *
  44.  *******************************************************************************
  45.  */
  46. void AutoTune(int nargs, char *args[]) {
  47.   unsigned int target_time = 3000, accuracy = 4, atstart, atend;
  48.   unsigned int time, current, setting[64], times[64], last_time, stageii;
  49.   int benchd, i, v, p, best, bestv, samples;
  50.   FILE *craftyrc = fopen(".craftyrc", "a");
  51.  
  52. /*
  53.  ************************************************************
  54.  *                                                          *
  55.  *  Initialize.                                             *
  56.  *                                                          *
  57.  ************************************************************
  58.  */
  59.   if (smp_max_threads < 2) {
  60.     Print(4095, "ERROR: smpmt must be set to > 1 for tuning to work\n");
  61.     fclose(craftyrc);
  62.     return;
  63.   }
  64.   if (nargs > 1)
  65.     target_time = atoi(args[1]) * 100;
  66.   if (nargs > 2)
  67.     accuracy = atoi(args[2]);
  68.   Print(4095, "AutoTune()  time=%s  accuracy=%d\n",
  69.       DisplayHHMMSS(target_time), accuracy);
  70. /*
  71.  ************************************************************
  72.  *                                                          *
  73.  *  First task is to find the benchmark setting that will   *
  74.  *  run in the alotted time.  The Bench() command runs six  *
  75.  *  positions, so we want the command to run in no more     *
  76.  *  than six times the autotune time limit to average the   *
  77.  *  specified time per move.  We break out of the loop when *
  78.  *  bench takes more than 6x this time limit and use the    *
  79.  *  previous value which just fit inside the limit.         *
  80.  *                                                          *
  81.  ************************************************************
  82.  */
  83.   atstart = ReadClock();
  84.   stageii = 0;
  85.   for (v = 0; v < autotune_params; v++)
  86.     for (current = tune[v].min; current <= tune[v].max;
  87.         current += tune[v].increment)
  88.       stageii++;
  89.   Print(4095, "Calculating optimal benchmark setting.\n");
  90.   Print(4095, "Target time average = %s.\n", DisplayHHMMSS(6 * target_time));
  91.   Print(4095, "Estimated run time (stage I) is %s.\n",
  92.       DisplayHHMMSS(accuracy * 12 * target_time));
  93.   Print(4095, "Estimated run time (stage II) is %s.\n",
  94.       DisplayHHMMSS(accuracy * stageii * 4 * target_time));
  95.   Print(4095, "\nBegin stage I (calibration)\n");
  96.   last_time = 0;
  97.   for (benchd = -5; benchd < 10; benchd++) {
  98.     Print(4095, "bench %2d:", benchd);
  99.     time = 0;
  100.     for (v = 0; v < accuracy; v++)
  101.       time += Bench(benchd, 1);
  102.     time /= accuracy;
  103.     Print(4095, " ->%s\n", DisplayHHMMSS(time));
  104.     if (time > 6 * target_time)
  105.       break;
  106.     last_time = time;
  107.   }
  108.   benchd--;
  109.   Print(4095, "Optimal setting is " "bench %d" "\n", benchd);
  110.   atend = ReadClock();
  111.   Print(4095, "Actual runtime for Stage I: %s\n",
  112.       DisplayHHMMSS(atend - atstart));
  113.   Print(4095, "New estimated run time (stage II) is %s.\n",
  114.       DisplayHHMMSS(accuracy * stageii * last_time));
  115.   Print(4095, "\nBegin stage II (SMP testing).\n");
  116.   atstart = ReadClock();
  117. /*
  118.  ************************************************************
  119.  *                                                          *
  120.  *  Next we simply take each option, one by one, and try    *
  121.  *  reasonable values between the min/max values as defined *
  122.  *  in data.c.                                              *
  123.  *                                                          *
  124.  *  The process is fairly simple, but very time-consuming.  *
  125.  *  We will start at the min value for a single paramenter, *
  126.  *  and run bench "accuracy" times and compute the average  *
  127.  *  of the times.  We then repeat for the next step in the  *
  128.  *  parameter, and continue until we try the max value that *
  129.  *  is allowed.  We choose the parameter value that used    *
  130.  *  the least amount of time which optimizes this value for *
  131.  *  minimum time-to-depth.                                  *
  132.  *                                                          *
  133.  ************************************************************
  134.  */
  135.   for (v = 0; v < autotune_params; v++) {
  136.     Print(4095, "auto-tuning %s (%d ~ %d by %d)\n", tune[v].description,
  137.         tune[v].min, tune[v].max, tune[v].increment);
  138.     current = *tune[v].parameter;
  139.     samples = 0;
  140.     if (v == 0 && tune[v].min > smp_max_threads) {
  141.       samples = 1;
  142.       times[0] = 0;
  143.       setting[0] = smp_max_threads;
  144.     } else
  145.       for (current = tune[v].min; current <= tune[v].max;
  146.           current += tune[v].increment) {
  147.         Print(4095, "Testing %d: ", current);
  148.         *tune[v].parameter = current;
  149.         time = 0;
  150.         for (p = 0; p < accuracy; p++)
  151.           time += Bench(benchd, 1);
  152.         time /= accuracy;
  153.         times[samples] = time;
  154.         setting[samples++] = current;
  155.         Print(4095, " ->%s\n", DisplayHHMMSS(time));
  156.       }
  157.     best = 0;
  158.     bestv = times[0];
  159.     for (i = 1; i < samples; i++)
  160.       if (bestv > times[i]) {
  161.         bestv = times[i];
  162.         best = i;
  163.       }
  164.     fprintf(craftyrc, "%s=%d\n", tune[v].command, setting[best]);
  165.     Print(4095, "adding " "%s=%d" " to .craftyrc file.\n", tune[v].command,
  166.         setting[best]);
  167.   }
  168.   atend = ReadClock();
  169.   Print(4095, "Runtime for StageII: %s\n", DisplayHHMMSS(atend - atstart));
  170.   fclose(craftyrc);
  171. }
  172.