Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • pypy pypy
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 668
    • Issues 668
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 15
    • Merge requests 15
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar

Mercurial Paris conference scheduled ! Main event : 2022-09-22. Call for papers deadline: 2022-06-17.

  • PyPy
  • pypypypy
  • Issues
  • #1820

Closed
Open
Created Jul 20, 2014 by Bitbucket Importer@bitbucket_importerMaintainer

IPython timeit magic not working anymore.

Created originally on Bitbucket by yuyichao (Yichao Yu)

The following is a copy of the %timeit magic in IPython. It works correctly (with limited function of course) on CPython 2 and 3 but the input statement does not work at all on pypy.

For testing, run run_timeit("print(1)"). On CPython, a lot of "1"'s are printed. On pypy, there's no output at all.

PyPy version, latest default 24db6697b691 ArchLinux x86_64, gcc 4.9, CFLAGS=-O3, pypy translated with --shared,

import timeit, ast, sys

class TimeitTemplateFiller(ast.NodeTransformer):
    """Fill in the AST template. for timing execution.

    This is quite closely tied to the template definition, which is in
    :meth:`ExecutionMagics.timeit`.
    """
    def __init__(self, ast_setup, ast_stmt):
        self.ast_setup = ast_setup
        self.ast_stmt = ast_stmt

    def visit_FunctionDef(self, node):
        "Fill in the setup statement"
        self.generic_visit(node)
        if node.name == "inner":
            node.body[:1] = self.ast_setup.body

        return node

    def visit_For(self, node):
        "Fill in the statement to be timed"
        if getattr(getattr(node.body[0], 'value', None), 'id', None) == 'stmt':
            node.body = self.ast_stmt.body
        return node

def _format_time(timespan, precision=3):
    """Formats the timespan in a human readable form"""
    import math

    if timespan >= 60.0:
        # we have more than a minute, format that in a human readable form
        # Idea from http://snipplr.com/view/5713/
        parts = [("d", 60*60*24),("h", 60*60),("min", 60), ("s", 1)]
        time = []
        leftover = timespan
        for suffix, length in parts:
            value = int(leftover / length)
            if value > 0:
                leftover = leftover % length
                time.append(u'%s%s' % (str(value), suffix))
            if leftover < 1:
                break
        return " ".join(time)

    # Unfortunately the unicode 'micro' symbol can cause problems in
    # certain terminals.
    # See bug: https://bugs.launchpad.net/ipython/+bug/348466
    # Try to prevent crashes by being more secure than it needs to
    # E.g. eclipse is able to print a, but has no sys.stdout.encoding set.
    units = [u"s", u"ms",u'us',"ns"] # the save value
    if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding:
        try:
            u'\xb5'.encode(sys.stdout.encoding)
            units = [u"s", u"ms",u'\xb5s',"ns"]
        except:
            pass
    scaling = [1, 1e3, 1e6, 1e9]

    if timespan > 0.0:
        order = min(-int(math.floor(math.log10(timespan)) // 3), 3)
    else:
        order = 3
    return u"%.*g %s" % (precision, timespan * scaling[order], units[order])

def run_timeit(stmt):
    timefunc = timeit.default_timer
    number = 0
    repeat = timeit.default_repeat
    precision = 3

    timer = timeit.Timer(timer=timefunc)
    # this code has tight coupling to the inner workings of timeit.Timer,
    # but is there a better way to achieve that the code stmt has access
    # to the shell namespace?

    # called as line magic
    ast_setup = ast.parse("pass")
    ast_stmt = ast.parse(stmt)

    # This codestring is taken from timeit.template - we fill it in as an
    # AST, so that we can apply our AST transformations to the user code
    # without affecting the timing code.
    timeit_ast_template = ast.parse('def inner(_it, _timer):\n'
                                    '    setup\n'
                                    '    _t0 = _timer()\n'
                                    '    for _i in _it:\n'
                                    '        stmt\n'
                                    '    _t1 = _timer()\n'
                                    '    return _t1 - _t0\n')

    timeit_ast = TimeitTemplateFiller(ast_setup, ast_stmt).visit(timeit_ast_template)
    timeit_ast = ast.fix_missing_locations(timeit_ast)

    code = compile(timeit_ast, "<magic-timeit>", "exec")

    ns = {}
    exec(code, {}, ns)
    timer.inner = ns["inner"]

    if number == 0:
        # determine number so that 0.2 <= total time < 2.0
        number = 1
        for _ in range(1, 10):
            if timer.timeit(number) >= 0.2:
                break
            number *= 10
    all_runs = timer.repeat(repeat, number)
    best = min(all_runs) / number
    print(u"%d loops, best of %d: %s per loop" % (number, repeat,
                                                  _format_time(best, precision)))
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking