├── .gitignore
├── AUTHORS
├── CODEOWNERS
├── COPYING
├── ChangeLog
├── Makefile.am
├── README.md
├── autogen.sh
├── build_pmwatch.sh
├── config
└── .gitignore
├── configure.ac
├── docs
├── PMWatch_User_Guide.docx
├── PMWatch_User_Guide.pdf
├── README
├── README_INSTALL
├── README_INSTALL.txt
└── esxi
│ ├── README
│ └── README_INSTALL
├── m4
└── .gitignore
├── package_pmwatch.sh
├── prepare_pmwatch_release.sh
├── scripts
├── esxi
│ ├── install-pmw
│ └── pmw_vars.sh
├── install-pmw
├── pmw_vars.cmd
└── pmw_vars.sh
└── src
├── .gitignore
├── esxi
└── pmwatch-stop
├── inc
├── pmw_api.h
├── pmw_collect.h
├── pmw_comm.h
├── pmw_struct.h
├── pmw_utils.h
└── pmw_version.h
├── pmw_api.c
├── pmw_collect.c
├── pmw_comm.c
├── pmw_utils.c
├── pmwatch-stop
└── pmwatch.c
/.gitignore:
--------------------------------------------------------------------------------
1 | INSTALL
2 | .deps/
3 | .libs/
4 | Makefile
5 | Makefile.in
6 | aclocal.m4
7 | autom4te.cache/
8 | bin64/
9 | config.log
10 | config.status
11 | configure
12 | libtool
13 | pmwatch
14 | *.la
15 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intel/intel-pmwatch/a19838bef7b6a269553b4206ecd531a781880fea/AUTHORS
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * hari.tg@intel.com
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intel/intel-pmwatch/a19838bef7b6a269553b4206ecd531a781880fea/ChangeLog
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | ACLOCAL_AMFLAGS = -I m4
2 | AM_CFLAGS = $(PROJECT_CFLAGS) \
3 | $(KMOD_CFLAGS) \
4 | $(UDEV_CFLAGS) \
5 | $(UUID_CFLAGS)
6 | EXTRA_DIST = autogen.sh
7 | AUTOMAKE_OPTIONS = subdir-objects foreign
8 |
9 | if BUILD_PMWATCH
10 | lib_LTLIBRARIES = libpmwcollect.la libpmwapi.la
11 | libpmwcollect_la_SOURCES = src/pmw_collect.c src/pmw_comm.c src/pmw_utils.c
12 | libpmwcollect_la_LDFLAGS = $(BUILD_WITH_LIBIPMCTL_LDFLAGS)
13 | if BUILD_ESXI
14 | libpmwcollect_la_LIBADD = -lipmctl -lvmkuser -lpthread
15 | libpmwcollect_la_CFLAGS = ${NEW_CFLAGS} $(AM_CFLAGS) -DBUILD_ESXI $(BUILD_WITH_LIBIPMCTL_CFLAGS)
16 | else
17 | libpmwcollect_la_LIBADD = -lipmctl -lpthread
18 | libpmwcollect_la_CFLAGS = ${NEW_CFLAGS} $(AM_CFLAGS) $(BUILD_WITH_LIBIPMCTL_CFLAGS)
19 | endif
20 | libpmwapi_la_SOURCES = src/pmw_api.c
21 | libpmwapi_la_LIBADD = -L./.libs libpmwcollect.la
22 | libpmwapi_la_CFLAGS = ${NEW_CFLAGS} $(AM_CFLAGS) $(BUILD_WITH_LIBIPMCTL_CFLAGS)
23 |
24 | include_HEADERS = src/inc/pmw_api.h src/inc/pmw_struct.h
25 |
26 | dist_bin_SCRIPTS = src/pmwatch-stop
27 |
28 | bin_PROGRAMS = pmwatch
29 | pmwatch_SOURCES = src/pmwatch.c
30 | pmwatch_LDFLAGS = -static
31 | pmwatch_CFLAGS = ${NEW_CFLAGS} $(AM_CFLAGS) $(BUILD_WITH_LIBIPMCTL_CFLAGS)
32 | if BUILD_ESXI
33 | pmwatch_LDADD = $(lib_LTLIBRARIES)
34 | else
35 | pmwatch_LDADD = $(lib_LTLIBRARIES) $(UUID_LIBS) $(KMOD_LIBS) $(UDEV_LIBS)
36 | endif
37 | endif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DISCONTINUATION OF PROJECT
2 |
3 | This project will no longer be maintained by Intel.
4 |
5 | Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project.
6 |
7 | Intel no longer accepts patches to this project.
8 |
9 | If you have an ongoing need to use this project, are interested in independently developing it, or would like to maintain patches for the open source software community, please create your own fork of this project.
10 |
11 | Contact: webadmin@linux.intel.com
12 | # Intel® PMWatch
13 | Intel® PMWatch (PersistentMemoryWatch) is a tool that monitors and reports the performance and health information metrics of the Intel® Optane™ DC Persistent Memory.
14 |
15 | # Supported OS
16 | Linux
17 |
18 | # Supported Platforms
19 | Any Intel® platform with Intel® Optane™ DC Persistent Memory.
20 |
21 | # Documentation
22 | The information about features and options available in the tool can be found at [PMWatch_User_Guide.pdf](https://github.com/intel/intel-pmwatch/blob/master/docs/PMWatch_User_Guide.pdf).
23 |
24 | # Build
25 | **Check *[Dependencies](#dependencies)* section to resolve the dependencies.**
26 |
27 | > $ ./autogen.sh
28 | > $ ./configure [--with-libipmctl=\ --with-libipmctl-inc=\ --prefix=\$HOME/pmwatch --bindir=\$HOME/pmwatch/bin64 --libdir=\$HOME/pmwatch/lib64]
29 | > $ make
30 | > $ make -j install
31 |
32 | The parameters for configure are optional.
33 | **If you are building PMWatch for [collectd (dcpmm plugin)](https://github.com/collectd/collectd) dependency, make sure to use `--libdir=/lib64`.**
34 |
35 | ## Using scripts to build and create install package
36 | You can *also* use the scripts available for build and package creation.
37 |
38 | > $ ./prepare_pmwatch_release.sh M= m= u= with-libipmctl= with-libipmctl-inc= os=linux -r
39 |
40 | Check *[pmw_version.h](https://github.com/intel/intel-pmwatch/blob/master/src/inc/pmw_version.h)* to obtain major, minor version and update number.
41 |
42 | ### Build
43 | Standalone build script.
44 |
45 | > $ ./build_pmwatch.sh -all with-libipmctl= with-libipmctl-inc= os=linux
46 |
47 | ### Package
48 | Standalone packaging script.
49 |
50 | > $ ./package_pmwatch.sh M= m= u= os=linux -r
51 |
52 | Use the `-h` option to get more details about the [scripts'](https://github.com/intel/intel-pmwatch/) options.
53 |
54 | ## Dependencies
55 | PMWatch is dependent on [libipmctl](https://github.com/intel/ipmctl).
56 |
57 | Perform the following steps to install the tool dependencies.
58 |
59 | #### Fedora
60 | > $ yum install daxctl-devel.x86_64 ndctl-devel.x86_64 libipmctl-devel.x86_64
61 |
62 | #### CentOS, RHEL
63 | > $ wget https://copr-be.cloud.fedoraproject.org/results/jhli/ipmctl/epel-7-x86_64/00874029-ipmctl/libipmctl-devel-02.00.00.3446-1.el7.x86_64.rpm
64 | > $ yum install ndctl-libs.x86_64
65 | > $ rpm -ivh libipmctl-devel-02.00.00.3446-1.el7.x86_64.rpm
66 |
67 | #### Ubuntu, Debian
68 | > $ apt install libdaxctl-dev libndctl-dev libipmctl-dev
69 |
70 | ### Build tools
71 | Install the following build tools:
72 | > autoconf, automake, flex, bison, libtool, pkg-config, libkmod-dev,
73 | > libudev-dev, uuid-dev
74 |
--------------------------------------------------------------------------------
/autogen.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | autoreconf --force --install --symlink -I config -I m4
3 |
--------------------------------------------------------------------------------
/build_pmwatch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | print_usage_and_exit()
4 | {
5 | echo "Usage: ./build_pmwatch.sh <-all|-cm|-m> with-libipmctl= with-libipmctl-inc= os=[esxi]"
6 |
7 | exit $1
8 | }
9 |
10 | if [ $# = 0 ] ; then
11 | print_usage_and_exit 0
12 | fi
13 |
14 | RUN_CONFIG=
15 | RUN_MAKE=
16 | RUN_CLEANMAKE=
17 | BUILD_ESXI=
18 | WITH_IPMCTL=
19 | WITH_IPMCTL_INC=
20 | while [ $# -gt 0 ] ; do
21 | case "$1" in
22 | --help | -h)
23 | print_usage_and_exit 0
24 | ;;
25 | -all)
26 | RUN_CONFIG=1
27 | RUN_CLEANMAKE=1
28 | RUN_MAKE=1
29 | ;;
30 | -cm)
31 | RUN_CLEANMAKE=1
32 | RUN_MAKE=1
33 | ;;
34 | -m)
35 | RUN_MAKE=1
36 | ;;
37 | with-libipmctl=*)
38 | WITH_IPMCTL=`echo $1 | sed s?^with-libipmctl=??g`
39 | ;;
40 | with-libipmctl-inc=*)
41 | WITH_IPMCTL_INC=`echo $1 | sed s?^with-libipmctl-inc=??g`
42 | ;;
43 | os=*)
44 | OS=`echo $1 | sed s?^os=??g`
45 | if [[ ${OS} = "esxi" ]] ; then
46 | BUILD_ESXI="BUILD_ESXI"
47 | fi
48 | ;;
49 | *)
50 | echo ""
51 | echo "Invalid option: \"$1\""
52 | print_usage_and_exit 1
53 | ;;
54 | esac
55 | shift
56 | done
57 |
58 | if [[ -n "${RUN_CONFIG}" ]] ; then
59 | echo "***************************************"
60 | echo "Executing ./autogen.sh..."
61 | echo "***************************************"
62 | ./autogen.sh
63 | if [[ $? -eq 0 ]] ; then
64 | echo "***************************************"
65 | echo "Execution of autogen.sh successful."
66 | echo "***************************************"
67 | echo
68 | else
69 | echo "***************************************"
70 | echo "Execution of autogen.sh failed."
71 | echo "***************************************"
72 | echo
73 | exit 1
74 | fi
75 |
76 | echo "***************************************"
77 | echo "Executing ./configure..."
78 | echo "***************************************"
79 | ./configure BUILD_ESXI=${BUILD_ESXI} --with-libipmctl=${WITH_IPMCTL} --with-libipmctl-inc=${WITH_IPMCTL_INC}
80 | if [[ $? -eq 0 ]] ; then
81 | echo "***************************************"
82 | echo "Execution of configure successful."
83 | echo "***************************************"
84 | echo
85 | else
86 | echo "***************************************"
87 | echo "Execution of configure failed."
88 | echo "***************************************"
89 | echo
90 | exit 1
91 | fi
92 | fi
93 |
94 | if [[ -n "${RUN_CLEANMAKE}" ]] ; then
95 | echo "***************************************"
96 | echo "Executing make clean..."
97 | echo "***************************************"
98 | make clean
99 | if [[ $? -eq 0 ]] ; then
100 | echo "***************************************"
101 | echo "Execution of make clean successful."
102 | echo "***************************************"
103 | echo
104 | else
105 | echo "***************************************"
106 | echo "Execution of make clean failed."
107 | echo "***************************************"
108 | echo
109 | exit 1
110 | fi
111 | fi
112 |
113 | if [[ -n "${RUN_MAKE}" ]] ; then
114 | echo "***************************************"
115 | echo "Executing make..."
116 | echo "***************************************"
117 | make -j 10 | tee makelog.log
118 | res=$?
119 | cat makelog.log | grep "Nothing to be done for 'all'" >> /dev/null 2>&1
120 | res_grep=$?
121 | rm -rf makelog.log
122 | if [[ ${res} -eq 0 && ${res_grep} -ne 0 ]] ; then
123 | echo "***************************************"
124 | echo "Execution of make successful."
125 | echo "***************************************"
126 | echo
127 | else
128 | echo "***************************************"
129 | echo "Execution of make failed."
130 | echo "***************************************"
131 | echo
132 | exit 1
133 | fi
134 | fi
135 |
--------------------------------------------------------------------------------
/config/.gitignore:
--------------------------------------------------------------------------------
1 | compile
2 | config.guess
3 | config.sub
4 | depcomp
5 | install-sh
6 | ltmain.sh
7 | missing
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(Intel PMWatch, 3.0)
2 | PROJECT_CFLAGS="-std=gnu99 -I./src/inc"
3 |
4 | AC_SUBST(PROJECT_CFLAGS)
5 | AC_CONFIG_AUX_DIR(config)
6 | AC_CONFIG_SRCDIR(src/pmwatch.c)
7 | : ${CXXFLAGS="-O2 -D_FORTIFY_SOURCE=2 -s"}
8 | AC_PROG_CXX
9 | : ${CFLAGS="-O2 -D_FORTIFY_SOURCE=2 -s"}
10 | AC_PROG_CC
11 | AM_INIT_AUTOMAKE
12 | LT_INIT
13 | AC_CONFIG_MACRO_DIR([m4])
14 | AC_CONFIG_FILES([Makefile])
15 | AM_CONDITIONAL(BUILD_ESXI, [test x${BUILD_ESXI} = xBUILD_ESXI])
16 | if test x${BUILD_ESXI} != xBUILD_ESXI ; then
17 | PKG_CHECK_MODULES([KMOD], [libkmod])
18 | PKG_CHECK_MODULES([UDEV], [libudev])
19 | PKG_CHECK_MODULES([UUID], [uuid])
20 | fi
21 |
22 | m4_divert_once([HELP_WITH], [
23 | PMWatch Dependencies:])
24 |
25 | # --with-libipmctl BEGIN
26 | AC_ARG_WITH([libipmctl],
27 | [AS_HELP_STRING([--with-libipmctl@<:@=PREFIX@:>@], [Path to libipmctl.])],
28 | [
29 | if test "x$withval" = "xyes" || test "x$withval" = "xno" ; then
30 | with_libipmctl="$withval"
31 | else
32 | with_libipmctl_ldflags="-L$withval"
33 | with_libipmctl="yes"
34 | fi
35 | ],
36 | [with_libipmctl="yes"]
37 | )
38 |
39 | if test "x$with_libipmctl" = "xyes" ; then
40 | SAVE_LDFLAGS="$LDFLAGS"
41 | LDFLAGS="$LDFLAGS $with_libipmctl_ldflags"
42 |
43 | AC_CHECK_LIB([ipmctl], [nvm_create_context],
44 | [with_libipmctls="yes"],
45 | [with_libipmctl="no (symbol 'nvm_create_context' not found)"]
46 | )
47 |
48 | AC_CHECK_LIB([ipmctl], [nvm_free_context],
49 | [with_libipmctls="yes"],
50 | [with_libipmctl="no (symbol 'nvm_free_context' not found)"]
51 | )
52 |
53 | AC_CHECK_LIB([ipmctl], [nvm_get_build_number],
54 | [with_libipmctls="yes"],
55 | [with_libipmctl="no (symbol 'nvm_get_build_number' not found)"]
56 | )
57 |
58 | AC_CHECK_LIB([ipmctl], [nvm_get_nvm_capacities],
59 | [with_libipmctls="yes"],
60 | [with_libipmctl="no (symbol 'nvm_get_nvm_capacities' not found)"]
61 | )
62 |
63 | AC_CHECK_LIB([ipmctl], [nvm_get_number_of_devices],
64 | [with_libipmctls="yes"],
65 | [with_libipmctl="no (symbol 'nvm_get_number_of_devices' not found)"]
66 | )
67 |
68 | AC_CHECK_LIB([ipmctl], [nvm_get_devices],
69 | [with_libipmctls="yes"],
70 | [with_libipmctl="no (symbol 'nvm_get_devices' not found)"]
71 | )
72 |
73 | AC_CHECK_LIB([ipmctl], [nvm_send_device_passthrough_cmd],
74 | [with_libipmctls="yes"],
75 | [with_libipmctl="no (symbol 'nvm_send_device_passthrough_cmd' not found)"]
76 | )
77 |
78 | AC_CHECK_LIB([ipmctl], [nvm_get_major_version],
79 | [with_libipmctls="yes"],
80 | [with_libipmctl="no (symbol 'nvm_get_major_version' not found)"]
81 | )
82 |
83 | AC_CHECK_LIB([ipmctl], [nvm_get_minor_version],
84 | [with_libipmctls="yes"],
85 | [with_libipmctl="no (symbol 'nvm_get_minor_version' not found)"]
86 | )
87 |
88 | AC_CHECK_LIB([ipmctl], [nvm_get_hotfix_number],
89 | [with_libipmctls="yes"],
90 | [with_libipmctl="no (symbol 'nvm_get_hotfix_number' not found)"]
91 | )
92 |
93 | AC_CHECK_LIB([ipmctl], [nvm_get_build_number],
94 | [with_libipmctls="yes"],
95 | [with_libipmctl="no (symbol 'nvm_get_build_number' not found)"]
96 | )
97 |
98 | LDFLAGS="$SAVE_LDFLAGS"
99 | fi
100 |
101 | if test "x$with_libipmctl" = "xyes" ; then
102 | BUILD_WITH_LIBIPMCTL_LDFLAGS="$with_libipmctl_ldflags"
103 | fi
104 |
105 | AC_SUBST([BUILD_WITH_LIBIPMCTL_LDFLAGS])
106 | # END
107 |
108 | # --with-libipmctl-inc BEGIN
109 | AC_ARG_WITH([libipmctl-inc],
110 | [AS_HELP_STRING([--with-libipmctl-inc@<:@=PREFIX@:>@], [Path to libipmctl header files.])],
111 | [
112 | if test "x$withval" = "xyes" || test "x$withval" = "xno" ; then
113 | with_libipmctlinc="$withval"
114 | else
115 | with_libipmctl_cflags="-I$withval"
116 | with_libipmctlinc="yes"
117 | fi
118 | ],
119 | [with_libipmctlinc="yes"]
120 | )
121 |
122 | if test "x$with_libipmctlinc" = "xyes" ; then
123 | SAVE_CFLAGS="$CFLAGS"
124 | CFLAGS="$CFLAGS $with_libipmctl_cflags"
125 |
126 | AC_CHECK_HEADERS([NvmSharedDefs.h],
127 | [with_libipmctlinc="yes"],
128 | [with_libipmctlinc="no (NvmSharedDefs.h not found)"]
129 | )
130 |
131 | AC_CHECK_HEADERS([nvm_types.h],
132 | [with_libipmctlinc="yes"],
133 | [with_libipmctlinc="no (nvm_types.h not found)"]
134 | )
135 |
136 | AC_CHECK_HEADERS([export_api.h],
137 | [with_libipmctlinc="yes"],
138 | [with_libipmctlinc="no (export_api.h not found)"]
139 | )
140 |
141 | AC_CHECK_HEADERS([nvm_management.h],
142 | [with_libipmctlinc="yes"],
143 | [with_libipmctlinc="no (nvm_management.h not found)"]
144 | )
145 |
146 | CFLAGS="$SAVE_CFLAGS"
147 | fi
148 |
149 | if test "x$with_libipmctlinc" = "xyes" ; then
150 | BUILD_WITH_LIBIPMCTL_CFLAGS="$with_libipmctl_cflags"
151 | fi
152 |
153 | AC_SUBST([BUILD_WITH_LIBIPMCTL_CFLAGS])
154 | # END
155 |
156 | AM_CONDITIONAL(BUILD_PMWATCH, test "x$with_libipmctl" = "xyes")
157 | if test "x$with_libipmctlinc" != "xyes" ; then
158 | AM_CONDITIONAL(BUILD_PMWATCH, test "x$with_libipmctlinc" = "xyes")
159 | fi
160 |
161 | AC_OUTPUT
162 |
163 | AC_MSG_RESULT()
164 | AC_MSG_RESULT([Library availability:])
165 | AC_MSG_RESULT([ libipmctl . . . . . . . $with_libipmctl])
166 | AC_MSG_RESULT([Header files availability:])
167 | AC_MSG_RESULT([ libipmctl-inc . . . . . . $with_libipmctlinc])
168 | AC_MSG_RESULT()
169 |
--------------------------------------------------------------------------------
/docs/PMWatch_User_Guide.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intel/intel-pmwatch/a19838bef7b6a269553b4206ecd531a781880fea/docs/PMWatch_User_Guide.docx
--------------------------------------------------------------------------------
/docs/PMWatch_User_Guide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/intel/intel-pmwatch/a19838bef7b6a269553b4206ecd531a781880fea/docs/PMWatch_User_Guide.pdf
--------------------------------------------------------------------------------
/docs/README:
--------------------------------------------------------------------------------
1 | Introduction: Intel PMWatch is a tool that monitors and reports the behavior of the Intel® Optane™ DC persistent memory.
2 | It consists of a data collector.
3 |
4 | Pre-requisites:
5 | Linux OS - Fedora or RHEL with nvdimm driver support
6 | Intel® Optane™ DC persistent memory firmware version: 01.01.00.5142 and newer
7 |
8 | PMWatch instructions:
9 | Run "source pmw_vars.sh" to set up the environment before using the tool.
10 |
11 | Tools Usage:
12 | pmwatch "" "" -f outputfile.csv
13 |
14 | Example: "pmwatch 1 100" reads the counters every 1 second 100 times.
15 |
16 | The output of PMWatch is in a CSV format listing the metrics for each DIMM on the system and outputs the counts for each interval.
17 |
18 | Explanation of metrics:
19 |
20 | Memory performance metrics:
21 | bytes_read (derived) : number of bytes transacted by the read operations
22 | bytes_written (derived): number of bytes transacted by the write operations
23 | Note: The total number of bytes transacted in any sample is computed as bytes_read (derived) + 2 * bytes_written (derived).
24 |
25 | Formula:
26 | bytes_read : (read_64B_ops_received - write_64B_ops_received) * 64
27 | bytes_written: write_64B_ops_received * 64
28 |
29 |
30 | read_hit_ratio (derived) : measures the efficiency of the buffer in the read path. Range of 0.0 - 0.75.
31 | write_hit_ratio (derived): measures the efficiency of the buffer in the write path. Range of 0.0 - 0.1.
32 |
33 | 0.75 : indicates 100% sequential write traffic
34 | > 0.75 : indicates writing to 64B addresses that are still in the write buffer (never had to go to media)
35 | 1 or ~1: likely writing to a specific address or small range of addresses (fitting in write buffer) for long periods of time.
36 |
37 | Formula:
38 | read_hit_ratio : (cpu_read_ops - media_read_ops) / cpu_read_ops
39 | write_hit_ratio: (cpu_write_ops - media_write_ops) / cpu_write_ops
40 |
41 |
42 | media_read_ops (derived) :
43 | media_write_ops (derived):
44 | Number of read and write operations performed to the physical media. Each operation transacts a 256 bytes operation.
45 |
46 | Formula:
47 | media_read_ops : (read_64B_ops_received - write_64B_ops_received) / 4
48 | media_write_ops: write_64B_ops_received / 4
49 |
50 |
51 | read_64B_ops_received :
52 | write_64B_ops_received:
53 | Number of read and write operations performed from/to the physical media. Each operation transacts a 64byte operation. These operations includes commands transacted for maintenance as well as the commands transacted by the CPU.
54 |
55 |
56 | cpu_read_ops :
57 | cpu_write_ops:
58 | Number of read and write operations received from the CPU (memory controller), for the Memory Mode and AppDirect Mode partitions.
59 |
60 | Health Information:
61 | health_status:
62 | Overall health summary.
63 |
64 | Value: Health Status
65 | 0: Normal
66 | 1: Non-critical
67 | 2: Critical
68 | 3: Fatal
69 |
70 | lifespan_used:
71 | The module’s used life as a percentage value of factory expected like span.
72 |
73 | lifespan_remaining:
74 | The module’s remaining life as a percentage value of factory expected like span.
75 |
76 | power_on_time:
77 | The lifetime the DIMM has been powered on in seconds.
78 |
79 | uptime:
80 | The current uptime of the DIMM for the current power cycle in seconds.
81 |
82 | last_shutdown_time:
83 | The time the system was last shutdown. The time is represented in epoch (seconds).
84 |
85 | media_temp :
86 | The media’s current temperature in degrees Celsius.
87 |
88 | controller_temp :
89 | The controller’s current temperature in degrees Celsius.
90 |
91 | max_media_temp :
92 | The media’s the highest temperature reported in degrees Celsius.
93 |
94 | max_controller_temp :
95 | The controller’s highest temperature reported in degrees Celsius.
96 |
--------------------------------------------------------------------------------
/docs/README_INSTALL:
--------------------------------------------------------------------------------
1 | Intel PMWatch
2 |
3 | How to install the tool:
4 | $ ./install-pmw
5 |
6 | How to set up environment:
7 | $ source /opt/intel/pmwatch/pmw_vars.sh
8 |
--------------------------------------------------------------------------------
/docs/README_INSTALL.txt:
--------------------------------------------------------------------------------
1 | Intel PMWatch
2 |
3 | How to install the tool:
4 | Run the below command with Administrator privilege
5 | $ install-pmw.cmd pmwatch_.zip
6 |
7 | How to set up environment:
8 | $ C:\Intel\pmwatch\pmw_vars.cmd
9 |
--------------------------------------------------------------------------------
/docs/esxi/README:
--------------------------------------------------------------------------------
1 | Introduction: Intel PMWatch is a tool that monitors and reports the behavior of the Intel® Optane™ DC persistent memory.
2 | It consists of a data collector.
3 |
4 | Pre-requisites:
5 | Supported Hypervisor: VMware ESXi 6.7.
6 | ESXi should be configured in maintenance mode.
7 |
8 | Run "cd /opt/intel/pmwatch && source pmw_vars.sh && cd -" to set up the environment before using the tool.
9 |
10 | Tools Usage:
11 | pmwatch "" "" -f outputfile.csv
12 |
13 | Example: "pmwatch 1 100" reads the counters every 1 second 100 times.
14 |
15 | The output of PMWatch is in a CSV format listing the metrics for each DIMM on the system and outputs the counts for each interval.
16 |
17 | Explanation of metrics:
18 | bytes_read (derived) : number of bytes transacted by the read operations
19 | bytes_written (derived): number of bytes transacted by the write operations
20 | Note: The total number of bytes transacted in any sample is computed as bytes_read (derived) + 2 * bytes_written (derived).
21 |
22 | Formula:
23 | bytes_read : (read_64B_ops_received - write_64B_ops_received) * 64
24 | bytes_written: write_64B_ops_received * 64
25 |
26 |
27 | read_hit_ratio (derived) : measures the efficiency of the buffer in the read path. Range of 0.0 - 0.75.
28 | write_hit_ratio (derived): measures the efficiency of the buffer in the write path. Range of 0.0 - 0.1.
29 |
30 | 0.75 : indicates 100% sequential write traffic
31 | > 0.75 : indicates writing to 64B addresses that are still in the write buffer (never had to go to media)
32 | 1 or ~1: likely writing to a specific address or small range of addresses (fitting in write buffer) for long periods of time.
33 |
34 | Formula:
35 | read_hit_ratio : (cpu_read_ops - media_read_ops) / cpu_read_ops
36 | write_hit_ratio: (cpu_write_ops - media_write_ops) / cpu_write_ops
37 |
38 |
39 | media_read_ops (derived) :
40 | media_write_ops (derived):
41 | Number of read and write operations performed to the physical media. Each operation transacts a 256 bytes operation.
42 |
43 | Formula:
44 | media_read_ops : (read_64B_ops_received - write_64B_ops_received) / 4
45 | media_write_ops: write_64B_ops_received / 4
46 |
47 |
48 | read_64B_ops_received :
49 | write_64B_ops_received:
50 | Number of read and write operations performed from/to the physical media. Each operation transacts a 64byte operation. These operations includes commands transacted for maintenance as well as the commands transacted by the CPU.
51 |
52 |
53 | cpu_read_ops :
54 | cpu_write_ops:
55 | Number of read and write operations received from the CPU (memory controller), for the Memory Mode and AppDirect Mode partitions.
56 |
--------------------------------------------------------------------------------
/docs/esxi/README_INSTALL:
--------------------------------------------------------------------------------
1 | Intel PMWatch
2 |
3 | How to install the tool:
4 | $ ./install-pmw pmwatch_.tar.bz2
5 |
6 | How to set up environment:
7 | $ cd /opt/intel/pmwatch
8 | $ source pmw_vars.sh
9 |
--------------------------------------------------------------------------------
/m4/.gitignore:
--------------------------------------------------------------------------------
1 | *.m4
--------------------------------------------------------------------------------
/package_pmwatch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # MIT License
4 | #
5 | # Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a
8 | # copy of this software and associated documentation files (the "Software"),
9 | # to deal in the Software without restriction, including without limitation
10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | # and/or sell copies of the Software, and to permit persons to whom the
12 | # Software is furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | # DEALINGS IN THE SOFTWARE.
24 |
25 | PWD="pwd"
26 | CWD=`${PWD}`
27 |
28 | print_usage_and_exit()
29 | {
30 | echo "Usage: ./package_pmwatch.sh M= m= u= os= [-r]"
31 | echo "Option:"
32 | echo " -r removes the package directory after tarball creation"
33 | echo
34 | echo "Always run this script at the base directory."
35 |
36 | exit $1
37 | }
38 |
39 | if [ $# = 0 ] ; then
40 | print_usage_and_exit 0
41 | fi
42 |
43 | OS=
44 | remove_package_dir=
45 | while [ $# -gt 0 ] ; do
46 | case "$1" in
47 | --help | -h)
48 | print_usage_and_exit 0
49 | ;;
50 | M=*)
51 | MAJOR_VERSION=`echo $1 | sed s?^M=??g`
52 | if [[ ! ${MAJOR_VERSION} =~ ^-?[0-9]+$ ]] ; then
53 | echo "Invalid argument $1! Use integer"
54 | exit
55 | fi
56 | ;;
57 | m=*)
58 | MINOR_VERSION=`echo $1 | sed s?^m=??g`
59 | if [[ ! ${MINOR_VERSION} =~ ^-?[0-9]+$ ]] ; then
60 | echo "Invalid argument $1! Use integer"
61 | exit
62 | fi
63 | ;;
64 | u=*)
65 | UPDATE_NUM=`echo $1 | sed s?^u=??g`
66 | if [[ ! ${UPDATE_NUM} =~ ^-?[0-9]+$ ]] ; then
67 | echo "Invalid argument $1! Use integer"
68 | exit
69 | fi
70 | ;;
71 | os=*)
72 | OS=`echo $1 | sed s?^os=??g`
73 | if [[ ${OS} != "esxi" && ${OS} != "linux" ]] ; then
74 | echo ""
75 | echo "Invalid OS!"
76 | print_usage_and_exit
77 | fi
78 | ;;
79 | -r)
80 | remove_package_dir=1
81 | ;;
82 | *)
83 | echo ""
84 | echo "Invalid option: \"$1\""
85 | print_usage_and_exit 1
86 | ;;
87 | esac
88 | shift
89 | done
90 |
91 |
92 | TOOL_NAME="pmwatch"
93 | PACKAGE_NAME="${TOOL_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${UPDATE_NUM}"
94 | PKG="package"
95 | OUTER_PACKAGE_NAME="${PACKAGE_NAME}_${OS}_${PKG}"
96 | PACKAGE_DIR="${CWD}/${PACKAGE_NAME}"
97 | OUTER_PACKAGE_DIR="${CWD}/${OUTER_PACKAGE_NAME}"
98 |
99 | if [[ ${OS} == "esxi" ]] ; then
100 | DIR_EXT="esxi"
101 | fi
102 |
103 | # setting up path
104 | PMW_SCRIPTS_DIR="scripts"
105 | PMW_DOCS_DIR="docs"
106 | PMW_SCRIPTS_PATH="${CWD}/${PMW_SCRIPTS_DIR}"
107 | PMW_DOCS_PATH="${CWD}/${PMW_DOCS_DIR}"
108 | BIN_DIR="${CWD}/bin64"
109 | LIB_DIR="${CWD}/lib64"
110 | INCLUDE_DIR="${CWD}/include"
111 |
112 | # scripts
113 | # pmw_vars
114 | PMW_VARS="pmw_vars.sh"
115 | if [[ ${OS} == "esxi" ]] ; then
116 | PMW_VARS="${DIR_EXT}/pmw_vars.sh"
117 | fi
118 | PMW_VARS_PATH="${PMW_SCRIPTS_PATH}/${PMW_VARS}"
119 |
120 | # installer
121 | INSTALL_SCRIPT="install-pmw"
122 | if [[ ${OS} == "esxi" ]] ; then
123 | INSTALL_SCRIPT="${DIR_EXT}/install-pmw"
124 | fi
125 | INSTALL_SCRIPT_PATH="${PMW_SCRIPTS_PATH}/${INSTALL_SCRIPT}"
126 |
127 | # docs
128 | README="README"
129 | if [[ ${OS} == "esxi" ]] ; then
130 | README="${DIR_EXT}/README"
131 | fi
132 | PMW_USER_GUIDE="PMWatch_User_Guide.pdf"
133 | README_INSTALL="README_INSTALL"
134 | if [[ ${OS} == "esxi" ]] ; then
135 | README_INSTALL="${DIR_EXT}/README_INSTALL"
136 | fi
137 | README_PATH="${PMW_DOCS_PATH}/${README}"
138 | README_INSTALL_PATH="${PMW_DOCS_PATH}/${README_INSTALL}"
139 | PMW_USER_GUIDE_PATH="${PMW_DOCS_PATH}/${PMW_USER_GUIDE}"
140 |
141 | # bin
142 | PMW_BIN1_PATH="${CWD}/pmwatch"
143 | PMW_BIN2_PATH="${CWD}/src/pmwatch-stop"
144 |
145 | # libs
146 | PMW_LIB_BASE_PATH="${CWD}/.libs"
147 | PMW_LIB1_NAME="libpmwapi.so*"
148 | PMW_LIB2_NAME="libpmwcollect.so*"
149 | PMW_LIB1_PATH="${PMW_LIB_BASE_PATH}/${PMW_LIB1_NAME}"
150 | PMW_LIB2_PATH="${PMW_LIB_BASE_PATH}/${PMW_LIB2_NAME}"
151 |
152 | # header files
153 | PMW_INCLUDE_BASE_PATH="${CWD}/src/inc"
154 | PMW_HEADER_FILE1="pmw_api.h"
155 | PMW_HEADER_FILE2="pmw_struct.h"
156 | PMW_INCLUDE1_PATH="${PMW_INCLUDE_BASE_PATH}/${PMW_HEADER_FILE1}"
157 | PMW_INCLUDE2_PATH="${PMW_INCLUDE_BASE_PATH}/${PMW_HEADER_FILE2}"
158 |
159 | # tar_name
160 | TAR_EXT=".tar.bz2"
161 | TAR_NAME="${PACKAGE_NAME}${TAR_EXT}"
162 | TAR_PATH="${CWD}/${TAR_NAME}"
163 | OUTER_TAR_NAME="${OUTER_PACKAGE_NAME}${TAR_EXT}"
164 | OUTER_TAR_PATH="${CWD}/${OUTER_TAR_NAME}"
165 |
166 |
167 | mkdir ${PACKAGE_DIR}
168 | if [ $? -ne 0 ] ; then
169 | echo "Package directory not successfully created!"
170 | exit
171 | fi
172 |
173 | if [[ ! -d ${BIN_DIR} ]]; then
174 | mkdir ${BIN_DIR}
175 | if [[ $? -ne 0 ]] ; then
176 | echo "Package creation not successful; mkdir ${BIN_DIR}!"
177 | echo
178 | exit 1
179 | fi
180 | fi
181 |
182 | cp -a {${PMW_BIN1_PATH},${PMW_BIN2_PATH}} ${BIN_DIR}
183 | if [ $? -ne 0 ] ; then
184 | echo "Package creation not successful; ${BIN_DIR} copy!"
185 | echo
186 | exit 1
187 | fi
188 |
189 | if [[ ! -d ${LIB_DIR} ]]; then
190 | mkdir ${LIB_DIR}
191 | if [[ $? -ne 0 ]] ; then
192 | echo "Package creation not successful; mkdir ${LIB_DIR}!"
193 | echo
194 | exit 1
195 | fi
196 | fi
197 |
198 | cp -a ${PMW_LIB1_PATH} ${LIB_DIR}
199 | if [ $? -ne 0 ] ; then
200 | echo "Package creation not successful; ${LIB_DIR} copy!"
201 | echo
202 | exit 1
203 | fi
204 | cp -a ${PMW_LIB2_PATH} ${LIB_DIR}
205 | if [ $? -ne 0 ] ; then
206 | echo "Package creation not successful; ${LIB_DIR} copy!"
207 | echo
208 | exit 1
209 | fi
210 |
211 | if [[ ! -d ${INCLUDE_DIR} ]]; then
212 | mkdir ${INCLUDE_DIR}
213 | if [[ $? -ne 0 ]] ; then
214 | echo "Package creation not successful; mkdir ${LIB_DIR}!"
215 | echo
216 | exit 1
217 | fi
218 | fi
219 |
220 | cp -a ${PMW_INCLUDE1_PATH} ${INCLUDE_DIR}
221 | if [ $? -ne 0 ] ; then
222 | echo "Package creation not successful; ${INCLUDE_DIR} copy!"
223 | echo
224 | exit 1
225 | fi
226 | cp -a ${PMW_INCLUDE2_PATH} ${INCLUDE_DIR}
227 | if [ $? -ne 0 ] ; then
228 | echo "Package creation not successful; ${INCLUDE_DIR} copy!"
229 | echo
230 | exit 1
231 | fi
232 |
233 | mv {${BIN_DIR},${LIB_DIR},${INCLUDE_DIR}} ${PACKAGE_DIR}
234 | if [ $? -ne 0 ] ; then
235 | echo "Package creation not successful; intial copy!"
236 | echo
237 | if [ -d ${PACKAGE_DIR} ] ; then
238 | rm -rf ${PACKAGE_DIR}
239 | fi
240 | exit 1
241 | fi
242 | cp -r {${PMW_VARS_PATH},${README_PATH},${PMW_USER_GUIDE_PATH}} ${PACKAGE_DIR}
243 | if [ $? -ne 0 ] ; then
244 | echo "Package creation not successful; intial copy!"
245 | echo
246 | if [ -d ${PACKAGE_DIR} ] ; then
247 | rm -rf ${PACKAGE_DIR}
248 | fi
249 | exit 1
250 | fi
251 |
252 | echo "Package directory created successfully."
253 |
254 | res=`tar cvfj ${TAR_PATH} ${PACKAGE_NAME}`
255 | if [ $? -ne 0 ] ; then
256 | echo "Core package tar ball cannot be created successfully."
257 | echo
258 | if [ -d ${PACKAGE_DIR} ] ; then
259 | rm -rf ${PACKAGE_DIR}
260 | fi
261 | exit 1
262 | else
263 | echo "Core package tar ball created successfully."
264 | fi
265 |
266 | mkdir ${OUTER_PACKAGE_DIR}
267 | if [ $? -ne 0 ] ; then
268 | echo "Unable to create ${OUTER_PACKAGE_DIR}! Exiting..."
269 | echo
270 | rm -rf ${PACKAGE_DIR} ${TAR_PATH}
271 | if [ -d ${OUTER_PACKAGE_DIR} ] ; then
272 | rm -rf ${OUTER_PACKAGE_DIR}
273 | fi
274 | exit 1
275 | fi
276 |
277 | cp {${TAR_PATH},${README_INSTALL_PATH},${INSTALL_SCRIPT_PATH}} ${OUTER_PACKAGE_DIR}
278 | if [ $? -ne 0 ] ; then
279 | echo "Unable to package ${OUTER_PACKAGE_NAME}; copy failed! Exiting..."
280 | echo
281 | rm -rf ${PACKAGE_DIR} ${TAR_PATH}
282 | if [ -d ${OUTER_PACKAGE_DIR} ] ; then
283 | rm -rf ${OUTER_PACKAGE_DIR}
284 | fi
285 | exit 1
286 | fi
287 |
288 | res=`tar cvfj ${OUTER_TAR_PATH} ${OUTER_PACKAGE_NAME}`
289 | if [ $? -ne 0 ] ; then
290 | echo "Final package tar ball cannot be created successfully."
291 | echo
292 | rm -rf ${PACKAGE_DIR} ${TAR_PATH} ${OUTER_PACKAGE_DIR}
293 | exit 1
294 | else
295 | echo "Final package tar ball created successfully."
296 | fi
297 |
298 | if [[ -n "${remove_package_dir}" ]] ; then
299 | rm -rf ${PACKAGE_DIR} ${OUTER_PACKAGE_DIR} ${TAR_PATH}
300 | if [ $? -ne 0 ] ; then
301 | echo "${PACKAGE_NAME}, ${OUTER_PACKAGE_NAME} and ${TAR_NAME} were not removed."
302 | echo
303 | exit 1
304 | else
305 | echo "${PACKAGE_NAME}, ${OUTER_PACKAGE_NAME} and ${TAR_NAME} were removed."
306 | echo
307 | fi
308 | fi
309 |
--------------------------------------------------------------------------------
/prepare_pmwatch_release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # MIT License
4 | #
5 | # Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a
8 | # copy of this software and associated documentation files (the "Software"),
9 | # to deal in the Software without restriction, including without limitation
10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | # and/or sell copies of the Software, and to permit persons to whom the
12 | # Software is furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | # DEALINGS IN THE SOFTWARE.
24 |
25 | print_usage_and_exit()
26 | {
27 | echo "Usage: ./prepare_pmwatch_release.sh M= m= u= with-libipmctl= with-libipmctl-inc= os= [-r]"
28 | echo "Option:"
29 | echo " -r removes the package directory after tarball creation"
30 | echo
31 |
32 | exit $1
33 | }
34 |
35 | if [ $# = 0 ] ; then
36 | print_usage_and_exit 0
37 | fi
38 |
39 | OS=linux
40 | remove_package_dir=
41 | WITH_IPMCTL=
42 | WITH_IPMCTL_INC=
43 | while [ $# -gt 0 ] ; do
44 | case "$1" in
45 | --help | -h)
46 | print_usage_and_exit 0
47 | ;;
48 | M=*)
49 | MAJOR_VERSION=`echo $1 | sed s?^M=??g`
50 | if [[ ! ${MAJOR_VERSION} =~ ^-?[0-9]+$ ]] ; then
51 | echo "Invalid argument $1! Use integer"
52 | exit
53 | fi
54 | ;;
55 | m=*)
56 | MINOR_VERSION=`echo $1 | sed s?^m=??g`
57 | if [[ ! ${MINOR_VERSION} =~ ^-?[0-9]+$ ]] ; then
58 | echo "Invalid argument $1! Use integer"
59 | exit
60 | fi
61 | ;;
62 | u=*)
63 | UPDATE_NUM=`echo $1 | sed s?^u=??g`
64 | if [[ ! ${UPDATE_NUM} =~ ^-?[0-9]+$ ]] ; then
65 | echo "Invalid argument $1! Use integer"
66 | exit
67 | fi
68 | ;;
69 | with-libipmctl=*)
70 | WITH_IPMCTL=`echo $1 | sed s?^with-libipmctl=??g`
71 | ;;
72 | with-libipmctl-inc=*)
73 | WITH_IPMCTL_INC=`echo $1 | sed s?^with-libipmctl-inc=??g`
74 | ;;
75 | os=*)
76 | OS=`echo $1 | sed s?^os=??g`
77 | if [[ ${OS} != "esxi" && ${OS} != "linux" ]] ; then
78 | echo ""
79 | echo "Invalid OS!"
80 | print_usage_and_exit
81 | fi
82 | ;;
83 | -r)
84 | remove_package_dir=$1
85 | ;;
86 | *)
87 | echo ""
88 | echo "Invalid option: \"$1\""
89 | print_usage_and_exit 1
90 | ;;
91 | esac
92 | shift
93 | done
94 |
95 | ./build_pmwatch.sh -all os=${OS} with-libipmctl=${WITH_IPMCTL} with-libipmctl-inc=${WITH_IPMCTL_INC} os=${OS}
96 | if [[ $? -ne 0 ]] ; then
97 | exit 1
98 | fi
99 |
100 | ./package_pmwatch.sh M=${MAJOR_VERSION} m=${MINOR_VERSION} u=${UPDATE_NUM} os=${OS} ${remove_package_dir}
101 | if [[ $? -ne 0 ]] ; then
102 | exit 1
103 | fi
104 |
--------------------------------------------------------------------------------
/scripts/esxi/install-pmw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # MIT License
4 | #
5 | # Copyright (C) 2018 - 2019 Intel Corporation. All rights reserved.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a
8 | # copy of this software and associated documentation files (the "Software"),
9 | # to deal in the Software without restriction, including without limitation
10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | # and/or sell copies of the Software, and to permit persons to whom the
12 | # Software is furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | # DEALINGS IN THE SOFTWARE.
24 |
25 | if [[ $# != 1 ]] ; then
26 | echo "Usage: install pmwatch_.tar.bz2"
27 | exit
28 | fi
29 |
30 | if [ "${USER}x" != "rootx" ] ; then
31 | echo "Non-root user. Try again with root access!"
32 | exit
33 | fi
34 |
35 | TARBALL="$1"
36 | if [ ! -f ${TARBALL} ] ; then
37 | echo "Invalid tarball!"
38 | exit
39 | fi
40 |
41 | BIN_DIR="bin64"
42 | LIB_DIR="lib64"
43 | SYSTEM_LIB64="lib64"
44 | INSTALL_BASE="/opt/intel"
45 | INSTALL_BASE_DIR="${INSTALL_BASE}/pmwatch"
46 | PMWATCH_VER=${TARBALL:9:5}
47 | PMWATCH_BASE_NAME=${TARBALL:0:-8}
48 | INSTALL_DIR="${INSTALL_BASE}/${PMWATCH_BASE_NAME}"
49 | LIBIPMCTL="libipmctl.so.3.1.0"
50 | LIBIPMCTL_LESS="libipmctl.so.3"
51 |
52 | if [ ! -d "${INSTALL_BASE}" ] ; then
53 | mkdir ${INSTALL_BASE}
54 | if [ $? -ne 0 ] ; then
55 | echo "Unable to create ${INSTALL_BASE}. Exiting..."
56 | exit
57 | fi
58 | fi
59 |
60 | sh -c "tar xf ${TARBALL} -C ${INSTALL_BASE}"
61 | sh -c "chown root ${INSTALL_DIR}/${BIN_DIR}/pmwatch"
62 | sh -c "chgrp root ${INSTALL_DIR}/${BIN_DIR}/pmwatch"
63 | sh -c "chown root ${INSTALL_DIR}/${BIN_DIR}/pmwatch-stop"
64 | sh -c "chgrp root ${INSTALL_DIR}/${BIN_DIR}/pmwatch-stop"
65 |
66 | find_ipmctl=$( find /${SYSTEM_LIB64}/ -name ${LIBIPMCTL} )
67 | if [ -z "${find_ipmctl}" ] ; then
68 | sh -c "mv ${INSTALL_DIR}/${LIB_DIR}/${LIBIPMCTL} /${SYSTEM_LIB64}/"
69 | sh -c "ln -s /${SYSTEM_LIB64}/${LIBIPMCTL} /${SYSTEM_LIB64}/${LIBIPMCTL_LESS}"
70 | else
71 | find_ipmctl=$( find /${SYSTEM_LIB64}/ -name ${LIBIPMCTL_LESS} )
72 | if [ -z "${find_ipmctl}" ] ; then
73 | sh -c "ln -s /${SYSTEM_LIB64}/${LIBIPMCTL} /${SYSTEM_LIB64}/${LIBIPMCTL_LESS}"
74 | fi
75 | fi
76 |
77 | if [ -L ${INSTALL_BASE_DIR} ] ; then
78 | sh -c "rm -f ${INSTALL_BASE_DIR}"
79 | fi
80 | sh -c "ln -s ${INSTALL_DIR} ${INSTALL_BASE_DIR}"
81 |
82 | echo "pmwatch ${PMWATCH_VER} is installed in ${INSTALL_BASE_DIR}"
83 | echo ""
84 | echo "Follow the below steps to start using pmwatch:"
85 | echo " cd ${INSTALL_BASE_DIR}"
86 | echo " source ./pmw_vars.sh"
87 | echo ""
88 | echo "Only root user has the the permission to run pmwatch!"
89 | echo "Please configure ESXi in maintenance mode for pmwatch to work."
90 | echo ""
91 |
--------------------------------------------------------------------------------
/scripts/esxi/pmw_vars.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # =============================================================================
4 | # Filename: pmw_vars.sh
5 | # Version: 1.0
6 | # Purpose: PMWatch Runtime environment setup script
7 | # Description: This script should be used to set up the run-time environment
8 | # for PMWatch. It requires sh. Run this script before running
9 | # PMWatch executable.
10 | #
11 | # Usage: source pmw_vars.sh
12 | #
13 | # MIT License
14 | #
15 | # Copyright (C) 2018 - 2019 Intel Corporation. All rights reserved.
16 | #
17 | # Permission is hereby granted, free of charge, to any person obtaining a
18 | # copy of this software and associated documentation files (the "Software"),
19 | # to deal in the Software without restriction, including without limitation
20 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 | # and/or sell copies of the Software, and to permit persons to whom the
22 | # Software is furnished to do so, subject to the following conditions:
23 | #
24 | # The above copyright notice and this permission notice shall be included in
25 | # all copies or substantial portions of the Software.
26 | #
27 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 | # DEALINGS IN THE SOFTWARE.
34 | #
35 | # =============================================================================
36 |
37 | echo "Please source this script under pmwatch install directory"
38 |
39 | GREP=grep
40 |
41 | #
42 | # Note: Busybox has a restricted shell environment, and
43 | # conventional system utilities may not be present;
44 | # so need to account for this ...
45 | #
46 | # busybox binary check
47 | BUSYBOX_SHELL=` ${GREP} --help 2>&1 | ${GREP} BusyBox`
48 |
49 | if [ -n "${BUSYBOX_SHELL}" ] ; then
50 | echo "Running on Busybox!"
51 | fi
52 |
53 | SCRIPT_DIR="$( cd "$( dirname "sh" )" && pwd )"
54 |
55 | export PMW_LOC_PATH="${SCRIPT_DIR}"
56 | export PMW_INSTALL_PATH="${PMW_LOC_PATH}/bin64"
57 | export LD_LIBRARY_PATH="${PMW_LOC_PATH}/lib64"
58 | export PATH="${PMW_INSTALL_PATH}:${PATH}"
59 |
60 | # show settings of various environment variables
61 | echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
62 | echo "PATH=${PATH}"
63 | echo ""
64 | echo "pmwatch is currently installed under ${PMW_INSTALL_PATH}"
65 | echo ""
66 | echo "pmwatch works only when ESXi is in maintenance mode."
67 | echo ""
68 |
--------------------------------------------------------------------------------
/scripts/install-pmw:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # MIT License
4 | #
5 | # Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a
8 | # copy of this software and associated documentation files (the "Software"),
9 | # to deal in the Software without restriction, including without limitation
10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | # and/or sell copies of the Software, and to permit persons to whom the
12 | # Software is furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | # DEALINGS IN THE SOFTWARE.
24 |
25 | PACKAGE_NAME_REGEX="pmwatch_[0-9\.]+[_a-zA-Z]*.tar.bz2"
26 | TARBALL=$( ls | grep -E ${PACKAGE_NAME_REGEX} )
27 | if [ ! -f "${TARBALL}" ] ; then
28 | echo ""
29 | echo "Package tarball is not available at the install script location!"
30 | echo "Run the install script from the location of package tarball"
31 | echo ""
32 |
33 | exit 150
34 | fi
35 |
36 | BIN_DIR="bin64"
37 | LIB_DIR="lib64"
38 | INSTALL_BASE="/opt/intel"
39 | PMWATCH_VER=${TARBALL:8:5}
40 | PMWATCH_BASE_NAME=${TARBALL:0:-8}
41 |
42 | print_usage_and_exit()
43 | {
44 | err=${1:-0}
45 | echo ""
46 | echo "Usage: $0 [ options ]"
47 | echo ""
48 | echo " where \"options\" are the following:"
49 | echo ""
50 | echo " -c | --custom-install-loc"
51 | echo " installs the tool at a user-specified location"
52 | echo ""
53 |
54 | exit $err
55 | }
56 |
57 | while [ $# -gt 0 ] ; do
58 | case "$1" in
59 | -c | --custom-install-loc)
60 | custom_install_loc=1
61 | shift
62 | INSTALL_BASE="$1"
63 | ;;
64 | --install-only-binary)
65 | install_only_binary=1
66 | ;;
67 | *)
68 | echo ""
69 | echo "ERROR: unrecognized option \"$1\""
70 | print_usage_and_exit 151
71 | ;;
72 | esac
73 | shift
74 | done
75 |
76 | if [ ! -d "${INSTALL_BASE}" ] ; then
77 | sudo mkdir ${INSTALL_BASE}
78 | if [ $? -ne 0 ] ; then
79 | echo "Unable to create directory ${INSTALL_BASE}. Exiting..."
80 | exit 152
81 | fi
82 | fi
83 |
84 | INSTALL_DIR="${INSTALL_BASE}/${PMWATCH_BASE_NAME}"
85 | INSTALL_DIR_SOFTLINK="${INSTALL_BASE}/pmwatch"
86 |
87 | sudo sh -c "tar --warning=no-timestamp -xf ${TARBALL} -C ${INSTALL_BASE}"
88 | sudo sh -c "chown root -R ${INSTALL_DIR}"
89 | if [ $? -ne 0 ] ; then
90 | echo
91 | echo "chown command failed!"
92 | echo
93 | sudo sh -c "rm -rf ${INSTALL_DIR}"
94 | exit 1
95 | fi
96 | sudo sh -c "chgrp root -R ${INSTALL_DIR}"
97 | if [ $? -ne 0 ] ; then
98 | echo
99 | echo "chgrp command failed!"
100 | echo
101 | sudo sh -c "rm -rf ${INSTALL_DIR}"
102 | exit 1
103 | fi
104 |
105 | if [ -L ${INSTALL_DIR_SOFTLINK} ] ; then
106 | sudo sh -c "unlink ${INSTALL_DIR_SOFTLINK}"
107 | fi
108 | sudo sh -c "ln -s ${INSTALL_DIR} ${INSTALL_DIR_SOFTLINK}"
109 |
110 |
111 | if [ -n "${install_only_binary}" ] ; then
112 | sudo sh -c "rm -rf ${INSTALL_DIR}/PMWatch_User_Guide.pdf ${INSTALL_DIR}/README ${INSTALL_DIR}/scripts > /dev/null 2>&1"
113 | fi
114 |
115 | # identify the OS
116 | os="default"
117 | cat /etc/*release | grep "SUSE" > /dev/null 2>&1
118 | if [ $? -eq 0 ] ; then
119 | os="suse"
120 | fi
121 | cat /etc/*release | grep "Ubuntu" > /dev/null 2>&1
122 | if [ $? -eq 0 ] ; then
123 | os="ubuntu"
124 | fi
125 |
126 | # check for missing dependencies
127 | tmp=`ldd ${INSTALL_DIR}/${BIN_DIR}/pmwatch | grep "not found"`
128 | if [ $? -eq 0 ] ; then
129 | echo ""
130 | dependent_libs=`ldd ${INSTALL_DIR}/${BIN_DIR}/pmwatch | grep "not found" | cut -d"=" -f1`
131 | echo "pmwatch has dependency on following libs: ${dependent_libs}"
132 | echo "Please install the relevant libraries and re-install pmwatch."
133 | echo ""
134 | echo "Depedency resolution tips:"
135 | echo " Install ndctl tool to resolve libndctl.so and libdaxctl.so dependencies."
136 |
137 | sudo sh -c "rm -rf ${INSTALL_DIR}"
138 |
139 | exit 153
140 | else
141 | echo ""
142 | echo "pmwatch ${PMWATCH_VER} is installed at ${INSTALL_DIR_SOFTLINK}."
143 | echo "Execute \"source ${INSTALL_DIR_SOFTLINK}/pmw_vars.sh\" to start using the tool."
144 | fi
145 |
146 | echo ""
147 |
--------------------------------------------------------------------------------
/scripts/pmw_vars.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | rem ===============================================================================================
3 |
4 | rem Purpose: PMWatch Runtime environment setup script
5 |
6 | rem Description: This script should be used to set up the run-time environment for PMWatch.
7 |
8 | rem MIT License
9 | rem
10 | rem Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
11 | rem
12 | rem Permission is hereby granted, free of charge, to any person obtaining a
13 | rem copy of this software and associated documentation files (the "Software"),
14 | rem to deal in the Software without restriction, including without limitation
15 | rem the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 | rem and/or sell copies of the Software, and to permit persons to whom the
17 | rem Software is furnished to do so, subject to the following conditions:
18 | rem
19 | rem The above copyright notice and this permission notice shall be included in
20 | rem all copies or substantial portions of the Software.
21 | rem
22 | rem THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 | rem IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 | rem FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 | rem AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 | rem LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 | rem FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 | rem DEALINGS IN THE SOFTWARE.
29 |
30 | rem ===============================================================================================
31 |
32 |
33 | set PMW_PKG_DIR=%~dp0%
34 |
35 | if "%PROCESSOR_ARCHITECTURE%"=="x86" (
36 | set PMW_BIN_DIR=bin32
37 | )
38 | if '%PROCESSOR_ARCHITECTURE%x'=='AMD64x' (
39 | set PMW_BIN_DIR=bin64
40 | )
41 |
42 | set PMW_LOC_PATH=%PMW_PKG_DIR%
43 | set PMW_INSTALL_PATH=%PMW_LOC_PATH%%PMW_BIN_DIR%
44 | set PATH=%PMW_INSTALL_PATH%;%PATH%
45 |
46 | rem echo all the variables
47 | rem echo PATH: %PATH%
48 | echo pmwatch is currently installed under %PMW_INSTALL_PATH%
49 |
50 | goto noerr
51 |
52 | :err
53 | echo Error occured during environment setup.
54 | goto :eof
55 |
56 | :noerr
57 | echo pmwatch run time environment successfully set.
58 |
--------------------------------------------------------------------------------
/scripts/pmw_vars.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # =============================================================================
4 | # Filename: pmw_vars.sh
5 | # Version: 1.0
6 | # Purpose: PMWatch Runtime environment setup script
7 | # Description: This script should be used to set up the run-time environment
8 | # for PMWatch. It requires sh. Run this script before running
9 | # PMWatch executable.
10 | #
11 | # Usage: source pmw_vars.sh
12 | #
13 | # MIT License
14 | #
15 | # Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
16 | #
17 | # Permission is hereby granted, free of charge, to any person obtaining a
18 | # copy of this software and associated documentation files (the "Software"),
19 | # to deal in the Software without restriction, including without limitation
20 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 | # and/or sell copies of the Software, and to permit persons to whom the
22 | # Software is furnished to do so, subject to the following conditions:
23 | #
24 | # The above copyright notice and this permission notice shall be included in
25 | # all copies or substantial portions of the Software.
26 | #
27 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 | # DEALINGS IN THE SOFTWARE.
34 | #
35 | # =============================================================================
36 |
37 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
38 |
39 | export PMW_LOC_PATH="${SCRIPT_DIR}"
40 | export PMW_INSTALL_PATH="${PMW_LOC_PATH}/bin64"
41 | export PMW_SCRIPT_INSTALL_PATH="${PMW_LOC_PATH}/scripts"
42 | export PATH="${PMW_INSTALL_PATH}:${PMW_SCRIPT_INSTALL_PATH}:${PATH}"
43 |
44 | # show settings of various environment variables
45 | echo "PATH=${PATH}"
46 | echo "PMW_SCRIPT_INSTALL_PATH=${PMW_SCRIPT_INSTALL_PATH}"
47 | echo pmwatch is currently installed under ${PMW_INSTALL_PATH}
48 |
--------------------------------------------------------------------------------
/src/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.lo
3 | .dirstamp
4 | .deps
5 | .libs
--------------------------------------------------------------------------------
/src/esxi/pmwatch-stop:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # MIT License
4 | #
5 | # Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a
8 | # copy of this software and associated documentation files (the "Software"),
9 | # to deal in the Software without restriction, including without limitation
10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | # and/or sell copies of the Software, and to permit persons to whom the
12 | # Software is furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | # DEALINGS IN THE SOFTWARE.
24 |
25 | res=`kill -9 $(pidof -s pmwatch)`
26 | echo
27 | if [[ $? -eq 0 ]] ; then
28 | echo "pmwatch stopped successfully."
29 | else
30 | echo "Unable to stop pmwatch."
31 | fi
32 | echo
33 |
--------------------------------------------------------------------------------
/src/inc/pmw_api.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #ifndef _PMW_API_H_INC_
27 | #define _PMW_API_H_INC_
28 |
29 | #include "pmw_struct.h"
30 |
31 | #ifndef PMW_API
32 | #define PMW_API
33 | #endif
34 |
35 | /* ------------------------------------------------------------------------- */
36 | /*!
37 | * @fn int PMWAPIGetDIMMCount (
38 | * int *num_nvdimms
39 | * )
40 | *
41 | * @brief function to obtain the number of DCPMM DIMMs
42 | *
43 | * @param OUT num_nvdimms: number of DCPMM DIMMs
44 | *
45 | * @return 0 if successful
46 | *
47 | * Special Notes:
48 | *
49 | */
50 | extern PMW_API int
51 | PMWAPIGetDIMMCount (
52 | int *num_nvdimms
53 | );
54 |
55 | /* ------------------------------------------------------------------------- */
56 | /*!
57 | * @fn int PMWAPIStart (
58 | * PMWATCH_CONFIG_NODE pmwatch_config
59 | * )
60 | *
61 | * @brief function to start the collection
62 | *
63 | * @param IN pmwatch_config: struct that provides collection configuration
64 | *
65 | * @return 0 if successful
66 | *
67 | * Special Notes:
68 | *
69 | */
70 | extern PMW_API int
71 | PMWAPIStart (
72 | PMWATCH_CONFIG_NODE pmwatch_config
73 | );
74 |
75 | /* ------------------------------------------------------------------------- */
76 | /*!
77 | * @fn int PMWAPIStop ()
78 | *
79 | * @brief function to stop the collection
80 | *
81 | * @param None
82 | *
83 | * @return 0 if successful
84 | *
85 | * Special Notes:
86 | *
87 | */
88 | extern PMW_API int
89 | PMWAPIStop ();
90 |
91 | /* ------------------------------------------------------------------------- */
92 | /*!
93 | * @fn int PMWAPIRead (
94 | * PMWATCH_OP_BUF* op_buf
95 | * )
96 | *
97 | * @brief function to obtain the metrics count
98 | *
99 | * @param OUT op_buf: output buffer
100 | *
101 | * @return 0 if successful
102 | *
103 | * Special Notes:
104 | *
105 | */
106 | extern PMW_API int
107 | PMWAPIRead (
108 | PMWATCH_OP_BUF* op_buf
109 | );
110 |
111 | #endif
112 |
--------------------------------------------------------------------------------
/src/inc/pmw_collect.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2018 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #ifndef _PMW_COLLECT_H_INC_
27 | #define _PMW_COLLECT_H_INC_
28 |
29 | #ifdef PMW_DLL
30 | #ifdef PMW_DLL_EXPORTS
31 | #define PMW_API PMW_HELPER_DLL_EXPORT
32 | #else
33 | #define PMW_API PMW_HELPER_DLL_IMPORT
34 | #endif // PMW_DLL_EXPORTS
35 | #else // PMW_DLL
36 | #define PMW_API
37 | #endif // NVM_DLL
38 |
39 | #include "pmw_struct.h"
40 |
41 | extern PMW_API NVM_UINT32
42 | PMW_COLLECT_Set_Global_Vars (
43 | FILE *l_fout,
44 | int l_loops,
45 | int l_infinite_run,
46 | uint64_t l_usec_sample_time,
47 | uint64_t l_usec_sample_time_prev,
48 | int l_collect_lifetime,
49 | int l_output_format_one,
50 | int l_output_format_two,
51 | int l_collect_health,
52 | char *l_delim
53 | );
54 |
55 | extern PMW_API int
56 | PMW_COLLECT_Print_Smart_Counters ();
57 |
58 | extern PMW_API int
59 | PMW_COLLECT_Print_Health_Info ();
60 |
61 | extern PMW_API void
62 | PMW_COLLECT_Print_Lifetime_Mem_Info_Counters ();
63 |
64 | #ifndef _WIN32
65 |
66 | extern PMW_API int
67 | PMW_COLLECT_Get_DIMM_Count (
68 | int *num_nvmdimms
69 | );
70 |
71 | extern PMW_API int
72 | PMW_COLLECT_Start_Collection (
73 | PMWATCH_CONFIG_NODE pmwatch_config
74 | );
75 |
76 | extern PMW_API int
77 | PMW_COLLECT_Stop_Collection ();
78 |
79 | extern PMW_API int
80 | PMW_COLLECT_Read_Data (
81 | PMWATCH_OP_BUF* op_buf
82 | );
83 |
84 | #endif
85 |
86 | #endif
87 |
--------------------------------------------------------------------------------
/src/inc/pmw_comm.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #ifndef _PMW_COMM_H_INC_
27 | #define _PMW_COMM_H_INC_
28 |
29 | #ifdef _WIN32
30 | #define PMW_DLL 1
31 | #define PMW_HELPER_DLL_IMPORT __declspec(dllimport)
32 | #define PMW_HELPER_DLL_EXPORT __declspec(dllexport)
33 | #endif
34 |
35 | #ifdef PMW_DLL
36 | #ifdef PMW_DLL_EXPORTS
37 | #define PMW_API PMW_HELPER_DLL_EXPORT
38 | #else
39 | #define PMW_API PMW_HELPER_DLL_IMPORT
40 | #endif // PMW_DLL_EXPORTS
41 | #else // PMW_DLL
42 | #define PMW_API
43 | #endif // NVM_DLL
44 |
45 | #define _STRINGIFY(x) #x
46 | #define STRINGIFY(x) _STRINGIFY(x)
47 |
48 | // defining ipmctl API macros
49 | #ifdef _WIN32
50 | #define NVM_CREATE_CONTEXT p_nvm_create_context
51 | #define NVM_FREE_CONTEXT p_nvm_free_context
52 | #define NVM_GET_BUILD_NUMBER p_nvm_get_build_number
53 | #define NVM_GET_NUMBER_OF_DEVICES p_nvm_get_number_of_devices
54 | #define NVM_GET_DEVICES p_nvm_get_devices
55 | #define NVM_GET_NVM_CAPACITIES p_nvm_get_nvm_capacities
56 | #define NVM_SEND_DEVICE_PASSTHROUGH_CMD p_nvm_send_device_passthrough_cmd
57 | #define NVM_GET_MAJOR_VERSION p_nvm_get_major_version
58 | #define NVM_GET_MINOR_VERSION p_nvm_get_minor_version
59 | #define NVM_GET_HOTFIX_NUMBER p_nvm_get_hotfix_number
60 | #define NVM_GET_BUILD_NUMBER p_nvm_get_build_number
61 | #else
62 | #define NVM_CREATE_CONTEXT nvm_create_context
63 | #define NVM_FREE_CONTEXT nvm_free_context
64 | #define NVM_GET_BUILD_NUMBER nvm_get_build_number
65 | #define NVM_GET_NUMBER_OF_DEVICES nvm_get_number_of_devices
66 | #define NVM_GET_DEVICES nvm_get_devices
67 | #define NVM_GET_NVM_CAPACITIES nvm_get_nvm_capacities
68 | #define NVM_SEND_DEVICE_PASSTHROUGH_CMD nvm_send_device_passthrough_cmd
69 | #define NVM_GET_MAJOR_VERSION nvm_get_major_version
70 | #define NVM_GET_MINOR_VERSION nvm_get_minor_version
71 | #define NVM_GET_HOTFIX_NUMBER nvm_get_hotfix_number
72 | #define NVM_GET_BUILD_NUMBER nvm_get_build_number
73 | #endif
74 |
75 | #define PMWATCH_SUPPORT_IPMCTL_VERSION_MIN "01.00.00.3262"
76 |
77 | // memory info struct
78 | typedef struct MEMORY_INFO_PAGE_NODE_S MEMORY_INFO_PAGE_NODE;
79 | typedef MEMORY_INFO_PAGE_NODE *MEMORY_INFO_PAGE;
80 |
81 | #if defined(_WIN32)
82 | #pragma pack(push,1)
83 | #endif
84 | struct MEMORY_INFO_PAGE_NODE_S { // output
85 | unsigned char total_bytes_read[16]; // Number of 64 byte reads from the DIMM
86 | unsigned char total_bytes_written[16]; // Number of 64 byte writes from the DIMM
87 | unsigned char total_read_reqs[16]; // Number of DDRT read transactions the DIMM has serviced
88 | unsigned char total_write_reqs[16]; // Number of DDRT write transactions the DIMM has serviced
89 | unsigned char rsvd[64];
90 | #if defined(_WIN32)
91 | };
92 | #pragma pack(pop)
93 | #else
94 | } __attribute__((packed));
95 | #endif
96 |
97 | typedef struct HEALTH_INFO_PAGE_NODE_S HEALTH_INFO_PAGE_NODE;
98 | typedef HEALTH_INFO_PAGE_NODE *HEALTH_INFO_PAGE;
99 |
100 | #if defined(_WIN32)
101 | #pragma pack(push,1)
102 | #endif
103 | struct HEALTH_INFO_PAGE_NODE_S {
104 | unsigned char validation_flags[4];
105 | unsigned char rsvd1[4];
106 | unsigned char health_status;
107 | unsigned char percentage_remaining;
108 | unsigned char percentage_used;
109 | unsigned char rsvd2;
110 | unsigned char media_temp[2];
111 | unsigned char controller_temp[2];
112 | unsigned char rsvd3[16];
113 | unsigned char vendor_data_size[4];
114 | unsigned char rsvd4[8];
115 | unsigned char power_on_time[8];
116 | unsigned char uptime[8];
117 | unsigned char rsvd5[5];
118 | unsigned char last_shutdown_time[8];
119 | unsigned char rsvd6[9];
120 | unsigned char max_media_temp[2];
121 | unsigned char max_controller_temp[2];
122 | unsigned char rsvd7[42];
123 | #if defined(_WIN32)
124 | };
125 | #pragma pack(pop)
126 | #else
127 | } __attribute__((packed));
128 | #endif
129 |
130 | #if defined(_WIN32)
131 | #pragma pack(push, 1)
132 | #endif
133 | struct pt_payload_input_memory_info { //input
134 | unsigned char memory_page; // The page of memory information you want to retrieve
135 | unsigned char rsvd[127];
136 | #if defined(_WIN32)
137 | };
138 | #pragma pack(pop)
139 | #else
140 | } __attribute__((packed));
141 | #endif
142 |
143 | /*
144 | * Strcuture to hold the SMART counter values
145 | */
146 | typedef struct LIFETIME_INFO_COUNTER_NODE_S LIFETIME_INFO_COUNTER_NODE;
147 | typedef LIFETIME_INFO_COUNTER_NODE *LIFETIME_INFO_COUNTER;
148 |
149 | struct LIFETIME_INFO_COUNTER_NODE_S
150 | {
151 | uint64_t bytes_read; // Lifetime number of 64 bytes of data read from the DIMM.
152 | uint64_t bytes_written; // Lifetime number of 64 bytes of data written to the DIMM.
153 | uint64_t host_reads; // Lifetime number of DDRT read requests the DIMM has serviced.
154 | uint64_t host_writes; // Lifetime number of DDRT write requests the DIMM has serviced.
155 | };
156 |
157 | typedef struct HEALTH_INFO_COUNTER_NODE_S HEALTH_INFO_COUNTER_NODE;
158 | typedef HEALTH_INFO_COUNTER_NODE *HEALTH_INFO_COUNTER;
159 |
160 | struct HEALTH_INFO_COUNTER_NODE_S
161 | {
162 | uint32_t validation_flags;
163 | unsigned char health_status;
164 | unsigned char percentage_remaining;
165 | unsigned char percentage_used;
166 | uint16_t media_temp;
167 | uint16_t controller_temp;
168 | uint32_t vendor_data_size;
169 | uint64_t power_on_time;
170 | uint64_t uptime;
171 | uint64_t last_shutdown_time;
172 | uint16_t max_media_temp;
173 | uint16_t max_controller_temp;
174 | };
175 |
176 |
177 | extern PMW_API struct device_discovery*
178 | PMW_COMM_Get_DIMM_Topology ();
179 |
180 | extern PMW_API NVM_INT32
181 | PMW_COMM_Get_Memory_Info_Page (
182 | NVM_INT32 dimm_index,
183 | void *counters,
184 | const unsigned char page_num
185 | );
186 |
187 | extern PMW_API NVM_INT32
188 | PMW_COMM_Get_Health_Info_Page (
189 | NVM_INT32 dimm_index,
190 | void *counters
191 | );
192 |
193 | extern PMW_API void
194 | PMW_COMM_Print_Warning_Message ();
195 |
196 | extern PMW_API NVM_INT32
197 | PMW_COMM_Is_DIMM_Available ();
198 |
199 | extern PMW_API NVM_INT32
200 | PMW_COMM_Read_DIMM_Topology ();
201 |
202 | extern PMW_API NVM_INT32
203 | PMW_COMM_Print_Topology (
204 | NVM_INT32 get_topo,
205 | NVM_INT32 detailed
206 | );
207 |
208 | extern PMW_API NVM_INT32
209 | PMW_COMM_Get_Number_of_DIMM (
210 | NVM_UINT32 *dimm_count
211 | );
212 |
213 | extern PMW_API NVM_INT32
214 | PMW_COMM_Get_Count_by_Topology (
215 | NVM_INT32 socket_num,
216 | NVM_INT32 mc_num,
217 | NVM_INT32 channel_num,
218 | NVM_INT32 dimm_num,
219 | LIFETIME_INFO_COUNTER smt_counters
220 | );
221 |
222 | extern PMW_API int
223 | PMW_COMM_Check_User_Permission ();
224 |
225 | extern PMW_API NVM_INT32
226 | PMW_COMM_Init ();
227 |
228 | extern PMW_API NVM_INT32
229 | PMW_COMM_Cleanup ();
230 |
231 | #endif
232 |
--------------------------------------------------------------------------------
/src/inc/pmw_struct.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #ifndef _PMW_STRUCT_H_INC_
27 | #define _PMW_STRUCT_H_INC_
28 |
29 | #include
30 | #include
31 |
32 | typedef struct PMWATCH_CONFIG_NODE_S PMWATCH_CONFIG_NODE;
33 | typedef PMWATCH_CONFIG_NODE *PMWATCH_CONFIG;
34 |
35 | struct PMWATCH_CONFIG_NODE_S
36 | {
37 | double interval;
38 | double health_interval;
39 | bool collect_health;
40 | bool collect_perf_metrics;
41 | };
42 |
43 | #define PMWATCH_CONFIG_INTERVAL(x) (x)->interval
44 | #define PMWATCH_CONFIG_HEALTH_INTERVAL(x) (x)->health_interval
45 | #define PMWATCH_CONFIG_COLLECT_HEALTH(x) (x)->collect_health
46 | #define PMWATCH_CONFIG_COLLECT_PERF_METRICS(x) (x)->collect_perf_metrics
47 |
48 | typedef struct PMWATCH_OP_BUF_NODE_S PMWATCH_OP_BUF_NODE;
49 | typedef PMWATCH_OP_BUF_NODE *PMWATCH_OP_BUF;
50 |
51 | struct PMWATCH_OP_BUF_NODE_S
52 | {
53 | uint64_t epoch;
54 | uint64_t timestamp;
55 | uint64_t total_bytes_read;
56 | uint64_t total_bytes_written;
57 | double read_hit_ratio;
58 | double write_hit_ratio;
59 | uint64_t media_read;
60 | uint64_t media_write;
61 | uint64_t bytes_read;
62 | uint64_t bytes_written;
63 | uint64_t host_reads;
64 | uint64_t host_writes;
65 | unsigned char health_status;
66 | unsigned char percentage_remaining;
67 | unsigned char percentage_used;
68 | uint64_t power_on_time;
69 | uint64_t uptime;
70 | uint64_t last_shutdown_time;
71 | double media_temp;
72 | double controller_temp;
73 | double max_media_temp;
74 | double max_controller_temp;
75 | };
76 |
77 | #define PMWATCH_OP_BUF_EPOCH(x) (x)->epoch
78 | #define PMWATCH_OP_BUF_TIMESTAMP(x) (x)->timestamp
79 | #define PMWATCH_OP_BUF_TOTAL_BYTES_READ(x) (x)->total_bytes_read
80 | #define PMWATCH_OP_BUF_TOTAL_BYTES_WRITTEN(x) (x)->total_bytes_written
81 | #define PMWATCH_OP_BUF_READ_HIT_RATIO(x) (x)->read_hit_ratio
82 | #define PMWATCH_OP_BUF_WRITE_HIT_RATIO(x) (x)->write_hit_ratio
83 | #define PMWATCH_OP_BUF_MEDIA_READ(x) (x)->media_read
84 | #define PMWATCH_OP_BUF_MEDIA_WRITE(x) (x)->media_write
85 | #define PMWATCH_OP_BUF_BYTES_READ(x) (x)->bytes_read
86 | #define PMWATCH_OP_BUF_BYTES_WRITTEN(x) (x)->bytes_written
87 | #define PMWATCH_OP_BUF_HOST_READS(x) (x)->host_reads
88 | #define PMWATCH_OP_BUF_HOST_WRITES(x) (x)->host_writes
89 | #define PMWATCH_OP_BUF_HEALTH_STATUS(x) (x)->health_status
90 | #define PMWATCH_OP_BUF_PERCENTAGE_REMAINING(x) (x)->percentage_remaining
91 | #define PMWATCH_OP_BUF_PERCENTAGE_USED(x) (x)->percentage_used
92 | #define PMWATCH_OP_POWER_ON_TIME(x) (x)->power_on_time
93 | #define PMWATCH_OP_BUF_UPTIME(x) (x)->uptime
94 | #define PMWATCH_OP_BUF_LAST_SHUTDOWN_TIME(x) (x)->last_shutdown_time
95 | #define PMWATCH_OP_BUF_MEDIA_TEMP(x) (x)->media_temp
96 | #define PMWATCH_OP_BUF_CONTROLLER_TEMP(x) (x)->controller_temp
97 | #define PMWATCH_OP_BUF_MAX_MEDIA_TEMP(x) (x)->max_media_temp
98 | #define PMWATCH_OP_BUF_MAX_CONTROLLER_TEMP(x) (x)->max_controller_temp
99 |
100 | #endif
101 |
--------------------------------------------------------------------------------
/src/inc/pmw_utils.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2018 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #ifndef _PMW_UTILS_H_INC_
27 | #define _PMW_UTILS_H_INC_
28 |
29 | #include "nvm_types.h"
30 | #include "pmw_comm.h"
31 |
32 | #define STRNCPY_SAFE PMW_UTILS_Strncpy_Safe
33 | #define STRNCAT_SAFE PMW_UTILS_Strncat_Safe
34 |
35 | #define CALCULATE_DIFFERENCE(cur,pre,diff,overflow_val) { \
36 | if (cur < pre) { \
37 | diff = (overflow_val - pre) + 1 + cur; \
38 | } \
39 | else { \
40 | diff = cur - pre; \
41 | } \
42 | }
43 |
44 | #define PMWATCH_GET_BIT_VALUE(val, idx) (val >> idx) & 0x1
45 |
46 | #define MICRO_SEC 1000000
47 | #define MILL_SEC 1000
48 | #define SMALL_STR_LEN 128
49 | #define MEDIUM_STR_LEN 512
50 | #define LARGE_STR_LEN 1024
51 | #define CELCIUS_CONV_VAL 0.0625
52 | #define TEMP_SIGN_BIT_INDEX 15
53 | #define TEMP_VALUE_MASK 0x7FFF
54 | #define ROOT_UID 0
55 |
56 | #define HEALTH_INFO_VENDOR_SPECIFIC_DATA_SIZE 11
57 | #define HEALTH_STATUS_FATAL 2
58 | #define HEALTH_REASON_CRITICAL_INTERNAL_STATE 7
59 |
60 | #define NEGATIVE_POSITIVE_BIT_INDEX 15
61 |
62 | // error codes
63 | #define PMW_ERR_DLLLOAD 300
64 | #define PMW_ERR_DLLSYM 301
65 |
66 | /**
67 | * Convert an array of 8 unsigned chars into an unsigned 64 bit value
68 | * @remarks While it doesn't seem right to be casting 8 bit chars to unsigned long
69 | * long, this is an issue with gcc - see http:// gcc.gnu.org/bugzilla/show_bug.cgi?id=47821.
70 | */
71 | #define PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(arr, val) \
72 | val = ((unsigned long long)(arr[7] & 0xFF) << 56) + \
73 | ((unsigned long long)(arr[6] & 0xFF) << 48) + \
74 | ((unsigned long long)(arr[5] & 0xFF) << 40) + \
75 | ((unsigned long long)(arr[4] & 0xFF) << 32) + \
76 | ((unsigned long long)(arr[3] & 0xFF) << 24) + \
77 | ((unsigned long long)(arr[2] & 0xFF) << 16) + \
78 | ((unsigned long long)(arr[1] & 0xFF) << 8) + \
79 | (unsigned long long)(arr[0] & 0xFF);
80 |
81 | #define PMW_4_BYTE_ARRAY_TO_32_BIT_VALUE(arr, val) \
82 | val = ((unsigned long long)(arr[3] & 0xFF) << 24) + \
83 | ((unsigned long long)(arr[2] & 0xFF) << 16) + \
84 | ((unsigned long long)(arr[1] & 0xFF) << 8) + \
85 | (unsigned long long)(arr[0] & 0xFF);
86 |
87 | #define PMW_3_BYTE_ARRAY_TO_32_BIT_VALUE(arr, val) \
88 | val = ((unsigned long long)(arr[2] & 0xFF) << 16) + \
89 | ((unsigned long long)(arr[1] & 0xFF) << 8) + \
90 | (unsigned long long)(arr[0] & 0xFF);
91 |
92 | #define PMW_2_BYTE_ARRAY_TO_16_BIT_VALUE(arr, val) \
93 | val = ((unsigned long long)(arr[1] & 0xFF) << 8) + \
94 | (unsigned long long)(arr[0] & 0xFF);
95 |
96 | /**
97 | * Convert an unsigned 64 bit integer to an array of 8 unsigned chars
98 | */
99 | #define PMW_64_BIT_VALUE_TO_8_BYTE_ARRAY(val, arr) \
100 | arr[7] = (unsigned char)((val >> 56) & 0xFF); \
101 | arr[6] = (unsigned char)((val >> 48) & 0xFF); \
102 | arr[5] = (unsigned char)((val >> 40) & 0xFF); \
103 | arr[4] = (unsigned char)((val >> 32) & 0xFF); \
104 | arr[3] = (unsigned char)((val >> 24) & 0xFF); \
105 | arr[2] = (unsigned char)((val >> 16) & 0xFF); \
106 | arr[1] = (unsigned char)((val >> 8) & 0xFF); \
107 | arr[0] = (unsigned char)(val & 0xFF);
108 |
109 | #if defined(_WIN32)
110 |
111 | #include
112 | #include
113 |
114 | PMW_API uint64_t
115 | PMW_UTILS_Read_TSC();
116 |
117 | PMW_API HANDLE
118 | PMW_UTILS_DLL_Open ();
119 |
120 | PMW_API void*
121 | PMW_UTILS_DLL_Sym (
122 | HANDLE handle,
123 | const char *symbol
124 | );
125 |
126 | PMW_API NVM_UINT32
127 | PMW_UTILS_DLL_Close (
128 | HANDLE handle
129 | );
130 |
131 | #else
132 |
133 | extern PMW_API uint64_t
134 | PMW_UTILS_Read_TSC();
135 |
136 | #endif
137 |
138 | PMW_API NVM_UINT32
139 | PMW_UTILS_Strncpy_Safe (
140 | char *dst,
141 | size_t dst_size,
142 | const char *src
143 | );
144 |
145 | PMW_API NVM_UINT32
146 | PMW_UTILS_Strncat_Safe(
147 | char *dst,
148 | size_t dst_size,
149 | const char *src
150 | );
151 |
152 | PMW_API void
153 | PMW_UTILS_Cal_Diff (
154 | const LIFETIME_INFO_COUNTER diff,
155 | const LIFETIME_INFO_COUNTER pre,
156 | const LIFETIME_INFO_COUNTER cur
157 | );
158 |
159 | PMW_API uint64_t
160 | PMW_UTILS_Get_Curr_Time_For_Sleep ();
161 |
162 | PMW_API uint64_t
163 | PMW_UTILS_Get_Curr_Time_In_Sec ();
164 |
165 | PMW_API void
166 | PMW_UTILS_Print_Key (const char* format, ... );
167 |
168 | PMW_API void
169 | PMW_UTILS_Print_Value (const char* format, ... );
170 |
171 | void
172 | PMW_UTILS_Sleep (uint64_t sleep_time);
173 |
174 | #endif
--------------------------------------------------------------------------------
/src/inc/pmw_version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #ifndef _PMW_VERSION_H_INC_
27 | #define _PMW_VERSION_H_INC_
28 |
29 | #define _STRINGIFY(x) #x
30 | #define STRINGIFY(x) _STRINGIFY(x)
31 |
32 | #define PRODUCT_NAME "Intel(R) PMWatch"
33 |
34 | #define MAJOR_VERSION 3
35 | #define MINOR_VERSION 2
36 | #define UPDATE_VERSION 1
37 | #if UPDATE_VERSION > 0
38 | #define UPDATE_STRING " Update "STRINGIFY(UPDATE_VERSION)
39 | #else
40 | #define UPDATE_STRING ""
41 | #endif
42 |
43 | #define ENG_BUILD ""
44 |
45 | #define OUTPUT_FORMAT_MAJOR_VERSION 1
46 | #define OUTPUT_FORMAT_MINOR_VERSION 0
47 |
48 | #define PRODUCT_TYPE "public"
49 |
50 | #define PRODUCT_TYPE_STR " ("PRODUCT_TYPE")"
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/src/pmw_api.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include "nvm_types.h"
34 | #include "pmw_collect.h"
35 |
36 | #ifndef _WIN32
37 |
38 | /* ------------------------------------------------------------------------- */
39 | /*!
40 | * @fn int PMWAPIGetDIMMCount (
41 | * int *num_nvdimms
42 | * )
43 | *
44 | * @brief function to obtain the number of DCPMM DIMMs
45 | *
46 | * @param OUT num_nvdimms: number of DCPMM DIMMs
47 | *
48 | * @return 0 if successful
49 | *
50 | * Special Notes:
51 | *
52 | */
53 | int
54 | PMWAPIGetDIMMCount (
55 | int *num_nvdimms
56 | )
57 | {
58 | return PMW_COLLECT_Get_DIMM_Count(num_nvdimms);
59 | }
60 |
61 | /* ------------------------------------------------------------------------- */
62 | /*!
63 | * @fn int PMWAPIStart (
64 | * PMWATCH_CONFIG_NODE pmwatch_config
65 | * )
66 | *
67 | * @brief function to start the collection
68 | *
69 | * @param IN pmwatch_config: struct that provides collection configuration
70 | *
71 | * @return 0 if successful
72 | *
73 | * Special Notes:
74 | *
75 | */
76 | int
77 | PMWAPIStart (
78 | PMWATCH_CONFIG_NODE pmwatch_config
79 | )
80 | {
81 | return PMW_COLLECT_Start_Collection(pmwatch_config);
82 | }
83 |
84 | /* ------------------------------------------------------------------------- */
85 | /*!
86 | * @fn int PMWAPIStop ()
87 | *
88 | * @brief function to stop the collection
89 | *
90 | * @param None
91 | *
92 | * @return 0 if successful
93 | *
94 | * Special Notes:
95 | *
96 | */
97 | int
98 | PMWAPIStop ()
99 | {
100 | return PMW_COLLECT_Stop_Collection();
101 | }
102 |
103 | /* ------------------------------------------------------------------------- */
104 | /*!
105 | * @fn int PMWAPIRead (
106 | * PMWATCH_OP_BUF* op_buf
107 | * )
108 | *
109 | * @brief function to obtain the metrics count
110 | *
111 | * @param OUT op_buf: output buffer
112 | *
113 | * @return 0 if successful
114 | *
115 | * Special Notes:
116 | *
117 | */
118 | int
119 | PMWAPIRead (
120 | PMWATCH_OP_BUF* op_buf
121 | )
122 | {
123 | return PMW_COLLECT_Read_Data(op_buf);
124 | }
125 |
126 | #endif
127 |
--------------------------------------------------------------------------------
/src/pmw_collect.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #ifdef _WIN32
34 | #define PMW_DLL_EXPORTS 1
35 | #else
36 | #include
37 | #include
38 | #endif
39 |
40 | #include "nvm_types.h"
41 | #include "nvm_management.h"
42 |
43 | #include "inc/pmw_utils.h"
44 | #include "inc/pmw_version.h"
45 | #include "inc/pmw_comm.h"
46 | #include "inc/pmw_collect.h"
47 |
48 | FILE *fout;
49 | int loops = 0, infinite_run = 0;
50 | uint64_t usec_sample_time, usec_sample_time_prev;
51 | int collect_lifetime = 0;
52 | char DELIMITER[] = ";";
53 | int output_format_one = 1;
54 | int output_format_two = 0;
55 | int collect_health = 0;
56 | char *filename;
57 | #ifndef _WIN32
58 | pthread_t thread_id;
59 | int using_api = 0;
60 | static int write_count = 0;
61 | static int collection_done = 0;
62 | static int thread_status = 0;
63 | PMWATCH_OP_BUF output_buf = NULL;
64 | pthread_mutex_t buffer_lock;
65 | #endif
66 |
67 | NVM_UINT32
68 | PMW_COLLECT_Set_Global_Vars (
69 | FILE *l_fout,
70 | int l_loops,
71 | int l_infinite_run,
72 | uint64_t l_usec_sample_time,
73 | uint64_t l_usec_sample_time_prev,
74 | int l_collect_lifetime,
75 | int l_output_format_one,
76 | int l_output_format_two,
77 | int l_collect_health,
78 | char *l_delim
79 | )
80 | {
81 | NVM_UINT32 ret_val = NVM_SUCCESS;
82 |
83 | fout = l_fout;
84 | loops = l_loops;
85 | infinite_run = l_infinite_run;
86 | usec_sample_time = l_usec_sample_time;
87 | usec_sample_time_prev = l_usec_sample_time_prev;
88 | collect_lifetime = l_collect_lifetime;
89 | output_format_one = l_output_format_one;
90 | output_format_two = l_output_format_two;
91 | collect_health = l_collect_health;
92 |
93 | ret_val = STRNCPY_SAFE(DELIMITER, sizeof(DELIMITER), l_delim);
94 |
95 | return ret_val;
96 | }
97 |
98 | void print_header_format_one (
99 | int count
100 | )
101 | {
102 | int i;
103 |
104 | // 1st header
105 | fprintf(fout, "timestamp%s%s", DELIMITER, DELIMITER);
106 | for (i = 0; i < count; i++){
107 | fprintf(fout, "DIMM%d%s%s%s%s%s%s%s%s%s%s", i, DELIMITER, DELIMITER, \
108 | DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER);
109 | }
110 | fprintf(fout, "\n");
111 | fflush(fout);
112 |
113 | // 2nd header
114 | fprintf(fout, "epoch%stimestamp%s", DELIMITER, DELIMITER);
115 | for (i = 0; i < count; i++){
116 | fprintf(fout, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
117 | "bytes_read (derived)",
118 | DELIMITER,
119 | "bytes_written (derived)",
120 | DELIMITER,
121 | "read_hit_ratio (derived)",
122 | DELIMITER,
123 | "write_hit_ratio (derived)",
124 | DELIMITER,
125 | "media_read_ops (derived)",
126 | DELIMITER,
127 | "media_write_ops (derived)",
128 | DELIMITER,
129 | "read_64B_ops_received",
130 | DELIMITER,
131 | "write_64B_ops_received",
132 | DELIMITER,
133 | "cpu_read_ops",
134 | DELIMITER,
135 | "cpu_write_ops",
136 | DELIMITER
137 | );
138 | }
139 | fprintf(fout, "\n");
140 | fflush(fout);
141 | }
142 |
143 | void print_header_format_two (
144 | int count
145 | )
146 | {
147 | struct device_discovery *lp_DIMM_devices;
148 | int num_packages, itr_p, itr_d;
149 |
150 | lp_DIMM_devices = PMW_COMM_Get_DIMM_Topology();
151 |
152 | // get the total number of packages
153 | num_packages = lp_DIMM_devices[count - 1].socket_id;
154 | ++num_packages;
155 |
156 | // header level 1
157 | fprintf(fout, "timestamp%s%s", DELIMITER, DELIMITER);
158 | for (itr_p = 0; itr_p < num_packages; itr_p++) {
159 | for (itr_d = 0; itr_d < count; itr_d++) {
160 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
161 | fprintf(fout, "Package%d%sPackage%d%sPackage%d%sPackage%d%s", itr_p, DELIMITER, \
162 | itr_p, DELIMITER, itr_p, DELIMITER, itr_p, DELIMITER);
163 | }
164 | }
165 | for (itr_d = 0; itr_d < count; itr_d++) {
166 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
167 | fprintf(fout, "Package%d%sPackage%d%s", itr_p, DELIMITER, \
168 | itr_p, DELIMITER);
169 | }
170 |
171 | }
172 | for (itr_d = 0; itr_d < count; itr_d++) {
173 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
174 | fprintf(fout, "Package%d%sPackage%d%s", itr_p, DELIMITER, \
175 | itr_p, DELIMITER);
176 | }
177 | }
178 | for (itr_d = 0; itr_d < count; itr_d++) {
179 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
180 | fprintf(fout, "Package%d%sPackage%d%s", itr_p, DELIMITER, itr_p, DELIMITER);
181 | }
182 | }
183 | }
184 | fprintf(fout, "\n");
185 | fflush(fout);
186 |
187 | // header level 2
188 | fprintf(fout, "%s%s", DELIMITER, DELIMITER);
189 | for (itr_p = 0; itr_p < num_packages; itr_p++) {
190 | for (itr_d = 0; itr_d < count; itr_d++) {
191 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
192 | fprintf(fout, "Media%sMedia%sMedia%sMedia%s", DELIMITER, \
193 | DELIMITER, DELIMITER, DELIMITER);
194 | }
195 | }
196 | for (itr_d = 0; itr_d < count; itr_d++) {
197 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
198 | fprintf(fout, "Buffer%sBuffer%s", DELIMITER, \
199 | DELIMITER);
200 | }
201 | }
202 | for (itr_d = 0; itr_d < count; itr_d++) {
203 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
204 | fprintf(fout, "Controller%sController%s", DELIMITER, DELIMITER);
205 | }
206 | }
207 | for (itr_d = 0; itr_d < count; itr_d++) {
208 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
209 | fprintf(fout, "CPU%sCPU%s", DELIMITER, DELIMITER);
210 | }
211 | }
212 | }
213 | fprintf(fout, "\n");
214 | fflush(fout);
215 |
216 | //header level 3
217 | fprintf(fout, "epoch%stimestamp%s", DELIMITER, DELIMITER);
218 | for (itr_p = 0; itr_p < num_packages; itr_p++) {
219 | for (itr_d = 0; itr_d < count; itr_d++) {
220 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
221 | fprintf(fout, "DIMM%d%sDIMM%d%sDIMM%d%sDIMM%d%s", itr_d, DELIMITER, itr_d, DELIMITER, \
222 | itr_d, DELIMITER, itr_d, DELIMITER);
223 | }
224 | }
225 | for (itr_d = 0; itr_d < count; itr_d++) {
226 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
227 | fprintf(fout, "DIMM%d%sDIMM%d%s", itr_d, DELIMITER, itr_d, DELIMITER);
228 | }
229 | }
230 | for (itr_d = 0; itr_d < count; itr_d++) {
231 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
232 | fprintf(fout, "DIMM%d%sDIMM%d%s", itr_d, DELIMITER, itr_d, DELIMITER);
233 | }
234 | }
235 | for (itr_d = 0; itr_d < count; itr_d++) {
236 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
237 | fprintf(fout, "DIMM%d%sDIMM%d%s", itr_d, DELIMITER, itr_d, DELIMITER);
238 | }
239 | }
240 | }
241 | fprintf(fout, "\n");
242 | fflush(fout);
243 |
244 | //header level 4
245 | fprintf(fout, "%s%s", DELIMITER, DELIMITER);
246 | for (itr_p = 0; itr_p < num_packages; itr_p++) {
247 | for (itr_d = 0; itr_d < count; itr_d++) {
248 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
249 | fprintf(fout, "bytes_read (derived)%sbytes_written (derived)%smedia_read_ops (derived)%smedia_write_ops (derived)%s", \
250 | DELIMITER, DELIMITER, DELIMITER, DELIMITER);
251 | }
252 | }
253 | for (itr_d = 0; itr_d < count; itr_d++) {
254 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
255 | fprintf(fout, "read_hit_ratio (derived)%swrite_hit_ratio (derived)%s", DELIMITER, DELIMITER);
256 | }
257 | }
258 | for (itr_d = 0; itr_d < count; itr_d++) {
259 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
260 | fprintf(fout, "read_64B_ops_received%swrite_64B_ops_received%s", \
261 | DELIMITER, DELIMITER);
262 | }
263 | }
264 | for (itr_d = 0; itr_d < count; itr_d++) {
265 | if (itr_p == lp_DIMM_devices[itr_d].socket_id) {
266 | fprintf(fout, "cpu_read_ops%scpu_write_ops%s", DELIMITER, DELIMITER);
267 | }
268 | }
269 | }
270 | fprintf(fout, "\n");
271 | fflush(fout);
272 | }
273 |
274 | void print_header_health_info (
275 | int count
276 | )
277 | {
278 | int i;
279 |
280 | // 1st header
281 | fprintf(fout, "timestamp%s%s", DELIMITER, DELIMITER);
282 | for (i = 0; i < count; i++){
283 | fprintf(fout, "DIMM%d%s%s%s%s%s%s%s%s%s%s", i, DELIMITER, DELIMITER, \
284 | DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER, DELIMITER);
285 | }
286 | fprintf(fout, "\n");
287 | fflush(fout);
288 |
289 | // 2nd header
290 | fprintf(fout, "epoch%stimestamp%s", DELIMITER, DELIMITER);
291 | for (i = 0; i < count; i++){
292 | fprintf(fout, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
293 | "health_status",
294 | DELIMITER,
295 | "lifespan_used",
296 | DELIMITER,
297 | "lifespan_remaining",
298 | DELIMITER,
299 | "power_on_time",
300 | DELIMITER,
301 | "uptime",
302 | DELIMITER,
303 | "last_shutdown_time",
304 | DELIMITER,
305 | "media_temp",
306 | DELIMITER,
307 | "controller_temp",
308 | DELIMITER,
309 | "max_media_temp",
310 | DELIMITER,
311 | "max_controller_temp",
312 | DELIMITER
313 | );
314 | }
315 | fprintf(fout, "\n");
316 | fflush(fout);
317 | }
318 |
319 | void print_info_header ()
320 | {
321 | time_t t;
322 | struct tm *local_time;
323 |
324 | // print version and collection time
325 | fprintf(fout, "# Collector: %s v%d.%d.%d\n", PRODUCT_NAME, MAJOR_VERSION, MINOR_VERSION, UPDATE_VERSION);
326 | fprintf(fout, "# Output Format: v%d.%d\n", OUTPUT_FORMAT_MAJOR_VERSION, OUTPUT_FORMAT_MINOR_VERSION);
327 | t = time(NULL);
328 | local_time = localtime(&t);
329 | if (local_time != NULL) {
330 | fprintf(fout, "# Collected on %s", asctime(local_time));
331 | }
332 | if (output_format_one) {
333 | fprintf(fout, "# Default Format\n");
334 | }
335 | else if (output_format_two) {
336 | fprintf(fout, "# Metric Grouping Format\n");
337 | }
338 |
339 | // configuration to calculate avergae value in csv viewer
340 | if (collect_health) {
341 | fprintf(fout, "%s: %s, %s, %s, %s, %s, %s, %s, %s, %s, %s", \
342 | "# Avg column", \
343 | "health_status", \
344 | "lifespan_used", \
345 | "lifespan_remaining", \
346 | "power_on_time", \
347 | "uptime", \
348 | "last_shutdown_time", \
349 | "media_temp", \
350 | "controller_temp", \
351 | "max_media_temp", \
352 | "max_controller_temp" \
353 | );
354 | }
355 | else {
356 | fprintf(fout, "# Avg column: read_hit_ratio (derived), write_hit_ratio (derived)");
357 | }
358 | fprintf(fout, "\n");
359 | }
360 |
361 | int adjust_for_overhead (
362 | int i,
363 | uint64_t elapsed_time,
364 | int *num_skips
365 | )
366 | {
367 | int itr = 0;
368 | int sample_time_sec_prev, sample_time_sec, elapsed_time_sec, temp_operand, loops_left;
369 |
370 | #ifdef _WIN32
371 | temp_operand = (int) MILL_SEC;
372 | #else
373 | temp_operand = (int) MICRO_SEC;
374 | #endif
375 |
376 | while (elapsed_time > usec_sample_time) {
377 | usec_sample_time = usec_sample_time * 2;
378 | ++itr;
379 |
380 | elapsed_time_sec = (float) elapsed_time / temp_operand;
381 | sample_time_sec_prev = (float) usec_sample_time_prev / temp_operand;
382 |
383 | if (i + itr > loops && !infinite_run) {
384 | fprintf(stderr, "\nERROR: The collection overhead is more than the remaining time for the run.\n");
385 | fprintf(stderr, " This system has substantial overhead during collection. Use a minimum sampling time of %d sec. Exiting...\n", \
386 | elapsed_time_sec + 1);
387 | return 1;
388 | }
389 | }
390 |
391 | sample_time_sec = (int) usec_sample_time / temp_operand;
392 |
393 | if (usec_sample_time != usec_sample_time_prev) {
394 | // calculate skipped loops and loops left
395 | if (!infinite_run) {
396 | // loops left with new sampling time: (number of loops left times previous sampling time) / new sampling time
397 | loops_left = ((loops - i) * sample_time_sec_prev) / sample_time_sec;
398 | // [ number of loops left] - loops_left gives the num_skips
399 | *num_skips += (loops - i) - loops_left;
400 | // total number of loops
401 | loops = i + loops_left;
402 | }
403 | if (!infinite_run && loops_left == 0) {
404 | fprintf(stderr, "\nERROR: The collection overhead is more than the remaining time for the run.\n");
405 | fprintf(stderr, " This system has substantial overhead during collection. Use a minimum sampling time of %d sec. Exiting...\n", \
406 | elapsed_time_sec + 1);
407 | }
408 | else {
409 | fprintf(stderr, "\nWARNING: The collection overhead (%d sec) is more than the sampling time.\n", elapsed_time_sec);
410 | fprintf(stderr, " Updating the collection time from %d sec to %d sec\n", sample_time_sec_prev, sample_time_sec);
411 | }
412 | usec_sample_time_prev = usec_sample_time;
413 | }
414 |
415 | return 0;
416 | }
417 |
418 | int
419 | PMW_COLLECT_Print_Smart_Counters ()
420 | {
421 | int i, j, itr_p, itr_m, itr_d, num_packages, num_skips = 0, ret_code = 0;
422 | unsigned int count;
423 | unsigned char page_num;
424 | uint64_t pre_tsc, cur_tsc, delta_tsc, start_time, cur_time, elapsed_time, sleep_time, epoch;
425 | uint64_t total_bytes_read, total_bytes_written, media_read, media_write, media_write_adjusted;
426 | double read_hit_ratio, write_hit_ratio;
427 | struct device_discovery *lp_DIMM_devices;
428 |
429 | uint64_t overflow_val = 0xFFFFFFFFFFFFFFFFULL;
430 |
431 | lp_DIMM_devices = PMW_COMM_Get_DIMM_Topology();
432 |
433 | i = 0;
434 | j = 0;
435 | pre_tsc = 0ULL;
436 | cur_tsc = 0ULL;
437 | delta_tsc = 0ULL;
438 | page_num = 1;
439 | PMW_COMM_Get_Number_of_DIMM(&count);
440 |
441 | #ifndef _WIN32
442 | if (using_api) {
443 | output_buf = (PMWATCH_OP_BUF) calloc (count, sizeof(PMWATCH_OP_BUF_NODE));
444 | if (output_buf == NULL) {
445 | fprintf(stderr, "ERROR: memory allocation failed!\n");
446 |
447 | return 1;
448 | }
449 | }
450 | #endif
451 |
452 | // get the total number of packages
453 | num_packages = lp_DIMM_devices[count - 1].socket_id;
454 | ++num_packages;
455 |
456 | LIFETIME_INFO_COUNTER sample1 = (LIFETIME_INFO_COUNTER)calloc(count, sizeof(LIFETIME_INFO_COUNTER_NODE));
457 | LIFETIME_INFO_COUNTER sample2 = (LIFETIME_INFO_COUNTER)calloc(count, sizeof(LIFETIME_INFO_COUNTER_NODE));
458 | LIFETIME_INFO_COUNTER diff = (LIFETIME_INFO_COUNTER)calloc(count, sizeof(LIFETIME_INFO_COUNTER_NODE));
459 | if (!sample1 || !sample2 || !diff) {
460 | fprintf(stderr, "ERROR: memory allocation failed!\n");
461 | free(sample1);
462 | free(sample2);
463 | free(diff);
464 | #ifndef _WIN32
465 | if (using_api) {
466 | free(output_buf);
467 | }
468 | #endif
469 |
470 | return 1;
471 | }
472 | LIFETIME_INFO_COUNTER pre_sample[count];
473 | LIFETIME_INFO_COUNTER cur_sample[count];
474 |
475 | print_info_header();
476 |
477 | // print header
478 | if (output_format_one) {
479 | print_header_format_one(count);
480 | }
481 | else {
482 | print_header_format_two(count);
483 | }
484 |
485 | for (j = 0; j < count; j++){
486 | pre_sample[j] = &sample1[j];
487 | cur_sample[j] = &sample2[j];
488 | }
489 | for (i = 0; i <= loops || infinite_run; i++){
490 | if (i == 0) {
491 | start_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
492 |
493 | pre_tsc = PMW_UTILS_Read_TSC();
494 |
495 | // get count from all SMART counters
496 | for (j = 0; j < count; j++){
497 | ret_code = PMW_COMM_Get_Memory_Info_Page(j, pre_sample[j], page_num);
498 | if ( ret_code != NVM_SUCCESS) {
499 | #ifndef _WIN32
500 | if (!using_api) {
501 | #endif
502 | fprintf(stderr, "\nSomething went wrong while collecting metrics.\n");
503 | #ifndef _WIN32
504 | }
505 | #endif
506 | goto cleanup;
507 | }
508 | }
509 | // sleep for sample time
510 | cur_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
511 | elapsed_time = cur_time - start_time;
512 |
513 | ret_code = adjust_for_overhead(i, elapsed_time, &num_skips);
514 | if (ret_code != 0) {
515 | goto cleanup;
516 | }
517 |
518 | sleep_time = usec_sample_time - elapsed_time;
519 |
520 | PMW_UTILS_Sleep(sleep_time);
521 |
522 | continue;
523 | }
524 |
525 | cur_tsc = PMW_UTILS_Read_TSC();
526 |
527 | CALCULATE_DIFFERENCE(cur_tsc, pre_tsc, delta_tsc, overflow_val);
528 |
529 | epoch = PMW_UTILS_Get_Curr_Time_In_Sec();
530 | fprintf(fout,"%" PRIu64 "%s%" PRIu64 "%s", epoch, DELIMITER, delta_tsc, DELIMITER);
531 |
532 | start_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
533 |
534 | #ifndef _WIN32
535 | if (using_api) {
536 | pthread_mutex_lock(&buffer_lock);
537 | }
538 | #endif
539 |
540 | for (j = 0; j < count; j++){
541 | #ifndef _WIN32
542 | if (using_api) {
543 | output_buf[j].timestamp = delta_tsc;
544 | output_buf[j].epoch = epoch;
545 | }
546 | #endif
547 |
548 | // get count from all SMART counters after sleep
549 | ret_code = PMW_COMM_Get_Memory_Info_Page(j, cur_sample[j], page_num);
550 | if ( ret_code != NVM_SUCCESS) {
551 | #ifndef _WIN32
552 | if (using_api) {
553 | pthread_mutex_unlock(&buffer_lock);
554 | }
555 | else {
556 | #endif
557 | fprintf(stderr, "\nSomething went wrong while collecting metrics.\n");
558 | #ifndef _WIN32
559 | }
560 | #endif
561 | goto cleanup;
562 | }
563 |
564 | // get the difference of before and after sleep count
565 | PMW_UTILS_Cal_Diff(&diff[j], pre_sample[j], cur_sample[j]);
566 |
567 | if (output_format_one) {
568 | // calculate derived output metrics
569 |
570 | // bytes_read less than bytes_written results in negative value for total_bytes_read/media_read
571 | // providing "0" value to avoid displaying bogus negative value in this scenario
572 | if (diff[j].bytes_read > diff[j].bytes_written) {
573 | total_bytes_read = (diff[j].bytes_read - diff[j].bytes_written) * 64;
574 | media_read = (diff[j].bytes_read - diff[j].bytes_written) / 4;
575 | }
576 | else {
577 | total_bytes_read = 0ULL;
578 | media_read = 0ULL;
579 | }
580 | total_bytes_written = diff[j].bytes_written * 64;
581 | media_write = diff[j].bytes_written / 4;
582 |
583 | // calculating read and write hit ratio
584 | if (diff[j].host_reads > media_read) {
585 | double opr_01 = (double) diff[j].host_reads - media_read;
586 | read_hit_ratio = (double) opr_01 / diff[j].host_reads;
587 | }
588 | else {
589 | read_hit_ratio = 0;
590 | }
591 | if (diff[j].host_writes > media_write) {
592 | double opr_02 = (double) diff[j].host_writes - media_write;
593 | write_hit_ratio = (double) opr_02 / diff[j].host_writes;
594 | }
595 | else {
596 | write_hit_ratio = 0;
597 | }
598 |
599 | // print counts
600 | fprintf(fout, "%" PRIu64 "%s%" PRIu64 "%s%.2lf%s%.2lf%s%" PRIu64 "%s%" PRIu64 "%s%" \
601 | PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s",
602 | total_bytes_read,
603 | DELIMITER,
604 | total_bytes_written,
605 | DELIMITER,
606 | read_hit_ratio,
607 | DELIMITER,
608 | write_hit_ratio,
609 | DELIMITER,
610 | media_read,
611 | DELIMITER,
612 | media_write,
613 | DELIMITER,
614 | diff[j].bytes_read,
615 | DELIMITER,
616 | diff[j].bytes_written,
617 | DELIMITER,
618 | diff[j].host_reads,
619 | DELIMITER,
620 | diff[j].host_writes,
621 | DELIMITER
622 | );
623 |
624 | #ifndef _WIN32
625 | if (using_api) {
626 | output_buf[j].total_bytes_read = total_bytes_read;
627 | output_buf[j].total_bytes_written = total_bytes_written;
628 | output_buf[j].read_hit_ratio = read_hit_ratio;
629 | output_buf[j].write_hit_ratio = write_hit_ratio;
630 | output_buf[j].media_read = media_read;
631 | output_buf[j].media_write = media_write;
632 | output_buf[j].bytes_read = diff[j].bytes_read;
633 | output_buf[j].bytes_written = diff[j].bytes_written;
634 | output_buf[j].host_reads = diff[j].host_reads;
635 | output_buf[j].host_writes = diff[j].host_writes;
636 | }
637 | #endif
638 |
639 | #ifdef BUILD_DEBUG
640 | #ifndef _WIN32
641 | fprintf(fout, "%" PRIu64 "%s%.2lf%s%.2lf%s%.2lf%s%" PRIu64 "%s%" PRIu64 "%s%" \
642 | PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s",
643 | output_buf[j].total_bytes_read,
644 | DELIMITER,
645 | output_buf[j].total_bytes_written,
646 | DELIMITER,
647 | output_buf[j].read_hit_ratio,
648 | DELIMITER,
649 | output_buf[j].write_hit_ratio,
650 | DELIMITER,
651 | output_buf[j].media_read,
652 | DELIMITER,
653 | output_buf[j].media_write,
654 | DELIMITER,
655 | output_buf[j].bytes_read,
656 | DELIMITER,
657 | output_buf[j].bytes_written,
658 | DELIMITER,
659 | output_buf[j].host_reads,
660 | DELIMITER,
661 | output_buf[j].host_writes,
662 | DELIMITER
663 | );
664 | #endif
665 | #endif
666 | }
667 |
668 | //switch pointers for pre and cur smt_counter samples
669 | if (pre_sample[j] == &sample1[j]) {
670 | pre_sample[j] = &sample2[j];
671 | cur_sample[j] = &sample1[j];
672 | }
673 | else {
674 | pre_sample[j] = &sample1[j];
675 | cur_sample[j] = &sample2[j];
676 | }
677 | }
678 |
679 | #ifndef _WIN32
680 | if (using_api) {
681 | ++write_count;
682 | pthread_mutex_unlock(&buffer_lock);
683 | }
684 | #endif
685 |
686 | if (output_format_two) {
687 | for (itr_p = 0; itr_p < num_packages; itr_p++) {
688 | for (itr_m = 0; itr_m < 4; itr_m++) {
689 | for (itr_d = 0; itr_d < count; itr_d++) {
690 | // calculate derived output metrics
691 |
692 | if (itr_p != lp_DIMM_devices[itr_d].socket_id) {
693 | continue;
694 | }
695 |
696 | if (itr_m == 0) {
697 | // bytes_read less than bytes_written results in negative value for total_bytes_read/media_read
698 | // providing "0" value to avoid displaying bogus negative value in this scenario
699 | if (diff[itr_d].bytes_read > diff[itr_d].bytes_written) {
700 | total_bytes_read = (diff[itr_d].bytes_read - diff[itr_d].bytes_written) * 64;
701 | media_read = (diff[itr_d].bytes_read - diff[itr_d].bytes_written) / 4;
702 | }
703 | else {
704 | total_bytes_read = 0ULL;
705 | media_read = 0ULL;
706 | }
707 | total_bytes_written = diff[itr_d].bytes_written * 64;
708 | media_write = diff[itr_d].bytes_written / 4;
709 |
710 | // print media metrics' counts
711 | fprintf(fout, "%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s",
712 | total_bytes_read,
713 | DELIMITER,
714 | total_bytes_written,
715 | DELIMITER,
716 | media_read,
717 | DELIMITER,
718 | media_write,
719 | DELIMITER
720 | );
721 | }
722 | else if (itr_m == 1) {
723 | // calculate media_read and media_write again
724 | if (diff[itr_d].bytes_read > diff[itr_d].bytes_written) {
725 | media_read = (diff[itr_d].bytes_read - diff[itr_d].bytes_written) / 4;
726 | }
727 | else {
728 | media_read = 0ULL;
729 | }
730 | media_write = diff[itr_d].bytes_written / 4;
731 |
732 | // calculating read and write hit ratio
733 | if (diff[itr_d].host_reads > media_read) {
734 | double opr_01 = (double) diff[itr_d].host_reads - media_read;
735 | read_hit_ratio = (double) opr_01 / diff[itr_d].host_reads;
736 | }
737 | else {
738 | read_hit_ratio = 0;
739 | }
740 | if (diff[itr_d].host_writes > media_write) {
741 | double opr_02 = (double) diff[itr_d].host_writes - media_write;
742 | write_hit_ratio = (double) opr_02 / diff[itr_d].host_writes;
743 | }
744 | else {
745 | write_hit_ratio = 0;
746 | }
747 |
748 | // print buffer metrics' counts
749 | fprintf(fout, "%.2lf%s%.2lf%s",
750 | read_hit_ratio,
751 | DELIMITER,
752 | write_hit_ratio,
753 | DELIMITER
754 | );
755 | }
756 | else if (itr_m == 2) {
757 | // print controller metrics' counts
758 | fprintf(fout, "%" PRIu64 "%s%" PRIu64 "%s",
759 | diff[itr_d].bytes_read,
760 | DELIMITER,
761 | diff[itr_d].bytes_written,
762 | DELIMITER
763 | );
764 | }
765 | else if (itr_m == 3) {
766 | // print CPU metrics' counts
767 | fprintf(fout, "%" PRIu64 "%s%" PRIu64 "%s",
768 | diff[itr_d].host_reads,
769 | DELIMITER,
770 | diff[itr_d].host_writes,
771 | DELIMITER
772 | );
773 | }
774 | }
775 | }
776 | }
777 | }
778 |
779 | fprintf(fout,"\n");
780 | fflush(fout);
781 |
782 | pre_tsc = cur_tsc;
783 | cur_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
784 | elapsed_time = cur_time - start_time;
785 |
786 | ret_code = adjust_for_overhead(i, elapsed_time, &num_skips);
787 | if (ret_code != 0) {
788 | goto cleanup;
789 | }
790 |
791 | sleep_time = usec_sample_time - elapsed_time;
792 |
793 | PMW_UTILS_Sleep(sleep_time);
794 | }
795 |
796 | cleanup:
797 | free(sample1);
798 | free(sample2);
799 | free(diff);
800 |
801 | #ifndef _WIN32
802 | if (using_api) {
803 | pthread_mutex_lock(&buffer_lock);
804 | collection_done = 1;
805 | pthread_mutex_unlock(&buffer_lock);
806 | }
807 | #endif
808 |
809 | if (num_skips) {
810 | fprintf(fout, "%d interval(s) skipped.\n", num_skips);
811 | }
812 |
813 | return ret_code;
814 | }
815 |
816 | int
817 | PMW_COLLECT_Print_Health_Info (
818 | )
819 | {
820 | int i, j, k, t, num_packages, num_skips = 0, ret_code = 0;
821 | unsigned int count;
822 | uint64_t pre_tsc, cur_tsc, delta_tsc, start_time, cur_time, elapsed_time, sleep_time, epoch;
823 | struct device_discovery *lp_DIMM_devices;
824 | int temp_val = 0;
825 | char media_temp[SMALL_STR_LEN], controller_temp[SMALL_STR_LEN], max_media_temp[SMALL_STR_LEN], max_controller_temp[SMALL_STR_LEN];
826 | double media_temp_d, controller_temp_d, max_media_temp_d, max_controller_temp_d;
827 |
828 | uint64_t overflow_val = 0xFFFFFFFFFFFFFFFFULL;
829 |
830 | lp_DIMM_devices = PMW_COMM_Get_DIMM_Topology();
831 |
832 | i = 0;
833 | j = 0;
834 | pre_tsc = 0ULL;
835 | cur_tsc = 0ULL;
836 | delta_tsc = 0ULL;
837 | PMW_COMM_Get_Number_of_DIMM(&count);
838 |
839 | #ifndef _WIN32
840 | if (using_api) {
841 | output_buf = (PMWATCH_OP_BUF) calloc (count, sizeof(PMWATCH_OP_BUF_NODE));
842 | if (output_buf == NULL) {
843 | fprintf(stderr, "ERROR: memory allocation failed!\n");
844 |
845 | return 1;
846 | }
847 | }
848 | #endif
849 |
850 | // get the total number of packages
851 | num_packages = lp_DIMM_devices[count - 1].socket_id;
852 | ++num_packages;
853 |
854 | HEALTH_INFO_COUNTER sample = (HEALTH_INFO_COUNTER)calloc(count, sizeof(HEALTH_INFO_COUNTER_NODE));
855 | if (sample == NULL) {
856 | fprintf(stderr, "ERROR: memory allocation failed!\n");
857 | #ifndef _WIN32
858 | if (using_api) {
859 | free(output_buf);
860 | }
861 | #endif
862 |
863 | return 1;
864 | }
865 | HEALTH_INFO_COUNTER health_info[count];
866 |
867 | print_info_header();
868 |
869 | print_header_health_info(count);
870 |
871 | for (i = 0; i < count; i++) {
872 | health_info[i] = &sample[i];
873 | }
874 |
875 | for (i = 0; i <= loops || infinite_run; i++){
876 | if (i == 0) {
877 | start_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
878 |
879 | pre_tsc = PMW_UTILS_Read_TSC();
880 |
881 | cur_time = start_time;
882 | elapsed_time = cur_time - start_time;
883 |
884 | ret_code = adjust_for_overhead(i, elapsed_time, &num_skips);
885 | if (ret_code != 0) {
886 | goto cleanup;
887 | }
888 |
889 | sleep_time = usec_sample_time - elapsed_time;
890 |
891 | PMW_UTILS_Sleep(sleep_time);
892 |
893 | continue;
894 | }
895 |
896 | cur_tsc = PMW_UTILS_Read_TSC();
897 |
898 | CALCULATE_DIFFERENCE(cur_tsc, pre_tsc, delta_tsc, overflow_val);
899 |
900 | epoch = PMW_UTILS_Get_Curr_Time_In_Sec();
901 | fprintf(fout,"%" PRIu64 "%s%" PRIu64 "%s", epoch, DELIMITER, delta_tsc, DELIMITER);
902 |
903 | start_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
904 |
905 | #ifndef _WIN32
906 | if (using_api) {
907 | pthread_mutex_lock(&buffer_lock);
908 | }
909 | #endif
910 |
911 | for (j = 0; j < count; j++) {
912 | #ifndef _WIN32
913 | if (using_api) {
914 | output_buf[j].timestamp = delta_tsc;
915 | output_buf[j].epoch = epoch;
916 | }
917 | #endif
918 |
919 | ret_code = PMW_COMM_Get_Health_Info_Page(j, health_info[j]);
920 | if ( ret_code != NVM_SUCCESS) {
921 | #ifndef _WIN32
922 | if (using_api) {
923 | pthread_mutex_unlock(&buffer_lock);
924 | }
925 | else {
926 | #endif
927 | fprintf(stderr, "\nSomething went wrong while collecting health info.\n");
928 | #ifndef _WIN32
929 | }
930 | #endif
931 | goto cleanup;
932 | }
933 |
934 | for (k = 0; k <= HEALTH_INFO_VENDOR_SPECIFIC_DATA_SIZE; k++) {
935 | if (PMWATCH_GET_BIT_VALUE(health_info[j]->validation_flags, k)) {
936 | switch (k) {
937 |
938 | case 0: // Health Status
939 | temp_val = 0;
940 | for (t = 0; t <= HEALTH_STATUS_FATAL; t++) {
941 | if (PMWATCH_GET_BIT_VALUE(health_info[j]->health_status, t)) {
942 | temp_val = t + 1;
943 | }
944 | }
945 | health_info[j]->health_status = temp_val;
946 | break;
947 |
948 | case 1: // Percentage Remaining
949 | health_info[j]->percentage_used = 100 - health_info[j]->percentage_remaining;
950 | break;
951 |
952 | case 3: // Media Temperature
953 | media_temp_d = (health_info[j]->media_temp & TEMP_VALUE_MASK) * CELCIUS_CONV_VAL;
954 | memset(media_temp, 0, sizeof(char) * SMALL_STR_LEN);
955 | snprintf(media_temp, sizeof(media_temp) - 1, "%s%.2f", \
956 | PMWATCH_GET_BIT_VALUE(health_info[j]->media_temp, TEMP_SIGN_BIT_INDEX) ? "-" : "", \
957 | media_temp_d);
958 | break;
959 |
960 | case 4: // Controller Temperature
961 | controller_temp_d = (health_info[j]->controller_temp & TEMP_VALUE_MASK) * CELCIUS_CONV_VAL;
962 | memset(controller_temp, 0, sizeof(char) * SMALL_STR_LEN);
963 | snprintf(controller_temp, sizeof(controller_temp) - 1, "%s%.2f", \
964 | PMWATCH_GET_BIT_VALUE(health_info[j]->controller_temp, TEMP_SIGN_BIT_INDEX) ? "-" : "", \
965 | controller_temp_d);
966 | break;
967 |
968 | case 11:
969 | max_media_temp_d = 0;
970 | max_controller_temp_d = 0;
971 | memset(max_media_temp, 0, sizeof(char) * SMALL_STR_LEN);
972 | memset(max_controller_temp, 0, sizeof(char) * SMALL_STR_LEN);
973 |
974 | if (health_info[j]->vendor_data_size > 0) {
975 | max_media_temp_d = (health_info[j]->max_media_temp & TEMP_VALUE_MASK) * CELCIUS_CONV_VAL;
976 | max_controller_temp_d = (health_info[j]->max_controller_temp & TEMP_VALUE_MASK) * CELCIUS_CONV_VAL;
977 | snprintf(max_media_temp, sizeof(max_media_temp), "%s%.2f", \
978 | PMWATCH_GET_BIT_VALUE(health_info[j]->max_media_temp, TEMP_SIGN_BIT_INDEX) ? "-" : "", \
979 | max_media_temp_d);
980 |
981 | snprintf(max_controller_temp, sizeof(max_controller_temp), "%s%.2f", \
982 | PMWATCH_GET_BIT_VALUE(health_info[j]->max_controller_temp, TEMP_SIGN_BIT_INDEX) ? "-" : "", \
983 | max_controller_temp_d);
984 | }
985 | else {
986 | health_info[j]->power_on_time = 0;
987 | health_info[j]->uptime = 0;
988 | health_info[j]->last_shutdown_time = 0;
989 | }
990 | break;
991 |
992 | default:
993 | break;
994 | }
995 | }
996 | }
997 |
998 | // Add to this fprintf when want to enable more fields. Data is already obtained
999 | fprintf(fout, "%d%s%d%s%d%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s%s%s%s%s%s%s%s%s", \
1000 | health_info[j]->health_status, \
1001 | DELIMITER, \
1002 | health_info[j]->percentage_used, \
1003 | DELIMITER, \
1004 | health_info[j]->percentage_remaining, \
1005 | DELIMITER, \
1006 | health_info[j]->power_on_time, \
1007 | DELIMITER, \
1008 | health_info[j]->uptime, \
1009 | DELIMITER, \
1010 | health_info[j]->last_shutdown_time, \
1011 | DELIMITER, \
1012 | media_temp, \
1013 | DELIMITER, \
1014 | controller_temp, \
1015 | DELIMITER, \
1016 | max_media_temp, \
1017 | DELIMITER, \
1018 | max_controller_temp, \
1019 | DELIMITER \
1020 | );
1021 | #ifndef _WIN32
1022 | if (using_api) {
1023 | output_buf[j].health_status = health_info[j]->health_status;
1024 | output_buf[j].percentage_remaining = health_info[j]->percentage_remaining;
1025 | output_buf[j].percentage_used = health_info[j]->percentage_used;
1026 | output_buf[j].power_on_time = health_info[j]->power_on_time;
1027 | output_buf[j].uptime = health_info[j]->uptime;
1028 | output_buf[j].last_shutdown_time = health_info[j]->last_shutdown_time;
1029 | output_buf[j].media_temp = media_temp_d;
1030 | output_buf[j].controller_temp = controller_temp_d;
1031 | output_buf[j].max_media_temp = max_media_temp_d;
1032 | output_buf[j].max_controller_temp = max_controller_temp_d;
1033 | }
1034 | #endif
1035 |
1036 | #ifdef BUILD_DEBUG
1037 | #ifndef _WIN32
1038 | if (using_api) {
1039 | fprintf(fout, "|%d%s%d%s%d%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s%.2f%s%.2f%s%.2f%s%.2f%s|",
1040 | output_buf[j].health_status,
1041 | DELIMITER,
1042 | output_buf[j].percentage_used,
1043 | DELIMITER,
1044 | output_buf[j].percentage_remaining,
1045 | DELIMITER,
1046 | output_buf[j].power_on_time,
1047 | DELIMITER,
1048 | output_buf[j].uptime,
1049 | DELIMITER,
1050 | output_buf[j].last_shutdown_time,
1051 | DELIMITER,
1052 | output_buf[j].media_temp,
1053 | DELIMITER,
1054 | output_buf[j].controller_temp,
1055 | DELIMITER,
1056 | output_buf[j].max_media_temp,
1057 | DELIMITER,
1058 | output_buf[j].max_controller_temp,
1059 | DELIMITER
1060 | );
1061 | }
1062 | #endif
1063 | #endif
1064 |
1065 | }
1066 |
1067 | #ifndef _WIN32
1068 | if (using_api) {
1069 | ++write_count;
1070 | pthread_mutex_unlock(&buffer_lock);
1071 | }
1072 | #endif
1073 | fprintf(fout, "\n");
1074 | fflush(fout);
1075 |
1076 | pre_tsc = cur_tsc;
1077 | cur_time = PMW_UTILS_Get_Curr_Time_For_Sleep();
1078 | elapsed_time = cur_time - start_time;
1079 |
1080 | ret_code = adjust_for_overhead(i, elapsed_time, &num_skips);
1081 | if (ret_code != 0) {
1082 | goto cleanup;
1083 | }
1084 |
1085 | sleep_time = usec_sample_time - elapsed_time;
1086 |
1087 | PMW_UTILS_Sleep(sleep_time);
1088 | }
1089 |
1090 | cleanup:
1091 | free(sample);
1092 |
1093 | #ifndef _WIN32
1094 | if (using_api) {
1095 | pthread_mutex_lock(&buffer_lock);
1096 | collection_done = 1;
1097 | pthread_mutex_unlock(&buffer_lock);
1098 | }
1099 | #endif
1100 |
1101 | if (num_skips) {
1102 | fprintf(fout, "%d interval(s) skipped.\n", num_skips);
1103 | }
1104 |
1105 | return ret_code;
1106 | }
1107 |
1108 | void
1109 | PMW_COLLECT_Print_Lifetime_Mem_Info_Counters ()
1110 | {
1111 | int i, j, ret_code;
1112 | unsigned char page_num;
1113 | unsigned int count;
1114 |
1115 | i = 0;
1116 | j = 0;
1117 | page_num = 1;
1118 | PMW_COMM_Get_Number_of_DIMM(&count);
1119 |
1120 | LIFETIME_INFO_COUNTER_NODE cur_sample[count];
1121 |
1122 | print_info_header();
1123 |
1124 | fprintf(fout, "%s%s%s%s%s%s%s%s%s%s\n",
1125 | "DIMM",
1126 | DELIMITER,
1127 | "read_64B_ops_received",
1128 | DELIMITER,
1129 | "write_64B_ops_received",
1130 | DELIMITER,
1131 | "cpu_read_ops",
1132 | DELIMITER,
1133 | "cpu_write_ops",
1134 | DELIMITER);
1135 |
1136 | for (i = 0; i < count; i++) {
1137 | ret_code = PMW_COMM_Get_Memory_Info_Page(i, &cur_sample[i], page_num);
1138 | if ( ret_code != NVM_SUCCESS) {
1139 | fprintf(stderr, "\nSomething went wrong while collecting metrics.\n");
1140 | return;
1141 | }
1142 | fprintf(fout,
1143 | "%s%d%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s%" PRIu64 "%s\n",
1144 | "DIMM",
1145 | i,
1146 | DELIMITER,
1147 | cur_sample[i].bytes_read,
1148 | DELIMITER,
1149 | cur_sample[i].bytes_written,
1150 | DELIMITER,
1151 | cur_sample[i].host_reads,
1152 | DELIMITER,
1153 | cur_sample[i].host_writes,
1154 | DELIMITER
1155 | );
1156 | }
1157 |
1158 | return;
1159 | }
1160 |
1161 | #ifndef _WIN32
1162 | void* threadable_func (
1163 | void *arg
1164 | )
1165 | {
1166 | if (collect_lifetime) {
1167 | thread_status = PMW_COLLECT_Print_Smart_Counters();
1168 | }
1169 | if (collect_health) {
1170 | thread_status = PMW_COLLECT_Print_Health_Info();
1171 | }
1172 |
1173 | pthread_exit((void *) &thread_status);
1174 | }
1175 |
1176 | int
1177 | PMW_COLLECT_Get_DIMM_Count (
1178 | int *num_nvmdimms
1179 | )
1180 | {
1181 | return PMW_COMM_Get_Number_of_DIMM(num_nvmdimms);
1182 | }
1183 |
1184 | int
1185 | PMW_COLLECT_Start_Collection (
1186 | PMWATCH_CONFIG_NODE pmwatch_config
1187 | )
1188 | {
1189 | int ret_code;
1190 |
1191 | loops = 1;
1192 | using_api = 1;
1193 | infinite_run = 1;
1194 |
1195 | collect_health = pmwatch_config.collect_health;
1196 | collect_lifetime = pmwatch_config.collect_perf_metrics;
1197 |
1198 | if (collect_lifetime && collect_health) {
1199 | fprintf(stderr, "WARNING: Health info and performance metrics cannot be collected simultaneously. Continuing with performance metrics collection...\n");
1200 | collect_health = 0;
1201 | }
1202 | else if (!collect_lifetime && !collect_health) {
1203 | fprintf(stderr, "ERROR: health info and performance metrics collection disabled. Enable atleast one.\n");
1204 |
1205 | pthread_mutex_lock(&buffer_lock);
1206 | collection_done = 1;
1207 | pthread_mutex_unlock(&buffer_lock);
1208 |
1209 | return 1;
1210 | }
1211 |
1212 | usec_sample_time = (uint64_t) (pmwatch_config.interval * MICRO_SEC);
1213 | // needed during overhead adjustment
1214 | usec_sample_time_prev = usec_sample_time;
1215 |
1216 | filename = (char *) calloc(SMALL_STR_LEN, sizeof(char));
1217 | if (filename == NULL) {
1218 | fprintf(stderr, "ERROR: memory allocation failed!\n");
1219 |
1220 | pthread_mutex_lock(&buffer_lock);
1221 | collection_done = 1;
1222 | pthread_mutex_unlock(&buffer_lock);
1223 |
1224 | return 1;
1225 | }
1226 |
1227 | ret_code = STRNCPY_SAFE(filename, SMALL_STR_LEN, "/dev/null");
1228 | if (ret_code != NVM_SUCCESS) {
1229 | pthread_mutex_lock(&buffer_lock);
1230 | collection_done = 1;
1231 | pthread_mutex_unlock(&buffer_lock);
1232 |
1233 | return ret_code;
1234 | }
1235 | fout = fopen(filename, "w");
1236 | if (!fout) {
1237 | fprintf(stderr, "ERROR: Unable to create output file %s. Exiting...\n", filename);
1238 | free(filename);
1239 |
1240 | pthread_mutex_lock(&buffer_lock);
1241 | collection_done = 1;
1242 | pthread_mutex_unlock(&buffer_lock);
1243 |
1244 | return 1;
1245 | }
1246 |
1247 | ret_code = PMW_COMM_Init();
1248 | if (ret_code != 0) {
1249 | PMW_COMM_Cleanup();
1250 | fclose(fout);
1251 | free(filename);
1252 |
1253 | pthread_mutex_lock(&buffer_lock);
1254 | collection_done = 1;
1255 | pthread_mutex_unlock(&buffer_lock);
1256 |
1257 | return 1;
1258 | }
1259 |
1260 | pthread_create(&thread_id, NULL, threadable_func, NULL);
1261 |
1262 | return 0;
1263 | }
1264 |
1265 | int
1266 | PMW_COLLECT_Stop_Collection ()
1267 | {
1268 | infinite_run = 0;
1269 |
1270 | // wait for collection thread to exit
1271 | while (1) {
1272 | pthread_mutex_lock(&buffer_lock);
1273 | if (collection_done || thread_status != 0) {
1274 | break;
1275 | }
1276 | pthread_mutex_unlock(&buffer_lock);
1277 | };
1278 | pthread_mutex_unlock(&buffer_lock);
1279 |
1280 | loops = 0;
1281 | using_api = 0;
1282 | collect_health = 0;
1283 | collection_done = 0;
1284 | collect_lifetime = 0;
1285 |
1286 | free(output_buf);
1287 | fclose(fout);
1288 | free(filename);
1289 |
1290 | return 0;
1291 | }
1292 |
1293 | int
1294 | PMW_COLLECT_Read_Data (
1295 | PMWATCH_OP_BUF* op_buf
1296 | )
1297 | {
1298 | unsigned int count;
1299 |
1300 | // wait to finish the first write to metrics count buffer
1301 | while (1) {
1302 | pthread_mutex_lock(&buffer_lock);
1303 | if (write_count != 0 || thread_status != 0) {
1304 | break;
1305 | }
1306 | pthread_mutex_unlock(&buffer_lock);
1307 | };
1308 |
1309 | if (thread_status != 0) {
1310 | fprintf(stderr, "%s:%d Collection thread exited with an error!\n", __FUNCTION__, __LINE__);
1311 | pthread_mutex_unlock(&buffer_lock);
1312 |
1313 | return 1;
1314 | }
1315 |
1316 | PMW_COMM_Get_Number_of_DIMM(&count);
1317 |
1318 | memset(*op_buf, 0, count * sizeof(PMWATCH_OP_BUF_NODE));
1319 | memcpy(*op_buf, output_buf, count * sizeof(PMWATCH_OP_BUF_NODE));
1320 |
1321 | pthread_mutex_unlock(&buffer_lock);
1322 |
1323 | return 0;
1324 | }
1325 | #endif
1326 |
--------------------------------------------------------------------------------
/src/pmw_comm.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #ifdef _WIN32
34 | #define PMW_DLL_EXPORTS 1
35 | #define __NVM_DLL__ 1
36 | #else
37 | #include
38 | #endif
39 |
40 | #include "nvm_types.h"
41 | #include "nvm_management.h"
42 |
43 | #include "inc/pmw_comm.h"
44 | #include "inc/pmw_utils.h"
45 |
46 | #define LIFETIME_INFO_PAGE_NUM 1
47 |
48 | #define IS_LIFETIME_INFO(x) (x == LIFETIME_INFO_PAGE_NUM ? 1 : 0)
49 |
50 | /*
51 | * Defines the Firmware Command Table opcodes
52 | */
53 | enum passthrough_opcode {
54 | PT_GET_LOG = 0x08
55 | };
56 |
57 | /*
58 | * Defines the Sub-Opcodes for PT_GET_LOG
59 | */
60 | enum get_log_subop {
61 | SUBOP_SMART_HEALTH = 0x00,
62 | SUBOP_MEM_INFO = 0x03
63 | };
64 |
65 |
66 | #ifdef _WIN32
67 | HANDLE handle;
68 | int (*p_nvm_create_context)();
69 | int (*p_nvm_free_context)(const NVM_BOOL);
70 | int (*p_nvm_get_build_number)();
71 | int (*p_nvm_get_number_of_devices)(int*);
72 | int (*p_nvm_get_devices)(struct device_discovery*, const NVM_UINT8);
73 | int (*p_nvm_get_nvm_capacities)(struct device_capacities*);
74 | int (*p_nvm_send_device_passthrough_cmd)(const NVM_UID, struct device_pt_cmd*);
75 | int (*p_nvm_get_major_version)();
76 | int (*p_nvm_get_minor_version)();
77 | int (*p_nvm_get_hotfix_number)();
78 | int (*p_nvm_get_build_number)();
79 | #endif
80 |
81 | NVM_UINT32 count = 0;
82 | char ipmctl_version_str[15];
83 | struct device_discovery *gp_DIMM_devices = NULL;
84 | int ipmctl_major_ver, ipmctl_minor_ver, ipmctl_hot_fix_num, ipmctl_build;
85 |
86 | /*!
87 | * @fn struct device_discovery* PMW_COMM_Get_DIMM_Topology
88 | *
89 | * @brief Get the the DIMM information
90 | *
91 | * @param None
92 | *
93 | * @return struct device_discovery*
94 | *
95 | */
96 | struct device_discovery*
97 | PMW_COMM_Get_DIMM_Topology ()
98 | {
99 | return gp_DIMM_devices;
100 | }
101 |
102 | /*!
103 | * @fn NVM_INT32 PMW_COMM_Get_Smart_Counters
104 | *
105 | * @brief Get the the smart couters in the DIMM dimm_index in the default page number
106 | *
107 | * @param NVM_INT32 dimm_index - index of the dimm
108 | * @param LIFETIME_INFO_COUNTER smt_counters - structure of smart counter
109 | *
110 | * @return error code
111 | *
112 | */
113 | NVM_INT32
114 | PMW_COMM_Get_Memory_Info (
115 | NVM_INT32 dimm_index,
116 | LIFETIME_INFO_COUNTER smt_counters
117 | )
118 | {
119 | return PMW_COMM_Get_Memory_Info_Page(dimm_index, smt_counters, LIFETIME_INFO_PAGE_NUM);
120 | }
121 |
122 | /*!
123 | * @fn NVM_INT32 PMW_COMM_Get_Count_by_Topology
124 | *
125 | * @brief Get the the smart couters based on user provided DIMM topology
126 | *
127 | * @param NVM_INT32 socket_num,
128 | * @param NVM_INT32 mc_num,
129 | * @param NVM_INT32 channel_num,
130 | * @param NVM_INT32 dimm_num,
131 | * @param LIFETIME_INFO_COUNTER smt_counters
132 | *
133 | * @return error code
134 | *
135 | */
136 | NVM_INT32
137 | PMW_COMM_Get_Count_by_Topology (
138 | NVM_INT32 socket_num,
139 | NVM_INT32 mc_num,
140 | NVM_INT32 channel_num,
141 | NVM_INT32 dimm_num,
142 | LIFETIME_INFO_COUNTER smt_counters
143 | )
144 | {
145 | int itr, dimm_found = 0;
146 |
147 | for (itr = 0; itr < count; itr++) {
148 | if (gp_DIMM_devices[itr].socket_id != socket_num) {
149 | continue;
150 | }
151 |
152 | if (gp_DIMM_devices[itr].memory_controller_id != mc_num) {
153 | continue;
154 | }
155 |
156 | if (gp_DIMM_devices[itr].channel_id != channel_num) {
157 | continue;
158 | }
159 |
160 | if (gp_DIMM_devices[itr].channel_pos != dimm_num) {
161 | continue;
162 | }
163 |
164 | dimm_found = 1;
165 | PMW_COMM_Get_Memory_Info_Page(itr, smt_counters, LIFETIME_INFO_PAGE_NUM);
166 | break;
167 | }
168 |
169 | if (dimm_found) {
170 | return NVM_SUCCESS;
171 | }
172 | else {
173 | return 1;
174 | }
175 | }
176 |
177 | /*!
178 | * @fn NVM_INT32 pmw_comm_Init_DLL()
179 | *
180 | * @brief Get process address for Windows APIs
181 | *
182 | * @param None
183 | *
184 | * @return NVM_SUCCESS on success
185 | * PMW_ERR_DLLLOAD or PMW_ERR_DLLSYM on error
186 | *
187 | */
188 | #ifdef _WIN32
189 | NVM_INT32
190 | pmw_comm_Init_DLL ()
191 | {
192 | handle = PMW_UTILS_DLL_Open();
193 | if (handle == INVALID_HANDLE_VALUE) {
194 | return PMW_ERR_DLLLOAD;
195 | }
196 |
197 | p_nvm_create_context = (int (*)()) PMW_UTILS_DLL_Sym(handle, "nvm_create_context");
198 | if (p_nvm_create_context == NULL) {
199 | return PMW_ERR_DLLSYM;
200 | }
201 |
202 | p_nvm_free_context = (int (*)(const NVM_BOOL)) PMW_UTILS_DLL_Sym(handle, "nvm_free_context");
203 | if (p_nvm_free_context == NULL) {
204 | return PMW_ERR_DLLSYM;
205 | }
206 |
207 | p_nvm_get_build_number = (int (*)()) PMW_UTILS_DLL_Sym(handle, "nvm_get_build_number");
208 | if (p_nvm_get_build_number == NULL) {
209 | return PMW_ERR_DLLSYM;
210 | }
211 |
212 | p_nvm_get_nvm_capacities = (int (*)(struct device_capacities*)) PMW_UTILS_DLL_Sym(handle, "nvm_get_nvm_capacities");
213 | if (p_nvm_get_nvm_capacities == NULL) {
214 | return PMW_ERR_DLLSYM;
215 | }
216 |
217 | p_nvm_get_number_of_devices = (int (*)(int*)) PMW_UTILS_DLL_Sym(handle, "nvm_get_number_of_devices");
218 | if (p_nvm_get_number_of_devices == NULL) {
219 | return PMW_ERR_DLLSYM;
220 | }
221 |
222 | p_nvm_get_devices = (int (*)(struct device_discovery*, const NVM_UINT8)) PMW_UTILS_DLL_Sym(handle, "nvm_get_devices");
223 | if (p_nvm_get_devices == NULL) {
224 | return PMW_ERR_DLLSYM;
225 | }
226 |
227 | p_nvm_send_device_passthrough_cmd = (int (*)(const NVM_UID, struct device_pt_cmd*)) PMW_UTILS_DLL_Sym(handle, "nvm_send_device_passthrough_cmd");
228 | if (p_nvm_send_device_passthrough_cmd == NULL) {
229 | return PMW_ERR_DLLSYM;
230 | }
231 |
232 | p_nvm_get_major_version = (int (*)()) PMW_UTILS_DLL_Sym(handle, "nvm_get_major_version");
233 | if (p_nvm_get_major_version == NULL) {
234 | return PMW_ERR_DLLSYM;
235 | }
236 |
237 | p_nvm_get_minor_version = (int (*)()) PMW_UTILS_DLL_Sym(handle, "nvm_get_minor_version");
238 | if (p_nvm_get_minor_version == NULL) {
239 | return PMW_ERR_DLLSYM;
240 | }
241 |
242 | p_nvm_get_hotfix_number = (int (*)()) PMW_UTILS_DLL_Sym(handle, "nvm_get_hotfix_number");
243 | if (p_nvm_get_hotfix_number == NULL) {
244 | return PMW_ERR_DLLSYM;
245 | }
246 |
247 | p_nvm_get_build_number = (int (*)()) PMW_UTILS_DLL_Sym(handle, "nvm_get_build_number");
248 | if (p_nvm_get_build_number == NULL) {
249 | return PMW_ERR_DLLSYM;
250 | }
251 |
252 | return NVM_SUCCESS;
253 | }
254 | #endif
255 |
256 | /*!
257 | * @fn NVM_INT32 pmw_comm_compare_topology
258 | *
259 | * @brief compare function for the quick sort
260 | *
261 | * @param const void *a - NVDIMM_TOPOLOGY struct
262 | * @param const void *b - NVDIMM_TOPOLOGY struct
263 | *
264 | * @return NVM_INT32
265 | *
266 | */
267 | NVM_INT32
268 | pmw_comm_Compare_Topology (
269 | const void *a,
270 | const void *b
271 | )
272 | {
273 | struct device_discovery *p_a = (struct device_discovery*) a;
274 | struct device_discovery *p_b = (struct device_discovery*) b;
275 |
276 | return p_a->device_handle.handle - p_b->device_handle.handle;
277 | }
278 |
279 | /*!
280 | * @fn void pmw_comm_Sort_DIMM_Topology
281 | *
282 | * @brief Sort the topology struct array based on socket number
283 | *
284 | * @param const NVM_UINT8 count - number of dimms
285 | * @param NVDIMM_TOPOLOGY p_dimm_topo - dimm topology information
286 | *
287 | * @return void
288 | *
289 | */
290 | void
291 | pmw_comm_Sort_DIMM_Topology ()
292 | {
293 | qsort(gp_DIMM_devices, count, sizeof(struct device_discovery), pmw_comm_Compare_Topology);
294 | }
295 |
296 | /*!
297 | * @fn NVM_INT32 pmw_comm_Get_Mode
298 | *
299 | * @brief Check and print the mode of DCPMM DIMM (App Direct, memory mode or both)
300 | *
301 | * @return NVM_SUCCESS on success
302 | *
303 | */
304 | NVM_INT32
305 | pmw_comm_Get_Mode ()
306 | {
307 | NVM_INT32 is_ad = 0, is_2lm = 0;
308 |
309 | // check to see if DCPMM has memory mode or AD capability.
310 | struct device_capacities *p_dcap;
311 | p_dcap = (struct device_capacities*) calloc(1, sizeof(struct device_capacities));
312 | if (p_dcap == NULL) {
313 | fprintf(stderr, "ERROR: memory allocation failed!\n");
314 | return 1;
315 | }
316 |
317 | NVM_GET_NVM_CAPACITIES(p_dcap);
318 |
319 | if (p_dcap->memory_capacity != 0) {
320 | is_2lm = 1;
321 | }
322 | if (p_dcap->app_direct_capacity != 0) {
323 | is_ad = 1;
324 | }
325 |
326 | free(p_dcap);
327 |
328 | PMW_UTILS_Print_Key("%s", "system.nvdimm_mode");
329 | if (is_ad && is_2lm) {
330 | PMW_UTILS_Print_Value("\"%s\"", "app_direct+memory_mode");
331 | }
332 | else if (is_ad) {
333 | PMW_UTILS_Print_Value("\"%s\"", "app_direct");
334 | }
335 | else if (is_2lm) {
336 | PMW_UTILS_Print_Value("\"%s\"", "memory_mode");
337 | }
338 | else {
339 | PMW_UTILS_Print_Value("\"%s\"", "unknown");
340 | }
341 |
342 | #if 0
343 | pmw_comm_Get_Device_Mapping();
344 | #endif
345 |
346 | return NVM_SUCCESS;
347 | }
348 |
349 | NVM_INT32
350 | pmw_comm_Create_Context()
351 | {
352 | NVM_INT32 ret_code = 0;
353 |
354 | ret_code = NVM_CREATE_CONTEXT();
355 | if (ret_code == NVM_ERR_INVALID_PERMISSIONS || ret_code == NVM_ERR_NO_MEM) {
356 | fprintf(stdout, "Failed to create context. Tool performace may be impacted. Continuing...\n");
357 | return ret_code;
358 | }
359 |
360 | return NVM_SUCCESS;
361 | }
362 |
363 | NVM_INT32
364 | pmw_comm_Free_Context()
365 | {
366 | NVM_INT32 ret_code;
367 |
368 | ret_code = NVM_FREE_CONTEXT(1);
369 | if (ret_code == NVM_ERR_INVALID_PERMISSIONS || ret_code == NVM_ERR_NO_MEM) {
370 | fprintf(stderr, "Failed to free context\n");
371 | return ret_code;
372 | }
373 |
374 | return NVM_SUCCESS;
375 | }
376 |
377 | #ifdef BUILD_DEBUG
378 | void
379 | pmw_comm_Print_Payload (
380 | void *mb_payload,
381 | size_t size
382 | )
383 | {
384 | const unsigned char * const bytes = mb_payload;
385 | size_t i;
386 |
387 | printf("[ ");
388 | for(i = 0; i < size; i++)
389 | {
390 | printf("%02x ", bytes[i]);
391 | if((i+1)%8 == 0) {
392 | printf(",\n ");
393 | }
394 | }
395 | printf("]\n");
396 | }
397 | #endif
398 |
399 | void
400 | pmw_comm_Prepare_Command (
401 | struct device_pt_cmd *cmd,
402 | NVM_UINT8 opcode,
403 | NVM_UINT8 sub_opcode,
404 | NVM_UINT32 input_payload_size,
405 | void *input_payload,
406 | NVM_UINT32 output_payload_size,
407 | void *output_payload
408 | )
409 | {
410 | cmd->opcode = opcode;
411 | cmd->sub_opcode = sub_opcode;
412 | cmd->input_payload_size = input_payload_size;
413 | cmd->input_payload = input_payload;
414 | cmd->output_payload_size = output_payload_size;
415 | cmd->output_payload = output_payload;
416 | }
417 |
418 | NVM_INT32
419 | PMW_COMM_Get_Memory_Info_Page (
420 | NVM_INT32 dimm_index,
421 | void *counters,
422 | const unsigned char page_num
423 | )
424 | {
425 | NVM_INT32 ret_code = NVM_SUCCESS;
426 | struct device_pt_cmd cmd;
427 | void *p_out_payload;
428 | NVM_UINT32 out_payload_size;
429 | MEMORY_INFO_PAGE_NODE mem_info_page; //output mailbox payload
430 | LIFETIME_INFO_COUNTER smt_counters;
431 |
432 | if (IS_LIFETIME_INFO(page_num)) {
433 | memset (&mem_info_page, 0, sizeof(MEMORY_INFO_PAGE_NODE));
434 | p_out_payload = &mem_info_page;
435 | out_payload_size = sizeof(MEMORY_INFO_PAGE_NODE);
436 |
437 | smt_counters = (LIFETIME_INFO_COUNTER) counters;
438 | }
439 | else {
440 | fprintf(stderr, "ERROR: Incorrect config information. Exiting...\n");
441 | return 1;
442 | }
443 |
444 | struct pt_payload_input_memory_info mem_input; //input mailbox payload
445 | memset(&cmd, 0, sizeof(struct device_pt_cmd));
446 | memset(&mem_input, 0, sizeof(struct pt_payload_input_memory_info));
447 |
448 | mem_input.memory_page = page_num;
449 |
450 | pmw_comm_Prepare_Command(&cmd, \
451 | PT_GET_LOG, \
452 | SUBOP_MEM_INFO, \
453 | sizeof(struct pt_payload_input_memory_info), \
454 | &mem_input, \
455 | out_payload_size, \
456 | p_out_payload);
457 |
458 | ret_code = NVM_SEND_DEVICE_PASSTHROUGH_CMD(gp_DIMM_devices[dimm_index].uid, &cmd);
459 | if (ret_code != NVM_SUCCESS) {
460 | fprintf(stderr, "Failed to obtain count\n");
461 | return ret_code;
462 | }
463 |
464 | //read data from mem_info_page and copy to smt_counters strcuture
465 | if (IS_LIFETIME_INFO(page_num)) {
466 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(mem_info_page.total_bytes_read, smt_counters->bytes_read);
467 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(mem_info_page.total_bytes_written, smt_counters->bytes_written);
468 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(mem_info_page.total_read_reqs, smt_counters->host_reads);
469 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(mem_info_page.total_write_reqs, smt_counters->host_writes);
470 | }
471 |
472 | return ret_code;
473 | }
474 |
475 | NVM_INT32
476 | PMW_COMM_Get_Health_Info_Page (
477 | NVM_INT32 dimm_index,
478 | void *counters
479 | )
480 | {
481 | NVM_INT32 ret_code = NVM_SUCCESS;
482 | struct device_pt_cmd cmd;
483 | void *p_out_payload;
484 | NVM_UINT32 out_payload_size;
485 | HEALTH_INFO_PAGE_NODE health_info_page; //output mailbox payload
486 | HEALTH_INFO_COUNTER smt_counters;
487 |
488 | memset (&health_info_page, 0, sizeof(HEALTH_INFO_PAGE_NODE));
489 | p_out_payload = &health_info_page;
490 | out_payload_size = sizeof(HEALTH_INFO_PAGE_NODE);
491 |
492 | smt_counters = (HEALTH_INFO_COUNTER) counters;
493 |
494 | struct pt_payload_input_memory_info mem_input; //input mailbox payload
495 | memset(&cmd, 0, sizeof(struct device_pt_cmd));
496 | memset(&mem_input, 0, sizeof(struct pt_payload_input_memory_info));
497 |
498 | pmw_comm_Prepare_Command(&cmd, \
499 | PT_GET_LOG, \
500 | SUBOP_SMART_HEALTH, \
501 | sizeof(struct pt_payload_input_memory_info), \
502 | &mem_input, \
503 | out_payload_size, \
504 | p_out_payload);
505 |
506 | ret_code = NVM_SEND_DEVICE_PASSTHROUGH_CMD(gp_DIMM_devices[dimm_index].uid, &cmd);
507 | if (ret_code != NVM_SUCCESS) {
508 | fprintf(stderr, "Failed to obtain count\n");
509 | return ret_code;
510 | }
511 |
512 | PMW_4_BYTE_ARRAY_TO_32_BIT_VALUE(health_info_page.validation_flags, smt_counters->validation_flags);
513 | PMW_2_BYTE_ARRAY_TO_16_BIT_VALUE(health_info_page.media_temp, smt_counters->media_temp);
514 | PMW_2_BYTE_ARRAY_TO_16_BIT_VALUE(health_info_page.controller_temp, smt_counters->controller_temp);
515 | PMW_4_BYTE_ARRAY_TO_32_BIT_VALUE(health_info_page.vendor_data_size, smt_counters->vendor_data_size);
516 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(health_info_page.power_on_time, smt_counters->power_on_time);
517 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(health_info_page.uptime, smt_counters->uptime);
518 | PMW_8_BYTE_ARRAY_TO_64_BIT_VALUE(health_info_page.last_shutdown_time, smt_counters->last_shutdown_time);
519 | PMW_2_BYTE_ARRAY_TO_16_BIT_VALUE(health_info_page.max_media_temp, smt_counters->max_media_temp);
520 | PMW_2_BYTE_ARRAY_TO_16_BIT_VALUE(health_info_page.max_controller_temp, smt_counters->max_controller_temp);
521 |
522 | smt_counters->health_status = health_info_page.health_status;
523 | smt_counters->percentage_remaining = health_info_page.percentage_remaining;
524 |
525 | return ret_code;
526 | }
527 |
528 | #if !defined(_WIN32) && !defined(BULID_ESXI)
529 |
530 | /*!
531 | * @fn int PMW_COMM_Check_Permission
532 | *
533 | * @brief Check if user has root permission
534 | *
535 | * @return 0 on success
536 | *
537 | */
538 | int
539 | PMW_COMM_Check_User_Permission ()
540 | {
541 | if (getuid() != ROOT_UID) {
542 | fprintf(stderr, "\nNon-root user!\n");
543 | fprintf(stderr, "Requires root access. Please run as root.\n\n");
544 |
545 | return 204;
546 | }
547 |
548 | return 0;
549 | }
550 |
551 | #endif
552 |
553 | /*!
554 | * @fn NVM_INT32 pmw_comm_Check_PreR_FW
555 | *
556 | * @brief Check if this is a supported firmware
557 | *
558 | * @return error code
559 | *
560 | */
561 | NVM_INT32
562 | pmw_comm_Check_PreR_FW (
563 | NVM_UINT32 *is_prer_fw
564 | )
565 | {
566 | NVM_UINT32 itr, i_fw_api_minor_ver, i_fw_api_major_ver, prer_fw = 0, status = NVM_SUCCESS;
567 | char *fw_api_version, *token;
568 | char fw_api_minor_ver[10];
569 | char fw_api_major_ver[10];
570 |
571 | *is_prer_fw = prer_fw;
572 |
573 | for(itr = 0; itr < count; itr++) {
574 | fw_api_version = strndup(gp_DIMM_devices[itr].fw_api_version, SMALL_STR_LEN);
575 | token = strtok(fw_api_version, ".");
576 | if (!token) {
577 | fprintf(stderr, "ERROR: Failure to parse version information. Exiting...\n");
578 | free(fw_api_version);
579 | return 1;
580 | }
581 | status = STRNCPY_SAFE(fw_api_major_ver, sizeof(fw_api_major_ver), token);
582 | if (status != NVM_SUCCESS) {
583 | free(fw_api_version);
584 | return status;
585 | }
586 | while(token) {
587 | status = STRNCPY_SAFE(fw_api_minor_ver, sizeof(fw_api_minor_ver), token);
588 | if (status != NVM_SUCCESS) {
589 | free(fw_api_version);
590 | return status;
591 | }
592 | token = strtok(NULL, ".");
593 | }
594 |
595 | i_fw_api_major_ver = atoi(fw_api_major_ver);
596 | i_fw_api_minor_ver = atoi(fw_api_minor_ver);
597 |
598 | // check for unsupported firmware
599 | prer_fw += (i_fw_api_major_ver > 1) ? 1 : 0;
600 |
601 | free(fw_api_version);
602 | }
603 |
604 | if (prer_fw) {
605 | *is_prer_fw = 1;
606 | }
607 |
608 | return status;
609 | }
610 |
611 | NVM_INT32
612 | PMW_COMM_Print_Topology (
613 | NVM_INT32 get_topo,
614 | NVM_INT32 detailed
615 | )
616 | {
617 | NVM_INT32 itr, dimm_avail = 1, ret_code = NVM_SUCCESS;
618 | NVM_UINT32 dummy_count, is_prer_fw = 0;
619 |
620 | #if !defined(_WIN32) && !defined(BULID_ESXI)
621 | ret_code = PMW_COMM_Check_User_Permission();
622 | if (ret_code != NVM_SUCCESS) {
623 | return ret_code;
624 | }
625 | #endif
626 |
627 | #ifdef _WIN32
628 | ret_code = pmw_comm_Init_DLL();
629 | if (ret_code != NVM_SUCCESS) {
630 | return 200;
631 | }
632 | #endif
633 |
634 | if (get_topo) {
635 | pmw_comm_Create_Context();
636 |
637 | ipmctl_major_ver = NVM_GET_MAJOR_VERSION();
638 | ipmctl_minor_ver = NVM_GET_MINOR_VERSION();
639 | ipmctl_hot_fix_num = NVM_GET_HOTFIX_NUMBER();
640 | ipmctl_build = NVM_GET_BUILD_NUMBER();
641 |
642 | snprintf(ipmctl_version_str, sizeof(ipmctl_version_str), "%02d.%02d.%02d.%04d", ipmctl_major_ver, ipmctl_minor_ver, ipmctl_hot_fix_num, ipmctl_build);
643 |
644 | ret_code = PMW_COMM_Is_DIMM_Available();
645 | if (ret_code != NVM_SUCCESS) {
646 | dimm_avail = 0;
647 | }
648 | if(!dimm_avail) {
649 | PMW_UTILS_Print_Key("%s", "system.nvdimm_availability");
650 | PMW_UTILS_Print_Value("%d", dimm_avail);
651 | return 200;
652 | }
653 |
654 | ret_code = PMW_COMM_Get_Number_of_DIMM(&dummy_count);
655 | if (ret_code != NVM_SUCCESS) {
656 | count = 0;
657 | }
658 | if(!count) {
659 | PMW_UTILS_Print_Key("%s", "system.num_nvdimm");
660 | PMW_UTILS_Print_Value("%d", count);
661 | return 200;
662 | }
663 |
664 | ret_code = PMW_COMM_Read_DIMM_Topology();
665 | if (ret_code != NVM_SUCCESS) {
666 | fprintf(stderr, "Unable to obtain topology\n");
667 | PMW_COMM_Cleanup();
668 | return 200;
669 | }
670 | }
671 |
672 | pmw_comm_Check_PreR_FW(&is_prer_fw);
673 | if (is_prer_fw) {
674 | fprintf(stderr, "\nUnsupported firmware.\n\n");
675 | PMW_COMM_Cleanup();
676 | return NVM_ERR_INVALID_PERMISSIONS;
677 | }
678 |
679 | if (get_topo) {
680 | PMW_UTILS_Print_Key("%s", "system.nvdimm_availability");
681 | PMW_UTILS_Print_Value("%d", dimm_avail);
682 | PMW_UTILS_Print_Key("%s", "system.num_nvdimm");
683 | PMW_UTILS_Print_Value("%d", count);
684 | }
685 |
686 | for(itr = 0; itr < count; itr++) {
687 | PMW_UTILS_Print_Key("system.package[%u].memory_controller[%u].channel[%hu].dimm[%d].name", \
688 | gp_DIMM_devices[itr].socket_id, \
689 | gp_DIMM_devices[itr].memory_controller_id, \
690 | gp_DIMM_devices[itr].channel_id, \
691 | gp_DIMM_devices[itr].channel_pos
692 | );
693 | // using channel position for DIMM ID. Not sure if it is the right way.
694 | PMW_UTILS_Print_Value("\"DIMM%d\"", itr);
695 | if (detailed) {
696 | PMW_UTILS_Print_Key("system.package[%u].memory_controller[%u].channel[%hu].dimm[%d].fw_version", \
697 | gp_DIMM_devices[itr].socket_id, \
698 | gp_DIMM_devices[itr].memory_controller_id, \
699 | gp_DIMM_devices[itr].channel_id, \
700 | gp_DIMM_devices[itr].channel_pos
701 | );
702 | PMW_UTILS_Print_Value("\"%s\"", gp_DIMM_devices[itr].fw_revision);
703 | PMW_UTILS_Print_Key("system.package[%u].memory_controller[%u].channel[%hu].dimm[%d].fw_api_version", \
704 | gp_DIMM_devices[itr].socket_id, \
705 | gp_DIMM_devices[itr].memory_controller_id, \
706 | gp_DIMM_devices[itr].channel_id, \
707 | gp_DIMM_devices[itr].channel_pos
708 | );
709 | PMW_UTILS_Print_Value("\"%s\"", gp_DIMM_devices[itr].fw_api_version);
710 | }
711 | }
712 |
713 | pmw_comm_Get_Mode();
714 |
715 | if (detailed) {
716 | PMW_UTILS_Print_Key("system.ipmctl_version");
717 | PMW_UTILS_Print_Value("%s", ipmctl_version_str);
718 | }
719 |
720 | PMW_COMM_Cleanup();
721 |
722 | return ret_code;
723 | }
724 |
725 | /*!
726 | * @fn NVM_INT32 PMW_COMM_Read_DIMM_Topology
727 | *
728 | * @brief Get the topology info of each DCPMM DIMMs
729 | *
730 | * @param const NVM_UINT8 count - number of dimms
731 | * @param NVDIMM_TOPOLOGY p_dimm_topo - dimm topology information
732 | *
733 | * @return error code
734 | *
735 | */
736 | NVM_INT32
737 | PMW_COMM_Read_DIMM_Topology ()
738 | {
739 | NVM_INT32 ret_code;
740 |
741 | gp_DIMM_devices = (struct device_discovery*) calloc(count, sizeof(struct device_discovery));
742 | if (gp_DIMM_devices == NULL){
743 | fprintf(stderr, "Memory allocation failed!\n");
744 | ret_code = NVM_ERR_NO_MEM;
745 | return ret_code;
746 | }
747 |
748 | ret_code = NVM_GET_DEVICES(gp_DIMM_devices, count);
749 | if (ret_code != NVM_SUCCESS) {
750 | fprintf(stderr, "Obtaining DIMM details failed!\n");
751 | return NVM_ERR_UNKNOWN;
752 | }
753 |
754 | pmw_comm_Sort_DIMM_Topology();
755 |
756 | return NVM_SUCCESS;
757 | }
758 |
759 | /*!
760 | * @fn NVM_INT32 PMW_COMM_Get_Number_of_DIMM
761 | *
762 | * @brief Get the number of DCPMM DIMMs
763 | *
764 | * @return error code
765 | *
766 | */
767 | NVM_INT32
768 | PMW_COMM_Get_Number_of_DIMM (
769 | NVM_UINT32 *dimm_count
770 | )
771 | {
772 | NVM_INT32 ret_val = NVM_SUCCESS;
773 |
774 | ret_val = NVM_GET_NUMBER_OF_DEVICES(&count);
775 |
776 | *dimm_count = count;
777 |
778 | if (count == 0) {
779 | fprintf(stderr, "Intel Optane DIMMs are not available in this system.\n");
780 | return NVM_ERR_DIMM_NOT_FOUND;
781 | }
782 |
783 | if (ret_val != NVM_SUCCESS) {
784 | fprintf(stderr, "Obtaining the number of Intel Optane DIMMs failed!\n");
785 | }
786 |
787 | return ret_val;
788 | }
789 |
790 | /*!
791 | * @fn NVM_INT32 PMW_COMM_Is_DIMM_Available
792 | *
793 | * @brief Check if DCPMM DIMM is available in the machine or not
794 | * Print DCPMM DIMM details if print_info is enabled
795 | * Check the DCPMM DIMM mode if print_info is enabled
796 | *
797 | * @return error code
798 | *
799 | */
800 | NVM_INT32
801 | PMW_COMM_Is_DIMM_Available ()
802 | {
803 | NVM_INT32 count, ret_val = NVM_SUCCESS;
804 |
805 | ret_val = NVM_GET_NUMBER_OF_DEVICES(&count);
806 | if (count == 0) {
807 | return NVM_ERR_DIMM_NOT_FOUND;
808 | }
809 |
810 | if (ret_val != NVM_SUCCESS) {
811 | fprintf(stderr, "Obtaining the number of Intel Optane DIMMs failed!\n");
812 | }
813 |
814 | return ret_val;
815 | }
816 |
817 | /*!
818 | * @fn void PMW_COMM_Print_Warning_Message
819 | *
820 | * @brief Print PMWatch pre-requisites as warning
821 | *
822 | * @return void
823 | *
824 | */
825 | void
826 | PMW_COMM_Print_Warning_Message ()
827 | {
828 | fprintf(stderr, "\nWARNING: pmwatch pre-requisites:\n");
829 | fprintf(stderr, " Firmware version may be unsupported.\n");
830 |
831 | if (count != 0 && gp_DIMM_devices != NULL) {
832 | fprintf(stderr, " Firmware version found on the system: %s\n", gp_DIMM_devices[0].fw_revision);
833 | }
834 |
835 | fprintf(stderr, "\n ipmctl >= ");
836 | fprintf(stderr, "%s\n", PMWATCH_SUPPORT_IPMCTL_VERSION_MIN);
837 | fprintf(stderr, " ipmctl found on the system: %02d.%02d.%02d.%04d\n", ipmctl_major_ver, ipmctl_minor_ver, ipmctl_hot_fix_num, ipmctl_build);
838 | fprintf(stderr, "\npmwatch is not guaranteed to work with versions less than the ones mentioned above.\n\n");
839 |
840 | return;
841 | }
842 |
843 | /*!
844 | * @fn NVM_INT32 PMW_COMM_Init
845 | *
846 | * @brief Intialize APIs
847 | *
848 | * @param None
849 | *
850 | * @return error code
851 | *
852 | */
853 | NVM_INT32
854 | PMW_COMM_Init ()
855 | {
856 | NVM_INT32 ret_code = NVM_SUCCESS;
857 | NVM_UINT32 dummy_count, is_prer_fw = 0;
858 | gp_DIMM_devices = NULL;
859 |
860 | #ifdef _WIN32
861 | ret_code = pmw_comm_Init_DLL();
862 | if (ret_code != NVM_SUCCESS) {
863 | return 201;
864 | }
865 | #endif
866 |
867 | pmw_comm_Create_Context();
868 |
869 | #if !defined(_WIN32) && !defined(BULID_ESXI)
870 | ret_code = PMW_COMM_Check_User_Permission();
871 | if (ret_code != NVM_SUCCESS) {
872 | return ret_code;
873 | }
874 | #endif
875 |
876 | ipmctl_major_ver = NVM_GET_MAJOR_VERSION();
877 | ipmctl_minor_ver = NVM_GET_MINOR_VERSION();
878 | ipmctl_hot_fix_num = NVM_GET_HOTFIX_NUMBER();
879 | ipmctl_build = NVM_GET_BUILD_NUMBER();
880 |
881 | snprintf(ipmctl_version_str, sizeof(ipmctl_version_str), "%02d.%02d.%02d.%04d", ipmctl_major_ver, ipmctl_minor_ver, ipmctl_hot_fix_num, ipmctl_build);
882 |
883 | ret_code = PMW_COMM_Is_DIMM_Available();
884 | if (ret_code != NVM_SUCCESS) {
885 | fprintf(stderr, "Intel Optane DIMMS are not available on this system.\n");
886 | return 201;
887 | }
888 |
889 | ret_code = PMW_COMM_Get_Number_of_DIMM(&dummy_count);
890 | if (ret_code != NVM_SUCCESS) {
891 | return 201;
892 | }
893 |
894 | ret_code = PMW_COMM_Read_DIMM_Topology();
895 | if (ret_code != NVM_SUCCESS) {
896 | fprintf(stderr, "Failed to initialize.\n");
897 | return 201;
898 | }
899 |
900 | pmw_comm_Check_PreR_FW(&is_prer_fw);
901 | if (is_prer_fw) {
902 | fprintf(stderr, "\nUnsupported firmware.\n\n");
903 | return NVM_ERR_INVALID_PERMISSIONS;
904 | }
905 |
906 | return ret_code;
907 | }
908 |
909 | NVM_INT32
910 | PMW_COMM_Cleanup ()
911 | {
912 | free(gp_DIMM_devices);
913 |
914 | pmw_comm_Free_Context();
915 |
916 | #ifdef _WIN32
917 | PMW_UTILS_DLL_Close(handle);
918 | #endif
919 |
920 | return NVM_SUCCESS;
921 | }
922 |
--------------------------------------------------------------------------------
/src/pmw_utils.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2018 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #ifdef _WIN32
33 | #include
34 | #include
35 | #pragma intrinsic(__rdtsc)
36 | #else
37 | #include
38 | #include
39 | #endif
40 |
41 | #if defined(_WIN32)
42 | #ifndef PMW_DLL_EXPORTS
43 | #define PMW_DLL_EXPORTS 1
44 | #endif
45 | #define DLL_FILE_NAME L"libipmctl.dll"
46 | #endif
47 |
48 | #include "pmw_utils.h"
49 |
50 | NVM_UINT32
51 | PMW_UTILS_Strncpy_Safe (
52 | char *dst,
53 | size_t dst_size,
54 | const char *src
55 | )
56 | {
57 | if (!dst || !src) {
58 | fprintf(stderr, "ERROR: NULL value for strncpy operation\n");
59 |
60 | return 1;
61 | }
62 |
63 | size_t to_copy = strlen(src);
64 |
65 | if (to_copy >= dst_size) {
66 | fprintf(stderr, "ERROR: (strncpy) buffer too small\n");
67 |
68 | return 1;
69 | }
70 |
71 | memcpy(dst, src, to_copy);
72 | dst[to_copy] = '\0';
73 |
74 | return NVM_SUCCESS;
75 | }
76 |
77 | NVM_UINT32
78 | PMW_UTILS_Strncat_Safe(
79 | char *dst,
80 | size_t dst_size,
81 | const char *src
82 | )
83 | {
84 | size_t to_copy, copy_at;
85 |
86 | if (!dst || !src) {
87 | fprintf(stderr, "ERROR: NULL value for strncat operation\n");
88 |
89 | return 1;
90 | }
91 |
92 | to_copy = strlen(src);
93 | copy_at = strlen(dst);
94 |
95 | if (to_copy + copy_at >= dst_size) {
96 | fprintf(stderr, "ERROR: (strncat) buffer too small\n");
97 |
98 | return 1;
99 | }
100 |
101 | memcpy(dst + copy_at, src, to_copy);
102 | dst[to_copy + copy_at] = '\0';
103 |
104 | return NVM_SUCCESS;
105 | }
106 |
107 | void
108 | PMW_UTILS_Cal_Diff (
109 | const LIFETIME_INFO_COUNTER diff,
110 | const LIFETIME_INFO_COUNTER pre,
111 | const LIFETIME_INFO_COUNTER cur
112 | )
113 | {
114 | uint64_t overflow_val = 0xFFFFFFFFFFFFFFFFULL;
115 |
116 | // bytes_read
117 | CALCULATE_DIFFERENCE(cur->bytes_read, pre->bytes_read, diff->bytes_read, overflow_val);
118 |
119 | // bytes_written
120 | CALCULATE_DIFFERENCE(cur->bytes_written, pre->bytes_written, diff->bytes_written, overflow_val);
121 |
122 | // host_reads
123 | CALCULATE_DIFFERENCE(cur->host_reads, pre->host_reads, diff->host_reads, overflow_val);
124 |
125 | // host_writes
126 | CALCULATE_DIFFERENCE(cur->host_writes, pre->host_writes, diff->host_writes, overflow_val);
127 |
128 | return ;
129 | }
130 |
131 | #ifdef _WIN32
132 | // return in millisec
133 | uint64_t
134 | PMW_UTILS_Get_Curr_Time_For_Sleep ()
135 | {
136 | time_t epoch_time;
137 |
138 | time(&epoch_time);
139 |
140 | return epoch_time * MILL_SEC;
141 | }
142 |
143 | uint64_t
144 | PMW_UTILS_Get_Curr_Time_In_Sec ()
145 | {
146 | time_t epoch_time;
147 |
148 | time(&epoch_time);
149 |
150 | return epoch_time;
151 | }
152 | #else
153 | // returns in microsec
154 | uint64_t
155 | PMW_UTILS_Get_Curr_Time_For_Sleep ()
156 | {
157 | struct timeval time;
158 |
159 | gettimeofday(&time, NULL);
160 |
161 | return (time.tv_sec * MICRO_SEC) + time.tv_usec;
162 | }
163 |
164 | uint64_t
165 | PMW_UTILS_Get_Curr_Time_In_Sec ()
166 | {
167 | struct timeval time;
168 | gettimeofday(&time, NULL);
169 |
170 | return time.tv_sec + (time.tv_usec / MICRO_SEC);
171 | }
172 | #endif
173 |
174 | /* ------------------------------------------------------------------------- */
175 | /*!
176 | * @fn PMW_UTILS_Print_Key
177 | *
178 | * @brief Print the key of a key-value pair (key, value)
179 | *
180 | * @param const char* format - format of the key string
181 | *
182 | * @return void
183 | * Special Notes:
184 | * < None >
185 | */
186 | void PMW_UTILS_Print_Key (const char* format, ... )
187 | {
188 | va_list args;
189 | va_start (args, format);
190 | fprintf(stdout, "(\"");
191 | vfprintf (stdout, format, args);
192 | fprintf(stdout, "\", ");
193 | va_end (args);
194 | }
195 |
196 | /* ------------------------------------------------------------------------- */
197 | /*!
198 | * @fn PMW_UTILS_Print_Value
199 | *
200 | * @brief Print the value of a key-value pair (key, value)
201 | *
202 | * @param const char* format - format of the value string
203 | *
204 | * @return void
205 | * Special Notes:
206 | * < None >
207 | */
208 | void PMW_UTILS_Print_Value (const char* format, ... )
209 | {
210 | va_list args;
211 | va_start (args, format);
212 | vfprintf (stdout, format, args);
213 | fprintf(stdout, ")\n");
214 | va_end (args);
215 | fflush(stdout);
216 | }
217 |
218 | #if !defined(_WIN32)
219 | #if defined(__i386__)
220 |
221 | static __inline__ unsigned long long rdtsc(void)
222 | {
223 | unsigned long long int x;
224 | __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
225 | return x;
226 | }
227 |
228 | #else
229 |
230 | static __inline__ unsigned long long rdtsc(void)
231 | {
232 | unsigned hi, lo;
233 | __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
234 | return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
235 | }
236 |
237 | #endif
238 | #endif
239 |
240 | /* ------------------------------------------------------------------------- */
241 | /*!
242 | * @fn PMW_UTILS_Read_TSC
243 | *
244 | * @brief Read TSC and return
245 | *
246 | * @return TSC
247 | *
248 | * Special Notes:
249 | * < None >
250 | */
251 | uint64_t PMW_UTILS_Read_TSC ()
252 | {
253 | #if _WIN32
254 | return __rdtsc();
255 | #else
256 | return rdtsc();
257 | #endif
258 | }
259 |
260 | #if defined(_WIN32)
261 | /* ------------------------------------------------------------------------- */
262 | /*!
263 | * @fn pmw_api_DLL_Error (
264 | * wchar_t *out_buffer,
265 | * NVM_UINT32 max_buffer_len
266 | * )
267 | *
268 | * @brief Convert error code to corresponding error message
269 | *
270 | * @return return code
271 | *
272 | * Special Notes:
273 | * < None >
274 | */
275 | NVM_UINT32
276 | pmw_api_DLL_Error (
277 | wchar_t *out_buffer,
278 | NVM_UINT32 max_buffer_len
279 | )
280 | {
281 | if(!out_buffer) {
282 | return NVM_ERR_UNKNOWN;
283 | }
284 |
285 | FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
286 | NULL,
287 | GetLastError(),
288 | 0,
289 | out_buffer,
290 | max_buffer_len,
291 | NULL);
292 |
293 | return NVM_SUCCESS;
294 | }
295 |
296 | /* ------------------------------------------------------------------------- */
297 | /*!
298 | * @fn HANDLE PMW_UTILS_DLL_Open ()
299 | *
300 | * @brief Convert error code to corresponding error message
301 | *
302 | * @return DLL handle
303 | *
304 | * Special Notes:
305 | * < None >
306 | */
307 | HANDLE
308 | PMW_UTILS_DLL_Open ()
309 | {
310 | void *p_mem = NULL;
311 | wchar_t vt_buffer[NVM_EVENT_MSG_LEN];
312 |
313 | p_mem = LoadLibraryExW(DLL_FILE_NAME, NULL, 0);
314 | if(p_mem == NULL) {
315 | fwprintf(stderr, L"Unable to open shared library: %s\n", DLL_FILE_NAME);
316 | pmw_api_DLL_Error(vt_buffer, NVM_EVENT_MSG_LEN);
317 | fwprintf(stderr, L"Error: %s\n", vt_buffer);
318 | fflush(stderr);
319 | p_mem = (void*) INVALID_HANDLE_VALUE;
320 | }
321 |
322 | return p_mem;
323 | }
324 |
325 | /* ------------------------------------------------------------------------- */
326 | /*!
327 | * @fn PMW_UTILS_DLL_Sym (
328 | * HANDLE handle,
329 | * const char *symbol
330 | * )
331 | *
332 | * @brief Get symbol from DLL
333 | *
334 | * @return pointer to symbol
335 | *
336 | * Special Notes:
337 | * < None >
338 | */
339 | void*
340 | PMW_UTILS_DLL_Sym (
341 | HANDLE handle,
342 | const char *symbol
343 | )
344 | {
345 | void *p_mem = NULL;
346 | wchar_t vt_buffer[NVM_EVENT_MSG_LEN];
347 |
348 | #if defined(UNICODE)
349 | char a_symbol[NVM_EVENT_MSG_LEN];
350 | w2a(a_symbol, symbol, NVM_EVENT_MSG_LEN);
351 | p_mem = GetProcAddress((HINSTANCE)handle, a_symbol);
352 | #else
353 | p_mem = GetProcAddress((HINSTANCE)handle, symbol);
354 | #endif
355 | if(p_mem == NULL) {
356 | pmw_api_DLL_Error(vt_buffer, NVM_EVENT_MSG_LEN);
357 | fprintf(stderr, "Unable to find symbol in shared library: %s\n", symbol);
358 | fwprintf(stderr, L"Error: %s\n", vt_buffer);
359 | fflush(stderr);
360 | }
361 |
362 | return p_mem;
363 | }
364 |
365 | /* ------------------------------------------------------------------------- */
366 | /*!
367 | * @fn PMW_UTILS_DLL_Close (
368 | * HANDLE handle
369 | * )
370 | *
371 | * @brief Close DLL handle
372 | *
373 | * @return return code
374 | *
375 | * Special Notes:
376 | * < None >
377 | */
378 | NVM_UINT32
379 | PMW_UTILS_DLL_Close (
380 | HANDLE handle
381 | )
382 | {
383 | NVM_UINT32 ret_val = NVM_SUCCESS;
384 | wchar_t vt_buffer[NVM_EVENT_MSG_LEN];
385 |
386 | if (handle != INVALID_HANDLE_VALUE && (void*) handle != NULL) {
387 | ret_val = FreeLibrary((HINSTANCE) handle);
388 | if(ret_val != 0) {
389 | ret_val = NVM_SUCCESS;
390 | }
391 | else {
392 | ret_val = NVM_ERR_UNKNOWN;
393 | }
394 | }
395 |
396 | if (ret_val != NVM_SUCCESS) {
397 | pmw_api_DLL_Error(vt_buffer, NVM_EVENT_MSG_LEN);
398 | fprintf(stderr, "Unable to close handle: %p\n", handle);
399 | fwprintf(stderr, L"Error: %s\n", vt_buffer);
400 | fflush(stderr);
401 | }
402 |
403 | return ret_val;
404 | }
405 |
406 | #endif
407 |
408 | /* ------------------------------------------------------------------------- */
409 | /*!
410 | * @fn PMW_COLLECTION_Sleep (
411 | * uint64_t sleep_time
412 | * )
413 | *
414 | * @brief Sleep the flow for the given time
415 | *
416 | * @return No Return
417 | *
418 | * Special Notes:
419 | * < None >
420 | */
421 | void
422 | PMW_UTILS_Sleep(uint64_t sleep_time)
423 | {
424 | #ifdef _WIN32
425 | Sleep(sleep_time);
426 | #else
427 | usleep(sleep_time);
428 | #endif
429 | }
--------------------------------------------------------------------------------
/src/pmwatch-stop:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # MIT License
4 | #
5 | # Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
6 | #
7 | # Permission is hereby granted, free of charge, to any person obtaining a
8 | # copy of this software and associated documentation files (the "Software"),
9 | # to deal in the Software without restriction, including without limitation
10 | # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 | # and/or sell copies of the Software, and to permit persons to whom the
12 | # Software is furnished to do so, subject to the following conditions:
13 | #
14 | # The above copyright notice and this permission notice shall be included in
15 | # all copies or substantial portions of the Software.
16 | #
17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | # DEALINGS IN THE SOFTWARE.
24 |
25 | PROCESS_NAME="pmwatch"
26 |
27 | pmw_pid_str=`ps -eo pid,comm | grep -w ${PROCESS_NAME} | grep -v ${PROCESS_NAME}-stop`
28 |
29 | if [[ -z ${pmw_pid_str} ]] ; then
30 | echo "pmwatch is not running!"
31 | exit
32 | fi
33 |
34 | itr=1
35 | while [[ itr -le 10 ]]
36 | do
37 | pmw_pid=`echo ${pmw_pid_str} | cut -d " " -f${itr}`
38 | if [[ ! -z ${pmw_pid} ]] ; then
39 | break
40 | fi
41 | itr=`expr ${itr} + 1`
42 | done
43 |
44 | res=`kill -9 ${pmw_pid}`
45 | echo
46 | if [[ $? -eq 0 ]] ; then
47 | echo "pmwatch stopped successfully."
48 | else
49 | echo "Unable to stop pmwatch."
50 | fi
51 | echo
52 |
--------------------------------------------------------------------------------
/src/pmwatch.c:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (C) 2017 - 2019 Intel Corporation. All rights reserved.
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a
7 | * copy of this software and associated documentation files (the "Software"),
8 | * to deal in the Software without restriction, including without limitation
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | * and/or sell copies of the Software, and to permit persons to whom the
11 | * Software is furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | * DEALINGS IN THE SOFTWARE.
23 | *
24 | */
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | #ifdef _WIN32
35 | #include
36 | #include
37 | #pragma intrinsic(__rdtsc)
38 | #else
39 | #include
40 | #include
41 | #include
42 | #endif
43 |
44 | #include "nvm_types.h"
45 | #include "nvm_management.h"
46 | #include "inc/pmw_utils.h"
47 | #include "inc/pmw_comm.h"
48 | #include "inc/pmw_version.h"
49 | #include "inc/pmw_collect.h"
50 |
51 | FILE *fout_m;
52 | int loops_m = 0, infinite_run_m = 0;
53 | uint64_t usec_sample_time_m, usec_sample_time_prev_m;
54 | int collect_lifetime_m = 0;
55 | char SEMICOLON_M[] = ";";
56 | char TAB_M[] = "\t";
57 | char DELIMITER_M[] = ";";
58 | int output_format_one_m = 1;
59 | int output_format_two_m = 0;
60 | int collect_health_m = 0;
61 |
62 | static char output_version[] = PRODUCT_NAME" "STRINGIFY(MAJOR_VERSION)"."STRINGIFY(MINOR_VERSION)""UPDATE_STRING""PRODUCT_TYPE_STR""ENG_BUILD;
63 | static char build_date[] = __DATE__" at "__TIME__;
64 |
65 | void
66 | pmwatch_print_help()
67 | {
68 | fprintf(stdout, "Usage:\npmwatch \n");
69 | fprintf(stdout, "pmwatch 1 (to run indefinitely; use \"pmwatch-stop\" to stop the collection)\n");
70 | fprintf(stdout, "pmwatch 0 (to run indefinitely with user specified collection time)\n");
71 | fprintf(stdout, "pmwatch -a | --avail (tool version and Optane DCPMM DIMM topology information)\n");
72 | fprintf(stdout, "pmwatch -l (collect lifetime data snapshot of memory performance)\n");
73 | fprintf(stdout, "Options:\n");
74 | fprintf(stdout, "\t-hi, --health-info\tcollects health information\n");
75 | fprintf(stdout, "\t-f \twrite the result to a csv file\n");
76 | fprintf(stdout, "\t-F \tappend the result to a csv file\n");
77 | fprintf(stdout, "\t-g, --group-metrics-format\tdisplay the output in metric grouping format\n");
78 | fprintf(stdout, "\t-td, --tab-delimited\tuse tab as delimiter. Default is comma\n");
79 | fprintf(stdout, "\n");
80 | fflush(stdout);
81 | }
82 |
83 | int
84 | pmwatch_parse_cli (
85 | int argc,
86 | char* argv[]
87 | )
88 | {
89 | int itr, valid_cli = 0, file_logging = 0, ret_val;
90 | double sample_time = 1;
91 | char *file_name;
92 | char extension[] = ".csv";
93 | char file_mode[] = "w";
94 |
95 | ret_val = STRNCPY_SAFE(DELIMITER_M, sizeof(DELIMITER_M), SEMICOLON_M);
96 | if (ret_val != NVM_SUCCESS) {
97 | return ret_val;
98 | }
99 |
100 | // check if sufficient args are available
101 | if(argc < 3){
102 | // check if indefinite run or single snapshot
103 | if (argc == 2) {
104 | if (strcmp(argv[1], "1") == 0) {
105 | infinite_run_m = 1;
106 | valid_cli = 1;
107 | }
108 | else if (strcmp(argv[1], "-l") == 0) {
109 | collect_lifetime_m = 1;
110 | valid_cli = 1;
111 | }
112 | }
113 |
114 | if (!valid_cli) {
115 | pmwatch_print_help();
116 | return NVM_ERR_INVALIDPARAMETER;
117 | }
118 | }
119 |
120 | // check if indefinite run or single snapshot (cli: pmwatch 1 -f or pmwatch -l -f)
121 | if (!infinite_run_m && !collect_lifetime_m) {
122 | if (strcmp(argv[2], "-f") == 0 || strcmp(argv[2], "-F") == 0 || \
123 | strcmp(argv[2], "-td") == 0 || strcmp(argv[2], "--tab-delimited") == 0 || \
124 | strcmp(argv[2], "-g") == 0 || strcmp(argv[2], "--group-metrics-format") == 0 || \
125 | strcmp(argv[2], "-hi") == 0 || strcmp(argv[2], "--health-info") == 0) {
126 | if (strcmp(argv[1], "1") == 0) {
127 | infinite_run_m = 1;
128 | valid_cli = 1;
129 | }
130 | else if (strcmp(argv[1], "-l") == 0) {
131 | collect_lifetime_m = 1;
132 | valid_cli = 1;
133 | }
134 | }
135 | }
136 |
137 | // if not indefinite run or single snapshot, parse cli args for sampling time and loops
138 | if (!infinite_run_m && !collect_lifetime_m) {
139 | sample_time = (double) atof(argv[1]);
140 | loops_m = (int) atof(argv[2]);
141 | if (sample_time <= 0 || loops_m < 0) {
142 | fprintf(stderr, "/ should be a positive value.\n");
143 | return NVM_ERR_INVALIDPARAMETER;
144 | }
145 | if (loops_m == 0) {
146 | infinite_run_m = 1;
147 | }
148 | valid_cli = 1;
149 | }
150 |
151 | if (!valid_cli) {
152 | pmwatch_print_help();
153 | return NVM_ERR_INVALIDPARAMETER;
154 | }
155 |
156 | #ifdef _WIN32
157 | usec_sample_time_m = (uint64_t) (sample_time * MILL_SEC);
158 | #else
159 | usec_sample_time_m = (uint64_t) (sample_time * MICRO_SEC);
160 | #endif
161 |
162 | // needed during overhead adjustment
163 | usec_sample_time_prev_m = usec_sample_time_m;
164 |
165 | // parse for other options
166 | itr = 2;
167 | while(itr < argc) {
168 | if (strcmp(argv[itr], "-f") == 0) {
169 | file_name = (char*) malloc (SMALL_STR_LEN * sizeof(char));
170 | if (itr + 1 >= argc) {
171 | fprintf(stderr, "Error: provide an output file name.\n");
172 | return NVM_ERR_INVALIDPARAMETER;
173 | }
174 |
175 | ret_val = STRNCPY_SAFE(file_name, SMALL_STR_LEN, argv[itr + 1]);
176 | if (ret_val != NVM_SUCCESS) {
177 | return ret_val;
178 | }
179 | file_logging = 1;
180 | }
181 | else if (strcmp(argv[itr], "-F") == 0) {
182 | file_name = (char*) malloc (SMALL_STR_LEN * sizeof(char));
183 | if (itr + 1 >= argc) {
184 | fprintf(stderr, "Error: provide an output file name.\n");
185 | return NVM_ERR_INVALIDPARAMETER;
186 | }
187 |
188 | ret_val = STRNCPY_SAFE(file_name, SMALL_STR_LEN, argv[itr + 1]);
189 | if (ret_val != NVM_SUCCESS) {
190 | return ret_val;
191 | }
192 | ret_val = STRNCPY_SAFE(file_mode, sizeof(file_mode), "a");
193 | if (ret_val != NVM_SUCCESS) {
194 | return ret_val;
195 | }
196 | file_logging = 1;
197 | }
198 | else if (strcmp(argv[itr], "-td") == 0 || strcmp(argv[itr], "--tab-delimited") == 0) {
199 | ret_val = STRNCPY_SAFE(extension, sizeof(extension), ".tsv");
200 | if (ret_val != NVM_SUCCESS) {
201 | return ret_val;
202 | }
203 | ret_val = STRNCPY_SAFE(DELIMITER_M, sizeof(DELIMITER_M), TAB_M);
204 | if (ret_val != NVM_SUCCESS) {
205 | return ret_val;
206 | }
207 | }
208 | else if (strcmp(argv[itr], "-g") == 0 || strcmp(argv[itr], "--group-metrics-format") == 0) {
209 | output_format_two_m = 1;
210 | output_format_one_m = 0;
211 | }
212 | else if (strcmp(argv[itr], "-hi") == 0 || strcmp(argv[itr], "--health-info") == 0) {
213 | collect_health_m = 1;
214 | }
215 | ++itr;
216 | }
217 |
218 | if (output_format_two_m && collect_lifetime_m) {
219 | fprintf(stderr, "WARNING: -g option cannot be used with -l option. Continuing without -g option ...\n");
220 | output_format_one_m = 1;
221 | output_format_two_m = 0;
222 | }
223 |
224 | // set stdout or fout
225 | if (file_logging) {
226 | if (strstr(file_name, ".csv") == NULL) {
227 | ret_val = STRNCAT_SAFE(file_name, SMALL_STR_LEN, extension);
228 | if (ret_val != NVM_SUCCESS) {
229 | return ret_val;
230 | }
231 | }
232 |
233 | fout_m = fopen(file_name, file_mode);
234 | if (!fout_m) {
235 | fprintf(stderr, "ERROR: Unable to open output file %s. Output will be sent to the console.\n", file_name);
236 | fout_m = stdout;
237 | }
238 | }
239 | else {
240 | fout_m = stdout;
241 | }
242 |
243 | return NVM_SUCCESS;
244 | }
245 |
246 | void
247 | pmwatch_Close_File ()
248 | {
249 | if (fout_m != stdout && fout_m != NULL) {
250 | fclose(fout_m);
251 | }
252 |
253 | return;
254 | }
255 |
256 | int main (int argc, char* argv[]){
257 | int ret_code = NVM_SUCCESS;
258 | int detailed = 0;
259 |
260 | // check for "-a"/"--avail" option and print in machine-readable format
261 | if ((argc == 2 || argc == 3) && (strcmp(argv[1], "-a") == 0 || strcmp(argv[1], "--avail") == 0)) {
262 | if (argc == 3 && (strcmp(argv[2], "-d") == 0 || strcmp(argv[2], "--detailed") == 0)) {
263 | detailed = 1;
264 | }
265 | PMW_UTILS_Print_Key("%s", "version");
266 | PMW_UTILS_Print_Value("\"%s\"", output_version);
267 | PMW_UTILS_Print_Key("%s","build_date");
268 | PMW_UTILS_Print_Value("\"%s\"", build_date);
269 |
270 | ret_code = PMW_COMM_Print_Topology(1, detailed);
271 | if (ret_code != NVM_SUCCESS) {
272 | if (ret_code != NVM_ERR_INVALID_PERMISSIONS) {
273 | PMW_COMM_Print_Warning_Message();
274 | }
275 | return ret_code;
276 | }
277 | return NVM_SUCCESS;
278 | }
279 |
280 | // parse cli option
281 | if (pmwatch_parse_cli(argc, argv) != NVM_SUCCESS) {
282 | return 1;
283 | }
284 |
285 | ret_code = PMW_COLLECT_Set_Global_Vars (fout_m,
286 | loops_m,
287 | infinite_run_m,
288 | usec_sample_time_m,
289 | usec_sample_time_prev_m,
290 | collect_lifetime_m,
291 | output_format_one_m,
292 | output_format_two_m,
293 | collect_health_m,
294 | DELIMITER_M);
295 | if (ret_code != NVM_SUCCESS) {
296 | return 1;
297 | }
298 |
299 | // initialize: check the availability
300 | // get the DIMM topology
301 | ret_code = PMW_COMM_Init();
302 | if (ret_code != NVM_SUCCESS) {
303 | if (ret_code != NVM_ERR_INVALID_PERMISSIONS) {
304 | PMW_COMM_Print_Warning_Message();
305 | }
306 | if (ret_code != PMW_ERR_DLLLOAD && ret_code != PMW_ERR_DLLSYM) {
307 | PMW_COMM_Cleanup();
308 | }
309 | pmwatch_Close_File();
310 | return ret_code;
311 | }
312 |
313 | if (collect_lifetime_m) {
314 | PMW_COLLECT_Print_Lifetime_Mem_Info_Counters();
315 | }
316 | else if (collect_health_m) {
317 | PMW_COLLECT_Print_Health_Info();
318 | }
319 | else {
320 | // get the counts from 6 SMART counters and output
321 | PMW_COLLECT_Print_Smart_Counters();
322 | }
323 |
324 | PMW_COMM_Cleanup();
325 |
326 | pmwatch_Close_File();
327 |
328 | return 0;
329 | }
330 |
--------------------------------------------------------------------------------