db_io_type_metrics_source

#!/usr/bin/env perl
#
# Author: Bertrand Drouvot
# Visit my blog : https://bdrouvot.wordpress.com/
# V1.0 (2014/05)
#
# Description:
# Utility used to display database IO type metrics (small,large,writes,reads and synchronous) in real time per snap or per average since the collection began.
# It basically takes a snapshot each second (default interval) of the gv$iostat_file cumulative view and computes the delta
# with the previous snapshot.
# The utility is RAC and Multitenant aware.
# You have to set oraenv on one DB instance
# You can choose the number of snapshots to display and the time to wait between snapshots.
#
# Usage:
# ./db_io_type_metrics.pl -help
#
# Chek for new version : https://bdrouvot.wordpress.com/db_io_type_metrics_script/
#
#----------------------------------------------------------------#

BEGIN {
 die "ORACLE_HOME not set\n" unless $ENV{ORACLE_HOME};
 unless ($ENV{OrAcLePeRl}) {
 $ENV{OrAcLePeRl} = "$ENV{ORACLE_HOME}/perl";
 $ENV{PERL5LIB} = "$ENV{PERL5LIB}:$ENV{OrAcLePeRl}/lib:$ENV{OrAcLePeRl}/lib/site_perl";
 $ENV{LD_LIBRARY_PATH} = "$ENV{LD_LIBRARY_PATH}:$ENV{ORACLE_HOME}/lib32:$ENV{ORACLE_HOME}/lib";
 exec "$ENV{OrAcLePeRl}/bin/perl", $0, @ARGV;
 }
}

use strict;
use DBI;
use DBD::Oracle qw(:ora_session_modes);

use Getopt::Long; 

our %options; 
our $debug=0;
our $version;
our $nb_pdbs=0;
our $interval=1; 
our $count=999999;
our $showinst=0;
our $rac=0;
our $inst_type='RDBMS';
our $dbh;
our $instpattern='all';
our $cont_pattern='';
our $file_type_tbs_pattern='file_type';
our $file_type_pattern='';
our $tbs_pattern='';
our $io_type_pattern='reads';
our $show_pattern='inst';
our $display_pattern='snap';
our $dg_suffixe='';
our $instid_pattern='f.inst_id';
our $sqlsuffixe;
our $sql1;
our $main_sql='';
our %instances;
our %showinstances=();
our %sql_patterns;
our %diffsnaps;
our %avgdiffsnaps=();
our %rtvalues;
our %pkeys;
our $bkey;
our @ekey;
our %ckeys=();
our @array_of_ckeys_description=();
our @array_of_display_keys=();
our @array_of_ckey=();
our @delta_fields;
our $global_sql_pattern='';
our @array_of_report_header;
our $report_format_values;
our @report_fields_values;
our $seconds;
our $minuts;
our $hours;
our @since_timing;
our %sort_fields;
our $sort_field_pattern='';

sub main {
&get_the_options(@ARGV);

 my $ckey_cpt=0; 
 &connect_db;
 $version=check_version();
 if ($version < 11) {&minimum_version()};
 if ($version >= 12) {$nb_pdbs=check_pdbs()};
 
 if ($nb_pdbs == 0) {
 $sort_fields{7}='LARGE_READS';
 $sort_fields{13}='LARGE_WRITES';
 $sort_fields{15}='NONE';
 $sort_fields{3}='SMALL_READS';
 $sort_fields{10}='SMALL_WRITES';
 %sort_fields = reverse %sort_fields;
 if (!$sort_field_pattern) {$sort_field_pattern='NONE'};
 if ($file_type_tbs_pattern =~ m/^file_type$/i ){
 # show file_type instead of tbs
 $instid_pattern="inst_id";
 $sql_patterns{'FILETYPE_NAME'}=$file_type_pattern;
 $main_sql="
 select inst_id,FILETYPE_NAME,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,SMALL_SYNC_READ_LATENCY,LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,$interval,file_no,SMALL_SYNC_READ_REQS from GV\$IOSTAT_FILE
 where 1=1
 ";
 }
 if ($file_type_tbs_pattern =~ m/^tbs$/i ){
 # show tbs instead of file_type
 $instid_pattern="inst_id";
 $sql_patterns{'tbs'}=$tbs_pattern;
 $main_sql="
 select inst_id,tbs,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,
 SMALL_SYNC_READ_LATENCY,LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,
 SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,interval,file_no,SMALL_SYNC_READ_REQS
 from
 (
 select f.inst_id as inst_id,t.name as tbs,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,
 SMALL_SYNC_READ_LATENCY,LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,
 SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,$interval as interval,file_no,SMALL_SYNC_READ_REQS 
 from GV\$IOSTAT_FILE f,gv\$tablespace t, gv\$datafile d 
 where f.inst_id=t.inst_id
 and d.inst_id=f.inst_id
 and d.file#=f.file_no
 and d.ts#=t.ts#
 and f.filetype_name='Data File'
 union all
 select f.inst_id,t.name as tbs,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,
 SMALL_SYNC_READ_LATENCY,LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,
 SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,$interval as interval,file_no,SMALL_SYNC_READ_REQS
 from GV\$IOSTAT_FILE f,gv\$tablespace t, gv\$tempfile d
 where f.inst_id=t.inst_id
 and d.inst_id=f.inst_id
 and d.file#=f.file_no
 and d.ts#=t.ts#
 and f.filetype_name='Temp File'
 ) where 1=1 
 ";
 }
 $pkeys{0}='%30s';
 $pkeys{1}='%100s';
 $pkeys{16}='%100s';
 # What need to be show
 my @show_fields = split (/,/,$show_pattern);
 foreach my $show (@show_fields) {
 if ($show =~ m/^inst$/i ){ 
 # group by instance
 $array_of_ckeys_description[$ckey_cpt]{0}='%30s'; 
 $array_of_ckeys_description[$ckey_cpt]{15}='%10s';
 $array_of_display_keys[$ckey_cpt]{0}='y'; 
 $array_of_display_keys[$ckey_cpt]{15}='y';
 $ckey_cpt=$ckey_cpt+1; 
 }
 if ($show =~ m/^file_type_tbs$/i ){
 # group by filetype or tbs
 $array_of_ckeys_description[$ckey_cpt]{15}='%10s';
 $array_of_display_keys[$ckey_cpt]{15}='y';
 if (grep (/^inst$/i,@show_fields)) {
 $array_of_ckeys_description[$ckey_cpt]{0}='%30s';
 $array_of_display_keys[$ckey_cpt]{0}='y';
 }
 $array_of_ckeys_description[$ckey_cpt]{1}='%100s';
 $array_of_display_keys[$ckey_cpt]{1}='y';
 $ckey_cpt=$ckey_cpt+1; 
 }
 }
 @delta_fields=(2,3,4,5,6,7,8,9,10,11,12,13,14,17);
 if ($io_type_pattern =~ m/^reads$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.3f %1s %-7.2f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,"2/15","3/15","6/15","7/15","2/3","6/7","4/3","8/7");
 @array_of_report_header=(["%02d:%02d:%02d %43s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','SMALL R','','SMALL R','','LARGE R','','LARGE R','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','SMALL R','','LARGE R','','SMALL R','','LARGE R'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^writes$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.3f %1s %-7.2f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,"9/15","10/15","12/15","13/15","9/10","12/13","11/10","14/13");
 @array_of_report_header=(["%02d:%02d:%02d %43s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','SMALL W','','SMALL W','','LARGE W','','LARGE W','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','SMALL W','','LARGE W','','SMALL W','','LARGE W'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^small$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.3f %1s %-7.3f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,"2/15","3/15","9/15","10/15","2/3","9/10","4/3","11/10");
 @array_of_report_header=(["%02d:%02d:%02d %43s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','SMALL R','','SMALL R','','SMALL W','','SMALL W','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','SMALL R','','SMALL W','','SMALL R','','SMALL W'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^large$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.2f %1s %-7.2f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,"6/15","7/15","12/15","13/15","6/7","12/13","8/7","14/13");
 @array_of_report_header=(["%02d:%02d:%02d %43s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','LARGE R','','LARGE R','','LARGE W','','LARGE W','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','LARGE R','','LARGE W','','LARGE R','','LARGE W'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^synch$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-7.0f %6s %-7.2f\n";
 @report_fields_values=(1,"17/15","5/17");
 @array_of_report_header=(["%02d:%02d:%02d %43s %1s %-12s %1s %-12s\n",'','','Sync SMALL R','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-12s %1s %-12s\n",'','INST','','FILE_TYPE_TBS','','RQ/s','','Sync SMALL R'],["%02d:%02d:%02d %1s %-10s %1s %-28s %1s %-12s %1s %-12s\n",'','----------','','----------------------------','','------------','','------------']);
 }
 } else {
 #There is pdbs
 $sort_fields{8}='LARGE_READS';
 $sort_fields{14}='LARGE_WRITES';
 $sort_fields{16}='NONE';
 $sort_fields{4}='SMALL_READS';
 $sort_fields{11}='SMALL_WRITES';
 %sort_fields = reverse %sort_fields;
 if (!$sort_field_pattern) {$sort_field_pattern='NONE'};
 if ($file_type_tbs_pattern =~ m/^file_type$/i ){
 # show file_type instead of tbs
 $sql_patterns{'c.name'}=$cont_pattern;
 $sql_patterns{'FILETYPE_NAME'}=$file_type_pattern;
 $instid_pattern="f.inst_id";
 $main_sql="
 select f.inst_id,c.name,FILETYPE_NAME,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,SMALL_SYNC_READ_LATENCY,LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,$interval,file_no,SMALL_SYNC_READ_REQS 
 from GV\$IOSTAT_FILE f, gv\$containers c
 where f.inst_id=c.inst_id and f.con_id=c.con_id
 and c.OPEN_MODE like 'READ%'
 ";
 }
 if ($file_type_tbs_pattern =~ m/^tbs$/i ){
 # show tbs instead of file_type
 $sql_patterns{'cont'}=$cont_pattern;
 $sql_patterns{'tbs'}=$tbs_pattern;
 $instid_pattern="inst_id";
 $main_sql="
 select inst_id,cont,TBS,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,SMALL_SYNC_READ_LATENCY,
 LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,
 SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,interval,file_no,SMALL_SYNC_READ_REQS 
 from
 (
 select f.inst_id as inst_id,c.name as cont,t.name as TBS,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,SMALL_SYNC_READ_LATENCY,
 LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,
 SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,$interval as interval,file_no,SMALL_SYNC_READ_REQS
 from 
 GV\$IOSTAT_FILE f, gv\$containers c, gv\$tablespace t, gv\$datafile d
 where
 f.inst_id=c.inst_id
 and c.con_id=f.con_id
 and d.inst_id=c.inst_id
 and t.inst_id=c.inst_id
 and t.con_id=c.con_id
 and d.con_id=c.con_id
 and d.file#=f.file_no
 and d.ts#=t.ts#
 and f.filetype_name='Data File'
 and c.OPEN_MODE like 'READ%'
 union all
 select f.inst_id as inst_id,c.name as cont,t.name as TBS,SMALL_READ_MEGABYTES,SMALL_READ_REQS,SMALL_READ_SERVICETIME,SMALL_SYNC_READ_LATENCY,
 LARGE_READ_MEGABYTES,LARGE_READ_REQS,LARGE_READ_SERVICETIME,SMALL_WRITE_MEGABYTES,SMALL_WRITE_REQS,
 SMALL_WRITE_SERVICETIME,LARGE_WRITE_MEGABYTES,LARGE_WRITE_REQS,LARGE_WRITE_SERVICETIME,$interval as interval,file_no,SMALL_SYNC_READ_REQS
 from
 GV\$IOSTAT_FILE f, gv\$containers c, gv\$tablespace t, gv\$tempfile d
 where
 f.inst_id=c.inst_id
 and c.con_id=f.con_id
 and d.inst_id=c.inst_id
 and t.inst_id=c.inst_id
 and t.con_id=c.con_id
 and d.con_id=c.con_id
 and d.file#=f.file_no
 and d.ts#=t.ts#
 and f.filetype_name='Temp File'
 and c.OPEN_MODE like 'READ%'
 ) where 1=1 
 ";
 }
 $pkeys{0}='%30s';
 $pkeys{1}='%80s';
 $pkeys{2}='%100s';
 $pkeys{17}='%100s';
 # What need to be show
 my @show_fields = split (/,/,$show_pattern);
 foreach my $show (@show_fields) {
 if ($show =~ m/^inst$/i ){ 
 # group by instance
 $array_of_ckeys_description[$ckey_cpt]{0}='%30s'; 
 $array_of_ckeys_description[$ckey_cpt]{16}='%10s';
 $array_of_display_keys[$ckey_cpt]{0}='y'; 
 $array_of_display_keys[$ckey_cpt]{16}='y';
 $ckey_cpt=$ckey_cpt+1; 
 }
 if ($show =~ m/^cont$/i ){
 # group by container
 $array_of_ckeys_description[$ckey_cpt]{16}='%10s';
 $array_of_display_keys[$ckey_cpt]{16}='y';
 if (grep (/^inst$/i,@show_fields)) {
 $array_of_ckeys_description[$ckey_cpt]{0}='%30s';
 $array_of_display_keys[$ckey_cpt]{0}='y';
 }
 $array_of_ckeys_description[$ckey_cpt]{1}='%100s';
 $array_of_display_keys[$ckey_cpt]{1}='y';
 $ckey_cpt=$ckey_cpt+1; 
 }
 if ($show =~ m/^file_type_tbs/i ){
 # group by file_type or tbs
 $array_of_ckeys_description[$ckey_cpt]{16}='%10s';
 $array_of_display_keys[$ckey_cpt]{16}='y';
 if (grep (/^inst$/i,@show_fields)) {
 $array_of_ckeys_description[$ckey_cpt]{0}='%30s';
 $array_of_display_keys[$ckey_cpt]{0}='y';
 }
 if (grep (/^cont/i,@show_fields)) {
 $array_of_ckeys_description[$ckey_cpt]{1}='%100s';
 $array_of_display_keys[$ckey_cpt]{1}='y';
 }
 $array_of_ckeys_description[$ckey_cpt]{2}='%100s';
 $array_of_display_keys[$ckey_cpt]{2}='y';
 $ckey_cpt=$ckey_cpt+1;
 }
 }
 @delta_fields=(3,4,5,6,7,8,9,10,11,12,13,14,15,18);
 if ($io_type_pattern =~ m/^reads$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.3f %1s %-7.2f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,2,"3/16","4/16","7/16","8/16","3/4","7/8","5/4","9/8");
 @array_of_report_header=(["%02d:%02d:%02d %61s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','SMALL R','','SMALL R','','LARGE R','','LARGE R','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','CONT','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','SMALL R','','LARGE R','','SMALL R','','LARGE R'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','---------------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^writes$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.3f %1s %-7.2f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,2,"10/16","11/16","13/16","14/16","10/11","13/14","12/11","15/14");
 @array_of_report_header=(["%02d:%02d:%02d %61s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','SMALL W','','SMALL W','','LARGE W','','LARGE W','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','CONT','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','SMALL W','','LARGE W','','SMALL W','','LARGE W'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','---------------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^small$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.3f %1s %-7.3f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,2,"3/16","4/16","10/16","11/16","3/4","10/11","5/4","12/11");
 @array_of_report_header=(["%02d:%02d:%02d %61s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','SMALL R','','SMALL R','','SMALL W','','SMALL W','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','CONT','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','SMALL R','','SMALL W','','SMALL R','','SMALL W'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','---------------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^large$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.0f %1s %-7.2f %1s %-7.2f %1s %-7.2f %1s %-7.2f\n";
 @report_fields_values=(1,2,"7/16","8/16","13/16","14/16","7/8","13/14","9/8","15/14");
 @array_of_report_header=(["%02d:%02d:%02d %61s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','','LARGE R','','LARGE R','','LARGE W','','LARGE W','','Avg MB/','','Avg MB/','','Avg ms/','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','INST','','CONT','','FILE_TYPE_TBS','','MB/s','','RQ/s','','MB/s','','RQ/s','','LARGE R','','LARGE W','','LARGE R','','LARGE W'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s %1s %-7s\n",'','----------','','---------------','','----------------------------','','-------','','-------','','-------','','-------','','-------','','-------','','-------','','-------']);
 }
 if ($io_type_pattern =~ m/^synch$/i ){
 $report_format_values="%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-7.0f %6s %-7.2f\n";
 @report_fields_values=(1,2,"18/16","6/18");
 @array_of_report_header=(["%02d:%02d:%02d %61s %1s %-12s %1s %-12s\n",'','','Sync SMALL R','','Avg ms/'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-12s %1s %-12s\n",'','INST','','CONT','','FILE_TYPE_TBS','','RQ/s','','Sync SMALL R'],["%02d:%02d:%02d %1s %-10s %1s %-15s %1s %-28s %1s %-12s %1s %-12s\n",'','----------','','---------------','','----------------------------','','------------','','------------']);
 }
 }
 &go_sql_real_time;
}

#
# Ctrl+C signal
#
$SIG{INT}= \&close;

sub close {
 print "Disconnecting from RDBMS...\n";
 $sql1->finish;
 $dbh->disconnect();
 exit 0;
}

sub minimum_version {
 print "RDBMS version < 11.1\n";
 print "Disconnecting from RDBMS...\n";
 $dbh->disconnect();
 exit 0;
}

sub get_the_options {
 my $help; 
 GetOptions('help|h' => \$help,
 'interval=i'=>\$interval,
 'count=i'=>\$count,
 'inst:s' => \$instpattern,
 'sort_field:s' => \$sort_field_pattern,
 'file_type_tbs:s' => \$file_type_tbs_pattern,
 'file_type:s' => \$file_type_pattern,
 'tbs:s' => \$tbs_pattern,
 'io_type:s' => \$io_type_pattern,
 'cont:s' => \$cont_pattern,
 'display:s' => \$display_pattern,
 'show:s' => \$show_pattern) or &usage();

 &usage() if ($help); 
}

sub go_sql_real_time {
&connect_db;
&check_instance_type($inst_type);
&check_rac;
&build_instances;
&build_rac_pattern;
&build_glob_sql_pattern;
&build_glob_sql;
&initialise_arrays;
&launch_loop;
}

sub connect_db {
$dbh = DBI->connect('dbi:Oracle:',"", "", { ora_session_mode => ORA_SYSDBA });
}
 
sub check_instance_type {
my $inst_type=$_[0];
debug("Instance Type: ".$inst_type);
my $sql1 = $dbh->prepare('select value from v$parameter where name=\'instance_type\' ');
$sql1->execute;

if ( $sql1->fetchrow_array =~ /$inst_type/i) {
 $sql1->finish;
}
else {
 print "\n\n ERROR : You must connect to a ".$inst_type." instance \n\n";
 $sql1->finish;
 $dbh->disconnect();
 exit 1;
}
}

sub check_rac {
my $sql1 = $dbh->prepare('select value from v$parameter where name = \'cluster_database\'');
$sql1->execute;
if ( $sql1->fetchrow_array =~ /true/i) {
 $rac=1;
}
$sql1->finish;
}

sub check_version {
my $sql1 = $dbh->prepare('select regexp_replace(version,\'\..*\') from v$instance');
$sql1->execute;
return ($sql1->fetchrow_array);
$sql1->finish;
}

sub check_pdbs {
my $sql1 = $dbh->prepare('select count(*) from v$pdbs');
$sql1->execute;
return ($sql1->fetchrow_array);
$sql1->finish;
}

sub build_instances {
my $sql1 = $dbh->prepare('select inst_id,instance_name, host_name from gv$instance');
$sql1->execute;
while ( my ($instid, $instname,$host) = $sql1->fetchrow_array) {
 $instances{$instname} = $instid;
}
$sql1->finish;
}

sub build_in_pattern {
 my $pattern=shift;
 my $column=shift;
 my %list_of_field=@_; 
 my %reverse_list_of_field = reverse %list_of_field;
 my @fields = split (/,/,$pattern);
 my $output_in_pattern=''; 
 foreach my $field (@fields) {
 if (!exists $reverse_list_of_field{uc($field)}) {
 print "\n\n ERROR : $field $column is not found !! \n";
 exit 1;
 } else {
 if (!$output_in_pattern) {
 $output_in_pattern=" and $column in ('"."$reverse_list_of_field{uc($field)}'";
 } else {
 $output_in_pattern=$output_in_pattern.",'$reverse_list_of_field{uc($field)}'";
 }
 }
 }
 ($output_in_pattern)?$output_in_pattern=$output_in_pattern.")":"";
 return $output_in_pattern;
}

sub build_rac_pattern
{
if ($rac & ! ($instpattern =~ /all|current/i)) {
 my @fields = split (/,/,$instpattern);

 foreach my $instname (@fields) {

 if (!exists $instances{uc($instname)}) {
 print "\n\n ERROR : The instance $instname is not found !! \n";
 $dbh->disconnect();
 exit 1;
 } else {
 $showinstances{$instname}=$instances{$instname};;
 }
 }
}

# If not rac put pattern as current

if (! $rac) {
$instpattern = 'current';
}

if ($instpattern =~ /current/i) {

my $sql1_sql = "select inst_id,instance_name, host_name from gv\$instance where inst_id = userenv('instance')";

my $sql1 = $dbh->prepare($sql1_sql);
$sql1->execute;
while ( my ($instid, $instname,$host) = $sql1->fetchrow_array) {
 $instances{$instname} = $instid;
}
$sql1->finish;
}

if (($rac & ($instpattern =~ /all|current/i)) | (! $rac & ($instpattern =~ /current/i))) {
 %showinstances = %instances;
}

# RAC : Create the SQL suffixe based on the instances to request on

# Case 1 : The current instance or list of instances
$sqlsuffixe = ((! $rac) | ($rac & $instpattern =~ /current/i) ? " and ".$instid_pattern. " = userenv('instance')" : "");

# Case 2 : All the instances
# Nothing to do

if ($rac & ! ($instpattern =~ /all|current/i)) {

 foreach my $inst (keys %showinstances) {

 my $inst_id = $showinstances{$inst};

 if ($sqlsuffixe) {
 $sqlsuffixe = $sqlsuffixe." or ".$instid_pattern. " = $inst_id";
 }
 else
 {
 $sqlsuffixe = $sqlsuffixe." and (".$instid_pattern. " = $inst_id";
 }
 }
 $sqlsuffixe = $sqlsuffixe.")";

}
debug("sqlsuffixe: ".$sqlsuffixe);
# Reverse the hash for display usage (Report Section)
%showinstances = reverse %showinstances;
}

sub build_glob_sql_pattern {

 foreach my $column (keys %sql_patterns) {
 debug("column: ".$column);
 debug("pattern: ".$sql_patterns{$column});
 if ($sql_patterns{$column}) {$global_sql_pattern = $global_sql_pattern." and ".$column." like '".$sql_patterns{$column}."' "}
 }
 debug("global_sql_pattern: ".$global_sql_pattern);
}

sub build_glob_sql {
 $main_sql = $main_sql.$global_sql_pattern.$sqlsuffixe; 
 debug("Main sql: ".$main_sql);
}

sub build_the_key {
 my @tab1 = @_;
 $bkey='';
 @ekey=();
 foreach my $id (sort { $a <=> $b }(keys %pkeys)) {
 if ($bkey) {$bkey = $bkey.".".$pkeys{$id}};
 if (!$bkey) {$bkey = $pkeys{$id}};
 push(@ekey,$tab1[$id]);
 }
}

sub build_compute_key {
 my @tab1 = @_;
 for my $i ( 0 .. $#array_of_ckeys_description ) {
 my $bckey='';
 my @eckey=();
 for my $j ( sort { $a <=> $b } (keys %{ $array_of_ckeys_description[$i] }) ) {
 ($bckey)?($bckey = $bckey.".".$array_of_ckeys_description[$i]{$j}):($bckey = $array_of_ckeys_description[$i]{$j});
 push(@eckey,$tab1[$j]);
 }
 my $ckey = sprintf($bckey,@eckey);
 $array_of_ckey[$i]=$ckey;
 } 
}

sub initialise_arrays { 
 $sql1 = $dbh->prepare($main_sql);
 my $key;
 $sql1->execute;
 while ( my @tab1 = $sql1->fetchrow_array) {
 &build_the_key(@tab1); 
 $key = sprintf($bkey,@ekey);
 @{$rtvalues{$key}}=@tab1;
 @{$diffsnaps{$key}}=@tab1;
 debug("key is : ".$key);
 }
}

sub launch_loop {
 my $key;
 my $ckey;
 my $cpt=0;
 for (my $nb=0;$nb < $count;$nb++) {
 print "............................\n";
 print "Collecting $interval sec....\n";
 print "............................\n";
 sleep $interval;
 $sql1->execute;
 ($seconds, $minuts, $hours) = localtime(time);

 # Keep the first timing for the average section
 ($cpt==0)?(@since_timing=($hours,$minuts,$seconds)):"";

 # Empty diffsnaps
 %diffsnaps = ();
 while ( my @tab1 = $sql1->fetchrow_array) {
 &build_the_key(@tab1);
 $key = sprintf($bkey,@ekey);

 # Build the compute key

 &build_compute_key(@tab1);

 # Initialise non delta fields
 for (my $tabid=0;$tabid < scalar(@tab1);$tabid++) {
 for my $i ( 0 .. $#array_of_ckeys_description ) {
 my $ckey=$array_of_ckey[$i];
 $diffsnaps{$ckey}->[$tabid]=($array_of_display_keys[$i]{$tabid}?"$tab1[$tabid]":"") unless (grep (/^$tabid$/,@delta_fields));
 $avgdiffsnaps{$ckey}->[$tabid]=($array_of_display_keys[$i]{$tabid}?"$tab1[$tabid]":"") unless (grep (/^$tabid$/,@delta_fields));
 debug("Non delta fields: for display_keys $array_of_display_keys[$i]{$tabid} and tabid $tabid ".$diffsnaps{$ckey}->[$tabid]);
 }
 }
 
 # get the list of delta fields
 foreach my $deltaid (@delta_fields) {
 for my $i ( 0 .. $#array_of_ckeys_description ) {
 my $ckey=$array_of_ckey[$i];
 debug("deltaid : ".$deltaid);
 debug("key is : ".$key);
 debug("ckey during diff is : ".$ckey);
 $diffsnaps{$ckey}->[$deltaid] = $diffsnaps{$ckey}->[$deltaid] + $tab1[$deltaid] - $rtvalues{$key}->[$deltaid];
 debug("Previous : ".$rtvalues{$key}->[$deltaid]);
 debug("Current : ".$tab1[$deltaid]);
 debug("Diff is : ".$diffsnaps{$ckey}->[$deltaid]);
 }
 }
 @{$rtvalues{$key}} = @tab1;
 debug("key is : ".$key);
 debug("ckey is : ".$ckey);
 } 

 # compute the average since the collection began
 
 foreach my $deltaid (@delta_fields) {
 foreach my $diffkey (keys %diffsnaps){
 $avgdiffsnaps{$diffkey}->[$deltaid] = (($avgdiffsnaps{$diffkey}->[$deltaid] * $cpt) + $diffsnaps{$diffkey}->[$deltaid]) / ($cpt+1); 
 } 
 }
 $cpt=$cpt+1;
 # Report now for snaps
 (grep (/snap/i,$display_pattern))?(print "\n"):"";
 (grep (/snap/i,$display_pattern))?(print "......... SNAP TAKEN AT ...................\n"):"";
 (grep (/snap/i,$display_pattern))?(print "\n"):"";
 (grep (/snap/i,$display_pattern))?(&report_header("snap",@array_of_report_header)):"";
 (grep (/snap/i,$display_pattern))?(&report_values("snap",%diffsnaps)):"";
 # Report now for average
 (grep (/avg/i,$display_pattern))?(print "\n"):"";
 (grep (/avg/i,$display_pattern))?(print "......... AVERAGE SINCE ...................\n"):"";
 (grep (/avg/i,$display_pattern))?(print "\n"):"";
 (grep (/avg/i,$display_pattern))?(&report_header("avg",@array_of_report_header)):"";
 (grep (/avg/i,$display_pattern))?(&report_values("avg",%avgdiffsnaps)):"";
 }
}

sub report_header {
 my $display_date = shift;
 my @array_of_report_header = @_;
 foreach my $report_ligne (0..@array_of_report_header-1) {
 my @header;
 @header = ($display_date eq "avg")?(@since_timing):($hours,$minuts,$seconds);
 foreach my $report_column (1..@{$array_of_report_header[$report_ligne]}) {
 push(@header,$array_of_report_header[$report_ligne][$report_column]);
 }
 printf ($array_of_report_header[$report_ligne][0],@header);
 }
}

sub report_resultset {

 my $display_date = shift;
 my $pk=shift;
 my %resultset=@_;
 my $backup_mult;

 my @values; 
 @values = ($display_date eq "avg")?(@since_timing):($hours,$minuts,$seconds);

 if (%showinstances) {push(@values,'',$showinstances{$resultset{$pk}->[0]})};

 foreach my $id (@report_fields_values) {

 push(@values,'');

 my @need_div=split(/\//,$id);
 my @need_mult=split(/\*/,$id);

 if (@need_mult > 1) {
 $need_mult[1] =~ s/\/.*//;
 $backup_mult = $resultset{$pk}->[$need_mult[0]];
 $resultset{$pk}->[$need_mult[0]] = ($resultset{$pk}->[$need_mult[0]]) * $need_mult[1];
 debug("Mult is needed for id : ".$id);
 debug("Mult[0] is : ".$need_mult[0]);
 debug("Mult[1] is : ".$need_mult[1]);
 } 

 if (@need_div > 1) {
 $need_div[0] =~ s/\*.*//;
 debug("Div is needed for id : ".$id);
 debug("needed_div is : ".@need_div);
 debug("div[0] is : ".$need_div[0]);
 debug("div[1] is : ".$need_div[1]);
 if ($resultset{$pk}->[$need_div[1]] > 0) {push(@values,$resultset{$pk}->[$need_div[0]]/$resultset{$pk}->[$need_div[1]])};
 if ($resultset{$pk}->[$need_div[1]] == 0) {push(@values,0)};
 }
 else
 {
 push(@values,$resultset{$pk}->[$id]);
 }
 # In case the resultset has been changed, then put the value back (For the average..)
 if (@need_mult > 1) {
 $resultset{$pk}->[$need_mult[0]] = $backup_mult;
 } 
 }
 printf ($report_format_values,@values);
}

sub report_values {
 my $nb =1;
 my %resultset = ();
 my $display_date = shift;
 my %display_what = @_;
 my $rank = 1;
 my %ranked_instances = ();
 # rank the instance based on the sort field

 foreach my $pk (sort {$display_what{$b}[$sort_fields{uc($sort_field_pattern)}] <=> $display_what{$a}[$sort_fields{uc($sort_field_pattern)}] || $display_what{$a}[0] <=> $display_what{$b}[0]} (keys(%display_what))) {
 if (!(exists $ranked_instances{$display_what{$pk}[0]})) {
 $ranked_instances{$display_what{$pk}[0]}=$rank;
 $display_what{$pk}->[99] = $rank;
 $rank++;
 } else {
 $display_what{$pk}->[99] = $ranked_instances{$display_what{$pk}[0]};
 }
 debug("Rank is ".$display_what{$pk}->[99]." for instance ".$display_what{$pk}[0]);
 }


 if ($nb_pdbs == 0) {

 foreach my $pk (sort {$display_what{$a}[99] <=> $display_what{$b}[99] || $display_what{$b}[$sort_fields{uc($sort_field_pattern)}] <=> $display_what{$a}[$sort_fields{uc($sort_field_pattern)}] || $display_what{$a}[1] cmp $display_what{$b}[1]} (keys(%display_what))) {
 &report_resultset($display_date,$pk,%display_what);
 debug("Sorted value is : ".$display_what{$pk}[$sort_fields{uc($sort_field_pattern)}]);
 }
 } else {
 foreach my $pk (sort {$display_what{$a}[99] <=> $display_what{$b}[99] || $display_what{$b}[$sort_fields{uc($sort_field_pattern)}] <=> $display_what{$a}[$sort_fields{uc($sort_field_pattern)}] || $display_what{$a}[1] cmp $display_what{$b}[1] || $display_what{$a}[2] cmp $display_what{$b}[2]} (keys(%display_what))) {
 &report_resultset($display_date,$pk,%display_what);
 debug("Sorted value is : ".$display_what{$pk}[$sort_fields{uc($sort_field_pattern)}]);
 }
 }
}


sub usage {
&usage_db_io_type_metrics();
}


sub usage_db_io_type_metrics {

&connect_db;
$version=check_version();
if ($version >= 12) {$nb_pdbs=check_pdbs()};
 
if ($nb_pdbs == 0) {
print " \nUsage: $0 [-interval] [-count] [-inst] [-file_type_tbs] [-io_type] [-file_type] [-tbs] [-show] [-display] [-sort_field] [-help]\n";
} else {
print " \nUsage: $0 [-interval] [-count] [-inst] [-cont] [-file_type_tbs] [-io_type] [-file_type] [-tbs] [-show] [-display] [-sort_field] [-help]\n";
}
print "\n";
print " Default Interval : 1 second.\n";
print " Default Count : Unlimited\n\n";
printf (" %-15s %-75s %-10s \n",'Parameter','Comment','Default');
printf (" %-15s %-75s %-10s \n",'---------','-------','-------');
printf (" %-15s %-75s %-10s \n",'-INST=','ALL - Show all Instance(s) ','ALL');
printf (" %-15s %-75s %-10s \n",'','CURRENT - Show Current Instance ','');
if ($nb_pdbs > 0) {
printf (" %-15s %-75s %-10s \n",'-CONT=','Container to collect (wildcard allowed)','ALL');
}
printf (" %-15s %-75s %-10s \n",'-FILE_TYPE_TBS=','Collect on File Type or on Tablespace: file_type,tbs','FILE_TYPE');
printf (" %-15s %-75s %-10s \n",'-IO_TYPE=','IO Type to collect: reads,writes,small,large,synch','READS');
printf (" %-15s %-75s %-10s \n",'-FILE_TYPE=','File Type to collect (in case FILE_TYPE_TBS=file_type) (wildcard allowed)','NONE');
printf (" %-15s %-75s %-10s \n",'-TBS=','Tablespace to collect (in case FILE_TYPE_TBS=tbs) (wildcard allowed)','NONE');
if ($nb_pdbs == 0) {
printf (" %-15s %-75s %-10s \n",'-SHOW=','What to show: inst,file_type (comma separated list)','INST');
} else {
printf (" %-15s %-75s %-10s \n",'-SHOW=','What to show: inst,cont,file_type_tbs (comma separated list)','INST');
}
printf (" %-15s %-75s %-10s \n",'-DISPLAY=','What to display: snap,avg (comma separated list)','SNAP');
printf (" %-15s %-75s %-10s \n",'-SORT_FIELD=','small_reads,small_writes,large_reads,large_writes','NONE');
print ("\n");
print ("Example: $0 \n");
print ("Example: $0 -inst=CBDT1\n");
print ("Example: $0 -show=inst,file_type_tbs\n");
print ("Example: $0 -show=inst,file_type_tbs -file_type=%Data%\n");
print ("Example: $0 -show=inst -io_type=large\n");
print ("Example: $0 -show=inst -io_type=small -sort_field=small_reads\n");
print ("Example: $0 -show=inst,file_type_tbs -file_type_tbs=tbs -tbs=%USE%\n");
if ($nb_pdbs > 0) {
print ("Example: $0 -show=inst,cont\n");
print ("Example: $0 -show=inst,cont -cont=%P%\n");
print ("Example: $0 -show=inst,cont,file_type_tbs -io_type=small -sort_field=small_reads\n");
}
print "\n\n";
exit 1;
}

sub debug {
 if ($debug==1) {
 print $_[0]."\n";
 }
}


&main(@ARGV);

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.