[Midnightbsd-cvs] src [10366] trunk/usr.sbin: sync with freebsd.

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Jun 3 19:10:18 EDT 2018


Revision: 10366
          http://svnweb.midnightbsd.org/src/?rev=10366
Author:   laffer1
Date:     2018-06-03 19:10:18 -0400 (Sun, 03 Jun 2018)
Log Message:
-----------
sync with freebsd.

Modified Paths:
--------------
    trunk/usr.sbin/periodic/Makefile
    trunk/usr.sbin/periodic/periodic.8
    trunk/usr.sbin/periodic/periodic.sh
    trunk/usr.sbin/pmcannotate/Makefile
    trunk/usr.sbin/pmcannotate/pmcannotate.8
    trunk/usr.sbin/pmcannotate/pmcannotate.c
    trunk/usr.sbin/pmccontrol/Makefile
    trunk/usr.sbin/pmccontrol/pmccontrol.8
    trunk/usr.sbin/pmccontrol/pmccontrol.c
    trunk/usr.sbin/pmcstat/Makefile
    trunk/usr.sbin/pmcstat/pmcpl_annotate.c
    trunk/usr.sbin/pmcstat/pmcpl_annotate.h
    trunk/usr.sbin/pmcstat/pmcpl_callgraph.c
    trunk/usr.sbin/pmcstat/pmcpl_callgraph.h
    trunk/usr.sbin/pmcstat/pmcpl_calltree.c
    trunk/usr.sbin/pmcstat/pmcpl_calltree.h
    trunk/usr.sbin/pmcstat/pmcpl_gprof.c
    trunk/usr.sbin/pmcstat/pmcpl_gprof.h
    trunk/usr.sbin/pmcstat/pmcstat.8
    trunk/usr.sbin/pmcstat/pmcstat.c
    trunk/usr.sbin/pmcstat/pmcstat.h
    trunk/usr.sbin/pmcstat/pmcstat_log.c
    trunk/usr.sbin/pmcstat/pmcstat_log.h
    trunk/usr.sbin/pmcstat/pmcstat_top.h

Added Paths:
-----------
    trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.c
    trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.h
    trunk/usr.sbin/pmcstudy/
    trunk/usr.sbin/pmcstudy/Makefile
    trunk/usr.sbin/pmcstudy/eval_expr.c
    trunk/usr.sbin/pmcstudy/eval_expr.h
    trunk/usr.sbin/pmcstudy/pmcstudy.8
    trunk/usr.sbin/pmcstudy/pmcstudy.c

Property Changed:
----------------
    trunk/usr.sbin/periodic/periodic.8
    trunk/usr.sbin/periodic/periodic.sh
    trunk/usr.sbin/pmcannotate/pmcannotate.8
    trunk/usr.sbin/pmccontrol/pmccontrol.8
    trunk/usr.sbin/pmcstat/pmcstat.8

Modified: trunk/usr.sbin/periodic/Makefile
===================================================================
--- trunk/usr.sbin/periodic/Makefile	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/periodic/Makefile	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,5 +1,5 @@
 # $MidnightBSD$
-# $FreeBSD: src/usr.sbin/periodic/Makefile,v 1.4 2001/04/07 11:21:33 ru Exp $
+# $FreeBSD: stable/10/usr.sbin/periodic/Makefile 75286 2001-04-07 11:21:35Z ru $
 
 SCRIPTS=periodic.sh
 MAN=	periodic.8

Modified: trunk/usr.sbin/periodic/periodic.8
===================================================================
--- trunk/usr.sbin/periodic/periodic.8	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/periodic/periodic.8	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+.\" $MidnightBSD$
 .\" Copyright (c) 1997 FreeBSD, Inc.
 .\" All rights reserved.
 .\"
@@ -22,12 +23,11 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $MIdnightBSD$
-.\" $FreeBSD: src/usr.sbin/periodic/periodic.8,v 1.33 2007/09/07 21:54:45 gabor Exp $
+.\" $FreeBSD: stable/10/usr.sbin/periodic/periodic.8 302600 2016-07-11 23:15:54Z asomers $
 .\"
-.Dd April 27, 2008
+.Dd May 20, 2016
+.Dt PERIODIC 8
 .Os
-.Dt PERIODIC 8
 .Sh NAME
 .Nm periodic
 .Nd run periodic system functions
@@ -167,8 +167,9 @@
 the top level directory containing
 .Pa daily ,
 .Pa weekly ,
+.Pa monthly ,
 and
-.Pa monthly
+.Pa security
 subdirectories which contain standard system periodic executables
 .It Pa /etc/defaults/periodic.conf
 the
@@ -176,9 +177,9 @@
 system registry contains variables that control the behaviour of
 .Nm
 and the standard
-.Pa daily , weekly ,
+.Pa daily , weekly , monthly ,
 and
-.Pa monthly
+.Pa security
 scripts
 .It Pa /etc/periodic.conf
 this file contains local overrides for the default


Property changes on: trunk/usr.sbin/periodic/periodic.8
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.sbin/periodic/periodic.sh
===================================================================
--- trunk/usr.sbin/periodic/periodic.sh	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/periodic/periodic.sh	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,25 +1,37 @@
 #!/bin/sh -
 #
 # $MidnightBSD$
-# $FreeBSD: src/usr.sbin/periodic/periodic.sh,v 1.21 2007/06/22 10:04:05 dwmalone Exp $
+# $FreeBSD: stable/10/usr.sbin/periodic/periodic.sh 321260 2017-07-20 00:33:12Z ngie $
 #
 # Run nightly periodic scripts
 #
-# usage: periodic { daily | weekly | monthly } - run standard periodic scripts
+# usage: periodic { daily | weekly | monthly | security } - run standard scripts
 #        periodic /absolute/path/to/directory  - run periodic scripts in dir
 #
 
 usage () {
     echo "usage: $0 <directory of files to execute>" 1>&2
-    echo "or     $0 { daily | weekly | monthly }"    1>&2
+    echo "or     $0 { daily | weekly | monthly | security }"    1>&2
     exit 1
 }
 
+output_pipe()
+{
+    # Where's our output going ?
+    eval output=\$${1##*/}_output
+    case "$output" in
+    /*) pipe="cat >>$output";;
+    "") pipe=cat;;
+    *)  pipe="mail -E -s '$host ${2}${2:+ }${1##*/} run output' $output";;
+    esac
+    eval $pipe
+}
+
 if [ $# -lt 1 ] ; then
     usage
 fi
 
-# If possible, check the global system configuration file, 
+# If possible, check the global system configuration file,
 # to see if there are additional dirs to check
 if [ -r /etc/defaults/periodic.conf ]; then
     . /etc/defaults/periodic.conf
@@ -28,83 +40,105 @@
 
 host=`hostname`
 export host
+
+# If we were called normally, then create a lock file for each argument
+# in turn and reinvoke ourselves with the LOCKED argument.  This prevents
+# very long running jobs from being overlapped by another run as this is
+# will lead the system running progressivly slower and more and more jobs
+# are run at once.
+if [ $1 != "LOCKED" ]; then
+    ret=0
+    for arg; do
+        lockfile=/var/run/periodic.${arg##*/}.lock
+        lockf -t 0 "${lockfile}" /bin/sh $0 LOCKED "$arg"
+        case $? in
+        0) ;;
+        73) #EX_CANTCREATE
+            echo "can't create ${lockfile}" | \
+                output_pipe $arg "$PERIODIC"
+            ret=1
+            ;;
+        75) #EX_TEMPFAIL
+            echo "$host ${arg##*/} prior run still in progress" | \
+                output_pipe $arg "$PERIODIC"
+            ret=1
+            ;;
+        *)
+            ret=1
+            ;;
+        esac
+    done
+    exit $ret
+fi
+
+if [ $# -ne 2 ]; then
+    usage
+fi
+shift
+arg=$1
+
 tmp_output=`mktemp ${TMPDIR:-/tmp}/periodic.XXXXXXXXXX`
+context="$PERIODIC"
+export PERIODIC="$arg${PERIODIC:+ }${PERIODIC}"
 
 # Execute each executable file in the directory list.  If the x bit is not
 # set, assume the user didn't really want us to muck with it (it's a
 # README file or has been disabled).
 
-for arg
-do
-    # Where's our output going ?
-    eval output=\$${arg##*/}_output
-    case "$output" in
-    /*) pipe="cat >>$output";;
-    "") pipe=cat;;
-    *)  pipe="mail -E -s '$host ${arg##*/} run output' $output";;
+success=YES info=YES badconfig=NO empty_output=YES	# Defaults when ${run}_* aren't YES/NO
+for var in success info badconfig empty_output; do
+    case $(eval echo "\$${arg##*/}_show_$var") in
+    [Yy][Ee][Ss]) eval $var=YES;;
+    [Nn][Oo])     eval $var=NO;;
     esac
+done
 
-    success=YES info=YES badconfig=NO empty_output=YES	# Defaults when ${run}_* aren't YES/NO
-    for var in success info badconfig empty_output
-    do
-        case $(eval echo "\$${arg##*/}_show_$var") in
-        [Yy][Ee][Ss]) eval $var=YES;;
-        [Nn][Oo])     eval $var=NO;;
-        esac
+case $arg in
+/*) if [ -d "$arg" ]; then
+        dirlist="$arg"
+    else
+        echo "$0: $arg not found" >&2
+        continue
+    fi
+    ;;
+*)  dirlist=
+    for top in /etc/periodic ${local_periodic}; do
+        [ -d $top/$arg ] && dirlist="$dirlist $top/$arg"
     done
+    ;;
+esac
 
-    case $arg in
-    /*) if [ -d "$arg" ]
-        then
-            dirlist="$arg"
-        else
-            echo "$0: $arg not found" >&2 
-            continue
-        fi;;
-    *)  dirlist=
-        for top in /etc/periodic ${local_periodic}
-        do
-            [ -d $top/$arg ] && dirlist="$dirlist $top/$arg"
-        done;;
-    esac
-
-    {
-        empty=TRUE
-        processed=0
-        for dir in $dirlist
-        do
-            for file in $dir/*
-            do
-                if [ -x $file -a ! -d $file ]
-                then
-                    output=TRUE
-                    processed=$(($processed + 1))
-                    $file </dev/null >$tmp_output 2>&1
-                    rc=$?
-                    if [ -s $tmp_output ]
-                    then
-                      case $rc in
-                      0)  [ $success = NO ] && output=FALSE;;
-                      1)  [ $info = NO ] && output=FALSE;;
-                      2)  [ $badconfig = NO ] && output=FALSE;;
-                      esac
-                      [ $output = TRUE ] && { cat $tmp_output; empty=FALSE; }
-                    fi
-                    cp /dev/null $tmp_output
+{
+    empty=TRUE
+    processed=0
+    for dir in $dirlist; do
+        for file in $dir/*; do
+            if [ -x $file -a ! -d $file ]; then
+                output=TRUE
+                processed=$(($processed + 1))
+                $file </dev/null >$tmp_output 2>&1
+                rc=$?
+                if [ -s $tmp_output ]; then
+                    case $rc in
+                    0)  [ $success = NO ] && output=FALSE;;
+                    1)  [ $info = NO ] && output=FALSE;;
+                    2)  [ $badconfig = NO ] && output=FALSE;;
+                    esac
+                    [ $output = TRUE ] && { cat $tmp_output; empty=FALSE; }
                 fi
-            done
+                cp /dev/null $tmp_output
+            fi
         done
-        if [ $empty = TRUE ]
-        then
-          if [ $empty_output = TRUE ]
-          then
+    done
+    if [ $empty = TRUE ]; then
+        if [ $empty_output = TRUE ]; then
             [ $processed = 1 ] && plural= || plural=s
             echo "No output from the $processed file$plural processed"
-          fi
-        else
-          echo ""
-          echo "-- End of $arg output --"
         fi
-    } | eval $pipe
-done
+    else
+        echo ""
+        echo "-- End of $arg output --"
+    fi
+} | output_pipe $arg "$context"
+
 rm -f $tmp_output


Property changes on: trunk/usr.sbin/periodic/periodic.sh
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.sbin/pmcannotate/Makefile
===================================================================
--- trunk/usr.sbin/pmcannotate/Makefile	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcannotate/Makefile	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,6 +1,7 @@
-#
 # $MidnightBSD$
 #
+# $FreeBSD: stable/10/usr.sbin/pmcannotate/Makefile 201390 2010-01-02 11:07:44Z ed $
+#
 
 PROG=	pmcannotate
 MAN=	pmcannotate.8

Modified: trunk/usr.sbin/pmcannotate/pmcannotate.8
===================================================================
--- trunk/usr.sbin/pmcannotate/pmcannotate.8	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcannotate/pmcannotate.8	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+.\" $MidnightBSD$
 .\" Copyright (c) 2008 Nokia Corporation
 .\" All rights reserved.
 .\"
@@ -25,7 +26,7 @@
 .\" out of the use of this software, even if advised of the possibility of
 .\" such damage.
 .\"
-.\" $MidnightBSD$
+.\" $FreeBSD: stable/10/usr.sbin/pmcannotate/pmcannotate.8 249375 2013-04-11 19:05:24Z joel $
 .\"
 .Dd November 20, 2008
 .Dt PMCANNOTATE 8
@@ -45,7 +46,7 @@
 .Nm
 utility can produce both C sources or assembly sources of a program with
 a line-by-line based profiling.
-The profiling informations are retrieved through a
+The profiling information is retrieved through a
 .Xr pmcstat 8
 raw output while the program operations are retrieved through the
 .Xr objdump 1
@@ -71,9 +72,9 @@
 .Bl -tag -width indent
 .It Fl a
 Shows the program profiling inlined in the assembly code only.
-No C informations involving C sources are provided.
+No C information involving C sources is provided.
 .It Fl h
-Prints out informations about the usage of the tool.
+Prints out information about the usage of the tool.
 .It Fl l Ar level
 Changes the lower bound (expressed in percentage) for traced functions
 that will be printed out in the report.


Property changes on: trunk/usr.sbin/pmcannotate/pmcannotate.8
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.sbin/pmcannotate/pmcannotate.c
===================================================================
--- trunk/usr.sbin/pmcannotate/pmcannotate.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcannotate/pmcannotate.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2008 Nokia Corporation
  * All rights reserved.
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcannotate/pmcannotate.c 266889 2014-05-30 15:00:50Z gnn $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -41,8 +42,8 @@
 
 #include <unistd.h>
 
-#define	FNBUFF	161
-#define	LNBUFF	161
+#define	FNBUFF	512
+#define	LNBUFF	512
 
 #define	TMPPATH	"/tmp/pmcannotate.XXXXXX"
 
@@ -118,8 +119,6 @@
 	void *ptr;
 	int nbytes;
 
-	if (isxdigit(str[1]) == 0)
-		return (0);
 	if (sscanf(str, " %p%n", &ptr, &nbytes) != 1)
 		return (0);
 	if (str[nbytes] != ':' || isspace(str[nbytes + 1]) == 0)

Modified: trunk/usr.sbin/pmccontrol/Makefile
===================================================================
--- trunk/usr.sbin/pmccontrol/Makefile	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmccontrol/Makefile	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,6 +1,7 @@
-#
 # $MidnightBSD$
 #
+# $FreeBSD: stable/10/usr.sbin/pmccontrol/Makefile 201390 2010-01-02 11:07:44Z ed $
+#
 
 PROG=	pmccontrol
 MAN=	pmccontrol.8

Modified: trunk/usr.sbin/pmccontrol/pmccontrol.8
===================================================================
--- trunk/usr.sbin/pmccontrol/pmccontrol.8	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmccontrol/pmccontrol.8	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+.\" $MidnightBSD$
 .\" Copyright (c) 2003,2008 Joseph Koshy.  All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -21,7 +22,7 @@
 .\" out of the use of this software, even if advised of the possibility of
 .\" such damage.
 .\"
-.\" $MidnightBSD$
+.\" $FreeBSD: stable/10/usr.sbin/pmccontrol/pmccontrol.8 206622 2010-04-14 19:08:06Z uqs $
 .\"
 .Dd November 9, 2008
 .Dt PMCCONTROL 8


Property changes on: trunk/usr.sbin/pmccontrol/pmccontrol.8
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.sbin/pmccontrol/pmccontrol.c
===================================================================
--- trunk/usr.sbin/pmccontrol/pmccontrol.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmccontrol/pmccontrol.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003,2004 Joseph Koshy
  * All rights reserved.
@@ -26,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmccontrol/pmccontrol.c 241737 2012-10-19 14:49:42Z ed $");
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -66,7 +67,7 @@
 
 #define	PMCC_PROGRAM_NAME	"pmccontrol"
 
-STAILQ_HEAD(pmcc_op_list, pmcc_op) head = STAILQ_HEAD_INITIALIZER(head);
+static STAILQ_HEAD(pmcc_op_list, pmcc_op) head = STAILQ_HEAD_INITIALIZER(head);
 
 struct pmcc_op {
 	char	op_cpu;
@@ -94,7 +95,7 @@
 	"       " PMCC_PROGRAM_NAME " [-e pmc | -d pmc | -c cpu] ...";
 
 #if DEBUG
-FILE *debug_stream = NULL;
+static FILE *debug_stream = NULL;
 #endif
 
 #if DEBUG
@@ -104,15 +105,6 @@
 #define DEBUG_MSG(m)		/*  */
 #endif /* !DEBUG */
 
-int pmc_syscall = -1;
-
-#define PMC_CALL(cmd, params)						\
-if ((error = syscall(pmc_syscall, PMC_OP_##cmd, (params))) != 0)	\
-{									\
-	DEBUG_MSG("ERROR: syscall [" #cmd "]");				\
-	exit(EX_OSERR);							\
-}
-
 #if DEBUG
 /* log debug messages to a separate file */
 static void

Modified: trunk/usr.sbin/pmcstat/Makefile
===================================================================
--- trunk/usr.sbin/pmcstat/Makefile	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/Makefile	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,6 +1,7 @@
-#
 # $MidnightBSD$
 #
+# $FreeBSD: stable/10/usr.sbin/pmcstat/Makefile 265604 2014-05-07 20:20:52Z scottl $
+#
 
 PROG=	pmcstat
 MAN=	pmcstat.8
@@ -9,6 +10,7 @@
 LDADD=	-lelf -lkvm -lpmc -lm -lncurses
 
 SRCS=	pmcstat.c pmcstat.h pmcstat_log.c \
-pmcpl_callgraph.c pmcpl_gprof.c pmcpl_annotate.c pmcpl_calltree.c
+pmcpl_callgraph.c pmcpl_gprof.c pmcpl_annotate.c \
+pmcpl_annotate_cg.c pmcpl_calltree.c
 
 .include <bsd.prog.mk>

Modified: trunk/usr.sbin/pmcstat/pmcpl_annotate.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_annotate.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_annotate.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -34,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_annotate.c 203790 2010-02-11 22:51:44Z fabient $");
 
 #include <sys/param.h>
 #include <sys/endian.h>

Modified: trunk/usr.sbin/pmcstat/pmcpl_annotate.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_annotate.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_annotate.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -27,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_annotate.h 203790 2010-02-11 22:51:44Z fabient $
  */
 
 #ifndef	_PMCSTAT_PL_ANNOTATE_H_

Added: trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.c	                        (rev 0)
+++ trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,128 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2005-2007, Joseph Koshy
+ * Copyright (c) 2007 The FreeBSD Foundation
+ * Copyright (c) 2014, Adrian Chadd, Netflix Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Transform a hwpmc(4) log into human readable form, and into
+ * gprof(1) compatible profiles.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_annotate_cg.c 265604 2014-05-07 20:20:52Z scottl $");
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/gmon.h>
+#include <sys/imgact_aout.h>
+#include <sys/imgact_elf.h>
+#include <sys/mman.h>
+#include <sys/pmc.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <libgen.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pmc.h>
+#include <pmclog.h>
+#include <sysexits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pmcstat.h"
+#include "pmcstat_log.h"
+#include "pmcpl_annotate_cg.h"
+
+/*
+ * Record a callchain.
+ */
+
+void
+pmcpl_annotate_cg_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
+    uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu)
+{
+	struct pmcstat_pcmap *map;
+	struct pmcstat_symbol *sym;
+	uintfptr_t newpc;
+	struct pmcstat_image *image;
+	int i;
+	char filename[PATH_MAX], funcname[PATH_MAX];
+	unsigned sline;
+
+	(void) pmcr; (void) nsamples; (void) usermode; (void) cpu;
+
+	for (i = 0; i < (int) nsamples; i++) {
+		map = NULL;
+		sym = NULL;
+		image = NULL;
+		filename[0] = '\0';
+		funcname[0] = '\0';
+		sline = 0;
+
+		map = pmcstat_process_find_map(usermode ? pp : pmcstat_kernproc, cc[i]);
+		if (map != NULL) {
+			assert(cc[i] >= map->ppm_lowpc && cc[i] < map->ppm_highpc);
+			image = map->ppm_image;
+			newpc = cc[i] - (map->ppm_lowpc +
+				(image->pi_vaddr - image->pi_start));
+			sym = pmcstat_symbol_search(image, newpc);
+		}
+
+		if (map != NULL && image != NULL && sym != NULL) {
+			(void) pmcstat_image_addr2line(image, cc[i],
+			    filename, sizeof(filename), &sline, funcname, sizeof(funcname));
+		}
+
+		if (map != NULL && sym != NULL) {
+			fprintf(args.pa_graphfile, "%p %s %s:%d\n",
+			    (void *)cc[i],
+			    funcname,
+			    filename,
+			    sline);
+		} else {
+			fprintf(args.pa_graphfile, "%p <unknown> ??:0\n",
+			    (void *) cc[i]);
+		}
+	}
+	fprintf(args.pa_graphfile, "--\n");
+}


Property changes on: trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.h	                        (rev 0)
+++ trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,43 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2005-2007, Joseph Koshy
+ * Copyright (c) 2007 The FreeBSD Foundation
+ * Copyright (c) 2014, Adrian Chadd, Netflix Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by A. Joseph Koshy under
+ * sponsorship from the FreeBSD Foundation and Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_annotate_cg.h 265604 2014-05-07 20:20:52Z scottl $
+ */
+
+#ifndef	_PMCSTAT_PL_ANNOTATE_CG_H_
+#define	_PMCSTAT_PL_ANNOTATE_CG_H_
+
+/* Function prototypes */
+void pmcpl_annotate_cg_process(
+    struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
+    uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu);
+
+#endif	/* _PMCSTAT_PL_ANNOTATE_CG_H_ */


Property changes on: trunk/usr.sbin/pmcstat/pmcpl_annotate_cg.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/usr.sbin/pmcstat/pmcpl_callgraph.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_callgraph.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_callgraph.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -34,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_callgraph.c 212176 2010-09-03 13:54:02Z fabient $");
 
 #include <sys/param.h>
 #include <sys/endian.h>

Modified: trunk/usr.sbin/pmcstat/pmcpl_callgraph.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_callgraph.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_callgraph.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -27,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_callgraph.h 203790 2010-02-11 22:51:44Z fabient $
  */
 
 #ifndef	_PMCSTAT_PL_CALLGRAPH_H_

Modified: trunk/usr.sbin/pmcstat/pmcpl_calltree.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_calltree.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_calltree.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2012, Fabien Thomas
  * All rights reserved.
@@ -32,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_calltree.c 299826 2016-05-15 03:15:36Z pfg $");
 
 #include <sys/param.h>
 #include <sys/endian.h>
@@ -125,7 +126,7 @@
 	STAILQ_ENTRY(pmcpl_ct_node_hash) pch_next;
 };
 
-struct pmcpl_ct_sample pmcpl_ct_callid;
+static struct pmcpl_ct_sample pmcpl_ct_callid;
 
 #define	PMCPL_CT_MAXCOL		PMC_CALLCHAIN_DEPTH_MAX
 #define	PMCPL_CT_MAXLINE	1024	/* TODO: dynamic. */
@@ -135,8 +136,8 @@
 	unsigned	ln_index;
 };
 
-struct pmcpl_ct_line	pmcpl_ct_topmax[PMCPL_CT_MAXLINE+1];
-struct pmcpl_ct_node
+static struct pmcpl_ct_line	pmcpl_ct_topmax[PMCPL_CT_MAXLINE+1];
+static struct pmcpl_ct_node
     *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL+1][PMCPL_CT_MAXLINE+1];
 
 /*
@@ -830,7 +831,7 @@
 
 	/*
 	 * Child cost.
-	 * TODO: attach child cost to the real position in the funtion.
+	 * TODO: attach child cost to the real position in the function.
 	 * TODO: cfn=<fn> / call <ncall> addr(<fn>) / addr(call <fn>) <arccost>
 	 */
 	for (i=0 ; i<ct->pct_narc; i++) {
@@ -1023,9 +1024,6 @@
 	struct pmcpl_ct_node *child;
 
 	/*
-	 * Child cost.
-	 * TODO: attach child cost to the real position in the funtion.
-	 * TODO: cfn=<fn> / call <ncall> addr(<fn>) / addr(call <fn>) <arccost>
 	 * Resolve parent and compare to each instr location.
 	 */
 	faddr = ct->pct_image->pi_vaddr + ct->pct_func;

Modified: trunk/usr.sbin/pmcstat/pmcpl_calltree.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_calltree.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_calltree.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009, Fabien Thomas
  * All rights reserved.
@@ -23,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_calltree.h 203790 2010-02-11 22:51:44Z fabient $
  */
 
 #ifndef	_PMCSTAT_PL_CALLTREE_H_

Modified: trunk/usr.sbin/pmcstat/pmcpl_gprof.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_gprof.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_gprof.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -35,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_gprof.c 322399 2017-08-11 11:38:04Z kib $");
 
 #include <sys/param.h>
 #include <sys/endian.h>
@@ -74,6 +75,14 @@
 #include "pmcpl_callgraph.h"
 #include "pmcpl_gprof.h"
 
+typedef	uint64_t	WIDEHISTCOUNTER;
+
+#define	WIDEHISTCOUNTER_MAX		UINT64_MAX
+#define	HISTCOUNTER_MAX			USHRT_MAX
+#define	WIDEHISTCOUNTER_GMONTYPE	((int) 64)
+#define	HISTCOUNTER_GMONTYPE		((int) 0)
+static int hc_sz=0;
+
 /*
  * struct pmcstat_gmonfile tracks a given 'gmon.out' file.  These
  * files are mmap()'ed in as needed.
@@ -126,11 +135,13 @@
 
 	gm.lpc = image->pi_start;
 	gm.hpc = image->pi_end;
-	gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) +
-	    sizeof(struct gmonhdr);
+	gm.ncnt = (pgf->pgf_nbuckets * hc_sz) + sizeof(struct gmonhdr);
 	gm.version = GMONVERSION;
 	gm.profrate = 0;		/* use ticks */
-	gm.histcounter_type = 0;	/* compatibility with moncontrol() */
+	if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC)
+		gm.histcounter_type = WIDEHISTCOUNTER_GMONTYPE;
+	else
+		gm.histcounter_type = HISTCOUNTER_GMONTYPE;
 	gm.spare[0] = gm.spare[1] = 0;
 
 	/* Write out the gmon header */
@@ -326,7 +337,7 @@
 	else {
 		/*
 		 * Otherwise use a prefix from the original name and
-		 * upto 3 digits.
+		 * up to 3 digits.
 		 */
 		nlen = strlen(sn);
 		nlen = min(nlen, (int) (sizeof(name)-sizeof("~NNN.gmon")));
@@ -400,6 +411,7 @@
 	struct pmcstat_gmonfile *pgf;
 	uintfptr_t bucket;
 	HISTCOUNTER *hc;
+	WIDEHISTCOUNTER *whc;
 	pmc_id_t pmcid;
 
 	(void) nsamples; (void) usermode; (void) cpu;
@@ -437,6 +449,14 @@
 	 */
 	pgf = pmcstat_image_find_gmonfile(image, pmcid);
 	if (pgf == NULL) {
+		if (hc_sz == 0) {
+			/* Determine the correct histcounter size. */
+			if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC)
+				hc_sz = sizeof(WIDEHISTCOUNTER);
+			else
+				hc_sz = sizeof(HISTCOUNTER);
+		}
+
 		if ((pgf = calloc(1, sizeof(*pgf))) == NULL)
 			err(EX_OSERR, "ERROR:");
 
@@ -445,10 +465,10 @@
 		    image, pmcid);
 		pgf->pgf_pmcid = pmcid;
 		assert(image->pi_end > image->pi_start);
-		pgf->pgf_nbuckets = (image->pi_end - image->pi_start) /
-		    FUNCTION_ALIGNMENT;	/* see <machine/profile.h> */
+		pgf->pgf_nbuckets = howmany(image->pi_end - image->pi_start,
+		    FUNCTION_ALIGNMENT);	/* see <machine/profile.h> */
 		pgf->pgf_ndatabytes = sizeof(struct gmonhdr) +
-		    pgf->pgf_nbuckets * sizeof(HISTCOUNTER);
+		    pgf->pgf_nbuckets * hc_sz;
 		pgf->pgf_nsamples = 0;
 		pgf->pgf_file = NULL;
 
@@ -474,15 +494,26 @@
 
 	assert(bucket < pgf->pgf_nbuckets);
 
-	hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
-	    sizeof(struct gmonhdr));
+	if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) {
+		whc = (WIDEHISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
+		    sizeof(struct gmonhdr));
 
-	/* saturating add */
-	if (hc[bucket] < 0xFFFFU)  /* XXX tie this to sizeof(HISTCOUNTER) */
-		hc[bucket]++;
-	else /* mark that an overflow occurred */
-		pgf->pgf_overflow = 1;
+		/* saturating add */
+		if (whc[bucket] < WIDEHISTCOUNTER_MAX)
+			whc[bucket]++;
+		else /* mark that an overflow occurred */
+			pgf->pgf_overflow = 1;
+	} else {
+		hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
+		    sizeof(struct gmonhdr));
 
+		/* saturating add */
+		if (hc[bucket] < HISTCOUNTER_MAX)
+			hc[bucket]++;
+		else /* mark that an overflow occurred */
+			pgf->pgf_overflow = 1;
+	}
+
 	pgf->pgf_nsamples++;
 }
 

Modified: trunk/usr.sbin/pmcstat/pmcpl_gprof.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcpl_gprof.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcpl_gprof.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -28,7 +29,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcpl_gprof.h 203790 2010-02-11 22:51:44Z fabient $
  */
 
 #ifndef	_PMCSTAT_PL_GPROF_H_

Modified: trunk/usr.sbin/pmcstat/pmcstat.8
===================================================================
--- trunk/usr.sbin/pmcstat/pmcstat.8	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcstat.8	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+.\" $MidnightBSD$
 .\" Copyright (c) 2003-2008 Joseph Koshy
 .\" Copyright (c) 2007 The FreeBSD Foundation
 .\" All rights reserved.
@@ -23,9 +24,9 @@
 .\" out of the use of this software, even if advised of the possibility of
 .\" such damage.
 .\"
-.\" $MidnightBSD$
+.\" $FreeBSD: stable/10/usr.sbin/pmcstat/pmcstat.8 294046 2016-01-14 22:02:21Z jtl $
 .\"
-.Dd September 19, 2008
+.Dd November 18, 2015
 .Dt PMCSTAT 8
 .Os
 .Sh NAME
@@ -46,11 +47,14 @@
 .Op Fl S Ar event-spec
 .Op Fl T
 .Op Fl W
+.Op Fl a Ar pathname
 .Op Fl c Ar cpu-spec
 .Op Fl d
+.Op Fl e
 .Op Fl f Ar pluginopt
 .Op Fl g
 .Op Fl k Ar kerneldir
+.Op Fl l Ar secs
 .Op Fl m Ar pathname
 .Op Fl n Ar rate
 .Op Fl o Ar outputfile
@@ -221,6 +225,21 @@
 dynamic behaviour of processes in the system.
 It may incur substantial overhead if enabled.
 The default is for this feature to be disabled.
+.It Fl a Ar pathname
+Perform a symbol and file:line lookup for each address in each
+callgraph and save the output to
+.Ar pathname .
+Unlike
+.Fl m
+that only resolves the first symbol in the graph, this resolves
+every node in the callgraph, or prints out addresses if no
+lookup information is available.
+This option requires the
+.Fl R
+option to read in samples that were previously collected and
+saved with the 
+.Fl O
+option.
 .It Fl c Ar cpu-spec
 Set the cpus for subsequent system mode PMCs specified on the
 command line to
@@ -229,8 +248,8 @@
 .Ar cpu-spec
 is a comma separated list of CPU numbers, or the literal
 .Sq *
-denoting all unhalted CPUs.
-The default is to allocate system mode PMCs on all unhalted
+denoting all available CPUs.
+The default is to allocate system mode PMCs on all available
 CPUs.
 .It Fl d
 Toggle between process mode PMCs measuring events for the target
@@ -237,6 +256,18 @@
 process' current and future children or only measuring events for
 the target process.
 The default is to measure events for the target process alone.
+(it has to be passed in the command line prior to
+.Fl p ,
+.Fl s ,
+.Fl P ,
+or
+.Fl S ) .
+.It Fl e
+Specify that the gprof profile files will use a wide history counter.
+These files are produced in a format compatible with
+.Xr gprof 1 .
+However, other tools that cannot fully parse a BSD-style
+gmon header might be unable to correctly parse these files.
 .It Fl f Ar pluginopt
 Pass option string to the active plugin.
 .br
@@ -256,14 +287,22 @@
 This directory specifies where
 .Nm
 should look for the kernel and its modules.
-The default is
-.Pa /boot/kernel .
+The default is to use the path of the running kernel obtained from the
+.Va kern.bootfile
+sysctl.
+.It Fl l Ar secs
+Set system-wide performance measurement duration for
+.Ar secs
+seconds.
+The argument
+.Ar secs
+may be a fractional value.
 .It Fl m Ar pathname
 Print the sampled PCs with the name, the start and ending addresses
 of the function within they live.
 The
 .Ar pathname
-argument is mandatory and indicates where informations will be stored.
+argument is mandatory and indicates where the information will be stored.
 If argument
 .Ar pathname
 is a
@@ -271,6 +310,12 @@
 this information is sent to the output file specified by the
 .Fl o
 option.
+This option requires the
+.Fl R
+option to read in samples that were previously collected and
+saved with the
+.Fl O
+option.
 .It Fl n Ar rate
 Set the default sampling rate for subsequent sampling mode
 PMCs specified on the command line.
@@ -388,7 +433,7 @@
 is specified,
 .Nm
 may issue the following diagnostic messages:
-.Bl -diag -width indent
+.Bl -diag
 .It "#callchain/dubious-frames"
 The number of callchain records that had an
 .Dq impossible


Property changes on: trunk/usr.sbin/pmcstat/pmcstat.8
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.sbin/pmcstat/pmcstat.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcstat.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcstat.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2003-2008, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -29,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcstat.c 294046 2016-01-14 22:02:21Z jtl $");
 
 #include <sys/param.h>
 #include <sys/cpuset.h>
@@ -98,7 +99,7 @@
  *    and starts them. Sets up
  *    monitoring for the child.
  *  - Signals child to start.
- *					- Recieves signal, attempts exec().
+ *					- Receives signal, attempts exec().
  *
  * After this point normal processing can happen.
  */
@@ -105,23 +106,21 @@
 
 /* Globals */
 
-int	pmcstat_interrupt = 0;
-int	pmcstat_displayheight = DEFAULT_DISPLAY_HEIGHT;
-int	pmcstat_displaywidth  = DEFAULT_DISPLAY_WIDTH;
-int	pmcstat_sockpair[NSOCKPAIRFD];
-int	pmcstat_kq;
-kvm_t	*pmcstat_kvm;
-struct kinfo_proc *pmcstat_plist;
+int		pmcstat_displayheight = DEFAULT_DISPLAY_HEIGHT;
+int		pmcstat_displaywidth  = DEFAULT_DISPLAY_WIDTH;
+static int	pmcstat_sockpair[NSOCKPAIRFD];
+static int	pmcstat_kq;
+static kvm_t	*pmcstat_kvm;
+static struct kinfo_proc *pmcstat_plist;
 struct pmcstat_args args;
 
 static void
 pmcstat_clone_event_descriptor(struct pmcstat_ev *ev, const cpuset_t *cpumask)
 {
-	int cpu, mcpu;
+	int cpu;
 	struct pmcstat_ev *ev_clone;
 
-	mcpu = sizeof(*cpumask) * NBBY;
-	for (cpu = 0; cpu < mcpu; cpu++) {
+	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
 		if (!CPU_ISSET(cpu, cpumask))
 			continue;
 
@@ -162,6 +161,7 @@
 		CPU_SET(cpu, cpumask);
 		s = end + strspn(end, ", \t");
 	} while (*s);
+	assert(!CPU_EMPTY(cpumask));
 }
 
 void
@@ -504,11 +504,14 @@
 	    "\t -S spec\t allocate a system-wide sampling PMC\n"
 	    "\t -T\t\t start in top mode\n"
 	    "\t -W\t\t (toggle) show counts per context switch\n"
+	    "\t -a <file>\t print sampled PCs and callgraph to \"file\"\n"
 	    "\t -c cpu-list\t set cpus for subsequent system-wide PMCs\n"
 	    "\t -d\t\t (toggle) track descendants\n"
+	    "\t -e\t\t use wide history counter for gprof(1) output\n"
 	    "\t -f spec\t pass \"spec\" to as plugin option\n"
 	    "\t -g\t\t produce gprof(1) compatible profiles\n"
 	    "\t -k dir\t\t set the path to the kernel\n"
+	    "\t -l secs\t set duration time\n"
 	    "\t -m file\t print sampled PCs to \"file\"\n"
 	    "\t -n rate\t set sampling rate\n"
 	    "\t -o file\t send print output to \"file\"\n"
@@ -549,13 +552,14 @@
 int
 main(int argc, char **argv)
 {
-	cpuset_t cpumask;
+	cpuset_t cpumask, rootmask;
 	double interval;
-	int hcpu, option, npmc, ncpu;
-	int c, check_driver_stats, current_cpu, current_sampling_count;
+	double duration;
+	int option, npmc;
+	int c, check_driver_stats, current_sampling_count;
 	int do_callchain, do_descendants, do_logproccsw, do_logprocexit;
 	int do_print, do_read;
-	size_t dummy;
+	size_t len;
 	int graphdepth;
 	int pipefd[2], rfd;
 	int use_cumulative_counts;
@@ -572,7 +576,6 @@
 	char buffer[PATH_MAX];
 
 	check_driver_stats      = 0;
-	current_cpu 		= 0;
 	current_sampling_count  = DEFAULT_SAMPLE_COUNT;
 	do_callchain		= 1;
 	do_descendants          = 0;
@@ -585,7 +588,6 @@
 	args.pa_verbosity	= 1;
 	args.pa_logfd		= -1;
 	args.pa_fsroot		= "";
-	args.pa_kernel		= strdup("/boot/kernel");
 	args.pa_samplesdir	= ".";
 	args.pa_printfile	= stderr;
 	args.pa_graphdepth	= DEFAULT_CALLGRAPH_DEPTH;
@@ -601,6 +603,7 @@
 	args.pa_toptty		= 0;
 	args.pa_topcolor	= 0;
 	args.pa_mergepmc	= 0;
+	args.pa_duration	= 0.0;
 	STAILQ_INIT(&args.pa_events);
 	SLIST_INIT(&args.pa_targets);
 	bzero(&ds_start, sizeof(ds_start));
@@ -608,19 +611,32 @@
 	ev = NULL;
 	CPU_ZERO(&cpumask);
 
+	/* Default to using the running system kernel. */
+	len = 0;
+	if (sysctlbyname("kern.bootfile", NULL, &len, NULL, 0) == -1)
+		err(EX_OSERR, "ERROR: Cannot determine path of running kernel");
+	args.pa_kernel = malloc(len + 1);
+	if (sysctlbyname("kern.bootfile", args.pa_kernel, &len, NULL, 0) == -1)
+		err(EX_OSERR, "ERROR: Cannot determine path of running kernel");
+
 	/*
-	 * The initial CPU mask specifies all non-halted CPUS in the
-	 * system.
+	 * The initial CPU mask specifies the root mask of this process
+	 * which is usually all CPUs in the system.
 	 */
-	dummy = sizeof(int);
-	if (sysctlbyname("hw.ncpu", &ncpu, &dummy, NULL, 0) < 0)
-		err(EX_OSERR, "ERROR: Cannot determine the number of CPUs");
-	for (hcpu = 0; hcpu < ncpu; hcpu++)
-		CPU_SET(hcpu, &cpumask);
+	if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+	    sizeof(rootmask), &rootmask) == -1)
+		err(EX_OSERR, "ERROR: Cannot determine the root set of CPUs");
+	CPU_COPY(&rootmask, &cpumask);
 
 	while ((option = getopt(argc, argv,
-	    "CD:EF:G:M:NO:P:R:S:TWc:df:gk:m:n:o:p:qr:s:t:vw:z:")) != -1)
+	    "CD:EF:G:M:NO:P:R:S:TWa:c:def:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1)
 		switch (option) {
+		case 'a':	/* Annotate + callgraph */
+			args.pa_flags |= FLAG_DO_ANNOTATE;
+			args.pa_plugin = PMCSTAT_PL_ANNOTATE_CG;
+			graphfilename  = optarg;
+			break;
+
 		case 'C':	/* cumulative values */
 			use_cumulative_counts = !use_cumulative_counts;
 			args.pa_required |= FLAG_HAS_COUNTING_PMCS;
@@ -627,11 +643,9 @@
 			break;
 
 		case 'c':	/* CPU */
-
-			if (optarg[0] == '*' && optarg[1] == '\0') {
-				for (hcpu = 0; hcpu < ncpu; hcpu++)
-					CPU_SET(hcpu, &cpumask);
-			} else
+			if (optarg[0] == '*' && optarg[1] == '\0')
+				CPU_COPY(&rootmask, &cpumask);
+			else
 				pmcstat_get_cpumask(optarg, &cpumask);
 
 			args.pa_flags	 |= FLAGS_HAS_CPUMASK;
@@ -656,6 +670,10 @@
 			args.pa_required |= FLAG_HAS_PROCESS_PMCS;
 			break;
 
+		case 'e':	/* wide gprof metrics */
+			args.pa_flags |= FLAG_DO_WIDE_GPROF_HC;
+			break;
+
 		case 'F':	/* produce a system-wide calltree */
 			args.pa_flags |= FLAG_DO_CALLGRAPHS;
 			args.pa_plugin = PMCSTAT_PL_CALLTREE;
@@ -687,6 +705,15 @@
 			args.pa_flags    |= FLAG_HAS_KERNELPATH;
 			break;
 
+		case 'l':	/* time duration in seconds */
+			duration = strtod(optarg, &end);
+			if (*end != '\0' || duration <= 0)
+				errx(EX_USAGE, "ERROR: Illegal duration time "
+				    "value \"%s\".", optarg);
+			args.pa_flags |= FLAG_HAS_DURATION;
+			args.pa_duration = duration;
+			break;
+
 		case 'm':
 			args.pa_flags |= FLAG_DO_ANNOTATE;
 			args.pa_plugin = PMCSTAT_PL_ANNOTATE;
@@ -747,13 +774,9 @@
 			else
 				ev->ev_count = -1;
 
-			if (option == 'S' || option == 's') {
-				hcpu = sizeof(cpumask) * NBBY;
-				for (hcpu--; hcpu >= 0; hcpu--)
-					if (CPU_ISSET(hcpu, &cpumask))
-						break;
-				ev->ev_cpu = hcpu;
-			} else
+			if (option == 'S' || option == 's')
+				ev->ev_cpu = CPU_FFS(&cpumask) - 1;
+			else
 				ev->ev_cpu = PMC_CPU_ANY;
 
 			ev->ev_flags = 0;
@@ -780,11 +803,9 @@
 			STAILQ_INSERT_TAIL(&args.pa_events, ev, ev_next);
 
 			if (option == 's' || option == 'S') {
-				hcpu = CPU_ISSET(ev->ev_cpu, &cpumask);
 				CPU_CLR(ev->ev_cpu, &cpumask);
 				pmcstat_clone_event_descriptor(ev, &cpumask);
-				if (hcpu != 0)
-					CPU_SET(ev->ev_cpu, &cpumask);
+				CPU_SET(ev->ev_cpu, &cpumask);
 			}
 
 			break;
@@ -917,9 +938,16 @@
 		errx(EX_USAGE,
 		    "ERROR: options -O and -R are mutually exclusive.");
 
-	/* -m option is allowed with -R only. */
+	/* disallow -T and -l together */
+	if ((args.pa_flags & FLAG_HAS_DURATION) &&
+	    (args.pa_flags & FLAG_DO_TOP))
+		errx(EX_USAGE, "ERROR: options -T and -l are mutually "
+		    "exclusive.");
+
+	/* -a and -m require -R */
 	if (args.pa_flags & FLAG_DO_ANNOTATE && args.pa_inputpath == NULL)
-		errx(EX_USAGE, "ERROR: option -m requires an input file");
+		errx(EX_USAGE, "ERROR: option %s requires an input file",
+		    args.pa_plugin == PMCSTAT_PL_ANNOTATE ? "-m" : "-a");
 
 	/* -m option is not allowed combined with -g or -G. */
 	if (args.pa_flags & FLAG_DO_ANNOTATE &&
@@ -1000,6 +1028,13 @@
 "ERROR: options -g/-G/-m/-T require sampling PMCs or -R to be specified."
 		    );
 
+	/* check if -e was specified without -g */
+	if ((args.pa_flags & FLAG_DO_WIDE_GPROF_HC) &&
+	    !(args.pa_flags & FLAG_DO_GPROF))
+		errx(EX_USAGE,
+"ERROR: option -e requires gprof mode to be specified."
+		    );
+
 	/* check if -O was spuriously specified */
 	if ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) &&
 	    (args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0)
@@ -1037,33 +1072,31 @@
 		    );
 
 	/*
-	 * Check if "-k kerneldir" was specified, and if whether
-	 * 'kerneldir' actually refers to a file.  If so, use
-	 * `dirname path` to determine the kernel directory.
+	 * Check if 'kerneldir' refers to a file rather than a
+	 * directory.  If so, use `dirname path` to determine the
+	 * kernel directory.
 	 */
-	if (args.pa_flags & FLAG_HAS_KERNELPATH) {
-		(void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot,
-		    args.pa_kernel);
+	(void) snprintf(buffer, sizeof(buffer), "%s%s", args.pa_fsroot,
+	    args.pa_kernel);
+	if (stat(buffer, &sb) < 0)
+		err(EX_OSERR, "ERROR: Cannot locate kernel \"%s\"",
+		    buffer);
+	if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode))
+		errx(EX_USAGE, "ERROR: \"%s\": Unsupported file type.",
+		    buffer);
+	if (!S_ISDIR(sb.st_mode)) {
+		tmp = args.pa_kernel;
+		args.pa_kernel = strdup(dirname(args.pa_kernel));
+		free(tmp);
+		(void) snprintf(buffer, sizeof(buffer), "%s%s",
+		    args.pa_fsroot, args.pa_kernel);
 		if (stat(buffer, &sb) < 0)
-			err(EX_OSERR, "ERROR: Cannot locate kernel \"%s\"",
+			err(EX_OSERR, "ERROR: Cannot stat \"%s\"",
 			    buffer);
-		if (!S_ISREG(sb.st_mode) && !S_ISDIR(sb.st_mode))
-			errx(EX_USAGE, "ERROR: \"%s\": Unsupported file type.",
+		if (!S_ISDIR(sb.st_mode))
+			errx(EX_USAGE,
+			    "ERROR: \"%s\" is not a directory.",
 			    buffer);
-		if (!S_ISDIR(sb.st_mode)) {
-			tmp = args.pa_kernel;
-			args.pa_kernel = strdup(dirname(args.pa_kernel));
-			free(tmp);
-			(void) snprintf(buffer, sizeof(buffer), "%s%s",
-			    args.pa_fsroot, args.pa_kernel);
-			if (stat(buffer, &sb) < 0)
-				err(EX_OSERR, "ERROR: Cannot stat \"%s\"",
-				    buffer);
-			if (!S_ISDIR(sb.st_mode))
-				errx(EX_USAGE,
-				    "ERROR: \"%s\" is not a directory.",
-				    buffer);
-		}
 	}
 
 	/*
@@ -1273,6 +1306,20 @@
 			    "ERROR: Cannot register kevent for timer");
 	}
 
+	/*
+	 * Setup a duration timer if we have sampling mode PMCs and
+	 * a duration time is set
+	 */
+	if ((args.pa_flags & FLAG_HAS_SAMPLING_PMCS) &&
+	    (args.pa_flags & FLAG_HAS_DURATION)) {
+		EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD, 0,
+		    args.pa_duration * 1000, NULL);
+
+		if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
+			err(EX_OSERR, "ERROR: Cannot register kevent for "
+			    "time duration");
+	}
+
 	/* attach PMCs to the target process, starting it if specified */
 	if (args.pa_flags & FLAG_HAS_COMMANDLINE)
 		pmcstat_create_process();
@@ -1349,7 +1396,7 @@
 
 	/*
 	 * loop till either the target process (if any) exits, or we
-	 * are killed by a SIGINT.
+	 * are killed by a SIGINT or we reached the time duration.
 	 */
 	runstate = PMCSTAT_RUNNING;
 	do_print = do_read = 0;
@@ -1416,7 +1463,13 @@
 
 			break;
 
-		case EVFILT_TIMER: /* print out counting PMCs */
+		case EVFILT_TIMER:
+			/* time duration reached, exit */
+			if (args.pa_flags & FLAG_HAS_DURATION) {
+				runstate = PMCSTAT_FINISHED;
+				break;
+			}
+			/* print out counting PMCs */
 			if ((args.pa_flags & FLAG_DO_TOP) &&
 			     pmc_flush_logfile() == 0)
 				do_read = 1;
@@ -1460,14 +1513,24 @@
 			    "ERROR: Cannot retrieve driver statistics");
 		if (ds_start.pm_intr_bufferfull != ds_end.pm_intr_bufferfull &&
 		    args.pa_verbosity > 0)
-			warnx("WARNING: some samples were dropped.\n"
-"Please consider tuning the \"kern.hwpmc.nsamples\" tunable."
+			warnx(
+"WARNING: sampling was paused at least %u time%s.\n"
+"Please consider tuning the \"kern.hwpmc.nsamples\" tunable.",
+			    ds_end.pm_intr_bufferfull -
+			    ds_start.pm_intr_bufferfull,
+			    ((ds_end.pm_intr_bufferfull -
+			    ds_start.pm_intr_bufferfull) != 1) ? "s" : ""
 			    );
 		if (ds_start.pm_buffer_requests_failed !=
 		    ds_end.pm_buffer_requests_failed &&
 		    args.pa_verbosity > 0)
-			warnx("WARNING: some events were discarded.\n"
-"Please consider tuning the \"kern.hwpmc.nbuffers\" tunable."
+			warnx(
+"WARNING: at least %u event%s were discarded while running.\n"
+"Please consider tuning the \"kern.hwpmc.nbuffers\" tunable.",
+	 		    ds_end.pm_buffer_requests_failed -
+			    ds_start.pm_buffer_requests_failed,
+			    ((ds_end.pm_buffer_requests_failed -
+			    ds_start.pm_buffer_requests_failed) != 1) ? "s" : ""
 			    );
 	}
 

Modified: trunk/usr.sbin/pmcstat/pmcstat.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcstat.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcstat.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -27,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcstat.h 294046 2016-01-14 22:02:21Z jtl $
  */
 
 #ifndef	_PMCSTAT_H_
@@ -54,6 +55,8 @@
 #define	FLAG_DO_TOP			0x00010000	/* -T */
 #define	FLAG_DO_ANALYSIS		0x00020000	/* -g or -G or -m or -T */
 #define	FLAGS_HAS_CPUMASK		0x00040000	/* -c */
+#define	FLAG_HAS_DURATION		0x00080000	/* -l secs */
+#define	FLAG_DO_WIDE_GPROF_HC		0x00100000	/* -e */
 
 #define	DEFAULT_SAMPLE_COUNT		65536
 #define	DEFAULT_WAIT_INTERVAL		5.0
@@ -60,7 +63,7 @@
 #define	DEFAULT_DISPLAY_HEIGHT		256		/* file virtual height */
 #define	DEFAULT_DISPLAY_WIDTH		1024		/* file virtual width */
 #define	DEFAULT_BUFFER_SIZE		4096
-#define	DEFAULT_CALLGRAPH_DEPTH		4
+#define	DEFAULT_CALLGRAPH_DEPTH		16
 
 #define	PRINT_HEADER_PREFIX		"# "
 #define	READPIPEFD			0
@@ -91,6 +94,7 @@
 #define PMCSTAT_PL_GPROF	2
 #define PMCSTAT_PL_ANNOTATE	3
 #define PMCSTAT_PL_CALLTREE	4
+#define PMCSTAT_PL_ANNOTATE_CG	5
 
 #define PMCSTAT_TOP_DELTA 	0
 #define PMCSTAT_TOP_ACCUM	1
@@ -148,6 +152,7 @@
 	int	pa_toptty;		/* output to tty or file */
 	int	pa_topcolor;		/* terminal support color */
 	int	pa_mergepmc;		/* merge PMC with same name */
+	double	pa_duration;		/* time duration */
 	int	pa_argc;
 	char	**pa_argv;
 	STAILQ_HEAD(, pmcstat_ev) pa_events;

Modified: trunk/usr.sbin/pmcstat/pmcstat_log.c
===================================================================
--- trunk/usr.sbin/pmcstat/pmcstat_log.c	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcstat_log.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -34,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__MBSDID("$MidnightBSD$");
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstat/pmcstat_log.c 299826 2016-05-15 03:15:36Z pfg $");
 
 #include <sys/param.h>
 #include <sys/endian.h>
@@ -142,7 +143,7 @@
 struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH];
 
 struct pmcstat_stats pmcstat_stats; /* statistics */
-int ps_samples_period; /* samples count between top refresh. */
+static int ps_samples_period; /* samples count between top refresh. */
 
 struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */
 
@@ -149,9 +150,10 @@
 #include "pmcpl_gprof.h"
 #include "pmcpl_callgraph.h"
 #include "pmcpl_annotate.h"
+#include "pmcpl_annotate_cg.h"
 #include "pmcpl_calltree.h"
 
-struct pmc_plugins  {
+static struct pmc_plugins  {
 	const char 	*pl_name;	/* name */
 
 	/* configure */
@@ -214,11 +216,16 @@
 		.pl_topdisplay		= pmcpl_ct_topdisplay
 	},
 	{
+		.pl_name		= "annotate_cg",
+		.pl_process		= pmcpl_annotate_cg_process
+	},
+
+	{
 		.pl_name		= NULL
 	}
 };
 
-int pmcstat_mergepmc;
+static int pmcstat_mergepmc;
 
 int pmcstat_pmcinfilter = 0; /* PMC filter for top mode. */
 float pmcstat_threshold = 0.5; /* Cost filter for top mode. */
@@ -254,7 +261,7 @@
 /*
  * A simple implementation of interned strings.  Each interned string
  * is assigned a unique address, so that subsequent string compares
- * can be done by a simple pointer comparision instead of using
+ * can be done by a simple pointer comparison instead of using
  * strcmp().  This speeds up hash table lookups and saves memory if
  * duplicate strings are the norm.
  */
@@ -275,7 +282,7 @@
 /*
  * PMC Top mode pause state.
  */
-int pmcstat_pause;
+static int pmcstat_pause;
 
 static void
 pmcstat_stats_reset(int reset_global)
@@ -301,10 +308,10 @@
 static int
 pmcstat_string_compute_hash(const char *s)
 {
-	int hash;
+	unsigned hash;
 
-	for (hash = 0; *s; s++)
-		hash ^= *s;
+	for (hash = 2166136261; *s; s++)
+		hash = (hash ^ *s) * 16777619;
 
 	return (hash & PMCSTAT_HASH_MASK);
 }
@@ -572,6 +579,8 @@
 	}
 
 	image->pi_symcount += newsyms;
+	if (image->pi_symcount == 0)
+		return;
 
 	assert(newsyms <= nfuncsyms);
 
@@ -708,8 +717,9 @@
 				        ph.p_offset);
 				break;
 			case PT_LOAD:
-				if (ph.p_offset == 0)
-					image->pi_vaddr = ph.p_vaddr;
+				if ((ph.p_flags & PF_X) != 0 &&
+				    (ph.p_offset & (-ph.p_align)) == 0)
+					image->pi_vaddr = ph.p_vaddr & (-ph.p_align);
 				break;
 			}
 		}
@@ -1352,7 +1362,7 @@
 	assert(args.pa_flags & FLAG_DO_ANALYSIS);
 
 	if (elf_version(EV_CURRENT) == EV_NONE)
-		err(EX_UNAVAILABLE, "Elf library intialization failed");
+		err(EX_UNAVAILABLE, "Elf library initialization failed");
 
 	while (pmclog_read(args.pa_logparser, &ev) == 0) {
 		assert(ev.pl_state == PMCLOG_OK);

Modified: trunk/usr.sbin/pmcstat/pmcstat_log.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcstat_log.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcstat_log.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2005-2007, Joseph Koshy
  * Copyright (c) 2007 The FreeBSD Foundation
@@ -28,7 +29,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcstat_log.h 241737 2012-10-19 14:49:42Z ed $
  */
 
 #ifndef	_PMCSTAT_LOG_H_
@@ -176,8 +177,8 @@
 /*
  * Top mode global options.
  */
-float pmcstat_threshold; /* Threshold to filter node. */
-int pmcstat_pmcinfilter; /* PMC index displayed. */
+extern float pmcstat_threshold; /* Threshold to filter node. */
+extern int pmcstat_pmcinfilter; /* PMC index displayed. */
 
 /* Function prototypes */
 const char *pmcstat_pmcid_to_name(pmc_id_t _pmcid);

Modified: trunk/usr.sbin/pmcstat/pmcstat_top.h
===================================================================
--- trunk/usr.sbin/pmcstat/pmcstat_top.h	2018-06-03 23:06:13 UTC (rev 10365)
+++ trunk/usr.sbin/pmcstat/pmcstat_top.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*-
  * Copyright (c) 2009, Fabien Thomas
  * All rights reserved.
@@ -23,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/pmcstat/pmcstat_top.h 203790 2010-02-11 22:51:44Z fabient $
  */
 
 #ifndef	_PMCSTAT_TOP_H_

Added: trunk/usr.sbin/pmcstudy/Makefile
===================================================================
--- trunk/usr.sbin/pmcstudy/Makefile	                        (rev 0)
+++ trunk/usr.sbin/pmcstudy/Makefile	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,13 @@
+# $MidnightBSD$
+#	@(#)Makefile	8.1 (Berkeley) 6/9/93
+# $FreeBSD: stable/10/usr.sbin/pmcstudy/Makefile 281235 2015-04-07 21:05:52Z rrs $
+
+PROG=	pmcstudy
+MAN=	pmcstudy.8
+SRCS= pmcstudy.c eval_expr.c
+CFLAGS+= -Wall -Werror
+
+BINDIR= /usr/bin
+
+.include <bsd.prog.mk>
+


Property changes on: trunk/usr.sbin/pmcstudy/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/pmcstudy/eval_expr.c
===================================================================
--- trunk/usr.sbin/pmcstudy/eval_expr.c	                        (rev 0)
+++ trunk/usr.sbin/pmcstudy/eval_expr.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,718 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2015 Netflix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include "eval_expr.h"
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstudy/eval_expr.c 293290 2016-01-07 00:40:51Z bdrewery $");
+
+static struct expression *
+alloc_and_hook_expr(struct expression **exp_p, struct expression **last_p)
+{
+	struct expression *ex, *at;
+
+	ex = malloc(sizeof(struct expression));
+	if (ex == NULL) {
+		printf("Out of memory in exp allocation\n");
+		exit(-2);
+	}
+	memset(ex, 0, sizeof(struct expression));
+	if (*exp_p == NULL) {
+		*exp_p = ex;
+	}
+	at = *last_p;
+	if (at == NULL) {
+		/* First one, its last */
+		*last_p = ex;
+	} else {
+		/* Chain it to the end and update last */
+		at->next = ex;
+		ex->prev = at;
+		*last_p = ex;
+	}
+	return (ex);
+}
+
+
+static int
+validate_expr(struct expression *exp, int val1_is_set, int op_is_set, int val2_is_set, 
+	      int *op_cnt)
+{
+	int val1, op, val2;
+	int open_cnt;
+	val1 = op = val2 = 0;
+	if (val1_is_set) {
+		val1 = 1;
+	}
+	if (op_is_set) {
+		op = 1;
+	}
+	if (val2_is_set) {
+		val2 = 1;
+	}
+	open_cnt = *op_cnt;
+	if (exp == NULL) {
+		/* End of the road */
+		if (val1 && op && val2 && (open_cnt == 0)) {
+			return(0);
+		} else {
+			return(1);
+		}
+	}
+	switch(exp->type) {
+	case TYPE_OP_PLUS:
+	case TYPE_OP_MINUS:
+	case TYPE_OP_MULT:
+	case TYPE_OP_DIVIDE:
+		if (val1 && op && val2) {
+			/* We are at x + y + 
+			 * collapse back to val/op
+			 */
+			val1 = 1;
+			op = 1;
+			val2 = 0;
+		} else if ((op == 0) && (val1)) {
+			op = 1;
+		} else {
+			printf("Op but no val1 set\n");
+			return(-1);
+		}
+		break;
+	case TYPE_PARN_OPEN:
+		if (exp->next == NULL) {
+			printf("NULL after open paren\n");
+			exit(-1);
+		}
+		if ((exp->next->type == TYPE_OP_PLUS) ||
+		    (exp->next->type == TYPE_OP_MINUS) ||
+		    (exp->next->type == TYPE_OP_DIVIDE) ||
+		    (exp->next->type == TYPE_OP_MULT)) {
+			printf("'( OP' -- not allowed\n");
+			return(-1);
+		}
+		if (val1 && (op == 0)) {
+			printf("'Val (' -- not allowed\n");
+			return(-1);
+		}
+		if (val1 && op && val2) {
+			printf("'Val OP Val (' -- not allowed\n");
+			return(-1);
+		}
+		open_cnt++;
+		*op_cnt = open_cnt;
+		if (val1) {
+			if (validate_expr(exp->next, 0, 0, 0, op_cnt) == 0) {
+				val2 = 1;
+			} else {
+				return(-1);
+			}
+		} else {
+			return(validate_expr(exp->next, 0, 0, 0, op_cnt));
+		}
+		break;
+	case TYPE_PARN_CLOSE:
+		open_cnt--;
+		*op_cnt = open_cnt;
+		if (val1 && op && val2) {
+			return(0);
+		} else {
+			printf("Found close paren and not complete\n");
+			return(-1);
+		}
+		break;
+	case TYPE_VALUE_CON:
+	case TYPE_VALUE_PMC:
+		if (val1 == 0) {
+			val1 = 1;
+		} else if (val1 && op) {
+			val2 = 1;
+		} else {
+			printf("val1 set, val2 about to be set op empty\n");
+			return(-1);
+		}
+		break;
+	default:
+		printf("unknown type %d\n", exp->type);
+		exit(-5);
+		break;
+	}
+	return(validate_expr(exp->next, val1, op, val2, op_cnt));
+}
+
+void
+print_exp(struct expression *exp)
+{
+	if (exp == NULL) {
+		printf("\n");
+		return;
+	}
+	switch(exp->type) {
+	case TYPE_OP_PLUS:
+		printf(" + ");
+		break;
+	case TYPE_OP_MINUS:
+		printf(" - ");
+		break;
+	case TYPE_OP_MULT:
+		printf(" * ");
+		break;
+	case TYPE_OP_DIVIDE:
+		printf(" / ");
+		break;
+	case TYPE_PARN_OPEN:
+		printf(" ( ");
+		break;
+	case TYPE_PARN_CLOSE:
+		printf(" ) ");
+		break;
+	case TYPE_VALUE_CON:
+		printf("%f", exp->value);
+		break;
+	case TYPE_VALUE_PMC:
+		printf("%s", exp->name);
+		break;
+	default:
+		printf("Unknown op %d\n", exp->type);
+		break;
+	}
+	print_exp(exp->next);
+}
+
+static void
+walk_back_and_insert_paren(struct expression **beg, struct expression *frm)
+{
+	struct expression *at, *ex;
+
+	/* Setup our new open paren */
+	ex = malloc(sizeof(struct expression));
+	if (ex == NULL) {
+		printf("Out of memory in exp allocation\n");
+		exit(-2);
+	}
+	memset(ex, 0, sizeof(struct expression));
+	ex->type = TYPE_PARN_OPEN;
+	/* Now lets place it */
+	at = frm->prev;
+	if (at == *beg) {
+		/* We are inserting at the head of the list */
+	in_beg:
+		ex->next = at;
+		at->prev = ex;
+		*beg = ex;
+		return;
+	} else if ((at->type == TYPE_VALUE_CON) ||
+	    (at->type == TYPE_VALUE_PMC)) {
+		/* Simple case we have a value in the previous position */
+	in_mid:
+		ex->prev = at->prev;
+		ex->prev->next = ex;
+		ex->next = at;
+		at->prev = ex;
+		return;
+	} else if (at->type == TYPE_PARN_CLOSE) {
+		/* Skip through until we reach beg or all ( closes */
+		int par_cnt=1;
+
+		at = at->prev;
+		while(par_cnt) {
+			if (at->type == TYPE_PARN_CLOSE) {
+				par_cnt++;
+			} else if (at->type == TYPE_PARN_OPEN) {
+				par_cnt--;
+				if (par_cnt == 0) {
+					break;
+				}
+			}
+			at = at->prev;
+		}
+		if (at == *beg) {
+			/* At beginning we insert */
+			goto in_beg;
+		} else {
+			goto in_mid;
+		}
+	} else {
+		printf("%s:Unexpected type:%d?\n", 
+		       __FUNCTION__, at->type);
+		exit(-1);
+	}
+}
+
+static void
+walk_fwd_and_insert_paren(struct expression *frm, struct expression **added)
+{
+	struct expression *at, *ex;
+	/* Setup our new close paren */
+	ex = malloc(sizeof(struct expression));
+	if (ex == NULL) {
+		printf("Out of memory in exp allocation\n");
+		exit(-2);
+	}
+	memset(ex, 0, sizeof(struct expression));
+	ex->type = TYPE_PARN_CLOSE;
+	*added = ex;
+	/* Now lets place it */
+	at = frm->next;
+	if ((at->type == TYPE_VALUE_CON) ||
+	    (at->type == TYPE_VALUE_PMC)) {
+		/* Simple case we have a value in the previous position */
+	insertit:
+		ex->next = at->next;
+		ex->prev = at;
+		at->next = ex;
+		return;
+	} else if (at->type == TYPE_PARN_OPEN) {
+		int par_cnt=1;
+		at = at->next;
+		while(par_cnt) {
+			if (at->type == TYPE_PARN_OPEN) {
+				par_cnt++;
+			} else if (at->type == TYPE_PARN_CLOSE) {
+				par_cnt--;
+				if (par_cnt == 0) {
+					break;
+				}
+			}
+			at = at->next;
+		}
+		goto insertit;
+	} else {
+		printf("%s:Unexpected type:%d?\n", 
+		       __FUNCTION__,
+		       at->type);
+		exit(-1);
+	}
+}
+
+
+static void
+add_precendence(struct expression **beg, struct expression *start, struct expression *end)
+{
+	/* 
+	 * Between start and end add () around any * or /. This
+	 * is quite tricky since if there is a () set inside the
+	 * list we need to skip over everything in the ()'s considering
+	 * that just a value.
+	 */
+	struct expression *at, *newone;
+	int open_cnt;
+
+	at = start;
+	open_cnt = 0;
+	while(at != end) {
+		if (at->type == TYPE_PARN_OPEN) {
+			open_cnt++;
+		}
+		if (at->type == TYPE_PARN_CLOSE) {
+			open_cnt--;
+		}
+		if (open_cnt == 0) {
+			if ((at->type == TYPE_OP_MULT) ||
+			    (at->type == TYPE_OP_DIVIDE)) {
+				walk_back_and_insert_paren(beg, at);
+				walk_fwd_and_insert_paren(at, &newone);
+				at = newone->next;
+				continue;
+			}
+		}
+		at = at->next;
+	}
+	
+}
+
+static void
+set_math_precidence(struct expression **beg, struct expression *exp, struct expression **stopped)
+{
+	struct expression *at, *start, *end;
+	int cnt_lower, cnt_upper;
+	/* 
+	 * Walk through and set any math precedence to 
+	 * get proper precedence we insert () around * / over + -
+	 */
+	end = NULL;
+	start = at = exp;
+	cnt_lower = cnt_upper = 0;
+	while(at) { 
+		if (at->type == TYPE_PARN_CLOSE) {
+			/* Done with that paren */
+			if (stopped) {
+				*stopped = at;
+			}
+			if (cnt_lower && cnt_upper) {
+				/* We have a mixed set ... add precedence between start/end */
+				add_precendence(beg, start, end);
+			}
+			return;
+		}
+		if (at->type == TYPE_PARN_OPEN) {
+			set_math_precidence(beg, at->next, &end);
+			at = end;
+			continue;
+		} else if ((at->type == TYPE_OP_PLUS) ||
+			   (at->type == TYPE_OP_MINUS)) {
+			cnt_lower++;
+		} else if ((at->type == TYPE_OP_DIVIDE) ||
+			   (at->type == TYPE_OP_MULT)) {
+			cnt_upper++;
+		}
+		at = at->next;
+	}
+	if (cnt_lower && cnt_upper) {
+		add_precendence(beg, start, NULL);
+	}
+}
+
+extern char **valid_pmcs;
+extern int valid_pmc_cnt;
+
+static void
+pmc_name_set(struct expression *at)
+{
+	int i, idx, fnd;
+
+	if (at->name[0] == '%') {
+		/* Special number after $ gives index */
+		idx = strtol(&at->name[1], NULL, 0);
+		if (idx >= valid_pmc_cnt) {
+			printf("Unknown PMC %s -- largest we have is $%d -- can't run your expression\n",
+			       at->name, valid_pmc_cnt);
+			exit(-1);
+		}
+		strcpy(at->name, valid_pmcs[idx]);
+	} else {
+		for(i=0, fnd=0; i<valid_pmc_cnt; i++) {
+			if (strcmp(valid_pmcs[i], at->name) == 0) {
+				fnd = 1;
+				break;
+			}
+		}
+		if (!fnd) {
+			printf("PMC %s does not exist on this machine -- can't run your expression\n",
+			       at->name);
+			exit(-1);
+		}
+	}
+}
+
+struct expression *
+parse_expression(char *str)
+{
+	struct expression *exp=NULL, *last=NULL, *at;
+	int open_par, close_par;
+	int op_cnt=0;
+	size_t siz, i, x;
+	/* 
+	 * Walk through a string expression and convert
+	 * it to a linked list of actions. We do this by:
+	 * a) Counting the open/close paren's, there must
+	 *    be a matching number.
+	 * b) If we have balanced paren's then create a linked list
+	 *    of the operators, then we validate that expression further.
+	 * c) Validating that we have:
+	 *      val OP val <or>
+	 *      val OP (  <and>
+	 *    inside every paran you have a:
+	 *      val OP val <or>
+	 *      val OP (   <recursively>
+	 * d) A final optional step (not implemented yet) would be
+	 *    to insert the mathematical precedence paran's. For
+	 *    the start we will just do the left to right evaluation and
+	 *    then later we can add this guy to add paran's to make it
+	 *    mathimatically correct... i.e instead of 1 + 2 * 3 we
+	 *    would translate it into 1 + ( 2 * 3).
+	 */
+	open_par = close_par = 0;
+	siz = strlen(str);
+	/* No trailing newline please */
+	if (str[(siz-1)] == '\n') {
+		str[(siz-1)] = 0;
+		siz--;
+	}
+	for(i=0; i<siz; i++) {
+		if (str[i] == '(') {
+			open_par++;
+		} else if (str[i] == ')') {
+			close_par++;
+		}
+	}
+	if (open_par != close_par) {
+		printf("Invalid expression '%s' %d open paren's and %d close?\n",
+		       str, open_par, close_par);
+		exit(-1);
+	}
+	for(i=0; i<siz; i++) {
+		if (str[i] == '(') {
+			at = alloc_and_hook_expr(&exp, &last);
+			at->type = TYPE_PARN_OPEN;
+		} else if (str[i] == ')') {
+			at = alloc_and_hook_expr(&exp, &last);
+			at->type = TYPE_PARN_CLOSE;
+		} else if (str[i] == ' ') {
+			/* Extra blank */
+			continue;
+		} else if (str[i] == '\t') {
+			/* Extra tab */
+			continue;
+		} else if (str[i] == '+') {
+			at = alloc_and_hook_expr(&exp, &last);
+			at->type = TYPE_OP_PLUS;
+		} else if (str[i] == '-') {
+			at = alloc_and_hook_expr(&exp, &last);
+			at->type = TYPE_OP_MINUS;
+		} else if (str[i] == '/') {
+			at = alloc_and_hook_expr(&exp, &last);
+			at->type = TYPE_OP_DIVIDE;
+		} else if (str[i] == '*') {
+			at = alloc_and_hook_expr(&exp, &last);
+			at->type = TYPE_OP_MULT;
+		} else {
+			/* Its a value or PMC constant */
+			at = alloc_and_hook_expr(&exp, &last);
+			if (isdigit(str[i]) || (str[i] == '.')) {
+				at->type = TYPE_VALUE_CON;
+			} else {
+				at->type = TYPE_VALUE_PMC;
+			}
+			x = 0;
+			while ((str[i] != ' ') && 
+			       (str[i] != '\t') && 
+			       (str[i] != 0) && 
+			       (str[i] != ')') &&
+			       (str[i] != '(')) {
+				/* We collect the constant until a space or tab */
+				at->name[x] = str[i];
+				i++;
+				x++;
+				if (x >=(sizeof(at->name)-1)) {
+					printf("Value/Constant too long %d max:%d\n",
+					       (int)x, (int)(sizeof(at->name)-1));
+					exit(-3);
+				}
+			}
+			if (str[i] != 0) {
+				/* Need to back up and see the last char since
+				 * the for will increment the loop.
+				 */
+				i--;
+			}
+			/* Now we have pulled the string, set it up */
+			if (at->type == TYPE_VALUE_CON) {
+				at->state = STATE_FILLED;
+				at->value = strtod(at->name, NULL);
+			} else {
+				pmc_name_set(at);
+			}
+		}
+	}
+	/* Now lets validate its a workable expression */
+	if (validate_expr(exp, 0, 0, 0, &op_cnt)) {
+		printf("Invalid expression\n");
+		exit(-4);
+	}
+	set_math_precidence(&exp, exp, NULL);
+	return (exp);
+}
+
+
+
+static struct expression *
+gather_exp_to_paren_close(struct expression *exp, double *val_fill)
+{
+	/*
+	 * I have been given ( ???
+	 * so I could see either
+	 * (
+	 * or
+	 * Val Op
+	 *
+	 */
+	struct expression *lastproc;
+	double val;
+
+	if (exp->type == TYPE_PARN_OPEN) {
+		lastproc = gather_exp_to_paren_close(exp->next, &val);
+		*val_fill = val;
+	} else {
+		*val_fill = run_expr(exp, 0, &lastproc);
+	}
+	return(lastproc);
+}
+
+
+double
+run_expr(struct expression *exp, int initial_call, struct expression **lastone)
+{
+	/* 
+	 * We expect to find either
+	 * a) A Open Paren
+	 * or
+	 * b) Val-> Op -> Val
+	 * or
+	 * c) Val-> Op -> Open Paren
+	 */
+	double val1, val2, res;
+	struct expression *op, *other_half, *rest;
+	
+	if (exp->type == TYPE_PARN_OPEN) {
+		op = gather_exp_to_paren_close(exp->next, &val1);
+	} else if(exp->type == TYPE_VALUE_CON) {
+		val1 = exp->value;
+		op = exp->next;
+	} else if (exp->type ==  TYPE_VALUE_PMC) {
+		val1 = exp->value;
+		op = exp->next;
+	} else {
+		printf("Illegal value in %s huh?\n", __FUNCTION__);
+		exit(-1);
+	}
+	if (op == NULL) {
+		return (val1);
+	}
+more_to_do:
+	other_half = op->next;
+	if (other_half->type == TYPE_PARN_OPEN) {
+		rest = gather_exp_to_paren_close(other_half->next, &val2);
+	} else if(other_half->type == TYPE_VALUE_CON) {
+		val2 = other_half->value;
+		rest = other_half->next;
+	} else if (other_half->type ==  TYPE_VALUE_PMC) {
+		val2 = other_half->value;
+		rest = other_half->next;
+	} else {
+		printf("Illegal2 value in %s huh?\n", __FUNCTION__);
+		exit(-1);
+	}
+	switch(op->type) {
+	case TYPE_OP_PLUS:
+		res = val1 + val2;
+		break;
+	case TYPE_OP_MINUS:		
+		res = val1 - val2;
+		break;
+	case TYPE_OP_MULT:
+		res = val1 * val2;
+		break;
+	case TYPE_OP_DIVIDE:
+		if (val2 != 0.0)
+			res = val1 / val2;
+		else {
+			printf("Division by zero averted\n");
+			res = 1.0;
+		}	
+		break;
+	default:
+		printf("Op is not an operator -- its %d\n",
+		       op->type);
+		exit(-1);
+		break;
+	}
+	if (rest == NULL) {
+		if (lastone) {
+			*lastone = NULL;
+		}
+		return (res);
+	}
+	if ((rest->type == TYPE_PARN_CLOSE) && (initial_call == 0)) {
+		if (lastone) {
+			*lastone = rest->next;
+		}
+		return(res);
+	}
+	/* There is more, as in
+	 * a + b + c
+	 * where we just did a + b
+	 * so now it becomes val1 is set to res and
+	 * we need to proceed with the rest of it.
+	 */
+	val1 = res;
+	op = rest;
+	if ((op->type != TYPE_OP_PLUS) &&
+	    (op->type != TYPE_OP_MULT) &&
+	    (op->type != TYPE_OP_MINUS) &&
+	    (op->type != TYPE_OP_DIVIDE)) {
+		printf("%s ending on type:%d not an op??\n", __FUNCTION__, op->type);
+		return(res);
+	}
+	if (op)
+		goto more_to_do;
+	return (res);
+}
+
+#ifdef STAND_ALONE_TESTING
+
+static double
+calc_expr(struct expression *exp)
+{
+	struct expression *at;
+	double xx;
+
+	/* First clear PMC's setting */
+	for(at = exp; at != NULL; at = at->next) {
+		if (at->type == TYPE_VALUE_PMC) {
+			at->state = STATE_UNSET;
+		}
+	}
+	/* Now for all pmc's make up values .. here is where I would pull them */
+	for(at = exp; at != NULL; at = at->next) {
+		if (at->type == TYPE_VALUE_PMC) {
+			at->value = (random() * 1.0);
+			at->state = STATE_FILLED;
+			if (at->value == 0.0) {
+				/* So we don't have div by 0 */
+				at->value = 1.0;
+			}
+		}
+	}
+	/* Now lets calculate the expression */
+	print_exp(exp);
+	xx = run_expr(exp, 1, NULL);
+	printf("Answer is %f\n", xx);
+	return(xx);
+}
+
+
+int 
+main(int argc, char **argv) 
+{
+	struct expression *exp;
+	if (argc < 2) {
+		printf("Use %s expression\n", argv[0]);
+		return(-1);
+	}
+	exp = parse_expression(argv[1]);
+	printf("Now the calc\n");
+	calc_expr(exp);
+	return(0);
+}
+
+#endif


Property changes on: trunk/usr.sbin/pmcstudy/eval_expr.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/pmcstudy/eval_expr.h
===================================================================
--- trunk/usr.sbin/pmcstudy/eval_expr.h	                        (rev 0)
+++ trunk/usr.sbin/pmcstudy/eval_expr.h	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,59 @@
+/* $MidnightBSD$ */
+#ifndef __eval_expr_h__
+#define __eval_expr_h__
+/*-
+ * Copyright (c) 2015 Netflix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstudy/eval_expr.h 277177 2015-01-14 12:46:58Z rrs $");
+
+enum exptype {
+	TYPE_OP_PLUS,
+	TYPE_OP_MINUS,
+	TYPE_OP_MULT,
+	TYPE_OP_DIVIDE,
+	TYPE_PARN_OPEN,
+	TYPE_PARN_CLOSE,
+	TYPE_VALUE_CON,
+	TYPE_VALUE_PMC
+};
+
+#define STATE_UNSET  0		/* We have no setting yet in value */
+#define STATE_FILLED 1		/* We have filled in value */
+
+struct expression {
+	struct expression *next;	/* Next in expression. */
+	struct expression *prev;	/* Prev in expression. */
+	double value;			/* If there is a value to set */
+	enum exptype type;			/* What is it */
+	uint8_t state;			/* Current state if value type */
+	char name[252];			/* If a PMC whats the name, con value*/
+};
+
+struct expression *parse_expression(char *str);
+double run_expr(struct expression *exp, int initial_call, struct expression **lastone);
+void print_exp(struct expression *exp);
+#endif


Property changes on: trunk/usr.sbin/pmcstudy/eval_expr.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/pmcstudy/pmcstudy.8
===================================================================
--- trunk/usr.sbin/pmcstudy/pmcstudy.8	                        (rev 0)
+++ trunk/usr.sbin/pmcstudy/pmcstudy.8	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,132 @@
+.\" $MidnightBSD$
+.\" Copyright (c) 2015
+.\"		Netflix Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: stable/10/usr.sbin/pmcstudy/pmcstudy.8 281235 2015-04-07 21:05:52Z rrs $
+.\"
+.Dd Mar 26, 2015
+.Dt PMCSTUDY 8
+.Os
+.Sh NAME
+.Nm pmcstudy
+.Nd Perform various study's on a systems overall PMC's.
+.Sh SYNOPSIS
+.Nm
+.Oo Fl i Ar inputfile | Fl T | Fl v | Fl m Ar max | Fl e exp | Fl Ar E | Fl h | fl H Oc
+.Nm 
+.Fl i Ar inputfile 
+.Nm
+.Fl v 
+.Nm
+.Fl m Ar max
+.Nm
+.Fl e Ar exp-name
+.Nm
+.Fl E Ar your-expr
+.Nm
+.Fl h
+.Nm
+.Fl H
+.Nm
+.Fl T
+.Sh DESCRIPTION
+The
+.Nm
+program is designed to run various tests against your systems
+performance. There are roughly 20-22 canned tests that setup specific
+PMC's and then run various formulas on the output information.
+These formulas can be found in Intel documentation "Using Intel Vtune
+amplifier xe on NNN Generation Intel Core Processors". The NNN is either
+2nd, 3rd or 4th generation i.e. Sandy Bridge, Ivy Bridge and Haswell. 
+Currently the program only works on these three Intel processor types.
+.Sh OPTIONS
+The following options are available:
+.Bl -tag -width indent
+.It Fl i Ar filename
+If this option is supplied, instead of running a
+.Xr pmcstat 8 
+command to collecte the current running information the filename will be read
+in as input instead.
+.It Fl H
+This option will display the complete list of canned formulas that can be run including
+there names which can be input to the
+.Fl e
+option.
+.It Fl e Ar name
+Execute the canned test
+.Ar name
+on the running kernel.
+.It Fl h
+If you add this option to the
+.Fl e
+option the test will not execute but instead give you a small description
+of the test that would run.
+.It Fl T
+This option will execute a test of every PMC to validate that they are working
+on your system. If a PMC does not show up in this test chances
+are the kernel hwpmc driver needs updating with new PMC information.
+.It Fl m Ar num
+This option can restrict the number of one second samples that will
+be collected by your system when running a test (it bounds the
+time the test will run). Without this option the test will run
+for 1024 seconds or until the user types ctrl-c.
+.It Fl v
+The verbose option adds debugging output to the command.
+.It Fl E Ar expression
+This option can be used by those that have there own ideas
+on what formulas that you want to run. The expression given to
+the
+.Fl E
+option is a "formula". The formula can declare directly the PMC's by name
+or you can use an abbreviation %NNN. To find out the abbreviations
+on your system you may run the
+.Fl L
+option.
+An example of a formula of your own might be
+.Fl E
+"FP_ASSIST.ANY / INST_RETIRED.ANY_P" or using the abbreviations on a
+Haswell machine you would type
+.Fl E
+" %176 / %150". You must have spaces between each entry and
+you may use paraenthisis to prioritize the operators. Add (+), Subtract (-),
+Divide (/) and Multiplication (*) are supported. You may also introduce
+constant numbers as well. So for example you can do a standard efficency
+test like
+.FL E
+"UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD_P)".
+
+.It Fl L
+This option will list all known PMC's and there abbreviation (%NNN).
+.Sh SEE ALSO
+.Xr pmc 3 ,
+.Xr pmclog 3 ,
+.Xr hwpmc 4 ,
+.Xr pmcstat 8 ,
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 11.0.
+.Sh AUTHORS
+.An Randall Stewart Aq Mt rrs at FreeBSD.org


Property changes on: trunk/usr.sbin/pmcstudy/pmcstudy.8
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/pmcstudy/pmcstudy.c
===================================================================
--- trunk/usr.sbin/pmcstudy/pmcstudy.c	                        (rev 0)
+++ trunk/usr.sbin/pmcstudy/pmcstudy.c	2018-06-03 23:10:18 UTC (rev 10366)
@@ -0,0 +1,2433 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014, 2015 Netflix Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/errno.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <getopt.h>
+#include "eval_expr.h"
+__FBSDID("$FreeBSD: stable/10/usr.sbin/pmcstudy/pmcstudy.c 285849 2015-07-24 19:09:11Z emaste $");
+
+#define MAX_COUNTER_SLOTS 1024
+#define MAX_NLEN 64
+#define MAX_CPU 64
+static int verbose = 0;
+
+extern char **environ;
+extern struct expression *master_exp;
+struct expression *master_exp=NULL;
+
+#define PMC_INITIAL_ALLOC 512
+extern char **valid_pmcs;
+char **valid_pmcs = NULL;
+extern int valid_pmc_cnt;
+int valid_pmc_cnt=0;
+extern int pmc_allocated_cnt;
+int pmc_allocated_cnt=0;
+
+/*
+ * The following two varients on popen and pclose with
+ * the cavet that they get you the PID so that you
+ * can supply it to pclose so it can send a SIGTERM 
+ *  to the process.
+ */
+static FILE *
+my_popen(const char *command, const char *dir, pid_t *p_pid)
+{
+	FILE *io_out, *io_in;
+	int pdesin[2], pdesout[2];
+	char *argv[4];
+	pid_t pid;
+	char cmd[4];
+	char cmd2[1024];
+	char arg1[4];
+
+	if ((strcmp(dir, "r") != 0) &&
+	    (strcmp(dir, "w") != 0)) {
+		errno = EINVAL;
+		return(NULL);
+	}
+	if (pipe(pdesin) < 0)
+		return (NULL);
+
+	if (pipe(pdesout) < 0) {
+		(void)close(pdesin[0]);
+		(void)close(pdesin[1]);
+		return (NULL);
+	}
+	strcpy(cmd, "sh");
+	strcpy(arg1, "-c");
+	strcpy(cmd2, command);
+	argv[0] = cmd;
+	argv[1] = arg1;
+	argv[2] = cmd2;
+	argv[3] = NULL;
+
+	switch (pid = fork()) {
+	case -1:			/* Error. */
+		(void)close(pdesin[0]);
+		(void)close(pdesin[1]);
+		(void)close(pdesout[0]);
+		(void)close(pdesout[1]);
+		return (NULL);
+		/* NOTREACHED */
+	case 0:				/* Child. */
+		/* Close out un-used sides */
+		(void)close(pdesin[1]);
+		(void)close(pdesout[0]);
+		/* Now prepare the stdin of the process */
+		close(0);
+		(void)dup(pdesin[0]);
+		(void)close(pdesin[0]);
+		/* Now prepare the stdout of the process */
+		close(1);
+		(void)dup(pdesout[1]);
+		/* And lets do stderr just in case */
+		close(2);
+		(void)dup(pdesout[1]);
+		(void)close(pdesout[1]);
+		/* Now run it */
+		execve("/bin/sh", argv, environ);
+		exit(127);
+		/* NOTREACHED */
+	}
+	/* Parent; assume fdopen can't fail. */
+	/* Store the pid */
+	*p_pid = pid;
+	if (strcmp(dir, "r") != 0) {
+		io_out = fdopen(pdesin[1], "w");
+		(void)close(pdesin[0]);
+		(void)close(pdesout[0]);
+		(void)close(pdesout[1]);
+		return(io_out);
+ 	} else {
+		/* Prepare the input stream */
+		io_in = fdopen(pdesout[0], "r");
+		(void)close(pdesout[1]);
+		(void)close(pdesin[0]);
+		(void)close(pdesin[1]);
+		return (io_in);
+	}
+}
+
+/*
+ * pclose --
+ *	Pclose returns -1 if stream is not associated with a `popened' command,
+ *	if already `pclosed', or waitpid returns an error.
+ */
+static void
+my_pclose(FILE *io, pid_t the_pid)
+{
+	int pstat;
+	pid_t pid;
+
+	/*
+	 * Find the appropriate file pointer and remove it from the list.
+	 */
+	(void)fclose(io);
+	/* Die if you are not dead! */
+	kill(the_pid, SIGTERM);
+	do {
+		pid = wait4(the_pid, &pstat, 0, (struct rusage *)0);
+	} while (pid == -1 && errno == EINTR);
+}
+
+struct counters {
+	struct counters *next_cpu;
+	char counter_name[MAX_NLEN];		/* Name of counter */
+	int cpu;				/* CPU we are on */
+	int pos;				/* Index we are filling to. */
+	uint64_t vals[MAX_COUNTER_SLOTS];	/* Last 64 entries */
+	uint64_t sum;				/* Summary of entries */
+};
+
+extern struct counters *glob_cpu[MAX_CPU];
+struct counters *glob_cpu[MAX_CPU];
+
+extern struct counters *cnts;
+struct counters *cnts=NULL;
+
+extern int ncnts;
+int ncnts=0;
+
+extern int (*expression)(struct counters *, int);
+int (*expression)(struct counters *, int);
+
+static const char *threshold=NULL;
+static const char *command;
+
+struct cpu_entry {
+	const char *name;
+	const char *thresh;
+	const char *command;
+	int (*func)(struct counters *, int);
+};
+
+
+struct cpu_type {
+	char cputype[32];
+	int number;
+	struct cpu_entry *ents;
+	void (*explain)(const char *name);
+};
+extern struct cpu_type the_cpu;
+struct cpu_type the_cpu;
+
+static void
+explain_name_sb(const char *name)
+{
+	const char *mythresh;
+	if (strcmp(name, "allocstall1") == 0) {
+		printf("Examine PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "allocstall2") == 0) {
+		printf("Examine PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP_CYCLES/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "br_miss") == 0) {
+		printf("Examine (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "splitload") == 0) {
+		printf("Examine MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "splitstore") == 0) {
+		printf("Examine MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES\n");
+		mythresh = "thresh >= .01";
+	} else if (strcmp(name, "contested") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "blockstorefwd") == 0) {
+		printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "cache2") == 0) {
+		printf("Examine ((MEM_LOAD_RETIRED.L3_HIT * 26) + \n");
+		printf("         (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 43) + \n");
+		printf("         (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60)) / CPU_CLK_UNHALTED.THREAD_P\n");
+		printf("**Note we have it labeled MEM_LOAD_UOPS_RETIRED.LLC_HIT not MEM_LOAD_RETIRED.L3_HIT\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "cache1") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "dtlbmissload") == 0) {
+		printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
+		printf("         / CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "frontendstall") == 0) {
+		printf("Examine IDQ_UOPS_NOT_DELIVERED.CORE / (CPU_CLK_UNHALTED.THREAD_P * 4)\n");
+		mythresh = "thresh >= .15";
+	} else if (strcmp(name, "clears") == 0) {
+		printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
+		printf("          MACHINE_CLEARS.SMC + \n");
+		printf("          MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .02";
+	} else if (strcmp(name, "microassist") == 0) {
+		printf("Examine IDQ.MS_CYCLES / (CPU_CLK_UNHALTED.THREAD_P * 4)\n");
+		printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "aliasing_4k") == 0) {
+		printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "fpassist") == 0) {
+		printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "otherassistavx") == 0) {
+		printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "otherassistsse") == 0) {
+		printf("Examine (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "eff1") == 0) {
+		printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh < .9";
+	} else if (strcmp(name, "eff2") == 0) {
+		printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
+		mythresh = "thresh > 1.0";
+	} else if (strcmp(name, "dtlbmissstore") == 0) {
+		printf("Examine (((DTLB_STORE_MISSES.STLB_HIT * 7) + DTLB_STORE_MISSES.WALK_DURATION)\n");
+		printf("         / CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh >= .05";
+	} else {
+		printf("Unknown name:%s\n", name);
+		mythresh = "unknown entry";
+        }
+	printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
+}
+
+static void
+explain_name_ib(const char *name)
+{
+	const char *mythresh;
+	if (strcmp(name, "br_miss") == 0) {
+		printf("Examine ((BR_MISP_RETIRED.ALL_BRANCHES /(BR_MISP_RETIRED.ALL_BRANCHES +\n");
+		printf("         MACHINE_CLEAR.COUNT) * ((UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES)\n");
+		printf("/ (4 * CPU_CLK_UNHALTED.THREAD))))\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "eff1") == 0) {
+		printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh < .9";
+	} else if (strcmp(name, "eff2") == 0) {
+		printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
+		mythresh = "thresh > 1.0";
+	} else if (strcmp(name, "cache1") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "cache2") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_RETIRED.LLC_HIT / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "itlbmiss") == 0) {
+		printf("Examine ITLB_MISSES.WALK_DURATION / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05"; 
+	} else if (strcmp(name, "icachemiss") == 0) {
+		printf("Examine (ICACHE.IFETCH_STALL - ITLB_MISSES.WALK_DURATION)/ CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "lcpstall") == 0) {
+		printf("Examine ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "datashare") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 43)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "blockstorefwd") == 0) {
+		printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "splitload") == 0) {
+		printf("Examine  ((L1D_PEND_MISS.PENDING / MEM_LOAD_UOPS_RETIRED.L1_MISS) *\n");
+		printf("         LD_BLOCKS.NO_SR)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "splitstore") == 0) {
+		printf("Examine MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES\n");
+		mythresh = "thresh >= .01";
+	} else if (strcmp(name, "aliasing_4k") == 0) {
+		printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "dtlbmissload") == 0) {
+		printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
+		printf("         / CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "dtlbmissstore") == 0) {
+		printf("Examine (((DTLB_STORE_MISSES.STLB_HIT * 7) + DTLB_STORE_MISSES.WALK_DURATION)\n");
+		printf("         / CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "contested") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "clears") == 0) {
+		printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
+		printf("          MACHINE_CLEARS.SMC + \n");
+		printf("          MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .02";
+	} else if (strcmp(name, "microassist") == 0) {
+		printf("Examine IDQ.MS_CYCLES / (4 * CPU_CLK_UNHALTED.THREAD_P)\n");
+		printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "fpassist") == 0) {
+		printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "otherassistavx") == 0) {
+		printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "otherassistsse") == 0) {
+		printf("Examine (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "look for a excessive value";
+	} else {
+		printf("Unknown name:%s\n", name);
+		mythresh = "unknown entry";
+        }
+	printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
+}
+
+
+static void
+explain_name_has(const char *name)
+{
+	const char *mythresh;
+	if (strcmp(name, "eff1") == 0) {
+		printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh < .75";
+	} else if (strcmp(name, "eff2") == 0) {
+		printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
+		mythresh = "thresh > 1.0";
+	} else if (strcmp(name, "itlbmiss") == 0) {
+		printf("Examine ITLB_MISSES.WALK_DURATION / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05"; 
+	} else if (strcmp(name, "icachemiss") == 0) {
+		printf("Examine (36 * ICACHE.MISSES)/ CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "lcpstall") == 0) {
+		printf("Examine ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "cache1") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "cache2") == 0) {
+		printf("Examine ((MEM_LOAD_UOPS_RETIRED.LLC_HIT * 36) + \n");
+		printf("         (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 72) + \n");
+		printf("         (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84))\n");
+		printf("          / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "contested") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "datashare") == 0) {
+		printf("Examine (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 72)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh > .05";
+	} else if (strcmp(name, "blockstorefwd") == 0) {
+		printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "splitload") == 0) {
+		printf("Examine  (MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "splitstore") == 0) {
+		printf("Examine MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES\n");
+		mythresh = "thresh >= .01";
+	} else if (strcmp(name, "aliasing_4k") == 0) {
+		printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "dtlbmissload") == 0) {
+		printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
+		printf("         / CPU_CLK_UNHALTED.THREAD_P)\n");
+		mythresh = "thresh >= .1";
+	} else if (strcmp(name, "br_miss") == 0) {
+		printf("Examine (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD\n");
+		mythresh = "thresh >= .2";
+	} else if (strcmp(name, "clears") == 0) {
+		printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
+		printf("          MACHINE_CLEARS.SMC + \n");
+		printf("          MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "thresh >= .02";
+	} else if (strcmp(name, "microassist") == 0) {
+		printf("Examine IDQ.MS_CYCLES / (4 * CPU_CLK_UNHALTED.THREAD_P)\n");
+		printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
+		mythresh = "thresh >= .05";
+	} else if (strcmp(name, "fpassist") == 0) {
+		printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "otherassistavx") == 0) {
+		printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "look for a excessive value";
+	} else if (strcmp(name, "otherassistsse") == 0) {
+		printf("Examine (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+		mythresh = "look for a excessive value";
+	} else {
+		printf("Unknown name:%s\n", name);
+		mythresh = "unknown entry";
+        }
+	printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
+}
+
+
+static struct counters *
+find_counter(struct counters *base, const char *name)
+{
+	struct counters *at;
+	int len;
+
+	at = base;
+	len = strlen(name);
+	while(at) {
+		if (strncmp(at->counter_name, name, len) == 0) {
+			return(at);
+		}
+		at = at->next_cpu;
+	}
+	printf("Can't find counter %s\n", name);
+	printf("We have:\n");
+	at = base;
+	while(at) {
+		printf("- %s\n", at->counter_name);
+		at = at->next_cpu;
+	}
+	exit(-1);
+}
+
+static int
+allocstall1(struct counters *cpu, int pos)
+{
+/*  1  - PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW/CPU_CLK_UNHALTED.THREAD_P (thresh > .05)*/
+	int ret;
+	struct counters *partial;
+	struct counters *unhalt;
+	double un, par, res;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	partial = find_counter(cpu, "PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW");
+	if (pos != -1) {
+		par = partial->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		par = partial->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = par/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+allocstall2(struct counters *cpu, int pos)
+{
+/*  2  - PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP_CYCLES/CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
+	int ret;
+	struct counters *partial;
+	struct counters *unhalt;
+	double un, par, res;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	partial = find_counter(cpu, "PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP");
+	if (pos != -1) {
+		par = partial->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		par = partial->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = par/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+br_mispredict(struct counters *cpu, int pos)
+{
+	struct counters *brctr;
+	struct counters *unhalt;
+	int ret;
+/*  3  - (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
+	double br, un, con, res;
+	con = 20.0;
+	
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+        brctr = find_counter(cpu, "BR_MISP_RETIRED.ALL_BRANCHES");
+	if (pos != -1) {
+		br = brctr->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		br = brctr->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (con * br)/un;
+ 	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+br_mispredictib(struct counters *cpu, int pos)
+{
+	struct counters *brctr;
+	struct counters *unhalt;
+	struct counters *clear, *clear2, *clear3;
+	struct counters *uops;
+	struct counters *recv;	
+	struct counters *iss;
+/*	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",*/
+	int ret;
+        /*  
+	 * (BR_MISP_RETIRED.ALL_BRANCHES / 
+	 *         (BR_MISP_RETIRED.ALL_BRANCHES +
+	 *          MACHINE_CLEAR.COUNT) * 
+	 *	   ((UOPS_ISSUED.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES) / (4 * CPU_CLK_UNHALTED.THREAD)))
+	 *
+	 */
+	double br, cl, cl2, cl3, uo, re, un, con, res, is;
+	con = 4.0;
+	
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+        brctr = find_counter(cpu, "BR_MISP_RETIRED.ALL_BRANCHES");
+	clear = find_counter(cpu, "MACHINE_CLEARS.MEMORY_ORDERING");
+	clear2 = find_counter(cpu, "MACHINE_CLEARS.SMC");
+	clear3 = find_counter(cpu, "MACHINE_CLEARS.MASKMOV");
+	uops = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
+	iss = find_counter(cpu, "UOPS_ISSUED.ANY");
+	recv = find_counter(cpu, "INT_MISC.RECOVERY_CYCLES");
+	if (pos != -1) {
+		br = brctr->vals[pos] * 1.0;
+		cl = clear->vals[pos] * 1.0;
+		cl2 = clear2->vals[pos] * 1.0;
+		cl3 = clear3->vals[pos] * 1.0;
+		uo = uops->vals[pos] * 1.0;
+		re = recv->vals[pos] * 1.0;
+		is = iss->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		br = brctr->sum * 1.0;
+		cl = clear->sum * 1.0;
+		cl2 = clear2->sum * 1.0;
+		cl3 = clear3->sum * 1.0;
+		uo = uops->sum * 1.0;
+		re = recv->sum * 1.0;
+		is = iss->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (br/(br + cl + cl2 + cl3) * ((is - uo + con * re) / (con * un)));
+ 	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+splitloadib(struct counters *cpu, int pos)
+{
+	int ret;
+	struct counters *mem;
+	struct counters *l1d, *ldblock;
+	struct counters *unhalt;
+	double un, memd, res, l1, ldb;
+        /*  
+	 * ((L1D_PEND_MISS.PENDING / MEM_LOAD_UOPS_RETIRED.L1_MISS) * LD_BLOCKS.NO_SR) / CPU_CLK_UNHALTED.THREAD_P
+	 * "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s L1D_PEND_MISS.PENDING -s MEM_LOAD_UOPS_RETIRED.L1_MISS -s LD_BLOCKS.NO_SR -w 1",
+	 */
+
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.L1_MISS");
+	l1d = find_counter(cpu, "L1D_PEND_MISS.PENDING");
+	ldblock = find_counter(cpu, "LD_BLOCKS.NO_SR");
+	if (pos != -1) {
+		memd = mem->vals[pos] * 1.0;
+		l1 = l1d->vals[pos] * 1.0;
+		ldb = ldblock->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		memd = mem->sum * 1.0;
+		l1 = l1d->sum * 1.0;
+		ldb = ldblock->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = ((l1 / memd) * ldb)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+splitload(struct counters *cpu, int pos)
+{
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, un, memd, res;
+/*  4  - (MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .1)*/
+
+	con = 5.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_UOP_RETIRED.SPLIT_LOADS");
+	if (pos != -1) {
+		memd = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		memd = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (memd * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+splitstore(struct counters *cpu, int pos)
+{
+        /*  5  - MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES (thresh > 0.01) */
+	int ret;
+	struct counters *mem_split;
+	struct counters *mem_stores;
+	double memsplit, memstore, res;
+	mem_split = find_counter(cpu, "MEM_UOP_RETIRED.SPLIT_STORES");
+	mem_stores = find_counter(cpu, "MEM_UOP_RETIRED.ALL_STORES");
+	if (pos != -1) {
+		memsplit = mem_split->vals[pos] * 1.0;
+		memstore = mem_stores->vals[pos] * 1.0;
+	} else {
+		memsplit = mem_split->sum * 1.0;
+		memstore = mem_stores->sum * 1.0;
+	}
+	res = memsplit/memstore;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+
+static int
+contested(struct counters *cpu, int pos)
+{
+        /*  6  - (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, un, memd, res;
+
+	con = 60.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
+	if (pos != -1) {
+		memd = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		memd = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (memd * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+contested_has(struct counters *cpu, int pos)
+{
+        /*  6  - (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) / CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, un, memd, res;
+
+	con = 84.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
+	if (pos != -1) {
+		memd = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		memd = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (memd * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+
+static int
+blockstoreforward(struct counters *cpu, int pos)
+{
+        /*  7  - (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .05)*/
+	int ret;
+	struct counters *ldb;
+	struct counters *unhalt;
+	double con, un, ld, res;
+
+	con = 13.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	ldb = find_counter(cpu, "LD_BLOCKS_STORE_FORWARD");
+	if (pos != -1) {
+		ld = ldb->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		ld = ldb->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (ld * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+cache2(struct counters *cpu, int pos)
+{
+	/* ** Suspect ***
+	 *  8  - ((MEM_LOAD_RETIRED.L3_HIT * 26) + (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 43) +
+	 *        (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60)) / CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
+	 */
+	int ret;
+	struct counters *mem1, *mem2, *mem3;
+	struct counters *unhalt;
+	double con1, con2, con3, un, me_1, me_2, me_3, res;
+
+	con1 = 26.0;
+	con2 = 43.0;
+	con3 = 60.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+/* Call for MEM_LOAD_RETIRED.L3_HIT possibly MEM_LOAD_UOPS_RETIRED.LLC_HIT ?*/
+	mem1 = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.LLC_HIT");
+	mem2 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
+	mem3 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
+	if (pos != -1) {
+		me_1 = mem1->vals[pos] * 1.0;
+		me_2 = mem2->vals[pos] * 1.0;
+		me_3 = mem3->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me_1 = mem1->sum * 1.0;
+		me_2 = mem2->sum * 1.0;
+		me_3 = mem3->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = ((me_1 * con1) + (me_2 * con2) + (me_3 * con3))/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+datasharing(struct counters *cpu, int pos)
+{
+	/* 
+	 * (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 43)/ CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
+	 */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, res, me, un;
+
+	con = 43.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
+	if (pos != -1) {
+		me = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (me * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+
+}
+
+
+static int
+datasharing_has(struct counters *cpu, int pos)
+{
+	/* 
+	 * (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 43)/ CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
+	 */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, res, me, un;
+
+	con = 72.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
+	if (pos != -1) {
+		me = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (me * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+
+}
+
+
+static int
+cache2ib(struct counters *cpu, int pos)
+{
+        /*
+	 *  (29 * MEM_LOAD_UOPS_RETIRED.LLC_HIT / CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
+	 */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, un, me, res;
+
+	con = 29.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.LLC_HIT");
+	if (pos != -1) {
+		me = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (con * me)/un; 
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+cache2has(struct counters *cpu, int pos)
+{
+	/*
+	 * Examine ((MEM_LOAD_UOPS_RETIRED.LLC_HIT * 36) + \
+	 *          (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT * 72) +
+	 *          (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84))
+	 *           / CPU_CLK_UNHALTED.THREAD_P
+	 */
+	int ret;
+	struct counters *mem1, *mem2, *mem3;
+	struct counters *unhalt;
+	double con1, con2, con3, un, me1, me2, me3, res;
+
+	con1 = 36.0;
+	con2 = 72.0;
+	con3 = 84.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem1 = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.LLC_HIT");
+	mem2 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT");
+	mem3 = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
+	if (pos != -1) {
+		me1 = mem1->vals[pos] * 1.0;
+		me2 = mem2->vals[pos] * 1.0;
+		me3 = mem3->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me1 = mem1->sum * 1.0;
+		me2 = mem2->sum * 1.0;
+		me3 = mem3->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = ((me1 * con1) + (me2 * con2) + (me3 * con3))/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+cache1(struct counters *cpu, int pos)
+{
+	/*  9  - (MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS * 180) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, un, me, res;
+
+	con = 180.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS");
+	if (pos != -1) {
+		me = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (me * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+cache1ib(struct counters *cpu, int pos)
+{
+	/*  9  - (MEM_LOAD_UOPS_L3_MISS_RETIRED.LCOAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
+	int ret;
+	struct counters *mem;
+	struct counters *unhalt;
+	double con, un, me, res;
+
+	con = 180.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM");
+	if (pos != -1) {
+		me = mem->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		me = mem->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (me * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+
+static int
+dtlb_missload(struct counters *cpu, int pos)
+{
+	/* 10  - ((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION) / CPU_CLK_UNHALTED.THREAD_P (t >=.1) */
+	int ret;
+	struct counters *dtlb_m, *dtlb_d;
+	struct counters *unhalt;
+	double con, un, d1, d2, res;
+
+	con = 7.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	dtlb_m = find_counter(cpu, "DTLB_LOAD_MISSES.STLB_HIT");
+	dtlb_d = find_counter(cpu, "DTLB_LOAD_MISSES.WALK_DURATION");
+	if (pos != -1) {
+		d1 = dtlb_m->vals[pos] * 1.0;
+		d2 = dtlb_d->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		d1 = dtlb_m->sum * 1.0;
+		d2 = dtlb_d->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = ((d1 * con) + d2)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+dtlb_missstore(struct counters *cpu, int pos)
+{
+        /* 
+	 * ((DTLB_STORE_MISSES.STLB_HIT * 7) + DTLB_STORE_MISSES.WALK_DURATION) / 
+	 * CPU_CLK_UNHALTED.THREAD_P (t >= .1) 
+	 */
+        int ret;
+        struct counters *dtsb_m, *dtsb_d;
+        struct counters *unhalt;
+        double con, un, d1, d2, res;
+
+        con = 7.0;
+        unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+        dtsb_m = find_counter(cpu, "DTLB_STORE_MISSES.STLB_HIT");
+        dtsb_d = find_counter(cpu, "DTLB_STORE_MISSES.WALK_DURATION");
+        if (pos != -1) {
+                d1 = dtsb_m->vals[pos] * 1.0;
+                d2 = dtsb_d->vals[pos] * 1.0;
+                un = unhalt->vals[pos] * 1.0;
+        } else {
+                d1 = dtsb_m->sum * 1.0;
+                d2 = dtsb_d->sum * 1.0;
+                un = unhalt->sum * 1.0;
+        }
+        res = ((d1 * con) + d2)/un;
+        ret = printf("%1.3f", res);
+        return(ret);
+}
+
+static int
+itlb_miss(struct counters *cpu, int pos)
+{
+	/* ITLB_MISSES.WALK_DURATION / CPU_CLK_UNTHREAD_P  IB */
+	int ret;
+	struct counters *itlb;
+	struct counters *unhalt;
+	double un, d1, res;
+
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	itlb = find_counter(cpu, "ITLB_MISSES.WALK_DURATION");
+	if (pos != -1) {
+		d1 = itlb->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		d1 = itlb->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = d1/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+icache_miss(struct counters *cpu, int pos)
+{
+	/* (ICACHE.IFETCH_STALL - ITLB_MISSES.WALK_DURATION) / CPU_CLK_UNHALTED.THREAD_P IB */
+
+	int ret;
+	struct counters *itlb, *icache;
+	struct counters *unhalt;
+	double un, d1, ic, res;
+
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	itlb = find_counter(cpu, "ITLB_MISSES.WALK_DURATION");
+	icache = find_counter(cpu, "ICACHE.IFETCH_STALL");
+	if (pos != -1) {
+		d1 = itlb->vals[pos] * 1.0;
+		ic = icache->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		d1 = itlb->sum * 1.0;
+		ic = icache->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (ic-d1)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+
+}
+
+static int
+icache_miss_has(struct counters *cpu, int pos)
+{
+	/* (36 * ICACHE.MISSES) / CPU_CLK_UNHALTED.THREAD_P */
+
+	int ret;
+	struct counters *icache;
+	struct counters *unhalt;
+	double un, con, ic, res;
+
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	icache = find_counter(cpu, "ICACHE.MISSES");
+	con = 36.0;
+	if (pos != -1) {
+		ic = icache->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		ic = icache->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (con * ic)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+
+}
+
+static int
+lcp_stall(struct counters *cpu, int pos)
+{
+         /* ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P IB */
+	int ret;
+	struct counters *ild;
+	struct counters *unhalt;
+	double un, d1, res;
+
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	ild = find_counter(cpu, "ILD_STALL.LCP");
+	if (pos != -1) {
+		d1 = ild->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		d1 = ild->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = d1/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+
+}
+
+
+static int
+frontendstall(struct counters *cpu, int pos)
+{
+      /* 12  -  IDQ_UOPS_NOT_DELIVERED.CORE / (CPU_CLK_UNHALTED.THREAD_P * 4) (thresh >= .15) */
+	int ret;
+	struct counters *idq;
+	struct counters *unhalt;
+	double con, un, id, res;
+
+	con = 4.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	idq = find_counter(cpu, "IDQ_UOPS_NOT_DELIVERED.CORE");
+	if (pos != -1) {
+		id = idq->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		id = idq->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = id/(un * con);
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+clears(struct counters *cpu, int pos)
+{
+	/* 13  - ((MACHINE_CLEARS.MEMORY_ORDERING + MACHINE_CLEARS.SMC + MACHINE_CLEARS.MASKMOV ) * 100 )  
+	 *         / CPU_CLK_UNHALTED.THREAD_P (thresh  >= .02)*/
+	
+	int ret;
+	struct counters *clr1, *clr2, *clr3;
+	struct counters *unhalt;
+	double con, un, cl1, cl2, cl3, res;
+
+	con = 100.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	clr1 = find_counter(cpu, "MACHINE_CLEARS.MEMORY_ORDERING");
+	clr2 = find_counter(cpu, "MACHINE_CLEARS.SMC");
+	clr3 = find_counter(cpu, "MACHINE_CLEARS.MASKMOV");
+	
+	if (pos != -1) {
+		cl1 = clr1->vals[pos] * 1.0;
+		cl2 = clr2->vals[pos] * 1.0;
+		cl3 = clr3->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		cl1 = clr1->sum * 1.0;
+		cl2 = clr2->sum * 1.0;
+		cl3 = clr3->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = ((cl1 + cl2 + cl3) * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+microassist(struct counters *cpu, int pos)
+{
+	/* 14  - IDQ.MS_CYCLES / CPU_CLK_UNHALTED.THREAD_P (thresh > .05) */
+	int ret;
+	struct counters *idq;
+	struct counters *unhalt;
+	double un, id, res, con;
+
+	con = 4.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	idq = find_counter(cpu, "IDQ.MS_UOPS");
+	if (pos != -1) {
+		id = idq->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		id = idq->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = id/(un * con);
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+
+static int
+aliasing(struct counters *cpu, int pos)
+{
+	/* 15  - (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh > .1) */
+	int ret;	
+	struct counters *ld;
+	struct counters *unhalt;
+	double un, lds, con, res;
+
+	con = 5.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	ld = find_counter(cpu, "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS");
+	if (pos != -1) {
+		lds = ld->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		lds = ld->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (lds * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+fpassists(struct counters *cpu, int pos)
+{
+	/* 16  - FP_ASSIST.ANY/INST_RETIRED.ANY_P */
+	int ret;	
+	struct counters *fp;
+	struct counters *inst;
+	double un, fpd, res;
+
+	inst = find_counter(cpu, "INST_RETIRED.ANY_P");
+	fp = find_counter(cpu, "FP_ASSIST.ANY");
+	if (pos != -1) {
+		fpd = fp->vals[pos] * 1.0;
+		un = inst->vals[pos] * 1.0;
+	} else {
+		fpd = fp->sum * 1.0;
+		un = inst->sum * 1.0;
+	}
+	res = fpd/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+otherassistavx(struct counters *cpu, int pos)
+{
+	/* 17  - (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P thresh  .1*/
+	int ret;	
+	struct counters *oth;
+	struct counters *unhalt;
+	double un, ot, con, res;
+
+	con = 75.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	oth = find_counter(cpu, "OTHER_ASSISTS.AVX_TO_SSE");
+	if (pos != -1) {
+		ot = oth->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		ot = oth->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (ot * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+otherassistsse(struct counters *cpu, int pos)
+{
+
+	int ret;	
+	struct counters *oth;
+	struct counters *unhalt;
+	double un, ot, con, res;
+
+	/* 18     (OTHER_ASSISTS.SSE_TO_AVX * 75)/CPU_CLK_UNHALTED.THREAD_P  thresh .1*/
+	con = 75.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	oth = find_counter(cpu, "OTHER_ASSISTS.SSE_TO_AVX");
+	if (pos != -1) {
+		ot = oth->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		ot = oth->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = (ot * con)/un;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+efficiency1(struct counters *cpu, int pos)
+{
+
+	int ret;	
+	struct counters *uops;
+	struct counters *unhalt;
+	double un, ot, con, res;
+
+        /* 19 (UOPS_RETIRED.RETIRE_SLOTS/(4*CPU_CLK_UNHALTED.THREAD_P) look if thresh < .9*/
+	con = 4.0;
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	uops = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
+	if (pos != -1) {
+		ot = uops->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		ot = uops->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = ot/(con * un);
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+static int
+efficiency2(struct counters *cpu, int pos)
+{
+
+	int ret;	
+	struct counters *uops;
+	struct counters *unhalt;
+	double un, ot, res;
+
+        /* 20  - CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P good if > 1. (comp factor)*/
+	unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+	uops = find_counter(cpu, "INST_RETIRED.ANY_P");
+	if (pos != -1) {
+		ot = uops->vals[pos] * 1.0;
+		un = unhalt->vals[pos] * 1.0;
+	} else {
+		ot = uops->sum * 1.0;
+		un = unhalt->sum * 1.0;
+	}
+	res = un/ot;
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+#define SANDY_BRIDGE_COUNT 20	
+static struct cpu_entry sandy_bridge[SANDY_BRIDGE_COUNT] = {
+/*01*/	{ "allocstall1", "thresh > .05", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW -w 1",
+	  allocstall1 },
+/*02*/	{ "allocstall2", "thresh > .05", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP_CYCLES -w 1",
+	  allocstall2 },
+/*03*/	{ "br_miss", "thresh >= .2", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -w 1",
+	  br_mispredict },
+/*04*/	{ "splitload", "thresh >= .1", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOP_RETIRED.SPLIT_LOADS -w 1",
+	  splitload },
+/*05*/	{ "splitstore", "thresh >= .01", 
+	  "pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
+	  splitstore },
+/*06*/	{ "contested", "thresh >= .05", 
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM  -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  contested },
+/*07*/	{ "blockstorefwd", "thresh >= .05", 
+	  "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  blockstoreforward },
+/*08*/	{ "cache2", "thresh >= .2", 
+	  "pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  cache2 },
+/*09*/	{ "cache1", "thresh >= .2", 
+	  "pmcstat -s MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  cache1 },
+/*10*/	{ "dtlbmissload", "thresh >= .1", 
+	  "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  dtlb_missload },
+/*11*/	{ "dtlbmissstore", "thresh >= .05", 
+	  "pmcstat -s DTLB_STORE_MISSES.STLB_HIT -s DTLB_STORE_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  dtlb_missstore },
+/*12*/	{ "frontendstall", "thresh >= .15", 
+	  "pmcstat -s IDQ_UOPS_NOT_DELIVERED.CORE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  frontendstall },
+/*13*/	{ "clears", "thresh >= .02", 
+	  "pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  clears },
+/*14*/	{ "microassist", "thresh >= .05", 
+	  "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  microassist },
+/*15*/	{ "aliasing_4k", "thresh >= .1", 
+	  "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  aliasing },
+/*16*/	{ "fpassist", "look for a excessive value", 
+	  "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
+	  fpassists },
+/*17*/	{ "otherassistavx", "look for a excessive value", 
+	  "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  otherassistavx },
+/*18*/	{ "otherassistsse", "look for a excessive value", 
+	  "pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  otherassistsse },
+/*19*/	{ "eff1", "thresh < .9", 
+	  "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  efficiency1 },
+/*20*/	{ "eff2", "thresh > 1.0", 
+	  "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  efficiency2 },
+};
+
+
+#define IVY_BRIDGE_COUNT 21
+static struct cpu_entry ivy_bridge[IVY_BRIDGE_COUNT] = {
+/*1*/	{ "eff1", "thresh < .75", 
+	  "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  efficiency1 },
+/*2*/	{ "eff2", "thresh > 1.0", 
+	  "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  efficiency2 },
+/*3*/	{ "itlbmiss", "thresh > .05", 
+	  "pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  itlb_miss },
+/*4*/	{ "icachemiss", "thresh > .05", 
+	  "pmcstat -s ICACHE.IFETCH_STALL -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  icache_miss },
+/*5*/	{ "lcpstall", "thresh > .05", 
+	  "pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  lcp_stall },
+/*6*/	{ "cache1", "thresh >= .2", 
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  cache1ib },
+/*7*/	{ "cache2", "thresh >= .2", 
+	  "pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  cache2ib },
+/*8*/	{ "contested", "thresh >= .05", 
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM  -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  contested },
+/*9*/	{ "datashare", "thresh >= .05",
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  datasharing },
+/*10*/	{ "blockstorefwd", "thresh >= .05", 
+	  "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  blockstoreforward },
+/*11*/	{ "splitload", "thresh >= .1", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s L1D_PEND_MISS.PENDING -s MEM_LOAD_UOPS_RETIRED.L1_MISS -s LD_BLOCKS.NO_SR -w 1",
+	  splitloadib },
+/*12*/	{ "splitstore", "thresh >= .01", 
+	  "pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
+	  splitstore },
+/*13*/	{ "aliasing_4k", "thresh >= .1", 
+	  "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  aliasing },
+/*14*/	{ "dtlbmissload", "thresh >= .1", 
+	  "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  dtlb_missload },
+/*15*/	{ "dtlbmissstore", "thresh >= .05", 
+	  "pmcstat -s DTLB_STORE_MISSES.STLB_HIT -s DTLB_STORE_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  dtlb_missstore },
+/*16*/	{ "br_miss", "thresh >= .2", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",
+	  br_mispredictib },
+/*17*/	{ "clears", "thresh >= .02", 
+	  "pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  clears },
+/*18*/	{ "microassist", "thresh >= .05", 
+	  "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  microassist },
+/*19*/	{ "fpassist", "look for a excessive value", 
+	  "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
+	  fpassists },
+/*20*/	{ "otherassistavx", "look for a excessive value", 
+	  "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  otherassistavx },
+/*21*/	{ "otherassistsse", "look for a excessive value", 
+	  "pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  otherassistsse },
+};
+
+#define HASWELL_COUNT 20
+static struct cpu_entry haswell[HASWELL_COUNT] = {
+/*1*/	{ "eff1", "thresh < .75", 
+	  "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  efficiency1 },
+/*2*/	{ "eff2", "thresh > 1.0", 
+	  "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  efficiency2 },
+/*3*/	{ "itlbmiss", "thresh > .05", 
+	  "pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  itlb_miss },
+/*4*/	{ "icachemiss", "thresh > .05", 
+	  "pmcstat -s ICACHE.MISSES --s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  icache_miss_has },
+/*5*/	{ "lcpstall", "thresh > .05", 
+	  "pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  lcp_stall },
+/*6*/	{ "cache1", "thresh >= .2", 
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  cache1ib },
+/*7*/	{ "cache2", "thresh >= .2", 
+	  "pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT  -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  cache2has },
+/*8*/	{ "contested", "thresh >= .05", 
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM  -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  contested_has },
+/*9*/	{ "datashare", "thresh >= .05",
+	  "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  datasharing_has },
+/*10*/	{ "blockstorefwd", "thresh >= .05", 
+	  "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  blockstoreforward },
+/*11*/	{ "splitload", "thresh >= .1", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOP_RETIRED.SPLIT_LOADS -w 1",
+	  splitload },
+/*12*/	{ "splitstore", "thresh >= .01", 
+	  "pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
+	  splitstore },
+/*13*/	{ "aliasing_4k", "thresh >= .1", 
+	  "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  aliasing },
+/*14*/	{ "dtlbmissload", "thresh >= .1", 
+	  "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  dtlb_missload },
+/*15*/	{ "br_miss", "thresh >= .2", 
+	  "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -w 1",
+	  br_mispredict },
+/*16*/	{ "clears", "thresh >= .02", 
+	  "pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  clears },
+/*17*/	{ "microassist", "thresh >= .05", 
+	  "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  microassist },
+/*18*/	{ "fpassist", "look for a excessive value", 
+	  "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
+	  fpassists },
+/*19*/	{ "otherassistavx", "look for a excessive value", 
+	  "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  otherassistavx },
+/*20*/	{ "otherassistsse", "look for a excessive value", 
+	  "pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+	  otherassistsse },
+};
+
+
+static void
+set_sandybridge(void)
+{
+	strcpy(the_cpu.cputype, "SandyBridge PMC");
+	the_cpu.number = SANDY_BRIDGE_COUNT;
+	the_cpu.ents = sandy_bridge;
+	the_cpu.explain = explain_name_sb;
+}
+
+static void
+set_ivybridge(void)
+{
+	strcpy(the_cpu.cputype, "IvyBridge PMC");
+	the_cpu.number = IVY_BRIDGE_COUNT;
+	the_cpu.ents = ivy_bridge;
+	the_cpu.explain = explain_name_ib;
+}
+
+
+static void
+set_haswell(void)
+{
+	strcpy(the_cpu.cputype, "HASWELL PMC");
+	the_cpu.number = HASWELL_COUNT;
+	the_cpu.ents = haswell;
+	the_cpu.explain = explain_name_has;
+}
+
+static void
+set_expression(char *name)
+{
+	int found = 0, i;
+	for(i=0 ; i< the_cpu.number; i++) {
+		if (strcmp(name, the_cpu.ents[i].name) == 0) {
+			found = 1;
+			expression = the_cpu.ents[i].func;
+			command = the_cpu.ents[i].command;
+			threshold = the_cpu.ents[i].thresh;
+			break;
+		}
+	}
+	if (!found) {
+		printf("For CPU type %s we have no expression:%s\n",
+		       the_cpu.cputype, name);
+		exit(-1);
+	}
+}
+
+
+
+
+
+static int
+validate_expression(char *name) 
+{
+	int i, found;
+
+	found = 0;
+	for(i=0 ; i< the_cpu.number; i++) {
+		if (strcmp(name, the_cpu.ents[i].name) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		return(-1);
+	}
+	return (0);
+}
+
+static void
+do_expression(struct counters *cpu, int pos)
+{
+	if (expression == NULL) 
+		return;
+	(*expression)(cpu, pos);
+}
+
+static void
+process_header(int idx, char *p)
+{
+	struct counters *up;
+	int i, len, nlen;
+	/* 
+	 * Given header element idx, at p in
+	 * form 's/NN/nameof'
+	 * process the entry to pull out the name and
+	 * the CPU number.
+	 */
+	if (strncmp(p, "s/", 2)) {
+		printf("Check -- invalid header no s/ in %s\n",
+		       p);
+		return;
+	}
+	up = &cnts[idx];
+	up->cpu = strtol(&p[2], NULL, 10);
+	len = strlen(p);
+	for (i=2; i<len; i++) {
+		if (p[i] == '/') {
+			nlen = strlen(&p[(i+1)]);
+			if (nlen < (MAX_NLEN-1)) {
+				strcpy(up->counter_name, &p[(i+1)]);
+			} else {
+				strncpy(up->counter_name, &p[(i+1)], (MAX_NLEN-1));
+			}
+		}
+	}
+}
+
+static void
+build_counters_from_header(FILE *io)
+{
+	char buffer[8192], *p;
+	int i, len, cnt;
+	size_t mlen;
+
+	/* We have a new start, lets 
+	 * setup our headers and cpus.
+	 */
+	if (fgets(buffer, sizeof(buffer), io) == NULL) {
+		printf("First line can't be read from file err:%d\n", errno);
+		return;
+	}
+	/*
+	 * Ok output is an array of counters. Once
+	 * we start to read the values in we must
+	 * put them in there slot to match there CPU and 
+	 * counter being updated. We create a mass array
+	 * of the counters, filling in the CPU and 
+	 * counter name. 
+	 */
+	/* How many do we get? */
+	len = strlen(buffer);
+	for (i=0, cnt=0; i<len; i++) {
+		if (strncmp(&buffer[i], "s/", 2) == 0) {
+			cnt++;
+			for(;i<len;i++) {
+				if (buffer[i] == ' ')
+					break;
+			}
+		}
+	}
+	mlen = sizeof(struct counters) * cnt;
+	cnts = malloc(mlen);
+	ncnts = cnt;
+	if (cnts == NULL) {
+		printf("No memory err:%d\n", errno);
+		return;
+	}
+	memset(cnts, 0, mlen);
+	for (i=0, cnt=0; i<len; i++) {
+		if (strncmp(&buffer[i], "s/", 2) == 0) {
+			p = &buffer[i];
+			for(;i<len;i++) {
+				if (buffer[i] == ' ') {
+					buffer[i] = 0;
+					break;
+				}
+			}
+			process_header(cnt, p);
+			cnt++;
+		}
+	}
+	if (verbose)
+		printf("We have %d entries\n", cnt);	
+}
+extern int max_to_collect;
+int max_to_collect = MAX_COUNTER_SLOTS;
+
+static int
+read_a_line(FILE *io) 
+{
+	char buffer[8192], *p, *stop;	
+	int pos, i;
+
+	if (fgets(buffer, sizeof(buffer), io) == NULL) {
+		return(0);
+	}
+	p = buffer;
+	for (i=0; i<ncnts; i++) {
+		pos = cnts[i].pos;
+		cnts[i].vals[pos] = strtol(p, &stop, 0);
+		cnts[i].pos++;
+		cnts[i].sum += cnts[i].vals[pos];
+		p = stop;
+	}
+	return (1);
+}
+
+extern int cpu_count_out;
+int cpu_count_out=0;
+
+static void
+print_header(void)
+{
+	int i, cnt, printed_cnt;
+
+	printf("*********************************\n");
+	for(i=0, cnt=0; i<MAX_CPU; i++) {
+		if (glob_cpu[i]) {
+			cnt++;
+		}
+	}	
+	cpu_count_out = cnt;
+	for(i=0, printed_cnt=0; i<MAX_CPU; i++) {
+		if (glob_cpu[i]) {
+			printf("CPU%d", i);
+			printed_cnt++;
+		}
+		if (printed_cnt == cnt) {
+			printf("\n");
+			break;
+		} else {
+			printf("\t");
+		}
+	}
+}
+
+static void
+lace_cpus_together(void)
+{
+	int i, j, lace_cpu;
+	struct counters *cpat, *at;
+
+	for(i=0; i<ncnts; i++) {
+		cpat = &cnts[i];
+		if (cpat->next_cpu) {
+			/* Already laced in */
+			continue;
+		}
+		lace_cpu = cpat->cpu;
+		if (lace_cpu >= MAX_CPU) {
+			printf("CPU %d to big\n", lace_cpu);
+			continue;
+		}
+		if (glob_cpu[lace_cpu] == NULL) {
+			glob_cpu[lace_cpu] = cpat;
+		} else {
+			/* Already processed this cpu */
+			continue;
+		}
+		/* Ok look forward for cpu->cpu and link in */
+		for(j=(i+1); j<ncnts; j++) {
+			at = &cnts[j];
+			if (at->next_cpu) {
+				continue;
+			}
+			if (at->cpu == lace_cpu) {
+				/* Found one */
+				cpat->next_cpu = at;
+				cpat = at;
+			}
+		}
+	}
+}
+
+
+static void
+process_file(char *filename)
+{
+	FILE *io;
+	int i;
+	int line_at, not_done;
+	pid_t pid_of_command=0;
+
+	if (filename ==  NULL) {
+		io = my_popen(command, "r", &pid_of_command);
+	} else {
+		io = fopen(filename, "r");
+		if (io == NULL) {
+			printf("Can't process file %s err:%d\n",
+			       filename, errno);
+			return;
+		}
+	}
+	build_counters_from_header(io);
+	if (cnts == NULL) {
+		/* Nothing we can do */
+		printf("Nothing to do -- no counters built\n");
+		if (io) {
+			fclose(io);
+		}
+		return;
+	}
+	lace_cpus_together();
+	print_header();
+	if (verbose) {
+		for (i=0; i<ncnts; i++) {
+			printf("Counter:%s cpu:%d index:%d\n",
+			       cnts[i].counter_name,
+			       cnts[i].cpu, i);
+		}
+	}
+	line_at = 0;
+	not_done = 1;
+	while(not_done) {
+		if (read_a_line(io)) {
+			line_at++;
+		} else {
+			break;
+		}
+		if (line_at >= max_to_collect) {
+			not_done = 0;
+		}
+		if (filename == NULL) {
+			int cnt;
+			/* For the ones we dynamically open we print now */
+			for(i=0, cnt=0; i<MAX_CPU; i++) {
+				do_expression(glob_cpu[i], (line_at-1));
+				cnt++;
+				if (cnt == cpu_count_out) {
+					printf("\n");
+					break;
+				} else {
+					printf("\t");
+				}
+			}
+		}
+	}
+	if (filename) {
+		fclose(io);
+	} else {
+		my_pclose(io, pid_of_command);
+	}
+}
+#if defined(__amd64__)
+#define cpuid(in,a,b,c,d)\
+  asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
+#else
+#define cpuid(in, a, b, c, d) 
+#endif
+
+static void
+get_cpuid_set(void)
+{
+	unsigned long eax, ebx, ecx, edx;
+	int model;
+	pid_t pid_of_command=0;
+	size_t sz, len;
+	FILE *io;
+	char linebuf[1024], *str;
+
+	eax = ebx = ecx = edx = 0;
+
+	cpuid(0, eax, ebx, ecx, edx);
+	if (ebx == 0x68747541) {
+		printf("AMD processors are not supported by this program\n");
+		printf("Sorry\n");
+		exit(0);
+	} else if (ebx == 0x6972794) {
+		printf("Cyrix processors are not supported by this program\n");
+		printf("Sorry\n");
+		exit(0);
+	} else if (ebx == 0x756e6547) {
+		printf("Genuine Intel\n");
+	} else {
+		printf("Unknown processor type 0x%lx Only Intel AMD64 types are supported by this routine!\n", ebx);
+		exit(0);
+	}
+	cpuid(1, eax, ebx, ecx, edx);
+	model = (((eax & 0xF0000) >> 12) | ((eax & 0xF0) >> 4));
+	printf("CPU model is 0x%x id:0x%lx\n", model, eax);
+	switch (eax & 0xF00) {
+	case 0x500:		/* Pentium family processors */
+		printf("Intel Pentium P5\n");
+		goto not_supported;
+		break;
+	case 0x600:		/* Pentium Pro, Celeron, Pentium II & III */
+		switch (model) {
+		case 0x1:
+			printf("Intel Pentium P6\n");
+			goto not_supported;
+			break;
+		case 0x3: 
+		case 0x5:
+			printf("Intel PII\n");
+			goto not_supported;
+			break;
+		case 0x6: case 0x16:
+			printf("Intel CL\n");
+			goto not_supported;
+			break;
+		case 0x7: case 0x8: case 0xA: case 0xB:
+			printf("Intel PIII\n");
+			goto not_supported;
+			break;
+		case 0x9: case 0xD:
+			printf("Intel PM\n");
+			goto not_supported;
+			break;
+		case 0xE:
+			printf("Intel CORE\n");
+			goto not_supported;
+			break;
+		case 0xF:
+			printf("Intel CORE2\n");
+			goto not_supported;
+			break;
+		case 0x17:
+			printf("Intel CORE2EXTREME\n");
+			goto not_supported;
+			break;
+		case 0x1C:	/* Per Intel document 320047-002. */
+			printf("Intel ATOM\n");
+			goto not_supported;
+			break;
+		case 0x1A:
+		case 0x1E:	/*
+				 * Per Intel document 253669-032 9/2009,
+				 * pages A-2 and A-57
+				 */
+		case 0x1F:	/*
+				 * Per Intel document 253669-032 9/2009,
+				 * pages A-2 and A-57
+				 */
+			printf("Intel COREI7\n");
+			goto not_supported;
+			break;
+		case 0x2E:
+			printf("Intel NEHALEM\n");
+			goto not_supported;
+			break;
+		case 0x25:	/* Per Intel document 253669-033US 12/2009. */
+		case 0x2C:	/* Per Intel document 253669-033US 12/2009. */
+			printf("Intel WESTMERE\n");
+			goto not_supported;
+			break;
+		case 0x2F:	/* Westmere-EX, seen in wild */
+			printf("Intel WESTMERE\n");
+			goto not_supported;
+			break;
+		case 0x2A:	/* Per Intel document 253669-039US 05/2011. */
+			printf("Intel SANDYBRIDGE\n");
+			set_sandybridge();
+			break;
+		case 0x2D:	/* Per Intel document 253669-044US 08/2012. */
+			printf("Intel SANDYBRIDGE_XEON\n");
+			set_sandybridge();
+			break;
+		case 0x3A:	/* Per Intel document 253669-043US 05/2012. */
+			printf("Intel IVYBRIDGE\n");
+			set_ivybridge();
+			break;
+		case 0x3E:	/* Per Intel document 325462-045US 01/2013. */
+			printf("Intel IVYBRIDGE_XEON\n");
+			set_ivybridge();
+			break;
+		case 0x3F:	/* Per Intel document 325462-045US 09/2014. */
+			printf("Intel HASWELL (Xeon)\n");
+			set_haswell();
+			break;
+		case 0x3C:	/* Per Intel document 325462-045US 01/2013. */
+		case 0x45:
+		case 0x46:
+			printf("Intel HASWELL\n");
+			set_haswell();
+			break;
+		case 0x4D:
+			/* Per Intel document 330061-001 01/2014. */
+			printf("Intel ATOM_SILVERMONT\n");
+			goto not_supported;
+			break;
+		default:
+			printf("Intel model 0x%x is not known -- sorry\n",
+			       model);
+			goto not_supported;
+			break;
+		}
+		break;
+	case 0xF00:		/* P4 */
+		printf("Intel unknown model %d\n", model);
+		goto not_supported;
+		break;
+	}
+	/* Ok lets load the list of all known PMC's */
+	io = my_popen("/usr/sbin/pmccontrol -L", "r", &pid_of_command);
+	if (valid_pmcs == NULL) {
+		/* Likely */
+		pmc_allocated_cnt = PMC_INITIAL_ALLOC;
+		sz = sizeof(char *) * pmc_allocated_cnt;
+		valid_pmcs = malloc(sz);
+		if (valid_pmcs == NULL) {
+			printf("No memory allocation fails at startup?\n");	
+			exit(-1);
+		}
+		memset(valid_pmcs, 0, sz);
+	}
+	
+	while (fgets(linebuf, sizeof(linebuf), io) != NULL) {
+		if (linebuf[0] != '\t') {
+			/* sometimes headers ;-) */
+			continue;
+		}
+		len = strlen(linebuf);
+		if (linebuf[(len-1)] == '\n') {
+			/* Likely */
+			linebuf[(len-1)] = 0;
+		}
+		str = &linebuf[1];
+		len = strlen(str) + 1;
+		valid_pmcs[valid_pmc_cnt] = malloc(len);
+		if (valid_pmcs[valid_pmc_cnt] == NULL) {
+			printf("No memory2 allocation fails at startup?\n");	
+			exit(-1);
+		}
+		memset(valid_pmcs[valid_pmc_cnt], 0, len);
+		strcpy(valid_pmcs[valid_pmc_cnt], str);
+		valid_pmc_cnt++;
+		if (valid_pmc_cnt >= pmc_allocated_cnt) {
+			/* Got to expand -- unlikely */
+			char **more;
+
+			sz = sizeof(char *) * (pmc_allocated_cnt * 2);
+			more = malloc(sz);
+			if (more == NULL) {
+				printf("No memory3 allocation fails at startup?\n");	
+				exit(-1);
+			}
+			memset(more, 0, sz);
+			memcpy(more, valid_pmcs, sz);
+			pmc_allocated_cnt *= 2;
+			free(valid_pmcs);
+			valid_pmcs = more;
+		}
+	}
+	my_pclose(io, pid_of_command);	
+	return;
+not_supported:
+	printf("Not supported\n");	
+	exit(-1);
+}
+
+static void
+explain_all(void)
+{
+	int i;
+	printf("For CPU's of type %s the following expressions are available:\n",the_cpu.cputype);
+	printf("-------------------------------------------------------------\n");
+	for(i=0; i<the_cpu.number; i++){
+		printf("For -e %s ", the_cpu.ents[i].name);
+		(*the_cpu.explain)(the_cpu.ents[i].name);
+		printf("----------------------------\n");
+	}
+}
+
+static void
+test_for_a_pmc(const char *pmc, int out_so_far)
+{
+	FILE *io;
+	pid_t pid_of_command=0;	
+	char my_command[1024];
+	char line[1024];
+	char resp[1024];
+	int len, llen, i;
+
+	if (out_so_far < 50) {
+		len = 50 - out_so_far;
+		for(i=0; i<len; i++) {
+			printf(" ");
+		}
+	}
+	sprintf(my_command, "/usr/sbin/pmcstat -w .25 -c 0 -s %s", pmc);
+	io = my_popen(my_command, "r", &pid_of_command);	
+	if (io == NULL) {
+		printf("Failed -- popen fails\n");
+		return;
+	}
+	/* Setup what we expect */
+	len = sprintf(resp, "%s", pmc);
+	if (fgets(line, sizeof(line), io) == NULL) {
+		printf("Failed -- no output from pmstat\n");
+		goto out;
+	}
+	llen = strlen(line);
+	if (line[(llen-1)] == '\n') {
+		line[(llen-1)] = 0;
+		llen--;
+	}
+	for(i=2; i<(llen-len); i++) {
+		if (strncmp(&line[i], "ERROR", 5) == 0) {
+			printf("Failed %s\n", line);
+			goto out;
+		} else if (strncmp(&line[i], resp, len) == 0) {
+			int j, k;
+
+			if (fgets(line, sizeof(line), io) == NULL) {
+				printf("Failed -- no second output from pmstat\n");
+				goto out;
+			}
+			len = strlen(line);
+			for (j=0; j<len; j++) {
+				if (line[j] == ' ') {
+					j++; 
+				} else {
+					break;
+				}
+			}
+			printf("Pass");
+			len = strlen(&line[j]);
+			if (len < 20) {
+				for(k=0; k<(20-len); k++) {
+					printf(" ");
+				}
+			}
+			if (len) {
+				printf("%s", &line[j]);
+			} else {
+				printf("\n");
+			}
+			goto out;
+		}
+	}
+	printf("Failed -- '%s' not '%s'\n", line, resp);
+out:
+	my_pclose(io, pid_of_command);		
+	
+}
+
+static int
+add_it_to(char **vars, int cur_cnt, char *name)
+{
+	int i;
+	size_t len;
+	for(i=0; i<cur_cnt; i++) {
+		if (strcmp(vars[i], name) == 0) {
+			/* Already have */
+			return(0);
+		}
+	}
+	if (vars[cur_cnt] != NULL) {
+		printf("Cur_cnt:%d filled with %s??\n", 
+		       cur_cnt, vars[cur_cnt]);
+		exit(-1);
+	}
+	/* Ok its new */
+	len = strlen(name) + 1;
+	vars[cur_cnt] = malloc(len);
+	if (vars[cur_cnt] == NULL) {
+		printf("No memory %s\n", __FUNCTION__);
+		exit(-1);
+	}
+	memset(vars[cur_cnt], 0, len);
+	strcpy(vars[cur_cnt], name);
+	return(1);
+}
+
+static char *
+build_command_for_exp(struct expression *exp)
+{
+	/*
+	 * Build the pmcstat command to handle
+	 * the passed in expression.
+	 * /usr/sbin/pmcstat -w 1 -s NNN -s QQQ
+	 * where NNN and QQQ represent the PMC's in the expression
+	 * uniquely..
+	 */
+	char forming[1024];
+	int cnt_pmc, alloced_pmcs, i;
+	struct expression *at;
+	char **vars, *cmd;
+	size_t mal;
+
+	alloced_pmcs = cnt_pmc = 0;
+	/* first how many do we have */
+	at = exp;
+	while (at) {
+		if (at->type == TYPE_VALUE_PMC) {
+			cnt_pmc++;
+		}
+		at = at->next;
+	}
+	if (cnt_pmc == 0) {
+		printf("No PMC's in your expression -- nothing to do!!\n");
+		exit(0);
+	}
+	mal = cnt_pmc * sizeof(char *);
+	vars = malloc(mal);
+	if (vars == NULL) {
+		printf("No memory\n");
+		exit(-1);
+	}
+	memset(vars, 0, mal);
+	at = exp;
+	while (at) {
+		if (at->type == TYPE_VALUE_PMC) {
+			if(add_it_to(vars, alloced_pmcs, at->name)) {
+				alloced_pmcs++;
+			}
+		}
+		at = at->next;
+	}
+	/* Now we have a unique list in vars so create our command */
+	mal = 23; /*	"/usr/sbin/pmcstat -w 1"  + \0 */
+	for(i=0; i<alloced_pmcs; i++) {
+		mal += strlen(vars[i]) + 4;	/* var + " -s " */
+	}
+	cmd = malloc((mal+2));
+	if (cmd == NULL) {
+		printf("%s out of mem\n", __FUNCTION__);
+		exit(-1);
+	}
+	memset(cmd, 0, (mal+2));
+	strcpy(cmd, "/usr/sbin/pmcstat -w 1");
+	at = exp;
+	for(i=0; i<alloced_pmcs; i++) {
+		sprintf(forming, " -s %s", vars[i]);
+		strcat(cmd, forming);
+		free(vars[i]);
+		vars[i] = NULL;
+	}
+	free(vars);
+	return(cmd);
+}
+
+static int
+user_expr(struct counters *cpu, int pos)
+{
+	int ret;	
+	double res;
+	struct counters *var;
+	struct expression *at;
+
+	at = master_exp;
+	while (at) {
+		if (at->type == TYPE_VALUE_PMC) {
+			var = find_counter(cpu, at->name);
+			if (var == NULL) {
+				printf("%s:Can't find counter %s?\n", __FUNCTION__, at->name);
+				exit(-1);
+			}
+			if (pos != -1) {
+				at->value = var->vals[pos] * 1.0;
+			} else {
+				at->value = var->sum * 1.0;
+			}
+		}
+		at = at->next;
+	}
+	res = run_expr(master_exp, 1, NULL);
+	ret = printf("%1.3f", res);
+	return(ret);
+}
+
+
+static void
+set_manual_exp(struct expression *exp)
+{
+	expression = user_expr;
+	command = build_command_for_exp(exp);
+	threshold = "User defined threshold";
+}
+
+static void
+run_tests(void)
+{
+	int i, lenout;
+	printf("Running tests on %d PMC's this may take some time\n", valid_pmc_cnt);
+	printf("------------------------------------------------------------------------\n");
+	for(i=0; i<valid_pmc_cnt; i++) {
+		lenout = printf("%s", valid_pmcs[i]);
+		fflush(stdout);
+		test_for_a_pmc(valid_pmcs[i], lenout);
+	}
+}
+static void
+list_all(void)
+{
+	int i, cnt, j;
+	printf("PMC                                               Abbreviation\n");
+	printf("--------------------------------------------------------------\n");
+	for(i=0; i<valid_pmc_cnt; i++) {
+		cnt = printf("%s", valid_pmcs[i]);
+		for(j=cnt; j<52; j++) {
+			printf(" ");
+		}
+		printf("%%%d\n", i);
+	}
+}
+
+
+int
+main(int argc, char **argv)
+{
+	int i, j, cnt;
+	char *filename=NULL;
+	char *name=NULL;
+	int help_only = 0;
+	int test_mode = 0;
+
+	get_cpuid_set();
+	memset(glob_cpu, 0, sizeof(glob_cpu));
+	while ((i = getopt(argc, argv, "LHhvm:i:?e:TE:")) != -1) {
+		switch (i) {
+		case 'L':
+			list_all();
+			return(0);
+		case 'H':
+			printf("**********************************\n");
+			explain_all();
+			printf("**********************************\n");
+			return(0);
+			break;
+		case 'T':
+			test_mode = 1;
+			break;
+		case 'E':
+			master_exp = parse_expression(optarg);
+			if (master_exp) {
+				set_manual_exp(master_exp);
+			}
+			break;
+		case 'e':
+			if (validate_expression(optarg)) {
+				printf("Unknown expression %s\n", optarg);
+				return(0);
+			}
+			name = optarg;
+			set_expression(optarg);
+			break;
+		case 'm':
+			max_to_collect = strtol(optarg, NULL, 0);
+			if (max_to_collect > MAX_COUNTER_SLOTS) {
+				/* You can't collect more than max in array */
+				max_to_collect = MAX_COUNTER_SLOTS;
+			}
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'h':
+			help_only = 1;
+			break;
+		case 'i':
+			filename = optarg;
+			break;
+		case '?':
+		default:
+		use:
+			printf("Use %s [ -i inputfile -v -m max_to_collect -e expr -E -h -? -H]\n",
+			       argv[0]);
+			printf("-i inputfile -- use source as inputfile not stdin (if stdin collect)\n");
+			printf("-v -- verbose dump debug type things -- you don't want this\n");
+			printf("-m N -- maximum to collect is N measurments\n");
+			printf("-e expr-name -- Do expression expr-name\n");
+			printf("-E 'your expression' -- Do your expression\n");
+			printf("-h -- Don't do the expression I put in -e xxx just explain what it does and exit\n");
+			printf("-H -- Don't run anything, just explain all canned expressions\n");
+			printf("-T -- Test all PMC's defined by this processor\n");
+			return(0);
+			break;
+		};
+	}
+	if ((name == NULL) && (filename == NULL) && (test_mode == 0) && (master_exp == NULL)) {
+		printf("Without setting an expression we cannot dynamically gather information\n");
+		printf("you must supply a filename (and you probably want verbosity)\n");
+		goto use;
+	}
+	if (test_mode) {
+		run_tests();
+		return(0);
+	}
+	printf("*********************************\n");
+	if (master_exp == NULL) {
+		(*the_cpu.explain)(name);
+	} else {
+		printf("Examine your expression ");
+		print_exp(master_exp);
+		printf("User defined threshold\n");
+	}
+	if (help_only) {
+		return(0);
+	}
+	process_file(filename);
+	if (verbose >= 2) {
+		for (i=0; i<ncnts; i++) {
+			printf("Counter:%s cpu:%d index:%d\n",
+			       cnts[i].counter_name,
+			       cnts[i].cpu, i);
+			for(j=0; j<cnts[i].pos; j++) {
+				printf(" val - %ld\n", (long int)cnts[i].vals[j]);
+			}
+			printf(" sum - %ld\n", (long int)cnts[i].sum);
+		}
+	}
+	if (expression == NULL) {
+		return(0);
+	}
+	for(i=0, cnt=0; i<MAX_CPU; i++) {
+		if (glob_cpu[i]) {
+			do_expression(glob_cpu[i], -1);
+			cnt++;
+			if (cnt == cpu_count_out) {
+				printf("\n");
+				break;
+			} else {
+				printf("\t");
+			}
+		}
+	}
+	return(0);	
+}


Property changes on: trunk/usr.sbin/pmcstudy/pmcstudy.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property


More information about the Midnightbsd-cvs mailing list