Blame huge_page_setup_helper.py

Packit 2d622a
#!/usr/bin/python
Packit 2d622a
Packit 2d622a
#
Packit 2d622a
# Tool to set up Linux large page support with minimal effort
Packit 2d622a
#
Packit 2d622a
# by Jarod Wilson <jarod@redhat.com>
Packit 2d622a
# (c) Red Hat, Inc., 2009
Packit 2d622a
#
Packit 2d622a
# Requires hugeadm from libhugetlbfs 2.7 (or backported support)
Packit 2d622a
#
Packit 2d622a
import os
Packit 2d622a
Packit 2d622a
debug = False
Packit 2d622a
Packit 2d622a
# must be executed under the root to operate
Packit 2d622a
if os.geteuid() != 0:
Packit 2d622a
    print "You must be root to setup hugepages!"
Packit 2d622a
    os._exit(1)
Packit 2d622a
Packit 2d622a
# config files we need access to
Packit 2d622a
sysctlConf = "/etc/sysctl.conf"
Packit 2d622a
if not os.access(sysctlConf, os.W_OK):
Packit 2d622a
    print "Cannot access %s" % sysctlConf
Packit 2d622a
    if debug == False:
Packit 2d622a
        os._exit(1)
Packit 2d622a
Packit 2d622a
# This file will be created if it doesn't exist
Packit 2d622a
limitsConf = "/etc/security/limits.d/hugepages.conf"
Packit 2d622a
Packit 2d622a
Packit 2d622a
# Figure out what we've got in the way of memory
Packit 2d622a
memTotal = 0
Packit 2d622a
hugePageSize = 0
Packit 2d622a
hugePages = 0
Packit 2d622a
Packit 2d622a
hugeadmexplain = os.popen("/usr/bin/hugeadm --explain 2>/dev/null").readlines()
Packit 2d622a
Packit 2d622a
for line in hugeadmexplain:
Packit 2d622a
    if line.startswith("Total System Memory:"):
Packit 2d622a
        memTotal = int(line.split()[3])
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
if memTotal == 0:
Packit 2d622a
    print "Your version of libhugetlbfs' hugeadm utility is too old!"
Packit 2d622a
    os._exit(1)
Packit 2d622a
Packit 2d622a
Packit 2d622a
# Pick the default huge page size and see how many pages are allocated
Packit 2d622a
poolList = os.popen("/usr/bin/hugeadm --pool-list").readlines()
Packit 2d622a
for line in poolList:
Packit 2d622a
    if '*' in line:
Packit 2d622a
        hugePageSize = int(line.split()[0])
Packit 2d622a
        hugePages = int(line.split()[2])
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
if hugePageSize == 0:
Packit 2d622a
    print "Aborting, cannot determine system huge page size!"
Packit 2d622a
    os._exit(1)
Packit 2d622a
Packit 2d622a
# Get initial sysctl settings
Packit 2d622a
shmmax = 0
Packit 2d622a
hugeGID = 0
Packit 2d622a
Packit 2d622a
for line in hugeadmexplain:
Packit 2d622a
    if line.startswith("A /proc/sys/kernel/shmmax value of"):
Packit 2d622a
        shmmax = int(line.split()[4])
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
for line in hugeadmexplain:
Packit 2d622a
    if line.strip().startswith("vm.hugetlb_shm_group = "):
Packit 2d622a
        hugeGID = int(line.split()[2])
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
Packit 2d622a
# translate group into textual version
Packit 2d622a
hugeGIDName = "null"
Packit 2d622a
groupNames = os.popen("/usr/bin/getent group").readlines()
Packit 2d622a
for line in groupNames:
Packit 2d622a
    curGID = int(line.split(":")[2])
Packit 2d622a
    if curGID == hugeGID:
Packit 2d622a
        hugeGIDName = line.split(":")[0]
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
Packit 2d622a
# dump system config as we see it before we start tweaking it
Packit 2d622a
print "Current configuration:"
Packit 2d622a
print " * Total System Memory......: %6d MB" % memTotal
Packit 2d622a
print " * Shared Mem Max Mapping...: %6d MB" % (shmmax / (1024 * 1024))
Packit 2d622a
print " * System Huge Page Size....: %6d MB" % (hugePageSize / (1024 * 1024))
Packit 2d622a
print " * Number of Huge Pages.....: %6d"    % hugePages
Packit 2d622a
print " * Total size of Huge Pages.: %6d MB" % (hugePages * hugePageSize / (1024 * 1024))
Packit 2d622a
print " * Remaining System Memory..: %6d MB" % (memTotal - (hugePages * hugePageSize / (1024 * 1024)))
Packit 2d622a
print " * Huge Page User Group.....:  %s (%d)" % (hugeGIDName, hugeGID)
Packit 2d622a
print
Packit 2d622a
Packit 2d622a
Packit 2d622a
# ask how memory they want to allocate for huge pages
Packit 2d622a
userIn = None
Packit 2d622a
while not userIn:
Packit 2d622a
    try:
Packit 2d622a
        userIn = raw_input("How much memory would you like to allocate for huge pages? "
Packit 2d622a
                           "(input in MB, unless postfixed with GB): ")
Packit 2d622a
        if userIn[-2:] == "GB":
Packit 2d622a
            userHugePageReqMB = int(userIn[0:-2]) * 1024
Packit 2d622a
        elif userIn[-1:] == "G":
Packit 2d622a
            userHugePageReqMB = int(userIn[0:-1]) * 1024
Packit 2d622a
        elif userIn[-2:] == "MB":
Packit 2d622a
            userHugePageReqMB = int(userIn[0:-2])
Packit 2d622a
        elif userIn[-1:] == "M":
Packit 2d622a
            userHugePageReqMB = int(userIn[0:-1])
Packit 2d622a
        else:
Packit 2d622a
            userHugePageReqMB = int(userIn)
Packit 2d622a
        # As a sanity safeguard, require at least 128M not be allocated to huge pages
Packit 2d622a
        if userHugePageReqMB > (memTotal - 128):
Packit 2d622a
            userIn = None
Packit 2d622a
            print "Refusing to allocate %d, you must leave at least 128MB for the system" % userHugePageReqMB
Packit 2d622a
        elif userHugePageReqMB < (hugePageSize / (1024 * 1024)):
Packit 2d622a
            userIn = None
Packit 2d622a
            print "Sorry, allocation must be at least a page's worth!"
Packit 2d622a
        else:
Packit 2d622a
            break
Packit 2d622a
    except ValueError:
Packit 2d622a
        userIn = None
Packit 2d622a
        print "Input must be an integer, please try again!"
Packit 2d622a
userHugePageReqKB = userHugePageReqMB * 1024
Packit 2d622a
userHugePagesReq = userHugePageReqKB / (hugePageSize / 1024)
Packit 2d622a
print "Okay, we'll try to allocate %d MB for huge pages..." % userHugePageReqMB
Packit 2d622a
print
Packit 2d622a
Packit 2d622a
Packit 2d622a
# some basic user input validation
Packit 2d622a
badchars = list(' \\\'":;~`!$^&*(){}[]?/><,')
Packit 2d622a
inputIsValid = False
Packit 2d622a
# ask for the name of the group allowed access to huge pages
Packit 2d622a
while inputIsValid == False:
Packit 2d622a
    foundbad = False
Packit 2d622a
    userGroupReq = raw_input("What group should have access to the huge pages?"
Packit 2d622a
                             "(The group will be created, if need be) [hugepages]: ")
Packit 2d622a
    if userGroupReq is '':
Packit 2d622a
        userGroupReq = 'hugepages'
Packit 2d622a
    if userGroupReq[0].isdigit() or userGroupReq[0] == "-":
Packit 2d622a
        foundbad = True
Packit 2d622a
        print "Group names cannot start with a number or dash, please try again!"
Packit 2d622a
    for char in badchars:
Packit 2d622a
        if char in userGroupReq:
Packit 2d622a
            foundbad = True
Packit 2d622a
            print "Illegal characters in group name, please try again!"
Packit 2d622a
            break
Packit 2d622a
    if len(userGroupReq) > 16:
Packit 2d622a
        foundbad = True
Packit 2d622a
        print "Group names can't be more than 16 characaters, please try again!"
Packit 2d622a
    if foundbad == False:
Packit 2d622a
        inputIsValid = True
Packit 2d622a
print "Okay, we'll give group %s access to the huge pages" % userGroupReq
Packit 2d622a
Packit 2d622a
Packit 2d622a
# see if group already exists, use it if it does, if not, create it
Packit 2d622a
userGIDReq = -1
Packit 2d622a
for line in groupNames:
Packit 2d622a
    curGroupName = line.split(":")[0]
Packit 2d622a
    if curGroupName == userGroupReq:
Packit 2d622a
        userGIDReq = int(line.split(":")[2])
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
if userGIDReq > -1:
Packit 2d622a
    print "Group %s (gid %d) already exists, we'll use it" % (userGroupReq, userGIDReq)
Packit 2d622a
else:
Packit 2d622a
    if debug == False:
Packit 2d622a
        os.popen("/usr/sbin/groupadd %s" % userGroupReq)
Packit 2d622a
    else:
Packit 2d622a
        print "/usr/sbin/groupadd %s" % userGroupReq
Packit 2d622a
    groupNames = os.popen("/usr/bin/getent group %s" % userGroupReq).readlines()
Packit 2d622a
    for line in groupNames:
Packit 2d622a
        curGroupName = line.split(":")[0]
Packit 2d622a
        if curGroupName == userGroupReq:
Packit 2d622a
            userGIDReq = int(line.split(":")[2])
Packit 2d622a
            break
Packit 2d622a
    print "Created group %s (gid %d) for huge page use" % (userGroupReq, userGIDReq)
Packit 2d622a
print
Packit 2d622a
Packit 2d622a
Packit 2d622a
# basic user input validation, take 2
Packit 2d622a
# space is valid in this case, wasn't in the prior incarnation
Packit 2d622a
badchars = list('\\\'":;~`!$^&*(){}[]?/><,')
Packit 2d622a
inputIsValid = False
Packit 2d622a
# ask for user(s) that should be in the huge page access group
Packit 2d622a
while inputIsValid == False:
Packit 2d622a
    foundbad = False
Packit 2d622a
    userUsersReq = raw_input("What user(s) should have access to the huge pages (space-delimited list, users created as needed)? ")
Packit 2d622a
    for char in badchars:
Packit 2d622a
        if char in userUsersReq:
Packit 2d622a
            foundbad = True
Packit 2d622a
            print "Illegal characters in user name(s) or invalid list format, please try again!"
Packit 2d622a
            break
Packit 2d622a
    for n in userUsersReq.split():
Packit 2d622a
        if len(n) > 32:
Packit 2d622a
            foundbad = True
Packit 2d622a
            print "User names can't be more than 32 characaters, please try again!"
Packit 2d622a
            break
Packit 2d622a
        if n[0] == "-":
Packit 2d622a
            foundbad = True
Packit 2d622a
            print "User names cannot start with a dash, please try again!"
Packit 2d622a
            break
Packit 2d622a
    if foundbad == False:
Packit 2d622a
        inputIsValid = True
Packit 2d622a
# see if user(s) already exist(s)
Packit 2d622a
curUserList = os.popen("/usr/bin/getent passwd").readlines()
Packit 2d622a
hugePageUserList = userUsersReq.split()
Packit 2d622a
for hugeUser in hugePageUserList:
Packit 2d622a
    userExists = False
Packit 2d622a
    for line in curUserList:
Packit 2d622a
        curUser = line.split(":")[0]
Packit 2d622a
        if curUser == hugeUser:
Packit 2d622a
            print "Adding user %s to huge page group" % hugeUser
Packit 2d622a
            userExists = True
Packit 2d622a
            if debug == False:
Packit 2d622a
                os.popen("/usr/sbin/usermod -a -G %s %s" % (userGroupReq, hugeUser))
Packit 2d622a
            else:
Packit 2d622a
                print "/usr/sbin/usermod -a -G %s %s" % (userGroupReq, hugeUser)
Packit 2d622a
        if userExists == True:
Packit 2d622a
            break
Packit 2d622a
    if userExists == False:
Packit 2d622a
        print "Creating user %s with membership in huge page group" % hugeUser
Packit 2d622a
        if debug == False:
Packit 2d622a
            if hugeUser == userGroupReq:
Packit 2d622a
                os.popen("/usr/sbin/useradd %s -g %s" % (hugeUser, userGroupReq))
Packit 2d622a
            else:
Packit 2d622a
                os.popen("/usr/sbin/useradd %s -G %s" % (hugeUser, userGroupReq))
Packit 2d622a
        else:
Packit 2d622a
            print "/usr/sbin/useradd %s -G %s" % (hugeUser, userGroupReq)
Packit 2d622a
print
Packit 2d622a
Packit 2d622a
Packit 2d622a
# set values for the current running environment
Packit 2d622a
if debug == False:
Packit 2d622a
    os.popen("/usr/bin/hugeadm --pool-pages-min DEFAULT:%sM" % userHugePageReqMB)
Packit 2d622a
    os.popen("/usr/bin/hugeadm --pool-pages-max DEFAULT:%sM" % userHugePageReqMB)
Packit 2d622a
    os.popen("/usr/bin/hugeadm --set-shm-group %d" % userGIDReq)
Packit 2d622a
    os.popen("/usr/bin/hugeadm --set-recommended-shmmax")
Packit 2d622a
else:
Packit 2d622a
    print "/usr/bin/hugeadm --pool-pages-min DEFAULT:%sM" % userHugePageReqMB
Packit 2d622a
    print "/usr/bin/hugeadm --pool-pages-max DEFAULT:%sM" % userHugePageReqMB
Packit 2d622a
    print "/usr/bin/hugeadm --set-shm-group %d" % userGIDReq
Packit 2d622a
    print "/usr/bin/hugeadm --set-recommended-shmmax"
Packit 2d622a
    print
Packit 2d622a
Packit 2d622a
# figure out what that shmmax value we just set was
Packit 2d622a
hugeadmexplain = os.popen("/usr/bin/hugeadm --explain 2>/dev/null").readlines()
Packit 2d622a
for line in hugeadmexplain:
Packit 2d622a
    if line.strip().startswith("kernel.shmmax = "):
Packit 2d622a
        shmmax = int(line.split()[2])
Packit 2d622a
        break
Packit 2d622a
Packit 2d622a
# write out sysctl config changes to persist across reboot
Packit 2d622a
if debug == False:
Packit 2d622a
    sysctlConfLines = "# sysctl configuration\n"
Packit 2d622a
    if os.access(sysctlConf, os.W_OK):
Packit 2d622a
        try:
Packit 2d622a
            sysctlConfLines = open(sysctlConf).readlines()
Packit 2d622a
            os.rename(sysctlConf, sysctlConf + ".backup")
Packit 2d622a
            print("Saved original %s as %s.backup" % (sysctlConf, sysctlConf))
Packit 2d622a
        except:
Packit 2d622a
            pass
Packit 2d622a
Packit 2d622a
    fd = open(sysctlConf, "w")
Packit 2d622a
    for line in sysctlConfLines:
Packit 2d622a
        if line.startswith("kernel.shmmax"):
Packit 2d622a
            continue
Packit 2d622a
        elif line.startswith("vm.nr_hugepages"):
Packit 2d622a
            continue
Packit 2d622a
        elif line.startswith("vm.hugetlb_shm_group"):
Packit 2d622a
            continue
Packit 2d622a
        else:
Packit 2d622a
            fd.write(line);
Packit 2d622a
Packit 2d622a
    fd.write("kernel.shmmax = %d\n" % shmmax)
Packit 2d622a
    fd.write("vm.nr_hugepages = %d\n" % userHugePagesReq)
Packit 2d622a
    fd.write("vm.hugetlb_shm_group = %d\n" % userGIDReq)
Packit 2d622a
    fd.close()
Packit 2d622a
Packit 2d622a
else:
Packit 2d622a
    print "Add to %s:" % sysctlConf
Packit 2d622a
    print "kernel.shmmax = %d" % shmmax
Packit 2d622a
    print "vm.nr_hugepages = %d" % userHugePagesReq
Packit 2d622a
    print "vm.hugetlb_shm_group = %d" % userGIDReq
Packit 2d622a
    print
Packit 2d622a
Packit 2d622a
Packit 2d622a
# write out limits.conf changes to persist across reboot
Packit 2d622a
if debug == False:
Packit 2d622a
    limitsConfLines = "# Huge page access configuration\n"
Packit 2d622a
    if os.access(limitsConf, os.W_OK):
Packit 2d622a
        try:
Packit 2d622a
            limitsConfLines = open(limitsConf).readlines()
Packit 2d622a
            os.rename(limitsConf, limitsConf + ".backup")
Packit 2d622a
            print("Saved original %s as %s.backup" % (limitsConf, limitsConf))
Packit 2d622a
        except:
Packit 2d622a
            pass
Packit 2d622a
Packit 2d622a
    fd = open(limitsConf, "w")
Packit 2d622a
    for line in limitsConfLines:
Packit 2d622a
        cfgExist = False
Packit 2d622a
        for hugeUser in hugePageUserList:
Packit 2d622a
            try:
Packit 2d622a
                if line.split()[0] == hugeUser:
Packit 2d622a
                    cfgExist = True
Packit 2d622a
            except IndexError:
Packit 2d622a
                # hit either white or comment line, it is safe not to take
Packit 2d622a
                # any action and continue.
Packit 2d622a
                pass
Packit 2d622a
        if cfgExist == True:
Packit 2d622a
            continue
Packit 2d622a
        else:
Packit 2d622a
            fd.write(line)
Packit 2d622a
Packit 2d622a
    for hugeUser in hugePageUserList:
Packit 2d622a
        fd.write("%s		soft	memlock		%d\n" % (hugeUser, userHugePageReqKB))
Packit 2d622a
        fd.write("%s		hard	memlock		%d\n" % (hugeUser, userHugePageReqKB))
Packit 2d622a
    fd.close()
Packit 2d622a
Packit 2d622a
else:
Packit 2d622a
    print "Add to %s:" % limitsConf
Packit 2d622a
    for hugeUser in hugePageUserList:
Packit 2d622a
        print "%s		soft	memlock		%d" % (hugeUser, userHugePageReqKB)
Packit 2d622a
        print "%s		hard	memlock		%d" % (hugeUser, userHugePageReqKB)
Packit 2d622a
Packit 2d622a
Packit 2d622a
# dump the final configuration of things now that we're done tweaking
Packit 2d622a
print
Packit 2d622a
print "Final configuration:"
Packit 2d622a
print " * Total System Memory......: %6d MB" % memTotal
Packit 2d622a
if debug == False:
Packit 2d622a
    print " * Shared Mem Max Mapping...: %6d MB" % (shmmax / (1024 * 1024))
Packit 2d622a
else:
Packit 2d622a
    # This should be what we *would* have set it to, had we actually run hugeadm --set-recommended-shmmax
Packit 2d622a
    print " * Shared Mem Max Mapping...: %6d MB" % (userHugePagesReq * hugePageSize / (1024 * 1024))
Packit 2d622a
print " * System Huge Page Size....: %6d MB" % (hugePageSize / (1024 * 1024))
Packit 2d622a
print " * Available Huge Pages.....: %6d"    % userHugePagesReq
Packit 2d622a
print " * Total size of Huge Pages.: %6d MB" % (userHugePagesReq * hugePageSize / (1024 * 1024))
Packit 2d622a
print " * Remaining System Memory..: %6d MB" % (memTotal - userHugePageReqMB)
Packit 2d622a
print " * Huge Page User Group.....:  %s (%d)" % (userGroupReq, userGIDReq)
Packit 2d622a
print
Packit 2d622a