Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.5:Update
powerpc-utils.22222
lsdevinfo-optimize-criteria-filtering.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File lsdevinfo-optimize-criteria-filtering.patch of Package powerpc-utils.22222
From 4c6dc50d8de1a8b171675ee6b742c9f0250c28a1 Mon Sep 17 00:00:00 2001 From: Scott Cheloha <cheloha@linux.ibm.com> Date: Tue, 27 Jul 2021 11:30:58 -0500 Subject: [PATCH] lsdevinfo: optimize criteria filtering References: bsc#1189571 ltc#193419 Upstream: merged, expected 1.3.10 Git-commit: 4c6dc50d8de1a8b171675ee6b742c9f0250c28a1 lsdevinfo is significantly slower when a criteria filter is set with the -q flag. There are two culprits: 1. The criteria string given on the command line is parsed every time we call check_criteria(). We're forking two sed(1) processes whenever we hit that function. We hit it a lot. 2. Criteria checking runs in constant time. We call check_criteria() and do the parsing in (1) for every relevant attribute, even if we already have a match from a prior check_criteria() invocation. We can fix issue (1) by parsing the criteria string once at the start of the script. I have added a function, parse_criteria(), that parses the $criteria string and selects an appropriate matching function. This approach also fixes problem (2), but we first need to check whether the user's criteria is relevant to the attributes the script cares about before calling the matching function. We do this with criteria_is_relevant(). The speed improvement is nice. Consider my test machine with around thirty devices. On this machine, lsdevinfo without any options runs in 1.35s, but with the "status=1" criteria it runs in 2.12s: $ /usr/sbin/lsdevinfo | fgrep -c device: 29 $ command time -p /usr/sbin/lsdevinfo > /dev/null real 1.35 user 1.42 sys 0.16 $ command time -p /usr/sbin/lsdevinfo -q status=1 > /dev/null real 2.12 user 2.22 sys 0.30 With this patch, lsdevinfo with the "status=1" criteria now runs in 1.35s: $ command time -p /usr/sbin/lsdevinfo -q status=1 > /dev/null real 1.35 user 1.41 sys 0.18 This patch eliminates nearly all of the criteria-checking overhead in the current code. Signed-off-by: Scott Cheloha <cheloha@linux.ibm.com> Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com> --- scripts/lsdevinfo | 197 ++++++++++++++++++++++++++++++---------------- 1 file changed, 129 insertions(+), 68 deletions(-) diff --git a/scripts/lsdevinfo b/scripts/lsdevinfo index 1d9597bc4bc9..7a3cba3bee9f 100755 --- a/scripts/lsdevinfo +++ b/scripts/lsdevinfo @@ -61,37 +61,113 @@ show_version() echo "Written by: Santiago Leon <sleon@ec.ibm.com>" } -# check_criteria -# Modifies $show if the the attribute in the first parameter matches the -# criteria from the command line. -# The operands (=, !=, and LIKE) are defined the the lsdevinfo spec. # -check_criteria() +# Criteria matching boilerplate. +# +_class_eq() { [[ $class = $crit_rhs ]]; } +_class_neq() { [[ $class != $crit_rhs ]]; } +_class_like() { [[ $class =~ $crit_rhs ]]; } + +_driver_eq() { [[ $driver = $crit_rhs ]]; } +_driver_neq() { [[ $driver != $crit_rhs ]]; } +_driver_like() { [[ $driver =~ $crit_rhs ]]; } + +_name_eq() { [[ $name = $crit_rhs ]]; } +_name_neq() { [[ $name != $crit_rhs ]]; } +_name_like() { [[ $name =~ $crit_rhs ]]; } + +_parent_eq() { [[ $parent = $crit_rhs ]]; } +_parent_neq() { [[ $parent != $crit_rhs ]]; } +_parent_like() { [[ $parent =~ $crit_rhs ]]; } + +_physloc_eq() { [[ $physloc = $crit_rhs ]]; } +_physloc_neq() { [[ $physloc != $crit_rhs ]]; } +_physloc_like() { [[ $physloc =~ $crit_rhs ]]; } + +_prefix_eq() { [[ $prefix = $crit_rhs ]]; } +_prefix_neq() { [[ $prefix != $crit_rhs ]]; } +_prefix_like() { [[ $prefix =~ $crit_rhs ]]; } + +_status_eq() { [[ $status = $crit_rhs ]]; } +_status_neq() { [[ $status != $crit_rhs ]]; } +_status_like() { [[ $status =~ $crit_rhs ]]; } + +_subclass_eq() { [[ $subclass = $crit_rhs ]]; } +_subclass_neq() { [[ $subclass != $crit_rhs ]]; } +_subclass_like() { [[ $subclass =~ $crit_rhs ]]; } + +_type_eq() { [[ $type = $crit_rhs ]]; } +_type_neq() { [[ $type != $crit_rhs ]]; } +_type_like() { [[ $type =~ $crit_rhs ]]; } + +_uniquetype_eq() { [[ $uniquetype = $crit_rhs ]]; } +_uniquetype_neq() { [[ $uniquetype != $crit_rhs ]]; } +_uniquetype_like() { [[ $uniquetype =~ $crit_rhs ]]; } + +# Check if the attribute we're filtering on appears in the string +# given as argument. +criteria_is_relevant() { - attr=$1 - attr_val=${!attr} + [[ "$1" =~ "$crit_lhs" ]] +} +# Run the criteria-matching function. +criteria_matches() +{ + $criteria_checker +} + +# Select a criteria-matching function based on the $criteria string. +parse_criteria() +{ if [[ $criteria =~ "!=" ]] ; then - # Pull out the operands from the criteria (everything to the left of - # the operand, and everything on the right of the operand) - crit_opd1=$(echo $criteria | $SED -e "s/[ ]*!=.*//") - crit_opd2=$(echo $criteria | $SED -e "s/.*!=[ ]*//") - # Perfom the comparison of the attribute and its value - if [[ $crit_opd1 == $attr && $crit_opd2 != $attr_val ]]; then - show=1 - fi + crit_lhs=$(echo $criteria | $SED -e "s/[ ]*!=.*//") + crit_rhs=$(echo $criteria | $SED -e "s/.*!=[ ]*//") + case "$crit_lhs" in + class) criteria_checker=_class_neq;; + driver) criteria_checker=_driver_neq;; + name) criteria_checker=_name_neq;; + parent) criteria_checker=_parent_neq;; + physloc) criteria_checker=_physloc_neq;; + prefix) criteria_checker=_prefix_neq;; + status) criteria_checker=_status_neq;; + subclass) criteria_checker=_subclass_neq;; + type) criteria_checker=_type_neq;; + uniquetype) criteria_checker=_uniquetype_neq;; + *) criteria_checker=false;; + esac elif [[ $criteria =~ "=" ]]; then - crit_opd1=$(echo $criteria | $SED -e "s/[ ]*=.*//") - crit_opd2=$(echo $criteria | $SED -e "s/.*=[ ]*//") - if [[ $crit_opd1 == $attr && $crit_opd2 == $attr_val ]]; then - show=1 - fi + crit_lhs=$(echo $criteria | $SED -e "s/[ ]*=.*//") + crit_rhs=$(echo $criteria | $SED -e "s/.*=[ ]*//") + case "$crit_lhs" in + class) criteria_checker=_class_eq;; + driver) criteria_checker=_driver_eq;; + name) criteria_checker=_name_eq;; + parent) criteria_checker=_parent_eq;; + physloc) criteria_checker=_physloc_eq;; + prefix) criteria_checker=_prefix_eq;; + status) criteria_checker=_status_eq;; + subclass) criteria_checker=_subclass_eq;; + type) criteria_checker=_type_eq;; + uniquetype) criteria_checker=_uniquetype_eq;; + *) criteria_checker=false;; + esac elif [[ $criteria =~ " LIKE " ]]; then - crit_opd1=$(echo $criteria | $SED -e "s/[ ]*LIKE.*//") - crit_opd2=$(echo $criteria | $SED -e "s/.*LIKE[ ]*//") - if [[ $crit_opd1 == $attr && $attr_val =~ $crit_opd2 ]]; then - show=1 - fi + crit_lhs=$(echo $criteria | $SED -e "s/[ ]*LIKE.*//") + crit_rhs=$(echo $criteria | $SED -e "s/.*LIKE[ ]*//") + case "$crit_lhs" in + class) criteria_checker=_class_like;; + driver) criteria_checker=_driver_like;; + name) criteria_checker=_name_like;; + parent) criteria_checker=_parent_like;; + physloc) criteria_checker=_physloc_like;; + prefix) criteria_checker=_prefix_like;; + status) criteria_checker=_status_like;; + subclass) criteria_checker=_subclass_like;; + type) criteria_checker=_type_like;; + uniquetype) criteria_checker=_uniquetype_like;; + *) criteria_checker=false;; + esac else echo "Criteria must have =, !=, or LIKE operand. Exiting." exit 1 @@ -124,6 +200,8 @@ recursive=0 # default: display all devices criteria="" +criteria_checker=: +crit_lhs="" # default: display all attributes format="" @@ -162,6 +240,12 @@ if [[ $criteria =~ " AND " ]] ; then exit 1 fi +# If we have a criteria string, parse it and choose a criteria +# matching function. +if [[ -n "$criteria" ]]; then + parse_criteria +fi + # Fill variables for the two display formats (regular and comma-separated) so # we can print the output in a single place. if [[ $comma_sep -eq 0 ]]; then @@ -184,15 +268,10 @@ show_eth () # if there is a criteria in the command line, check if this device matches if [[ $criteria != "" ]] ; then show=0 - check_criteria "name" - check_criteria "physloc" - check_criteria "uniquetype" - check_criteria "class" - check_criteria "subclass" - check_criteria "type" - check_criteria "prefix" - check_criteria "driver" - check_criteria "status" + attrs="name physloc uniquetype class subclass type prefix driver status" + if criteria_is_relevant "$attrs" && criteria_matches; then + show=1 + fi fi # print the info only if the device matches the criteria @@ -330,15 +409,10 @@ for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # device matches if [[ $criteria != "" ]] ; then show=0 - check_criteria "name" - check_criteria "physloc" - check_criteria "status" - check_criteria "uniquetype" - check_criteria "class" - check_criteria "subclass" - check_criteria "type" - check_criteria "prefix" - check_criteria "driver" + attrs="name physloc status uniquetype class subclass type prefix driver" + if criteria_is_relevant "$attrs" && criteria_matches; then + show=1 + fi fi if [[ $show -ne 0 ]]; then @@ -395,14 +469,10 @@ for dev in $($LS -d /proc/device-tree/vdevice/v-scsi* 2> /dev/null) ; do # if there is a criteria in the command line, check if this # device matches show=0 - check_criteria "name" - check_criteria "status" - check_criteria "physloc" - check_criteria "parent" - check_criteria "uniquetype" - check_criteria "class" - check_criteria "subclass" - check_criteria "type" + attrs="name status physloc parent uniquetype class subclass type" + if criteria_is_relevant "$attrs" && criteria_matches; then + show=1 + fi else show=1 fi @@ -475,15 +545,10 @@ for dev in $($LS -d /proc/device-tree/vdevice/vfc-client* 2> /dev/null) ; do # device matches if [[ $criteria != "" ]] ; then show=0 - check_criteria "name" - check_criteria "physloc" - check_criteria "status" - check_criteria "uniquetype" - check_criteria "class" - check_criteria "subclass" - check_criteria "type" - check_criteria "prefix" - check_criteria "driver" + attrs="name physloc status uniquetype class subclass type prefix driver" + if criteria_is_relevant "$attrs" && criteria_matches; then + show=1 + fi fi if [[ $show -ne 0 ]]; then @@ -543,14 +608,10 @@ for dev in $($LS -d /proc/device-tree/vdevice/vfc-client* 2> /dev/null) ; do # if there is a criteria in the command line, check if this # device matches show=0 - check_criteria "name" - check_criteria "physloc" - check_criteria "status" - check_criteria "parent" - check_criteria "uniquetype" - check_criteria "class" - check_criteria "subclass" - check_criteria "type" + attrs="name physloc status parent uniquetype class subclass type" + if criteria_is_relevant "$attrs" && criteria_matches; then + show=1 + fi else show=1 fi -- 2.31.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor