Browse Source

Merge pull request #4090 from ghalliday/hugepage

HPCC-8934 Add support for huge pages to roxiemem

Reviewed-By: Jake Smith <jake.smith@lexisnexis.com>
Reviewed-By: Richard Chapman <rchapman@hpccsystems.com>
Richard Chapman 12 years ago
parent
commit
8f823c40d1

+ 1 - 1
common/thorhelper/roxierow.cpp

@@ -628,7 +628,7 @@ protected:
 
     void testSetup()
     {
-        setTotalMemoryLimit(40*HEAP_ALIGNMENT_SIZE, 0, NULL);
+        setTotalMemoryLimit(false, 40*HEAP_ALIGNMENT_SIZE, 0, NULL);
     }
 
     void testCleanup()

+ 7 - 2
ecl/eclagent/eclagent.cpp

@@ -2013,8 +2013,13 @@ void EclAgent::runProcess(IEclProcess *process)
     setHThorRowManager(rowManager.get());
 
     //Get memory limit. Workunit specified value takes precedence over config file
-    int memLimitMB = globals->getPropInt("defaultMemoryLimitMB", DEFAULT_MEM_LIMIT);
+    int memLimitMB = agentTopology->getPropInt("@defaultMemoryLimitMB", DEFAULT_MEM_LIMIT);
+    memLimitMB = globals->getPropInt("defaultMemoryLimitMB", memLimitMB);
     memLimitMB = queryWorkUnit()->getDebugValueInt("hthorMemoryLimit", memLimitMB);
+
+    bool allowHugePages = agentTopology->getPropBool("@heapUseHugePages", false);
+    allowHugePages = globals->getPropBool("heapUseHugePages", allowHugePages);
+
 #ifndef __64BIT__
     if (memLimitMB > 4096)
     {
@@ -2024,7 +2029,7 @@ void EclAgent::runProcess(IEclProcess *process)
     }
 #endif
     memsize_t memLimitBytes = (memsize_t)memLimitMB * 1024 * 1024;
-    roxiemem::setTotalMemoryLimit(memLimitBytes, 0, NULL);
+    roxiemem::setTotalMemoryLimit(allowHugePages, memLimitBytes, 0, NULL);
 
     if (debugContext)
         debugContext->checkBreakpoint(DebugStateReady, NULL, NULL);

+ 8 - 0
initfiles/componentfiles/configxml/eclagent_config.xsd.in

@@ -182,6 +182,14 @@
       </xs:annotation>
     </xs:attribute>
 
+    <xs:attribute name="heapUseHugePages" type="xs:boolean" default="false">
+        <xs:annotation>
+            <xs:appinfo>
+                <tooltip>Use memory from huge pages if they have been configured.</tooltip>
+            </xs:appinfo>
+        </xs:annotation>
+    </xs:attribute>
+
     <xs:attribute name="pluginDirectory" type="absolutePath" use="optional" default="${PLUGINS_PATH}/">
       <xs:annotation>
         <xs:appinfo>

+ 7 - 0
initfiles/componentfiles/configxml/roxie.xsd.in

@@ -747,6 +747,13 @@
         </xs:appinfo>
       </xs:annotation>
     </xs:attribute>
+    <xs:attribute name="heapUseHugePages" type="xs:boolean" default="false">
+      <xs:annotation>
+        <xs:appinfo>
+          <tooltip>Allow roxie to use memory from huge pages if they have been configured.</tooltip>
+        </xs:appinfo>
+      </xs:annotation>
+    </xs:attribute>
     <xs:attribute name="trapTooManyActiveQueries" type="xs:boolean" use="optional" default="true">
       <xs:annotation>
         <xs:appinfo>

+ 7 - 0
initfiles/componentfiles/configxml/thor.xsd.in

@@ -374,6 +374,13 @@
           </xs:appinfo>
         </xs:annotation>
       </xs:attribute>
+      <xs:attribute name="heapUseHugePages" type="xs:boolean" default="false">
+        <xs:annotation>
+          <xs:appinfo>
+            <tooltip>Allow Thor master and slave to use memory from huge pages if they have been configured.</tooltip>
+          </xs:appinfo>
+        </xs:annotation>
+      </xs:attribute>
       <xs:attribute name="pluginsPath" type="relativePath" default="${PLUGINS_PATH}/"/>
       <xs:attribute name="nodeGroup" type="xs:string" use="optional">
         <xs:annotation>

+ 2 - 1
roxie/ccd/ccdmain.cpp

@@ -720,9 +720,10 @@ int STARTQUERY_API start_query(int argc, const char *argv[])
         pingInterval = topology->getPropInt("@pingInterval", 0);
         socketCheckInterval = topology->getPropInt("@socketCheckInterval", 5000);
         memsize_t totalMemoryLimit = (memsize_t) topology->getPropInt64("@totalMemoryLimit", 0);
+        bool allowHugePages = topology->getPropBool("@heapUseHugePages", false);
         if (!totalMemoryLimit)
             totalMemoryLimit = 1024 * 0x100000;  // 1 Gb;
-        roxiemem::setTotalMemoryLimit(totalMemoryLimit, 0, NULL);
+        roxiemem::setTotalMemoryLimit(allowHugePages, totalMemoryLimit, 0, NULL);
 
         traceStartStop = topology->getPropBool("@traceStartStop", false);
         traceServerSideCache = topology->getPropBool("@traceServerSideCache", false);

+ 1 - 1
roxie/ccd/ccdserver.cpp

@@ -25756,7 +25756,7 @@ protected:
 
     void testSetup()
     {
-        roxiemem::setTotalMemoryLimit(100 * 1024 * 1024, 0, NULL);
+        roxiemem::setTotalMemoryLimit(false, 100 * 1024 * 1024, 0, NULL);
     }
 
     void testCleanup()

+ 47 - 14
roxie/roxiemem/roxiemem.cpp

@@ -90,6 +90,7 @@ const unsigned maxLeakReport = 4;
 
 static char *heapBase;
 static char *heapEnd;   // Equal to heapBase + (heapTotalPages * page size)
+static bool heapUseHugePages;
 static unsigned *heapBitmap;
 static unsigned heapBitmapSize;
 static unsigned heapTotalPages; // derived from heapBitmapSize - here for code clarity
@@ -120,7 +121,7 @@ typedef MapBetween<unsigned, unsigned, memsize_t, memsize_t> MapActivityToMemsiz
 
 static CriticalSection heapBitCrit;
 
-static void initializeHeap(unsigned pages, unsigned largeBlockGranularity, ILargeMemCallback * largeBlockCallback)
+static void initializeHeap(bool allowHugePages, unsigned pages, unsigned largeBlockGranularity, ILargeMemCallback * largeBlockCallback)
 {
     if (heapBase) return;
     // CriticalBlock b(heapBitCrit); // unnecessary - must call this exactly once before any allocations anyway!
@@ -145,13 +146,35 @@ static void initializeHeap(unsigned pages, unsigned largeBlockGranularity, ILarg
         }
     }
 #else
-    int ret;
-    if ((ret = posix_memalign((void **) &heapBase, HEAP_ALIGNMENT_SIZE, memsize)) != 0) {
-        DBGLOG("RoxieMemMgr: posix_memalign (alignment=%"I64F"u, size=%"I64F"u) failed - ret=%d", 
-                (unsigned __int64) HEAP_ALIGNMENT_SIZE, (unsigned __int64) memsize, ret);
-        HEAPERROR("RoxieMemMgr: Unable to create heap");
+    heapUseHugePages = false;
+    if (allowHugePages)
+    {
+        heapBase = (char *)mmap(NULL, memsize, (PROT_READ | PROT_WRITE), (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB), 0, 0);
+        if (heapBase != MAP_FAILED)
+        {
+            heapUseHugePages = true;
+            DBGLOG("Using Huge Pages for roxiemem");
+        }
+        else
+        {
+            heapBase = NULL;
+            DBGLOG("Huge Pages requested but unavailable");
+        }
+    }
+
+    if (!heapBase)
+    {
+        int ret;
+        if ((ret = posix_memalign((void **) &heapBase, HEAP_ALIGNMENT_SIZE, memsize)) != 0) {
+            DBGLOG("RoxieMemMgr: posix_memalign (alignment=%"I64F"u, size=%"I64F"u) failed - ret=%d", 
+                    (unsigned __int64) HEAP_ALIGNMENT_SIZE, (unsigned __int64) memsize, ret);
+            HEAPERROR("RoxieMemMgr: Unable to create heap");
+        }
     }
 #endif
+
+    assertex(((memsize_t)heapBase & (HEAP_ALIGNMENT_SIZE-1)) == 0);
+
     heapEnd = heapBase + memsize;
     heapBitmap = new unsigned [heapBitmapSize];
     memset(heapBitmap, 0xff, heapBitmapSize*sizeof(unsigned));
@@ -171,15 +194,22 @@ extern void releaseRoxieHeap()
             DBGLOG("RoxieMemMgr: releasing heap");
         delete [] heapBitmap;
         heapBitmap = NULL;
-        heapBitmapSize = 0;
-        heapTotalPages = 0;
 #ifdef _WIN32
         VirtualFree(heapBase, 0, MEM_RELEASE);
 #else
-        free(heapBase);
+        if (heapUseHugePages)
+        {
+            memsize_t memsize = memsize_t(heapTotalPages) * HEAP_ALIGNMENT_SIZE;
+            munmap(heapBase, memsize);
+            heapUseHugePages = false;
+        }
+        else
+            free(heapBase);
 #endif
         heapBase = NULL;
         heapEnd = NULL;
+        heapBitmapSize = 0;
+        heapTotalPages = 0;
     }
 }
 
@@ -3410,7 +3440,7 @@ extern void setMemoryStatsInterval(unsigned secs)
     lastStatsCycles = get_cycles_now();
 }
 
-extern void setTotalMemoryLimit(memsize_t max, memsize_t largeBlockSize, ILargeMemCallback * largeBlockCallback)
+extern void setTotalMemoryLimit(bool allowHugePages, memsize_t max, memsize_t largeBlockSize, ILargeMemCallback * largeBlockCallback)
 {
     assertex(largeBlockSize == align_pow2(largeBlockSize, HEAP_ALIGNMENT_SIZE));
     unsigned totalMemoryLimit = (unsigned) (max / HEAP_ALIGNMENT_SIZE);
@@ -3419,7 +3449,7 @@ extern void setTotalMemoryLimit(memsize_t max, memsize_t largeBlockSize, ILargeM
         totalMemoryLimit = 1;
     if (memTraceLevel)
         DBGLOG("RoxieMemMgr: Setting memory limit to %"I64F"d bytes (%u pages)", (unsigned __int64) max, totalMemoryLimit);
-    initializeHeap(totalMemoryLimit, largeBlockGranularity, largeBlockCallback);
+    initializeHeap(allowHugePages, totalMemoryLimit, largeBlockGranularity, largeBlockCallback);
 }
 
 extern memsize_t getTotalMemoryLimit()
@@ -3638,7 +3668,7 @@ public:
 protected:
     void testSetup()
     {
-        initializeHeap(300, 0, NULL);
+        initializeHeap(false, 300, 0, NULL);
     }
 
     void testCleanup()
@@ -3743,6 +3773,7 @@ protected:
             _heapTotalPages = heapTotalPages;
             _heapLWM = heapLWM;
             _heapAllocated = heapAllocated;
+            _heapUseHugePages = heapUseHugePages;
         }
         ~HeapPreserver()
         {
@@ -3753,6 +3784,7 @@ protected:
             heapTotalPages = _heapTotalPages;
             heapLWM = _heapLWM;
             heapAllocated = _heapAllocated;
+            heapUseHugePages = _heapUseHugePages;
         }
         char *_heapBase;
         char *_heapEnd;
@@ -3761,6 +3793,7 @@ protected:
         unsigned _heapTotalPages;
         unsigned _heapLWM;
         unsigned _heapAllocated;
+        bool _heapUseHugePages;
     };
     void initBitmap(unsigned size)
     {
@@ -4750,7 +4783,7 @@ public:
 protected:
     void testSetup()
     {
-        setTotalMemoryLimit(memorySize, 0, NULL);
+        setTotalMemoryLimit(false, memorySize, 0, NULL);
     }
 
     void testCleanup()
@@ -4946,7 +4979,7 @@ public:
 protected:
     void testSetup()
     {
-        setTotalMemoryLimit(hugeMemorySize, 0, NULL);
+        setTotalMemoryLimit(false, hugeMemorySize, 0, NULL);
     }
 
     void testCleanup()

+ 1 - 1
roxie/roxiemem/roxiemem.hpp

@@ -454,7 +454,7 @@ interface IDataBufferManager : extends IInterface
 
 extern roxiemem_decl IDataBufferManager *createDataBufferManager(size32_t size);
 extern roxiemem_decl void setMemoryStatsInterval(unsigned secs);
-extern roxiemem_decl void setTotalMemoryLimit(memsize_t max, memsize_t largeBlockSize, ILargeMemCallback * largeBlockCallback);
+extern roxiemem_decl void setTotalMemoryLimit(bool allowHugePages, memsize_t max, memsize_t largeBlockSize, ILargeMemCallback * largeBlockCallback);
 extern roxiemem_decl memsize_t getTotalMemoryLimit();
 extern roxiemem_decl void releaseRoxieHeap();
 extern roxiemem_decl bool memPoolExhausted();

+ 1 - 1
roxie/udplib/uttest.cpp

@@ -753,7 +753,7 @@ int main(int argc, char * argv[] )
             printf("ERROR: my ip does not appear to be in range\n");
             usage();
         }
-        roxiemem::setTotalMemoryLimit(1048576000, 0, NULL);
+        roxiemem::setTotalMemoryLimit(false, 1048576000, 0, NULL);
         testNxN();
         roxiemem::releaseRoxieHeap();
     }

+ 2 - 1
thorlcr/master/thmastermain.cpp

@@ -645,12 +645,13 @@ int main( int argc, char *argv[]  )
             // should prob. error here
         }
         unsigned gmemSizeMaster = globals->getPropInt("@masterMemorySize", gmemSize); // in MB
+        bool gmemAllowHugePages = globals->getPropBool("@heapUseHugePages", false);
 
         // if @masterMemorySize and @globalMemorySize unspecified gmemSize will be default based on h/w
         globals->setPropInt("@masterMemorySize", gmemSizeMaster);
 
         PROGLOG("Global memory size = %d MB", gmemSizeMaster);
-        roxiemem::setTotalMemoryLimit(((memsize_t)gmemSizeMaster) * 0x100000, 0, NULL);
+        roxiemem::setTotalMemoryLimit(gmemAllowHugePages, ((memsize_t)gmemSizeMaster) * 0x100000, 0, NULL);
 
         const char * overrideBaseDirectory = globals->queryProp("@thorDataDirectory");
         const char * overrideReplicateDirectory = globals->queryProp("@thorReplicateDirectory");

+ 2 - 1
thorlcr/slave/slavmain.cpp

@@ -660,11 +660,12 @@ void slaveMain()
     if (hdwInfo.totalMemory < masterMemMB)
         WARNLOG("Slave has less memory than master node");
     unsigned gmemSize = globals->getPropInt("@globalMemorySize");
+    bool gmemAllowHugePages = globals->getPropBool("@heapUseHugePages", false);
     if (gmemSize >= hdwInfo.totalMemory)
     {
         // should prob. error here
     }
-    roxiemem::setTotalMemoryLimit(((memsize_t)gmemSize) * 0x100000, 0, NULL);
+    roxiemem::setTotalMemoryLimit(gmemAllowHugePages, ((memsize_t)gmemSize) * 0x100000, 0, NULL);
 
     CJobListener jobListener;
     CThorResourceSlave slaveResource;