xref: /OK3568_Linux_fs/yocto/poky/scripts/contrib/bb-perf/buildstats.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/bin/bash
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# Copyright (c) 2011, Intel Corporation.
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-or-later
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun# DESCRIPTION
8*4882a593Smuzhiyun# Given 'buildstats' data (generate by bitbake when setting
9*4882a593Smuzhiyun# USER_CLASSES ?= "buildstats" on local.conf), task names and a stats values
10*4882a593Smuzhiyun# (these are the ones preset on the buildstats files), outputs
11*4882a593Smuzhiyun# '<task> <recipe> <value_1> <value_2> ... <value_n>'. The units are the ones
12*4882a593Smuzhiyun# defined at buildstats, which in turn takes data from /proc/[pid] files
13*4882a593Smuzhiyun#
14*4882a593Smuzhiyun# Some useful pipelines
15*4882a593Smuzhiyun#
16*4882a593Smuzhiyun# 1. Tasks with largest stime (Amount of time that this process has been scheduled
17*4882a593Smuzhiyun#    in kernel mode) values
18*4882a593Smuzhiyun# $ buildstats.sh -b <buildstats> -s stime | sort -k3 -n -r | head
19*4882a593Smuzhiyun#
20*4882a593Smuzhiyun# 2. Min, max, sum utime (Amount  of  time  that  this process has been scheduled
21*4882a593Smuzhiyun#    in user mode) per task (in needs GNU datamash)
22*4882a593Smuzhiyun# $ buildstats.sh -b <buildstats> -s utime | datamash -t' ' -g1 min 3 max 3 sum 3 | sort -k4 -n -r
23*4882a593Smuzhiyun#
24*4882a593Smuzhiyun# AUTHORS
25*4882a593Smuzhiyun# Leonardo Sandoval <leonardo.sandoval.gonzalez@linux.intel.com>
26*4882a593Smuzhiyun#
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun# Stats, by type
29*4882a593SmuzhiyunTIME="utime:stime:cutime:cstime"
30*4882a593SmuzhiyunIO="IO wchar:IO write_bytes:IO syscr:IO read_bytes:IO rchar:IO syscw:IO cancelled_write_bytes"
31*4882a593SmuzhiyunRUSAGE="rusage ru_utime:rusage ru_stime:rusage ru_maxrss:rusage ru_minflt:rusage ru_majflt:\
32*4882a593Smuzhiyunrusage ru_inblock:rusage ru_oublock:rusage ru_nvcsw:rusage ru_nivcsw"
33*4882a593Smuzhiyun
34*4882a593SmuzhiyunCHILD_RUSAGE="Child rusage ru_utime:Child rusage ru_stime:Child rusage ru_maxrss:Child rusage ru_minflt:\
35*4882a593SmuzhiyunChild rusage ru_majflt:Child rusage ru_inblock:Child rusage ru_oublock:Child rusage ru_nvcsw:\
36*4882a593SmuzhiyunChild rusage ru_nivcsw"
37*4882a593Smuzhiyun
38*4882a593SmuzhiyunBS_DIR="tmp/buildstats"
39*4882a593SmuzhiyunRECIPE=""
40*4882a593SmuzhiyunTASKS="compile:configure:fetch:install:patch:populate_lic:populate_sysroot:unpack"
41*4882a593SmuzhiyunSTATS="$TIME"
42*4882a593SmuzhiyunACCUMULATE=""
43*4882a593SmuzhiyunHEADER="" # No header by default
44*4882a593Smuzhiyun
45*4882a593Smuzhiyunfunction usage {
46*4882a593SmuzhiyunCMD=$(basename $0)
47*4882a593Smuzhiyuncat <<EOM
48*4882a593SmuzhiyunUsage: $CMD [-b buildstats_dir] [-t do_task]
49*4882a593Smuzhiyun  -b buildstats The path where the folder resides
50*4882a593Smuzhiyun                (default: "$BS_DIR")
51*4882a593Smuzhiyun  -r recipe     The recipe to be computed
52*4882a593Smuzhiyun  -t tasks      The tasks to be computed
53*4882a593Smuzhiyun                (default: "$TASKS")
54*4882a593Smuzhiyun  -s stats      The stats to be matched. Options: TIME, IO, RUSAGE, CHILD_RUSAGE
55*4882a593Smuzhiyun                or any other defined buildstat separated by colons, i.e. stime:utime
56*4882a593Smuzhiyun                (default: "$STATS")
57*4882a593Smuzhiyun                Default stat sets:
58*4882a593Smuzhiyun                    TIME=$TIME
59*4882a593Smuzhiyun                    IO=$IO
60*4882a593Smuzhiyun                    RUSAGE=$RUSAGE
61*4882a593Smuzhiyun                    CHILD_RUSAGE=$CHILD_RUSAGE
62*4882a593Smuzhiyun  -a            Accumulate all stats values for found recipes
63*4882a593Smuzhiyun  -h            Display this help message
64*4882a593SmuzhiyunEOM
65*4882a593Smuzhiyun}
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun# Parse and validate arguments
68*4882a593Smuzhiyunwhile getopts "b:r:t:s:aHh" OPT; do
69*4882a593Smuzhiyun    case $OPT in
70*4882a593Smuzhiyun    b)
71*4882a593Smuzhiyun        BS_DIR="$OPTARG"
72*4882a593Smuzhiyun        ;;
73*4882a593Smuzhiyun    r)
74*4882a593Smuzhiyun        RECIPE="$OPTARG"
75*4882a593Smuzhiyun        ;;
76*4882a593Smuzhiyun    t)
77*4882a593Smuzhiyun        TASKS="$OPTARG"
78*4882a593Smuzhiyun        ;;
79*4882a593Smuzhiyun    s)
80*4882a593Smuzhiyun        STATS="$OPTARG"
81*4882a593Smuzhiyun        ;;
82*4882a593Smuzhiyun    a)
83*4882a593Smuzhiyun        ACCUMULATE="y"
84*4882a593Smuzhiyun        ;;
85*4882a593Smuzhiyun    H)
86*4882a593Smuzhiyun        HEADER="y"
87*4882a593Smuzhiyun        ;;
88*4882a593Smuzhiyun    h)
89*4882a593Smuzhiyun        usage
90*4882a593Smuzhiyun        exit 0
91*4882a593Smuzhiyun        ;;
92*4882a593Smuzhiyun    *)
93*4882a593Smuzhiyun        usage
94*4882a593Smuzhiyun        exit 1
95*4882a593Smuzhiyun        ;;
96*4882a593Smuzhiyun    esac
97*4882a593Smuzhiyundone
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun# Ensure the buildstats folder exists
100*4882a593Smuzhiyunif [ ! -d "$BS_DIR" ]; then
101*4882a593Smuzhiyun    echo "ERROR: $BS_DIR does not exist"
102*4882a593Smuzhiyun    usage
103*4882a593Smuzhiyun    exit 1
104*4882a593Smuzhiyunfi
105*4882a593Smuzhiyun
106*4882a593Smuzhiyunstats=""
107*4882a593SmuzhiyunIFS=":"
108*4882a593Smuzhiyunfor stat in ${STATS}; do
109*4882a593Smuzhiyun    case $stat in
110*4882a593Smuzhiyun        TIME)
111*4882a593Smuzhiyun            stats="${stats}:${TIME}"
112*4882a593Smuzhiyun            ;;
113*4882a593Smuzhiyun        IO)
114*4882a593Smuzhiyun            stats="${stats}:${IO}"
115*4882a593Smuzhiyun            ;;
116*4882a593Smuzhiyun        RUSAGE)
117*4882a593Smuzhiyun            stats="${stats}:${RUSAGE}"
118*4882a593Smuzhiyun            ;;
119*4882a593Smuzhiyun        CHILD_RUSAGE)
120*4882a593Smuzhiyun            stats="${stats}:${CHILD_RUSAGE}"
121*4882a593Smuzhiyun            ;;
122*4882a593Smuzhiyun        *)
123*4882a593Smuzhiyun            stats="${STATS}"
124*4882a593Smuzhiyun            ;;
125*4882a593Smuzhiyun    esac
126*4882a593Smuzhiyundone
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun# remove possible colon at the beginning
129*4882a593Smuzhiyunstats="$(echo "$stats" | sed -e 's/^://1')"
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun# Provide a header if required by the user
132*4882a593Smuzhiyunif [ -n "$HEADER" ] ; then
133*4882a593Smuzhiyun    if [ -n "$ACCUMULATE" ]; then
134*4882a593Smuzhiyun        echo "task:recipe:accumulated(${stats//:/;})"
135*4882a593Smuzhiyun    else
136*4882a593Smuzhiyun        echo "task:recipe:$stats"
137*4882a593Smuzhiyun    fi
138*4882a593Smuzhiyunfi
139*4882a593Smuzhiyun
140*4882a593Smuzhiyunfor task in ${TASKS}; do
141*4882a593Smuzhiyun    task="do_${task}"
142*4882a593Smuzhiyun    for file in $(find ${BS_DIR} -type f -path *${RECIPE}*/${task} | awk 'BEGIN{ ORS=""; OFS=":" } { print $0,"" }'); do
143*4882a593Smuzhiyun        recipe="$(basename $(dirname $file))"
144*4882a593Smuzhiyun        times=""
145*4882a593Smuzhiyun        for stat in ${stats}; do
146*4882a593Smuzhiyun            [ -z "$stat" ] && { echo "empty stats"; }
147*4882a593Smuzhiyun            time=$(sed -n -e "s/^\($stat\): \\(.*\\)/\\2/p" $file)
148*4882a593Smuzhiyun            # in case the stat is not present, set the value as NA
149*4882a593Smuzhiyun            [ -z "$time" ] && { time="NA"; }
150*4882a593Smuzhiyun            # Append it to times
151*4882a593Smuzhiyun            if [ -z "$times" ]; then
152*4882a593Smuzhiyun                times="${time}"
153*4882a593Smuzhiyun            else
154*4882a593Smuzhiyun                times="${times} ${time}"
155*4882a593Smuzhiyun            fi
156*4882a593Smuzhiyun        done
157*4882a593Smuzhiyun        if [ -n "$ACCUMULATE" ]; then
158*4882a593Smuzhiyun            IFS=' '; valuesarray=(${times}); IFS=':'
159*4882a593Smuzhiyun            times=0
160*4882a593Smuzhiyun            for value in "${valuesarray[@]}"; do
161*4882a593Smuzhiyun                [ "$value" == "NA" ] && { echo "ERROR: stat is not present."; usage; exit 1; }
162*4882a593Smuzhiyun                times=$(( $times + $value ))
163*4882a593Smuzhiyun            done
164*4882a593Smuzhiyun        fi
165*4882a593Smuzhiyun        echo "${task} ${recipe} ${times}"
166*4882a593Smuzhiyun    done
167*4882a593Smuzhiyundone
168