File: performance-run.sh

package info (click to toggle)
glib2.0 2.87.2-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 67,436 kB
  • sloc: ansic: 546,337; python: 9,937; sh: 1,612; xml: 1,511; perl: 1,223; cpp: 551; makefile: 308; javascript: 11
file content (228 lines) | stat: -rwxr-xr-x 8,185 bytes parent folder | download | duplicates (3)
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
#!/bin/bash

# Copyright (C) 2024 Red Hat, Inc.
#
# SPDX-License-Identifier: LGPL-2.1-or-later

# Run ./build/gobject/tests/performance/performance for several commits
# and compare the result.
#
# Howto:
#
# 1) configure the build. For example run
#     $ git clean -fdx
#     $ meson build -Dprefix=/tmp/glib/ -Db_lto=true --buildtype release -Ddebug=false
#    Beware, that running the script will check out other commits,
#    build the tree and run `ninja install`. Don't have important
#    work there.
#
#    Consider setting `echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`
#    and check `watch cat /sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_cur_freq`.
#
# 2) run the script. Set $COMMITS to the list of commit sha's to test.
#    Environment variables:
#      COMMITS: list of git references to test.
#      PATCH: if set, after checking out each commit, run `git cherry-pick $PATCH`
#        before building.
#      PREPARE_CMD: if set, invoke $PREPARE_CMD after checking out commit. Can be used
#        to patch the sources.
#      PERF: if set, run performance test via perf. Set for example, `PERF="perf stat -r 10 -B"`
#        When setting `PERF`, you probably also want to set GLIB_PERFORMANCE_FACTOR,
#        which depends on the test (run the test in verbose mode to find a suitable factor).
#      STRIP: if set to 1, call `strip` on the library and binary before running.
#   Arguments: arguments are directly passed to performance. For example try "-s 1".
#
# Example:
#
#    # once:
#    git clean -fdx
#    meson build -Dprefix=/tmp/glib/ -Db_lto=true --buildtype release -Ddebug=false
#
#    # test:
#    COMMIT_END=my-test-branch
#    COMMIT_START="$(git merge-base origin/main "$COMMIT_END")"
#    PERF="" PATCH="" COMMITS=" $COMMIT_START $COMMIT_END " /tmp/performance-run.sh -q -s 5
#    PERF="" PATCH="" COMMITS=" $COMMIT_START $( git log --reverse --pretty=%H "$COMMIT_START..$COMMIT_END" ) " /tmp/performance-run.sh -q -s 5
#
#    GLIB_PERFORMANCE_FACTOR=1 PERF='perf stat -r 3 -B' PATCH="" COMMITS=" $COMMIT_START $COMMIT_END " /tmp/performance-run.sh -q -s 1 property-get

set -e

usage() {
    sed -n '/^# Run /,/^$/ s/^#\( \(.*\)\|\)$/\2/p' "$0"
}

if [[ "$#" -eq 1 && ( "$1" == "-h" || "$1" == "--help" ) ]]; then
    usage
    exit 0
fi

die() {
    printf "%s\n" "$*"
    exit 1
}

die_with_last_cmd() {
    cat /tmp/glib-performance-last-cmd || :
    die "$@"
}

read -ra COMMITS_V -d '' <<<"$COMMITS" || :

[ "${#COMMITS_V[@]}" -gt 0 ] || die "Must set \$COMMITS"

COMMITS_SHA=()
for commit in "${COMMITS_V[@]}" ; do
    c="$(git rev-parse --verify "$commit^{commit}")" || die "invalid git reference \"$commit\""
    COMMITS_SHA+=( "$c" )
done

_list_commits() {
    local PREFIX="$1"
    local idx
    local I

    I=0
    for idx in "${!COMMITS_V[@]}" ; do
        I=$((I+1))
        echo "${PREFIX}[$I] $(git log -n1 --oneline "${COMMITS_SHA[$idx]}") (${COMMITS_V[$idx]})"
    done
}

cat << EOF

Testing commits:

$(_list_commits "    ")

  \$ meson build -Dprefix=/tmp/glib/ -Db_lto=true --buildtype release -Ddebug=false
  \$ PATCH=$(printf '%q' "$PATCH") \\
    PREPARE_CMD=$(printf '%q' "$PREPARE_CMD") \\
    PERF=$(printf '%q' "$PERF") \\
    GLIB_PERFORMANCE_FACTOR=$(printf '%q' "$GLIB_PERFORMANCE_FACTOR") \\
    STRIP=$(printf '%q' "$STRIP") \\
    COMMITS=$(printf '%q' "$COMMITS") \\
       $0$(printf ' %q' "$@")

EOF

_get_timing() {
    local LINE_NUM="$1"
    local LINE_PREFIX="$2"
    local FILE="$3"

    sed -n "$LINE_NUM s/^$LINE_PREFIX: //p" "$FILE"
}

_perc() {
    awk -v n1="$1" -v n2="$2" 'BEGIN { printf("%+0.3g%\n", (n2 - n1) / n1 * 100.0); }'
}

_cmd() {
    # printf '   $' ; printf ' %s' "$@" ; printf '\n'
    "$@"
}


I=0
for idx in "${!COMMITS_V[@]}" ; do
    commit="${COMMITS_V[$idx]}"
    commit_sha="${COMMITS_SHA[$idx]}"
    I=$((I+1))
    echo -n ">>> [$I] test [ $(git log -n1 --oneline "$commit") ]"
    git checkout -f "$commit_sha" &> /tmp/glib-performance-last-cmd || (echo ...; die_with_last_cmd "Failure to checkout \"$commit\"")
    touch glib/gdataset.c gobject/gobject.c gobject/tests/performance/performance.c
    if [ "$PATCH" != "" ] ; then
        read -ra PATCH_ARR -d '' <<<"$PATCH" || :
        for p in "${PATCH_ARR[@]}" ; do
            git cherry-pick "$p" &> /tmp/glib-performance-last-cmd || (echo ...; die_with_last_cmd "Failure to cherry-pick \"$PATCH\"")
        done
    fi
    if [ "$PREPARE_CMD" != "" ] ; then
        I="$I" COMMIT="$commit" "$PREPARE_CMD" &> /tmp/glib-performance-last-cmd || (echo ...; die_with_last_cmd "\$PREPARE_CMD failed")
    fi
    echo " commit $(git rev-parse --verify HEAD) > /tmp/glib-performance-output.$I"
    ( ninja -C build || ninja -C build ) &> /tmp/glib-performance-last-cmd || die_with_last_cmd "Failure to build with \`ninja -C build\`"
    ninja -C build install &> /tmp/glib-performance-last-cmd || die_with_last_cmd "FAilure to install with \`ninja -C build install\`"
    if [ "$STRIP" = 1 ] ; then
        strip ./build/gobject/libgobject-2.0.so ./build/glib/libglib-2.0.so.0 ./build/gobject/tests/performance/performance
    fi

    # ls -lad -L \
    #     ./build/gobject/libgobject-2.0.so \
    #     ./build/glib/libglib-2.0.so \
    #     ./build/gobject/tests/performance/performance
    # ldd ./build/gobject/tests/performance/performance

    sleep 2
    (
        if [ -z "$PERF" ] ; then
            TESTRUN="$I" TESTCOMMIT="$commit" ./build/gobject/tests/performance/performance "$@"
        else
            TESTRUN="$I" TESTCOMMIT="$commit" $PERF ./build/gobject/tests/performance/performance "$@"
        fi
    ) |& tee "/tmp/glib-performance-output.$I" || :
    [ "${PIPESTATUS[0]}" -eq 0 ] || die "Performance test failed"
done

merge_output() {
    (
        declare -A RES
        LINE_NUM=0
        OLD_IFS="$IFS"
        while IFS=$'\n' read -r LINE ; do
            LINE="${LINE:1}"
            LINE_NUM=$((LINE_NUM+1))
            line_regex='^([a-zA-Z0-9].*): +([0-9.]+)$'

            if [[ "$LINE" =~ $line_regex ]] ; then
                LINE_PREFIX="${BASH_REMATCH[1]}"
                T1="${BASH_REMATCH[2]}"
                echo -n "$LINE_PREFIX: $T1"
                RES["$LINE_PREFIX"]="${RES[$LINE_PREFIX]} $T1"
                for J in $(seq 2 "${#COMMITS_V[@]}") ; do
                    T="$(_get_timing "$LINE_NUM" "$LINE_PREFIX" "/tmp/glib-performance-output.$J")"
                    echo -n "	$T ($(_perc "$T1" "$T"))"
                    RES["$LINE_PREFIX"]="${RES[$LINE_PREFIX]} $T"
                done
                echo
                continue
            fi
            if [ -n "$PERF" ] ; then
                if [[ "$LINE" == *"seconds time elapsed"* ]] ; then
                    echo "[1] $LINE"
                    for J in $(seq 2 "${#COMMITS_V[@]}") ; do
                        echo "[$J] $(sed -n "$LINE_NUM s/seconds time elapsed/\\0/p" "/tmp/glib-performance-output.$J")"
                    done
                    continue
                fi
            fi
            echo "$LINE"
        done < <( sed 's/^/x/' "/tmp/glib-performance-output.1" )

        IFS="$OLD_IFS"
        if [ -n "$PERF" ] ; then
            for LINE_PREFIX in "${!RES[@]}"; do
                # The values are interleaved. To cumbersome to process in bash.
                read -ra T -d '' <<<"${RES[$LINE_PREFIX]}" || :
                read -ra T_SORTED -d '' < <(printf '%s\n' "${T[@]}" | awk -v C="${#COMMITS_V[@]}" '{ print (1 + (NR-1) % C) " " $0 }' | sort -n -s | sed 's/^[0-9]\+ *//' ) || :
                NGROUP="$(( "${#T_SORTED[@]}" / "${#COMMITS_V[@]}" ))"
                echo -n "$LINE_PREFIX: "
                SEP=''
                for J in $(seq 0 "${#T_SORTED[@]}") ; do
                    echo -n "$SEP${T_SORTED[$J]}"
                    if [ $(( (J+1) % NGROUP )) = 0 ]; then
                        echo -n "  ;  "
                        SEP=''
                    else
                        SEP=" , "
                    fi
                done
                echo
            done
        fi
    ) | tee "/tmp/glib-performance-output.all"
}

echo ">>> combined result > /tmp/glib-performance-output.all"
merge_output