Hugepages: on the fly allocation.
[vswitchperf.git] / tools / hugepages.py
1 # Copyright 2015-2016 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """Automation of hugepages management
16 """
17
18 import os
19 import re
20 import subprocess
21 import logging
22 import locale
23 import math
24
25 from tools import tasks
26 from conf import settings
27
28 _LOGGER = logging.getLogger(__name__)
29
30 #
31 # hugepage management
32 #
33
34 def get_hugepage_size():
35     """Return the size of the configured hugepages
36     """
37     hugepage_size_re = re.compile(r'^Hugepagesize:\s+(?P<size_hp>\d+)\s+kB',
38                                   re.IGNORECASE)
39     with open('/proc/meminfo', 'r') as fh:
40         data = fh.readlines()
41         for line in data:
42             match = hugepage_size_re.search(line)
43             if match:
44                 _LOGGER.info('Hugepages size: %s', match.group('size_hp'))
45                 return int(match.group('size_hp'))
46         else:
47             _LOGGER.error('Could not parse for hugepage size')
48             return 0
49
50
51
52 def allocate_hugepages():
53     """Allocate hugepages on the fly
54     """
55     hp_size = get_hugepage_size()
56
57     if hp_size > 0:
58         nr_hp = int(math.ceil(settings.getValue('HUGEPAGE_RAM_ALLOCATION')/hp_size))
59         _LOGGER.info('Will allocate %s hugepages.', nr_hp)
60
61         nr_hugepages = 'vm.nr_hugepages=' + str(nr_hp)
62         try:
63             tasks.run_task(['sudo', 'sysctl', nr_hugepages],
64                            _LOGGER, 'Trying to allocate hugepages..', True)
65         except subprocess.CalledProcessError:
66             _LOGGER.error('Unable to allocate hugepages.')
67             return False
68         return True
69
70     else:
71         _LOGGER.error('Division by 0 will be supported in next release')
72         return False
73
74
75 def is_hugepage_available():
76     """Check if hugepages are available on the system.
77     """
78     hugepage_re = re.compile(r'^HugePages_Free:\s+(?P<num_hp>\d+)$')
79
80     # read in meminfo
81     with open('/proc/meminfo') as mem_file:
82         mem_info = mem_file.readlines()
83
84     # first check if module is loaded
85     for line in mem_info:
86         result = hugepage_re.match(line)
87         if not result:
88             continue
89
90         num_huge = result.group('num_hp')
91         if num_huge == '0':
92             _LOGGER.info('No free hugepages.')
93             if not allocate_hugepages():
94                 return False
95         else:
96             _LOGGER.info('Found \'%s\' free hugepage(s).', num_huge)
97         return True
98
99     return False
100
101
102 def is_hugepage_mounted():
103     """Check if hugepages are mounted.
104     """
105     output = subprocess.check_output(['mount'], shell=True)
106     my_encoding = locale.getdefaultlocale()[1]
107     for line in output.decode(my_encoding).split('\n'):
108         if 'hugetlbfs' in line:
109             return True
110
111     return False
112
113
114 def mount_hugepages():
115     """Ensure hugepages are mounted.
116     """
117     if not is_hugepage_available():
118         return
119
120     if is_hugepage_mounted():
121         return
122
123     if not os.path.exists(settings.getValue('HUGEPAGE_DIR')):
124         tasks.run_task(['sudo', 'mkdir', settings.getValue('HUGEPAGE_DIR')], _LOGGER,
125                        'Creating directory ' + settings.getValue('HUGEPAGE_DIR'), True)
126     try:
127         tasks.run_task(['sudo', 'mount', '-t', 'hugetlbfs', 'nodev',
128                         settings.getValue('HUGEPAGE_DIR')],
129                        _LOGGER, 'Mounting hugepages...', True)
130     except subprocess.CalledProcessError:
131         _LOGGER.error('Unable to mount hugepages.')
132
133
134 def umount_hugepages():
135     """Ensure hugepages are unmounted.
136     """
137     if not is_hugepage_mounted():
138         return
139
140     try:
141         tasks.run_task(['sudo', 'umount', settings.getValue('HUGEPAGE_DIR')],
142                        _LOGGER, 'Unmounting hugepages...', True)
143     except subprocess.CalledProcessError:
144         _LOGGER.error('Unable to umount hugepages.')
145
146