Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / dumptree.c
1 /**
2
3 Copyright (c) Scott Gasch
4
5 Module Name:
6
7     dumptree.c
8
9 Abstract:
10
11     Support routines for dumping a search tree into an XML file for
12     offline analysis by typhoonui.exe.
13
14 Author:
15
16     Scott Gasch ([email protected]) 17 Jul 2004
17
18 Revision History:
19
20 **/
21
22 #ifdef DUMP_TREE
23 #include "chess.h"
24
25 #define NHUMAN_READABLE
26 #ifdef HUMAN_READABLE
27 #define SPACES_TO_INDENT_PER_PLY (2)
28 #else
29 #define SPACES_TO_INDENT_PER_PLY (0)
30 #endif
31 #define DISK_SECTOR_SIZE_BYTES   (512)
32 #define NUM_SECTORS_TO_BUFFER    (2)
33
34 FILE *pfTreeDump = NULL;
35 ULONG g_uBufferSize = 0;
36 ULONG g_uBufferUsed = 0;
37 CHAR *g_Buffer = NULL;
38 #ifdef MP
39 volatile static ULONG g_uBufferLock = 0;
40 #define BUF_IS_LOCKED (g_uBufferLock != 0)
41 #define LOCK_BUF \
42     AcquireSpinLock(&g_uBufferLock); \
43     ASSERT(BUF_IS_LOCKED);
44 #define UNLOCK_BUF \
45     ASSERT(BUF_IS_LOCKED); \
46     ReleaseSpinLock(&g_uBufferLock);
47 #else // no MP
48 #define BUF_IS_LOCKED
49 #define LOCK_BUF
50 #define UNLOCK_BUF
51 #endif
52
53 void 
54 InitializeTreeDump(void)
55 /**
56
57 Routine description:
58
59     Initialize tree dumping system.
60
61 Parameters:
62
63     void
64
65 Return value:
66
67     void
68
69 **/
70 {
71     //
72     // Allocate an internal buffer so that our writes to disk
73     // approximate a sector size.
74     //
75     g_uBufferSize = DISK_SECTOR_SIZE_BYTES * NUM_SECTORS_TO_BUFFER;
76     g_Buffer = SystemAllocateMemory(g_uBufferSize);
77
78     //
79     // Here's the file we'll want to write to...
80     //
81     pfTreeDump = fopen("typhoon.xml", "wb+");
82     if (NULL == pfTreeDump)
83     {
84         UtilPanic(FATAL_ACCESS_DENIED,
85                   NULL, "typhoon.xml", "write", "NULL", __FILE__, __LINE__);
86     }
87     fprintf(pfTreeDump, "<?xml version=\"1.0\" encoding=\"utf-8\""
88             " standalone=\"no\"?>\n");
89 }
90
91 static 
92 void _FlushTheBuffer(void)
93 /**
94
95 Routine description:
96
97     Flush the buffer to the disk file.
98
99 Parameters:
100
101     void
102
103 Return value:
104
105     void
106
107 **/
108 {
109     fprintf(pfTreeDump, g_Buffer);
110     g_Buffer[0] = '\0';
111     g_uBufferUsed = 0;
112 }
113
114
115 static void CDECL 
116 _AppendToBuffer(CHAR *buf)
117 /**
118
119 Routine description:
120
121     Append a string to the buffer; possibly flush the buffer to disk
122     first to make enough room for the new string.
123
124 Parameters:
125
126     CHAR *buf : the string to append
127
128 Return value:
129
130     void
131
132 **/
133 {
134     ULONG uSpaceNeeded;
135     ASSERT(BUF_IS_LOCKED);
136     
137     //
138     // How much space do we need?
139     //
140     uSpaceNeeded = strlen(buf);
141     ASSERT(uSpaceNeeded < MEDIUM_STRING_LEN_CHAR);
142     ASSERT(uSpaceNeeded < g_uBufferSize);
143     
144     //
145     // See if we need to flush the real buffer to the disk before we can
146     // append this new message.
147     // 
148     LOCK_BUF;
149     if (g_uBufferUsed + uSpaceNeeded >= g_uBufferSize)
150     {
151         _FlushTheBuffer();
152         ASSERT(g_uBufferUsed + uSpaceNeeded < g_uBufferSize);
153     }
154     
155     //
156     // Append the new data to the big buffer
157     //
158     strcat(g_Buffer, buf);
159     g_uBufferUsed += uSpaceNeeded;
160     ASSERT(g_uBufferUsed < g_uBufferSize);
161     UNLOCK_BUF;
162 }
163
164
165 static void _IndentTreeDumpMessage(ULONG uPly)
166 /**
167
168 Routine description:
169
170     Append a number of spaces to the buffer to indent the next output
171     appropriately based upon the current search ply.
172
173 Parameters:
174
175     ULONG uPly : the current search ply
176
177 Return value:
178
179     void
180
181 **/
182 {
183     ULONG uSpaces = uPly * SPACES_TO_INDENT_PER_PLY;
184     ASSERT(uSpaces < g_uBufferSizeBytes);
185     ASSERT(HUMAN_READABLE);
186     while(uSpaces)
187     {
188         _AppendToBuffer(" ");
189         uSpaces--;
190     }
191 }
192
193
194 void CDECL 
195 DTTrace(ULONG uPly, CHAR *szMessage, ...)
196 /**
197
198 Routine description:
199
200     A printf-like routine for adding a message to the buffer / dumpfile.
201     Note: messages that exceed MEDIUM_STRING_LEN_CHAR are truncated.
202
203 Parameters:
204
205     ULONG uPly : the current search ply
206     CHAR *szMessage : the message format string
207     ... : variable number of interpolated arguments
208
209 Return value:
210
211     void 
212
213 **/
214 {
215     va_list ap;
216     CHAR buf[MEDIUM_STRING_LEN_CHAR];
217     buf[0] = '\0';
218
219     //
220     // Populate the local buffer
221     //
222     va_start(ap, szMessage);
223     COMPILER_VSNPRINTF(buf, MEDIUM_STRING_LEN_CHAR - 2, szMessage, ap);
224     va_end(ap);
225 #ifdef HUMAN_READABLE
226     strcat(buf, "\n");
227     _IndentTreeDumpMessage(uPly);
228 #endif
229     _AppendToBuffer(buf);
230 }
231
232
233 void 
234 CleanupTreeDump(void)
235 /**
236
237 Routine description:
238
239     Tear down the tree dumping system
240
241 Parameters:
242
243     void
244
245 Return value:
246
247     void
248
249 **/
250 {
251     //
252     // Cleanup file and buffer
253     //
254     if (NULL != pfTreeDump)
255     {
256         _FlushTheBuffer();
257         fflush(pfTreeDump);
258         fclose(pfTreeDump);
259     }
260
261     if (NULL != g_Buffer)
262     {
263         SystemFreeMemory(g_Buffer);
264         g_Buffer = NULL;
265         g_uBufferSize = 0;
266     }
267 }
268
269
270 void 
271 DTEnterNode(SEARCHER_THREAD_CONTEXT *ctx,
272             ULONG uDepth, 
273             FLAG fIsQNode,
274             SCORE iAlpha, 
275             SCORE iBeta)
276 /**
277
278 Routine description:
279
280     Called by search or qsearch upon entering a new node.
281
282 Parameters:
283
284     SEARCHER_THREAD_CONTEXT *ctx : searcher context
285     ULONG uDepth : depth
286     FLAG fIsQNode : is it a q node?
287     SCORE iAlpha : current alpha
288     SCORE iBeta : current beta
289
290 Return value:
291
292     void
293
294 **/
295 {
296     ULONG uPly = ctx->uPly;
297     UINT64 u64NodeNum = ctx->sCounters.tree.u64TotalNodeCount;
298     CHAR *p;
299     
300     if (FALSE == fIsQNode)
301     {
302         DTTrace(uPly, "<n n=\"%"
303                 COMPILER_LONGLONG_UNSIGNED_FORMAT 
304                 "\">", u64NodeNum);
305     }
306     else
307     {
308         DTTrace(uPly, "<qn n=\"%" 
309                 COMPILER_LONGLONG_UNSIGNED_FORMAT 
310                 "\">", u64NodeNum);
311         p = PositionToFen(&ctx->sPosition);
312         ASSERT(p);
313         DTTrace(uPly + 1, "<fen p=\"%s\"/>", p);
314         SystemFreeMemory(p);
315         DTTrace(uPly + 1, "<i ab=\"%d, %d\" ply=\"%u\" depth=\"%u\"/>",
316                 iAlpha, iBeta, uPly, uDepth);
317     }
318 }
319
320
321 void 
322 DTLeaveNode(SEARCHER_THREAD_CONTEXT *ctx, 
323             FLAG fQNode,
324             SCORE iBestScore,
325             MOVE mvBestMove)
326 /**
327
328 Routine description:
329
330     Called by the search upon leaving a normal (non q) node.
331
332 Parameters:
333
334     SEARCHER_THREAD_CONTEXT *ctx : searcher context
335     SCORE iBestScore : best score found
336     MOVE mvBestMove : best move found
337
338 Return value:
339
340     void
341
342 **/
343 {
344     ULONG uPly = ctx->uPly;
345     
346     DTTrace(uPly + 1, "<d score=\"%d\" mv=\"%s\"/>",
347             iBestScore, MoveToSan(mvBestMove, &ctx->sPosition));
348     if (!fQNode) 
349     {
350         DTTrace(uPly, "</n>");
351     }
352     else
353     {
354         DTTrace(uPly, "</qn>");
355     }
356 }
357 #endif