diff --git a/Makefile b/Makefile index 8550f52..4d75c42 100644 --- a/Makefile +++ b/Makefile @@ -89,10 +89,10 @@ CFLAGS := -std=gnu11 ### dev OR release # dev -CFLAGS += -O1 +#CFLAGS += -O1 #CFLAGS += -g # release -#CFLAGS += -Ofast +CFLAGS += -Ofast CFLAGS += -march=native CFLAGS += -flto @@ -100,7 +100,7 @@ CFLAGS += -Wall CFLAGS += -Wextra CFLAGS += -Wmissing-declarations # for gprof -CFLAGS += -pg +#CFLAGS += -pg # Next one may be useful for valgrind (when invalid instructions) # CFLAGS += -mno-tbm @@ -309,7 +309,7 @@ BB_OBJS := $(FEN_OBJS) MOVEGEN_OBJS := $(BB_OBJS) move.o move-gen.o ATTACK_OBJS := $(MOVEGEN_OBJS) MOVEDO_OBJS := $(ATTACK_OBJS) move-do.o -PERFT_OBJS := $(MOVEDO_OBJS) search.o +PERFT_OBJS := $(MOVEDO_OBJS) search.o misc.o TEST := $(addprefix $(BINDIR)/,$(TEST)) diff --git a/src/chessdefs.h b/src/chessdefs.h index 27bcdb5..c94af26 100644 --- a/src/chessdefs.h +++ b/src/chessdefs.h @@ -134,5 +134,35 @@ typedef enum { NORTH_WEST = (NORTH + WEST), } dir_t; +#include + +typedef struct mclock { + clockid_t clocktype; + ulong elapsed_l; + double elapsed_f; + struct timespec start; +} mclock_t; + +#define CLOCK_WALL CLOCK_REALTIME +#define CLOCK_SYSTEM CLOCK_MONOTONIC_RAW +#define CLOCK_PROCESS CLOCK_PROCESS_CPUTIME_ID +#define CLOCK_THREAD CLOCK_THREAD_CPUTIME_ID + +/** + * CLOCK_DEFINE - define a clock type. + * @name: clock name + * @type: clock type + * + * This macro is equivalent to: + * mclock_t name; + * clock_init(&name, type); + */ +#define CLOCK_DEFINE(name, type) struct mclock name = { .clocktype = type } + +void clock_init(mclock_t *clock, clockid_t type); +void clock_start(mclock_t *clock); +s64 clock_elapsed_μs(mclock_t *clock); +s64 clock_elapsed_ms(mclock_t *clock); +double clock_elapsed_sec(mclock_t *clock); #endif /* _CHESSDEFS_H */ diff --git a/src/misc.c b/src/misc.c new file mode 100644 index 0000000..fb707e2 --- /dev/null +++ b/src/misc.c @@ -0,0 +1,112 @@ +/* misc.c - generic/catchall functions. + * + * Copyright (C) 2024 Bruno Raoult ("br") + * Licensed under the GNU General Public License v3.0 or later. + * Some rights reserved. See COPYING. + * + * You should have received a copy of the GNU General Public License along with this + * program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include + +#include "chessdefs.h" + +/* + * 1 sec = 1000 millisec + * 1 millisec = 1000 microsec + * 1 microsec = 1000 nanosec + * milli = sec * 1000 + nanosec / 1000000 + * + */ + +/* We use microsec for all intermediate calcluation */ +#define NANO_IN_MICRO 1000ll /* nanosecond in millisecond */ +#define MICRO_IN_SEC 1000000ll /* millisecond in second */ + +#define MILLI_IN_SEC 1000ll /* millisecond in second */ + +#define MICRO_IN_MILLI 1000ll + +//#define NANO_IN_MILLI 1000000ll /* nanosecond in millisecond */ +//#define NANO_IN_SEC (NANOS_IN_MS * MS_IN_SEC) + + +/** + * clock_start - start or restart a clock. + * @clock: &mclock_t clock + * + * Save current time according to @clock type. + */ +void clock_start(mclock_t *clock) +{ + clock_gettime(clock->clocktype, &clock->start); +} + +/** + * clock_init - initializes a clock type. + * @clock: &mclock_t clock + * @type: clock type + * + * See the clock_gettime(2) for details. + * CLOCK_WALL (a.k.a CLOCK_REALTIME): Wall clock. + * CLOCK_SYSTEM (a.k.a CLOCK_MONOTONIC_RAW): System clock. + * CLOCK_PROCESS (a.k.a CLOCK_PROCESS_CPUTIME_ID): Process CPU clock (incl. threads). + * CLOCK_THREAD (a.k.a CLOCK_THREAD_CPUTIME_ID): Thread CPU clock. + */ +void clock_init(mclock_t *clock, clockid_t type) +{ + clock->clocktype = type; + clock_start(clock); +} + +/** + * clock_elapsed_μs - return a mclock_t elapsed time in microseconds. + * @clock: &mclock_t clock + * + * The elapsed time is calculated between current time and last clock_start(@clock) + * call time. + * + * @return: microseconds elapsed since last clock_start(). + */ +s64 clock_elapsed_μs(mclock_t *clock) +{ + struct timespec current; + s64 μs; + + clock_gettime(clock->clocktype, ¤t); + μs = ((s64)current.tv_sec - (s64)clock->start.tv_sec) * MICRO_IN_SEC + + ((s64)current.tv_nsec - (s64)clock->start.tv_nsec) / NANO_IN_MICRO ; + return μs; +} + +/** + * clock_elapsed_ms - return a mclock_t elapsed time in milliseconds. + * @clock: &mclock_t clock + * + * The elapsed time is calculated between current time and last clock_start(@clock) + * call time. + * + * @return: milliseconds elapsed since last clock_start(). + */ +s64 clock_elapsed_ms(mclock_t *clock) +{ + return clock_elapsed_μs(clock) / MICRO_IN_MILLI; +} + +/** + * clock_elapsed_sec - return a mclock_t elapsed time in seconds. + * @clock: &mclock_t clock + * + * The elapsed time is calculated between current time and last clock_start(@clock) + * call time. + * + * @return: seconds elapsed since last clock_start(). + */ +double clock_elapsed_sec(mclock_t *clock) +{ + return (double) clock_elapsed_μs(clock) / (double) MICRO_IN_SEC; +} diff --git a/src/search.c b/src/search.c index 30d8cd8..4852cad 100644 --- a/src/search.c +++ b/src/search.c @@ -21,9 +21,6 @@ #include "search.h" #include "attack.h" -//#include "move.h" -//#include "eval.h" - /** * perft() - Perform perft on position * @pos: &position to search @@ -63,7 +60,7 @@ u64 perft(pos_t *pos, int depth, int ply) } if (ply == 1) - printf("\nTotal: %lu\n", nodes); + printf("Total: %lu\n", nodes); return nodes; } @@ -88,19 +85,19 @@ u64 perft2(pos_t *pos, int depth, int ply) for (nmove = 0; nmove < pseudo.nmoves; ++nmove ) { move = pseudo.move[nmove]; move_do(pos, move); - //if (!is_in_check(pos, OPPONENT(pos->turn))) { + subnodes = perft2(pos, depth - 1, ply + 1); + nodes += subnodes; if (ply == 1) { char movestr[8]; printf("%s: %d\n", move_str(movestr, move, 0), subnodes); } - //} move_undo(pos, move); pos->state = state; } if (ply == 1) - printf("\nTotal: %lu\n", nodes); + printf("Total: %lu\n", nodes); return nodes; } diff --git a/test/perft-test.c b/test/perft-test.c index e93847f..ae40814 100644 --- a/test/perft-test.c +++ b/test/perft-test.c @@ -256,41 +256,28 @@ int main(int __unused ac, __unused char**av) savepos = pos_dup(pos); //int j = 0; -#define NANOSEC 1000000000 /* nano sec in sec */ -#define MILLISEC 1000000 /* milli sec in sec */ + s64 μs; + CLOCK_DEFINE(clock, CLOCK_SYSTEM); - // 1 sec = 1000 millisec - // 1 millisec = 1000 microsec - // 1 microsec = 1000 nanosec - // milli = sec * 1000 + nanosec / 1000000 - struct timespec ts1, ts2; - s64 microsecs; - - clock_gettime(CLOCK_MONOTONIC_RAW, &ts1); + clock_start(&clock); my_count = perft(pos, depth, 1); - clock_gettime(CLOCK_MONOTONIC_RAW, &ts2); + μs = clock_elapsed_μs(&clock); - microsecs = ((s64)ts2.tv_sec - (s64)ts1.tv_sec) * 1000000l - + ((s64)ts2.tv_nsec - (s64)ts1.tv_nsec) / 1000l ; if (sf_count == my_count) { - printf("pt1 OK : line=%03d perft=%lu ms=%'ldms lps=%'lu \"%s\"\n", - test_line, my_count, microsecs/1000l, - my_count*1000000l/microsecs, fen); + printf("pt1 OK : line=%03d perft=%lu μs=%'ldms lps=%'lu \"%s\"\n", + test_line, my_count, μs, my_count*1000000l/μs, fen); } else { printf("pt1 ERR: line=%03d sf=%lu me=%lu \"%s\"\n", test_line, sf_count, my_count, fen); } - clock_gettime(CLOCK_MONOTONIC_RAW, &ts1); + clock_start(&clock); my_count = perft2(pos, depth, 1); - clock_gettime(CLOCK_MONOTONIC_RAW, &ts2); + μs = clock_elapsed_μs(&clock); - microsecs = ((s64)ts2.tv_sec - (s64)ts1.tv_sec) * 1000000l - + ((s64)ts2.tv_nsec - (s64)ts1.tv_nsec) / 1000l ; if (sf_count == my_count) { - printf("pt2 OK : line=%03d perft=%lu ms=%'ldms lps=%'lu \"%s\"\n\n", - test_line, my_count, microsecs/1000l, - my_count*1000000l/microsecs, fen); + printf("pt2 OK : line=%03d perft=%lu μs=%'ldms lps=%'lu \"%s\"\n\n", + test_line, my_count, μs, my_count*1000000l/μs, fen); } else { printf("pt2 ERR: line=%03d sf=%lu me=%lu \"%s\"\n\n", test_line, sf_count, my_count, fen);