Hi Thomas,

Please let me know if there is any feedback on this patch.

Regards,
Ankur

>-----Original Message-----
>From: Ankur Dwivedi <adwiv...@marvell.com>
>Sent: Tuesday, March 7, 2023 5:35 PM
>To: dev@dpdk.org
>Cc: tho...@monjalon.net; Jerin Jacob Kollanukkaran <jer...@marvell.com>;
>Ankur Dwivedi <adwiv...@marvell.com>
>Subject: [PATCH v5 1/1] devtools: add tracepoint check in checkpatch
>
>This patch adds a validation in checkpatch tool, to check if a tracepoint is
>present in any new function added in cryptodev, ethdev, eventdev and
>mempool library.
>
>In this patch, the build_map_changes function is copied from check-symbol-
>change.sh to check-tracepoint.sh. The check-tracepoint.sh script uses
>build_map_changes function to create a map of functions.
>In the map, the newly added functions, added in the experimental section are
>identified and their definition are checked for the presence of tracepoint. The
>checkpatch return error if the tracepoint is not present.
>
>For functions for which trace is not needed, they can be added to
>devtools/trace-skiplist.txt file. The above tracepoint check will be skipped 
>for
>them.
>
>Signed-off-by: Ankur Dwivedi <adwiv...@marvell.com>
>---
> devtools/check-tracepoint.sh | 223 +++++++++++++++++++++++++++++++++++
> devtools/checkpatches.sh     |   9 ++
> devtools/trace-skiplist.txt  |   0
> 3 files changed, 232 insertions(+)
> create mode 100755 devtools/check-tracepoint.sh  create mode 100644
>devtools/trace-skiplist.txt
>
>diff --git a/devtools/check-tracepoint.sh b/devtools/check-tracepoint.sh new
>file mode 100755 index 0000000000..88d6b1fd53
>--- /dev/null
>+++ b/devtools/check-tracepoint.sh
>@@ -0,0 +1,223 @@
>+#!/bin/sh
>+# SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Neil Horman
>+<nhor...@tuxdriver.com> # Copyright(C) 2023 Marvell.
>+
>+selfdir=$(dirname $(readlink -f $0))
>+
>+# Library for trace check
>+libdir="cryptodev ethdev eventdev mempool"
>+
>+# Functions for which the trace check can be skipped
>+skiplist="$selfdir/trace-skiplist.txt"
>+
>+build_map_changes()
>+{
>+      local fname="$1"
>+      local mapdb="$2"
>+
>+      cat "$fname" | awk '
>+              # Initialize our variables
>+              BEGIN {map="";sym="";ar="";sec=""; in_sec=0; in_map=0}
>+
>+              # Anything that starts with + or -, followed by an a
>+              # and ends in the string .map is the name of our map file
>+              # This may appear multiple times in a patch if multiple
>+              # map files are altered, and all section/symbol names
>+              # appearing between a triggering of this rule and the
>+              # next trigger of this rule are associated with this file
>+              /[-+] [ab]\/.*\.map/ {map=$2; in_map=1; next}
>+
>+              # The previous rule catches all .map files, anything else
>+              # indicates we left the map chunk.
>+              /[-+] [ab]\// {in_map=0}
>+
>+              # Triggering this rule, which starts a line and ends it
>+              # with a { identifies a versioned section.  The section name is
>+              # the rest of the line with the + and { symbols removed.
>+              # Triggering this rule sets in_sec to 1, which actives the
>+              # symbol rule below
>+              /^.*{/ {
>+                      gsub("+", "");
>+                      if (in_map == 1) {
>+                              sec=$(NF-1); in_sec=1;
>+                      }
>+              }
>+
>+              # This rule identifies the end of a section, and disables the
>+              # symbol rule
>+              /.*}/ {in_sec=0}
>+
>+              # This rule matches on a + followed by any characters except a
>:
>+              # (which denotes a global vs local segment), and ends with a ;.
>+              # The semicolon is removed and the symbol is printed with its
>+              # association file name and version section, along with an
>+              # indicator that the symbol is a new addition.  Note this rule
>+              # only works if we have found a version section in the rule
>+              # above (hence the in_sec check) And found a map file (the
>+              # in_map check).  If we are not in a map chunk, do nothing.  If
>+              # we are in a map chunk but not a section chunk, record it as
>+              # unknown.
>+              /^+[^}].*[^:*];/ {gsub(";","");sym=$2;
>+                      if (in_map == 1) {
>+                              if (in_sec == 1) {
>+                                      print map " " sym " " sec " add"
>+                              } else {
>+                                      print map " " sym " unknown add"
>+                              }
>+                      }
>+              }
>+
>+              # This is the same rule as above, but the rule matches on a
>+              # leading - rather than a +, denoting that the symbol is being
>+              # removed.
>+              /^-[^}].*[^:*];/ {gsub(";","");sym=$2;
>+                      if (in_map == 1) {
>+                              if (in_sec == 1) {
>+                                      print map " " sym " " sec " del"
>+                              } else {
>+                                      print map " " sym " unknown del"
>+                              }
>+                      }
>+              }' > "$mapdb"
>+
>+              sort -u "$mapdb" > "$mapdb.2"
>+              mv -f "$mapdb.2" "$mapdb"
>+
>+}
>+
>+find_trace_fn()
>+{
>+      local fname="$1"
>+
>+      cat "$fname" | awk -v symname="$2 *\\\(" '
>+              # Initialize the variables.
>+              # The variable symname provides a pattern to match
>+              # "function_name(", zero or more spaces can be present
>+              # between function_name and (.
>+              BEGIN {state=0; ln_pth=0}
>+
>+              # Matches the function name, set state=1.
>+              $0 ~ symname {state=1}
>+
>+              # If closing parentheses with semicolon ");" is found, then it
>+              # is not the function definition.
>+              /) *;/ {
>+                      if (state == 1) {
>+                              state=0
>+                      }
>+              }
>+
>+              /)/ {
>+                      if (state == 1) {
>+                              state=2
>+                              ln_pth=NR
>+                              next
>+                      }
>+              }
>+
>+              # If closing parentheses and then opening braces is found in
>+              # adjacent line, then this is the start of function
>+              # definition. Check for tracepoint in the function definition.
>+              # The tracepoint has _trace_ in its name.
>+              /{/ {
>+                      if (state == 2) {
>+                              if (ln_pth != NR - 1) {
>+                                      state=0
>+                                      next
>+                              }
>+                              while (index($0, "}") != 2) {
>+                                      if (index($0, "_trace_") != 0) {
>+                                              exit 0
>+                                      }
>+                                      if (getline <= 0) {
>+                                              break
>+                                      }
>+                              }
>+                              exit 1
>+                      }
>+              }
>+      '
>+}
>+
>+check_for_tracepoint()
>+{
>+      local patch="$1"
>+      local mapdb="$2"
>+      local skip_sym
>+      local libname
>+      local secname
>+      local mname
>+      local ret=0
>+      local pdir
>+      local libp
>+      local libn
>+      local sym
>+      local ar
>+
>+      while read -r mname symname secname ar; do
>+              pdir=$(echo $mname | awk 'BEGIN {FS="/"};{print $2}')
>+              libname=$(echo $mname | awk 'BEGIN {FS="/"};{print $3}')
>+              skip_sym=0
>+              libp=0
>+
>+              if [ "$pdir" != "lib" ]; then
>+                      continue
>+              fi
>+
>+              for libn in $libdir; do
>+                      if [ $libn = $libname ]; then
>+                              libp=1
>+                              break
>+                      fi
>+              done
>+
>+              if [ $libp -eq 0 ]; then
>+                      continue
>+              fi
>+
>+              for sym in $(cat $skiplist); do
>+                      if [ $sym = $symname ]; then
>+                              skip_sym=1
>+                              break
>+                      fi
>+              done
>+
>+              if [ $skip_sym -eq 1 ]; then
>+                      continue
>+              fi
>+
>+              if [ "$ar" = "add" ] && [ "$secname" = "EXPERIMENTAL" ]; then
>+                      # Check if new API is added with tracepoint
>+                      find_trace_fn $patch $symname
>+                      if [ $? -eq 1 ]; then
>+                              ret=1
>+                              echo -n "ERROR: New function $symname is
>added "
>+                              echo -n "without a tracepoint. Please add a
>tracepoint "
>+                              echo -n "or add the function $symname in "
>+                              echo "devtools/trace-skiplist.txt to skip this
>error."
>+                      fi
>+              fi
>+      done < "$mapdb"
>+
>+      return $ret
>+}
>+
>+trap clean_and_exit_on_sig EXIT
>+
>+mapfile=`mktemp -t dpdk.mapdb.XXXXXX`
>+patch=$1
>+exit_code=1
>+
>+clean_and_exit_on_sig()
>+{
>+      rm -f "$mapfile"
>+      exit $exit_code
>+}
>+
>+build_map_changes "$patch" "$mapfile"
>+check_for_tracepoint "$patch" "$mapfile"
>+exit_code=$?
>+rm -f "$mapfile"
>+
>+exit $exit_code
>diff --git a/devtools/checkpatches.sh b/devtools/checkpatches.sh index
>1dee094c7a..471db1d21b 100755
>--- a/devtools/checkpatches.sh
>+++ b/devtools/checkpatches.sh
>@@ -10,6 +10,7 @@
> . $(dirname $(readlink -f $0))/load-devel-config
>
> VALIDATE_NEW_API=$(dirname $(readlink -f $0))/check-symbol-change.sh
>+VALIDATE_TRACEPOINT=$(dirname $(readlink -f $0))/check-tracepoint.sh
>
> # Enable codespell by default. This can be overwritten from a config file.
> # Codespell can also be enabled by setting DPDK_CHECKPATCH_CODESPELL to
>a valid path @@ -386,6 +387,14 @@ check () { # <patch-file> <commit>
>               ret=1
>       fi
>
>+      ! $verbose || printf '\nChecking API additions with tracepoint :\n'
>+      report=$($VALIDATE_TRACEPOINT "$tmpinput")
>+      if [ $? -ne 0 ] ; then
>+              $headline_printed || print_headline "$subject"
>+              printf '%s\n' "$report"
>+              ret=1
>+      fi
>+
>       if [ "$tmpinput" != "$1" ]; then
>               rm -f "$tmpinput"
>               trap - INT
>diff --git a/devtools/trace-skiplist.txt b/devtools/trace-skiplist.txt new file
>mode 100644 index 0000000000..e69de29bb2
>--
>2.25.1

Reply via email to