#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2017-2018  Nexedi SA and Contributors.
#                          Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""tcpu - cpu-related benchmarks"""

from __future__ import print_function

import sys
import hashlib
import zlib
from os.path import dirname
from zodbtools.util import Adler32Hasher, CRC32Hasher

from golang import testing

# fmtsize formats size in human readable form
_unitv = "BKMGT" # (2^10)^i represents by corresponding char suffix
def fmtsize(size):
    order = 1<<10
    norder = 0
    while size and (size % order) == 0 and (norder + 1 < len(_unitv)):
        size //= order
        norder += 1

    return "%d%s" % (size, _unitv[norder])

def prettyarg(arg):
    try:
        arg = int(arg)
    except ValueError:
        return arg     # return as it is - e.g. "null-4K"
    else:
        return fmtsize(arg)


# benchit benchmarks benchf(bencharg)
def benchit(benchf, bencharg):
    def _(b):
        benchf(b, bencharg)
    r = testing.benchmark(_)

    benchname = benchf.__name__
    if benchname.startswith('bench_'):
        benchname = benchname[len('bench_'):]

    print('Benchmark%s/py/%s %d\t%.3f µs/op' %
                (benchname, prettyarg(bencharg), r.N, r.T * 1E6 / r.N))


def _bench_hasher(b, h, blksize):
    blksize = int(blksize)
    data = '\0'*blksize

    b.reset_timer()

    n = b.N
    i = 0
    while i < n:
        h.update(data)
        i += 1


def bench_adler32(b, blksize):  _bench_hasher(b, Adler32Hasher(), blksize)
def bench_crc32(b, blksize):    _bench_hasher(b, CRC32Hasher(), blksize)
def bench_sha1(b, blksize):     _bench_hasher(b, hashlib.sha1(), blksize)


def readfile(path):
    with open(path, 'r') as f:
        return f.read()


__dir__ = dirname(__file__)

def bench_unzlib(b, zfile):
    zdata = readfile('%s/testdata/zlib/%s' % (__dir__, zfile))
    b.reset_timer()

    n = b.N
    i = 0
    while i < n:
        zlib.decompress(zdata)
        i += 1


def main():
    bench    = sys.argv[1]
    bencharg = sys.argv[2]

    benchf = globals()['bench_%s' % bench]
    benchit(benchf, bencharg)

if __name__ == '__main__':
    main()
