Logo Search packages:      
Sourcecode: s390-tools version File versions  Download package

ziorep_traffic.cpp

/*
 * FCP report generators
 *
 * Traffic report program
 *
 * Copyright IBM Corp. 2008
 * Author(s): Stefan Raspl <raspl@linux.vnet.ibm.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <linux/types.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <assert.h>
#include <limits.h>

#include <list>

#include "zt_common.h"
#include "ziorep_collapser.hpp"
#include "ziorep_utils.hpp"


using std::list;


const char *toolname = "ziorep_traffic";
int verbose=0;


struct options {
      __u64             begin;
      __u64             end;
      __u32             interval;
      list<const char*> devices;
      list<const char*> mp_devices;
      __u64             topline;
      char*             filename;
      bool              print_summary;
      bool              details;
      Aggregator        col_crit;
      list<__u32>       chpids;
      list<__u32>       devnos;
      list<__u64>       wwpns;
      list<__u64>       luns;
      bool              csv_export;
};


static void init_opts(struct options *opts)
{
      opts->begin       = 0;
      opts->end         = UINT64_MAX;
      opts->interval          = UINT32_MAX;
      opts->topline           = 0;
      opts->filename          = NULL;
      opts->print_summary     = false;
      opts->details           = false;
      opts->col_crit          = none;
      opts->csv_export  = false;
}


static const char help_text[] =
    "Usage: ziorep_traffic [-V] [-v] [-h] [-b <begin>] [-e <end>]"
    " [-i <time>] [-s]\n"
    "                        [-c <chpid>] [-u <id>] [-t <num>] [-p <port>]\n"
    "                        [-l <lun>] [-d <fdev> ] [-m <mdev>] [-x] [-D]\n"
    "                        [-C a|u|p|m|A] <filename>\n\n"
    "-h, --help              Print usage information and exit.\n"
    "-v, --version           Print version information and exit.\n"
    "-V, --verbose           Be verbose.\n"
    "-b, --begin <begin>     Do not consider data earlier than 'begin'.\n"
    "                        Defaults to begin of available data.\n"
    "                        Format is YYYY-MM-DD HH:MM[:SS],\n"
    "                        e.g. '-b \"2008-03-21 09:08\"\n"
    "-e, --end <end>         Do not consider data later than 'end'.\n"
    "                        Defaults to end of available data.\n"
    "                        Format is YYYY-MM-DD HH:MM[:SS],\n"
    "                        e.g. '-e \"2008-03-21 09:08:57\"\n"
    "-i, --interval <time>   Set aggregation interval to 'time' in seconds.\n"
    "                        Must be a multiple of the interval size of the source\n"
    "                        data.\n"
    "                        Set to 0 to aggregate over all data.\n"
    "-s, --summary           Show a summary of the data.\n"
    "-C, --collapse <val>    Collapse data for multiple instances of\n"
    "                        a device into a single one. See man page for details.\n"
    "-c, --chpid <chpid>     Select adapter by CHPID in hex, e.g. '-c 32'\n"
    "-u, --bus-id <id>       Select by bus-ID, e.g. '-u 0.0.7f1d'\n"
    "-p, --port <port>       Select by target port, e.g. '-p 0x500507630040710b'\n"
    "-l, --lun <lun>         Select by lun, e.g. '-l 0x4021402200000000'\n"
    "-d, --device <fdev>     Select by device, e.g. '-d sda'\n"
    "-m, --mdev <mdev>       Select by multipath device,\n"
    "                        e.g. '-m 36005076303ffc1040002120'\n"
    "-D, --detailed          Print histograms instead of min/max/avg/stdev\n"
    "-x, --export-csv        Export data to files in CSV format.\n"
    "-t, --topline <num>     Repeat topline after every 'num' frames.\n"
    "                        0 for no repeat (default).\n";


static void print_help()
{
        printf("%s", help_text);
}


static void print_version()
{
        printf("%s: Traffic report generator version %s\n"
               "Copyright IBM Corp. 2008\n", toolname, RELEASE_STRING);
}


static int parse_params(int argc, char **argv, struct options *opts)
{
      int c;
      int index;
      int rc;
      __u32 tmp32;
      long long unsigned int tmp64;
      long tmpl;
      char mychar;
        static struct option long_options[] = {
                { "version",         no_argument,       NULL, 'v'},
            { "help",            no_argument,       NULL, 'h'},
            { "verbose",         no_argument,       NULL, 'V'},
            { "begin",           required_argument, NULL, 'b'},
                { "end",             required_argument, NULL, 'e'},
            { "interval",        required_argument, NULL, 'i'},
            { "summary",         no_argument,       NULL, 's'},
            { "collapse",        required_argument, NULL, 'C'},
            { "chpid",           required_argument, NULL, 'c'},
            { "bus-id",          required_argument, NULL, 'u'},
            { "port",            required_argument, NULL, 'p'},
            { "lun",             required_argument, NULL, 'l'},
            { "device",          required_argument, NULL, 'd'},
            { "mdev",            required_argument, NULL, 'm'},
            { "detailed",        required_argument, NULL, 'D'},
            { "export-csv",      no_argument,       NULL, 'x'},
            { "topline",         required_argument, NULL, 't'},
                { 0,                 0,                 0,     0 }
      };

      if (argc < 2) {
            print_help();
            return 1;
      }

      assert(sizeof(long long int) == sizeof(__u64));
      while ((c = getopt_long(argc, argv, "m:C:b:e:i:c:u:p:l:d:t:xDshvV",
                        long_options, &index)) != EOF) {
            switch (c) {
            case 'V':
                  verbose++;
                  break;
            case 'h':
                  print_help();
                  return 1;
            case 'v':
                  print_version();
                  return 1;
            case 'b':
                  if (get_datetime_val(optarg, &opts->begin))
                        return -1;
                  break;
            case 'e':
                  if (get_datetime_val(optarg, &opts->end))
                        return -1;
                  break;
            case 'i':
                  if (sscanf(optarg, "%lu", &tmpl) != 1) {
                        fprintf(stderr, "%s:"
                              " Cannot parse %s as an integer value."
                              " Please correct and try again.\n", toolname,
                              optarg);
                        return -1;
                  }
                  if (tmpl < 0) {
                        fprintf(stderr, "%s:"
                              " Argument %s must be greater than or"
                              " equal to 0.", toolname, optarg);
                        return -1;
                  }
                  opts->interval = tmpl;
                  break;
            case 's':
                  opts->print_summary = true;
                  break;
            case 'c':
                  rc = sscanf(optarg, "%x%c", &tmp32, &mychar);
                  if (rc < 1) {
                        fprintf(stderr, "%s: Could"
                              " not read chpid %s\n", toolname, optarg);
                        return -1;
                  }
                  if (rc > 1) {
                        fprintf(stderr, "%s: %s is not a valid chpid\n", toolname, optarg);
                        return -1;
                  }
                  opts->chpids.push_back(tmp32);
                  break;
            case 'p':
                   rc = sscanf(optarg, "0x%Lx", &tmp64);
                   if (rc != 1) {
                         fprintf(stderr, "%s: Could"
                               " not read port number %s\n", toolname, optarg);
                         return -1;
                   }
                   opts->wwpns.push_back(tmp64);
                   break;
            case 'l':
                  rc = sscanf(optarg, "0x%Lx", &tmp64);
                  if (rc != 1) {
                        fprintf(stderr, "%s: Could"
                              " not read lun %s\n", toolname, optarg);
                        return -1;
                  }
                  opts->luns.push_back(tmp64);
                  break;
            case 'u':
                  rc = sscanf(optarg, "0.0.%x", &tmp32);
                  if (rc != 1) {
                        fprintf(stderr, "%s: Could not read bus-ID"
                              " %s\n", toolname, optarg);
                        return -1;
                  }
                  opts->devnos.push_back(tmp32);
                  break;
            case 'd':
                  opts->devices.push_back(optarg);
                  break;
            case 'm':
                  opts->mp_devices.push_back(optarg);
                  break;
            case 'D':
                  opts->details = true;
                  break;
            case 't':
                  if (parse_topline_arg(optarg, &opts->topline))
                        return -1;
                  break;
            case 'x':
                  opts->csv_export = true;
                  break;
            case 'C':
                  rc = 0;
                  switch (*optarg) {
                  case 'a': opts->col_crit = chpid;
                        break;
                  case 'u': opts->col_crit = devno;
                        break;
                  case 'p': opts->col_crit = wwpn;
                        break;
                  case 'm': opts->col_crit = multipath_device;
                        break;
                  case 'A': opts->col_crit = all;
                        break;
                  default:
                        rc = -1;
                  }
                  if (rc || strlen(optarg) > 1) {
                        fprintf(stderr, "%s:"
                            " Unrecognized switch '%s' to parameter"
                            " '-C'. Please check the help for a list"
                            " of valid switches, correct and try"
                            " again.\n", toolname, optarg);
                        return -2;
                  }
                  break;
            default:
                  fprintf(stderr, "%s: Try '%s --help' for"
                        " more information.\n", toolname, toolname);
                  return -1;
            }
      }
      if (optind == argc - 1)
            opts->filename = argv[optind];
      if (optind < argc - 1) {
            fprintf(stderr, "%s: Multiple filenames"
                  " specified. Specify only a single one at a time.\n", toolname);
            return -1;
      }

      return 0;
}


static int check_opts(struct options *opts, ConfigReader **cfg)
{
      int rc = 0;

      // check filename
      if (!opts->filename) {
            fprintf(stderr, "%s: No filename specified.\n", toolname);
            return -2;
      }
      else {
            if (strncmp(opts->filename + strlen(opts->filename) - strlen(DACC_FILE_EXT_LOG),
                      DACC_FILE_EXT_LOG, strlen(DACC_FILE_EXT_LOG)) == 0) {
                  verbose_msg("Filename carries " DACC_FILE_EXT_LOG " extension - stripping\n");
                  opts->filename[strlen(opts->filename) - strlen(DACC_FILE_EXT_LOG)] = '\0';
            }
            if (strncmp(opts->filename + strlen(opts->filename) - strlen(DACC_FILE_EXT_AGG),
                      DACC_FILE_EXT_AGG, strlen(DACC_FILE_EXT_AGG)) == 0) {
                  verbose_msg("Filename carries " DACC_FILE_EXT_AGG " extension - stripping\n");
                  opts->filename[strlen(opts->filename) - strlen(DACC_FILE_EXT_AGG)] = '\0';
            }
            verbose_msg("Filename is %s\n", opts->filename);
      }

      // check config
      *cfg = new ConfigReader(&rc, opts->filename);
      if (rc)
            return -1;

      for (list<__u32>::const_iterator i = opts->chpids.begin();
            i != opts->chpids.end(); ++i) {
            if (!(*cfg)->verify_chpid(*i)) {
                  fprintf(stderr, "Error: Could not find chpid %x in"
                        " configuration.\n", *i);
                  rc = -2;
            }
      }
      for (list<__u32>::const_iterator i = opts->devnos.begin();
            i != opts->devnos.end(); ++i) {
            if (!(*cfg)->verify_devno(*i)) {
                  fprintf(stderr, "Error: Could not find bus-ID 0.0.%04x in"
                        " configuration.\n", *i);
                  rc = -3;
            }
      }
      for (list<__u64>::const_iterator i = opts->wwpns.begin();
            i != opts->wwpns.end(); ++i) {
            if (!(*cfg)->verify_wwpn(*i)) {
                  fprintf(stderr, "Error: Could not find WWPN %016Lx in"
                        " configuration.\n", (long long unsigned int)*i);
                  rc = -4;
            }
      }
      for (list<__u64>::const_iterator i = opts->luns.begin();
            i != opts->luns.end(); ++i) {
            if (!(*cfg)->verify_lun(*i)) {
                  fprintf(stderr, "Error: Could not find LUN %016Lx in"
                        " configuration.\n", (long long unsigned int)*i);
                  rc = -5;
            }
      }
      for (list<const char*>::iterator i = opts->devices.begin();
            i != opts->devices.end(); ++i) {
            if (!(*cfg)->verify_device(*i)) {
                  fprintf(stderr, "Error: Could not find device %s in"
                        " configuration.\n", *i);
                  rc = -6;
            }
      }
      for (list<const char*>::iterator i = opts->mp_devices.begin();
            i != opts->mp_devices.end(); ++i) {
            if (!(*cfg)->verify_mp_device(*i)) {
                  fprintf(stderr, "Error: Could not find multipath"
                        " device %s in configuration.\n", *i);
                  rc = -7;
            }
      }
      if (opts->csv_export && opts->topline > 0) {
            fprintf(stderr, "%s: Warning: Both, topline"
                  " repeat and CSV export activated, deactivating"
                  " topline repeat.\n", toolname);
            opts->topline = 0;
      }

      if (!opts->print_summary
          && adjust_timeframe(opts->filename, &opts->begin, &opts->end,
                       &opts->interval))
            rc = -8;

      return rc;
}


static int configure_coarse_devices(struct options *opts, ConfigReader &cfg,
                             StagedDeviceFilter &dev_flt)
{
      list<__u32> mms;
      int rc = 0;

      for (list<const char *>::const_iterator i = opts->devices.begin();
            i != opts->devices.end(); ++i) {
            __u32 mm = cfg.get_mm_by_device(*i, &rc);
            dev_flt.add_device(mm, cfg.get_ident_by_mm_internal(mm, &rc));
      }
      for (list<__u64>::const_iterator i = opts->luns.begin();
            i != opts->luns.end(); ++i) {
            cfg.get_mms_by_lun(mms, *i);
            for (list<__u32>::const_iterator j = mms.begin();
                  j != mms.end(); j++)
                  dev_flt.add_device(*j, cfg.get_ident_by_mm_internal(*j, &rc));
      }
      for (list<const char *>::const_iterator i = opts->mp_devices.begin();
            i != opts->mp_devices.end(); ++i)
            dev_flt.stage_mp_mm(cfg.get_mp_mm_by_multipath(*i, &rc));
      if (rc)
            return -1;
      for (list<__u64>::const_iterator i = opts->wwpns.begin();
            i != opts->wwpns.end(); ++i)
            dev_flt.stage_wwpn(*i);
      for (list<__u32>::const_iterator i = opts->devnos.begin();
            i != opts->devnos.end(); ++i)
            dev_flt.stage_devno(*i);
      for (list<__u32>::const_iterator i = opts->chpids.begin();
            i != opts->chpids.end(); ++i)
            dev_flt.stage_chpid(*i);

      return dev_flt.finish(cfg, false);
}


static int configure_device_filter(struct options *opts, ConfigReader &cfg,
                           DeviceFilter **dev_filt)
{
      int rc = 0;
      list<__u32> mm_lst;
      list<__u32>::const_iterator i_32, j_32;

      verbose_msg("Configure device filter\n");
      // verify and sort out devices
      if (opts->devices.size() > 0 ||  opts->luns.size() > 0
             || opts->wwpns.size() > 0 || opts->mp_devices.size() > 0
             || opts->devnos.size() > 0 || opts->chpids.size() > 0) {
            verbose_msg("    devices specified via coarse criteria"
                      " - let's see...\n");
            StagedDeviceFilter *stgd_flt = new StagedDeviceFilter;
            *dev_filt = stgd_flt;
            rc = configure_coarse_devices(opts, cfg, *stgd_flt);
      }
      else {
            verbose_msg("    no devices specified - accept all\n");
            *dev_filt = new DeviceFilter;
            add_all_devices(cfg, **dev_filt);
      }

      verbose_msg("Device filter configured (total: %zd devices)\n",
                (*dev_filt)->get_mm_list().size());

      return rc;
}


static int print_report(struct options *opts, ConfigReader &cfg)
{
      int rc = 0;
      FILE *fp;
      MsgTypeFilter msgtype_filter;
      Printer *printer = NULL;
      DeviceFilter *dev_filt;
      Collapser *col = NULL;
      list<MsgTypes> type_flt;

      type_flt.push_back(zfcpdd);
      type_flt.push_back(blkiomon);

      if (configure_device_filter(opts, cfg, &dev_filt)) {
            rc = -1;
            goto out;
      }

      if (opts->col_crit == none)
            col = new NoopCollapser();
      else if (opts->col_crit == all)
            col = new TotalCollapser();
      else {
            col = new AggregationCollapser(cfg,
                                     opts->col_crit,
                                     *dev_filt,
                                     &rc);
            if (rc)
                  goto out;
      }

      if (opts->details) {
            if (opts->csv_export) {
                  fp = open_csv_output_file(opts->filename,
                                      "_traffic_detailed.csv", &rc);
                  if (rc)
                        goto out;
            }
            else
                  fp = stdout;
            printer = new DetailedTrafficPrinter(&cfg, *col,
                                         opts->csv_export);
      }
      else {
            if (opts->csv_export) {
                  fp = open_csv_output_file(opts->filename,
                                      "_traffic.csv",
                                      &rc);
                  if (rc)
                        goto out;
            }
            else
                  fp = stdout;
            printer = new SummaryTrafficPrinter(&cfg, *col,
                                        opts->csv_export);
      }

      if ( (rc = print_report(fp, opts->begin, opts->end,
                        opts->interval, opts->filename, opts->topline,
                        &type_flt, *dev_filt, *col, *printer)) < 0 )
            rc = -3;

      if (opts->csv_export)
            fclose(fp);
out:
      delete dev_filt;
      delete col;
      delete printer;

      return rc;
}


int main(int argc, char **argv)
{
      int rc;
      struct options opts;
      ConfigReader *cfg = NULL;

      verbose = 0;

      init_opts(&opts);
      if ( (rc = parse_params(argc, argv, &opts)) ) {
            if (rc == 1)
                  rc = 0;
            goto out;
      }
      if ( (rc = check_opts(&opts, &cfg)) )
            goto out;

      if (opts.print_summary)
            rc = print_summary_report(stdout, opts.filename, *cfg);
      else
            rc = print_report(&opts, *cfg);

out:
      delete cfg;

      return rc;
}


Generated by  Doxygen 1.6.0   Back to index