def time(self,line='', cell=None, local_ns=None): expr = self.shell.input_transformer_manager.transform_cell(cell) ## parse ast tp_min = 0.1 t0 = clock() expr_ast = self.shell.compile.ast_parse(expr) tp = clock()-t0 ## compile tc_min = 0.1 t0 = clock() code = self.shell.compile(expr_ast, source, mode) tc = clock()-t0 ## execute st = clock2() try: exec(code, glob, local_ns) except: self.shell.showtraceback() return end = clock2() # Compute actual times and report cpu_user = end[0]-st[0] cpu_sys = end[1]-st[1] cpu_tot = cpu_user+cpu_sys print("CPU times: user %s, sys: %s, total: %s" % (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot))) if tc > tc_min: print("Compiler : %s" % _format_time(tc)) if tp > tp_min: print("Parser : %s" % _format_time(tp))
def logit(self, line, cell): """Log the execution time and file size in a sqlite database %%logit testid, filename [, sql_type] """ user_name = self.shell.user_ns['user_name'] extra = None sql_type = None ## Extracting the testid and filename inputs = line.replace(' ', '').split(',') if len(inputs) == 2: testid, filename = inputs elif len(inputs) == 3: testid, filename, extra = inputs if extra == 'sql_type': ## Get the sql_type from the shell and add it to the testid sql_type = self.shell.user_ns['sql_type'] testid += '_' + sql_type else: testid += '_' + extra ## Current time ctime = time.strftime("%y-%m-%d %H:%M:%S", time.localtime()) ns = {} t0 = clock() ## Execute the cell content exec(cell, self.shell.user_ns, ns) tc = clock() - t0 if sql_type == 'mysql': filesize = -1 else: if os.path.exists(self.file_name): filesize = os.path.getsize(filename) / 1024.**2 else: filesize = -1 ## Print the valuesi print testid, ':' print ctime print 'File size:', filesize, 'MB' print 'Creation time:', tc, 'sec' ## Add the values to the log database self.execute("INSERT INTO %s VALUES ('%s', '%s', '%s', '%s', '%s')" % (self.table_name, user_name, ctime, testid, filesize, tc)) ## Adding the result of the cell back to the shell user_ns for k, v in ns.iteritems(): self.shell.user_ns[k] = v
def logit(self, line, cell): """Log the execution time and file size in a sqlite database %%logit testid, filename [, sql_type] """ user_name = self.shell.user_ns['user_name'] extra = None sql_type = None ## Extracting the testid and filename inputs = line.replace(' ','').split(',') if len(inputs) == 2: testid, filename = inputs elif len(inputs) == 3: testid, filename, extra = inputs if extra == 'sql_type': ## Get the sql_type from the shell and add it to the testid sql_type = self.shell.user_ns['sql_type'] testid += '_' + sql_type else: testid += '_' + extra ## Current time ctime = time.strftime("%y-%m-%d %H:%M:%S", time.localtime()) ns = {} t0 = clock() ## Execute the cell content exec(cell, self.shell.user_ns, ns) tc = clock() - t0 if sql_type == 'mysql': filesize = -1 else: if os.path.exists(self.file_name): filesize = os.path.getsize(filename)/1024.**2 else: filesize = -1 ## Print the valuesi print testid,':' print ctime print 'File size:', filesize, 'MB' print 'Creation time:', tc, 'sec' ## Add the values to the log database self.execute("INSERT INTO %s VALUES ('%s', '%s', '%s', '%s', '%s')"% (self.table_name, user_name, ctime, testid, filesize, tc)) ## Adding the result of the cell back to the shell user_ns for k,v in ns.iteritems(): self.shell.user_ns[k] = v
def time(self,parameter_s, local_ns=None): """Time execution of a Python statement or expression. The CPU and wall clock times are printed, and the value of the expression (if any) is returned. Note that under Win32, system time is always reported as 0, since it can not be measured. This function provides very basic timing functionality. In Python 2.3, the timeit module offers more control and sophistication, so this could be rewritten to use it (patches welcome). Examples -------- :: In [1]: time 2**128 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Out[1]: 340282366920938463463374607431768211456L In [2]: n = 1000000 In [3]: time sum(range(n)) CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s Wall time: 1.37 Out[3]: 499999500000L In [4]: time print 'hello world' hello world CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Note that the time needed by Python to compile the given expression will be reported if it is more than 0.1s. In this example, the actual exponentiation is done by Python at compilation time, so while the expression can take a noticeable amount of time to compute, that time is purely due to the compilation: In [5]: time 3**9999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s In [6]: time 3**999999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s Compiler : 0.78 s """ # fail immediately if the given expression can't be compiled expr = self.shell.prefilter(parameter_s,False) # Minimum time above which parse time will be reported tp_min = 0.1 t0 = clock() expr_ast = ast.parse(expr) tp = clock()-t0 # Apply AST transformations expr_ast = self.shell.transform_ast(expr_ast) # Minimum time above which compilation time will be reported tc_min = 0.1 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr): mode = 'eval' source = '<timed eval>' expr_ast = ast.Expression(expr_ast.body[0].value) else: mode = 'exec' source = '<timed exec>' t0 = clock() code = compile(expr_ast, source, mode) tc = clock()-t0 # skew measurement as little as possible glob = self.shell.user_ns wtime = time.time # time execution wall_st = wtime() if mode=='eval': st = clock2() out = eval(code, glob, local_ns) end = clock2() else: st = clock2() exec code in glob, local_ns end = clock2() out = None wall_end = wtime() # Compute actual times and report wall_time = wall_end-wall_st cpu_user = end[0]-st[0] cpu_sys = end[1]-st[1] cpu_tot = cpu_user+cpu_sys print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ (cpu_user,cpu_sys,cpu_tot) print "Wall time: %.2f s" % wall_time if tc > tc_min: print "Compiler : %.2f s" % tc if tp > tp_min: print "Parser : %.2f s" % tp return out
def timeit(self, line='', cell=None): """Time execution of a Python statement or expression Usage, in line mode: %timeit [-n<N> -r<R> [-t|-c]] statement or in cell mode: %%timeit [-n<N> -r<R> [-t|-c]] setup_code code code... Time execution of a Python statement or expression using the timeit module. This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - In cell mode, the statement in the first line is used as setup code (executed but not timed) and the body of the cell is timed. The cell body has access to any variables created in the setup code. Options: -n<N>: execute the given statement <N> times in a loop. If this value is not given, a fitting value is chosen. -r<R>: repeat the loop iteration <R> times and take the best result. Default: 3 -t: use time.time to measure the time, which is the default on Unix. This function measures wall time. -c: use time.clock to measure the time, which is the default on Windows and measures wall time. On Unix, resource.getrusage is used instead and returns the CPU user time. -p<P>: use a precision of <P> digits to display the timing result. Default: 3 Examples -------- :: In [1]: %timeit pass 10000000 loops, best of 3: 53.3 ns per loop In [2]: u = None In [3]: %timeit u is None 10000000 loops, best of 3: 184 ns per loop In [4]: %timeit -r 4 u == None 1000000 loops, best of 4: 242 ns per loop In [5]: import time In [6]: %timeit -n1 time.sleep(2) 1 loops, best of 3: 2 s per loop The times reported by %timeit will be slightly higher than those reported by the timeit.py script when variables are accessed. This is due to the fact that %timeit executes the statement in the namespace of the shell, compared with timeit.py, which uses a single setup statement to import function or create variables. Generally, the bias does not matter as long as results from timeit.py are not mixed with those from %timeit.""" import timeit import math # XXX: Unfortunately the unicode 'micro' symbol can cause problems in # certain terminals. Until we figure out a robust way of # auto-detecting if the terminal can deal with it, use plain 'us' for # microseconds. I am really NOT happy about disabling the proper # 'micro' prefix, but crashing is worse... If anyone knows what the # right solution for this is, I'm all ears... # # Note: using # # s = u'\xb5' # s.encode(sys.getdefaultencoding()) # # is not sufficient, as I've seen terminals where that fails but # print s # # succeeds # # See bug: https://bugs.launchpad.net/ipython/+bug/348466 #units = [u"s", u"ms",u'\xb5',"ns"] units = [u"s", u"ms",u'us',"ns"] scaling = [1, 1e3, 1e6, 1e9] opts, stmt = self.parse_options(line,'n:r:tcp:', posix=False, strict=False) if stmt == "" and cell is None: return timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) repeat = int(getattr(opts, "r", timeit.default_repeat)) precision = int(getattr(opts, "p", 3)) if hasattr(opts, "t"): timefunc = time.time if hasattr(opts, "c"): timefunc = clock 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? transform = self.shell.input_splitter.transform_cell if cell is None: # called as line magic ast_setup = ast.parse("pass") ast_stmt = ast.parse(transform(stmt)) else: ast_setup = ast.parse(transform(stmt)) ast_stmt = ast.parse(transform(cell)) ast_setup = self.shell.transform_ast(ast_setup) ast_stmt = self.shell.transform_ast(ast_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') class TimeitTemplateFiller(ast.NodeTransformer): "This is quite tightly tied to the template definition above." def visit_FunctionDef(self, node): "Fill in the setup statement" self.generic_visit(node) if node.name == "inner": node.body[:1] = 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 = ast_stmt.body return node timeit_ast = TimeitTemplateFiller().visit(timeit_ast_template) timeit_ast = ast.fix_missing_locations(timeit_ast) # Track compilation time so it can be reported if too long # Minimum time above which compilation time will be reported tc_min = 0.1 t0 = clock() code = compile(timeit_ast, "<magic-timeit>", "exec") tc = clock()-t0 ns = {} exec code in self.shell.user_ns, ns timer.inner = ns["inner"] if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break number *= 10 best = min(timer.repeat(repeat, number)) / number if best > 0.0 and best < 1000.0: order = min(-int(math.floor(math.log10(best)) // 3), 3) elif best >= 1000.0: order = 0 else: order = 3 print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat, precision, best * scaling[order], units[order]) if tc > tc_min: print "Compiler time: %.2f s" % tc
def time(self,line='', cell=None, local_ns=None): """Time execution of a Python statement or expression. The CPU and wall clock times are printed, and the value of the expression (if any) is returned. Note that under Win32, system time is always reported as 0, since it can not be measured. This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - In cell mode, you can time the cell body (a directly following statement raises an error). This function provides very basic timing functionality. Use the timeit magic for more controll over the measurement. Examples -------- :: In [1]: %time 2**128 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Out[1]: 340282366920938463463374607431768211456L In [2]: n = 1000000 In [3]: %time sum(range(n)) CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s Wall time: 1.37 Out[3]: 499999500000L In [4]: %time print 'hello world' hello world CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Note that the time needed by Python to compile the given expression will be reported if it is more than 0.1s. In this example, the actual exponentiation is done by Python at compilation time, so while the expression can take a noticeable amount of time to compute, that time is purely due to the compilation: In [5]: %time 3**9999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s In [6]: %time 3**999999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s Compiler : 0.78 s """ # fail immediately if the given expression can't be compiled if line and cell: raise UsageError("Can't use statement directly after '%%time'!") if cell: expr = self.shell.input_transformer_manager.transform_cell(cell) else: expr = self.shell.input_transformer_manager.transform_cell(line) # Minimum time above which parse time will be reported tp_min = 0.1 t0 = clock() expr_ast = ast.parse(expr) tp = clock()-t0 # Apply AST transformations expr_ast = self.shell.transform_ast(expr_ast) # Minimum time above which compilation time will be reported tc_min = 0.1 if len(expr_ast.body)==1 and isinstance(expr_ast.body[0], ast.Expr): mode = 'eval' source = '<timed eval>' expr_ast = ast.Expression(expr_ast.body[0].value) else: mode = 'exec' source = '<timed exec>' t0 = clock() code = compile(expr_ast, source, mode) tc = clock()-t0 # skew measurement as little as possible glob = self.shell.user_ns wtime = time.time # time execution wall_st = wtime() if mode=='eval': st = clock2() out = eval(code, glob, local_ns) end = clock2() else: st = clock2() exec code in glob, local_ns end = clock2() out = None wall_end = wtime() # Compute actual times and report wall_time = wall_end-wall_st cpu_user = end[0]-st[0] cpu_sys = end[1]-st[1] cpu_tot = cpu_user+cpu_sys # On windows cpu_sys is always zero, so no new information to the next print if sys.platform != 'win32': print "CPU times: user %s, sys: %s, total: %s" % \ (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot)) print "Wall time: %s" % _format_time(wall_time) if tc > tc_min: print "Compiler : %s" % _format_time(tc) if tp > tp_min: print "Parser : %s" % _format_time(tp) return out
def timeit(self, line='', cell=None): """Time execution of a Python statement or expression Usage, in line mode: %timeit [-n<N> -r<R> [-t|-c]] statement or in cell mode: %%timeit [-n<N> -r<R> [-t|-c]] setup_code code code... Time execution of a Python statement or expression using the timeit module. This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - In cell mode, the statement in the first line is used as setup code (executed but not timed) and the body of the cell is timed. The cell body has access to any variables created in the setup code. Options: -n<N>: execute the given statement <N> times in a loop. If this value is not given, a fitting value is chosen. -r<R>: repeat the loop iteration <R> times and take the best result. Default: 3 -t: use time.time to measure the time, which is the default on Unix. This function measures wall time. -c: use time.clock to measure the time, which is the default on Windows and measures wall time. On Unix, resource.getrusage is used instead and returns the CPU user time. -p<P>: use a precision of <P> digits to display the timing result. Default: 3 Examples -------- :: In [1]: %timeit pass 10000000 loops, best of 3: 53.3 ns per loop In [2]: u = None In [3]: %timeit u is None 10000000 loops, best of 3: 184 ns per loop In [4]: %timeit -r 4 u == None 1000000 loops, best of 4: 242 ns per loop In [5]: import time In [6]: %timeit -n1 time.sleep(2) 1 loops, best of 3: 2 s per loop The times reported by %timeit will be slightly higher than those reported by the timeit.py script when variables are accessed. This is due to the fact that %timeit executes the statement in the namespace of the shell, compared with timeit.py, which uses a single setup statement to import function or create variables. Generally, the bias does not matter as long as results from timeit.py are not mixed with those from %timeit.""" import timeit opts, stmt = self.parse_options(line,'n:r:tcp:', posix=False, strict=False) if stmt == "" and cell is None: return timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) repeat = int(getattr(opts, "r", timeit.default_repeat)) precision = int(getattr(opts, "p", 3)) if hasattr(opts, "t"): timefunc = time.time if hasattr(opts, "c"): timefunc = clock 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? transform = self.shell.input_splitter.transform_cell if cell is None: # called as line magic ast_setup = ast.parse("pass") ast_stmt = ast.parse(transform(stmt)) else: ast_setup = ast.parse(transform(stmt)) ast_stmt = ast.parse(transform(cell)) ast_setup = self.shell.transform_ast(ast_setup) ast_stmt = self.shell.transform_ast(ast_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') class TimeitTemplateFiller(ast.NodeTransformer): "This is quite tightly tied to the template definition above." def visit_FunctionDef(self, node): "Fill in the setup statement" self.generic_visit(node) if node.name == "inner": node.body[:1] = 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 = ast_stmt.body return node timeit_ast = TimeitTemplateFiller().visit(timeit_ast_template) timeit_ast = ast.fix_missing_locations(timeit_ast) # Track compilation time so it can be reported if too long # Minimum time above which compilation time will be reported tc_min = 0.1 t0 = clock() code = compile(timeit_ast, "<magic-timeit>", "exec") tc = clock()-t0 ns = {} exec code in self.shell.user_ns, ns timer.inner = ns["inner"] if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break number *= 10 best = min(timer.repeat(repeat, number)) / number print u"%d loops, best of %d: %s per loop" % (number, repeat, _format_time(best, precision)) if tc > tc_min: print "Compiler time: %.2f s" % tc
def time(self, line='', cell=None, local_ns=None): """Time execution of a Python statement or expression. The CPU and wall clock times are printed, and the value of the expression (if any) is returned. Note that under Win32, system time is always reported as 0, since it can not be measured. This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - In cell mode, you can time the cell body (a directly following statement raises an error). This function provides very basic timing functionality. Use the timeit magic for more controll over the measurement. Examples -------- :: In [1]: %time 2**128 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Out[1]: 340282366920938463463374607431768211456L In [2]: n = 1000000 In [3]: %time sum(range(n)) CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s Wall time: 1.37 Out[3]: 499999500000L In [4]: %time print 'hello world' hello world CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Note that the time needed by Python to compile the given expression will be reported if it is more than 0.1s. In this example, the actual exponentiation is done by Python at compilation time, so while the expression can take a noticeable amount of time to compute, that time is purely due to the compilation: In [5]: %time 3**9999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s In [6]: %time 3**999999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s Compiler : 0.78 s """ # fail immediately if the given expression can't be compiled if line and cell: raise UsageError("Can't use statement directly after '%%time'!") if cell: expr = self.shell.input_transformer_manager.transform_cell(cell) else: expr = self.shell.input_transformer_manager.transform_cell(line) # Minimum time above which parse time will be reported tp_min = 0.1 t0 = clock() expr_ast = ast.parse(expr) tp = clock() - t0 # Apply AST transformations expr_ast = self.shell.transform_ast(expr_ast) # Minimum time above which compilation time will be reported tc_min = 0.1 if len(expr_ast.body) == 1 and isinstance(expr_ast.body[0], ast.Expr): mode = 'eval' source = '<timed eval>' expr_ast = ast.Expression(expr_ast.body[0].value) else: mode = 'exec' source = '<timed exec>' t0 = clock() code = compile(expr_ast, source, mode) tc = clock() - t0 # skew measurement as little as possible glob = self.shell.user_ns wtime = time.time # time execution wall_st = wtime() if mode == 'eval': st = clock2() out = eval(code, glob, local_ns) end = clock2() else: st = clock2() exec code in glob, local_ns end = clock2() out = None wall_end = wtime() # Compute actual times and report wall_time = wall_end - wall_st cpu_user = end[0] - st[0] cpu_sys = end[1] - st[1] cpu_tot = cpu_user + cpu_sys # On windows cpu_sys is always zero, so no new information to the next print if sys.platform != 'win32': print "CPU times: user %s, sys: %s, total: %s" % \ (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot)) print "Wall time: %s" % _format_time(wall_time) if tc > tc_min: print "Compiler : %s" % _format_time(tc) if tp > tp_min: print "Parser : %s" % _format_time(tp) return out
def timeit(self, line='', cell=None): """Time execution of a Python statement or expression Usage, in line mode: %timeit [-n<N> -r<R> [-t|-c]] statement or in cell mode: %%timeit [-n<N> -r<R> [-t|-c]] setup_code code code... Time execution of a Python statement or expression using the timeit module. This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - In cell mode, the statement in the first line is used as setup code (executed but not timed) and the body of the cell is timed. The cell body has access to any variables created in the setup code. Options: -n<N>: execute the given statement <N> times in a loop. If this value is not given, a fitting value is chosen. -r<R>: repeat the loop iteration <R> times and take the best result. Default: 3 -t: use time.time to measure the time, which is the default on Unix. This function measures wall time. -c: use time.clock to measure the time, which is the default on Windows and measures wall time. On Unix, resource.getrusage is used instead and returns the CPU user time. -p<P>: use a precision of <P> digits to display the timing result. Default: 3 Examples -------- :: In [1]: %timeit pass 10000000 loops, best of 3: 53.3 ns per loop In [2]: u = None In [3]: %timeit u is None 10000000 loops, best of 3: 184 ns per loop In [4]: %timeit -r 4 u == None 1000000 loops, best of 4: 242 ns per loop In [5]: import time In [6]: %timeit -n1 time.sleep(2) 1 loops, best of 3: 2 s per loop The times reported by %timeit will be slightly higher than those reported by the timeit.py script when variables are accessed. This is due to the fact that %timeit executes the statement in the namespace of the shell, compared with timeit.py, which uses a single setup statement to import function or create variables. Generally, the bias does not matter as long as results from timeit.py are not mixed with those from %timeit.""" import timeit opts, stmt = self.parse_options(line, 'n:r:tcp:', posix=False, strict=False) if stmt == "" and cell is None: return timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) repeat = int(getattr(opts, "r", timeit.default_repeat)) precision = int(getattr(opts, "p", 3)) if hasattr(opts, "t"): timefunc = time.time if hasattr(opts, "c"): timefunc = clock 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? transform = self.shell.input_splitter.transform_cell if cell is None: # called as line magic ast_setup = ast.parse("pass") ast_stmt = ast.parse(transform(stmt)) else: ast_setup = ast.parse(transform(stmt)) ast_stmt = ast.parse(transform(cell)) ast_setup = self.shell.transform_ast(ast_setup) ast_stmt = self.shell.transform_ast(ast_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') class TimeitTemplateFiller(ast.NodeTransformer): "This is quite tightly tied to the template definition above." def visit_FunctionDef(self, node): "Fill in the setup statement" self.generic_visit(node) if node.name == "inner": node.body[:1] = 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 = ast_stmt.body return node timeit_ast = TimeitTemplateFiller().visit(timeit_ast_template) timeit_ast = ast.fix_missing_locations(timeit_ast) # Track compilation time so it can be reported if too long # Minimum time above which compilation time will be reported tc_min = 0.1 t0 = clock() code = compile(timeit_ast, "<magic-timeit>", "exec") tc = clock() - t0 ns = {} exec code in self.shell.user_ns, ns timer.inner = ns["inner"] if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break number *= 10 best = min(timer.repeat(repeat, number)) / number print u"%d loops, best of %d: %s per loop" % ( number, repeat, _format_time(best, precision)) if tc > tc_min: print "Compiler time: %.2f s" % tc
def timeit2(self, line='', cell=None): import timeit opts, stmt = self.parse_options(line, 'n:r:gtcp:', posix=False, strict=False) if stmt == "" and cell is None: return timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) repeat = int(getattr(opts, "r", timeit.default_repeat)) precision = int(getattr(opts, "p", 3)) if hasattr(opts, "t"): timefunc = time.time if hasattr(opts, "c"): timefunc = clock if hasattr(opts, "g"): timer = timeit.Timer(timer=timefunc, setup='gc.enable()') else: 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? transform = self.shell.input_splitter.transform_cell if cell is None: # called as line magic ast_setup = ast.parse("pass") ast_stmt = ast.parse(transform(stmt)) else: ast_setup = ast.parse(transform(stmt)) ast_stmt = ast.parse(transform(cell)) ast_setup = self.shell.transform_ast(ast_setup) ast_stmt = self.shell.transform_ast(ast_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') class TimeitTemplateFiller(ast.NodeTransformer): "This is quite tightly tied to the template definition above." def visit_FunctionDef(self, node): "Fill in the setup statement" self.generic_visit(node) if node.name == "inner": node.body[:1] = 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 = ast_stmt.body return node timeit_ast = TimeitTemplateFiller().visit(timeit_ast_template) timeit_ast = ast.fix_missing_locations(timeit_ast) # Track compilation time so it can be reported if too long # Minimum time above which compilation time will be reported tc_min = 0.1 t0 = clock() code = compile(timeit_ast, "<magic-timeit>", "exec") tc = clock() - t0 ns = {} exec code in self.shell.user_ns, ns timer.inner = ns["inner"] if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break number *= 10 result = timer.repeat(repeat, number) best = min(result) / number worst = max(result) / number avg = sum(result) / number / float(len(result)) print u"{0} loops" \ u"\n AVG of {1}: {2:>5} per loop" \ u"\n BEST of {1}: {3:>5} per loop" \ u"\n WORST of {1}: {4:>5} per loop".format( number, repeat, _format_time(avg, precision), _format_time(best, precision), _format_time(worst, precision) ) if tc > tc_min: print "Compiler time: %.2f s" % tc
def time(self, parameter_s, local_ns=None): """Time execution of a Python statement or expression. The CPU and wall clock times are printed, and the value of the expression (if any) is returned. Note that under Win32, system time is always reported as 0, since it can not be measured. This function provides very basic timing functionality. In Python 2.3, the timeit module offers more control and sophistication, so this could be rewritten to use it (patches welcome). Examples -------- :: In [1]: time 2**128 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Out[1]: 340282366920938463463374607431768211456L In [2]: n = 1000000 In [3]: time sum(range(n)) CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s Wall time: 1.37 Out[3]: 499999500000L In [4]: time print 'hello world' hello world CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 Note that the time needed by Python to compile the given expression will be reported if it is more than 0.1s. In this example, the actual exponentiation is done by Python at compilation time, so while the expression can take a noticeable amount of time to compute, that time is purely due to the compilation: In [5]: time 3**9999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s In [6]: time 3**999999; CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s Wall time: 0.00 s Compiler : 0.78 s """ # fail immediately if the given expression can't be compiled expr = self.shell.prefilter(parameter_s, False) # Minimum time above which compilation time will be reported tc_min = 0.1 try: mode = 'eval' t0 = clock() code = compile(expr, '<timed eval>', mode) tc = clock() - t0 except SyntaxError: mode = 'exec' t0 = clock() code = compile(expr, '<timed exec>', mode) tc = clock() - t0 # skew measurement as little as possible glob = self.shell.user_ns wtime = time.time # time execution wall_st = wtime() if mode == 'eval': st = clock2() out = eval(code, glob, local_ns) end = clock2() else: st = clock2() exec code in glob, local_ns end = clock2() out = None wall_end = wtime() # Compute actual times and report wall_time = wall_end - wall_st cpu_user = end[0] - st[0] cpu_sys = end[1] - st[1] cpu_tot = cpu_user + cpu_sys print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \ (cpu_user,cpu_sys,cpu_tot) print "Wall time: %.2f s" % wall_time if tc > tc_min: print "Compiler : %.2f s" % tc return out
def timeit(self, line='', cell=None): """Time execution of a Python statement or expression Usage, in line mode: %timeit [-n<N> -r<R> [-t|-c]] statement or in cell mode: %%timeit [-n<N> -r<R> [-t|-c]] setup_code code code... Time execution of a Python statement or expression using the timeit module. This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - In cell mode, the statement in the first line is used as setup code (executed but not timed) and the body of the cell is timed. The cell body has access to any variables created in the setup code. Options: -n<N>: execute the given statement <N> times in a loop. If this value is not given, a fitting value is chosen. -r<R>: repeat the loop iteration <R> times and take the best result. Default: 3 -t: use time.time to measure the time, which is the default on Unix. This function measures wall time. -c: use time.clock to measure the time, which is the default on Windows and measures wall time. On Unix, resource.getrusage is used instead and returns the CPU user time. -p<P>: use a precision of <P> digits to display the timing result. Default: 3 Examples -------- :: In [1]: %timeit pass 10000000 loops, best of 3: 53.3 ns per loop In [2]: u = None In [3]: %timeit u is None 10000000 loops, best of 3: 184 ns per loop In [4]: %timeit -r 4 u == None 1000000 loops, best of 4: 242 ns per loop In [5]: import time In [6]: %timeit -n1 time.sleep(2) 1 loops, best of 3: 2 s per loop The times reported by %timeit will be slightly higher than those reported by the timeit.py script when variables are accessed. This is due to the fact that %timeit executes the statement in the namespace of the shell, compared with timeit.py, which uses a single setup statement to import function or create variables. Generally, the bias does not matter as long as results from timeit.py are not mixed with those from %timeit.""" import timeit import math # XXX: Unfortunately the unicode 'micro' symbol can cause problems in # certain terminals. Until we figure out a robust way of # auto-detecting if the terminal can deal with it, use plain 'us' for # microseconds. I am really NOT happy about disabling the proper # 'micro' prefix, but crashing is worse... If anyone knows what the # right solution for this is, I'm all ears... # # Note: using # # s = u'\xb5' # s.encode(sys.getdefaultencoding()) # # is not sufficient, as I've seen terminals where that fails but # print s # # succeeds # # See bug: https://bugs.launchpad.net/ipython/+bug/348466 #units = [u"s", u"ms",u'\xb5',"ns"] units = [u"s", u"ms", u'us', "ns"] scaling = [1, 1e3, 1e6, 1e9] opts, stmt = self.parse_options(line, 'n:r:tcp:', posix=False, strict=False) if stmt == "" and cell is None: return timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) repeat = int(getattr(opts, "r", timeit.default_repeat)) precision = int(getattr(opts, "p", 3)) if hasattr(opts, "t"): timefunc = time.time if hasattr(opts, "c"): timefunc = clock 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? transform = self.shell.input_splitter.transform_cell if cell is None: # called as line magic setup = 'pass' stmt = timeit.reindent(transform(stmt), 8) else: setup = timeit.reindent(transform(stmt), 4) stmt = timeit.reindent(transform(cell), 8) # From Python 3.3, this template uses new-style string formatting. if sys.version_info >= (3, 3): src = timeit.template.format(stmt=stmt, setup=setup) else: src = timeit.template % dict(stmt=stmt, setup=setup) # Track compilation time so it can be reported if too long # Minimum time above which compilation time will be reported tc_min = 0.1 t0 = clock() code = compile(src, "<magic-timeit>", "exec") tc = clock() - t0 ns = {} exec code in self.shell.user_ns, ns timer.inner = ns["inner"] if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break number *= 10 best = min(timer.repeat(repeat, number)) / number if best > 0.0 and best < 1000.0: order = min(-int(math.floor(math.log10(best)) // 3), 3) elif best >= 1000.0: order = 0 else: order = 3 print u"%d loops, best of %d: %.*g %s per loop" % ( number, repeat, precision, best * scaling[order], units[order]) if tc > tc_min: print "Compiler time: %.2f s" % tc