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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
#! /bin/bash
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Finds the optimal update_pch settings that results in,
# per module and library, the fastest build time and
# smallest intermediate files (.o/.obj) output.
# Usage: update_pch_autotune.sh [<module1> <module2>]
# Invoke: /opt/lo/bin/make cmd cmd="./bin/update_pch_autotune.sh [..]"
# The resulting values may be entered in update_pch
# to be use for generating PCH in the future.
# Run this script after major header changes.
root=`dirname $0`
root=`cd $root/.. && pwd`
cd $root
if test -z "$1"; then
modules=`ls ./*/inc/pch/precompiled_*.hxx | sed -e s%./%% -e s%/.*%% | uniq`
else
modules="$@"
fi
if [[ "$OSTYPE" == "cygwin" ]]; then
MAKE=/opt/lo/bin/make
else
MAKE=make
fi
function build()
{
local START=$(date +%s.%N)
$MAKE -sr "$module" > /dev/null
status=$?
if [ $status -ne 0 ];
then
# Spurious failures happen.
$MAKE "$module.build" > /dev/null
status=$?
fi
local END=$(date +%s.%N1)
build_time=$(printf %.1f $(echo "$END - $START" | bc))
size="FAILED"
score="FAILED"
if [ $status -eq 0 ];
then
# The total size of the object files.
size="$(du -s workdir/CxxObject/$module/ | awk '{print $1}')"
# Add the pch file size.
filename_rel="workdir/PrecompiledHeader/nodebug/$(basename $header)*"
filename_dbg="workdir/PrecompiledHeader/debug/$(basename $header)*"
if [[ $filename_rel -nt $filename_dbg ]]; then
pch_size="$(du -s $filename_rel | awk '{print $1}' | paste -sd+ | bc)"
else
pch_size="$(du -s $filename_dbg | awk '{print $1}' | paste -sd+ | bc)"
fi
size="$(echo "$pch_size + $size" | bc)"
# Compute a score based on the build time and size.
# The shorter the build time, and smaller disk usage, the higher the score.
score=$(printf %.2f $(echo "10000 / ($build_time * e($size/1048576))" | bc -l))
fi
}
function run()
{
local msg="$module.$libname, ${@:3}, "
printf "$msg"
./bin/update_pch "$module" "$libname" "${@:3}" --silent
status=$?
if [ $status -eq 0 ];
then
build
summary="$build_time, $size, $score"
if [ $status -eq 0 ];
then
new_best_for_cuttof=$(echo "$score > $best_score_for_cuttof" | bc -l)
if [ $new_best_for_cuttof -eq 1 ];
then
best_score_for_cuttof=$score
fi
new_best=$(echo "$score > $best_score" | bc -l)
if [ $new_best -eq 1 ];
then
best_score=$score
best_args="${@:3}"
best_time=$build_time
best_cutoff=$cutoff
summary="$build_time, $size, $score,*"
fi
fi
else
# Skip if pch is not updated.
summary="0, 0, 0"
fi
echo "$summary"
}
function args_to_table()
{
local sys="EXCLUDE"
local mod="EXCLUDE"
local loc="EXCLUDE"
local cutoff=0
IFS=' ' read -r -a aargs <<< $best_args
for index in "${!aargs[@]}"
do
if [ "${aargs[index]}" = "--include:system" ];
then
sys="INCLUDE"
elif [ "${aargs[index]}" = "--exclude:system" ];
then
sys="EXCLUDE"
elif [ "${aargs[index]}" = "--include:module" ];
then
mod="INCLUDE"
elif [ "${aargs[index]}" = "--exclude:module" ];
then
mod="EXCLUDE"
elif [ "${aargs[index]}" = "--include:local" ];
then
loc="INCLUDE"
elif [ "${aargs[index]}" = "--exclude:local" ];
then
loc="EXCLUDE"
elif [[ "${aargs[index]}" == *"cutoff"* ]]
then
cutoff=$(echo "${aargs[index]}" | grep -Po '\-\-cutoff\=\K\d+')
fi
done
local key=$(printf "'%s.%s'" $module $libname)
echo "$(printf " %-36s: (%2d, %s, %s, %s), # %5.1f" $key $cutoff $sys $mod $loc $best_time)"
}
for module in $modules; do
# Build without pch includes as sanity check.
#run "$root" "$module" --cutoff=999
# Build before updating pch.
$MAKE "$module.build" > /dev/null
if [ $? -ne 0 ];
then
# Build with dependencies before updating pch.
echo "Failed to build $module, building known state with dependencies..."
./bin/update_pch.sh "$module" > /dev/null
$MAKE "$module.clean" > /dev/null
$MAKE "$module.all" > /dev/null
if [ $? -ne 0 ];
then
# Build all!
echo "Failed to build $module with dependencies, building all..."
$MAKE > /dev/null
if [ $? -ne 0 ];
then
>&2 echo "Broken build. Please revert changes and try again."
exit 1
fi
fi
fi
# Find pch files in the module to update.
headers=`find $root/$module/ -type f -iname "precompiled_*.hxx"`
# Each pch belongs to a library.
for header in $headers; do
libname=`echo $header | sed -e s/.*precompiled_// -e s/\.hxx//`
#TODO: Backup the header and restore when last tune fails.
# Force update on first try below.
echo "Autotuning $module.$libname..."
./bin/update_pch "$module" "$libname" --cutoff=999 --silent --force
best_score=0
best_args=""
best_time=0
best_cutoff=0
for i in {1..16}; do
cutoff=$i
best_score_for_cuttof=0
#run "$root" "$module" "--cutoff=$i" --include:system --exclude:module --exclude:local
run "$root" "$module" "--cutoff=$i" --exclude:system --exclude:module --exclude:local
#run "$root" "$module" "--cutoff=$i" --include:system --include:module --exclude:local
run "$root" "$module" "--cutoff=$i" --exclude:system --include:module --exclude:local
#run "$root" "$module" "--cutoff=$i" --include:system --exclude:module --include:local
run "$root" "$module" "--cutoff=$i" --exclude:system --exclude:module --include:local
#run "$root" "$module" "--cutoff=$i" --include:system --include:module --include:local
run "$root" "$module" "--cutoff=$i" --exclude:system --include:module --include:local
if [ $i -gt $((best_cutoff+2)) ];
then
score_too_low=$(echo "$best_score_for_cuttof < $best_score / 1.10" | bc -l)
if [ $score_too_low -eq 1 ];
then
echo "Score hit low of $best_score_for_cuttof, well below overall best of $best_score. Stopping."
break;
fi
fi
done
./bin/update_pch "$module" "$libname" $best_args --force --silent
echo "> $module.$libname, $best_args, $best_time, $size, $score"
echo
table+=$'\n'
table+="$(args_to_table)"
done
done
echo "Update the relevant lines in ./bin/update_pch script:"
>&2 echo "$table"
exit 0
|