Przeglądaj źródła

Fix GCStress on Linux

Complete the port of GCStress to linux.
1. Fix bugs in implementation of BitTestAndSet etc.
2. Support passing in command line flags to GCStress
3. Use sigtrap for assertion failures to break into both lldb and gdb
4. Lower threshold of initial object count/op count to show progress
   on my VM. We'll have a future investigation item to understand what
   operations are slower on linux and how they can be sped up.
Hitesh Kanwathirtha 10 lat temu
rodzic
commit
039b059082

+ 1 - 0
CMakeLists.txt

@@ -104,6 +104,7 @@ if(CMAKE_BUILD_TYPE STREQUAL Debug)
     add_definitions(
         -DDBG=1
         -DDEBUG=1
+        -D_DEBUG=1 # for PAL
         -DDBG_DUMP=1        
     )
     # xplat-todo: reenable this warning

+ 30 - 2
bin/GCStress/GCStress.cpp

@@ -5,6 +5,11 @@
 #include "stdafx.h"
 #include "GCStress.h"
 
+// For converting from ANSI to UTF16
+#ifndef _WIN32
+#include <src/include/pal/utils.h>
+#endif
+
 void DoVerify(bool value, const char * expr, const char * file, int line)
 {
     if (!value)
@@ -20,9 +25,16 @@ static const unsigned int stackRootCount = 50;
 static const unsigned int globalRootCount = 50;
 static const unsigned int implicitRootCount = 50;
 
+#ifdef _WIN32
 static const unsigned int initializeCount = 1000000;
-
 static const unsigned int operationsPerHeapWalk = 1000000;
+#else
+// xplat-todo: Increase this number to match the windows numbers
+// Currently, the windows numbers seem to be really slow on linux
+// Need to investigate what operation is so much slower on linux
+static const unsigned int initializeCount = 10000;
+static const unsigned int operationsPerHeapWalk = 100000;
+#endif
 
 // Some global variables
 
@@ -405,7 +417,23 @@ int __cdecl wmain(int argc, __in_ecount(argc) WCHAR* argv[])
 #ifndef _WIN32
 int main(int argc, char** argv)
 {
-    int ret = wmain(0, NULL);
+    // Ignoring mem-alloc failures here as this is
+    // simply a test tool. We can add more error checking
+    // here later if desired.
+    wchar16** args = new wchar16*[argc];
+    for (int i = 0; i < argc; i++)
+    {
+        args[i] = UTIL_MBToWC_Alloc(argv[i], -1);
+    }
+    
+    int ret = wmain(argc, args);
+
+    for (int i = 0; i < argc; i++)
+    {
+        free(args[i]);
+    }
+    delete[] args;
+    
     PAL_Shutdown();
     return ret;
 }

+ 2 - 3
lib/Common/CommonPal.h

@@ -55,8 +55,7 @@ inline int get_cpuid(int cpuInfo[4], int function_id)
 
 inline void DebugBreak()
 {
-    asm ("int3");
-    __builtin_unreachable();
+    __builtin_trap();
 }
 
 #define _BitScanForward BitScanForward
@@ -67,7 +66,7 @@ inline void DebugBreak()
 #define _bittestandset BitTestAndSet
 #define _interlockedbittestandset InterlockedBitTestAndSet
 
-#define DbgRaiseAssertionFailure() __asm__ volatile("int $0x03");
+#define DbgRaiseAssertionFailure() __builtin_trap()
 
 // These are not available in pal
 #define fwprintf_s      fwprintf

+ 1 - 1
lib/Common/Memory/Recycler.cpp

@@ -324,7 +324,7 @@ Recycler::Recycler(AllocationPolicyManager * policyManager, IdleDecommitPageAllo
 
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
     // recycler requires at least Recycler::PrimaryMarkStackReservedPageCount to function properly for the main mark context
-    this->markContext.SetMaxPageCount(max(GetRecyclerFlagsTable().MaxMarkStackPageCount, Recycler::PrimaryMarkStackReservedPageCount));
+    this->markContext.SetMaxPageCount(max(static_cast<size_t>(GetRecyclerFlagsTable().MaxMarkStackPageCount), static_cast<size_t>(Recycler::PrimaryMarkStackReservedPageCount)));
     this->parallelMarkContext1.SetMaxPageCount(GetRecyclerFlagsTable().MaxMarkStackPageCount);
     this->parallelMarkContext2.SetMaxPageCount(GetRecyclerFlagsTable().MaxMarkStackPageCount);
     this->parallelMarkContext3.SetMaxPageCount(GetRecyclerFlagsTable().MaxMarkStackPageCount);

+ 28 - 8
pal/inc/pal.h

@@ -5634,6 +5634,9 @@ InterlockedOr(
     return __sync_fetch_and_or(Destination, Value);
 }
 
+#define BITS_IN_BYTE 8
+#define BITS_IN_LONG (sizeof(LONG) * BITS_IN_BYTE)
+  
 EXTERN_C
 PALIMPORT
 inline
@@ -5643,7 +5646,13 @@ InterlockedBitTestAndReset(
     IN OUT LONG volatile *Base,
     IN LONG Bit)
 {
-    return (InterlockedAnd(Base, ~(1 << Bit)) & (1 << Bit)) != 0;
+    // The BitTestAndReset family of functions allow for arbitrary bit
+    // indices- so a bit index can be greater than the number of bits in
+    // LONG. We need to account for this in all BitTest/BitTestAndSet
+    // related functions.    
+    volatile LONG* longToTest = Base + (Bit / BITS_IN_LONG);
+    LONG bitToTest  = Bit % BITS_IN_LONG;
+    return (InterlockedAnd(longToTest, ~(1 << bitToTest)) & (1 << bitToTest)) != 0;
 }
 
 EXTERN_C
@@ -5655,10 +5664,11 @@ InterlockedBitTestAndSet(
     IN OUT LONG volatile *Base,
     IN LONG Bit)
 {
-    return (InterlockedOr(Base, (1 << Bit)) & (1 << Bit)) != 0;
+    volatile LONG* longToTest = Base + (Bit / BITS_IN_LONG);
+    LONG bitToTest  = Bit % BITS_IN_LONG;
+    return (InterlockedOr(longToTest, (1 << bitToTest)) & (1 << bitToTest)) != 0;
 }
-
-// xplat-todo: review this implementation
+  
 EXTERN_C
 PALIMPORT
 inline
@@ -5668,10 +5678,11 @@ BitTest(
     IN LONG *Base,
     IN LONG Bit)
 {
-    return ((*Base) & (1 << Bit)) != 0;
+    LONG* longToTest = Base + (Bit / BITS_IN_LONG);
+    LONG bitToTest  = Bit % BITS_IN_LONG;
+    return ((*longToTest) & (1 << bitToTest)) != 0;
 }
-
-// xplat-todo: review this implementation
+  
 EXTERN_C
 PALIMPORT
 inline
@@ -5681,7 +5692,16 @@ BitTestAndSet(
     IN OUT LONG *Base,
     IN LONG Bit)
 {
-    return (__sync_fetch_and_or(Base, (1 << Bit)) & (1 << Bit)) != 0;
+    // xplat-todo: Benchmark whether this is better than
+    // using the inline assembler to generate a bts instruction
+    LONG* longToTest = Base + (Bit / BITS_IN_LONG);
+    LONG bitToTest  = Bit % BITS_IN_LONG;
+
+    // Save whether the bit was set or not. Then, unconditionally set the
+    // bit. Return whether the bit was set or not.   
+    UCHAR wasBitSet = (((*longToTest) & (1 << bitToTest)) != 0);
+    *longToTest = *longToTest | (1 << bitToTest);
+    return wasBitSet;
 }
 
 #if defined(BIT64)