File: perf-fsck.py

package info (click to toggle)
libfiu 1.2-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 768 kB
  • sloc: ansic: 2,633; python: 973; makefile: 599; sh: 309
file content (158 lines) | stat: -rw-r--r-- 4,403 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python3

"""
Performance tests using fsck.ext2 on a test file.

It can be tuned with the following environment variables:

 - TEST_FILE: The name of the file used for testing. By default, ".test_fs".
 - TEST_FILE_SIZE_MB: The size of the test file, in megabytes. Only used if
   the file doesn't exist. Default: 10.
 - VERBOSE: Show verbose output (from 0 to 2). Default: 0.
 - LD_LIBRARY_PATH: Library path to pass on to the subcommands.
   Default: <directory of this file>/../libfiu/, which is usually the one
   containing the current build.
"""

import os
import sys
import subprocess
import time

test_file = os.environ.get("TEST_FILE", ".test_fs")

test_file_size = int(os.environ.get("TEST_FILE_SIZE_MB", 10))

ld_library_path = os.environ.get(
    "LD_LIBRARY_PATH",
    os.path.abspath(
        os.path.abspath(os.path.dirname(sys.argv[0])) + "/../libfiu/"
    ),
)

verbose = int(os.environ.get("VERBOSE", 0))

dev_null = open("/dev/null", "w")


def run_child(name, args, stdout=dev_null, stderr=dev_null):
    """Runs the subprocess, returns the Popen object."""
    env = dict(os.environ)
    env["LD_LIBRARY_PATH"] = ld_library_path

    if verbose and stdout == stderr == dev_null:
        stdout = stderr = None

    child = subprocess.Popen(args, env=env, stdout=stdout, stderr=stderr)
    return child


def run_and_time(name, args):
    """Run the given arguments, print the times."""
    start = time.time()
    child = run_child(name, args)
    _, status, rusage = os.wait4(child.pid, 0)
    end = time.time()

    if verbose == 2:
        print("Ran %s -> %d" % (args, status))

    if status != 0:
        print("Error running %s: %s" % (args[0], status))
        raise RuntimeError

    print(
        "%-10s u:%.3f  s:%.3f  r:%.3f"
        % (name, rusage.ru_utime, rusage.ru_stime, end - start)
    )


def run_fsck(name, fiu_args):
    """Runs an fsck with the given fiu arguments."""
    child = run_child(
        name,
        ["fiu-run", "-x"]
        + fiu_args
        + "fsck.ext2 -n -t -f".split()
        + [test_file],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    stdout, stderr = child.communicate()

    if child.returncode != 0:
        print("Error running fsck: %s" % child.returncode)
        raise RuntimeError

    # Find the times reported by fsck.
    # Not very robust, but useful as it measures the real program time run,
    # and not the startup overhead.
    # The line looks like:
    #   Memory used: 560k/0k (387k/174k), time:  2.18/ 2.17/ 0.00
    user_time = sys_time = real_time = -1
    for l in stdout.split("\n"):
        if not l.startswith("Memory used"):
            continue

        times = l.split(":")[-1].split("/")
        times = [s.strip() for s in times]
        if len(times) != 3:
            continue

        real_time = float(times[0])
        user_time = float(times[1])
        sys_time = float(times[2])
        break

    print(
        "%-10s u:%.3f  s:%.3f  r:%.3f" % (name, user_time, sys_time, real_time)
    )


def check_test_file():
    if os.path.exists(test_file):
        return

    with open(test_file, "w") as fd:
        fd.truncate(test_file_size * 1024 * 1024)

    retcode = subprocess.call(
        ["mkfs.ext2", "-F", test_file], stdout=open("/dev/null", "w")
    )
    if retcode != 0:
        print("Error running mkfs.ext2:", retcode)
        return


if __name__ == "__main__":
    check_test_file()

    run_and_time("base", "fsck.ext2 -n -f".split() + [test_file])

    # 1 all-matching wildcard.
    run_fsck("w1", ["-c", "enable_random name=*,probability=0"])

    # 1k final failure points, no matches.
    args = []
    for i in range(1000):
        args += ["-c", "enable_random name=none/%d,probability=0" % i]
    run_fsck("f1k", args)

    # 1k wildcard failure points, no matches.
    args = []
    for i in range(1000):
        args += ["-c", "enable_random name=none/%d/*,probability=0" % i]
    run_fsck("w1k", args)

    # 1k wildcarded failure points, and 1 match.
    args = []
    for i in range(1000):
        args += ["-c", "enable_random name=none/%d/*,probability=0" % i]
    args += ["-c", "enable_random name=*,probability=0"]
    run_fsck("w1k+1", args)

    # 1k final failure points, *all* matches.
    args = []
    for i in range(1000):
        args += ["-c", "enable_random name=*,probability=0"]
    run_fsck("m1k", args)