Hey folks,

We (Red Hat) get the occasional complaint, particularly from jboss folks, that setting up large page access for java app servers is too difficult. As a result, I was asked to throw together a scriptlet to make life easier for such people.

The attached python script has been used successfully on Red Hat Enterprise Linux 5, Fedora 11 and Fedora 12, and is likely to work for other distros (though possibly with some minor tweaking required). I believe we're intending to include it in an upcoming RHEL release, and if at all possible and appropriate, I'd appreciate seeing it included in the official libhugetlbfs distribution for the benefit of others (and ultimately for RHEL too, so we don't have to carry anything out-of-tree), even if it were just under a not-installed-by-default contrib/ directory.

Comments welcomed... Even if they are "wow, this sucks horribly, please go away" (but hopefully they aren't). :)

--
Jarod Wilson
ja...@redhat.com
#!/usr/bin/python

#
# Tool to set up Linux large page support with minimal effort
#
# by Jarod Wilson <ja...@redhat.com>
# (c) Red Hat, Inc., 2009
#
import os

debug = False

# config files we need access to
sysctlConf = "/etc/sysctl.conf"
if not os.access(sysctlConf, os.W_OK):
    print "Cannot access %s" % sysctlConf
limitsConf = "/etc/security/limits.d/hugepages.conf"
if not os.access(limitsConf, os.W_OK):
    print "Cannot access %s" % limitsConf


# Figure out what we've got in the way of memory
memInfo = open("/proc/meminfo").readlines()
memTotal = 0
hugePages = 0
hugePageSize = 0

for line in memInfo:
    if line.startswith("MemTotal:"):
        memTotal = int(line.split()[1])
        break

for line in memInfo:
    if line.startswith("HugePages_Total:"):
        hugePages = int(line.split()[1])
        break

for line in memInfo:
    if line.startswith("Hugepagesize:"):
        hugePageSize = int(line.split()[1])
        break


# Get initial sysctl settings
shmmax = 0
nr_hugepages = 0
hugeGID = 0

sysctlCur = os.popen("/sbin/sysctl -a").readlines()

for line in sysctlCur:
    if line.startswith("kernel.shmmax = "):
        shmmax = int(line.split()[2])
        break

for line in sysctlCur:
    if line.startswith("vm.nr_hugepages = "):
        nr_hugepages = int(line.split()[2])
        break

for line in sysctlCur:
    if line.startswith("vm.hugetlb_shm_group = "):
        hugeGID = int(line.split()[2])
        break


# translate group into textual version
hugeGIDName = "null"
groupNames = os.popen("/usr/bin/getent group").readlines()
for line in groupNames:
    curGID = int(line.split(":")[2])
    if curGID == hugeGID:
        hugeGIDName = line.split(":")[0]
        break


# dump system config as we see it before we start tweaking it
print "Current configuration:"
print " * Total System Memory......: %6d MB" % (memTotal / 1024)
print " * Shared Mem Max Mapping...: %6d MB" % (shmmax / (1024 * 1024))
print " * System Huge Page Size....: %6d MB" % (hugePageSize / 1024)
print " * Number of Huge Pages.....: %6d"    % hugePages
print " * Total size of Huge Pages.: %6d MB" % (hugePages * hugePageSize / 1024)
print " * Remaining System Memory..: %6d MB" % ((memTotal / 1024) - (hugePages * hugePageSize / 1024))
print " * Huge Page User Group.....:  %s (%d)" % (hugeGIDName, hugeGID)
print


# determine some sanity safeguards
halfOfMem = memTotal / 2
allMemLess2G = memTotal - 2048000

if halfOfMem >= allMemLess2G:
    maxHugePageReqKB = halfOfMem
else:
    maxHugePageReqKB = allMemLess2G

maxHugePageReqMB = maxHugePageReqKB / 1024
maxHugePageReq = maxHugePageReqKB / hugePageSize


# ask how memory they want to allocate for huge pages
userIn = None
while not userIn:
    try:
        userIn = raw_input("How much memory would you like to allocate for huge pages? "
                           "(input in MB, unless postfixed with GB): ")
	if userIn[-2:] == "GB":
            userHugePageReqMB = int(userIn[0:-2]) * 1024
	elif userIn[-1:] == "G":
            userHugePageReqMB = int(userIn[0:-1]) * 1024
	elif userIn[-2:] == "MB":
            userHugePageReqMB = int(userIn[0:-2])
	elif userIn[-1:] == "MB":
            userHugePageReqMB = int(userIn[0:-1])
        else:
            userHugePageReqMB = int(userIn)
        if userHugePageReqMB > maxHugePageReqMB:
            userIn = None
            print "Sorry, the most I'll let you allocate is %d MB, try again!" % maxHugePageReqMB
        else:
            break
    except ValueError:
        userIn = None
        print "Input must be an integer, please try again!"
userHugePageReqKB = userHugePageReqMB * 1024
userHugePagesReq = userHugePageReqKB / hugePageSize
print "Okay, we'll try to allocate %d MB for huge pages..." % userHugePageReqMB
print


# some basic user input validation
badchars = list(' \\\'":;~`!$^&*(){}[]?/><,')
inputIsValid = False
foundbad = False
# ask for the name of the group allowed access to huge pages
while inputIsValid == False:
    userGroupReq = raw_input("What group should have access to the huge pages? "
                             "(The group will be created, if need be): ")
    for char in badchars:
        if char in userGroupReq:
            foundbad = True
            print "Illegal characters in group name, please try again!"
            break
    if foundbad == False:
        inputIsValid = True
print "Okay, we'll give group %s access to the huge pages" % userGroupReq


# see if group already exists, use it if it does, if not, create it
userGIDReq = -1
for line in groupNames:
    curGroupName = line.split(":")[0]
    if curGroupName == userGroupReq:
        userGIDReq = int(line.split(":")[2])
        break

if userGIDReq > -1:
    print "Group %s (gid %d) already exists, we'll use it" % (userGroupReq, userGIDReq)
else:
    if debug == False:
    	os.popen("/usr/sbin/groupadd %s" % userGroupReq)
    else:
        print "/usr/sbin/groupadd %s" % userGroupReq
    groupNames = os.popen("/usr/bin/getent group %s" % userGroupReq).readlines()
    for line in groupNames:
        curGroupName = line.split(":")[0]
        if curGroupName == userGroupReq:
            userGIDReq = int(line.split(":")[2])
            break
    print "Created group %s (gid %d) for huge page use" % (userGroupReq, userGIDReq)
print


# basic user input validation, take 2
# space is valid in this case, wasn't in the prior incarnation
badchars = list('\\\'":;~`!$^&*(){}[]?/><,')
inputIsValid = False
# ask for user(s) that should be in the huge page access group
while inputIsValid == False:
    userUsersReq = raw_input("What user(s) should have access to the huge pages (space-delimited list, users created as needed)? ")
    for char in badchars:
        if char in userUsersReq:
            foundbad = True
            print "Illegal characters in user name(s) or invalid list format, please try again!"
            break
    if foundbad == False:
        inputIsValid = True
# see if user(s) already exist(s)
curUserList = os.popen("/usr/bin/getent passwd").readlines()
hugePageUserList = userUsersReq.split()
for hugeUser in hugePageUserList:
    userExists = False
    for line in curUserList:
        curUser = line.split(":")[0]
        if curUser == hugeUser:
            print "Adding user %s to huge page group" % hugeUser
            userExists = True
            if debug == False:
                os.popen("/usr/sbin/usermod -a -G %s %s" % (userGroupReq, hugeUser))
            else:
                print "/usr/sbin/usermod -a -G %s %s" % (userGroupReq, hugeUser)
        if userExists == True:
            break
    if userExists == False:
        print "Creating user %s with membership in huge page group" % hugeUser
        if debug == False:
            os.popen("/usr/sbin/useradd %s -G %s" % (hugeUser, userGroupReq))
        else:
            print "/usr/sbin/useradd %s -G %s" % (hugeUser, userGroupReq)
print


# set sysctl values for the current running environment
if debug == False:
    os.popen("/sbin/sysctl -w kernel.shmmax=%d" % (memTotal * 1024))
    os.popen("/sbin/sysctl -w vm.nr_hugepages=%d" % userHugePagesReq)
    os.popen("/sbin/sysctl -w vm.hugetlb_shm_group=%d" % userGIDReq)
else:
    print "/sbin/sysctl -w kernel.shmmax=%d" % (memTotal * 1024)
    print "/sbin/sysctl -w vm.nr_hugepages=%d" % userHugePagesReq
    print "/sbin/sysctl -w vm.hugetlb_shm_group=%d" % userGIDReq
    print


# write out sysctl config changes to persist across reboot
if debug == False:
    sysctlConfLines = "# sysctl configuration\n"
    if os.access(sysctlConf, os.W_OK):
        try:
            sysctlConfLines = open(sysctlConf).readlines()
            os.rename(sysctlConf, sysctlConf + ".backup")
            print("Saved original %s as %s.backup" % (sysctlConf, sysctlConf))
        except:
            pass

    fd = open(sysctlConf, "w")
    for line in sysctlConfLines:
        if line.startswith("kernel.shmmax"):
            continue
        elif line.startswith("vm.nr_hugepages"):
            continue
        elif line.startswith("vm.hugetlb_shm_group"):
            continue
        else:
            fd.write(line);

    fd.write("kernel.shmmax = %d\n" % (memTotal * 1024))
    fd.write("vm.nr_hugepages = %d\n" % userHugePagesReq)
    fd.write("vm.hugetlb_shm_group = %d\n" % userGIDReq)
    fd.close()

else:
    print "Add to %s:" % sysctlConf
    print "kernel.shmmax = %d" % (memTotal * 1024)
    print "vm.nr_hugepages = %d" % userHugePagesReq
    print "vm.hugetlb_shm_group = %d" % userGIDReq
    print


# write out limits.conf changes to persist across reboot
if debug == False:
    limitsConfLines = "# Huge page access configuration\n"
    if os.access(limitsConf, os.W_OK):
        try:
            limitsConfLines = open(limitsConf).readlines()
            os.rename(limitsConf, limitsConf + ".backup")
            print("Saved original %s as %s.backup" % (limitsConf, limitsConf))
        except:
            pass

    fd = open(limitsConf, "w")
    for line in limitsConfLines:
        cfgExist = False
        for hugeUser in hugePageUserList:
            if line.split()[0] == hugeUser:
                cfgExist = True
        if cfgExist == True:
            continue
        else:
            fd.write(line)

    for hugeUser in hugePageUserList:
        fd.write("%s		soft	memlock		%d\n" % (hugeUser, userHugePageReqKB))
        fd.write("%s		hard	memlock		%d\n" % (hugeUser, userHugePageReqKB))
    fd.close()

else:
    print "Add to %s:" % limitsConf
    for hugeUser in hugePageUserList:
        print "%s		soft	memlock		%d" % (hugeUser, userHugePageReqKB)
        print "%s		hard	memlock		%d" % (hugeUser, userHugePageReqKB)


# dump the final configuration of things now that we're done tweaking
print
print "Final configuration:"
print " * Total System Memory......: %6d MB" % (memTotal / 1024)
print " * Shared Mem Max Mapping...: %6d MB" % (memTotal / 1024)
print " * System Huge Page Size....: %6d MB" % (hugePageSize / 1024)
print " * Available Huge Pages.....: %6d"    % userHugePagesReq
print " * Total size of Huge Pages.: %6d MB" % (userHugePagesReq * hugePageSize / 1024)
print " * Remaining System Memory..: %6d MB" % ((memTotal / 1024) - userHugePageReqMB)
print " * Huge Page User Group.....:  %s (%d)" % (userGroupReq, userGIDReq)
print


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Libhugetlbfs-devel mailing list
Libhugetlbfs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to