• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

smarr / ReBench / 12978886586

26 Jan 2025 10:23PM UTC coverage: 85.2% (+0.7%) from 84.488%
12978886586

Pull #281

github

smarr
Enable denoise.py to work as script to avoid need for PYTHONPATH to be set in environment

- make denoise.py executable for all
- denoise.py does not support —version any longer, but that seems like an ok tradeoff

Signed-off-by: Stefan Marr <git@stefan-marr.de>
Pull Request #281: Enable denoise.py to work as script to avoid need for PYTHONPATH in env

10 of 21 new or added lines in 3 files covered. (47.62%)

13 existing lines in 1 file now uncovered.

5630 of 6608 relevant lines covered (85.2%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

53.45
/rebench/denoise_client.py
1
import getpass
1✔
2
import json
1✔
3
import os
1✔
4
import subprocess
1✔
5

6
from cpuinfo import get_cpu_info
1✔
7

8
from .denoise import paths
1✔
9
from .output import output_as_str
1✔
10
from .ui import escape_braces
1✔
11

12

13
_num_cpu_cores = None
1✔
14

15

16
def get_number_of_cores():
1✔
17
    global _num_cpu_cores  # pylint: disable=global-statement
18
    if _num_cpu_cores is None:
1✔
19
        cpu_info = get_cpu_info()
1✔
20
        _num_cpu_cores = cpu_info["count"]
1✔
21
    return _num_cpu_cores
1✔
22

23

24
class DenoiseResult:
1✔
25

26
    def __init__(self, succeeded, warn_msg, use_nice, use_shielding, details):
1✔
27
        self.succeeded = succeeded
1✔
28
        self.warn_msg = warn_msg
1✔
29
        self.use_nice = use_nice
1✔
30
        self.use_shielding = use_shielding
1✔
31
        self.details = details
1✔
32

33

34
def minimize_noise(show_warnings, ui, for_profiling):  # pylint: disable=too-many-statements
1✔
35
    num_cores = get_number_of_cores()
1✔
36

37
    result = {}
1✔
38

39
    env = os.environ
1✔
40
    cmd = ["sudo", "-n", paths.get_denoise()]
1✔
41
    if for_profiling:
1✔
42
        cmd += ["--for-profiling"]
1✔
43

44
    if paths.has_cset():
1✔
45
        cmd += ["--cset-path", paths.get_cset()]
×
46
    cmd += ["--json", "minimize"]
1✔
47
    cmd += ["--num-cores", str(num_cores)]
1✔
48

49
    try:
1✔
50
        output = output_as_str(
1✔
51
            subprocess.check_output(cmd, stderr=subprocess.STDOUT, env=env))
52
    except subprocess.CalledProcessError as e:
1✔
53
        output = output_as_str(e.output)
1✔
54
    except FileNotFoundError as e:
×
55
        print("FileNotFoundError")
×
56
        output = str(e)
×
57

58
    try:
1✔
59
        result = json.loads(output)
1✔
60
        got_json = True
1✔
61
    except ValueError:
×
62
        got_json = False
×
63

64
    msg = "Minimizing noise with rebench-denoise failed\n"
1✔
65
    msg += "{ind}possibly causing benchmark results to vary more.\n\n"
1✔
66

67
    success = False
1✔
68
    use_nice = False
1✔
69
    use_shielding = False
1✔
70

71
    if got_json:
1✔
72
        use_nice = result.get("can_set_nice", False)
1✔
73
        use_shielding = result.get("shielding", False)
1✔
74

75
        failed = ""
1✔
76

77
        for k, value in result.items():
1✔
78
            if value == "failed":
1✔
79
                failed += "{ind}{ind} - " + k + "\n"
1✔
80

81
        if not use_nice:
1✔
82
            failed += "{ind}{ind} - nice was not used\n"
×
83
        if not use_shielding:
1✔
84
            failed += "{ind}{ind} - core shielding was not used\n"
1✔
85

86
        if failed:
1✔
87
            msg += "{ind}Failed to set:\n" + failed + "\n"
1✔
88

89
        if not use_nice and show_warnings:
1✔
90
            msg += ("{ind}Process niceness could not be set.\n"
×
91
                    + "{ind}{ind}`nice` is used to elevate the priority of the benchmark,\n"
92
                    + "{ind}{ind}without it, other processes my interfere with it"
93
                    + " nondeterministically.\n")
94

95
        if not use_shielding and show_warnings:
1✔
96
            msg += "{ind}Core shielding could not be set up"
×
97

98
            if not paths.has_cset():
×
99
                msg += ", because the cset command was not found.\n"
×
100
            else:
101
                msg += ".\n"
×
102

103
            msg += ("{ind}{ind}Shielding is used to restrict the use of cores to"
×
104
                    + " benchmarking.\n"
105
                    + "{ind}{ind}Without it, there my be more nondeterministic interference.\n")
106

107
            if not paths.has_cset():
×
108
                msg += ("{ind}{ind}cset is part of the cpuset package on Debian, Ubuntu," +
×
109
                        " and OpenSuSE. The code is maintained here:" +
110
                        " https://github.com/SUSE/cpuset\n")
111

112
        if use_nice and use_shielding and not failed:
1✔
113
            success = True
×
114
    else:
115
        if 'password is required' in output:
×
116
            msg += '{ind}Please make sure `sudo ' + paths.get_denoise() + '`' \
×
117
                   + ' can be used without password.\n'
NEW
118
            msg += '{ind}To be able to run denoise without password,\n'
×
119
            msg += '{ind}add the following to the end of your sudoers file (using visudo):\n'
×
120
            msg += '{ind}{ind}' + getpass.getuser() + ' ALL = (root) NOPASSWD:SETENV: '\
×
121
                   + paths.get_denoise() + '\n'
122
        elif 'command not found' in output:
×
NEW
123
            msg += '{ind}Please make sure ' + paths.get_denoise() + ' is accessible.\n'
×
124
        elif "No such file or directory: 'sudo'" in output:
×
NEW
125
            msg += "{ind}sudo is not available. Can't use denoise to manage the system.\n"
×
126
        else:
127
            msg += "{ind}Error: " + escape_braces(output)
×
128

129
    if not success and show_warnings:
1✔
130
        ui.warning(msg)
×
131

132
    return DenoiseResult(success, msg, use_nice, use_shielding, result)
1✔
133

134

135
def restore_noise(denoise_result, show_warning, ui):
1✔
136
    if not denoise_result:
×
137
        # likely has failed completely. And without details, just no-op
138
        return
×
139

140
    num_cores = get_number_of_cores()
×
141

NEW
142
    env = os.environ
×
143
    values = set(denoise_result.details.values())
×
144
    if len(values) == 1 and "failed" in values:
×
145
        # everything failed, don't need to try to restore things
146
        pass
×
147
    else:
148
        try:
×
NEW
149
            cmd = ["sudo", "-n", paths.get_denoise(), "--json"]
×
150
            if not denoise_result.use_shielding:
×
151
                cmd += ["--without-shielding"]
×
152
            elif paths.has_cset():
×
153
                cmd += ["--cset-path", paths.get_cset()]
×
154
            if not denoise_result.use_nice:
×
155
                cmd += ["--without-nice"]
×
156
            cmd += ["--num-cores", str(num_cores)]
×
157
            subprocess.check_output(cmd + ["restore"], stderr=subprocess.STDOUT, env=env)
×
158
        except (subprocess.CalledProcessError, FileNotFoundError):
×
159
            pass
×
160

161
    if not denoise_result.succeeded and show_warning:
×
162
        # warn a second time at the end of the execution
163
        ui.error(denoise_result.warn_msg)
×
164

165

166
def deliver_kill_signal(pid):
1✔
NEW
167
    env = os.environ
×
168

169
    try:
×
NEW
170
        cmd = ['sudo',
×
171
               '-n', paths.get_denoise(), '--json', 'kill', str(pid)]
172
        subprocess.check_output(cmd, stderr=subprocess.STDOUT, env=env)
×
173
    except (subprocess.CalledProcessError, FileNotFoundError):
×
174
        pass
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc