Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //////////////////////////////////////////////////////////////////////
- // filename: luaHashTest.cpp
- // author: James Poag for Rumbic Studios
- //
- // purpose: This is to demonstrate a real-world scenario in which
- // 'luai_hashnum' FAILS to generate a DETERMINISTIC
- // hash value for identical keys when executed non-concurrently
- // on separate threads.
- //
- // It is the fault of different precision controls being
- // set on different threads, one of which is automatically
- // set to 24 bits when using DirectX without the D3DCREATE_FPU_PRESERVE
- // flag. (But not strictly limited to DX, anyone wanting to
- // increase floating point performance with the sacrifice of
- // precision).
- //
- // Another scenario is where the LuaVM is created and setup
- // before DirectX (or anyone) resets the precision control and the
- // resulting LuaVM appears empty (because of hash misses)
- /////////////////////////////////////////////////////////////////////
- #include "targetver.h"
- #include <stdio.h>
- #include <tchar.h>
- #include <string.h>
- #include <float.h>
- #include <math.h>
- #include <limits.h>
- #define WIN32_LEAN_AND_MEAN
- #include <Windows.h>
- #pragma fenv_access (on)
- /*
- ================================================================================================
- Minimum Lua defined macros to reproduce error
- ================================================================================================
- */
- /* type of numbers in Lua */
- #define LUA_NUMBER double
- typedef LUA_NUMBER lua_Number;
- #define cast(t, exp) ((t)(exp))
- #define cast_num(i) cast(lua_Number, (i))
- /*
- ** lua_number2int is a macro to convert lua_Number to int.
- */
- #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
- #define l_mathop(x) (x)
- /*
- ** luai_hashnum is a macro to hash a lua_Number value into an integer.
- ** The hash must be deterministic and give reasonable values for
- ** both small and large values (outside the range of integers).
- */
- #define luai_hashnum(i,n) { int e; \
- n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
- lua_number2int(i, n); i += e; }
- /*
- ================================================================================================
- Test Code to reproduce error
- ================================================================================================
- */
- DWORD WINAPI workerThreadFunc (LPVOID lpThread); // forward decl
- #define THREAD_COUNT 1
- /*
- ========================
- Main Entry Point
- ========================
- */
- int _tmain(int argc, _TCHAR* argv[])
- {
- /*
- * In this scenario, we setup both the Render System and the LuaVM
- * on the [Main Thread].
- */
- //////////////////////////////////////////////////////////////////////////
- // DirectX sets precision to 24 bits on '[Main Thread]'
- unsigned int control_word_x87;
- control_word_x87 = __control87_2(_PC_24, MCW_PC,
- &control_word_x87, 0);
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // LuaVM is created and filled
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // Per Doom3 and many modern multithreaded renderers, the [Main Thread] is
- // used to:
- // 1. Process User/App input events (uses LuaVM on [Main Thread])
- //
- // 2. Spawn/Signal [Worker Thread] that will update game and generate
- // render commands for next frame (uses LuaVM on [Worker Thread])
- //
- // 3. Execute render commands from previous frame on [Main Thread]
- // (does not use LuaVM)
- //
- // 4. WaitFor/Join the threads together
- //
- // Although the LuaVM is used on separate threads, it is never used
- // concurrently.
- //////////////////////////////////////////////////////////////////////////
- // spawn [Worker Thread]
- HANDLE pThreads [THREAD_COUNT] = {0};
- for (int i = 0; i < THREAD_COUNT; ++i){
- DWORD nThreadId = 0;
- pThreads[i] = CreateThread (NULL,
- 0,
- workerThreadFunc,
- 0,
- 0,
- &nThreadId);
- }
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // Run the hash function on the [Main Thread]
- lua_Number nk = cast_num(3);
- int hashVal = 0;
- luai_hashnum(hashVal, nk);
- printf("[Main Thread] reports: %i \n", hashVal); // 1610611970
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- // Waitfor/Join
- WaitForMultipleObjects(THREAD_COUNT, pThreads, TRUE, INFINITE);
- //////////////////////////////////////////////////////////////////////////
- return 0;
- }
- /*
- ========================
- [Worker Thread]
- ========================
- */
- DWORD WINAPI workerThreadFunc (LPVOID lpThread)
- {
- //////////////////////////////////////////////////////////////////////////
- // The precision is not set on the [Worker Thread]
- //////////////////////////////////////////////////////////////////////////
- Sleep(3); // avoid printf() collision & demo non-concurrent
- //////////////////////////////////////////////////////////////////////////
- // Run the hash function on the [Worker Thread]
- lua_Number nk = cast_num(3);
- int hashVal = 0;
- luai_hashnum(hashVal, nk);
- printf("[Worker Thread] reports: %i \n", hashVal); // 1610611969
- //////////////////////////////////////////////////////////////////////////
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement