# # Patch name: @bench # Patch version: 1 # Author's name: Anonymous Coward # Author's email: kmoon@geocities.com # Version of PennMUSH: 1.7.4p8 # Date patch made: Mon Aug 13 23:59:42 EDT 2001 # Author is willing to support (yes/no): yes # Patch format: context diff # # # This is a contributed PennMUSH patch. Its use is subject to the # same restrictions found in PennMUSH's hdrs/copyrite.h file. # # No warranty is given for this patch. It is not necessarily going # to work on your system, with any version of PennMUSH other than # the one above, etc. # # If the author given above was willing to support the patch, you # should write to the author if you have any questions or problems. Do # *NOT* send email messages to Javelin or any PennMUSH mailing list about # this patch! # # Below this line is the author's description of the patch, # followed by the patch itself. If the patch is in context diff # format, you'll probably apply it by typing: patch < patchfile # in your top-level MUSH directory, unless instructed otherwise # below. # SUMMARY This patch adds a @BENCH local command to an unmodified cmdlocal.c. This is good for things like winning bar bets about whose code really runs faster, and can help you choose between different alternative ways of coding an expression by providing benchmark data. REQUIREMENTS This patch was originally written for a PennMUSH 1.7.4p8, but was backwritten for 1.7.2p35 as well (the only actual change was to change the last few lines to use a snprintf() instead of a notify_format, which is specific to 1.7.4). This patch require the availability of a function similar to gettimeofday(), and the snprintf() function. Neither is in the ANSI C standard libraries. The patch currently does not take advantage of PennMUSH's autoconf header, but may at a later time. Sorry, this was a quick-and-dirty hack. INSTALLATION Simply type patch -p0 < benchmark.174p3 in your pennmush directory. This will patch the cmdlocal.c file in the src directory. You'll also need to either add -DPENNMARK to your makefile, or add #define PENNMARK to your options.h file. Then make install and restart. SYNTAX The syntax for @BENCH is: @BENCH = This command basically benchmarks a softcode expression by running it times. It returns the total running time as a number of seconds elapsed (with a precision to 6 decimal places). This command can only be used to evaluate expressions, and thus is useless for benchmarking commands. Since there is a considerable overhead from executing process_expression, the results from @BENCH are only really meaningful for compound softcode expressions, and shouldn't be used to directly compare the performance of hardcode hacks. However, in practice @BENCH does provide reasonable information for making relative comparisons. KNOWN BUGS This version of the patch does not support the autoconf header file, and so does not attempt to resolve platform issues like the presence or absence of gettimeofday() and snprintf(). snprintf() may be replaced by sprintf(), or on the Win32 platform, _snprintf(). PennMUSH provides an our_gettimeofday() which provides the functions of gettimeofday() (although with a slightly different calling syntax). If you have problems compiling this code, consider making the appropriate changes. This patch makes changes to the src/cmdlocal.c file. If you have made changes to this file, this patch probably won't work perfectly. As a work around, you can try patching a copy of cmdlocal.dst and then manually copying the changes to your cmdlocal.c. A glaringly obvious issue which isn't exactly a bug is the fact that the @BENCH command circumvents PennMUSH's function invocation limit restrictions. This is to allow accurate benchmarking with a large number of iterations. Since this will completely lock up your game for the duration of the benchmark procedure with no way to interrupt the benchmark except a hard kill, it is recommended that this patch not be used on a production game server, or at least not without additional security restrictions, perhaps restricting the command to only GOD, rather than to only WIZARDs. *** src/cmdlocal.dst Tue Aug 14 00:19:18 2001 --- src/cmdlocal.c Tue Aug 14 00:20:14 2001 *************** *** 60,65 **** --- 60,133 ---- } #endif + #ifdef PENNMARK + extern int global_fun_invocations; + extern int global_fun_recursions; + COMMAND(cmd_bench) { + char buff[BUFFER_LEN]; + char *bp = buff; + + const char *str; + + struct timeval tvtot = { 0, 0 }, tv1, tv2; + int count, limit; + + const int local_fun_invocations = global_fun_invocations; + const int local_fun_recursions = global_fun_recursions; + + /* a modicum of security */ + if (!Wizard(player)) { + notify(player, "Permission denied."); + return; + } + + /* perform benchmarking */ + limit = atoi(arg_left); + for (count = 0; count < limit; count++) { + /* reset state data */ + bp = buff; + str = arg_right; + global_fun_invocations = local_fun_invocations; + global_fun_recursions = local_fun_recursions; + + /* time the operation */ + gettimeofday(&tv1, NULL); + process_expression(buff, &bp, &str, + player, player, player, + PE_DEFAULT, PT_DEFAULT, NULL); + gettimeofday(&tv2, NULL); + + /* calculate time difference */ + if (tv2.tv_usec < tv1.tv_usec) { + tvtot.tv_sec += tv2.tv_sec - 1 - tv1.tv_sec; + tvtot.tv_usec += 1000000 + tv2.tv_usec - tv1.tv_usec; + } else { + tvtot.tv_sec += tv2.tv_sec - tv1.tv_sec; + tvtot.tv_usec += tv2.tv_usec - tv1.tv_usec; + } + + if (tvtot.tv_usec >= 1000000) { + (tvtot.tv_sec)++; + tvtot.tv_usec -= 1000000; + } + } + *bp = '\0'; + + /* display */ + bp = (char *)malloc(BUFFER_LEN * sizeof(char)); + if (!bp) { + notify(player, "Unable to allocate memory for output."); + return; + } + snprintf(bp, BUFFER_LEN, + "run time: %d.%06ds (%d iteration%s)\nlast output:%s", + (int)(tvtot.tv_sec), (int)(tvtot.tv_usec), + limit, limit == 1 ? "" : "s", + buff); + notify(player, bp); + free(bp); + } + #endif /* PENNMARK */ /* Called during the command init sequence. * This is where you'd put calls to add_command to insert a local *************** *** 69,74 **** --- 137,146 ---- void local_commands() { + #ifdef PENNMARK + command_add("BENCH", CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, 0, 0, 0, + NULL, cmd_bench); + #endif /* PENNMARK */ #ifdef EXAMPLE command_add("@SILLY", CMD_T_ANY, 0, 0, 0, switchmask("NOISY NOEVAL"), cmd_local_silly);