Rev 108 | Go to most recent revision | 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; |
||
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"); |
||
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; |
||
154 | pmbaty | 100 | for (v = 0; v < accuracy; v++) |
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; |
||
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; |
||
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 | } |