1#!/bin/bash
2#
3#  Copyright (c) 2019, The OpenThread Authors.
4#  All rights reserved.
5#
6#  Redistribution and use in source and binary forms, with or without
7#  modification, are permitted provided that the following conditions are met:
8#  1. Redistributions of source code must retain the above copyright
9#     notice, this list of conditions and the following disclaimer.
10#  2. Redistributions in binary form must reproduce the above copyright
11#     notice, this list of conditions and the following disclaimer in the
12#     documentation and/or other materials provided with the distribution.
13#  3. Neither the name of the copyright holder nor the
14#     names of its contributors may be used to endorse or promote products
15#     derived from this software without specific prior written permission.
16#
17#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27#  POSSIBILITY OF SUCH DAMAGE.
28#
29
30set -euo pipefail
31
32OT_TMP_DIR=/tmp/ot-size-report
33readonly OT_TMP_DIR
34
35OT_SHA_NEW=${GITHUB_SHA:-$(git rev-parse HEAD)}
36readonly OT_SHA_NEW
37
38OT_SHA_OLD="$(git cat-file -p "${OT_SHA_NEW}" | grep 'parent ' | head -n1 | cut -d' ' -f2)"
39readonly OT_SHA_OLD
40
41OT_REPORT_FILE=/tmp/size_report
42readonly OT_REPORT_FILE
43
44setup_arm_gcc_7()
45{
46    if arm-none-eabi-gcc --version | grep -q 'Arm Embedded Processors 7'; then
47        return 0
48    fi
49
50    (cd /tmp/ \
51        && wget --tries 4 --no-check-certificate --quiet https://developer.arm.com/-/media/Files/downloads/gnu-rm/7-2018q2/gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2 \
52        && tar xjf gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2)
53    export PATH=/tmp/gcc-arm-none-eabi-7-2018-q2-update/bin:$PATH
54
55    arm-none-eabi-gcc --version
56}
57
58setup_ninja_build()
59{
60    sudo apt-get --no-install-recommends install -y ninja-build
61}
62
63setup()
64{
65    setup_arm_gcc_7
66    setup_ninja_build
67}
68
69markdown_init()
70{
71    echo '|  name  |  branch  |  text  | data  | bss  | total |'
72    echo '| :----: | :------: | -----: | ----: | ---: | ----: |'
73}
74
75markdown_size()
76{
77    local name
78    name=$(basename "$1")
79
80    read -r -a size_old <<<"$(size "$1" | awk '{text+=$1} {bss+=$2} {data+=$3} {total+=$4} END {printf "%d %d %d %d", text, bss, data, total}')"
81    read -r -a size_new <<<"$(size "$2" | awk '{text+=$1} {bss+=$2} {data+=$3} {total+=$4} END {printf "%d %d %d %d", text, bss, data, total}')"
82
83    local -a size_diff
84
85    for i in 0 1 2 3; do
86        size_diff[$i]="$((size_new["$i"] - size_old["$i"]))"
87        if [[ ${size_diff["$i"]} != 0 ]]; then
88            size_diff["$i"]=$(printf '%+d' "${size_diff["$i"]}")
89        fi
90    done
91
92    echo "| ${name} | -${OT_SHA_OLD:0:7} | ${size_old[0]} | ${size_old[1]} | ${size_old[2]} | ${size_old[3]} |"
93    echo "|  | +${OT_SHA_NEW:0:7} | ${size_new[0]} | ${size_new[1]} | ${size_new[2]} | ${size_new[3]} |"
94    echo "|  | +/- | ${size_diff[0]} | ${size_diff[1]} | ${size_diff[2]} | ${size_diff[3]} |"
95}
96
97markdown()
98{
99    case "$1" in
100        init)
101            shift
102            markdown_init "$@" >"${OT_REPORT_FILE}"
103            ;;
104        size)
105            shift
106            markdown_size "$@" >>"${OT_REPORT_FILE}"
107            ;;
108        post)
109            mdv "${OT_REPORT_FILE}"
110            ;;
111    esac
112}
113
114nm_size()
115{
116    arm-none-eabi-nm --print-size --defined-only -C "$1" | cut -d' ' -f2- >nmsize_old
117    arm-none-eabi-nm --print-size --defined-only -C "$2" | cut -d' ' -f2- >nmsize_new
118    diff -Nuar nmsize_old nmsize_new || true
119}
120
121size_nrf52840_version()
122{
123    local options=(
124        "-DOT_ANYCAST_LOCATOR=ON"
125        "-DOT_BORDER_AGENT=ON"
126        "-DOT_BORDER_ROUTER=ON"
127        "-DOT_CHANNEL_MANAGER=ON"
128        "-DOT_CHANNEL_MONITOR=ON"
129        "-DOT_COAP=ON"
130        "-DOT_COAPS=ON"
131        "-DOT_COMMISSIONER=ON"
132        "-DOT_DATASET_UPDATER=ON"
133        "-DOT_DHCP6_CLIENT=ON"
134        "-DOT_DHCP6_SERVER=ON"
135        "-DOT_DIAGNOSTIC=ON"
136        "-DOT_DNSSD_SERVER=ON"
137        "-DOT_DNS_CLIENT=ON"
138        "-DOT_ECDSA=ON"
139        "-DOT_FULL_LOGS=ON"
140        "-DOT_JAM_DETECTION=ON"
141        "-DOT_JOINER=ON"
142        "-DOT_LINK_RAW=ON"
143        "-DOT_MAC_FILTER=ON"
144        "-DOT_MESSAGE_USE_HEAP=ON"
145        "-DOT_NETDATA_PUBLISHER=ON"
146        "-DOT_PING_SENDER=ON"
147        "-DOT_SERVICE=ON"
148        "-DOT_SLAAC=ON"
149        "-DOT_SNTP_CLIENT=ON"
150        "-DOT_SRP_CLIENT=ON"
151        "-DOT_SRP_SERVER=ON"
152        "-DOT_TIME_SYNC=ON"
153        "-DOT_UDP_FORWARD=ON"
154        "-DOT_UPTIME=ON"
155    )
156
157    local thread_version=$1
158
159    if [[ ${thread_version} != "1.1" ]]; then
160        options+=(
161            "-DOT_THREAD_VERSION=1.3"
162            "-DOT_BACKBONE_ROUTER=ON"
163            "-DOT_DUA=ON"
164            "-DOT_MLR=ON"
165            "-DOT_CSL_RECEIVER=ON"
166            "-DOT_LINK_METRICS_INITIATOR=ON"
167            "-DOT_LINK_METRICS_SUBJECT=ON"
168        )
169    fi
170
171    rm -rf "${OT_TMP_DIR}"
172
173    local build_dir="build"
174
175    # new commit
176    mkdir -p "${OT_TMP_DIR}/b"
177    script/git-tool clone https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/b"
178    rm -rf "${OT_TMP_DIR}/b/openthread/*" # replace openthread submodule with latest commit
179    git archive "${OT_SHA_NEW}" | tar x -C "${OT_TMP_DIR}/b/openthread"
180
181    (cd "${OT_TMP_DIR}/b" \
182        && OT_CMAKE_BUILD_DIR=${build_dir} script/build nrf52840 UART_trans "${options[@]}")
183
184    # old commit
185    if [[ "${GITHUB_ACTIONS+x}" ]]; then
186        git fetch --depth 1 --no-recurse-submodules origin "${OT_SHA_OLD}"
187    fi
188
189    mkdir -p "${OT_TMP_DIR}/a"
190    git clone https://github.com/openthread/ot-nrf528xx.git "${OT_TMP_DIR}/a"
191    rm -rf "${OT_TMP_DIR}/a/openthread/*" # replace openthread submodule with last commit
192    git archive "${OT_SHA_OLD}" | tar x -C "${OT_TMP_DIR}/a/openthread"
193
194    (cd "${OT_TMP_DIR}/a" \
195        && OT_CMAKE_BUILD_DIR=${build_dir} script/build nrf52840 UART_trans "${options[@]}")
196
197    # rename the generated files to be ready for size-report
198    # shellcheck disable=SC2011
199    (
200        cd "${OT_TMP_DIR}"/a/"${build_dir}"/bin
201        ls | xargs -I{} mv {} {}_"${thread_version}"
202        cd "${OT_TMP_DIR}"/b/"${build_dir}"/bin
203        ls | xargs -I{} mv {} {}_"${thread_version}"
204
205        cd "${OT_TMP_DIR}"/a/"${build_dir}"/lib
206        ls ./*.a | xargs -I{} mv {} {}_"${thread_version}"
207        cd "${OT_TMP_DIR}"/b/"${build_dir}"/lib
208        ls ./*.a | xargs -I{} mv {} {}_"${thread_version}"
209    )
210
211    local bins=(
212        "ot-cli-ftd"
213        "ot-cli-mtd"
214        "ot-ncp-ftd"
215        "ot-ncp-mtd"
216        "ot-rcp"
217    )
218
219    local libs=(
220        "libopenthread-cli-ftd.a"
221        "libopenthread-cli-mtd.a"
222        "libopenthread-ftd.a"
223        "libopenthread-mtd.a"
224        "libopenthread-ncp-ftd.a"
225        "libopenthread-ncp-mtd.a"
226        "libopenthread-rcp.a"
227        "libopenthread-radio.a"
228    )
229
230    for file in "${bins[@]}"; do
231        "${reporter}" size "${OT_TMP_DIR}"/a/"${build_dir}"/bin/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/bin/"${file}"_"${thread_version}"
232        echo nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/bin/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/bin/"${file}"_"${thread_version}"
233        nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/bin/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/bin/"${file}"_"${thread_version}"
234    done
235
236    for file in "${libs[@]}"; do
237        "${reporter}" size "${OT_TMP_DIR}"/a/"${build_dir}"/lib/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/lib/"${file}"_"${thread_version}"
238        echo nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/lib/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/lib/"${file}"_"${thread_version}"
239        nm_size "${OT_TMP_DIR}"/a/"${build_dir}"/lib/"${file}"_"${thread_version}" "${OT_TMP_DIR}"/b/"${build_dir}"/lib/"${file}"_"${thread_version}"
240    done
241}
242
243size_nrf52840()
244{
245    export OT_SHA_NEW OT_SHA_OLD
246
247    local reporter="${OT_SIZE_REPORTER:-markdown}"
248    "${reporter}" init OpenThread
249
250    size_nrf52840_version 1.1
251    size_nrf52840_version 1.3
252
253    "${reporter}" post
254}
255
256main()
257{
258    if [[ $# == 0 ]]; then
259        setup
260        size_nrf52840
261    elif [[ $1 == setup ]]; then
262        setup
263    elif [[ $1 == nrf52840 ]]; then
264        size_nrf52840
265    else
266        echo "USAGE: $0 [setup|nrf52840]"
267        exit 128
268    fi
269}
270
271main "$@"
272