-
Notifications
You must be signed in to change notification settings - Fork 0
/
minimize-flags.py
executable file
·146 lines (107 loc) · 5.22 KB
/
minimize-flags.py
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
#!/usr/bin/env python3
# Flag optimization
# This file is part of SimpleTuner
# Copyright (C) 2021-2023 Embecosm <www.embecosm.com>
# Contributor Maxim Blinov <[email protected]>
# SPDX-License-Identifier: GPL-3.0-or-later
import copy;
import logging;
import argparse;
import importlib;
from tempfile import TemporaryDirectory;
parser = argparse.ArgumentParser(description='Remove redundant compiler flags.');
parser.add_argument("--cc", default=None,
help="C compiler to use for initial flag validation.");
parser.add_argument("--context", default=None,
help="Specify which worker context class to use. This is a user-defined classname.");
parser.add_argument("--benchmark", default=None,
help="Specify which benchmark to run. This parameter is specific to whatever worker context you selected in the --context parameter.");
parser.add_argument("--target", required=True, type=float,
help="Benchmark result to target. minimize-flags.py won't remove flags that affect this number.");
parser.add_argument("--starting-cflags-file", default=None,
help="C flags to start with. These can help speed up combined elimination. If you're trying to minimize size, try '-Os'. If you're trying to maximise performance, try '-O3' or '-Ofast'.");
args = parser.parse_args();
def get_worker_context_class(worker_context_classname):
ctx_module = importlib.import_module("{}.{}".format("context", worker_context_classname));
ctx_class = getattr(ctx_module, worker_context_classname);
WorkerContext = ctx_class;
return WorkerContext;
def minimize(input_flags, target, worker):
current_flags = copy.deepcopy(input_flags);
compulsory_flags = [];
while len(current_flags) > 0:
compile_ok = worker.compile([] + compulsory_flags);
result = worker.benchmark();
benchmark_ok = compile_ok and (result == target);
if benchmark_ok:
break;
idx_mid = len(current_flags) // 2;
while not benchmark_ok:
include = current_flags[:idx_mid];
exclude = current_flags[idx_mid:];
logging.debug("include: " + ", ".join(include));
logging.debug("exclude: " + ", ".join(exclude));
compile_ok = worker.compile(include + compulsory_flags);
result = worker.benchmark();
benchmark_ok = compile_ok and (result == target);
if not benchmark_ok:
if len(exclude) == 1:
compulsory_flag = exclude[0];
logging.debug("Found failing flag: " + compulsory_flag);
compulsory_flags.append(compulsory_flag);
del current_flags[idx_mid:];
break;
logging.debug("Build failed");
idx_mid = (idx_mid + len(current_flags)) // 2;
else:
logging.debug("Build success");
del current_flags[idx_mid:];
break;
logging.info("We're done - compulsory flags: " + str(compulsory_flags));
return compulsory_flags;
def main():
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(name)s: %(message)s",
)
logging.root.setLevel(logging.NOTSET)
logger = logging.getLogger()
# The WorkerContext class that we will be using
if args.context is None:
logger.warning("No worker context specified, using ExampleWorkerContext")
worker_context_classname = "ExampleWorkerContext"
else:
worker_context_classname = args.context
WorkerContext = get_worker_context_class(worker_context_classname)
if args.benchmark is None:
logger.error("You must provide a benchmark to use via the --benchmark flag. Aborting.");
logger.error("Valid --benchmark arguments: " + ", ".join(
['"' + benchmark + '"'
for benchmark in WorkerContext.get_available_benchmark_types()]));
exit(1);
elif args.benchmark not in WorkerContext.get_available_benchmark_types():
logger.error("--benchmark \"{}\" is invalid for worker context \"{}\""\
.format(args.benchmark, args.context));
logger.error("Valid --benchmark arguments: " + ", ".join(
['"' + benchmark + '"'
for benchmark in WorkerContext.get_available_benchmark_types()]));
exit(1);
else:
logger.info("Will be using the benchmark \"{}\"".format(args.benchmark));
workspace = TemporaryDirectory();
logger.info("Using temporary workspace directory \"{}\"".format(workspace.name));
worker = WorkerContext(0, workspace.name, args.cc, args.benchmark);
worker.init_workspace();
with open(args.starting_cflags_file, "r") as file:
raw = file.read();
starting_flags = [e.strip() for e in raw.split()]
minimized_flags = minimize(starting_flags, args.target, worker);
print("Reduced flags:");
for flag in minimized_flags:
print(flag);
# for flag in ["-O0", "-O1", "-O2", "-O3", "-Ofast", "-Os"]:
# context.compile([flag]);
# result = context.benchmark();
# logger.info("Got result for {}: {}".format(flag, result));
workspace.cleanup();
if __name__ == "__main__":
main()