Advertisement
Guest User

luai_hashnum bug

a guest
Apr 22nd, 2014
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.97 KB | None | 0 0
  1. //////////////////////////////////////////////////////////////////////
  2. //    filename:     luaHashTest.cpp
  3. //    author:        James Poag for Rumbic Studios
  4. //    
  5. //    purpose:    This is to demonstrate a real-world scenario in which
  6. //                'luai_hashnum'  FAILS to generate a DETERMINISTIC
  7. //                hash value for identical keys when executed non-concurrently
  8. //                on separate threads.
  9. //
  10. //                It is the fault of different precision controls being
  11. //                set on different threads, one of which is automatically
  12. //                set to 24 bits when using DirectX without the D3DCREATE_FPU_PRESERVE
  13. //                flag.  (But not strictly limited to DX, anyone wanting to
  14. //                increase floating point performance with the sacrifice of
  15. //                precision).
  16. //
  17. //                Another scenario is where the LuaVM is created and setup
  18. //                before DirectX (or anyone) resets the precision control and the
  19. //                resulting LuaVM appears empty (because of hash misses)
  20. /////////////////////////////////////////////////////////////////////
  21.  
  22. #include "targetver.h"
  23.  
  24. #include <stdio.h>
  25. #include <tchar.h>
  26. #include <string.h>
  27.  
  28. #include <float.h>
  29. #include <math.h>
  30. #include <limits.h>
  31.  
  32. #define WIN32_LEAN_AND_MEAN
  33. #include <Windows.h>
  34.  
  35. #pragma fenv_access (on)
  36.  
  37.  
  38. /*
  39. ================================================================================================
  40.  
  41.    Minimum Lua defined macros to reproduce error
  42.  
  43. ================================================================================================
  44. */
  45.  
  46. /* type of numbers in Lua */
  47. #define LUA_NUMBER    double
  48. typedef LUA_NUMBER lua_Number;
  49. #define cast(t, exp)    ((t)(exp))
  50. #define cast_num(i)    cast(lua_Number, (i))
  51.  
  52. /*
  53. ** lua_number2int is a macro to convert lua_Number to int.
  54. */
  55. #define lua_number2int(i,n)  __asm {__asm fld n   __asm fistp i}
  56. #define l_mathop(x)        (x)
  57.  
  58. /*
  59. ** luai_hashnum is a macro to hash a lua_Number value into an integer.
  60. ** The hash must be deterministic and give reasonable values for
  61. ** both small and large values (outside the range of integers).
  62. */
  63. #define luai_hashnum(i,n) { int e;  \
  64.    n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP);  \
  65.    lua_number2int(i, n); i += e; }
  66.  
  67.  
  68.  
  69.  
  70.  
  71. /*
  72. ================================================================================================
  73.  
  74.    Test Code to reproduce error
  75.  
  76. ================================================================================================
  77. */
  78.  
  79. DWORD WINAPI workerThreadFunc (LPVOID lpThread); // forward decl
  80. #define THREAD_COUNT 1    
  81.  
  82.  
  83. /*
  84. ========================
  85. Main Entry Point
  86. ========================
  87. */
  88. int _tmain(int argc, _TCHAR* argv[])
  89. {
  90.  
  91.    /*
  92.     *  In this scenario, we setup both the Render System and the LuaVM
  93.     *  on the [Main Thread].
  94.     */
  95.  
  96.  
  97.    //////////////////////////////////////////////////////////////////////////
  98.    // DirectX sets precision to 24 bits on '[Main Thread]'
  99.    unsigned int control_word_x87;
  100.    control_word_x87 = __control87_2(_PC_24, MCW_PC,
  101.        &control_word_x87, 0);
  102.    //////////////////////////////////////////////////////////////////////////
  103.  
  104.  
  105.    //////////////////////////////////////////////////////////////////////////
  106.    // LuaVM is created and filled
  107.    //////////////////////////////////////////////////////////////////////////
  108.  
  109.  
  110.    //////////////////////////////////////////////////////////////////////////
  111.    // Per Doom3 and many modern multithreaded renderers, the [Main Thread] is
  112.    // used to:
  113.    //        1. Process User/App input events (uses LuaVM on [Main Thread])
  114.    //
  115.    //        2. Spawn/Signal [Worker Thread] that will update game and generate
  116.    //           render commands for next frame (uses LuaVM on [Worker Thread])
  117.    //
  118.    //        3. Execute render commands from previous frame on [Main Thread]
  119.    //           (does not use LuaVM)
  120.    //
  121.    //        4. WaitFor/Join the threads together
  122.    //
  123.    //        Although the LuaVM is used on separate threads, it is never used
  124.    //        concurrently.
  125.  
  126.  
  127.    //////////////////////////////////////////////////////////////////////////
  128.    // spawn [Worker Thread]
  129.    HANDLE pThreads [THREAD_COUNT] = {0};
  130.    for (int i = 0; i < THREAD_COUNT; ++i){
  131.  
  132.        DWORD nThreadId = 0;
  133.        pThreads[i] = CreateThread (NULL,
  134.            0,
  135.            workerThreadFunc,
  136.            0,
  137.            0,
  138.            &nThreadId);
  139.    }
  140.    //////////////////////////////////////////////////////////////////////////
  141.  
  142.  
  143.    //////////////////////////////////////////////////////////////////////////
  144.    // Run the hash function on the [Main Thread]
  145.    lua_Number nk = cast_num(3);
  146.  
  147.    int hashVal = 0;
  148.    luai_hashnum(hashVal, nk);
  149.  
  150.    printf("[Main Thread] reports: %i \n", hashVal); // 1610611970
  151.    //////////////////////////////////////////////////////////////////////////
  152.  
  153.  
  154.  
  155.    //////////////////////////////////////////////////////////////////////////
  156.    // Waitfor/Join
  157.    WaitForMultipleObjects(THREAD_COUNT, pThreads, TRUE, INFINITE);
  158.    //////////////////////////////////////////////////////////////////////////
  159.  
  160.    return 0;
  161. }
  162.  
  163.  
  164. /*
  165. ========================
  166. [Worker Thread]
  167. ========================
  168. */
  169. DWORD WINAPI workerThreadFunc (LPVOID lpThread)
  170. {
  171.    //////////////////////////////////////////////////////////////////////////
  172.    // The precision is not set on the [Worker Thread]
  173.    //////////////////////////////////////////////////////////////////////////
  174.  
  175.  
  176.    Sleep(3); // avoid printf() collision & demo non-concurrent
  177.  
  178.  
  179.    //////////////////////////////////////////////////////////////////////////
  180.    // Run the hash function on the [Worker Thread]
  181.    lua_Number nk = cast_num(3);
  182.  
  183.    int hashVal = 0;
  184.    luai_hashnum(hashVal, nk);
  185.  
  186.    printf("[Worker Thread] reports: %i \n", hashVal); // 1610611969
  187.    //////////////////////////////////////////////////////////////////////////
  188.    
  189.    return 0;
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement