Subject: [PATCH] [FEAT KRN1203] s390/perf: add support for the CPU-measurement sampling Facility
From: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>

Summary:     s390/perf: add support for the CPU-measurement sampling Facility
Description: Use the CPU-measurement sampling facility to obtain performance
             data for Linux in LPAR mode.  The s390-tools include the lscpumf
             and chcpumf tools.  Use lscpumf to display information about
             the counter and sampling facilities.
Upstream-ID: -
Problem-ID:  KRN1203

Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
---
 Makefile                              |    2 
 common.mak                            |    5 
 cpumf/Makefile                        |   63 ++++
 cpumf/bin/chcpumf.in                  |  182 +++++++++++++
 cpumf/bin/cpumf_helper.in             |  459 ++++++++++++++++++++++++++++++++++
 cpumf/bin/lscpumf.in                  |  384 ++++++++++++++++++++++++++++
 cpumf/data/cpum-cf-extended-z10.ctr   |   96 +++++++
 cpumf/data/cpum-cf-extended-z196.ctr  |  122 +++++++++
 cpumf/data/cpum-cf-extended-zEC12.ctr |  195 ++++++++++++++
 cpumf/data/cpum-cf-generic.ctr        |  132 +++++++++
 cpumf/data/cpum-cf-hw-counter.map     |   15 +
 cpumf/data/cpum-sf-modes.ctr          |   13 
 cpumf/man/chcpumf.8                   |   66 ++++
 cpumf/man/lscpumf.1                   |   70 +++++
 14 files changed, 1802 insertions(+), 2 deletions(-)

--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ LIB_DIRS = libvtoc libu2s
 SUB_DIRS = $(LIB_DIRS) zipl zdump fdasd dasdfmt dasdview tunedasd \
 	   tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
 	   vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
-	   ziomon iucvterm hyptop cmsfs-fuse
+	   ziomon iucvterm hyptop cmsfs-fuse cpumf
 
 all: subdirs_make
 
--- a/common.mak
+++ b/common.mak
@@ -54,9 +54,10 @@ BINDIR          = $(INSTROOT)/sbin
 LIBDIR          = $(INSTROOT)/lib
 SYSCONFDIR      = $(INSTROOT)/etc
 MANDIR          = $(INSTROOT)/usr/share/man
+TOOLS_DATADIR   = $(INSTROOT)/usr/share/s390-tools
 TOOLS_LIBDIR    = $(INSTROOT)/lib/s390-tools
 INSTDIRS        = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
-			$(SYSCONFDIR) $(TOOLS_LIBDIR)
+			$(SYSCONFDIR) $(TOOLS_LIBDIR) $(TOOLS_DATADIR)
 OWNER           = $(shell id -un)
 GROUP		= $(shell id -gn)
 export INSTROOT BINDIR LIBDIR MANDIR OWNER GROUP
@@ -69,10 +70,12 @@ export ZFCPDUMP_DIR ZFCPDUMP_IMAGE ZFCPD
 
 CFLAGS		= $(WARNFLAGS) -O3 -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
 			-DS390_TOOLS_LIBDIR=$(TOOLS_LIBDIR) \
+			-DS390_TOOLS_DATADIR=$(TOOLS_DATADIR) \
 			-DS390_TOOLS_SYSCONFDIR=$(SYSCONFDIR) \
 			-g $(OPT_FLAGS)
 CXXFLAGS	= $(WARNFLAGS) -O3 -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
 			-DS390_TOOLS_LIBDIR=$(TOOLS_LIBDIR) \
+			-DS390_TOOLS_DATADIR=$(TOOLS_DATADIR) \
 			-DS390_TOOLS_SYSCONFDIR=$(SYSCONFDIR) \
 			 -g $(OPT_FLAGS)
 
--- /dev/null
+++ b/cpumf/Makefile
@@ -0,0 +1,63 @@
+#!/usr/bin/make -f
+
+include ../common.mak
+
+
+CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf
+DATA_FILES = cpum-cf-hw-counter.map cpum-cf-generic.ctr \
+             cpum-cf-extended-z10.ctr cpum-cf-extended-z196.ctr \
+	     cpum-cf-extended-zEC12.ctr cpum-sf-modes.ctr
+LIB_FILES = bin/cpumf_helper
+USRBIN_SCRIPTS = bin/lscpumf
+USRSBIN_SCRIPTS = bin/chcpumf
+MAN_FILES = lscpumf.1 chcpumf.8
+
+all:
+
+scripts: $(USRBIN_SCRIPTS) $(USRSBIN_SCRIPTS) $(LIB_FILES)
+	chmod +x $(USRBIN_SCRIPTS) $(USRSBIN_SCRIPTS) $(LIB_FILES)
+
+check:
+
+install: scripts install-man
+	for prg in $(USRBIN_SCRIPTS); do \
+	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$prg $(USRBINDIR) ; \
+	done
+	for prg in $(USRSBIN_SCRIPTS); do \
+	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$prg $(USRSBINDIR) ; \
+	done
+	test -d $(CPUMF_DATADIR) || mkdir -p $(CPUMF_DATADIR)
+	for lib in $(LIB_FILES); do \
+	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$lib $(TOOLS_LIBDIR) ; \
+	done
+	for data in $(DATA_FILES); do \
+	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 data/$$data $(CPUMF_DATADIR) ; \
+	done
+
+install-man:
+	for man in $(MAN_FILES); do \
+	  msection=`echo $$man |sed 's/.*\.\([1-9]\)$$/man\1/'` ; \
+	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 -D man/$$man $(MANDIR)/$$msection/$$man ; \
+	done
+
+man2pdf:
+	for man in $(MAN_FILES); do \
+	  man -t man/$$man |ps2pdf -sPAPERSIZE=a4 - man/$${man}.pdf ; \
+	done
+man2text:
+	for man in $(MAN_FILES); do \
+	  MANWIDTH=80 LANG=C man man/$$man |col -b |expand > man/$${man}.txt ; \
+	done
+
+clean:
+	rm -f $(LIB_FILES) $(USRBIN_SCRIPTS) $(USRSBIN_SCRIPTS)
+
+%: %.in
+	real_sysconf=`echo $(SYSCONFDIR)/iucvterm |sed 's#^$(INSTROOT)##'` ; \
+	real_cpumfdir=`echo $(CPUMF_DATADIR) |sed 's#^$(INSTROOT)##'` ; \
+	sed    -e "s#@sysconf_path@#$$real_sysconf#g" \
+	       -e "s#@cpumfdata_path@#$$real_cpumfdir#g" \
+	       -e 's#@S390_TOOLS_RELEASE@#$(S390_TOOLS_RELEASE)#g' \
+	< $< > $@
+
+.PHONY: all scripts install install-man man2pdf man2text clean
--- /dev/null
+++ b/cpumf/bin/chcpumf.in
@@ -0,0 +1,182 @@
+#!/usr/bin/perl -W
+#
+# Control CPU-measurement facilities
+#
+#
+# Copyright IBM Corp. 2014
+# Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+#
+#
+use strict;
+use warnings;
+use File::Basename qw/fileparse/;
+use Data::Dumper;
+use Getopt::Long qw/:config no_ignore_case/;
+
+# Global constants
+my $CPUMF_HELPER='/lib/s390-tools/cpumf_helper';
+my $CPUM_SFB_SIZE = '/sys/module/kernel/parameters/cpum_sfb_size';
+
+# Prototypes
+sub main();
+sub show_help();
+sub show_version();
+sub do_set_sfb_size($);
+sub cpumf_set_sfb_size($);
+sub invoke_cpumf_helper($);
+
+sub main()
+{
+	my $config = {
+		# Internal data
+		cpumf	    => {},	# CPU-MF information hash
+	};
+
+	unless (GetOptions(
+		# General options for help, version, verbose,...
+		"h|help"	      => \&show_help,
+		"v|version"	      => \&show_version,
+		"V|verbose+"	      => \$config->{verbose},
+		# Change specific options
+		"m|min=i"	    => \$config->{min},
+		"x|max=i"	    => \$config->{max},
+	)) {
+		print STDERR "One or more options are not valid\n";
+		print STDERR "Try '" . fileparse($0) .
+			      " --help' for more information\n";
+		exit 1;
+	}
+
+	# Collect CPU-MF information
+	$config->{cpumf} = invoke_cpumf_helper("-i");
+	die "Failed to collect CPU-MF information: $!\n" unless $config->{cpumf};
+
+	# Process parameters
+	my $exitval = 5;
+	if (defined($config->{min}) || defined($config->{max})) {
+		$exitval = do_set_sfb_size($config);
+	} else {
+		print STDERR "You must specify a valid option\n";
+		exit 1;
+	}
+
+	exit($exitval);
+}
+
+sub show_help()
+{
+	my $prog = fileparse($0);
+
+	print <<"EoHelp";
+Usage:	chcpumf -h|-v
+	chcpumf -m <num_sdb>
+	chcpumf -x <num_sdb>
+
+Options:
+	-m <num_sdb>  Specifies the initial size of the sampling buffer.
+		      A sample-data-block (SDB) consumes about 4 kilobytes.
+	-x <num_sdb>  Specifies the maximum size of the sampling buffer.
+		      A sample-data-block (SDB) consumes about 4 kilobytes.
+	-h	      Displays help information, then exits.
+	-v	      Displays version information, then exits.
+
+For more help information, issue 'man $prog'.
+EoHelp
+	exit 0;
+}
+
+sub show_version()
+{
+	print <<'EoVersion';
+CPU-measurement facility utilities, version @S390_TOOLS_RELEASE@
+Copyright IBM Corp. 2014
+
+EoVersion
+	exit 0;
+}
+
+sub cpumf_set_sfb_size($)
+{
+	my @size = @{shift()};
+	my $val = join ',', @size[0,1];
+	my ($SFBSIZE, $rc);
+
+	return undef unless open($SFBSIZE, '>', $CPUM_SFB_SIZE);
+	# Check the return code of print and close to detect error conditions
+	# reported by the device driver.  Because perl might buffer data, print
+	# might be successful, but close might then report the error condition.
+	# So check the return code of both functions and always close the file
+	# handle.
+	$rc = print { $SFBSIZE } "$val\n";
+	unless ($rc) {
+		close($SFBSIZE);
+		return $rc;
+	}
+	return close($SFBSIZE);
+}
+
+sub do_set_sfb_size($)
+{
+	my $c = shift();
+	my $size;
+
+	# Check if sampling facility is available
+	unless (exists $c->{cpumf}->{sf}) {
+		print STDERR "No CPU-measurement sampling facility detected\n";
+		return 2;
+	}
+	# Check if perf support is available
+	unless (exists $c->{cpumf}->{sf}->{perf}) {
+		print STDERR "No perf support for the CPU-measurement" .
+			     " sampling facility availalble\n";
+		return 2;
+	}
+
+	# Optionally, change the sampling buffer sizes
+	if (defined($c->{min}) || defined($c->{max})) {
+		$size = invoke_cpumf_helper("--sfb-size");
+		# Use current size value for zero min/max specifications
+		$size->[0] = $c->{min} if defined($c->{min});
+		$size->[1] = $c->{max} if defined($c->{max});
+		# Validate new settings
+		if ($size->[0] < 1 || $size->[1] < 1) {
+			die "The specified number(s) are not valid\n";
+		}
+		if ($size->[0] >= $size->[1]) {
+			die "The specified maximum must be greater " .
+			    "than the minimum\n";
+		}
+		# Set new sampling buffer sizes
+		unless (cpumf_set_sfb_size($size)) {
+			die "Failed to change sampling buffer size: $!\n";
+		}
+	}
+
+	# Finally, show sampling buffer sizes
+	if ($c->{verbose}) {
+		$size = invoke_cpumf_helper("--sfb-size");
+		print "Sampling buffer sizes:\n";
+		printf "    Minimum: %6u sample-data-blocks\n", $size->[0];
+		printf "    Maximum: %6u sample-data-blocks\n", $size->[1];
+	}
+
+	return 0;
+}
+
+sub invoke_cpumf_helper($)
+{
+	my $parms = shift();
+	my $result;
+
+	# Call helper module
+	my $output = qx"$CPUMF_HELPER $parms";
+	die "Failed to run helper module for '$parms'\n" if $? >> 8;
+	$result = eval "$output";
+	die "Failed to parse helper module data\n" if $@;
+
+	return $result;
+}
+
+&main();
+__DATA__
+__END__
--- /dev/null
+++ b/cpumf/bin/cpumf_helper.in
@@ -0,0 +1,459 @@
+#!/usr/bin/perl -W
+#
+# Helper module for managing CPU-measurement facilities (CPU-MF)
+#
+#
+# Copyright IBM Corp. 2014
+# Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+#
+#
+use strict;
+use warnings;
+use Carp qw/croak/;
+use Data::Dumper;
+use Getopt::Long qw/:config no_ignore_case/;
+use Pod::Usage;
+
+
+# Global constants
+my $SERVICE_LEVELS = '/proc/service_levels';
+my $CPUMF_DATA_DIR='/usr/share/s390-tools/cpumf';
+my $CPUM_SFB_SIZE = '/sys/module/kernel/parameters/cpum_sfb_size';
+my $CPUM_SF_DBF='/sys/kernel/debug/s390dbf/cpum_sf';
+
+# Counter set bits (according to QUERY COUNTER INFORMATION)
+my $BASIC_SET = 0x0002;
+my $PROBLEM_STATE_SET = 0x004;
+my $CRYPTO_SET = 0x0008;
+my $EXTENTED_SET = 0x0001;
+my $COPROC_GRP_SET = 0x8000;
+
+
+# Public prototypes
+sub cpumf_collect_data();
+sub cpumf_get_sfb_size();
+sub cpumf_set_sfb_size($);
+sub cpumf_parse_ctrdef($;$);
+sub cpumf_load_ctrdef($;$);
+sub cpumf_get_counter_set($);
+sub cpumf_counter_set_names();
+sub cpumf_counter_set_ids();
+sub cpumf_hardware_counter_map();
+
+# Internal prototypes
+sub cpumf_parse_cf($$);
+sub cpumf_parse_sf($$);
+
+
+sub cpumf_get_sfb_size()
+{
+	my $val = "0,0";
+	my $SFBSIZE;
+
+	return $val unless open($SFBSIZE, '<', $CPUM_SFB_SIZE);
+	$val = <$SFBSIZE>;
+	chomp($val);
+	close($SFBSIZE);
+
+	return [split /,/, $val];
+}
+
+sub cpumf_set_sfb_size($)
+{
+	my @size = @{shift()};
+	my $val = join ',', @size[0,1];
+	my ($SFBSIZE, $rc);
+
+	return undef unless open($SFBSIZE, '>', $CPUM_SFB_SIZE);
+	# Check the return code of print and close to detect error conditions
+	# reported by the device driver.  Because perl might buffer data, print
+	# might be successful, but close might then report the error condition.
+	# So check the return code of both functions and always close the file
+	# handle.
+	$rc = print { $SFBSIZE } "$val\n";
+	unless ($rc) {
+		close($SFBSIZE);
+		return $rc;
+	}
+	return close($SFBSIZE);
+}
+
+
+sub cpumf_parse_cf($$)
+{
+	my ($ent, $data) = @_;
+
+	if ($ent =~ /version=([0-9.]+) authorization=([[:xdigit:]]+)/) {
+		$data->{cf} = { version => $1, auth => hex($2) };
+	}
+}
+
+sub cpumf_parse_sf($$)
+{
+	my ($ent, $data) = @_;
+
+	# Parse common sampling facility entry
+	if ($ent =~ /min_rate=(\d+) max_rate=(\d+) cpu_speed=(\d+)/) {
+		$data->{sf} = {
+			min_sampl_interval => $1,
+			max_sampl_interval => $2,
+			cpu_speed	   => $3,
+			# This contains a list of authorized sampling modes, for
+			# example, basic
+			modes		    => {},
+		};
+	}
+
+	# Parse sampling facility mode entries
+	if ($ent =~ /mode=(\w+) sample_size=(\d+)/) {
+		$data->{sf}->{modes}->{$1}->{sample_size} = $2;
+	}
+}
+
+sub cpumf_collect_data()
+{
+	my $SL;
+
+	# Collect CPU-MF information from /proc/service_levels
+	return undef unless open($SL, '<', $SERVICE_LEVELS);
+	my @sl = <$SL>;
+	chomp(@sl);
+	close($SL);
+
+	# Process CPU-MF information and build data hash
+	my $data = {};
+	foreach my $ent (@sl) {
+		$ent =~ s/^CPU-MF: // or next;
+		cpumf_parse_cf($ent, $data) if $ent =~ s/Counter facility: //;
+		cpumf_parse_sf($ent, $data) if $ent =~ s/Sampling facility: //;
+	}
+
+	# Collect perf support for available facilities
+	if (-e '/sys/bus/event_source/devices/cpum_cf') {
+		$data->{cf}->{perf} = "cpum_cf" if exists $data->{cf};
+	}
+	if (-e '/sys/bus/event_source/devices/cpum_sf') {
+		$data->{sf}->{perf} = "cpum_sf" if exists $data->{sf};
+	}
+
+	return $data;
+}
+
+# Parse the specified counter definition file and returns a hash containing
+# the parsed counter definition.  The optional argument specifies a hash
+# reference to which the new definitions are added.  This reference is returned.
+sub cpumf_parse_ctrdef($;$)
+{
+	my $ctrdef = shift();
+	my $h = @_ ? shift() : {};
+	my $CTRDEF;
+
+	return undef unless open($CTRDEF, '<', "$CPUMF_DATA_DIR/$ctrdef");
+	my ($ctr, $name);
+	while (my $line = <$CTRDEF>) {
+		next if $line =~ /^#/;
+		chomp($line);
+
+		# Parse start of counter definition entry
+		if ($line =~ m/^Counter:\s*(0x[[:xdigit:]]+|\d+)
+			        \s+Name:\s*([[:alnum:]_]+)$/x) {
+			($ctr, $name) = ($1, $2);
+			$ctr = hex($ctr) if $ctr =~ /^0x/;
+			unless (length($ctr)) {
+				print STDERR "Found invalid entry in counter " .
+				      "definition: line $.\n";
+			}
+			$h->{$ctr} = { name => $name || "" };
+		}
+
+		# At this point, a counter must be defined
+		next unless defined($ctr);
+
+		# Parse short description (optional)
+		if ($line =~ m/^Short-Description:\s*(\S.*)?$/) {
+			$h->{ctr}->{shortdesc} = $1 || "";
+
+		# Parse start of counter description
+		} elsif ($line =~ m/^Description:\s*(\S.*)?$/) {
+			$h->{$ctr}->{desc} = $1 || "";
+
+		# Parse end of counter description
+		} elsif ($line =~ m/^\.$/) {
+			# Complete the counter definition
+			$h->{$ctr}->{set} = cpumf_get_counter_set($ctr);
+			# Trim whitespaces
+			$h->{$ctr}->{shortdesc} =~ s/^\s+|\s+$//g if $h->{$ctr}->{shortdesc};
+			$h->{$ctr}->{desc} =~ s/^\s+|\s+$//g if $h->{$ctr}->{desc};
+			# Finally, reset counter for next entry
+			$ctr = undef;
+
+		# Line is part of counter description (if $ctr_num is set)
+		} else {
+			$h->{$ctr}->{desc} .= " $line";
+		}
+	}
+	close($CTRDEF);
+
+	return $h;
+}
+
+# IBM System z hardware with CPU-M counter facility support
+my $system_z_hwtype_map = {
+	# Machine type	   Description
+	2097		=> 'IBM System z10 EC',
+	2098		=> 'IBM System z10 BC',
+	2817		=> 'IBM zEnterprise 196',
+	2818		=> 'IBM zEnterprise 114',
+	2827		=> 'IBM zEnterprise EC12',
+	2828		=> 'IBM zEnterprise BC12',
+};
+
+sub get_hardware_type()
+{
+	my $type = "";
+	my $SYSINFO;
+
+	return undef unless open($SYSINFO, '<', '/proc/sysinfo');
+	while (my $line = <$SYSINFO>) {
+		if ($line =~ m/^Type:\s*(\d+)\s*$/) {
+			$type = $1;
+			last;
+		}
+	}
+	close($SYSINFO);
+	return $type;
+}
+
+sub cpumf_load_ctrdef($;$)
+{
+	my $hw_type = shift();
+	my $authorized = @_ ? shift() : 0xffff;   # Counter Set authorization
+
+	my $ctrmap = cpumf_hardware_counter_map();
+	return unless $ctrmap;
+
+	my $h = {};
+	# Load generic counter sets
+	cpumf_parse_ctrdef($ctrmap->{0}, $h) or
+		croak "Failed to read generic counter definition: $!\n";
+	# Remove counter sets that miss authorizations
+	my @no_auth_list = ();
+	foreach my $ctr (sort keys %$h) {
+		push @no_auth_list, $ctr unless $h->{$ctr}->{set} & $authorized;
+	}
+	delete $h->{$_} foreach (@no_auth_list);
+	# Load extended counter set for specified hardware type
+	if ($hw_type && ($authorized & $EXTENTED_SET)) {
+		cpumf_parse_ctrdef($ctrmap->{$hw_type}, $h) or
+			croak "Failed to read extended counter definition: $!\n";
+	}
+
+	return $h;
+}
+
+
+sub cpumf_get_counter_set($)
+{
+	my $ctr = shift();
+
+	return $BASIC_SET if $ctr < 32;
+	return $PROBLEM_STATE_SET if $ctr < 64;
+	return $CRYPTO_SET if $ctr < 128;
+	return $EXTENTED_SET if $ctr <= 0xFFFF;
+	return 0;
+}
+
+sub cpumf_counter_set_names()
+{
+	return {
+		# Identifier	       Name
+		$BASIC_SET	    => 'Basic Counter Set',
+		$PROBLEM_STATE_SET  => 'Problem-State Counter Set',
+		$CRYPTO_SET	    => 'Crypto-Activity Counter Set',
+		$EXTENTED_SET	    => 'Extended Counter Set',
+		$COPROC_GRP_SET	    => 'Coprocessor Group Counter Set',
+	};
+}
+
+sub cpumf_counter_set_ids()
+{
+	return [$BASIC_SET, $PROBLEM_STATE_SET, $CRYPTO_SET, $EXTENTED_SET,
+		$COPROC_GRP_SET];
+}
+
+sub cpumf_hardware_counter_map()
+{
+	my $map = do "$CPUMF_DATA_DIR/cpum-cf-hw-counter.map";
+	croak "Failed to parse mapfile: $@" if $@;
+	croak "Failed to read mapfile: $!" unless defined $map;
+	return $map;
+}
+
+
+sub cpumf_helper_main()
+{
+	# Configuration settings and options
+	my $conf = {
+	};
+
+	# Parse command line option
+	GetOptions(
+		"i|info"	=> \$conf->{opt_info},
+		"c|counter=i"	=> \$conf->{opt_ctr},
+		"ctr-def=i"	=> \$conf->{opt_ctrdef},
+		"hardware-type"	=> \$conf->{opt_hwtype},
+		"ctr-set-names"	=> \$conf->{opt_ctrset_names},
+		"ctr-set-ids"	=> \$conf->{opt_ctrset_ids},
+		"sfb-size"	=> \$conf->{opt_sfb_size},
+		"ctr-sf"	=> \$conf->{opt_sf_ctr},
+	) or pod2usage(-message =>"One or more options are not valid",
+		       -exitval => 1);
+
+	# Setting up Data::Dumper to create parseable Perl output
+	local $Data::Dumper::Purity = 1;
+	local $Data::Dumper::Sortkeys = 1;
+	local $Data::Dumper::Terse = 1;
+
+	###print STDERR "CONF: " . Dumper($conf) . "\n";
+
+	# Process command line options
+	my $exitval = 0;
+	my $result;
+	if (defined($conf->{opt_info})) {
+		$result = cpumf_collect_data();
+
+	# Display System z hardware type
+	} elsif (defined($conf->{opt_hwtype})) {
+		my $type = get_hardware_type();
+		$result = [$type, $system_z_hwtype_map->{$type}];
+
+	# Display counters for current System z hardware
+	} elsif (defined($conf->{opt_ctr})) {
+		my $type = get_hardware_type();
+		$type = 0 unless $type;
+		$result = cpumf_load_ctrdef($type, $conf->{opt_ctr});
+
+	# Display counters for a particular System z hardware type
+	} elsif (defined($conf->{opt_ctrdef})) {
+		my $m = cpumf_hardware_counter_map();
+		if (exists $m->{$conf->{opt_ctrdef}}) {
+			$result = cpumf_parse_ctrdef($m->{$conf->{opt_ctrdef}});
+		} else {
+			printf STDERR "Invalid counter definition\n";
+			$exitval = 2;
+		}
+	# Display the size of the sampling facility buffer (sfb)
+	} elsif (defined($conf->{opt_sfb_size})) {
+		$result = cpumf_get_sfb_size();
+
+	# Display counter definitions for the sampling facility support (perf)
+	} elsif (defined($conf->{opt_sf_ctr})) {
+		$result = cpumf_parse_ctrdef('cpum-sf-modes.ctr');
+
+	# Display mapping of counter set IDs to counter set names
+	} elsif (defined($conf->{opt_ctrset_names})) {
+		$result = cpumf_counter_set_names();
+
+	# Display counter set IDs
+	} elsif (defined($conf->{opt_ctrset_ids})) {
+		$result = cpumf_counter_set_ids();
+
+	} else {
+		pod2usage(-message => "No option specified",
+			  -exitval => 1);
+	}
+
+	# Display result
+	print Dumper($result) if $result;
+	exit $exitval;
+}
+
+&cpumf_helper_main();
+__DATA__
+__END__
+=head1 NAME
+
+B<cpumf_helper> - Helper module for managing CPU-Measurement Facilities (CPU-MF)
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+The B<cpumf_helper> program is not intended for ordinary use.
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-i>, B<--info>
+
+Displays detailed information about installed and available CPU-measurement
+facilities and the related Linux support.
+
+=item B<-c>, B<--counter> I<authorization_value>
+
+Displays counter information for the current System z hardware.  The
+authorization value provides information about the authorized counter sets.  The
+value must be specified in decimal format.
+
+To display all supported counters, specify C<65535> (FFFF hex).
+
+To display supported counters for a particular System z hardware, use the
+B<--ctr-def> option and specify the System z hardware type.
+
+=item B<--hardware-type>
+
+Displays the System z hardware type.
+
+=item B<--ctr-def> I<hardware_type>
+
+Displays detailed information about a particular counter set for the specified
+System z hardware type, I<hardware_type>.  If you specify zero for
+I<hardware_type>, type-independent counter sets are displayed.
+
+=item B<--ctr-set-names>
+
+Displays the mapping of counter set IDs to counter set names.  The counter set
+IDs are numbers that are used in counter definitions.
+
+=item B<--ctr-set-ids>
+
+Displays the counter set IDs.  The counter set IDs are numbers that match the
+authorization bits (see QUERY COUNTER INFORMATION).  The output format is a
+list.  To get the ID for a particular counter set, use an index number as
+follows:
+
+=over 16
+
+=item 0: Basic Counter Set
+
+=item 1: Problem-State Counter Set
+
+=item 2: Crypto-Activity Counter Set
+
+=item 3: Extended Counter Set
+
+=item 4: Coprocessor Group Counter Set
+
+=back
+
+=item B<--ctr-sf>
+
+Displays the counter definitions for the sampling facility support.  These
+counter definitions are specific to Linux perf infrastructure.
+
+=item B<--sfb-size>
+
+Displays the size of the sampling facility buffer (SFB).  The minimum and
+maximum numbers are measured in units of sample-data-blocks.  A
+sample-data-block uses about 4 kilobytes.
+
+=back
+
+=head1 FILES
+
+=head1 SEE ALSO
+
+L<lscpumf(1)>, L<chcpumf(1)>
+
+=cut
--- /dev/null
+++ b/cpumf/bin/lscpumf.in
@@ -0,0 +1,384 @@
+#!/usr/bin/perl -W
+#
+# Display information about CPU-measurement facilities
+#
+#
+# Copyright IBM Corp. 2014
+# Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+#
+#
+use strict;
+use warnings;
+use Data::Dumper;
+use File::Basename qw/fileparse/;
+use Getopt::Long qw/:config no_ignore_case/;
+
+# Global constants
+my $CPUMF_HELPER='/lib/s390-tools/cpumf_helper';
+
+# Prototypes
+sub main();
+sub show_help();
+sub show_version();
+sub do_show_info($);
+sub do_show_cf($);
+sub do_show_sf($);
+sub do_show_ctr($;$);
+sub do_show_sf_events($);
+sub invoke_cpumf_helper($);
+
+
+sub main()
+{
+	my $config = {
+		# Internal data
+		cpumf	    => {},	# CPU-MF information hash
+	};
+
+	unless (GetOptions(
+		# General options for help, version,...
+		"h|help"	      => \&show_help,
+		"v|version"	      => \&show_version,
+		# Display options
+		"i|info"	      => \$config->{opt_info},
+		"c|list-counters"     => \$config->{opt_ctr},
+		"C|list-all-counters" => \$config->{opt_ctr_all},
+		"s|list-sampling-events" => \$config->{opt_ctr_sf},
+	)) {
+		print STDERR "One or more options are not valid\n";
+		print STDERR "Try '" . fileparse($0) .
+			      " --help' for more information\n";
+		exit 1;
+	}
+
+	# Collect CPU-MF information
+	$config->{cpumf} = invoke_cpumf_helper("-i");
+	die "Failed to collect CPU-MF information: $!\n" unless $config->{cpumf};
+
+	# Process parameters
+	my $exitval = 5;
+	if (defined($config->{opt_info})) {
+		do_show_cf($config);
+		do_show_sf($config);
+		$exitval = 0;
+
+	} elsif (defined($config->{opt_ctr})) {
+		$exitval = do_show_ctr($config);
+	} elsif (defined($config->{opt_ctr_all})) {
+		$exitval = do_show_ctr($config, "all")
+	} elsif (defined($config->{opt_ctr_sf})) {
+		$exitval = do_show_sf_events($config);
+	} else {
+		$exitval = do_show_info($config);
+	}
+
+	exit($exitval);
+}
+
+sub show_help()
+{
+	my $prog = fileparse($0);
+
+	print <<"EoHelp";
+Usage:	lscpumf -h|-v
+	lscpumf [-i]
+	lscpumf -c|-C
+
+Options:
+	-i    Displays detailed information.
+	-c    Lists counters for which the LPAR is authorized.
+	-C    Lists counters regardless of LPAR authorization.
+	-s    Lists perf raw events that activate the sampling facility.
+	-h    Displays help information, then exits.
+	-v    Displays version information, then exits.
+
+For more help information, issue 'man $prog'.
+EoHelp
+	exit 0;
+}
+
+sub show_version()
+{
+	print <<'EoVersion';
+CPU-measurement facility utilities, version @S390_TOOLS_RELEASE@
+Copyright IBM Corp. 2014
+
+EoVersion
+	exit 0;
+}
+
+sub do_show_info($)
+{
+	my $c = shift();
+	my $cpumf = $c->{cpumf};
+	my @f = ();
+
+	push @f, "CPU-measurement Counter Facility" if exists $cpumf->{cf};
+	push @f, "CPU-measurement Sampling Facility" if exists $cpumf->{cf};
+
+	if (@f) {
+		print((join "\n", @f) . "\n");
+	} else {
+		print STDERR "No CPU-measurement facilities detected\n";
+		return 2;
+	}
+	return 0;
+}
+
+sub do_show_cf($)
+{
+	my $c = shift();
+
+	# Check if counter facility is available
+	unless (exists $c->{cpumf}->{cf}) {
+		print STDERR "No CPU-measurement counter facility detected\n";
+		return 2;
+	}
+
+	# Retrieve counter facility information
+	my $cf = $c->{cpumf}->{cf};
+
+	# Create list of authorized counter sets
+	my @sets = ();
+	push @sets, "None" unless $cf->{auth};
+	push @sets, "Crypto-Activity counter set" if $cf->{auth} & 0x8;
+	push @sets, "Problem-State counter set" if $cf->{auth} & 0x4;
+	push @sets, "Basic counter set" if $cf->{auth} & 0x2;
+	push @sets, "Extented counter set" if $cf->{auth} & 0x1;
+
+	print "CPU-measurement counter facility\n";
+	print "-" x 74 . "\n";
+	# TODO Display additional information about available conters depending
+	# on the version information
+	print "Version: " . $cf->{version} . "\n";
+	print "\n";
+	print "Authorized counter sets:\n";
+	print "    $_\n" foreach (sort @sets);
+	printf "\nLinux perf event support: %s\n\n",
+	       exists $cf->{perf} ? "Yes (PMU: $cf->{perf})" : "No";
+
+	return 0;
+}
+
+sub div_ceil($$)
+{
+	my ($a, $b) = @_;
+	return int(($a + $b - 1) / $b);
+}
+
+sub humanize_bytes($;$)
+{
+	my $bytes = shift();
+	my @units = split //, " KMGTPEZY";
+
+	my $u = @_ ? shift() : 0;
+	while ($bytes >= 1024 && $u <= $#units) {
+		$bytes /= 1024;
+		$u++;
+	}
+	return sprintf "%.f%sB", $bytes, $units[$u];
+}
+
+sub get_sfb_details($)
+{
+	my $n_sdb = shift();
+
+	# Calculate sampling buffer structure
+	my $n_sdbt = div_ceil($n_sdb, 511);
+	my $n_pages = $n_sdb + $n_sdbt;
+	return [
+		$n_sdb,		    # number of sample-data-blocks
+		$n_sdbt,	    # number of sample-data-block-tables
+		$n_pages,	    # number of 4K pages
+		$n_pages * 4096,    # size in bytes
+	];
+}
+
+sub do_show_sf($)
+{
+	my $c = shift();
+
+	# Check if sampling facility is available
+	unless (exists $c->{cpumf}->{sf}) {
+		print STDERR "No CPU-measurement sampling facility detected\n";
+		return 2;
+	}
+	my $sf = $c->{cpumf}->{sf};
+	my $size = invoke_cpumf_helper("--sfb-size");
+
+	# Sampling facility information
+	print "CPU-measurement sampling facility\n";
+	print "-" x 74 . "\n";
+	print  "Sampling Interval:\n";
+	printf "     Minimum: %10u cycles (approx. %8u Hz)\n",
+		$sf->{min_sampl_interval},
+		1000000 * $sf->{cpu_speed} / $sf->{min_sampl_interval};
+	printf "     Maximum: %10u cycles (approx. %8u Hz)\n",
+		$sf->{max_sampl_interval},
+		1000000 * $sf->{cpu_speed} / $sf->{max_sampl_interval};
+	print "\n";
+	print "Authorized sampling modes:\n";
+	foreach my $m (sort keys %{$sf->{modes}}) {
+		printf "     %-10s (sample size: %3u bytes)\n", $m,
+		       $sf->{modes}->{$m}->{sample_size};
+	}
+	print "\n";
+	printf "\nLinux perf event support: %s\n\n",
+	       exists $sf->{perf} ? "Yes (PMU: $sf->{perf})" : "No";
+
+	# Sampling buffer settings for cpum_sf
+	goto out unless exists $sf->{perf};
+
+	print "Current sampling buffer settings for $sf->{perf}:\n";
+	printf "    Basic-sampling mode\n";
+	my $s = get_sfb_details($size->[0]);
+	printf "	Minimum: %6u sample-data-blocks (%6s)\n",
+			$s->[0], humanize_bytes($s->[3]);
+	$s = get_sfb_details($size->[1]);
+	printf "	Maximum: %6u sample-data-blocks (%6s)\n",
+			$s->[0], humanize_bytes($s->[3]);
+	unless (exists $sf->{modes}->{diagnostic}) {
+		goto out;
+	}
+
+	# Sampling buffer setting specific to diagnostic-sampling mode
+	my $f_diag = div_ceil($sf->{modes}->{diagnostic}->{sample_size},
+			      $sf->{modes}->{basic}->{sample_size});
+	print  "\n";
+	printf "    Diagnostic-sampling mode (including basic-sampling)\n";
+	$s = get_sfb_details($size->[0] * $f_diag);
+	printf "	Minimum: %6u sample-data-blocks (%6s)\n",
+			$s->[0], humanize_bytes($s->[3]);
+	$s = get_sfb_details($size->[1] * $f_diag);
+	printf "	Maximum: %6u sample-data-blocks (%6s)\n",
+			$s->[0], humanize_bytes($s->[3]);
+	printf "        Size factor: %2u\n", $f_diag;
+out:
+	return 0;
+}
+
+sub print_counters($$)
+{
+	my ($ctrdef, $header) = @_;
+	my $set_name_map = invoke_cpumf_helper('--ctr-set-names');
+	my $out = [];
+
+	my ($ctr_perf, $ctr_num, $set, $name, $desc);
+	format PERF_CTR_FORM =
+r@<<<<	@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$ctr_perf,   $name
+
+		^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+		$desc
+		^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~
+		$desc
+		@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+		$set
+
+.
+	print $header;
+	$~ = "PERF_CTR_FORM";
+	foreach my $ctr (sort { $a <=> $b } keys %$ctrdef) {
+		$ctr_perf = sprintf "%x", $ctr;
+		$ctr_num = $ctr < (1 << 16) ? $ctr : "";
+		$name = $ctrdef->{$ctr}->{name};
+		$desc = $ctrdef->{$ctr}->{shortdesc} ?
+				  $ctrdef->{$ctr}->{shortdesc}
+				: $ctrdef->{$ctr}->{desc};
+		$desc .= ".";
+		$set = $set_name_map->{$ctrdef->{$ctr}->{set}};
+		if ($set) {
+			$set = "Counter $ctr_num / $set.";
+		} else {
+			$set = "This event is not associated with a counter set.";
+		}
+		write;
+	}
+}
+
+sub do_show_ctr($;$)
+{
+	my $c = shift();
+	my $auth = @_ ? hex("0xFFFF") : $c->{cpumf}->{cf}->{auth};
+
+	# Check if counter facility is available
+	unless (exists $c->{cpumf}->{cf}) {
+		print STDERR "No CPU-measurement counter facility detected\n";
+		return 2;
+	}
+
+	# Retrieve counter information
+	my $ctrs = invoke_cpumf_helper("-c $auth");
+	unless ($ctrs) {
+		print STDERR "No counters are available or authorized\n";
+		return 3;
+	}
+
+	# Retrieve hardware type
+	my $hwtype = invoke_cpumf_helper("--hardware-type");
+	my $header = <<"EoHeader";
+Perf event counter list for $hwtype->[1]
+==============================================================================
+
+Raw
+event	Name	Description
+------------------------------------------------------------------------------
+EoHeader
+	print_counters($ctrs, $header);
+
+	return 0;
+}
+
+sub do_show_sf_events($)
+{
+	my $c = shift();
+
+	# Check if sampling facility is available
+	unless (exists $c->{cpumf}->{sf}) {
+		print STDERR "No CPU-measurement sampling facility detected\n";
+		return 2;
+	}
+	my $sf = $c->{cpumf}->{sf};
+	my $events = invoke_cpumf_helper("--ctr-sf");
+
+	# Remove events with missing authorization
+	delete $events->{0xB0000} unless exists $sf->{modes}->{basic};
+	delete $events->{0xBD000} unless exists $sf->{modes}->{diagnostic};
+
+	unless ($events) {
+		print STDERR "Sampling facility is not authorized\n";
+		return 3;
+	}
+
+	# Display sampling facility events (aka. counters)
+	my $hwtype = invoke_cpumf_helper("--hardware-type");
+	my $header = <<"EoHeader";
+Perf events for activating the sampling facility
+==============================================================================
+
+Raw
+event	Name	Description
+------------------------------------------------------------------------------
+EoHeader
+	print_counters($events, $header);
+
+	return 0;
+}
+
+sub invoke_cpumf_helper($)
+{
+	my $parms = shift();
+	my $result;
+
+	# Call helper module
+	my $output = qx"$CPUMF_HELPER $parms";
+	die "Failed to run helper module for '$parms'\n" if $? >> 8;
+	$result = eval "$output";
+	die "Failed to parse helper module data\n" if $@;
+
+	return $result;
+}
+
+&main();
+__DATA__
+__END__
--- /dev/null
+++ b/cpumf/data/cpum-cf-extended-z10.ctr
@@ -0,0 +1,96 @@
+Counter: 128	Name:L1I_L2_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from the Level-2 (L1.5) cache
+.
+Counter: 129	Name:L1D_L2_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the installed
+cache line was sourced from the Level-2 (L1.5) cache
+.
+Counter: 130	Name:L1I_L3_LOCAL_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the installed
+cache line was sourced from the Level-3 cache that is on the same book
+as the Instruction cache (Local L2 cache)
+.
+Counter: 131	Name:L1D_L3_LOCAL_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the installtion
+cache line was source from the Level-3 cache that is on the same book
+as the Data cache (Local L2 cache)
+.
+Counter: 132	Name:L1I_L3_REMOTE_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the installed
+cache line was sourced from a Level-3 cache that is not on the same
+book as the Instruction cache (Remote L2 cache)
+.
+Counter: 133	Name:L1D_L3_REMOTE_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the installed
+cache line was sourced from a Level-3 cache that is not on the same
+book as the Data cache (Remote L2 cache)
+.
+Counter: 134	Name:L1D_LMEM_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the installed
+cache line was sourced from memory that is attached to the same book
+as the Data cache (Local Memory)
+.
+Counter: 135	Name:L1I_LMEM_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache where the installed cache
+line was sourced from memory that is attached to the s ame book as the
+Instruction cahe (local Memory)
+.
+Counter: 136	Name:L1D_RO_EXCL_WRITES
+Description:
+A directory write to the Level-1 D-Cache where the line was originally
+in a Read-Only state in the cache but has been updated to be in the
+Exclusive state that allows stores to the cache line
+.
+Counter: 137	Name:L1I_CACHELINE_INVALIDATES
+Description:
+A cache line in the Level-1 I-Cache has been invalidated by a store on
+the same CPU as the Level-1 I-Cache
+.
+Counter: 138	Name:ITLB1_WRITES
+Description:
+A translation entry has been written into the Level-1 Instruction
+Translation Lookaside Buffer
+.
+Counter: 139	Name:DTLB1_WRITES
+Description:
+A translation entry has been written to the Level-1 Data Translation
+Lookaside Buffer
+.
+Counter: 140	Name:TLB2_PTE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Page Table
+Entry arrays
+.
+Counter: 141	Name:TLB2_CRSTE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Common Region
+Segment Table Entry arrays
+.
+Counter: 142	Name:TLB2_CRSTE_HPAGE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Common Region
+Segment Table Entry arrays for a one-megabyte large page translation
+.
+Counter: 145	Name:ITLB1_MISSES
+Description:
+Level-1 Instruction TLB miss in progress. Incremented by one for every
+cycle an ITLB1 miss is in progress
+.
+Counter: 146	Name:DTLB1_MISSES
+Description:
+Level-1 Data TLB miss in progress. Incremented by one for every cycle
+an DTLB1 miss is in progress
+.
+Counter: 147	Name:L2C_STORES_SENT
+Description:
+Incremented by one for every store sent to Level-2 (L1.5) cache
+.
--- /dev/null
+++ b/cpumf/data/cpum-cf-extended-z196.ctr
@@ -0,0 +1,122 @@
+Counter: 128	Name:L1D_L2_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the returned
+cache line was sourced from the Level-2 cache
+.
+Counter: 129	Name:L1I_L2_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from the Level-2 cache
+.
+Counter: 130	Name:DTLB1_MISSES
+Description:
+Level-1 Data TLB miss in progress. Incremented by one for every cycle
+a DTLB1 miss is in progress.
+.
+Counter: 131	Name:ITLB1_MISSES
+Description:
+Level-1 Instruction TLB miss in progress. Incremented by one for every
+cycle a ITLB1 miss is in progress.
+.
+Counter: 133	Name:L2C_STORES_SENT
+Description:
+Incremented by one for every store sent to Level-2 cache
+.
+Counter: 134	Name:L1D_OFFBOOK_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the returned
+cache line was sourced from an Off Book Level-3 cache
+.
+Counter: 135	Name:L1D_ONBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the returned
+cache line was sourced from an On Book Level-4 cache
+.
+Counter: 136	Name:L1I_ONBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from an On Book Level-4 cache
+.
+Counter: 137	Name:L1D_RO_EXCL_WRITES
+Description:
+A directory write to the Level-1 D-Cache where the line was originally
+in a Read-Only state in the cache but has been updated to be in the
+Exclusive state that allows stores to the cache line
+.
+Counter: 138	Name:L1D_OFFBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the returned
+cache line was sourced from an Off Book Level-4 cache
+.
+Counter: 139	Name:L1I_OFFBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from an Off Book Level-4 cache
+.
+Counter: 140	Name:DTLB1_HPAGE_WRITES
+Description:
+A translation entry has been written to the Level-1 Data Translation
+Lookaside Buffer for a one-megabyte page
+.
+Counter: 141	Name:L1D_LMEM_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache where the installed cache line
+was sourced from memory that is attached to the same book as the Data
+cache (Local Memory)
+.
+Counter: 142	Name:L1I_LMEM_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache where the installed cache
+line was sourced from memory that is attached to the same book as the
+Instruction cache (Local Memory)
+.
+Counter: 143	Name:L1I_OFFBOOK_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from an Off Book Level-3 cache
+.
+Counter: 144	Name:DTLB1_WRITES
+Description:
+A translation entry has been written to the Level-1 Data Translation
+Lookaside Buffer
+.
+Counter: 145	Name:ITLB1_WRITES
+Description:
+A translation entry has been written to the Level-1 Instruction
+Translation Lookaside Buffer
+.
+Counter: 146	Name:TLB2_PTE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Page Table
+Entry arrays
+.
+Counter: 147	Name:TLB2_CRSTE_HPAGE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Common Region
+Segment Table Entry arrays for a one-megabyte large page translation
+.
+Counter: 148	Name:TLB2_CRSTE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Common Region
+Segment Table Entry arrays
+.
+Counter: 150	Name:L1D_ONCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the returned
+cache line was sourced from an On Chip Level-3 cache
+.
+Counter: 152	Name:L1D_OFFCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 D-Cache directory where the returned
+cache line was sourced from an Off Chip/On Book Level-3 cache
+.
+Counter: 153	Name:L1I_ONCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from an On Chip Level-3 cache
+.
+Counter: 155	Name:L1I_OFFCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 I-Cache directory where the returned
+cache line was sourced from an Off Chip/On Book Level-3 cache
+.
--- /dev/null
+++ b/cpumf/data/cpum-cf-extended-zEC12.ctr
@@ -0,0 +1,195 @@
+Counter: 128	Name:DTLB1_MISSES
+Description:
+Level-1 Data TLB miss in progress. Incremented by one for every cycle
+a DTLB1 miss is in progress.
+.
+Counter:129	Name:ITLB1_MISSES
+Description:
+Level-1 Instruction TLB miss in progress. Incremented by one for every
+cycle a ITLB1 miss is in progress.
+.
+Counter:130	Name:L1D_L2I_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from the Level-2 Instruction cache
+.
+Counter:131	Name:L1I_L2I_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from the Level-2 Instruction cache
+.
+Counter:132	Name:L1D_L2D_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from the Level-2 Data cache
+.
+Counter:133	Name:DTLB1_WRITES
+Description:
+A translation entry has been written to the Level-1 Data Translation
+Lookaside Buffer
+.
+Counter:135	Name:L1D_LMEM_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache where the installed cache line
+was sourced from memory that is attached to the same book as the Data
+cache (Local Memory)
+.
+Counter:137	Name:L1I_LMEM_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache where the installed cache
+line was sourced from memory that is attached to the same book as the
+Instruction cache (Local Memory)
+.
+Counter:138	Name:L1D_RO_EXCL_WRITES
+Description:
+A directory write to the Level-1 D-Cache where the line was originally
+in a Read-Only state in the cache but has been updated to be in the
+Exclusive state that allows stores to the cache line
+.
+Counter:139	Name:DTLB1_HPAGE_WRITES
+Description:
+A translation entry has been written to the Level-1 Data Translation
+Lookaside Buffer for a one-megabyte page
+.
+Counter:140	Name:ITLB1_WRITES
+Description:
+A translation entry has been written to the Level-1 Instruction
+Translation Lookaside Buffer
+.
+Counter:141	Name:TLB2_PTE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Page Table
+Entry arrays
+.
+Counter:142	Name:TLB2_CRSTE_HPAGE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Common Region
+Segment Table Entry arrays for a one-megabyte large page translation
+.
+Counter:143	Name:TLB2_CRSTE_WRITES
+Description:
+A translation entry has been written to the Level-2 TLB Common Region
+Segment Table Entry arrays
+.
+Counter:144	Name:L1D_ONCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an On Chip Level-3 cache without intervention
+.
+Counter:145	Name:L1D_OFFCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an Off Chip/On Book Level-3 cache without
+intervention
+.
+Counter:146	Name:L1D_OFFBOOK_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an Off Book Level-3 cache without intervention
+.
+Counter:147	Name:L1D_ONBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an On Book Level-4 cache
+.
+Counter:148	Name:L1D_OFFBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an Off Book Level-4 cache
+.
+#
+# Notes for the transactional-execution mode notations:
+#   TX .. transactional-execution mode
+#   NC .. nonconstrained
+#    C .. constrained
+#
+Counter:149	Name:TX_NC_TEND
+Description:
+A TEND instruction has completed in a nonconstrained
+transactional-execution mode
+.
+Counter:150	Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from a On Chip Level-3 cache with intervention
+.
+Counter:151	Name:L1D_OFFCHIP_L3_SOURCED_WRITES_IV
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an Off Chip/On Book Level-3 cache with
+intervention
+.
+# XXX Remove SOURCED from L1D_OFFBOOK_L3_SOURCED_WRITES...
+Counter:152	Name:L1D_OFFBOOK_L3_SOURCED_WRITES_IV
+Description:
+A directory write to the Level-1 Data cache directory where the returned
+cache line was sourced from an Off Book Level-3 cache with intervention
+.
+Counter:153	Name:L1I_ONCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an On Chip Level-3 cache without
+intervention
+.
+Counter:154	Name:L1I_OFFCHIP_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an Off Chip/On Book Level-3 cache
+without intervention
+.
+Counter:155	Name:L1I_OFFBOOK_L3_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an Off Book Level-3 cache without
+intervention
+.
+Counter:156	Name:L1I_ONBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an On Book Level-4 cache
+.
+Counter:157	Name:L1I_OFFBOOK_L4_SOURCED_WRITES
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an Off Book Level-4 cache
+.
+Counter:158	Name:TX_C_TEND
+Description:
+A TEND instruction has completed in a constrained transactional-execution
+mode
+.
+Counter:159	Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an On Chip Level-3 cache with
+intervention
+.
+Counter:160	Name:L1I_OFFCHIP_L3_SOURCED_WRITES_IV
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an Off Chip/On Book Level-3 cache
+with intervention
+.
+Counter:161	Name:L1I_OFFBOOK_L3_SOURCED_WRITES_IV
+Description:
+A directory write to the Level-1 Instruction cache directory where the
+returned cache line was sourced from an Off Book Level-3 cache with
+intervention
+.
+Counter:177	Name:TX_NC_TABORT
+Description:
+A transaction abort has occurred in a nonconstrained
+transactional-execution mode
+.
+Counter:178	Name:TX_C_TABORT_NO_SPECIAL
+Description:
+A transaction abort has occurred in a constrained transactional-execution
+mode and the CPU is not using any special logic to allow the transaction
+to complete
+.
+Counter:179	Name:TX_C_TABORT_SPECIAL
+Description:
+A transaction abort has occurred in a constrained transactional-execution
+mode and the CPU is using special logic to allow the transaction to
+complete
+.
--- /dev/null
+++ b/cpumf/data/cpum-cf-generic.ctr
@@ -0,0 +1,132 @@
+Counter:   0	Name:CPU_CYCLES
+Description:
+Cycle Count
+.
+Counter:   1	Name:INSTRUCTIONS
+Description:
+Instruction Count
+.
+Counter:   2	Name:L1I_DIR_WRITES
+Description:
+Level-1 I-Cache Directory Write Count
+.
+Counter:   3	Name:L1I_PENALTY_CYCLES
+Description:
+Level-1 I-Cache Penalty Cycle Count
+.
+Counter:   4	Name:L1D_DIR_WRITES
+Description:
+Level-1 D-Cache Directory Write Count
+.
+Counter:   5	Name:L1D_PENALTY_CYCLES
+Description:
+Level-1 D-Cache Penalty Cycle Count
+.
+Counter:  32	Name:PROBLEM_STATE_CPU_CYCLES
+Description:
+Problem-State Cycle Count
+.
+Counter:  33	Name:PROBLEM_STATE_INSTRUCTIONS
+Description:
+Problem-State Instruction Count
+.
+Counter:  34	Name:PROBLEM_STATE_L1I_DIR_WRITES
+Description:
+Problem-State Level-1 I-Cache Directory Write Count
+.
+Counter:  35	Name:PROBLEM_STATE_L1I_PENALTY_CYCLES
+Description:
+Problem-State Level-1 I-Cache Penalty Cycle Count
+.
+Counter:  36	Name:PROBLEM_STATE_L1D_DIR_WRITES
+Description:
+Problem-State Level-1 D-Cache Directory Write Count
+.
+Counter:  37	Name:PROBLEM_STATE_L1D_PENALTY_CYCLES
+Description:
+Problem-State Level-1 D-Cache Penalty Cycle Count
+.
+Counter:  64	Name:PRNG_FUNCTIONS
+Description:
+Total number of the PRNG functions issued by the CPU
+.
+Counter:  65	Name:PRNG_CYCLES
+Description:
+Total number of CPU cycles when the DEA/AES coprocessor is busy
+performing PRNG functions issued by the CPU
+.
+Counter:  66	Name:PRNG_BLOCKED_FUNCTIONS
+Description:
+Total number of the PRNG functions that are issued by the CPU and are
+blocked because the DEA/AES coprocessor is busy performing a function
+issued by another CPU
+.
+Counter:  67	Name:PRNG_BLOCKED_CYCLES
+Description:
+Total number of CPU cycles blocked for the PRNG functions issued by
+the CPU because the DEA/AES coprocessor is busy performing a function
+issued by another CPU
+.
+Counter:  68	Name:SHA_FUNCTIONS
+Description:
+Total number of SHA functions issued by the CPU
+.
+Counter:  69	Name:SHA_CYCLES
+Description:
+Total number of CPU cycles when the SHA coprocessor is busy performing
+the SHA functions issued by the CPU
+.
+Counter:  70	Name:SHA_BLOCKED_FUNCTIONS
+Description:
+Total number of the SHA functions that are issued by the CPU and are
+blocked because the SHA coprocessor is busy performing a function issued
+by another CPU
+.
+Counter:  71	Name:SHA_BLOCKED_CYCLES
+Description:
+Total number of CPU cycles blocked for the SHA functions issued by the
+CPU because the SHA coprocessor is busy performing a function issued
+by another CPU
+.
+Counter:  72	Name:DEA_FUNCTIONS
+Description:
+Total number of the DEA functions issued by the CPU
+.
+Counter:  73	Name:DEA_CYCLES
+Description:
+Total number of CPU cycles when the DEA/AES coprocessor is busy
+performing the DEA functions issued by the CPU
+.
+Counter:  74	Name:DEA_BLOCKED_FUNCTIONS
+Description:
+Total number of the DEA functions that are issued by the CPU and are
+blocked because the DEA/AES coprocessor is busy performing a function
+issued by another CPU
+.
+Counter:  75	Name:DEA_BLOCKED_CYCLES
+Description:
+Total number of CPU cycles blocked for the DEA functions issued by the
+CPU because the DEA/AES coprocessor is busy performing a function issued
+by another CPU
+.
+Counter:  76	Name:AES_FUNCTIONS
+Description:
+Total number of AES functions issued by the CPU
+.
+Counter:  77	Name:AES_CYCLES
+Description:
+Total number of CPU cycles when the DEA/AES coprocessor is busy
+performing the AES functions issued by the CPU
+.
+Counter:  78	Name:AES_BLOCKED_FUNCTIONS
+Description:
+Total number of AES functions that are issued by the CPU and are blocked
+because the DEA/AES coprocessor is busy performing a function issued
+by another CPU
+.
+Counter:  79	Name:AES_BLOCKED_CYCLES
+Description:
+Total number of CPU cycles blocked for the AES functions issued by the
+CPU because the DEA/AES coprocessor is busy performing a function issued
+by another CPU
+.
--- /dev/null
+++ b/cpumf/data/cpum-cf-hw-counter.map
@@ -0,0 +1,15 @@
+# CPU-measurement facilities
+#
+# Mapping of IBM System z hardware types to extended counter set defintions
+#
+#
+{
+	# Definition	   # File name
+	   0		=> 'cpum-cf-generic.ctr',
+	2097		=> 'cpum-cf-extended-z10.ctr',
+	2098		=> 'cpum-cf-extended-z10.ctr',
+	2817		=> 'cpum-cf-extended-z196.ctr',
+	2818		=> 'cpum-cf-extended-z196.ctr',
+	2827		=> 'cpum-cf-extended-zEC12.ctr',
+	2828		=> 'cpum-cf-extended-zEC12.ctr',
+};
--- /dev/null
+++ b/cpumf/data/cpum-sf-modes.ctr
@@ -0,0 +1,13 @@
+# Perf raw event counter definitions for the
+#   CPU-measurment sampling facility
+#
+# Basic-sampling mode
+Counter: 0xB0000  Name:SF_CYCLES_BASIC
+Description:
+Sample CPU cycles using basic-sampling mode
+.
+# Diagnostic-sampling mode (includes basic-sampling)
+Counter: 0xBD000  Name:SF_CYCLES_BASIC_DIAG
+Description:
+Sample CPU cycle using diagnostic-sampling mode (not for ordinary use)
+.
--- /dev/null
+++ b/cpumf/man/chcpumf.8
@@ -0,0 +1,66 @@
+.\" chcpumf.8
+.\"
+.\"
+.\" Copyright IBM Corp. 2014
+.\" Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+.\" ----------------------------------------------------------------------
+.TH chcpumf "8" "February 2014" "s390-tools" "CPU-MF management programs"
+.
+.LO 8
+.ds c \fBchcpumf\fP
+.
+.
+.SH NAME
+chcpumf \- manage the CPU-measurement facilities support
+.
+.
+.SH SYNOPSIS
+.B chcpumf
+.RB [ \-m | \-\-min
+.IR num_sdb ]
+.RB [ \-x | \-\-max
+.IR num_sdb ]
+.br
+.B chcpumf
+.BR \-h | \-\-help
+.br
+.B chcpumf
+.BR \-v | \-\-version
+.
+.
+.SH DESCRIPTION
+The chcpumf program helps you to manage settings for the CPU-measurement
+facilities for Linux on System z.
+.
+.
+.SH OPTIONS
+.TP
+.BR \-m ", " \-\-min " \fInum_sdb\fP"
+Specifies the minimum sampling facility buffer size in sample-data-blocks
+(SDB).  A sample-data-block consumes about 4 kilobytes.
+
+This is the initial buffer size when you start the sampling facility.
+.
+.TP
+.BR \-x ", " \-\-max " \fInum_sdb\fP"
+Specifies the maximum sampling facility buffer size in sample-data-blocks
+(SDB).  A sample-data-block consumes about 4 kilobytes.
+
+This is the maximum size to which the buffer is dynamically adjusted during
+sampling.
+.
+.TP
+.BR \-V ", " \-\-verbose
+Displays verbose messages.
+.
+.TP
+.BR \-h ", " \-\-help
+Displays help information, then exits.
+.
+.TP
+.BR \-v ", " \-\-version
+Displays version information, then exits.
+.
+.
+.SH "SEE ALSO"
+.BR lscpumf (1)
--- /dev/null
+++ b/cpumf/man/lscpumf.1
@@ -0,0 +1,70 @@
+\" lscpumf.1
+.\"
+.\"
+.\" Copyright IBM Corp. 2014
+.\" Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+.\" ----------------------------------------------------------------------
+.TH lscpumf "1" "February 2014" "s390-tools" "CPU-MF management programs"
+.
+.LO 8
+.ds c \fBlscpumf\fP
+.
+.
+.SH NAME
+lscpumf \- display information about CPU-measurement facilities
+.
+.
+.SH SYNOPSIS
+.B lscpumf
+.RB [ \-i | \-\-info ]
+.br
+.B lscpumf
+.RB [ \-c | \-\-list\-counters ]
+.RB [ \-C | \-\-list\-all\-counters ]
+.RB [ \-s | \-\-list\-sampling\-events ]
+.br
+.B lscpumf
+.BR \-h | \-\-help
+.br
+.B lscpumf
+.BR \-v | \-\-version
+.
+.
+.SH DESCRIPTION
+The lscpumf program lists information about CPU-measurement facilities that
+are supported by Linux on System z.
+.
+.
+.SH OPTIONS
+.TP
+.BR \-i ", " \-\-info
+Displays detailed information about available and supported CPU-measurement
+facilities.
+.
+.TP
+.BR \-c ", " \-\-list\-counters
+Lists counters that are provided by the CPU-measurement facility, omitting
+counters for which the LPAR is not authorized. For counter measurements with
+the perf program, the raw event identifier is displayed.
+.
+.TP
+.BR \-C ", " \-\-list\-all\-counters
+Lists all counters that are provided by the CPU-measurement counter facility,
+regardless of LPAR authorization. To list only those counters for which the
+LPAR is authorized, use the -c option.
+.
+.TP
+.BR \-s ", " \-\-list\-sampling\-events
+Lists perf raw events that activate the sampling facility.
+.
+.TP
+.BR \-h ", " \-\-help
+Displays help information, then exits.
+.
+.TP
+.BR \-v ", " \-\-version
+Displays version information, then exits.
+.
+.
+.SH "SEE ALSO"
+.BR chcpumf (8)
