#!/usr/bin/env python
# ex: set shiftwidth=4 tabstop=4 expandtab:
# Copyright C 2002-2008 by Isilon Systems, Inc. All rights not expressly
# granted herein are reserved.
# Created in the United States of America.
#
# This digital media is protected by U.S. and international copyright and
# intellectual property laws. Unless otherwise specified, all information
# and screens appearing as part of this digital medium, including
# software, services, documents, text, images, icons, and logos design;
# the selection, assembly, arrangement, and design thereof; and the code
# that enables its presentation, are the sole property of Isilon Systems,
# Inc.
#
# Except as otherwise required by applicable law, no part of any
# copyrighted material may be reproduced, modified, translated,
# distributed, published, or transmitted by any means, electronic or
# mechanical, for any purpose, without the prior written consent of Isilon
# Systems.
#
# Isilon and Isilon Systems are registered trademarks of Isilon Systems,
# Inc.  "Isilon IQ" is a trademark of Isilon Systems, Inc.  All other
# trademarks and registered trademarks are the property of their
# respective holders.

import getopt
import os
import sys

try:
    import isi.ph.client as client
    import isi.ph.perf as perf
    import isi.ph.perfcollector as perfcollector
    import isi.ph.util as util
except ImportError:
    try:
        # old-style, from ph directory
        import client as client
        import perf as perf
        import perfcollector as perfcollector
        import util as util
    except ImportError:
        print "Either run on a node or from within the ph library directory."
        sys.exit(1)

def Version():
    return "$Revision: 107108 $".split(" ")[1]

def usage():
    tests = perfcollector.ListTests()
    tests.sort()
    print """
Usage: isi_ph_pc [-d dir] [-m mode ] [--tests test1,test2] [-t time] nodes...
    dir:
            Store PC results here; default is current working directory.
    mode:
            full            all stats; default
            light           slightly less than full; skips SleepProfiler,
                                MessageProfiler, and TCPConnectionQuality
            nosleep         skip the sleep profiler
            sleep           only run the sleep profiler
            delaysleep      run the full set of stats, but run the sleep
                            profiler in a second phase
    tests:
            A list of specific tests to run; see available tests below.
            Use : to separate tests into distinct phases.  E.g.,
                --tests BAMEventProfiler,CPUUsage:SleepProfiler
            is equivalent to
                -m delaysleep --tests BAMEventProfiler,CPUUsage
            except that the latter is disallowed to simplify option checking.
    time:
            Sample period for collection.  Can use units (H,M,S) and floats.
            If more than one phase is given, the full time is used per phase.

Available tests:
    %s
""" % ("\n    ".join(tests))
    sys.exit(1)

directory = os.getcwd()
period = 20
mode = None
phases = []
phased_test = False

flags, others = getopt.getopt(sys.argv[1:], "d:hm:t:", [ "help", "mode=",
                                                         "tests=",
                                                         "version" ])
for opt in flags:
    flag = opt[0]
    if flag == "-d":
        directory = opt[1]
    elif flag in ("-h", "--help"):
        usage()
    elif flag in ("-m", "--mode"):
        mode = opt[1]
    elif flag == "-t":
        period = util.ConvertTimeUnits(opt[1])
    elif flag == "--tests":
        phased_test = True
        phase_lists = opt[1].split(':')
        for phase_list in phase_lists:
            phases.append(phase_list.split(','))

        # check selections
        available = perfcollector.ListTests()
        erred = []
        for phase in phases:
            for test in phase:
                if test not in available:
                    erred.append(test)
        if erred:
            print "Requested unavailable tests:\n%s" % "\n".join(erred)
            usage()
    elif flag == "--version":
        util.PrintVersions("isi_ph_pc", Version())

if mode and phases:
    print "Can't define --mode and --tests together.\n"
    usage()
elif not mode and not phases:
    mode = 'full'
elif mode == 'sleep':
    phases = [ [ 'SleepProfiler' ] ]
    mode = None
elif mode == 'delaysleep':
    # this will set phase 1 to full - sleep and phase 2 to sleep
    mode = 'nosleep'
    phases = [ [], [ 'SleepProfiler' ] ]
    phased_test = True

if not os.path.exists(directory):
    try:
        os.makedirs(directory)
    except Exception, e:
        print "Failed to make PC data directory: %s" % str(e)
        sys.exit(1)

nodes = others
if not nodes:
    print "Need to list some node IPs"
    usage()

pcs = {}
for node in nodes:
    try:
        pcs[node] = perfcollector.TestManagerCaller(node, None, mode=mode,
                                                    phased_tests=phases)
    except Exception, e:
        print "Error starting performance collector on %s: %s" % (node, e)
        sys.exit(1)
    pcs[node].Start()

for node in nodes:
    error = pcs[node].WaitStarted()
    if error:
        print "Error %d waiting for pcs to start" % error
        usage()

error, data = perf.GetPCData(pcs, [], "manual", period,
                             phase_count=len(phases))
if error:
    print "Error while collecting performance data: %d" % error
    usage()

perf.StorePCDataDir(directory, data)
print "Finished PC data collection."
sys.exit(0)
