#===============================================================#
#                                                               #
# $ID$                                                          #
#                                                               #
# perf_aggr_latency.pl                                          #
#                                                               #
# Copyright (c) 2009 NetApp, Inc. All rights reserved.          #
# Specifications subject to change without notice.              #
#                                                               #
# We do not have API to get read_latency, write_latency, and    #
# average_latency at aggregate level. This sample code          #
# demonstrates a method to get this data by reading the         #
# required latency of all volumes for the given aggregate.      #
# Use this information to generate latency at aggregate level.  #
#                                                               #
# This Sample code is supported from DataFabric Manager 3.7.1   #
# onwards.                                                      #
# However few of the functionalities of the sample code may     #
# work on older versions of DataFabric Manager.                 #
#===============================================================#

require 5.6.1;
use strict;
use warnings;

use lib '../../../../../../../lib/perl/NetApp';
use NaServer;
use NaElement;

# Command line arguments
my $args = scalar @ARGV;
my $dfm = shift;
my $user = shift;
my $pw  = shift;
my $aggr_name = shift;

my @time;
my @read_latency;
my @write_latency;
my @avg_latency;

sub main() {
	# check for valid number of parameters
	if ($args != 4)	{
		die print_help();
	}

	my $perf_out = invoke_perf_zapi();
	extract_perf_counter_data($perf_out);
	print_output();

	exit 0;
}

sub invoke_perf_zapi() {
	# Initialize server context
	my $server_ctx = NaServer->new ($dfm, 1, 0);
	$server_ctx->set_transport_type("HTTP");
	$server_ctx->set_style("LOGIN");
	$server_ctx->set_admin_user($user, $pw);
	$server_ctx->set_server_type("DFM");
	$server_ctx->set_port(8088);

	# Create API request
	my $perf_in = NaElement->new("perf-get-counter-data");
	$perf_in->child_add_string("duration", 6000);
	$perf_in->child_add_string("number-samples", 50);
	$perf_in->child_add_string("time-consolidation-method", "average");

	my $instance_info = NaElement->new("instance-counter-info");
	$instance_info->child_add_string("object-name-or-id", $aggr_name);

	my $counter_info = NaElement->new("counter-info");
	my $perf_obj_ctr1 = NaElement->new("perf-object-counter");
	$perf_obj_ctr1->child_add_string("object-type", "volume");
	$perf_obj_ctr1->child_add_string("counter-name", "read_latency");

	my $perf_obj_ctr2 = NaElement->new("perf-object-counter");
	$perf_obj_ctr2->child_add_string("object-type", "volume");
	$perf_obj_ctr2->child_add_string("counter-name", "write_latency");

	my $perf_obj_ctr3 = NaElement->new("perf-object-counter");
	$perf_obj_ctr3->child_add_string("object-type", "volume");
	$perf_obj_ctr3->child_add_string("counter-name", "avg_latency");

	$counter_info->child_add($perf_obj_ctr1);
	$counter_info->child_add($perf_obj_ctr2);
	$counter_info->child_add($perf_obj_ctr3);
	$instance_info->child_add($counter_info);
	$perf_in->child_add($instance_info);

	my $perf_out = $server_ctx->invoke_elem($perf_in);
	if($perf_out->results_status() eq "failed") {
		print($perf_out->results_reason() ."\n");
		exit(-2);
	}

	return $perf_out;
}

sub extract_perf_counter_data() {
	my $perf_out = $_[0];

	my $gen_time_arr = 1;
	my $time_i = 0;
	my $read_i = 0;
	my $write_i = 0;
	my $avg_i = 0;
	my $rec;
	my $instance = $perf_out->child_get("perf-instances");
	my @instances = $instance->children_get("perf-instance-counter-data");

	foreach $rec (@instances){
		my $vol_name = $rec->child_get_string("instance-name");
		my $counters = $rec->child_get("counters");
		my @perf_cnt_data = $counters->children_get("perf-counter-data");
		my $rec1;
		foreach $rec1 (@perf_cnt_data) {
			$read_i = 0;
			$write_i = 0;
			$avg_i = 0;
			my $time_val;
			my $counter_name = $rec1->child_get_string("counter-name");
			my $counter_str = $rec1->child_get_string("counter-data");
			my @counter_arr = split (/,/, $counter_str);

			if($counter_name eq "read_latency") {
				foreach $time_val (@counter_arr) {
					my @time_val_arr = split(/:/, $time_val);
					if($gen_time_arr) {
						$time[$time_i++] = localtime($time_val_arr[0]);
					}

					if($read_latency[$read_i]) {
						$read_latency[$read_i] = $read_latency[$read_i] +
									$time_val_arr[1];
					} else {
						$read_latency[$read_i] = $time_val_arr[1];
					}
					$read_i++;
				}
				$gen_time_arr = 0;
			} elsif($counter_name eq "write_latency") {
				foreach $time_val (@counter_arr) {
					my @time_val_arr = split(/:/, $time_val);
					if($gen_time_arr) {
						$time[$time_i++] = localtime($time_val_arr[0]);
					}

					if($write_latency[$write_i]) {
						$write_latency[$write_i] = $write_latency[$write_i] +
									$time_val_arr[1];
					} else {
						$write_latency[$write_i] = $time_val_arr[1];
					}
					$write_i++;
				}
				$gen_time_arr = 0;
			} elsif($counter_name eq "avg_latency") {
				foreach $time_val (@counter_arr) {
					my @time_val_arr = split(/:/, $time_val);
					if($gen_time_arr) {
						$time[$time_i++] = localtime($time_val_arr[0]);
					}

					if ($avg_latency[$avg_i]) {
						$avg_latency[$avg_i] = $avg_latency[$avg_i] +
									$time_val_arr[1];
					} else {
						$avg_latency[$avg_i] = $time_val_arr[1];
					}
					$avg_i++;
				}
				$gen_time_arr = 0;
			}
		}
	}
}

sub print_output() {
	my $i = 0;
	my $samples = scalar(@time);

	print "Time\tRead Latency\tWrite Latency\tAverage Latency\n";

	if ($samples > 0) {
		for($i=0; $i<$samples; $i++) {
			print $time[$i] . "\t";
			print $read_latency[$i]/$samples . "\t";
			print $write_latency[$i]/$samples . "\t";
			print $avg_latency[$i]/$samples . "\n";
		}
	}
}

sub print_help() {
	print "\nCommand:\n";
	print "perf_aggr_latency.pl <dfm> <user> <password> <aggr-name>\n";
	print "<dfm>       -- DFM Server name\n";
	print "<user>      -- User name\n";
	print "<password>  -- Password\n";
	print "<aggr-name> -- Name of the aggregate in format storage:aggrName\n";
	print "-" x 80 . "\n";

	print "This sample code provides information on read latency, write latency\n";
	print "and average latency of an aggregate.\n";
	print "This data can be used to charts to represent data in graphical format.\n";
	print "To generate the graph, redirect output of this sample code to\n";
	print "an Excel sheet.\n";

	exit (-1);
}

#Invoke routine
main();

#=========================== POD ============================#

=head1 NAME

  perf_aggr_latency.pl - This sample code provides information on read latency,
  write latency and average latency of an aggregate.

=head1 SYNOPSIS

  perf_aggr_latency.pl <dfm> <user> <password> <aggr-name>

=head1 ARGUMENTS

  <dfm>
  DFM Server name.

  <user>
  User name.

  <password>
  Password.

  <aggr-name>
  Name of the aggregate in format storage:aggrName.

=head1 SEE ALSO

  NaElement.pm, NaServer.pm

=head1 COPYRIGHT

 Copyright (c) 2009 NetApp, Inc. All rights reserved.
 Specifications subject to change without notice.

=cut
