Rev 154 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 108 | pmbaty | 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; | ||
| 156 | pmbaty | 49 | int benchd, i, v; unsigned int p; int best; unsigned int bestv; int samples; // Pierre-Marie Baty -- fixed types | 
| 108 | pmbaty | 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"); | ||
| 154 | pmbaty | 61 | fclose(craftyrc); | 
| 108 | pmbaty | 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; | ||
| 156 | pmbaty | 100 | for (v = 0; v < (int) accuracy; v++) // Pierre-Marie Baty -- added type cast | 
| 108 | pmbaty | 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; | ||
| 156 | pmbaty | 140 | if (v == 0 && tune[v].min > (unsigned int) smp_max_threads) { // Pierre-Marie Baty -- added type cast | 
| 108 | pmbaty | 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; | ||
| 154 | pmbaty | 150 | for (p = 0; p < accuracy; p++) | 
| 108 | pmbaty | 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++) | ||
| 154 | pmbaty | 160 | if (bestv > times[i]) { | 
| 108 | pmbaty | 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 | } |