xref: /dpdk/usertools/dpdk-hugepages.py (revision f63ca249b8a13171000d348c31d14bda1b3ac0f0)
16e1b58faSStephen Hemminger#! /usr/bin/env python3
26e1b58faSStephen Hemminger# SPDX-License-Identifier: BSD-3-Clause
36e1b58faSStephen Hemminger# Copyright (c) 2020 Microsoft Corporation
4*f63ca249SAnatoly Burakov
56e1b58faSStephen Hemminger"""Script to query and setup huge pages for DPDK applications."""
66e1b58faSStephen Hemminger
76e1b58faSStephen Hemmingerimport argparse
86e1b58faSStephen Hemmingerimport os
96e1b58faSStephen Hemmingerimport re
10*f63ca249SAnatoly Burakovimport subprocess
116e1b58faSStephen Hemmingerimport sys
12*f63ca249SAnatoly Burakovimport typing as T
136e1b58faSStephen Hemmingerfrom math import log2
146e1b58faSStephen Hemminger
156e1b58faSStephen Hemminger# Standard binary prefix
166e1b58faSStephen HemmingerBINARY_PREFIX = "KMG"
176e1b58faSStephen Hemminger
186e1b58faSStephen Hemminger# systemd mount point for huge pages
196e1b58faSStephen HemmingerHUGE_MOUNT = "/dev/hugepages"
20*f63ca249SAnatoly Burakov# default directory for non-NUMA huge pages
21*f63ca249SAnatoly BurakovNO_NUMA_HUGE_DIR = "/sys/kernel/mm/hugepages"
22*f63ca249SAnatoly Burakov# default base directory for NUMA nodes
23*f63ca249SAnatoly BurakovNUMA_NODE_BASE_DIR = "/sys/devices/system/node"
24*f63ca249SAnatoly Burakov# procfs paths
25*f63ca249SAnatoly BurakovMEMINFO_PATH = "/proc/meminfo"
26*f63ca249SAnatoly BurakovMOUNTS_PATH = "/proc/mounts"
276e1b58faSStephen Hemminger
286e1b58faSStephen Hemminger
29*f63ca249SAnatoly Burakovclass HugepageMount:
30*f63ca249SAnatoly Burakov    """Mount operations for huge page filesystem."""
31*f63ca249SAnatoly Burakov
32*f63ca249SAnatoly Burakov    def __init__(self, path: str, mounted: bool):
33*f63ca249SAnatoly Burakov        self.path = path
34*f63ca249SAnatoly Burakov        # current mount status
35*f63ca249SAnatoly Burakov        self.mounted = mounted
36*f63ca249SAnatoly Burakov
37*f63ca249SAnatoly Burakov    def mount(
38*f63ca249SAnatoly Burakov        self, pagesize_kb: int, user: T.Optional[str], group: T.Optional[str]
39*f63ca249SAnatoly Burakov    ) -> None:
40*f63ca249SAnatoly Burakov        """Mount the huge TLB file system"""
41*f63ca249SAnatoly Burakov        if self.mounted:
42*f63ca249SAnatoly Burakov            return
43*f63ca249SAnatoly Burakov        cmd = ["mount", "-t", "hugetlbfs"]
44*f63ca249SAnatoly Burakov        cmd += ["-o", f"pagesize={pagesize_kb * 1024}"]
45*f63ca249SAnatoly Burakov        if user is not None:
46*f63ca249SAnatoly Burakov            cmd += ["-o", f"uid={user}"]
47*f63ca249SAnatoly Burakov        if group is not None:
48*f63ca249SAnatoly Burakov            cmd += ["-o", f"gid={group}"]
49*f63ca249SAnatoly Burakov        cmd += ["nodev", self.path]
50*f63ca249SAnatoly Burakov
51*f63ca249SAnatoly Burakov        subprocess.run(cmd, check=True)
52*f63ca249SAnatoly Burakov        self.mounted = True
53*f63ca249SAnatoly Burakov
54*f63ca249SAnatoly Burakov    def unmount(self) -> None:
55*f63ca249SAnatoly Burakov        """Unmount the huge TLB file system (if mounted)"""
56*f63ca249SAnatoly Burakov        if self.mounted:
57*f63ca249SAnatoly Burakov            subprocess.run(["umount", self.path], check=True)
58*f63ca249SAnatoly Burakov            self.mounted = False
59*f63ca249SAnatoly Burakov
60*f63ca249SAnatoly Burakov
61*f63ca249SAnatoly Burakovclass HugepageRes:
62*f63ca249SAnatoly Burakov    """Huge page reserve operations. Can be NUMA-node-specific."""
63*f63ca249SAnatoly Burakov
64*f63ca249SAnatoly Burakov    def __init__(self, path: str, node: T.Optional[int] = None):
65*f63ca249SAnatoly Burakov        self.path = path
66*f63ca249SAnatoly Burakov        # if this is a per-NUMA node huge page dir, store the node number
67*f63ca249SAnatoly Burakov        self.node = node
68*f63ca249SAnatoly Burakov        self.valid_page_sizes = self._get_valid_page_sizes()
69*f63ca249SAnatoly Burakov
70*f63ca249SAnatoly Burakov    def _get_valid_page_sizes(self) -> T.List[int]:
71*f63ca249SAnatoly Burakov        """Extract valid huge page sizes"""
72*f63ca249SAnatoly Burakov        return [get_memsize(d.split("-")[1]) for d in os.listdir(self.path)]
73*f63ca249SAnatoly Burakov
74*f63ca249SAnatoly Burakov    def _nr_pages_path(self, sz: int) -> str:
75*f63ca249SAnatoly Burakov        if sz not in self.valid_page_sizes:
76*f63ca249SAnatoly Burakov            raise ValueError(
77*f63ca249SAnatoly Burakov                f"Invalid page size {sz}. " f"Valid sizes: {self.valid_page_sizes}"
78*f63ca249SAnatoly Burakov            )
79*f63ca249SAnatoly Burakov        return os.path.join(self.path, f"hugepages-{sz}kB", "nr_hugepages")
80*f63ca249SAnatoly Burakov
81*f63ca249SAnatoly Burakov    def __getitem__(self, sz: int) -> int:
82*f63ca249SAnatoly Burakov        """Get current number of reserved pages of specified size"""
83*f63ca249SAnatoly Burakov        with open(self._nr_pages_path(sz), encoding="utf-8") as f:
84*f63ca249SAnatoly Burakov            return int(f.read())
85*f63ca249SAnatoly Burakov
86*f63ca249SAnatoly Burakov    def __setitem__(self, sz: int, nr_pages: int) -> None:
87*f63ca249SAnatoly Burakov        """Set number of reserved pages of specified size"""
88*f63ca249SAnatoly Burakov        with open(self._nr_pages_path(sz), "w", encoding="utf-8") as f:
89*f63ca249SAnatoly Burakov            f.write(f"{nr_pages}\n")
90*f63ca249SAnatoly Burakov
91*f63ca249SAnatoly Burakov
92*f63ca249SAnatoly Burakovdef fmt_memsize(kb: int) -> str:
93*f63ca249SAnatoly Burakov    """Format memory size in kB into conventional format"""
946e1b58faSStephen Hemminger    logk = int(log2(kb) / 10)
956e1b58faSStephen Hemminger    suffix = BINARY_PREFIX[logk]
966e1b58faSStephen Hemminger    unit = 2 ** (logk * 10)
97*f63ca249SAnatoly Burakov    return f"{int(kb / unit)}{suffix}b"
986e1b58faSStephen Hemminger
996e1b58faSStephen Hemminger
100*f63ca249SAnatoly Burakovdef get_memsize(arg: str) -> int:
101*f63ca249SAnatoly Burakov    """Convert memory size with suffix to kB"""
102*f63ca249SAnatoly Burakov    # arg may have a 'b' at the end
103*f63ca249SAnatoly Burakov    if arg[-1].lower() == "b":
104*f63ca249SAnatoly Burakov        arg = arg[:-1]
105*f63ca249SAnatoly Burakov    match = re.match(rf"(\d+)([{BINARY_PREFIX}]?)$", arg.upper())
1066e1b58faSStephen Hemminger    if match is None:
107*f63ca249SAnatoly Burakov        raise ValueError(f"{arg} is not a valid size")
1086e1b58faSStephen Hemminger    num = float(match.group(1))
1096e1b58faSStephen Hemminger    suffix = match.group(2)
110*f63ca249SAnatoly Burakov    if not suffix:
1116e1b58faSStephen Hemminger        return int(num / 1024)
1126e1b58faSStephen Hemminger    idx = BINARY_PREFIX.find(suffix)
1136e1b58faSStephen Hemminger    return int(num * (2 ** (idx * 10)))
1146e1b58faSStephen Hemminger
1156e1b58faSStephen Hemminger
116*f63ca249SAnatoly Burakovdef is_numa() -> bool:
117*f63ca249SAnatoly Burakov    """Check if NUMA is supported"""
118*f63ca249SAnatoly Burakov    return os.path.exists(NUMA_NODE_BASE_DIR)
1196e1b58faSStephen Hemminger
1206e1b58faSStephen Hemminger
121*f63ca249SAnatoly Burakovdef default_pagesize() -> int:
122*f63ca249SAnatoly Burakov    """Get default huge page size from /proc/meminfo"""
123*f63ca249SAnatoly Burakov    key = "Hugepagesize"
124*f63ca249SAnatoly Burakov    with open(MEMINFO_PATH, encoding="utf-8") as meminfo:
1256e1b58faSStephen Hemminger        for line in meminfo:
126*f63ca249SAnatoly Burakov            if line.startswith(f"{key}:"):
1276e1b58faSStephen Hemminger                return int(line.split()[1])
128*f63ca249SAnatoly Burakov    raise KeyError(f'"{key}" not found in {MEMINFO_PATH}')
1296e1b58faSStephen Hemminger
1306e1b58faSStephen Hemminger
131*f63ca249SAnatoly Burakovdef get_hugetlbfs_mountpoints() -> T.List[str]:
132*f63ca249SAnatoly Burakov    """Get list of where huge page filesystem is mounted"""
133*f63ca249SAnatoly Burakov    mounted: T.List[str] = []
134*f63ca249SAnatoly Burakov    with open(MOUNTS_PATH, encoding="utf-8") as mounts:
1356e1b58faSStephen Hemminger        for line in mounts:
1366e1b58faSStephen Hemminger            fields = line.split()
137*f63ca249SAnatoly Burakov            if fields[2] != "hugetlbfs":
1386e1b58faSStephen Hemminger                continue
1396e1b58faSStephen Hemminger            mounted.append(fields[1])
1406e1b58faSStephen Hemminger    return mounted
1416e1b58faSStephen Hemminger
1426e1b58faSStephen Hemminger
143*f63ca249SAnatoly Burakovdef print_row(cells: T.Tuple[str, ...], widths: T.List[int]) -> None:
144*f63ca249SAnatoly Burakov    """Print a row of a table with the given column widths"""
145*f63ca249SAnatoly Burakov    first, *rest = cells
146*f63ca249SAnatoly Burakov    w_first, *w_rest = widths
147*f63ca249SAnatoly Burakov    first_end = " " * 2
148*f63ca249SAnatoly Burakov    rest_end = " " * 2
149*f63ca249SAnatoly Burakov
150*f63ca249SAnatoly Burakov    print(first.ljust(w_first), end=first_end)
151*f63ca249SAnatoly Burakov    for cell, width in zip(rest, w_rest):
152*f63ca249SAnatoly Burakov        print(cell.rjust(width), end=rest_end)
153*f63ca249SAnatoly Burakov    print()
1546e1b58faSStephen Hemminger
1556e1b58faSStephen Hemminger
156*f63ca249SAnatoly Burakovdef print_hp_status(hp_res: T.List[HugepageRes]) -> None:
157*f63ca249SAnatoly Burakov    """Display status of huge page reservations"""
158*f63ca249SAnatoly Burakov    numa = is_numa()
1596e1b58faSStephen Hemminger
160*f63ca249SAnatoly Burakov    # print out huge page information in a table
161*f63ca249SAnatoly Burakov    rows: T.List[T.Tuple[str, ...]]
162*f63ca249SAnatoly Burakov    headers: T.Tuple[str, ...]
163*f63ca249SAnatoly Burakov    if numa:
164*f63ca249SAnatoly Burakov        headers = "Node", "Pages", "Size", "Total"
165*f63ca249SAnatoly Burakov        rows = [
166*f63ca249SAnatoly Burakov            (
167*f63ca249SAnatoly Burakov                str(hp.node),
168*f63ca249SAnatoly Burakov                str(nr_pages),
169*f63ca249SAnatoly Burakov                fmt_memsize(sz),
170*f63ca249SAnatoly Burakov                fmt_memsize(sz * nr_pages),
171*f63ca249SAnatoly Burakov            )
172*f63ca249SAnatoly Burakov            # iterate over each huge page sysfs node...
173*f63ca249SAnatoly Burakov            for hp in hp_res
174*f63ca249SAnatoly Burakov            # ...and each page size within that node...
175*f63ca249SAnatoly Burakov            for sz in hp.valid_page_sizes
176*f63ca249SAnatoly Burakov            # ...we need number of pages multiple times, so we read it here...
177*f63ca249SAnatoly Burakov            for nr_pages in [hp[sz]]
178*f63ca249SAnatoly Burakov            # ...include this row only if there are pages reserved
179*f63ca249SAnatoly Burakov            if nr_pages
180*f63ca249SAnatoly Burakov        ]
1816e1b58faSStephen Hemminger    else:
182*f63ca249SAnatoly Burakov        headers = "Pages", "Size", "Total"
183*f63ca249SAnatoly Burakov        # if NUMA is disabled, we know there's only one huge page dir
184*f63ca249SAnatoly Burakov        hp = hp_res[0]
185*f63ca249SAnatoly Burakov        rows = [
186*f63ca249SAnatoly Burakov            (str(nr_pages), fmt_memsize(sz), fmt_memsize(sz * nr_pages))
187*f63ca249SAnatoly Burakov            # iterate over each page size within the huge page dir
188*f63ca249SAnatoly Burakov            for sz in hp.valid_page_sizes
189*f63ca249SAnatoly Burakov            # read number of pages for this size
190*f63ca249SAnatoly Burakov            for nr_pages in [hp[sz]]
191*f63ca249SAnatoly Burakov            # skip if no pages
192*f63ca249SAnatoly Burakov            if nr_pages
193*f63ca249SAnatoly Burakov        ]
194*f63ca249SAnatoly Burakov    if not rows:
195*f63ca249SAnatoly Burakov        print("No huge pages reserved")
196*f63ca249SAnatoly Burakov        return
197*f63ca249SAnatoly Burakov
198*f63ca249SAnatoly Burakov    # find max widths for each column, including header and rows
199*f63ca249SAnatoly Burakov    col_widths = [
200*f63ca249SAnatoly Burakov        max(len(tup[col_idx]) for tup in rows + [headers])
201*f63ca249SAnatoly Burakov        for col_idx in range(len(headers))
202*f63ca249SAnatoly Burakov    ]
203*f63ca249SAnatoly Burakov
204*f63ca249SAnatoly Burakov    # print everything
205*f63ca249SAnatoly Burakov    print_row(headers, col_widths)
206*f63ca249SAnatoly Burakov    for r in rows:
207*f63ca249SAnatoly Burakov        print_row(r, col_widths)
208*f63ca249SAnatoly Burakov
209*f63ca249SAnatoly Burakov
210*f63ca249SAnatoly Burakovdef print_mount_status() -> None:
211*f63ca249SAnatoly Burakov    """Display status of huge page filesystem mounts"""
212*f63ca249SAnatoly Burakov    mounted = get_hugetlbfs_mountpoints()
213*f63ca249SAnatoly Burakov    if not mounted:
214*f63ca249SAnatoly Burakov        print("No huge page filesystems mounted")
215*f63ca249SAnatoly Burakov        return
216*f63ca249SAnatoly Burakov    print("Huge page filesystems mounted at:", *mounted, sep=" ")
217*f63ca249SAnatoly Burakov
218*f63ca249SAnatoly Burakov
219*f63ca249SAnatoly Burakovdef scan_huge_dirs(node: T.Optional[int]) -> T.List[HugepageRes]:
220*f63ca249SAnatoly Burakov    """Return a HugepageRes object for each huge page directory"""
221*f63ca249SAnatoly Burakov    # if NUMA is enabled, scan per-NUMA node huge pages
222*f63ca249SAnatoly Burakov    if is_numa():
223*f63ca249SAnatoly Burakov        # helper function to extract node number from directory name
224*f63ca249SAnatoly Burakov        def _get_node(path: str) -> T.Optional[int]:
225*f63ca249SAnatoly Burakov            m = re.match(r"node(\d+)", os.path.basename(path))
226*f63ca249SAnatoly Burakov            return int(m.group(1)) if m else None
227*f63ca249SAnatoly Burakov
228*f63ca249SAnatoly Burakov        # we want a sorted list of NUMA nodes
229*f63ca249SAnatoly Burakov        nodes = sorted(
230*f63ca249SAnatoly Burakov            n
231*f63ca249SAnatoly Burakov            # iterate over all directories in the base directory
232*f63ca249SAnatoly Burakov            for d in os.listdir(NUMA_NODE_BASE_DIR)
233*f63ca249SAnatoly Burakov            # extract the node number from the directory name
234*f63ca249SAnatoly Burakov            for n in [_get_node(d)]
235*f63ca249SAnatoly Burakov            # filter out None values (non-NUMA node directories)
236*f63ca249SAnatoly Burakov            if n is not None
237*f63ca249SAnatoly Burakov        )
238*f63ca249SAnatoly Burakov        return [
239*f63ca249SAnatoly Burakov            HugepageRes(os.path.join(NUMA_NODE_BASE_DIR, f"node{n}", "hugepages"), n)
240*f63ca249SAnatoly Burakov            for n in nodes
241*f63ca249SAnatoly Burakov            # if user requested a specific node, only include that one
242*f63ca249SAnatoly Burakov            if node is None or n == node
243*f63ca249SAnatoly Burakov        ]
244*f63ca249SAnatoly Burakov    # otherwise, use non-NUMA huge page directory
245*f63ca249SAnatoly Burakov    if node is not None:
246*f63ca249SAnatoly Burakov        raise ValueError("NUMA node requested but not supported")
247*f63ca249SAnatoly Burakov    return [HugepageRes(NO_NUMA_HUGE_DIR)]
248*f63ca249SAnatoly Burakov
249*f63ca249SAnatoly Burakov
250*f63ca249SAnatoly Burakovdef try_reserve_huge_pages(
251*f63ca249SAnatoly Burakov    hp_res: T.List[HugepageRes], mem_sz: str, pagesize_kb: int
252*f63ca249SAnatoly Burakov) -> None:
253*f63ca249SAnatoly Burakov    """Reserve huge pages if possible"""
254*f63ca249SAnatoly Burakov    reserve_kb = get_memsize(mem_sz)
255*f63ca249SAnatoly Burakov
256*f63ca249SAnatoly Burakov    # is this a valid request?
257*f63ca249SAnatoly Burakov    if reserve_kb % pagesize_kb != 0:
258*f63ca249SAnatoly Burakov        fmt_res = fmt_memsize(reserve_kb)
259*f63ca249SAnatoly Burakov        fmt_sz = fmt_memsize(pagesize_kb)
260*f63ca249SAnatoly Burakov        raise ValueError(
261*f63ca249SAnatoly Burakov            f"Huge reservation {fmt_res} is " f"not a multiple of page size {fmt_sz}"
262*f63ca249SAnatoly Burakov        )
263*f63ca249SAnatoly Burakov
264*f63ca249SAnatoly Burakov    # request is valid, reserve pages
265*f63ca249SAnatoly Burakov    for hp in hp_res:
266*f63ca249SAnatoly Burakov        req = reserve_kb // pagesize_kb
267*f63ca249SAnatoly Burakov        hp[pagesize_kb] = req
268*f63ca249SAnatoly Burakov        got = hp[pagesize_kb]
269*f63ca249SAnatoly Burakov        # did we fulfill our request?
270*f63ca249SAnatoly Burakov        if got != req:
271*f63ca249SAnatoly Burakov            raise OSError(
272*f63ca249SAnatoly Burakov                f"Failed to reserve {req} pages of size "
273*f63ca249SAnatoly Burakov                f"{fmt_memsize(pagesize_kb)}, "
274*f63ca249SAnatoly Burakov                f"got {got} pages instead"
275*f63ca249SAnatoly Burakov            )
2766e1b58faSStephen Hemminger
2776e1b58faSStephen Hemminger
2786e1b58faSStephen Hemmingerdef main():
279*f63ca249SAnatoly Burakov    """Process the command line arguments and setup huge pages"""
2806e1b58faSStephen Hemminger    parser = argparse.ArgumentParser(
2816e1b58faSStephen Hemminger        formatter_class=argparse.RawDescriptionHelpFormatter,
2826e1b58faSStephen Hemminger        description="Setup huge pages",
2836e1b58faSStephen Hemminger        epilog="""
2846e1b58faSStephen HemmingerExamples:
2856e1b58faSStephen Hemminger
2866e1b58faSStephen HemmingerTo display current huge page settings:
2876e1b58faSStephen Hemminger    %(prog)s -s
2886e1b58faSStephen Hemminger
2896e1b58faSStephen HemmingerTo a complete setup of with 2 Gigabyte of 1G huge pages:
2906e1b58faSStephen Hemminger    %(prog)s -p 1G --setup 2G
291*f63ca249SAnatoly Burakov""",
292*f63ca249SAnatoly Burakov    )
2936e1b58faSStephen Hemminger    parser.add_argument(
294*f63ca249SAnatoly Burakov        "--show",
295*f63ca249SAnatoly Burakov        "-s",
296*f63ca249SAnatoly Burakov        action="store_true",
297*f63ca249SAnatoly Burakov        help="Print current huge page configuration",
298*f63ca249SAnatoly Burakov    )
2996e1b58faSStephen Hemminger    parser.add_argument(
300*f63ca249SAnatoly Burakov        "--clear", "-c", action="store_true", help="Clear existing huge pages"
301*f63ca249SAnatoly Burakov    )
3026e1b58faSStephen Hemminger    parser.add_argument(
303*f63ca249SAnatoly Burakov        "--mount",
304*f63ca249SAnatoly Burakov        "-m",
305*f63ca249SAnatoly Burakov        action="store_true",
306*f63ca249SAnatoly Burakov        help="Mount the huge page filesystem",
307*f63ca249SAnatoly Burakov    )
3086e1b58faSStephen Hemminger    parser.add_argument(
309*f63ca249SAnatoly Burakov        "--unmount",
310*f63ca249SAnatoly Burakov        "-u",
311*f63ca249SAnatoly Burakov        action="store_true",
312*f63ca249SAnatoly Burakov        help="Unmount the system huge page directory",
313*f63ca249SAnatoly Burakov    )
3146e1b58faSStephen Hemminger    parser.add_argument(
315*f63ca249SAnatoly Burakov        "--directory",
316*f63ca249SAnatoly Burakov        "-d",
317*f63ca249SAnatoly Burakov        metavar="DIR",
31831af02efSDmitry Kozlyuk        default=HUGE_MOUNT,
319*f63ca249SAnatoly Burakov        help="Mount point for huge pages",
320*f63ca249SAnatoly Burakov    )
32131af02efSDmitry Kozlyuk    parser.add_argument(
322*f63ca249SAnatoly Burakov        "--user",
323*f63ca249SAnatoly Burakov        "-U",
324*f63ca249SAnatoly Burakov        metavar="UID",
325*f63ca249SAnatoly Burakov        help="Set the mounted directory owner user",
326*f63ca249SAnatoly Burakov    )
3278d73de6fSDmitry Kozlyuk    parser.add_argument(
328*f63ca249SAnatoly Burakov        "--group",
329*f63ca249SAnatoly Burakov        "-G",
330*f63ca249SAnatoly Burakov        metavar="GID",
331*f63ca249SAnatoly Burakov        help="Set the mounted directory owner group",
332*f63ca249SAnatoly Burakov    )
3338d73de6fSDmitry Kozlyuk    parser.add_argument(
334*f63ca249SAnatoly Burakov        "--node", "-n", type=int, help="Select numa node to reserve pages on"
335*f63ca249SAnatoly Burakov    )
3366e1b58faSStephen Hemminger    parser.add_argument(
337*f63ca249SAnatoly Burakov        "--pagesize", "-p", metavar="SIZE", help="Choose huge page size to use"
338*f63ca249SAnatoly Burakov    )
3396e1b58faSStephen Hemminger    parser.add_argument(
340*f63ca249SAnatoly Burakov        "--reserve",
341*f63ca249SAnatoly Burakov        "-r",
342*f63ca249SAnatoly Burakov        metavar="SIZE",
343*f63ca249SAnatoly Burakov        help="Reserve huge pages. Size is in bytes with K, M, or G suffix",
344*f63ca249SAnatoly Burakov    )
3456e1b58faSStephen Hemminger    parser.add_argument(
346*f63ca249SAnatoly Burakov        "--setup",
347*f63ca249SAnatoly Burakov        metavar="SIZE",
348*f63ca249SAnatoly Burakov        help="Setup huge pages by doing clear, unmount, reserve and mount",
349*f63ca249SAnatoly Burakov    )
3506e1b58faSStephen Hemminger    args = parser.parse_args()
3516e1b58faSStephen Hemminger
352*f63ca249SAnatoly Burakov    # setup is clear, then unmount, then reserve, then mount
3536e1b58faSStephen Hemminger    if args.setup:
3546e1b58faSStephen Hemminger        args.clear = True
3556e1b58faSStephen Hemminger        args.unmount = True
3566e1b58faSStephen Hemminger        args.reserve = args.setup
3576e1b58faSStephen Hemminger        args.mount = True
3586e1b58faSStephen Hemminger
359b41bd046SThomas Monjalon    if not (args.show or args.mount or args.unmount or args.clear or args.reserve):
360b41bd046SThomas Monjalon        parser.error("no action specified")
361b41bd046SThomas Monjalon
362*f63ca249SAnatoly Burakov    # read huge page data from sysfs
363*f63ca249SAnatoly Burakov    hp_res = scan_huge_dirs(args.node)
364*f63ca249SAnatoly Burakov
365*f63ca249SAnatoly Burakov    # read huge page mountpoint data
366*f63ca249SAnatoly Burakov    hp_mountpoint = args.directory
367*f63ca249SAnatoly Burakov    hp_mounted = hp_mountpoint in get_hugetlbfs_mountpoints()
368*f63ca249SAnatoly Burakov    hp_mount = HugepageMount(hp_mountpoint, hp_mounted)
369*f63ca249SAnatoly Burakov
370*f63ca249SAnatoly Burakov    # get requested page size we will be working with
3716e1b58faSStephen Hemminger    if args.pagesize:
3726e1b58faSStephen Hemminger        pagesize_kb = get_memsize(args.pagesize)
3736e1b58faSStephen Hemminger    else:
3746e1b58faSStephen Hemminger        pagesize_kb = default_pagesize()
3756e1b58faSStephen Hemminger
376*f63ca249SAnatoly Burakov    # were we asked to clear?
3776e1b58faSStephen Hemminger    if args.clear:
378*f63ca249SAnatoly Burakov        for hp in hp_res:
379*f63ca249SAnatoly Burakov            for sz in hp.valid_page_sizes:
380*f63ca249SAnatoly Burakov                hp[sz] = 0
3816e1b58faSStephen Hemminger
382*f63ca249SAnatoly Burakov    # were we asked to unmount?
383*f63ca249SAnatoly Burakov    if args.unmount:
384*f63ca249SAnatoly Burakov        hp_mount.unmount()
385*f63ca249SAnatoly Burakov
386*f63ca249SAnatoly Burakov    # were we asked to reserve pages?
3876e1b58faSStephen Hemminger    if args.reserve:
388*f63ca249SAnatoly Burakov        try_reserve_huge_pages(hp_res, args.reserve, pagesize_kb)
389*f63ca249SAnatoly Burakov
390*f63ca249SAnatoly Burakov    # were we asked to mount?
3916e1b58faSStephen Hemminger    if args.mount:
392*f63ca249SAnatoly Burakov        hp_mount.mount(pagesize_kb, args.user, args.group)
393*f63ca249SAnatoly Burakov
394*f63ca249SAnatoly Burakov    # were we asked to display status?
3956e1b58faSStephen Hemminger    if args.show:
396*f63ca249SAnatoly Burakov        print_hp_status(hp_res)
3976e1b58faSStephen Hemminger        print()
398*f63ca249SAnatoly Burakov        print_mount_status()
3996e1b58faSStephen Hemminger
4006e1b58faSStephen Hemminger
4016e1b58faSStephen Hemmingerif __name__ == "__main__":
402*f63ca249SAnatoly Burakov    try:
4036e1b58faSStephen Hemminger        main()
404*f63ca249SAnatoly Burakov    except PermissionError:
405*f63ca249SAnatoly Burakov        sys.exit("Permission denied: need to be root!")
406*f63ca249SAnatoly Burakov    except subprocess.CalledProcessError as e:
407*f63ca249SAnatoly Burakov        sys.exit(f"Command failed: {e}")
408*f63ca249SAnatoly Burakov    except (KeyError, ValueError, OSError) as e:
409*f63ca249SAnatoly Burakov        sys.exit(f"Error: {e}")
410