RepoBenchmark.py #1

  • //
  • main/
  • guest/
  • robert_cowham/
  • p4benchmark/
  • main/
  • locust_files/
  • svn/
  • RepoBenchmark.py
  • View
  • Commits
  • Open Download .zip Download (11 KB)
#! /usr/bin/env python3
#
# Main driver for benchmarks
#
# Copyright (C) 2016, Robert Cowham, Perforce
#

from __future__ import print_function

import logging
import os
import P4
import platform
import sys
import random
import string
import subprocess
from argparse import ArgumentParser
import yaml
from createfiles import create_file, generator

python3 = sys.version_info[0] >= 3

CONFIG_FILE = "benchmark_config.yaml"   # Configuration parameters

# The following can be overridden in the config file svn/svnexe
SVN = "svn" # Default SVN command
if platform.system() == "Windows":
    SVN = "svn.exe"

def readConfig(startdir):
    config = {}
    with open(os.path.join(startdir, CONFIG_FILE), "r") as f:
        config = yaml.load(f)
    return config

logger = logging.getLogger("repo_benchmark")

if not (0x02070000 <= sys.hexversion < 0x02080000):
    sys.exit("Python 2.7 is required to run this program.")

LINE_LENGTH = 80
BLOCK_SIZE = 65536

class RepoBenchmark(object):
    """Generic benchmarking class - must be subclassed"""

    def __init__(self, startdir, config):
        self.id = id(self)      # Object id - unique enough for now.
        if "workspace_root" in config["general"]:
            self.test_root = config["general"]["workspace_root"]
        else:
            self.test_root = os.path.join(startdir, "testdata")
        self.localfilelist = []

    def createWorkspace(self):
        raise NotImplementedError("createWorkspace")

    def syncWorkspace(self):
        raise NotImplementedError("syncWorkspace")

    def addFile(self, filename):
        raise NotImplementedError("addFile")

    def editFile(self, filename):
        raise NotImplementedError("editFile")

    def deleteFile(self, filename):
        raise NotImplementedError("deleteFile")

    def basicFileActions(self):
        """Randomly edit/delete/add files in workspace"""
        numActions = random.randint(1, 20)
        for i in range(numActions):
            action = random.choice(["add", "edit", "edit", "edit", "edit", "delete"])
            filename = random.choice(self.localfilelist)
            if action == "add":
                addfilename = os.path.join(os.path.dirname(filename), generator(20, eol=""))
                create_file(random.randint(100, 1000000), addfilename, random.choice([True, False]))
                self.addFile(addfilename)
            elif action == "edit":
                self.editFile(filename)
                with open(filename, "a") as f:
                    f.write("Some extra data\n")
            else:
                self.deleteFile(filename)
        return numActions

    def commit(self):
        """Commit/Submit changes"""
        raise NotImplementedError("commit")

    def run(self):
        """Run the appropriate test - basically a sync/edit/add/delete and submit"""
        try:
            self.createWorkspace()
            self.syncWorkspace()
            self.basicFileActions()
            self.commit()
        except Exception as e:
            logger.exception(e)
            raise e

class P4Benchmark(RepoBenchmark):
    """Performs basic benchmark test - Perforce specific subclass"""

    def __init__(self, startdir, config):
        super(P4Benchmark, self).__init__(startdir, config)
        if "P4CONFIG" in os.environ:    # Problems with DVCS
            logger.warning("Overriding P4CONFIG from environment")
            os.environ["P4CONFIG"] = "dummy_p4config"
        self.p4 = P4.P4()
        self.p4.logger = logger
        self.config = config
        p4config = config["perforce"]
        self.p4.port = p4config["port"]
        if "charset" in p4config and p4config["charset"]:
            self.p4.charset = p4config["charset"]
        self.repoPath = p4config["repoPath"]
        self.p4.user = p4config["user"]
        result = self.p4.connect()
        if p4config["password"]:
            self.p4.password = p4config["password"]
            self.p4.run_login()
        self.workspace_name = "{}.{}.{}".format(self.p4.user, self.id, platform.node())
        self.workspace_root = os.path.join(self.test_root, self.workspace_name)
        if not os.path.isdir(self.test_root):
            os.makedirs(self.test_root, 0o777)

    def createWorkspace(self):
        ws = self.p4.fetch_client(self.workspace_name)
        existed = (ws._root == self.workspace_root)
        ws._root = self.workspace_root
        ws._view = ["{} //{}/...".format(self.repoPath, self.workspace_name)]
        ws._options = ws._options.replace("normdir", "rmdir")
        result = self.p4.save_client(ws)
        self.p4.client = self.workspace_name
        return existed

    def syncWorkspace(self):
        result = None
        if not os.path.isdir(self.workspace_root):
            os.makedirs(self.workspace_root, 0o777)
        os.chdir(self.workspace_root)
        with self.p4.at_exception_level(P4.P4.RAISE_ERRORS):
            result = self.p4.run_sync("//{}/...".format(self.p4.client))
        havelist = self.p4.run_have()
        self.localfilelist = [f["path"] for f in havelist]
        return len(result)

    def addFile(self, filename):
        self.p4.run_add(filename)

    def editFile(self, filename):
        self.p4.run_edit(filename)

    def deleteFile(self, filename):
        self.p4.run_delete(filename)

    def commit(self):
        """Submit our change"""
        opened = self.p4.run_opened()
        if len(opened) > 0:
            with self.p4.at_exception_level(P4.P4.RAISE_ERRORS):
                files = [x['depotFile'] for x in opened]
                self.p4.run_sync(files)
                self.p4.run_resolve("-ay")
            chg = self.p4.fetch_change()
            chg._description = "A test change"
            self.p4.save_submit(chg)
            with self.p4.at_exception_level(P4.P4.RAISE_ERRORS):
                self.p4.run_revert("//...")


class P4BuildFarmBenchmark(RepoBenchmark):
    """Performs basic benchmark test - Perforce specific subclass"""

    def __init__(self, startdir, config):
        super(P4BuildFarmBenchmark, self).__init__(startdir, config)
        if "P4CONFIG" in os.environ:    # Problems with DVCS
            logger.warning("Removing P4CONFIG from environment")
            del os.environ["P4CONFIG"]
        self.p4 = P4.P4()
        self.p4.logger = logger
        self.config = config
        p4config = config["perforce"]
        self.p4.port = p4config["port"]
        if "charset" in p4config and p4config["charset"]:
            self.p4.charset = p4config["charset"]
        self.repoPath = p4config["repoPath"]
        self.p4.user = p4config["user"]
        result = self.p4.connect()
        if p4config["password"]:
            self.p4.password = p4config["password"]
            self.p4.run_login()
        self.workspace_name = "{}.{}.{}".format(self.p4.user, self.id, platform.node())
        self.workspace_root = os.path.join(self.test_root, self.workspace_name)
        if not os.path.isdir(self.test_root):
            os.makedirs(self.test_root, 0o777)

    def createWorkspace(self):
        ws = self.p4.fetch_client(self.workspace_name)
        existed = (ws._root == self.workspace_root)
        ws._root = self.workspace_root
        ws._view = ["{} //{}/...".format(self.repoPath, self.workspace_name)]
        ws._options = ws._options.replace("normdir", "rmdir")
        result = self.p4.save_client(ws)
        self.p4.client = self.workspace_name
        return existed

    def syncWorkspace(self):
        result = None
        if not os.path.isdir(self.workspace_root):
            os.makedirs(self.workspace_root, 0o777)
        os.chdir(self.workspace_root)
        with self.p4.at_exception_level(P4.P4.RAISE_ERRORS):
            result = self.p4.run_sync("//{}/...".format(self.p4.client))
        havelist = self.p4.run_have()
        self.localfilelist = [f["path"] for f in havelist]
        return len(result)

    def addFile(self, filename):
        pass

    def editFile(self, filename):
        pass

    def deleteFile(self, filename):
        pass

    def commit(self):
        pass

    def basicFileActions(self):
        return 1

    def run(self):
        """Run the appropriate test - basically a sync and submit"""
        try:
            self.createWorkspace()
            self.syncWorkspace()
        except Exception as e:
            logger.exception(e)
            raise e

class SvnBenchmark(RepoBenchmark):
    """Performs basic benchmark test - SVN specific subclass"""

    def __init__(self, startdir, config):
        super(SvnBenchmark, self).__init__(startdir, config)
        self.config = config
        svnconfig = config["svn"]
        self.serverURL = svnconfig["serverURL"]
        self.repoPath = svnconfig["repoPath"]
        self.fullURL = "{}/{}".format(self.serverURL, self.repoPath)
        self.user = svnconfig["user"]
        self.password = svnconfig["password"]
        if "svnexe" in svnconfig and svnconfig["svnexe"]:
            self.svnexe = svnconfig["svnexe"]
        else:
            self.svnexe = SVN
        self.workspace_name = "{}.{}.{}".format(self.user, self.id, platform.node())
        self.workspace_root = os.path.join(self.test_root, self.workspace_name)
        if not os.path.isdir(self.test_root):
            os.makedirs(self.test_root, 0o777)

    def svncmd(self, cmd, args, special = []):
        command = [self.svnexe, cmd]
        for arg in args:
            command.append(arg)

        logger.debug(", ".join(command))
        p = subprocess.Popen(command, stdout=subprocess.PIPE)
        result = p.stdout.read()
        logger.debug(result)
        return result

    def createWorkspace(self):
        "Returns true if existed previously"
        return os.path.isdir(self.workspace_root)

    def syncWorkspace(self):
        cmd = "co"
        if os.path.isdir(self.workspace_root):
            cmd = "update"
        result = self.svncmd(cmd,
                    ["--username", self.user, "--password", self.password,
                     self.fullURL,
                     self.workspace_root
                    ])
        self.localfilelist = []
        for root, dirs, files in os.walk(self.workspace_root):
            if ".svn" in dirs:
                dirs.remove(".svn")
            self.localfilelist.extend([os.path.join(root, f) for f in files])
        return len(result)

    def addFile(self, filename):
        os.chdir(self.workspace_root)
        self.svncmd("add", [filename])

    def editFile(self, filename):
        logger.info("svn edit")
        pass    # SVN doesn't do edits

    def deleteFile(self, filename):
        os.chdir(self.workspace_root)
        self.svncmd("delete", [filename])

    def commit(self):
        description = "SVN checkin"
        os.chdir(self.workspace_root)
        self.svncmd("ci", ["-m", description])

# For testing purposes - normally expect this module to be imported and classes used directly
if __name__ == "__main__":
    parser = ArgumentParser(
            description="Benchmark Testing",
            epilog="Copyright (C) 2016 Robert Cowham, Perforce Software Ltd")
    parser.add_argument("-s","--svn", action='store_true', default=False, help="Run SVN")
    parser.add_argument("-p","--p4", action='store_true', default=True, help="Run P4")
    options = parser.parse_args()

    startdir = os.getcwd()
    if options.svn:
        b = SvnBenchmark(startdir, readConfig(startdir))
    else:
        b = P4Benchmark(startdir, readConfig(startdir))
    try:
        b.run()
    except Exception as e:
        pass
# Change User Description Committed
#1 25529 Robert Cowham Latest copy of files including docker compose setup.
Merging
//guest/robert_cowham/p4benchmark/pb/...
to //guest/robert_cowham/p4benchmark/main/...
//guest/robert_cowham/p4benchmark/pb/locust_files/svn/RepoBenchmark.py
#1 25436 Robert Cowham Moved cross platform scripts to subdir
//guest/robert_cowham/p4benchmark/pb/locust_files/RepoBenchmark.py
#1 25346 Robert Cowham Populate //stream/pure.