2015-10-17 15:33:43 +02:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
|
|
|
# Copyright (C) 2014 by Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
import argparse
|
|
|
|
import csv
|
|
|
|
import collections
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
import math
|
2015-10-17 15:33:43 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
import matplotlib
|
|
|
|
matplotlib.use('Agg')
|
|
|
|
import matplotlib.font_manager as fm
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
except ImportError:
|
|
|
|
sys.stderr.write("You need python-matplotlib to generate the size graph\n")
|
|
|
|
exit(1)
|
|
|
|
|
support/graph-size: add option to change percentage to group in Others
Currently, we group packages that contribute less then 1%, into the
"Other" category.
However, in some cases, there can be a lot of very comparatively small
packages, and they may not exceed this limit, and so only the "Others"
category would be displayed, which is not nice.
Conversely, if there are a lot of packages, most of which only so
slightly exceeding this limit, then we get all of them in the graph,
which is not nice either.
Add a way for the developers to pass a different cut-off limit. As for
the dependency graph which has BR2_GRAPH_DEPS_OPTS, add the environment
variable BR2_GRAPH_SIZE_OPTS to carry those extra option (in preparation
for more to come, later).
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
[Arnout:
- remove empty base class definition from Config;
- use parser.error instead of ValueError for invalid argument.]
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:27 +02:00
|
|
|
|
|
|
|
class Config:
|
2019-08-17 19:18:29 +02:00
|
|
|
biggest_first = False
|
2019-08-17 19:18:28 +02:00
|
|
|
iec = False
|
support/graph-size: add option to change percentage to group in Others
Currently, we group packages that contribute less then 1%, into the
"Other" category.
However, in some cases, there can be a lot of very comparatively small
packages, and they may not exceed this limit, and so only the "Others"
category would be displayed, which is not nice.
Conversely, if there are a lot of packages, most of which only so
slightly exceeding this limit, then we get all of them in the graph,
which is not nice either.
Add a way for the developers to pass a different cut-off limit. As for
the dependency graph which has BR2_GRAPH_DEPS_OPTS, add the environment
variable BR2_GRAPH_SIZE_OPTS to carry those extra option (in preparation
for more to come, later).
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
[Arnout:
- remove empty base class definition from Config;
- use parser.error instead of ValueError for invalid argument.]
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:27 +02:00
|
|
|
size_limit = 0.01
|
2019-08-17 19:18:30 +02:00
|
|
|
colors = ['#e60004', '#f28e00', '#ffed00', '#940084',
|
|
|
|
'#2e1d86', '#0068b5', '#009836', '#97c000']
|
2015-10-17 15:33:43 +02:00
|
|
|
|
2018-01-22 01:44:33 +01:00
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
#
|
|
|
|
# This function adds a new file to 'filesdict', after checking its
|
|
|
|
# size. The 'filesdict' contain the relative path of the file as the
|
|
|
|
# key, and as the value a tuple containing the name of the package to
|
|
|
|
# which the file belongs and the size of the file.
|
|
|
|
#
|
|
|
|
# filesdict: the dict to which the file is added
|
|
|
|
# relpath: relative path of the file
|
|
|
|
# fullpath: absolute path to the file
|
|
|
|
# pkg: package to which the file belongs
|
|
|
|
#
|
|
|
|
def add_file(filesdict, relpath, abspath, pkg):
|
|
|
|
if not os.path.exists(abspath):
|
|
|
|
return
|
|
|
|
if os.path.islink(abspath):
|
|
|
|
return
|
|
|
|
sz = os.stat(abspath).st_size
|
|
|
|
filesdict[relpath] = (pkg, sz)
|
|
|
|
|
2018-01-22 01:44:33 +01:00
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
#
|
|
|
|
# This function returns a dict where each key is the path of a file in
|
|
|
|
# the root filesystem, and the value is a tuple containing two
|
|
|
|
# elements: the name of the package to which this file belongs and the
|
|
|
|
# size of the file.
|
|
|
|
#
|
|
|
|
# builddir: path to the Buildroot output directory
|
|
|
|
#
|
|
|
|
def build_package_dict(builddir):
|
|
|
|
filesdict = {}
|
2019-08-17 19:18:22 +02:00
|
|
|
with open(os.path.join(builddir, "build", "packages-file-list.txt")) as f:
|
|
|
|
for l in f.readlines():
|
2016-08-09 12:25:11 +02:00
|
|
|
pkg, fpath = l.split(",", 1)
|
2015-10-17 15:33:43 +02:00
|
|
|
# remove the initial './' in each file path
|
|
|
|
fpath = fpath.strip()[2:]
|
|
|
|
fullpath = os.path.join(builddir, "target", fpath)
|
|
|
|
add_file(filesdict, fpath, fullpath, pkg)
|
|
|
|
return filesdict
|
|
|
|
|
2018-01-22 01:44:33 +01:00
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
#
|
|
|
|
# This function builds a dictionary that contains the name of a
|
|
|
|
# package as key, and the size of the files installed by this package
|
|
|
|
# as the value.
|
|
|
|
#
|
|
|
|
# filesdict: dictionary with the name of the files as key, and as
|
|
|
|
# value a tuple containing the name of the package to which the files
|
|
|
|
# belongs, and the size of the file. As returned by
|
|
|
|
# build_package_dict.
|
|
|
|
#
|
|
|
|
# builddir: path to the Buildroot output directory
|
|
|
|
#
|
|
|
|
def build_package_size(filesdict, builddir):
|
|
|
|
pkgsize = collections.defaultdict(int)
|
|
|
|
|
2016-10-24 16:36:39 +02:00
|
|
|
seeninodes = set()
|
2015-10-17 15:33:43 +02:00
|
|
|
for root, _, files in os.walk(os.path.join(builddir, "target")):
|
|
|
|
for f in files:
|
|
|
|
fpath = os.path.join(root, f)
|
|
|
|
if os.path.islink(fpath):
|
|
|
|
continue
|
2016-10-24 16:36:39 +02:00
|
|
|
|
|
|
|
st = os.stat(fpath)
|
|
|
|
if st.st_ino in seeninodes:
|
|
|
|
# hard link
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
seeninodes.add(st.st_ino)
|
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
frelpath = os.path.relpath(fpath, os.path.join(builddir, "target"))
|
2018-01-22 01:44:33 +01:00
|
|
|
if frelpath not in filesdict:
|
2015-10-17 15:33:43 +02:00
|
|
|
print("WARNING: %s is not part of any package" % frelpath)
|
|
|
|
pkg = "unknown"
|
|
|
|
else:
|
|
|
|
pkg = filesdict[frelpath][0]
|
|
|
|
|
2016-10-24 16:36:39 +02:00
|
|
|
pkgsize[pkg] += st.st_size
|
2015-10-17 15:33:43 +02:00
|
|
|
|
|
|
|
return pkgsize
|
|
|
|
|
2018-01-22 01:44:33 +01:00
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
#
|
|
|
|
# Given a dict returned by build_package_size(), this function
|
|
|
|
# generates a pie chart of the size installed by each package.
|
|
|
|
#
|
|
|
|
# pkgsize: dictionary with the name of the package as a key, and the
|
|
|
|
# size as the value, as returned by build_package_size.
|
|
|
|
#
|
|
|
|
# outputf: output file for the graph
|
|
|
|
#
|
|
|
|
def draw_graph(pkgsize, outputf):
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
def size2string(sz):
|
2019-08-17 19:18:28 +02:00
|
|
|
if Config.iec:
|
|
|
|
divider = 1024.0
|
|
|
|
prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti']
|
|
|
|
else:
|
|
|
|
divider = 1000.0
|
|
|
|
prefixes = ['', 'k', 'M', 'G', 'T']
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
while sz > divider and len(prefixes) > 1:
|
|
|
|
prefixes = prefixes[1:]
|
|
|
|
sz = sz/divider
|
|
|
|
# precision is made so that there are always at least three meaningful
|
|
|
|
# digits displayed (e.g. '3.14' and '10.4', not just '3' and '10')
|
|
|
|
precision = int(2-math.floor(math.log10(sz))) if sz < 1000 else 0
|
|
|
|
return '{:.{prec}f} {}B'.format(sz, prefixes[0], prec=precision)
|
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
total = sum(pkgsize.values())
|
|
|
|
labels = []
|
|
|
|
values = []
|
|
|
|
other_value = 0
|
2019-08-17 19:18:25 +02:00
|
|
|
unknown_value = 0
|
2019-08-17 19:18:29 +02:00
|
|
|
for (p, sz) in sorted(pkgsize.items(), key=lambda x: x[1],
|
|
|
|
reverse=Config.biggest_first):
|
support/graph-size: add option to change percentage to group in Others
Currently, we group packages that contribute less then 1%, into the
"Other" category.
However, in some cases, there can be a lot of very comparatively small
packages, and they may not exceed this limit, and so only the "Others"
category would be displayed, which is not nice.
Conversely, if there are a lot of packages, most of which only so
slightly exceeding this limit, then we get all of them in the graph,
which is not nice either.
Add a way for the developers to pass a different cut-off limit. As for
the dependency graph which has BR2_GRAPH_DEPS_OPTS, add the environment
variable BR2_GRAPH_SIZE_OPTS to carry those extra option (in preparation
for more to come, later).
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
[Arnout:
- remove empty base class definition from Config;
- use parser.error instead of ValueError for invalid argument.]
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:27 +02:00
|
|
|
if sz < (total * Config.size_limit):
|
2015-10-17 15:33:43 +02:00
|
|
|
other_value += sz
|
2019-08-17 19:18:25 +02:00
|
|
|
elif p == "unknown":
|
|
|
|
unknown_value = sz
|
2015-10-17 15:33:43 +02:00
|
|
|
else:
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
labels.append("%s (%s)" % (p, size2string(sz)))
|
2015-10-17 15:33:43 +02:00
|
|
|
values.append(sz)
|
2019-08-17 19:18:25 +02:00
|
|
|
if unknown_value != 0:
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
labels.append("Unknown (%s)" % (size2string(unknown_value)))
|
2019-08-17 19:18:25 +02:00
|
|
|
values.append(unknown_value)
|
2019-08-17 19:18:24 +02:00
|
|
|
if other_value != 0:
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
labels.append("Other (%s)" % (size2string(other_value)))
|
2019-08-17 19:18:24 +02:00
|
|
|
values.append(other_value)
|
2015-10-17 15:33:43 +02:00
|
|
|
|
|
|
|
plt.figure()
|
|
|
|
patches, texts, autotexts = plt.pie(values, labels=labels,
|
|
|
|
autopct='%1.1f%%', shadow=True,
|
support/graph-size: add option to change percentage to group in Others
Currently, we group packages that contribute less then 1%, into the
"Other" category.
However, in some cases, there can be a lot of very comparatively small
packages, and they may not exceed this limit, and so only the "Others"
category would be displayed, which is not nice.
Conversely, if there are a lot of packages, most of which only so
slightly exceeding this limit, then we get all of them in the graph,
which is not nice either.
Add a way for the developers to pass a different cut-off limit. As for
the dependency graph which has BR2_GRAPH_DEPS_OPTS, add the environment
variable BR2_GRAPH_SIZE_OPTS to carry those extra option (in preparation
for more to come, later).
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
[Arnout:
- remove empty base class definition from Config;
- use parser.error instead of ValueError for invalid argument.]
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:27 +02:00
|
|
|
colors=Config.colors)
|
2015-10-17 15:33:43 +02:00
|
|
|
# Reduce text size
|
|
|
|
proptease = fm.FontProperties()
|
|
|
|
proptease.set_size('xx-small')
|
|
|
|
plt.setp(autotexts, fontproperties=proptease)
|
|
|
|
plt.setp(texts, fontproperties=proptease)
|
|
|
|
|
|
|
|
plt.suptitle("Filesystem size per package", fontsize=18, y=.97)
|
support/graph-size: display human-readable size
Currently, we forcibly report sizes in multiple of Kilobytes. In some
big configurations, the sizes of the system as a whole, as well as that
of individual packages, may exceed megabytes, and when some artistic
assets get used, even the gigabyte may get exceed.
These big sizes are not easy to read when expressed in kilobytes.
Additionally, some very small packages might have sizes below the
kilobyte (and when we can specify the cut-off grouping size, they may
get reported), and thus the size displayed for those would be 0 kB.
Add a helper function that can format a floating-point size into a
string with all the appropriate formatting:
- there are at least 3 meaningfull digits visible, i.e. we display
"3.14" or "10.4" instead of just "3" or "10", but for big number we
don't care about too many precision either, so we report "100" or
"1000", not "100.42" or "1000.27";
- the proper SI prefix is appended, if needed.
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:26 +02:00
|
|
|
plt.title("Total filesystem size: %s" % (size2string(total)), fontsize=10,
|
2019-08-17 19:18:22 +02:00
|
|
|
y=.96)
|
2015-10-17 15:33:43 +02:00
|
|
|
plt.savefig(outputf)
|
|
|
|
|
2018-01-22 01:44:33 +01:00
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
#
|
|
|
|
# Generate a CSV file with statistics about the size of each file, its
|
|
|
|
# size contribution to the package and to the overall system.
|
|
|
|
#
|
|
|
|
# filesdict: dictionary with the name of the files as key, and as
|
|
|
|
# value a tuple containing the name of the package to which the files
|
|
|
|
# belongs, and the size of the file. As returned by
|
|
|
|
# build_package_dict.
|
|
|
|
#
|
|
|
|
# pkgsize: dictionary with the name of the package as a key, and the
|
|
|
|
# size as the value, as returned by build_package_size.
|
|
|
|
#
|
|
|
|
# outputf: output CSV file
|
|
|
|
#
|
|
|
|
def gen_files_csv(filesdict, pkgsizes, outputf):
|
|
|
|
total = 0
|
|
|
|
for (p, sz) in pkgsizes.items():
|
|
|
|
total += sz
|
|
|
|
with open(outputf, 'w') as csvfile:
|
|
|
|
wr = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
|
|
|
|
wr.writerow(["File name",
|
|
|
|
"Package name",
|
|
|
|
"File size",
|
|
|
|
"Package size",
|
|
|
|
"File size in package (%)",
|
|
|
|
"File size in system (%)"])
|
|
|
|
for f, (pkgname, filesize) in filesdict.items():
|
|
|
|
pkgsize = pkgsizes[pkgname]
|
2017-11-28 04:37:07 +01:00
|
|
|
|
|
|
|
if pkgsize == 0:
|
|
|
|
percent_pkg = 0
|
|
|
|
else:
|
|
|
|
percent_pkg = float(filesize) / pkgsize * 100
|
|
|
|
|
|
|
|
percent_total = float(filesize) / total * 100
|
|
|
|
|
2015-10-17 15:33:43 +02:00
|
|
|
wr.writerow([f, pkgname, filesize, pkgsize,
|
2017-11-28 04:37:07 +01:00
|
|
|
"%.1f" % percent_pkg,
|
|
|
|
"%.1f" % percent_total])
|
2015-10-17 15:33:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Generate a CSV file with statistics about the size of each package,
|
|
|
|
# and their size contribution to the overall system.
|
|
|
|
#
|
|
|
|
# pkgsize: dictionary with the name of the package as a key, and the
|
|
|
|
# size as the value, as returned by build_package_size.
|
|
|
|
#
|
|
|
|
# outputf: output CSV file
|
|
|
|
#
|
|
|
|
def gen_packages_csv(pkgsizes, outputf):
|
|
|
|
total = sum(pkgsizes.values())
|
|
|
|
with open(outputf, 'w') as csvfile:
|
|
|
|
wr = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL)
|
2019-08-17 19:18:22 +02:00
|
|
|
wr.writerow(["Package name", "Package size",
|
|
|
|
"Package size in system (%)"])
|
2015-10-17 15:33:43 +02:00
|
|
|
for (pkg, size) in pkgsizes.items():
|
|
|
|
wr.writerow([pkg, size, "%.1f" % (float(size) / total * 100)])
|
|
|
|
|
2018-01-22 01:44:33 +01:00
|
|
|
|
2019-08-17 19:18:28 +02:00
|
|
|
#
|
|
|
|
# Our special action for --iec, --binary, --si, --decimal
|
|
|
|
#
|
|
|
|
class PrefixAction(argparse.Action):
|
|
|
|
def __init__(self, option_strings, dest, **kwargs):
|
|
|
|
for key in ["type", "nargs"]:
|
|
|
|
if key in kwargs:
|
|
|
|
raise ValueError('"{}" not allowed'.format(key))
|
|
|
|
super(PrefixAction, self).__init__(option_strings, dest, nargs=0,
|
|
|
|
type=bool, **kwargs)
|
|
|
|
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
|
|
setattr(namespace, self.dest, option_string in ["--iec", "--binary"])
|
|
|
|
|
|
|
|
|
2019-08-17 19:18:23 +02:00
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser(description='Draw size statistics graphs')
|
|
|
|
|
|
|
|
parser.add_argument("--builddir", '-i', metavar="BUILDDIR", required=True,
|
|
|
|
help="Buildroot output directory")
|
|
|
|
parser.add_argument("--graph", '-g', metavar="GRAPH",
|
|
|
|
help="Graph output file (.pdf or .png extension)")
|
|
|
|
parser.add_argument("--file-size-csv", '-f', metavar="FILE_SIZE_CSV",
|
|
|
|
help="CSV output file with file size statistics")
|
|
|
|
parser.add_argument("--package-size-csv", '-p', metavar="PKG_SIZE_CSV",
|
|
|
|
help="CSV output file with package size statistics")
|
2019-08-17 19:18:29 +02:00
|
|
|
parser.add_argument("--biggest-first", action='store_true',
|
|
|
|
help="Sort packages in decreasing size order, " +
|
|
|
|
"rather than in increasing size order")
|
2019-08-17 19:18:28 +02:00
|
|
|
parser.add_argument("--iec", "--binary", "--si", "--decimal",
|
|
|
|
action=PrefixAction,
|
|
|
|
help="Use IEC (binary, powers of 1024) or SI (decimal, "
|
|
|
|
"powers of 1000, the default) prefixes")
|
support/graph-size: add option to change percentage to group in Others
Currently, we group packages that contribute less then 1%, into the
"Other" category.
However, in some cases, there can be a lot of very comparatively small
packages, and they may not exceed this limit, and so only the "Others"
category would be displayed, which is not nice.
Conversely, if there are a lot of packages, most of which only so
slightly exceeding this limit, then we get all of them in the graph,
which is not nice either.
Add a way for the developers to pass a different cut-off limit. As for
the dependency graph which has BR2_GRAPH_DEPS_OPTS, add the environment
variable BR2_GRAPH_SIZE_OPTS to carry those extra option (in preparation
for more to come, later).
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
[Arnout:
- remove empty base class definition from Config;
- use parser.error instead of ValueError for invalid argument.]
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:27 +02:00
|
|
|
parser.add_argument("--size-limit", "-l", type=float,
|
|
|
|
help='Under this size ratio, files are accounted to ' +
|
|
|
|
'the generic "Other" package. Default: 0.01 (1%%)')
|
2019-08-17 19:18:23 +02:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
2019-08-17 19:18:29 +02:00
|
|
|
Config.biggest_first = args.biggest_first
|
2019-08-17 19:18:28 +02:00
|
|
|
Config.iec = args.iec
|
support/graph-size: add option to change percentage to group in Others
Currently, we group packages that contribute less then 1%, into the
"Other" category.
However, in some cases, there can be a lot of very comparatively small
packages, and they may not exceed this limit, and so only the "Others"
category would be displayed, which is not nice.
Conversely, if there are a lot of packages, most of which only so
slightly exceeding this limit, then we get all of them in the graph,
which is not nice either.
Add a way for the developers to pass a different cut-off limit. As for
the dependency graph which has BR2_GRAPH_DEPS_OPTS, add the environment
variable BR2_GRAPH_SIZE_OPTS to carry those extra option (in preparation
for more to come, later).
Signed-off-by: Yann E. MORIN <yann.morin.1998@free.fr>
Cc: Thomas De Schampheleire <thomas.de_schampheleire@nokia.com>
[Arnout:
- remove empty base class definition from Config;
- use parser.error instead of ValueError for invalid argument.]
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
2019-08-17 19:18:27 +02:00
|
|
|
if args.size_limit is not None:
|
|
|
|
if args.size_limit < 0.0 or args.size_limit > 1.0:
|
|
|
|
parser.error("--size-limit must be in [0.0..1.0]")
|
|
|
|
Config.size_limit = args.size_limit
|
|
|
|
|
2019-08-17 19:18:23 +02:00
|
|
|
# Find out which package installed what files
|
|
|
|
pkgdict = build_package_dict(args.builddir)
|
|
|
|
|
|
|
|
# Collect the size installed by each package
|
|
|
|
pkgsize = build_package_size(pkgdict, args.builddir)
|
|
|
|
|
|
|
|
if args.graph:
|
|
|
|
draw_graph(pkgsize, args.graph)
|
|
|
|
if args.file_size_csv:
|
|
|
|
gen_files_csv(pkgdict, pkgsize, args.file_size_csv)
|
|
|
|
if args.package_size_csv:
|
|
|
|
gen_packages_csv(pkgsize, args.package_size_csv)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|