buildhistory: improve performance of image info collection

Reduce the number of calls to the packaging tool, especially in the case
of rpm, using helper utilities to gather the required information more
efficiently where possible.

(From OE-Core rev: d0b8a98c5b46c305afd389fc862b3bf0c6f1eaab)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Paul Eggleton
2012-07-23 07:59:11 +01:00
committed by Richard Purdie
parent 98b0f956e7
commit 20ad566d60
5 changed files with 162 additions and 101 deletions

View File

@@ -285,48 +285,43 @@ buildhistory_get_image_installed() {
mkdir -p ${BUILDHISTORY_DIR_IMAGE} mkdir -p ${BUILDHISTORY_DIR_IMAGE}
# Get list of installed packages # Get list of installed packages
list_installed_packages | sort > ${BUILDHISTORY_DIR_IMAGE}/installed-package-names.txt pkgcache="${BUILDHISTORY_DIR_IMAGE}/installed-packages.tmp"
INSTALLED_PKGS=`cat ${BUILDHISTORY_DIR_IMAGE}/installed-package-names.txt` list_installed_packages file | sort > $pkgcache
# Produce installed package file and size lists and dependency graph cat $pkgcache | awk '{ print $1 }' > ${BUILDHISTORY_DIR_IMAGE}/installed-package-names.txt
echo -n > ${BUILDHISTORY_DIR_IMAGE}/installed-packages.txt cat $pkgcache | awk '{ print $2 }' | xargs -n1 basename > ${BUILDHISTORY_DIR_IMAGE}/installed-packages.txt
echo -n > ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp
# Produce dependency graph
# First, filter out characters that cause issues for dot
rootfs_list_installed_depends | sed -e 's:-:_:g' -e 's:\.:_:g' -e 's:+::g' > ${BUILDHISTORY_DIR_IMAGE}/depends.tmp
# Change delimiter from pipe to -> and set style for recommend lines
sed -i -e 's:|: -> :' -e 's:\[REC\]:[style=dotted]:' -e 's:$:;:' ${BUILDHISTORY_DIR_IMAGE}/depends.tmp
# Add header, sorted and de-duped contents and footer and then delete the temp file
echo -e "digraph depends {\n node [shape=plaintext]" > ${BUILDHISTORY_DIR_IMAGE}/depends.dot echo -e "digraph depends {\n node [shape=plaintext]" > ${BUILDHISTORY_DIR_IMAGE}/depends.dot
for pkg in $INSTALLED_PKGS; do cat ${BUILDHISTORY_DIR_IMAGE}/depends.tmp | sort | uniq >> ${BUILDHISTORY_DIR_IMAGE}/depends.dot
pkgfile=`get_package_filename $pkg` echo "}" >> ${BUILDHISTORY_DIR_IMAGE}/depends.dot
echo `basename $pkgfile` >> ${BUILDHISTORY_DIR_IMAGE}/installed-packages.txt rm ${BUILDHISTORY_DIR_IMAGE}/depends.tmp
# Produce installed package sizes list
echo -n > ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp
cat $pkgcache | while read pkg pkgfile
do
if [ -f $pkgfile ] ; then if [ -f $pkgfile ] ; then
pkgsize=`du -k $pkgfile | head -n1 | awk '{ print $1 }'` pkgsize=`du -k $pkgfile | head -n1 | awk '{ print $1 }'`
echo $pkgsize $pkg >> ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp echo $pkgsize $pkg >> ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp
fi fi
done
deps=`list_package_depends $pkg`
for dep in $deps ; do
echo "$pkg OPP $dep;" | sed -e 's:-:_:g' -e 's:\.:_:g' -e 's:+::g' | sed 's:OPP:->:g'
done
recs=`list_package_recommends $pkg`
for rec in $recs ; do
echo "$pkg OPP $rec [style=dotted];" | sed -e 's:-:_:g' -e 's:\.:_:g' -e 's:+::g' | sed 's:OPP:->:g'
done
done | sort | uniq >> ${BUILDHISTORY_DIR_IMAGE}/depends.dot
echo "}" >> ${BUILDHISTORY_DIR_IMAGE}/depends.dot
cat ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp | sort -n -r | awk '{print $1 "\tKiB " $2}' > ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.txt cat ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp | sort -n -r | awk '{print $1 "\tKiB " $2}' > ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.txt
rm ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp rm ${BUILDHISTORY_DIR_IMAGE}/installed-package-sizes.tmp
# We're now done with the cache, delete it
rm $pkgcache
# Produce some cut-down graphs (for readability) # Produce some cut-down graphs (for readability)
grep -v kernel_image ${BUILDHISTORY_DIR_IMAGE}/depends.dot | grep -v kernel_2 | grep -v kernel_3 > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel.dot grep -v kernel_image ${BUILDHISTORY_DIR_IMAGE}/depends.dot | grep -v kernel_2 | grep -v kernel_3 > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel.dot
grep -v libc6 ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel.dot | grep -v libgcc > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc.dot grep -v libc6 ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel.dot | grep -v libgcc > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc.dot
grep -v update_ ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc.dot > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc-noupdate.dot grep -v update_ ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc.dot > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc-noupdate.dot
grep -v kernel_module ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc-noupdate.dot > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc-noupdate-nomodules.dot grep -v kernel_module ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc-noupdate.dot > ${BUILDHISTORY_DIR_IMAGE}/depends-nokernel-nolibc-noupdate-nomodules.dot
# Workaround for broken shell function dependencies
if false ; then
get_package_filename
list_package_depends
list_package_recommends
fi
} }
buildhistory_get_imageinfo() { buildhistory_get_imageinfo() {

View File

@@ -96,26 +96,24 @@ list_installed_packages() {
if [ "$1" = "arch" ] ; then if [ "$1" = "arch" ] ; then
# Here we want the PACKAGE_ARCH not the deb architecture # Here we want the PACKAGE_ARCH not the deb architecture
${DPKG_QUERY_COMMAND} -W -f='${Package} ${PackageArch}\n' ${DPKG_QUERY_COMMAND} -W -f='${Package} ${PackageArch}\n'
elif [ "$1" = "file" ] ; then
${DPKG_QUERY_COMMAND} -W -f='${Package} ${Package}_${Version}_${Architecture}.deb\n' | while read pkg pkgfile
do
fullpath=`find ${DEPLOY_DIR_DEB} -name "$pkgfile" || true`
if [ "$fullpath" = "" ] ; then
echo "$pkg $pkgfile"
else
echo "$pkg $fullpath"
fi
done
else else
${DPKG_QUERY_COMMAND} -W -f='${Package}\n' ${DPKG_QUERY_COMMAND} -W -f='${Package}\n'
fi fi
} }
get_package_filename() { rootfs_list_installed_depends() {
fullname=`find ${DEPLOY_DIR_DEB} -name "$1_*.deb" || true` # Cheat here a little bit by using the opkg query helper util
if [ "$fullname" = "" ] ; then ${DPKG_QUERY_COMMAND} -W -f='Package: ${Package}\nDepends: ${Depends}\nRecommends: ${Recommends}\n\n' | opkg-query-helper.py
echo $name
else
echo $fullname
fi
}
list_package_depends() {
${DPKG_QUERY_COMMAND} -s $1 | grep ^Depends | sed -e 's/^Depends: //' -e 's/,//g' -e 's:([=<>]* [^ )]*)::g'
}
list_package_recommends() {
${DPKG_QUERY_COMMAND} -s $1 | grep ^Recommends | sed -e 's/^Recommends: //' -e 's/,//g' -e 's:([=<>]* [^ )]*)::g'
} }
rootfs_install_packages() { rootfs_install_packages() {

View File

@@ -131,33 +131,23 @@ remove_packaging_data_files() {
list_installed_packages() { list_installed_packages() {
if [ "$1" = "arch" ] ; then if [ "$1" = "arch" ] ; then
opkg-cl ${IPKG_ARGS_POST} status | opkg-query-helper.py -a opkg-cl ${IPKG_ARGS_POST} status | opkg-query-helper.py -a
elif [ "$1" = "file" ] ; then
opkg-cl ${IPKG_ARGS_POST} status | opkg-query-helper.py -f | while read pkg pkgfile
do
fullpath=`find ${DEPLOY_DIR_IPK} -name "$pkgfile" || true`
if [ "$fullpath" = "" ] ; then
echo "$pkg $pkgfile"
else
echo "$pkg $fullpath"
fi
done
else else
opkg-cl ${IPKG_ARGS_POST} list_installed | awk '{ print $1 }' opkg-cl ${IPKG_ARGS_POST} list_installed | awk '{ print $1 }'
fi fi
} }
get_package_filename() { rootfs_list_installed_depends() {
set +x opkg-cl ${IPKG_ARGS_POST} status | opkg-query-helper.py
info=`opkg-cl ${IPKG_ARGS_POST} info $1 | grep -B 7 -A 7 "^Status.* \(\(installed\)\|\(unpacked\)\)" || true`
name=`echo "${info}" | awk '/^Package/ {printf $2"_"}'`
name=$name`echo "${info}" | awk -F: '/^Version/ {printf $NF"_"}' | sed 's/^\s*//g'`
name=$name`echo "${info}" | awk '/^Archi/ {print $2".ipk"}'`
set -x
fullname=`find ${DEPLOY_DIR_IPK} -name "$name" || true`
if [ "$fullname" = "" ] ; then
echo $name
else
echo $fullname
fi
}
list_package_depends() {
opkg-cl ${IPKG_ARGS_POST} info $1 | grep ^Depends | sed -e 's/^Depends: //' -e 's/,//g' -e 's:([=<>]* [^ )]*)::g'
}
list_package_recommends() {
opkg-cl ${IPKG_ARGS_POST} info $1 | grep ^Recommends | sed -e 's/^Recommends: //' -e 's/,//g' -e 's:([=<>]* [^ )]*)::g'
} }
rootfs_install_packages() { rootfs_install_packages() {

View File

@@ -143,40 +143,15 @@ RPM_QUERY_CMD = '${RPM} --root $INSTALL_ROOTFS_RPM -D "_dbpath ${rpmlibdir}" \
list_installed_packages() { list_installed_packages() {
if [ "$1" = "arch" ] ; then if [ "$1" = "arch" ] ; then
${RPM_QUERY_CMD} -qa --qf "[%{NAME} %{ARCH}\n]" ${RPM_QUERY_CMD} -qa --qf "[%{NAME} %{ARCH}\n]"
elif [ "$1" = "file" ] ; then
${RPM_QUERY_CMD} -qa --qf "[%{NAME} %{PACKAGEORIGIN}\n]"
else else
${RPM_QUERY_CMD} -qa --qf "[%{NAME}\n]" ${RPM_QUERY_CMD} -qa --qf "[%{NAME}\n]"
fi fi
} }
get_package_filename() { rootfs_list_installed_depends() {
resolve_package_rpm ${RPMCONF_TARGET_BASE}-base_archs.conf $1 rpmresolve -d $INSTALL_ROOTFS_RPM/${rpmlibdir}
}
list_package_depends() {
pkglist=`list_installed_packages`
# REQUIRE* lists "soft" requirements (which we know as recommends and RPM refers to
# as "suggests") so filter these out with the help of awk
for req in `${RPM_QUERY_CMD} -q --qf "[%{REQUIRENAME} %{REQUIREFLAGS}\n]" $1 | awk '{ if( and($2, 0x80000) == 0) print $1 }'`; do
if echo "$req" | grep -q "^rpmlib" ; then continue ; fi
realpkg=""
for dep in $pkglist; do
if [ "$dep" = "$req" ] ; then
realpkg="1"
echo $req
break
fi
done
if [ "$realdep" = "" ] ; then
${RPM_QUERY_CMD} -q --whatprovides $req --qf "%{NAME}\n"
fi
done
}
list_package_recommends() {
${RPM_QUERY_CMD} -q --suggests $1
} }
rootfs_install_packages() { rootfs_install_packages() {

View File

@@ -204,10 +204,104 @@ int processPackages(rpmts *ts, int tscount, const char *packagelistfn, int ignor
return rc; return rc;
} }
int lookupProvider(rpmts ts, const char *req, char **provider)
{
int rc = 0;
rpmmi provmi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, req, 0);
if(provmi) {
Header h;
if ((h = rpmmiNext(provmi)) != NULL) {
HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
he->tag = RPMTAG_NAME;
rc = (headerGet(h, he, 0) != 1);
if(rc==0)
*provider = strdup((char *)he->p.ptr);
}
(void)rpmmiFree(provmi);
}
else {
rc = -1;
}
return rc;
}
int printDepList(rpmts *ts, int tscount)
{
int rc = 0;
if( tscount > 1 )
printf(">1 database specified with dependency list, using first only\n");
/* Get list of names */
rpmdb db = rpmtsGetRdb(ts[0]);
ARGV_t names = NULL;
rc = rpmdbMireApply(db, RPMTAG_NAME,
RPMMIRE_STRCMP, NULL, &names);
int nnames = argvCount(names);
/* Get list of NVRAs */
ARGV_t keys = NULL;
rc = rpmdbMireApply(db, RPMTAG_NVRA,
RPMMIRE_STRCMP, NULL, &keys);
if (keys) {
int i, j;
HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
int nkeys = argvCount(keys);
for(i=0; i<nkeys; i++) {
rpmmi mi = rpmtsInitIterator(ts[0], RPMTAG_NVRA, keys[i], 0);
Header h;
if ((h = rpmmiNext(mi)) != NULL) {
/* Get name of package */
he->tag = RPMTAG_NAME;
rc = (headerGet(h, he, 0) != 1);
char *name = strdup((char *)he->p.ptr);
/* Get its requires */
he->tag = RPMTAG_REQUIRENAME;
rc = (headerGet(h, he, 0) != 1);
ARGV_t reqs = (ARGV_t)he->p.ptr;
/* Get its requireflags */
he->tag = RPMTAG_REQUIREFLAGS;
rc = (headerGet(h, he, 0) != 1);
rpmuint32_t *reqflags = (rpmuint32_t *)he->p.ui32p;
for(j=0; j<he->c; j++) {
int k;
char *prov = NULL;
for(k=0; k<nnames; k++) {
if(strcmp(names[k], reqs[j]) == 0) {
prov = names[k];
break;
}
}
if(prov) {
if((int)reqflags[j] & 0x80000)
printf("%s|%s [REC]\n", name, prov);
else
printf("%s|%s\n", name, prov);
}
else {
rc = lookupProvider(ts[0], reqs[j], &prov);
if(rc==0 && prov) {
if((int)reqflags[j] & 0x80000)
printf("%s|%s [REC]\n", name, prov);
else
printf("%s|%s\n", name, prov);
free(prov);
}
}
}
free(name);
}
(void)rpmmiFree(mi);
}
}
return rc;
}
void usage() void usage()
{ {
fprintf(stderr, "OpenEmbedded rpm resolver utility\n"); fprintf(stderr, "OpenEmbedded rpm resolver utility\n");
fprintf(stderr, "syntax: rpmresolve [-i] <dblistfile> <packagelistfile>\n"); fprintf(stderr, "syntax: rpmresolve [-i] [-d] <dblistfile> <packagelistfile>\n");
} }
int main(int argc, char **argv) int main(int argc, char **argv)
@@ -218,13 +312,17 @@ int main(int argc, char **argv)
int i; int i;
int c; int c;
int ignoremissing = 0; int ignoremissing = 0;
int deplistmode = 0;
opterr = 0; opterr = 0;
while ((c = getopt (argc, argv, "i")) != -1) { while ((c = getopt (argc, argv, "id")) != -1) {
switch (c) { switch (c) {
case 'i': case 'i':
ignoremissing = 1; ignoremissing = 1;
break; break;
case 'd':
deplistmode = 1;
break;
case '?': case '?':
if(isprint(optopt)) if(isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt); fprintf(stderr, "Unknown option `-%c'.\n", optopt);
@@ -258,12 +356,17 @@ int main(int argc, char **argv)
return 1; return 1;
} }
if( argc - optind < 2 ) { if(deplistmode) {
fprintf(stderr, "Please specify package list file\n"); rc = printDepList(ts, tscount);
return 1; }
else {
if( argc - optind < 2 ) {
fprintf(stderr, "Please specify package list file\n");
return 1;
}
const char *pkglistfn = argv[optind+1];
rc = processPackages(ts, tscount, pkglistfn, ignoremissing);
} }
const char *pkglistfn = argv[optind+1];
rc = processPackages(ts, tscount, pkglistfn, ignoremissing);
for(i=0; i<tscount; i++) for(i=0; i<tscount; i++)
(void) rpmtsCloseDB(ts[i]); (void) rpmtsCloseDB(ts[i]);