├── .gitignore ├── AUTHORS ├── INSTALL ├── Makefile.in ├── README ├── config.h.in ├── configure ├── configure.ac ├── install-sh ├── report ├── Makefile ├── conclusion.tex ├── introduction.tex ├── methodology.tex ├── results.tex ├── tiptop-bug.pdf ├── tiptop-default.pdf ├── tiptop-papi.pdf ├── tiptop-report.bib ├── tiptop-report.pdf ├── tiptop-report.tex └── tiptop-threads.pdf ├── src ├── Makefile.in ├── calc.lex ├── calc.y ├── conf.c ├── conf.h ├── debug.c ├── debug.h ├── error.c ├── error.h ├── formula-parser.h ├── hash.c ├── hash.h ├── helpwin.c ├── helpwin.h ├── options.c ├── options.h ├── pmc.c ├── pmc.h ├── process.c ├── process.h ├── requisite.c ├── requisite.h ├── screen.c ├── screen.h ├── spawn.c ├── spawn.h ├── target-x86.c ├── target.c ├── target.h ├── tiptop.1 ├── tiptop.c ├── utils-expression.c ├── utils-expression.h ├── version.c ├── version.h ├── xml-parser.c └── xml-parser.h ├── tests ├── nthreads.c ├── test_tiptop_basic.py ├── test_tiptop_fd.py ├── test_tiptop_main.py ├── test_tiptop_thread_main.py └── testobjects.txt ├── tiptoprc └── tiptoprc.papi /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by configure 2 | /config.* 3 | /Makefile 4 | /src/Makefile 5 | 6 | # Flex and Bison products 7 | /src/lex.yy.c 8 | /src/y.tab.[ch] 9 | 10 | # Object files 11 | *.o 12 | 13 | # Build products 14 | /src/ptiptop 15 | /src/tiptop 16 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Authors of tiptop 2 | 3 | 4 | Erven ROHOU 5 | Main author 6 | 7 | Antoine NAUDIN 8 | Contributed the configuration file, the expression parser, and 9 | the error management mechanism. 10 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Tiptop can be built in two ways: 2 | - in-directory, mixing object files with source code; 3 | - in another directory. 4 | 5 | 6 | * In-directory 7 | 8 | 1. cd /where/you/unpacked/tiptop-x.y 9 | 2. ./configure [--prefix=/some/where] 10 | 3. make 11 | (4. optional) make install 12 | 13 | 14 | 15 | * In another directory 16 | 17 | 1. mkdir build-dir 18 | 2. cd build-dir 19 | 3. /where/you/unpacked/tiptop-x.y/configure [--prefix=/some/where] 20 | 4. make 21 | (5. optional) make install 22 | 23 | 24 | 25 | Consider editing and installing the provided configuration file 26 | tiptoprc. -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # @configure_input@ 2 | 3 | package = @PACKAGE_NAME@ 4 | version = @PACKAGE_VERSION@ 5 | tarname = @PACKAGE_TARNAME@ 6 | distdir = $(tarname)-$(version) 7 | 8 | prefix = @prefix@ 9 | exec_prefix = @exec_prefix@ 10 | bindir = @bindir@ 11 | datarootdir = @datarootdir@ 12 | mandir = @mandir@ 13 | man1dir = $(mandir)/man1 14 | 15 | # VPATH-specific substitution variables 16 | srcdir = @srcdir@ 17 | VPATH = @srcdir@ 18 | 19 | 20 | export prefix 21 | export exec_prefix 22 | export bindir 23 | export datarootdir 24 | export mandir 25 | export man1dir 26 | 27 | 28 | 29 | 30 | all clean install uninstall tiptop: 31 | cd src && $(MAKE) $@ 32 | 33 | 34 | dist: $(distdir).tar.gz 35 | 36 | 37 | $(distdir).tar.gz: $(distdir) 38 | tar chof - $(distdir) | gzip -9 -c > $@ 39 | rm -rf $(distdir) 40 | 41 | 42 | distcheck: $(distdir).tar.gz 43 | gzip -cd $(distdir).tar.gz | tar xvf - 44 | cd $(distdir) && ./configure 45 | cd $(distdir) && $(MAKE) all 46 | cd $(distdir) && $(MAKE) prefix=$${PWD}/_inst install 47 | cd $(distdir) && $(MAKE) prefix=$${PWD}/_inst uninstall 48 | @remaining="`find $${PWD}/$(distdir)/_inst -type f | wc -l`"; \ 49 | if test "$${remaining}" -ne 0; then \ 50 | echo "*** $${remaining} file(s) remaining in stage directory!"; \ 51 | exit 1; \ 52 | fi 53 | cd $(distdir) && $(MAKE) clean 54 | rm -rf $(distdir) 55 | @echo "*** Package $(distdir).tar.gz is ready for distribution." 56 | 57 | 58 | Makefile: Makefile.in config.status 59 | ./config.status $@ 60 | 61 | config.status: configure 62 | ./config.status --recheck 63 | 64 | 65 | $(distdir): FORCE 66 | mkdir -p $(distdir)/src 67 | cp $(srcdir)/configure.ac $(distdir) 68 | cp $(srcdir)/configure $(distdir) 69 | cp $(srcdir)/config.h.in $(distdir) 70 | cp $(srcdir)/install-sh $(distdir) 71 | cp $(srcdir)/AUTHORS $(distdir) 72 | cp $(srcdir)/INSTALL $(distdir) 73 | cp $(srcdir)/README $(distdir) 74 | cp $(srcdir)/Makefile.in $(distdir) 75 | cp $(srcdir)/tiptoprc $(distdir) 76 | cp $(srcdir)/src/Makefile.in $(distdir)/src 77 | cp $(srcdir)/src/tiptop.1 $(distdir)/src 78 | cp $(srcdir)/src/calc.lex $(distdir)/src 79 | cp $(srcdir)/src/calc.y $(distdir)/src 80 | cp $(srcdir)/src/conf.c $(distdir)/src 81 | cp $(srcdir)/src/conf.h $(distdir)/src 82 | cp $(srcdir)/src/debug.c $(distdir)/src 83 | cp $(srcdir)/src/debug.h $(distdir)/src 84 | cp $(srcdir)/src/error.c $(distdir)/src 85 | cp $(srcdir)/src/error.h $(distdir)/src 86 | cp $(srcdir)/src/formula-parser.h $(distdir)/src 87 | cp $(srcdir)/src/hash.c $(distdir)/src 88 | cp $(srcdir)/src/hash.h $(distdir)/src 89 | cp $(srcdir)/src/helpwin.c $(distdir)/src 90 | cp $(srcdir)/src/helpwin.h $(distdir)/src 91 | cp $(srcdir)/src/options.c $(distdir)/src 92 | cp $(srcdir)/src/options.h $(distdir)/src 93 | cp $(srcdir)/src/pmc.c $(distdir)/src 94 | cp $(srcdir)/src/pmc.h $(distdir)/src 95 | cp $(srcdir)/src/process.c $(distdir)/src 96 | cp $(srcdir)/src/process.h $(distdir)/src 97 | cp $(srcdir)/src/requisite.c $(distdir)/src 98 | cp $(srcdir)/src/requisite.h $(distdir)/src 99 | cp $(srcdir)/src/screen.c $(distdir)/src 100 | cp $(srcdir)/src/screen.h $(distdir)/src 101 | cp $(srcdir)/src/spawn.c $(distdir)/src 102 | cp $(srcdir)/src/spawn.h $(distdir)/src 103 | cp $(srcdir)/src/target.c $(distdir)/src 104 | cp $(srcdir)/src/target.h $(distdir)/src 105 | cp $(srcdir)/src/target-x86.c $(distdir)/src 106 | cp $(srcdir)/src/tiptop.c $(distdir)/src 107 | cp $(srcdir)/src/utils-expression.c $(distdir)/src 108 | cp $(srcdir)/src/utils-expression.h $(distdir)/src 109 | cp $(srcdir)/src/version.c $(distdir)/src 110 | cp $(srcdir)/src/version.h $(distdir)/src 111 | cp $(srcdir)/src/xml-parser.c $(distdir)/src 112 | cp $(srcdir)/src/xml-parser.h $(distdir)/src 113 | 114 | FORCE: 115 | -rm $(distdir).tar.gz > /dev/null 2>&1 116 | -rm -rf $(distdir) > /dev/null 2>&1 117 | 118 | .PHONY: FORCE all clean dist distcheck install uninstall 119 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | Tiptop 3 | 4 | 5 | Tiptop is a performance monitoring tool for Linux. It provides a 6 | dynamic real-time view of the tasks running in the system. tiptop is 7 | very similar to the top utility, but most of the information displayed 8 | comes from hardware counters. 9 | 10 | 11 | * Installation 12 | Tiptop is a single executable. It can be launched from any place in 13 | the filesystem. Documentation is in the man page tiptop.1. 14 | For installation instructions, check file INSTALL. 15 | 16 | 17 | * Requirements 18 | Linux 2.6.31+, /proc filesystem. For live-mode, the ncurses library is 19 | needed. libxml2 is required to parse the configuration file. 20 | PAPI 5.0.1 is required to use PAPI macros for hardware counters. 21 | 22 | 23 | * Common command lines: 24 | 25 | tiptop --help 26 | 27 | tiptop 28 | no arg, uses default 29 | 30 | tiptop -b 31 | batch mode 32 | 33 | tiptop -d 10 34 | refresh every 10 seconds 35 | 36 | tiptop -i 37 | also show idle processes (see --cpu-min to define the threshold) 38 | 39 | tiptop -H 40 | also show threads 41 | 42 | tiptop -W path 43 | specify the location of the configuration file 44 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 to enable support for debug. */ 4 | #undef ENABLE_DEBUG 5 | 6 | /* Define to 1 if you have the `fork' function. */ 7 | #undef HAVE_FORK 8 | 9 | /* Define to 1 if you have the `gettimeofday' function. */ 10 | #undef HAVE_GETTIMEOFDAY 11 | 12 | /* Define to 1 if you have the header file. */ 13 | #undef HAVE_INTTYPES_H 14 | 15 | /* Define to 1 if you have the `curses' library (-lcurses). */ 16 | #undef HAVE_LIBCURSES 17 | 18 | /* Define to 1 if you have the `libpapi' library (-lpapi). */ 19 | #undef HAVE_LIBPAPI 20 | 21 | /* Define to 1 if you have the `libxml2' library (-lxml2). */ 22 | #undef HAVE_LIBXML2 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_LINUX_PERF_COUNTER_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_LINUX_PERF_EVENT_H 29 | 30 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 31 | to 0 otherwise. */ 32 | #undef HAVE_MALLOC 33 | 34 | /* Define to 1 if you have the header file. */ 35 | #undef HAVE_MEMORY_H 36 | 37 | /* Define to 1 if you have the `memset' function. */ 38 | #undef HAVE_MEMSET 39 | 40 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 41 | and to 0 otherwise. */ 42 | #undef HAVE_REALLOC 43 | 44 | /* Define to 1 if you have the `select' function. */ 45 | #undef HAVE_SELECT 46 | 47 | /* Define to 1 if you have the header file. */ 48 | #undef HAVE_STDINT_H 49 | 50 | /* Define to 1 if you have the header file. */ 51 | #undef HAVE_STDLIB_H 52 | 53 | /* Define to 1 if you have the `strdup' function. */ 54 | #undef HAVE_STRDUP 55 | 56 | /* Define to 1 if you have the `strerror' function. */ 57 | #undef HAVE_STRERROR 58 | 59 | /* Define to 1 if you have the header file. */ 60 | #undef HAVE_STRINGS_H 61 | 62 | /* Define to 1 if you have the header file. */ 63 | #undef HAVE_STRING_H 64 | 65 | /* Define to 1 if you have the `strstr' function. */ 66 | #undef HAVE_STRSTR 67 | 68 | /* Define to 1 if you have the header file. */ 69 | #undef HAVE_SYS_IOCTL_H 70 | 71 | /* Define to 1 if you have the header file. */ 72 | #undef HAVE_SYS_STAT_H 73 | 74 | /* Define to 1 if you have the header file. */ 75 | #undef HAVE_SYS_TIME_H 76 | 77 | /* Define to 1 if you have the header file. */ 78 | #undef HAVE_SYS_TYPES_H 79 | 80 | /* Define to 1 if you have the `uname' function. */ 81 | #undef HAVE_UNAME 82 | 83 | /* Define to 1 if you have the header file. */ 84 | #undef HAVE_UNISTD_H 85 | 86 | /* Define to 1 if you have the `vfork' function. */ 87 | #undef HAVE_VFORK 88 | 89 | /* Define to 1 if you have the header file. */ 90 | #undef HAVE_VFORK_H 91 | 92 | /* Define to 1 if `fork' works. */ 93 | #undef HAVE_WORKING_FORK 94 | 95 | /* Define to 1 if `vfork' works. */ 96 | #undef HAVE_WORKING_VFORK 97 | 98 | /* Define to 1 when no specific target is supported. */ 99 | #undef NOTARGET 100 | 101 | /* Define to the address where bug reports for this package should be sent. */ 102 | #undef PACKAGE_BUGREPORT 103 | 104 | /* Define to the full name of this package. */ 105 | #undef PACKAGE_NAME 106 | 107 | /* Define to the full name and version of this package. */ 108 | #undef PACKAGE_STRING 109 | 110 | /* Define to the one symbol short name of this package. */ 111 | #undef PACKAGE_TARNAME 112 | 113 | /* Define to the home page for this package. */ 114 | #undef PACKAGE_URL 115 | 116 | /* Define to the version of this package. */ 117 | #undef PACKAGE_VERSION 118 | 119 | /* Define to 1 if you have the ANSI C header files. */ 120 | #undef STDC_HEADERS 121 | 122 | /* Define to 1 if the target is x86. */ 123 | #undef TARGET_X86 124 | 125 | /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a 126 | `char[]'. */ 127 | #undef YYTEXT_POINTER 128 | 129 | /* Define for Solaris 2.5.1 so the uint32_t typedef from , 130 | , or is not used. If the typedef were allowed, the 131 | #define below would cause a syntax error. */ 132 | #undef _UINT32_T 133 | 134 | /* Define for Solaris 2.5.1 so the uint64_t typedef from , 135 | , or is not used. If the typedef were allowed, the 136 | #define below would cause a syntax error. */ 137 | #undef _UINT64_T 138 | 139 | /* Define to `int' if doesn't define. */ 140 | #undef gid_t 141 | 142 | /* Define to `__inline__' or `__inline' if that's what the C compiler 143 | calls it, or to nothing if 'inline' is not supported under any name. */ 144 | #ifndef __cplusplus 145 | #undef inline 146 | #endif 147 | 148 | /* Define to the type of a signed integer type of width exactly 32 bits if 149 | such a type exists and the standard includes do not define it. */ 150 | #undef int32_t 151 | 152 | /* Define to the type of a signed integer type of width exactly 64 bits if 153 | such a type exists and the standard includes do not define it. */ 154 | #undef int64_t 155 | 156 | /* Define to rpl_malloc if the replacement function should be used. */ 157 | #undef malloc 158 | 159 | /* Define to `int' if does not define. */ 160 | #undef pid_t 161 | 162 | /* Define to rpl_realloc if the replacement function should be used. */ 163 | #undef realloc 164 | 165 | /* Define to `int' if doesn't define. */ 166 | #undef uid_t 167 | 168 | /* Define to the type of an unsigned integer type of width exactly 32 bits if 169 | such a type exists and the standard includes do not define it. */ 170 | #undef uint32_t 171 | 172 | /* Define to the type of an unsigned integer type of width exactly 64 bits if 173 | such a type exists and the standard includes do not define it. */ 174 | #undef uint64_t 175 | 176 | /* Define as `fork' if `vfork' does not work. */ 177 | #undef vfork 178 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.68]) 2 | AC_INIT([tiptop], [2.1], [erven.rohou@inria.fr]) 3 | 4 | AC_CONFIG_SRCDIR([src/tiptop.c]) 5 | AC_CONFIG_HEADERS([config.h]) 6 | 7 | # Checks for programs. 8 | AC_PROG_CC 9 | AC_PROG_LEX 10 | AC_PROG_YACC 11 | AC_PROG_INSTALL 12 | 13 | 14 | AC_ARG_ENABLE(curses, [ --disable-curses disable usage of libcurses, even if available], 15 | [disable_curses=$enableval], [disable_curses=$enableval]) 16 | 17 | AC_ARG_ENABLE(libxml2, [ --disable-libxml2 disable usage of libxml2, even if available], 18 | [disable_libxml2=$enableval], [disable_libxml2=$enableval]) 19 | 20 | # Checks for libraries. 21 | if test ! x$disable_curses = xno; then # check only if not disabled 22 | AC_CHECK_LIB([curses], [initscr], 23 | [have_curses=yes; 24 | AC_DEFINE([HAVE_LIBCURSES], [1], [Define to 1 if you have the `curses' library (-lcurses).]) 25 | LIBS="-lcurses $LIBS"], 26 | [have_curses=no]) 27 | fi 28 | 29 | if test ! x$disable_libxml2 = xno; then # check only if not disabled 30 | AC_CHECK_LIB([xml2], [xmlParseFile], 31 | [have_xml2=yes; 32 | AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have the `libxml2' library (-lxml2).]) 33 | LIBS="-lxml2 $LIBS" 34 | CFLAGS="$CFLAGS -I/usr/include/libxml2"], 35 | [have_xml2=no]) 36 | fi 37 | 38 | # Check for papi 39 | AC_CHECK_LIB([papi], [PAPI_library_init], 40 | [have_papi=yes; 41 | AC_DEFINE([HAVE_LIBPAPI], [1], [Define to 1 if you have the `libpapi' library (-lpapi).]) 42 | LIBS="-lpapi $LIBS"], 43 | [have_papi=no]) 44 | 45 | 46 | # Checks for header files. 47 | AC_CHECK_HEADERS([inttypes.h stdint.h stdlib.h string.h sys/ioctl.h sys/time.h unistd.h]) 48 | 49 | 50 | 51 | AC_CHECK_HEADERS([linux/perf_counter.h], [have_perf_counter=yes], 52 | [have_perf_counter=no]) 53 | 54 | AC_CHECK_HEADERS([linux/perf_event.h], [have_perf_event=yes], 55 | [have_perf_event=no]) 56 | 57 | if test "x${have_perf_counter}" = xno -a "x${have_perf_event}" = xno; then 58 | os=`uname -s -r` 59 | AC_MSG_FAILURE([ 60 | ------------------------------------------------------------ 61 | Could not locate linux/perf_count.h or linux/perf_event.h. 62 | Are performance counters supported on this machine? 63 | Linux 2.6.31+ is required. 64 | uname reports: ${os} 65 | ------------------------------------------------------------]) 66 | fi 67 | 68 | 69 | # Check for hardware architecture 70 | no_target=yes 71 | AC_MSG_CHECKING([hardware]) 72 | hw=`uname -m` 73 | case $hw in 74 | x86_64 | i386 | i686 ) : 75 | AC_MSG_RESULT([x86]) 76 | AC_DEFINE([TARGET_X86], [1], [Define to 1 if the target is x86.]) 77 | no_target=no 78 | ;; 79 | unknown ) : 80 | AC_MSG_RESULT([unknown]) 81 | AC_MSG_WARN([Could not detect architecture]) 82 | ;; 83 | * ) : 84 | AC_MSG_RESULT([$hw]) 85 | ;; 86 | esac 87 | 88 | if test x$no_target = xyes; then 89 | AC_DEFINE([NOTARGET], [1], [Define to 1 when no specific target is supported.]) 90 | fi 91 | 92 | # Checks for typedefs, structures, and compiler characteristics. 93 | AC_C_INLINE 94 | AC_TYPE_INT32_T 95 | AC_TYPE_INT64_T 96 | AC_TYPE_PID_T 97 | AC_TYPE_UID_T 98 | AC_TYPE_UINT32_T 99 | AC_TYPE_UINT64_T 100 | 101 | # Checks for library functions. 102 | AC_FUNC_FORK 103 | AC_FUNC_MALLOC 104 | AC_FUNC_REALLOC 105 | AC_CHECK_FUNCS([gettimeofday memset select strdup strerror strstr uname]) 106 | 107 | AC_CONFIG_FILES([Makefile 108 | src/Makefile]) 109 | 110 | AC_ARG_ENABLE(debug, [ --enable-debug enable support for debug], 111 | [AC_DEFINE([ENABLE_DEBUG], [1], [Define to 1 to enable support for debug.])]) 112 | 113 | 114 | if test "x${have_curses}" = xno; then 115 | AC_MSG_WARN([ 116 | ----------------------------------------------------- 117 | Library curses not found. Building without support. 118 | -----------------------------------------------------]) 119 | fi 120 | 121 | if test "x${have_xml2}" = xno; then 122 | AC_MSG_WARN([ 123 | ----------------------------------------------------- 124 | Library xml2 not found. Building without support. 125 | -----------------------------------------------------]) 126 | fi 127 | 128 | AC_OUTPUT 129 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2009-04-28.21; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | shift;; 160 | 161 | -T) no_target_directory=true;; 162 | 163 | --version) echo "$0 $scriptversion"; exit $?;; 164 | 165 | --) shift 166 | break;; 167 | 168 | -*) echo "$0: invalid option: $1" >&2 169 | exit 1;; 170 | 171 | *) break;; 172 | esac 173 | shift 174 | done 175 | 176 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 177 | # When -d is used, all remaining arguments are directories to create. 178 | # When -t is used, the destination is already specified. 179 | # Otherwise, the last argument is the destination. Remove it from $@. 180 | for arg 181 | do 182 | if test -n "$dst_arg"; then 183 | # $@ is not empty: it contains at least $arg. 184 | set fnord "$@" "$dst_arg" 185 | shift # fnord 186 | fi 187 | shift # arg 188 | dst_arg=$arg 189 | done 190 | fi 191 | 192 | if test $# -eq 0; then 193 | if test -z "$dir_arg"; then 194 | echo "$0: no input file specified." >&2 195 | exit 1 196 | fi 197 | # It's OK to call `install-sh -d' without argument. 198 | # This can happen when creating conditional directories. 199 | exit 0 200 | fi 201 | 202 | if test -z "$dir_arg"; then 203 | trap '(exit $?); exit' 1 2 13 15 204 | 205 | # Set umask so as not to create temps with too-generous modes. 206 | # However, 'strip' requires both read and write access to temps. 207 | case $mode in 208 | # Optimize common cases. 209 | *644) cp_umask=133;; 210 | *755) cp_umask=22;; 211 | 212 | *[0-7]) 213 | if test -z "$stripcmd"; then 214 | u_plus_rw= 215 | else 216 | u_plus_rw='% 200' 217 | fi 218 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 219 | *) 220 | if test -z "$stripcmd"; then 221 | u_plus_rw= 222 | else 223 | u_plus_rw=,u+rw 224 | fi 225 | cp_umask=$mode$u_plus_rw;; 226 | esac 227 | fi 228 | 229 | for src 230 | do 231 | # Protect names starting with `-'. 232 | case $src in 233 | -*) src=./$src;; 234 | esac 235 | 236 | if test -n "$dir_arg"; then 237 | dst=$src 238 | dstdir=$dst 239 | test -d "$dstdir" 240 | dstdir_status=$? 241 | else 242 | 243 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 244 | # might cause directories to be created, which would be especially bad 245 | # if $src (and thus $dsttmp) contains '*'. 246 | if test ! -f "$src" && test ! -d "$src"; then 247 | echo "$0: $src does not exist." >&2 248 | exit 1 249 | fi 250 | 251 | if test -z "$dst_arg"; then 252 | echo "$0: no destination specified." >&2 253 | exit 1 254 | fi 255 | 256 | dst=$dst_arg 257 | # Protect names starting with `-'. 258 | case $dst in 259 | -*) dst=./$dst;; 260 | esac 261 | 262 | # If destination is a directory, append the input filename; won't work 263 | # if double slashes aren't ignored. 264 | if test -d "$dst"; then 265 | if test -n "$no_target_directory"; then 266 | echo "$0: $dst_arg: Is a directory" >&2 267 | exit 1 268 | fi 269 | dstdir=$dst 270 | dst=$dstdir/`basename "$src"` 271 | dstdir_status=0 272 | else 273 | # Prefer dirname, but fall back on a substitute if dirname fails. 274 | dstdir=` 275 | (dirname "$dst") 2>/dev/null || 276 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 277 | X"$dst" : 'X\(//\)[^/]' \| \ 278 | X"$dst" : 'X\(//\)$' \| \ 279 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 280 | echo X"$dst" | 281 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 282 | s//\1/ 283 | q 284 | } 285 | /^X\(\/\/\)[^/].*/{ 286 | s//\1/ 287 | q 288 | } 289 | /^X\(\/\/\)$/{ 290 | s//\1/ 291 | q 292 | } 293 | /^X\(\/\).*/{ 294 | s//\1/ 295 | q 296 | } 297 | s/.*/./; q' 298 | ` 299 | 300 | test -d "$dstdir" 301 | dstdir_status=$? 302 | fi 303 | fi 304 | 305 | obsolete_mkdir_used=false 306 | 307 | if test $dstdir_status != 0; then 308 | case $posix_mkdir in 309 | '') 310 | # Create intermediate dirs using mode 755 as modified by the umask. 311 | # This is like FreeBSD 'install' as of 1997-10-28. 312 | umask=`umask` 313 | case $stripcmd.$umask in 314 | # Optimize common cases. 315 | *[2367][2367]) mkdir_umask=$umask;; 316 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 317 | 318 | *[0-7]) 319 | mkdir_umask=`expr $umask + 22 \ 320 | - $umask % 100 % 40 + $umask % 20 \ 321 | - $umask % 10 % 4 + $umask % 2 322 | `;; 323 | *) mkdir_umask=$umask,go-w;; 324 | esac 325 | 326 | # With -d, create the new directory with the user-specified mode. 327 | # Otherwise, rely on $mkdir_umask. 328 | if test -n "$dir_arg"; then 329 | mkdir_mode=-m$mode 330 | else 331 | mkdir_mode= 332 | fi 333 | 334 | posix_mkdir=false 335 | case $umask in 336 | *[123567][0-7][0-7]) 337 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 338 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 339 | ;; 340 | *) 341 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 342 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 343 | 344 | if (umask $mkdir_umask && 345 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 346 | then 347 | if test -z "$dir_arg" || { 348 | # Check for POSIX incompatibilities with -m. 349 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 350 | # other-writeable bit of parent directory when it shouldn't. 351 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 352 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 353 | case $ls_ld_tmpdir in 354 | d????-?r-*) different_mode=700;; 355 | d????-?--*) different_mode=755;; 356 | *) false;; 357 | esac && 358 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 359 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 360 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 361 | } 362 | } 363 | then posix_mkdir=: 364 | fi 365 | rmdir "$tmpdir/d" "$tmpdir" 366 | else 367 | # Remove any dirs left behind by ancient mkdir implementations. 368 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 369 | fi 370 | trap '' 0;; 371 | esac;; 372 | esac 373 | 374 | if 375 | $posix_mkdir && ( 376 | umask $mkdir_umask && 377 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 378 | ) 379 | then : 380 | else 381 | 382 | # The umask is ridiculous, or mkdir does not conform to POSIX, 383 | # or it failed possibly due to a race condition. Create the 384 | # directory the slow way, step by step, checking for races as we go. 385 | 386 | case $dstdir in 387 | /*) prefix='/';; 388 | -*) prefix='./';; 389 | *) prefix='';; 390 | esac 391 | 392 | eval "$initialize_posix_glob" 393 | 394 | oIFS=$IFS 395 | IFS=/ 396 | $posix_glob set -f 397 | set fnord $dstdir 398 | shift 399 | $posix_glob set +f 400 | IFS=$oIFS 401 | 402 | prefixes= 403 | 404 | for d 405 | do 406 | test -z "$d" && continue 407 | 408 | prefix=$prefix$d 409 | if test -d "$prefix"; then 410 | prefixes= 411 | else 412 | if $posix_mkdir; then 413 | (umask=$mkdir_umask && 414 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 415 | # Don't fail if two instances are running concurrently. 416 | test -d "$prefix" || exit 1 417 | else 418 | case $prefix in 419 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 420 | *) qprefix=$prefix;; 421 | esac 422 | prefixes="$prefixes '$qprefix'" 423 | fi 424 | fi 425 | prefix=$prefix/ 426 | done 427 | 428 | if test -n "$prefixes"; then 429 | # Don't fail if two instances are running concurrently. 430 | (umask $mkdir_umask && 431 | eval "\$doit_exec \$mkdirprog $prefixes") || 432 | test -d "$dstdir" || exit 1 433 | obsolete_mkdir_used=true 434 | fi 435 | fi 436 | fi 437 | 438 | if test -n "$dir_arg"; then 439 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 440 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 441 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 442 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 443 | else 444 | 445 | # Make a couple of temp file names in the proper directory. 446 | dsttmp=$dstdir/_inst.$$_ 447 | rmtmp=$dstdir/_rm.$$_ 448 | 449 | # Trap to clean up those temp files at exit. 450 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 451 | 452 | # Copy the file name to the temp name. 453 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 454 | 455 | # and set any options; do chmod last to preserve setuid bits. 456 | # 457 | # If any of these fail, we abort the whole thing. If we want to 458 | # ignore errors from any of these, just make sure not to ignore 459 | # errors from the above "$doit $cpprog $src $dsttmp" command. 460 | # 461 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 462 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 463 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 464 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 465 | 466 | # If -C, don't bother to copy if it wouldn't change the file. 467 | if $copy_on_change && 468 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 469 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 470 | 471 | eval "$initialize_posix_glob" && 472 | $posix_glob set -f && 473 | set X $old && old=:$2:$4:$5:$6 && 474 | set X $new && new=:$2:$4:$5:$6 && 475 | $posix_glob set +f && 476 | 477 | test "$old" = "$new" && 478 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 479 | then 480 | rm -f "$dsttmp" 481 | else 482 | # Rename the file to the real destination. 483 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 484 | 485 | # The rename failed, perhaps because mv can't rename something else 486 | # to itself, or perhaps because mv is so ancient that it does not 487 | # support -f. 488 | { 489 | # Now remove or move aside any old file at destination location. 490 | # We try this two ways since rm can't unlink itself on some 491 | # systems and the destination file might be busy for other 492 | # reasons. In this case, the final cleanup might fail but the new 493 | # file should still install successfully. 494 | { 495 | test ! -f "$dst" || 496 | $doit $rmcmd -f "$dst" 2>/dev/null || 497 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 498 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 499 | } || 500 | { echo "$0: cannot unlink or rename $dst" >&2 501 | (exit 1); exit 1 502 | } 503 | } && 504 | 505 | # Now rename the file to the real destination. 506 | $doit $mvcmd "$dsttmp" "$dst" 507 | } 508 | fi || exit 1 509 | 510 | trap '' 0 511 | fi 512 | done 513 | 514 | # Local variables: 515 | # eval: (add-hook 'write-file-hooks 'time-stamp) 516 | # time-stamp-start: "scriptversion=" 517 | # time-stamp-format: "%:y-%02m-%02d.%02H" 518 | # time-stamp-time-zone: "UTC" 519 | # time-stamp-end: "; # UTC" 520 | # End: 521 | -------------------------------------------------------------------------------- /report/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pdflatex tiptop-report.tex 3 | bibtex tiptop-report 4 | pdflatex tiptop-report.tex 5 | pdflatex tiptop-report.tex 6 | 7 | clean: 8 | rm -f *.log 9 | rm -f *.aux 10 | rm -f tiptop-report.pdf 11 | -------------------------------------------------------------------------------- /report/conclusion.tex: -------------------------------------------------------------------------------- 1 | \section{Future Work} 2 | \label{sec:conclusion} 3 | Tiptop is a useful application, and our extensions further enhance its utility. 4 | However, aside from the unresolved bug, there are four major points that require further investigation. 5 | 6 | First, our solution to the ``Too many open file descriptors bug" is unfortunately not comprehensive. On systems that have more than 819 processes and a hard file descriptor limit of 4096, this will still be an issue. 7 | We do not believe that it is reasonable to require superuser permissions to solve this problem. 8 | %We see two possible solutions to this. 9 | Therefore, as one solution, it may be possible to develop a heuristic algorithm that only opens a file descriptor for processes of interest. 10 | As an example the algorithm can create a hardware counter (i.e., open a file descriptor) for any process that has used the CPU in the last $N$ seconds. 11 | Of course, this will require process monitoring that does not use hardware performance counters. 12 | However, we believe that the overhead of such a strategy is justified, in order to minimize the probability of this bug occurring. 13 | %Alternatively, we have not fully investigated the opportunities that PAPI may present in mitigating this problem. 14 | 15 | Second, we found that tiptop is not well-supported in virtualized environments. 16 | The man page briefly mentions this, but does not elaborate further. 17 | Our testing confirms that data is often omitted or not reported correctly in VM instances. 18 | We believe this requires further investigation to understand why this is the case. 19 | Certainly, for testing purposes, the ability to test tiptop without requiring physical hardware would greatly increase the ability to verify that features are correctly implemented across CPU architectures. 20 | 21 | Third, further investigation is require to understand if tiptop needs superuser access. 22 | The PAPI library requires superuser permission to operate properly, and current bugs in the mainline version of tiptop can be resolved by running tiptop as a super user, too. 23 | An understanding of these issues and a step towards a fully-featured non-superuser tiptop would be ideal. 24 | 25 | Finally, our integration with PAPI opens tiptop to a much wider range of architectures and kernel versions. The tiptop application would benefit from a more robust testing framework that is able to automatically validate the correctness of performance counters. 26 | As an example, it may be possible to create a suite low-level assembly programs that execute a deterministic number of instructions. 27 | Then, this testing framework should be deployed and executed on a wide variety of configurations, in order to test the extensibility of tiptop. 28 | Unfortunately, building such a testing framework was beyond the scope of this project, but would be an ideal next step to validate the statistics reported by tiptop. -------------------------------------------------------------------------------- /report/introduction.tex: -------------------------------------------------------------------------------- 1 | \section{Introduction} 2 | Hardware performance counters are architecture-specific special-purpose registers integrated into modern central processing units (CPUs) and used for performance profiling. 3 | As an example, modern Intel processors support hardware counters that report events such as CPU utilization, L1 cache misses, branch mispredictions and a host of other CPU-specific performance indicators. 4 | This information is invaluable when profiling low-level software performance. 5 | What is more, compared to traditional software-based profiling, hardware performance counters incur negligible overhead because they are integrated into the hardware. 6 | However, support for hardware counters is still in early stages, and was not integrated into the Linux kernel until the 2.6.31 release. 7 | In addition, some architectures support hardware counters, but have a hard limit on the number of events, sometimes only two or four, that can be monitored at a time. 8 | 9 | Tiptop~\cite{rohou:hal-00639173} is an application developed by Erven Rohou\footnote{\texttt{erven.rohou@inria.fr}} and is an attempt towards an intuitive interface for accessing hardware performance counters in modern CPUs. 10 | The interface for tiptop is similar to the popular top\footnote{\texttt{\url{http://sourceforge.net/projects/unixtop/}}} utility. 11 | In tiptop's default configuration, it provides real-time per-process hardware counter statistics, such as the number of CPU instructions executed per-process. 12 | The values that appear on the real-time screen are configurable by the user. 13 | Through use of an XML file, multiple screens can be configured and flipped through in real-time. 14 | In Figure~\ref{fig:tiptop-default} we have a screenshot of tiptop's default screen, and highlight a few of its key features. 15 | 16 | Despite tiptop's advantages, we identified a number of limitations. 17 | As one example, the Pentium III supports 80 hardware counter events, but can track at most two in parallel~\cite{hpc-trusted}. 18 | However, the default tiptop screen assumes that the underlying architecture can track five hardware counter events. 19 | In addition, we found that building XML files for tiptop was cumbersome and required platform-specific knowledge. 20 | To compound this problem, tiptop exposes less than 20\% of the hardware performance counters available across platforms. 21 | In many cases, tracking a hardware counter not currently supported by tiptop requires modification and recompilation of tiptop's C source files. 22 | 23 | In light of these limitations, we identified two feature enhancements for tiptop. 24 | First, we enhanced tiptop to display the number of threads per-process as a default feature. 25 | Then, as a substantial feature enhancement, we integrated the cross-platform Performance Application Programming Interface (PAPI)~\cite{Mucci99papi:a} library into tiptop as an alternative API to access hardware counters. (This is backwards-compatible change, and use of the PAPI API is optional when creating an XML configuration file.) 26 | Integration with PAPI increases the breadth of platforms and kernel versions supported by tiptop. 27 | Now, tiptop can run with kernel versions prior to 2.6.31, via a PAPI-supplied kernel patch. 28 | In addition, through software multiplexing, PAPI enables the number of hardware counter events to exceed the hard limit imposed by the hardware. 29 | Finally, the integration with PAPI simplifies the process of creating cross-platform XML configuration files through use of cross-platform PAPI-specific macros, by abstracting architecture-specific configuration parameters from the user. 30 | 31 | In addition to feature enhancements, we encountered and identified two tiptop bugs, and confirmed them through personal communications with lead developer Erven Rohou. 32 | Both bugs prevent tiptop from correctly displaying hardware counter statistics under specific conditions. 33 | For the first bug, we identified a solution that minimizes the probability that the bug occurs, and will work with Erven Rohou to include our patch into the main branch of the tiptop source. 34 | The second bug remains unresolved, but can be avoided by running tiptop as a superuser. 35 | 36 | In section~\ref{sec:methodology} we give an overview of our high-level development cycle and the tools we used to repair and enhance tiptop. 37 | In section~\ref{sec:results} we give further details about our feature enhancements and bugfixes. 38 | We conclude in section~\ref{sec:conclusion} with a discussion about additional feature improvements for future versions of tiptop. 39 | 40 | \begin{figure}[t] 41 | \footnotesize 42 | \centering 43 | \includegraphics[width=1\textwidth]{tiptop-default} 44 | %\hspace{.1in} 45 | %\includegraphics[width=0.48\textwidth]{tiptop-default-screenshot-1} 46 | \caption{\footnotesize A screenshot of the default screen for tiptop version 2.1. Each row in the display represents a single process. 47 | In the top-left corner we have the number of running and displayed processes. 48 | By default, tiptop only displays processes that have non-zero CPU utilization. 49 | In the bottom-left we highlight the CPU utilization, reported as percentage of cycles used since the last screen refresh. 50 | In the bottom-right corner we highlight the number of branch mispredictions. 51 | Finally, in the top-right we highlight the label for the current screen. 52 | Multiple views with custom columns can be configured and flipped through (using the right and left arrow keys) in real-time.} 53 | \label{fig:tiptop-default} 54 | \end{figure} -------------------------------------------------------------------------------- /report/methodology.tex: -------------------------------------------------------------------------------- 1 | \section{Methodology} 2 | \label{sec:methodology} 3 | In our development we started with tiptop version 2.1, which (optionally) depends upon the libxml2\footnote{\texttt{\url{http://www.xmlsoft.org/}}} and ncurses\footnote{\texttt{\url{http://www.gnu.org/software/ncurses/}}} libraries. 4 | Tiptop is written in C~\cite{Kernighan:1988:CPL:576122} and all our improvements and bugfixes were implemented in C, too. 5 | As a key feature enhancement, we integrated the PAPI~\cite{Mucci99papi:a} library into tiptop. 6 | In our testing we used Python\footnote{\texttt{\url{http://www.python.org/}}} and C to automate the process of verifying bug fixes and feature enhancements. 7 | 8 | Fortunately, tiptop has an integral feature called \emph{batch mode}, which enables tiptop to output statistics to stdout, rather than the default real-time display. 9 | The batch mode feature greatly simplified the testing process and enabled us to easily extract process statistics from tiptop. 10 | 11 | Roughly, we can describe our methodology as a three-step process. 12 | \begin{enumerate} 13 | \item Identify feature or bug. 14 | \item Develop code to enhance or fix tiptop. 15 | \item Use Python (and sometimes C) to develop unit tests that execute tiptop, then parse and verify the output, and ensure that the enhancement produces expected output, or the bug is resolved. 16 | \end{enumerate} 17 | 18 | In many cases we face the challenge of knowing what the ``correct" statistics are for an application. As an example, we are not aware of a trivial way to know the correct value for the number of threads for a Chrome browser process. 19 | In such cases we constructed applications with known values, such as a simple C program that spawns $N$ threads, and verified that tiptop reported the values correctly for our simple, and deterministic, application. -------------------------------------------------------------------------------- /report/results.tex: -------------------------------------------------------------------------------- 1 | \section{Results} 2 | \label{sec:results} 3 | In this section we start with an overview of our feature enhancements. Then, we follow with a discussion of the bugs we identified in tiptop. 4 | 5 | \subsection{Feature Enhancements} 6 | Roughly, we enhanced tiptop with two new features. 7 | First, we enhanced the default screen to include the number of threads per process. 8 | Then, we added support for tiptop to use the cross-platform Performance Application Programming Interface (PAPI)~\cite{Mucci99papi:a} library, which enables a new, and more robust way, for tiptop to access performance counters. 9 | We will discuss each of these feature in turn. 10 | 11 | \subsubsection{Thread count on main screen} 12 | The primary focus for tiptop is to enable a user to view hardware counters in real-time. 13 | However, there are other variables that can indirectly influence hardware performance. 14 | As an example, say a developer wants to investigate the effect of inter-thread cache contention on the performance of their application. 15 | Especially in cases when the number of threads in a process is not deterministic, it would be valuable to have the thread count on the tiptop screen. 16 | Therefore, we enabled tiptop to display the number of threads per process, and we included this feature on the default screen. 17 | 18 | In our implementation we added hooks to the XML configuration logic to enable the ability to display the number of threads per process. 19 | This involved adding code at multiple layers, including a call that exposed thread count from tiptops's data-gathering layer to the layer that handles presentation logic. 20 | In addition, tiptop has multiple modes, which influence the filter that is applied to the processes/threads to be displayed. 21 | As an example, tiptop can be run with the \texttt{-H} flag, in order to show per-thread information, rather than per-process. 22 | In such a case we do not want to display thread count, and our implementation includes logic such that thread count only appears in the case when we filter by processes. 23 | 24 | In the testing of this feature we did the following, using Python and C. 25 | \begin{enumerate} 26 | \item Execute a C program that spawns $N$ threads. 27 | \item Start tiptop in batch mode. 28 | \item Execute tiptop, parse the output and verify that tiptop displays $N$ threads for the long-running C process. 29 | \end{enumerate} 30 | 31 | Our tests passed on Ubuntu 12.04 executing a simple C program that invokes threads through the pthreads library, for values $N\in\{1,10,100\}$. 32 | In Figure~\ref{fig:tiptop-threads} we have a screenshot of the enhanced default screen with the thread-count column, \texttt{\#TH}, highlighted. 33 | 34 | The implementation and testing of this feature was relatively straightforward, and was an excellent introduction to hardware counters and the structure of the tiptop source code. 35 | 36 | \begin{figure}[t] 37 | \footnotesize 38 | \centering 39 | \includegraphics[width=.7\textwidth]{tiptop-threads} 40 | %\hspace{.1in} 41 | %\includegraphics[width=0.48\textwidth]{tiptop-default-screenshot-1} 42 | \caption{\footnotesize A screenshot of the enhanced tiptop homescreen, showing the number of threads in each process.} 43 | \label{fig:tiptop-threads} 44 | \end{figure} 45 | 46 | \subsubsection{Integration with the PAPI library} 47 | \begin{figure}[t] 48 | \footnotesize 49 | \centering 50 | \includegraphics[width=.7\textwidth]{tiptop-papi} 51 | %\hspace{.1in} 52 | %\includegraphics[width=0.48\textwidth]{tiptop-default-screenshot-1} 53 | \caption{\footnotesize The tiptop home screen implemented using the PAPI API. One side effect of using PAPI is that zero-values appear as \texttt{-} on the tiptop output. This was an inadvertent side-effect, but makes the screen more readable.} 54 | \label{fig:tiptop-papi} 55 | \end{figure} 56 | 57 | As our next feature for tiptop, we integrated support for the Performance Application Programming Interface (PAPI) library. 58 | The PAPI library is a cross-platform API for accessing hardware performance counters. 59 | Roughly, it is a interface that removes the complexity involved in accessing hardware performance counters across a range of architectures. 60 | 61 | Consider the following concrete example for why integration with PAPI enhances tiptop. 62 | The man page for tiptop gives the following example for a way to manually specify a counter that records the number of issued mico-ops on Sandy Bridge: 63 | \begin{verbatim} 64 | 69 | \end{verbatim} 70 | Then we must construct the column on the tiptop screen, too, which references the \texttt{uops\_issued} counter: 71 | \begin{verbatim} 72 | 75 | \end{verbatim} 76 | The values for \texttt{config} and \texttt{model} in the \texttt{counter} tag are hardware-specific, and require that the user identifies the appropriate values in architecture-specific documentation in order to implement an alias, which can then be used to construct a column in a custom tiptop screen. 77 | Indeed, it is less than ideal that a user must specify magic numbers for their CPU. 78 | What is more, this is not portable, an alias for \texttt{uops\_issued} on a different platform will require different \texttt{config} and \texttt{model} values. 79 | This is certainly a nightmare when developing a tiptop screen that may be used across multiple platforms. 80 | 81 | Fortunately, PAPI makes life much easier. 82 | Instead of having to specify a hardware-specific counter macro, then reference the macro for display, our new feature enables a user to specify the PAPI event directly. 83 | There are 103 counter events specified in PAPI 5.0.1, and our integration with PAPI enables a user specify the PAPI-defined macro. 84 | As an example, the following declaration would be able to integrate directly into the tiptop XML file to display the number of issued mico-ops on any architecture: 85 | \begin{verbatim} 86 | 89 | \end{verbatim} 90 | It is then up to PAPI to determine the correct hooks for a hardware counter, and the burden is not on the user to identify magic numbers. 91 | This is cross-platform, as far as PAPI supports the specific counter specified. 92 | Hence, the user does not have to specify a custom hardware-specific \texttt{counter} macro, and a single XML file can be specified and deployed across multiple system. 93 | In addition, this is backwards compatible with previous versions of tiptop configurations files, and the prefix \texttt{PAPI\_} for an \texttt{expr} attribute in a \texttt{column} tag, is a flag for tiptop to call PAPI, rather than using a direct kernel call for hardware counters. 94 | 95 | In addition to a cleaner interface for accessing hardware counters, PAPI implements multiplexing for hardware counters, which enables a user to specify more counters that are permitted by the hardware. 96 | As previously mentioned, if the underlying architecture is a Pentium III, tiptop is limited to two hardware counter events. 97 | Yet, the tiptop home screen requires that the underlying architecture supports five hardware counter events. 98 | However, PAPI implements multiplexing via high-precision timeslice sharing. This means that hardware counters are rotated, by default, every 100ms such that values can be obtained for all requested counters. 99 | If we, say, specify four hardware events to monitor, in a 200ms window PAPI would monitor two hardware events for the first 100ms, then rotate to monitor the other two hardware events for the remaining 100ms. 100 | 101 | Multiplexing does present limitations, if a user wanted to display a value such as instructions per second, this would require additional logic in order to know the amount of time that a specific counter was active. 102 | We will leave this edge-case as future work. 103 | 104 | As an additional feature, integration with PAPI enables tiptop to support a broader range of kernels. Currently, tiptop supports Linux kernels 2.6.31 and above. 105 | PAPI supports Linux kernels 2.6.31 and above out of the box, and supports kernels 2.6.30 and below with a kernel patch. 106 | Tiptop is not compatible with the PAPI patch for pre-2.6.31 kernels, and would require further modification to work for pre-2.6.31 kernels. 107 | Hence, the PAPI integretation enables a greater range of kernel support without further changes to tiptop. 108 | 109 | \begin{figure}[t] 110 | \footnotesize 111 | \centering 112 | \begin{tabular}{lrr} 113 | \toprule 114 | field & default expression & PAPI expression \\ 115 | \midrule 116 | Millions of cycles (Mcycle) & \texttt{delta(CYCLE) / 1000000} & \texttt{PAPI\_TOT\_CYC / 1000000} \\ 117 | Millions of instructions (Minstr) & \texttt{delta(INSN) / 1000000} & \texttt{PAPI\_TOT\_INS / 1000000} \\ 118 | Instructions per Cycle (IPC) & \texttt{delta(INSN) / delta(CYCLE)} & \texttt{PAPI\_TOT\_INS / PAPI\_TOT\_CYC} \\ 119 | Instruction cache miss \% (\%MISS) & \texttt{100 * delta(MISS) / delta(INSN)} & \texttt{100 * PAPI\_L1\_ICM / PAPI\_TOT\_INS} \\ 120 | Branch misprediction \% (\%BMIS) & \texttt{100 * delta(BR) / delta(INSN)} & \texttt{100 * PAPI\_BR\_MSP / PAPI\_TOT\_INS} \\ 121 | \bottomrule 122 | \end{tabular} 123 | \caption{\footnotesize The expression changes required in the tiptop XML configuration file in order to use PAPI, instead of the default direct call to the Linux kernel. The previous expression still work, and the new PAPI macros simply extend the range of hardware counters that can be accessed from tiptop.} 124 | \label{fig:tiptop-papi-expressions} 125 | \end{figure} 126 | 127 | \paragraph{Challenges in integrating PAPI with tiptop.} 128 | When integrating PAPI with tiptop, we encountered a number of challenges. 129 | First, PAPI's documentation was nearly non-existent when describing its ability to multiplex and monitor external processes. 130 | A correct implementation required extensive reading and searching through the PAPI mailing lists. 131 | In addition, understanding tiptop's workflow and the correct PAPI functions to call to release the hardware counters at the correct times took some effort, too. 132 | 133 | \paragraph{Case Study: Building the tiptop default home screen with PAPI.} 134 | In order to demonstrate the flexibility of our PAPI integration and its correctness, we implement the default tiptop screen using PAPI, instead of tiptop's default behavior of using direct kernel calls. 135 | In Figure~\ref{fig:tiptop-papi} we have a screenshot of the tiptop homescreen, implemented by building an XML file that references PAPI macros. 136 | We first notice that the top of the screen the \texttt{[conf]} flag, which indicates that the tiptop screen is specified by the an XML configuration file. 137 | 138 | In Figure \ref{fig:tiptop-papi-expressions} we have a listing of the current tiptop expression used to build the default screen, and the alternative expression that can now be used to access counter via PAPI. These expressions can be mixed and matched within the same XML file. 139 | 140 | As an example of another benefit of PAPI exposed by building the home screen, the tiptop interface exposes \texttt{MISS} (Figure \ref{fig:tiptop-papi-expressions}, default expressions) as a direct call to the kernel macro \texttt{PERF\_COUNT\_HW\_CACHE\_MISSES}. 141 | Depending upon your kernel version, for \%MISS in Figure \ref{fig:tiptop-papi-expressions} with return either Level 1 or Level 2 instruction cache misses\footnote{\texttt{\url{https://lkml.org/lkml/2010/11/1/131}}}. However, it is clear from the PAPI macro that we are returning the Level 1 instruction cache miss. If we, say, wanted to report Level 2 instruction cache misses instead, we simply replace \texttt{PAPI\_L1\_ICM} with \texttt{PAPI\_L2\_ICM}. 142 | Alternatively, if we wanted, instead, the Level 3 data cache miss, we could use the macro \texttt{PAPI\_L3\_DCM}. 143 | The flexibility, clarity, and robustness of using PAPI macros are already clear in this simple example of recreating the tiptop homescreen. 144 | 145 | \subsection{Bug Fixes} 146 | In our initial attempt to understand tiptop and its range of features we encountered an anomaly. 147 | In some cases a question mark would appear, instead of a value from the hardware performance counter. 148 | This would happen consistently for programs such as the Chrome\footnote{\texttt{\url{http://www.google.come/chrome}}} web browser, and would happen sporadically for other applications. 149 | In Figure~\ref{fig:tiptop-bug} we have a screenshot that highlights this bug. 150 | Upon investigation, we identified two separate issues that lead to this error condition. 151 | \begin{figure}[t] 152 | \footnotesize 153 | \centering 154 | \includegraphics[width=.9\textwidth]{tiptop-bug} 155 | %\hspace{.1in} 156 | %\includegraphics[width=0.48\textwidth]{tiptop-default-screenshot-1} 157 | \caption{\footnotesize A screenshot of the manifestation of the two bugs identified in our development. When tiptop is unable to determine the values associated with a process it ouputs a question mark instead. As we can see, tiptop failed to gather statistics for three of the four Chrome processes in the above screenshot, at the bottom of the screen, in the red box, tiptop reports that \texttt{[errors]} occurred.} 158 | \label{fig:tiptop-bug} 159 | \end{figure} 160 | 161 | \paragraph{Bug 1: Too many open file descriptors.} 162 | First, a bit of background. Linux systems include a \texttt{limits.conf} file which enables a systems administrator to have fine-grained control over the system resources used by users and groups. 163 | As an example, it is possible to specify the maximum priority of a process run by a specific user or group, or even the maximum number of processes spawned by a specific user or group. Each resource has a \emph{hard} and \emph{soft} limit. Hard limits are enforced by the kernel and can only be modified by superusers. Soft limits are default values and can be manually raised per-user, up to the hard limit. 164 | For example, Ubuntu 12.04 has a soft limit of 1024 open file descriptors per user, and a hard limit of 4096. 165 | This means that a regular user can open up to 1024 file descriptors under normal circumstances, or can open up to 4096 file descriptors by explicitly requesting (to the kernel) for the soft limit to be increased to 4096. 166 | 167 | In order to read hardware counters, tiptop opens five counters per process in its default configuration. 168 | For each combination of process and hardware counter, a file descriptor is opened. 169 | As we can can see in the screenshot for Figure~\ref{fig:tiptop-bug}, my desktop had 332 running processes. 170 | Hence, we now have a problem. 171 | We have 332 processes, five hardware counters per process, so we have exceeded our soft limit for the number of file handlers open by requesting to open $332\cdot 5 = 1660$ file descriptors. 172 | 173 | As a stopgap solution to this problem, we explicitly request for our soft file descriptor limit to be increased to the hard limit. This may be performed by fetching the hard limit from \texttt{/proc/N/limits}, then making a call to the \texttt{setrlimit} function, which is provided by \texttt{sys/resource.h}. 174 | Unfortunately, increasing the open file descriptor limit beyond the hard limit requires superuser permission. 175 | Our solution, raising the soft limit to the hard limit, is consistent with other open source project that have encountered this issue, such as Wine\footnote{\texttt{\url{https://bugs.launchpad.net/ubuntu/+source/linux/+bug/663090}}}. 176 | A more robust solution for this bug is an open problem and would require fundamental changes to the design of tiptop, we talk about possible solutions in section~\ref{sec:conclusion}. 177 | 178 | The testing for this was not straightforward due to a different bug, which we will discuss next. 179 | In order to verify our fix for this bug we ran tiptop as root, with root having a hard number of file descriptor set to 4096 and soft set to 1024. (By default, root has a soft limit of 4096 and hard limit of 8192 on Ubuntu 12.04.) 180 | We may then run the version of tiptop that uses the soft limit and we get the following output. 181 | \begin{verbatim} 182 | 19884+ 4.6 0.0 0 ? ? ? ? ? ? chrome 183 | ... 184 | 19818+ 0.5 0.5 0 ? ? ? ? ? ? firefox 185 | \end{verbatim} 186 | 187 | Simultaneously, we run the enhanced version of tiptop that explicitly requests a file descriptor limit to be raised to the hard limit, and we get the following output. 188 | \begin{verbatim} 189 | 19884+ 4.3 0.0 0 19327.35 19327.35 1.00 0.00 0.00 0.0 chrome 190 | ... 191 | 19818+ 0.5 0.5 0 8589.93 8589.93 1.00 0.00 0.00 0.0 firefox 192 | \end{verbatim} 193 | 194 | We verify by that this bug is solved by checking that no value in the tiptop output has a question mark. A more robust testing strategy will require an enhanced error reporting layer for tiptop, which distinguishes between different types of hardware counter read failures. However, an enhanced error reporting layer is beyond the scope of this project. 195 | 196 | \paragraph{Bug 2: \texttt{EACCES}, permission denied.} 197 | A second cause of ``questions marks" in the tiptop output has been traced to an \texttt{EACCES} permission denied error returned by the kernel, and is isolated to only a few applications, such as Chrome and the gnome-keyring-daemon, to name a few. 198 | This condition only occurs when running tiptop as a regular user. 199 | We contacted the lead developer of tiptop, Erven Rohou, in order to determine the cause of this problem. 200 | This was an unknown bug, but it can be avoided by running tiptop as root. 201 | Unfortunately, we have no further progress towards a solution to this bug. -------------------------------------------------------------------------------- /report/tiptop-bug.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeCastle/tiptop/529886d445ec32febad14246245372a8f244b3eb/report/tiptop-bug.pdf -------------------------------------------------------------------------------- /report/tiptop-default.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeCastle/tiptop/529886d445ec32febad14246245372a8f244b3eb/report/tiptop-default.pdf -------------------------------------------------------------------------------- /report/tiptop-papi.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeCastle/tiptop/529886d445ec32febad14246245372a8f244b3eb/report/tiptop-papi.pdf -------------------------------------------------------------------------------- /report/tiptop-report.bib: -------------------------------------------------------------------------------- 1 | %% hal-00639173, version 1 2 | %% http://hal.inria.fr/hal-00639173 3 | @techreport{rohou:hal-00639173, 4 | hal_id = {hal-00639173}, 5 | url = {http://hal.inria.fr/hal-00639173}, 6 | title = {{Tiptop: Hardware Performance Counters for the Masses}}, 7 | author = {Rohou, Erven}, 8 | abstract = {{Hardware performance monitoring counters have recently received a lot of attention. They have been used by diverse communities to understand and improve the quality of computing systems: for example, architects use them to extract application characteristics and propose new hardware mechanisms; compiler writers study how generated code behaves on particular hardware; software developers identify critical regions of their applications and evaluate design choices to select the best performing implementation. In this paper, we propose that counters be used by all categories of users, in particular non-experts, and we advocate that a few simple metrics derived from these counters are relevant and useful. For example, a low IPC (number of executed instructions per cycle) indicates that the hardware is not performing at its best; a high cache miss ratio can suggest several causes, such as conflicts between processes in a multicore environment. We also introduce a new simple and flexible user-level tool that collects these data on Linux platforms, and we illustrate its practical benefits through several use cases.}}, 9 | keywords = {performance; hardware counters; analysis tool}, 10 | language = {Anglais}, 11 | affiliation = {ALF - INRIA - IRISA}, 12 | pages = {23}, 13 | type = {Rapport de recherche}, 14 | institution = {INRIA}, 15 | number = {RR-7789}, 16 | year = {2011}, 17 | month = Nov, 18 | pdf = {http://hal.inria.fr/hal-00639173/PDF/RR-7789.pdf}, 19 | } 20 | 21 | @INPROCEEDINGS{Mucci99papi:a, 22 | author = {Philip J. Mucci and Shirley Browne and Christine Deane and George Ho}, 23 | title = {PAPI: A Portable Interface to Hardware Performance Counters}, 24 | booktitle = {In Proceedings of the Department of Defense HPCMP Users Group Conference}, 25 | year = {1999}, 26 | pages = {7--10} 27 | } 28 | 29 | @book{Kernighan:1988:CPL:576122, 30 | author = {Kernighan, Brian W.}, 31 | editor = {Ritchie, Dennis M.}, 32 | title = {The C Programming Language}, 33 | year = {1988}, 34 | isbn = {0131103709}, 35 | edition = {2nd}, 36 | publisher = {Prentice Hall Professional Technical Reference}, 37 | } 38 | 39 | @INPROCEEDINGS{hpc-trusted, 40 | author={Weaver, V.M. and McKee, S.A.}, 41 | booktitle={Workload Characterization, 2008. IISWC 2008. IEEE International Symposium on}, title={Can hardware performance counters be trusted?}, 42 | year={2008}, 43 | month={sept.}, 44 | volume={}, 45 | number={}, 46 | pages={141 -150}, 47 | keywords={SPEC CPU 2000;SPEC CPU 2006;SPEC benchmarks;architectural tools;dynamic binary instrumentation tools;hardware performance counters;computer architecture;}, 48 | doi={10.1109/IISWC.2008.4636099}, 49 | ISSN={} 50 | } -------------------------------------------------------------------------------- /report/tiptop-report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeCastle/tiptop/529886d445ec32febad14246245372a8f244b3eb/report/tiptop-report.pdf -------------------------------------------------------------------------------- /report/tiptop-report.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | 3 | \usepackage{graphicx} 4 | \usepackage{url} 5 | \usepackage{booktabs} 6 | \usepackage[margin=1in]{geometry} 7 | 8 | \title{CS533 Project Report: Tiptop} 9 | \author{Kevin Dyer and Paul Vu} 10 | 11 | \begin{document} 12 | \maketitle 13 | 14 | \input{introduction} 15 | \input{methodology} 16 | \input{results} 17 | \input{conclusion} 18 | 19 | \bibliographystyle{acm} 20 | \bibliography{tiptop-report} 21 | 22 | \end{document} -------------------------------------------------------------------------------- /report/tiptop-threads.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FeCastle/tiptop/529886d445ec32febad14246245372a8f244b3eb/report/tiptop-threads.pdf -------------------------------------------------------------------------------- /src/Makefile.in: -------------------------------------------------------------------------------- 1 | # @configure_input@ 2 | 3 | package = @PACKAGE_NAME@ 4 | version = @PACKAGE_VERSION@ 5 | tarname = @PACKAGE_TARNAME@ 6 | distdir = $(tarname)-$(version) 7 | 8 | prefix = @prefix@ 9 | exec_prefix = @exec_prefix@ 10 | bindir = @bindir@ 11 | datarootdir = @datarootdir@ 12 | mandir = @mandir@ 13 | man1dir = $(mandir)/man1 14 | 15 | # VPATH-specific substitution variables 16 | srcdir= @srcdir@ 17 | VPATH = @srcdir@ 18 | 19 | 20 | CC = @CC@ 21 | LIBS = @LIBS@ 22 | CFLAGS = @CFLAGS@ -I.. 23 | CPPFLAGS = @CPPFLAGS@ 24 | INSTALL = @INSTALL@ 25 | LEX = @LEX@ 26 | YACC = @YACC@ 27 | 28 | OBJS=tiptop.o pmc.o process.o requisite.o conf.o screen.o \ 29 | debug.o version.o helpwin.o options.o hash.o spawn.o \ 30 | xml-parser.o target.o utils-expression.o \ 31 | error.o lex.yy.o y.tab.o 32 | 33 | 34 | all: tiptop 35 | 36 | tiptop: $(OBJS) 37 | $(CC) -o tiptop $(OBJS) $(LIBS) 38 | rm -f ptiptop 39 | ln tiptop ptiptop 40 | 41 | 42 | Makefile: Makefile.in ../config.status 43 | cd .. && ./config.status src/$@ 44 | 45 | ../config.status: ../configure 46 | cd .. && ./config.status --recheck 47 | 48 | 49 | 50 | version.o: version.c 51 | $(CC) $(CFLAGS) -DCOMPILE_HOST="\""`hostname`"\"" \ 52 | -DCOMPILE_DATE="\"`date`\"" \ 53 | -c $(srcdir)/version.c 54 | 55 | 56 | lex.yy.c: calc.lex 57 | $(LEX) $(srcdir)/calc.lex 58 | 59 | lex.yy.o: lex.yy.c 60 | $(CC) $(CFLAGS) -I$(srcdir) -c lex.yy.c 61 | 62 | 63 | y.tab.c y.tab.h: calc.y 64 | $(YACC) -d $(srcdir)/calc.y 65 | 66 | y.tab.o: y.tab.c 67 | $(CC) $(CFLAGS) -I$(srcdir) -c y.tab.c 68 | 69 | install: 70 | $(INSTALL) -d $(DESTDIR)$(bindir) 71 | $(INSTALL) -m 0755 tiptop $(DESTDIR)$(bindir) 72 | $(INSTALL) -d $(DESTDIR)$(man1dir) 73 | $(INSTALL) -m 0644 tiptop.1 $(DESTDIR)$(man1dir) 74 | ln $(DESTDIR)$(bindir)/tiptop $(DESTDIR)$(bindir)/ptiptop 75 | 76 | uninstall: 77 | -rm $(DESTDIR)$(bindir)/tiptop 78 | -rm $(DESTDIR)$(bindir)/ptiptop 79 | -rm $(DESTDIR)$(man1dir)/tiptop.1 80 | 81 | clean: 82 | /bin/rm -f $(OBJS) lex.yy.c y.tab.c y.tab.h tiptop ptiptop 83 | 84 | 85 | depend: 86 | makedepend -Y *.c 87 | 88 | 89 | .PHONY: all clean depend install uninstall 90 | 91 | 92 | # DO NOT DELETE 93 | 94 | conf.o: conf.h options.h screen.h utils-expression.h 95 | conf.o: process.h xml-parser.h 96 | error.o: error.h 97 | 98 | hash.o: hash.h process.h screen.h options.h 99 | options.o: options.h version.h 100 | pmc.o: pmc.h 101 | process.o: error.h hash.h process.h screen.h options.h pmc.h 102 | process.o: spawn.h 103 | requisite.o: pmc.h requisite.h 104 | screen.o: conf.h options.h screen.h process.h 105 | screen.o: utils-expression.h error.h 106 | spawn.o: options.h process.h screen.h spawn.h 107 | target-x86.o: screen.h options.h target.h 108 | target.o: target.h 109 | tiptop.o: conf.h options.h screen.h debug.h error.h 110 | tiptop.o: helpwin.h pmc.h process.h requisite.h spawn.h utils-expression.h 111 | utils-expression.o: process.h screen.h options.h 112 | utils-expression.o: utils-expression.h y.tab.h 113 | version.o: version.h 114 | lex.yy.o: utils-expression.h y.tab.h 115 | y.tab.o: utils-expression.h formula-parser.h 116 | -------------------------------------------------------------------------------- /src/calc.lex: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of tiptop. 3 | * 4 | * Author: Antoine NAUDIN 5 | * Copyright (c) 2012 Inria 6 | * 7 | * License: GNU General Public License version 2. 8 | * 9 | */ 10 | 11 | %{ 12 | #include 13 | #include 14 | 15 | #include "formula-parser.h" 16 | #include "y.tab.h" 17 | 18 | 19 | /* Do not read from stdin, but from a string. my_yyinput takes care 20 | of filling in the buffer */ 21 | #undef YY_INPUT 22 | int my_yyinput(char*, int); 23 | #define YY_INPUT(t,r,m) (r = my_yyinput(t,m)) 24 | 25 | 26 | %} 27 | 28 | blank [ \t\n]+ 29 | 30 | letter [A-Za-z] 31 | 32 | base16 0x[0-9A-Fa-f]+ 33 | 34 | exponent [eE][+-]?[0-9]+ 35 | 36 | word [A-Za-z]([A-Za-z0-9]|_)* 37 | 38 | constant [0-9]+("."[0-9])?{exponent}?|{base16} 39 | 40 | %% 41 | 42 | 43 | {blank} { /* ignored */ } 44 | 45 | 46 | "delta" return DELTA; 47 | "and" return AND; 48 | "or" return OR; 49 | "shr" return SHR; 50 | "shl" return SHL; 51 | 52 | "|" return OR; 53 | "+" return ADD; 54 | "-" return SUB; 55 | 56 | "*" return MUL; 57 | "/" return DIV; 58 | 59 | "^" return POWER; 60 | 61 | "(" return B_LEFT; 62 | ")" return B_RIGHT; 63 | 64 | {base16} { 65 | yylval.txt = strdup(yytext); 66 | return BASE16; 67 | } 68 | 69 | {constant} { 70 | yylval.txt = strdup(yytext); 71 | return NUMBER; 72 | } 73 | 74 | {word} { 75 | yylval.txt = strdup(yytext); 76 | return COUNTER; 77 | } 78 | 79 | %% 80 | 81 | int yywrap(void) 82 | { 83 | return 1; 84 | } 85 | 86 | 87 | int yyerror(char *s) 88 | { 89 | printf("error: %s at '%s'\n", s, yytext); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /src/calc.y: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of tiptop. 3 | * 4 | * Author: Antoine NAUDIN 5 | * Copyright (c) 2012 Inria 6 | * 7 | * License: GNU General Public License version 2. 8 | * 9 | */ 10 | 11 | %{ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "error.h" 19 | #include "utils-expression.h" 20 | 21 | extern expression* res_expr; 22 | 23 | expression* build_node_operation(expression* exp1, expression* exp2, int opera); 24 | expression* build_node_counter(char* alias, int delta); 25 | expression* build_node_constant(char* txt); 26 | 27 | 28 | int yylex(); 29 | int yyerror(char *s); 30 | 31 | %} 32 | 33 | 34 | %union { 35 | expression* e; 36 | char* txt ; 37 | }; 38 | 39 | %token NUMBER 40 | %token COUNTER 41 | %token EXPOSANT 42 | %token BASE16 43 | 44 | %token ADD SUB MUL DIV 45 | %token OR AND SHR SHL 46 | %token B_LEFT B_RIGHT 47 | %token END 48 | %token DELTA 49 | 50 | %type Expression Line 51 | 52 | %left ADD SUB AND OR SHR SHL 53 | %left MUL DIV 54 | %right POWER 55 | 56 | %start Line 57 | %% 58 | 59 | Line: Expression { res_expr = $1; }; 60 | 61 | Expression: 62 | 63 | BASE16 { 64 | $$ = build_node_counter($1, 0); 65 | } 66 | | 67 | NUMBER { 68 | $$ = build_node_constant($1); 69 | } 70 | | DELTA B_LEFT COUNTER B_RIGHT { 71 | $$ = build_node_counter($3, DELT); 72 | } 73 | | COUNTER { 74 | $$ = build_node_counter($1, 0); 75 | } 76 | | Expression ADD Expression { 77 | $$ = build_node_operation($1,$3, '+'); 78 | } 79 | | Expression SUB Expression { 80 | $$ = build_node_operation($1,$3, '-'); 81 | } 82 | | Expression MUL Expression { 83 | $$ = build_node_operation($1,$3, '*'); 84 | } 85 | | Expression DIV Expression { 86 | $$ = build_node_operation($1,$3, '/'); 87 | } 88 | | Expression OR Expression { 89 | $$ = build_node_operation($1,$3, '|'); 90 | } 91 | | Expression AND Expression { 92 | $$ = build_node_operation($1,$3, '&'); 93 | } 94 | | Expression SHR Expression { 95 | $$ = build_node_operation($1,$3, '>'); 96 | } 97 | | Expression SHL Expression { 98 | $$ = build_node_operation($1,$3, '<'); 99 | } 100 | | B_LEFT Expression B_RIGHT { 101 | $$=$2; 102 | } 103 | 104 | %% 105 | 106 | 107 | expression* build_node_operation(expression* exp1, expression* exp2, int opera) 108 | { 109 | expression* tmp = alloc_expression(); 110 | tmp->type = OPER; 111 | tmp->op = alloc_operation(); 112 | tmp->op->exp1 = exp1; 113 | tmp->op->exp2 = exp2; 114 | tmp->op->operator = opera; 115 | return tmp; 116 | } 117 | 118 | 119 | expression* build_node_counter(char* alias, int delta) 120 | { 121 | expression* tmp = alloc_expression(); 122 | tmp->ele = alloc_unit(); 123 | tmp->ele->alias = alias; 124 | tmp->ele->type = COUNT; 125 | if (delta == DELT) { 126 | tmp->ele->delta = DELT; 127 | } 128 | tmp->type = ELEM; 129 | return tmp; 130 | } 131 | 132 | 133 | expression* build_node_constant(char* txt) 134 | { 135 | expression* tmp = alloc_expression(); 136 | tmp->ele = alloc_unit(); 137 | errno = 0; 138 | tmp->ele->val = strtod(txt, NULL); 139 | if (errno != 0) { 140 | error_printf("Error while reading float in '%s'.\n", txt); 141 | tmp->type = ERROR; 142 | } 143 | else { 144 | tmp->ele->type = CONST; 145 | tmp->type = ELEM; 146 | } 147 | free(txt); 148 | return tmp; 149 | } 150 | -------------------------------------------------------------------------------- /src/conf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of tiptop. 3 | * 4 | * Author: Erven ROHOU 5 | * Copyright (c) 2011, 2012 Inria 6 | * 7 | * License: GNU General Public License version 2. 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "config.h" 20 | #include "conf.h" 21 | #include "options.h" 22 | #include "utils-expression.h" 23 | #include "xml-parser.h" 24 | 25 | static const char* const config_file = ".tiptoprc"; 26 | 27 | /* Read configuration file. 28 | * 29 | * First check the path specified on the command line (if any), then 30 | * the TIPTOP environment variable, then the local directory, finally 31 | * $HOME. */ 32 | 33 | int read_config(char* path_conf_file, struct option* options) 34 | { 35 | #ifdef HAVE_LIBXML2 36 | char* path = NULL; 37 | char* file = NULL; 38 | int res; 39 | 40 | /* Check path with '-W' in tiptop options */ 41 | if (path_conf_file != NULL) { 42 | path = path_conf_file; 43 | } 44 | 45 | if (!path) { 46 | /* Check Env. Var. $TIPTOP */ 47 | path = getenv("TIPTOP"); 48 | } 49 | 50 | if (!path) { 51 | /* Check Current Folder */ 52 | if (access(config_file, R_OK) == 0) { 53 | path = "."; 54 | } 55 | } 56 | 57 | if (!path) { 58 | /* Check $HOME */ 59 | path = getenv("HOME"); 60 | } 61 | 62 | if (!path) 63 | return -1; 64 | 65 | file = malloc(strlen(path) + strlen(config_file) + 2); 66 | sprintf(file, "%s/%s", path, config_file); 67 | 68 | if (access(file, R_OK) == -1) { 69 | free(file); 70 | return -1; 71 | } 72 | 73 | res = parse_doc(file, options); 74 | free(file); 75 | return res; 76 | 77 | #else /* HAVE_LIBXML2 */ 78 | 79 | fprintf(stderr, "No xml support, cannot read config file.\n"); 80 | return -1; 81 | 82 | #endif /* !HAVE_LIBXML2 */ 83 | } 84 | 85 | 86 | static const char* const tok_opt_sta = "\t\t