Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sage
Path: blob/develop/src/bin/sage-startuptime.py
4052 views
1
#!/usr/bin/env python3
2
3
########################################################################
4
# Originally based on a script by Andrew Dalke:
5
# http://projects.scipy.org/pipermail/numpy-discussion/2008-July/035415.html
6
#
7
# 2012: Total rewrite by Volker Braun
8
########################################################################
9
10
11
########################################################################
12
# Copyright (C) 2012 Volker Braun <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
#
16
# https://www.gnu.org/licenses/
17
########################################################################
18
import sys
19
import os
20
import time
21
import gc
22
import warnings
23
24
# Ignore collections.abc warnings, there are a lot of them but they are
25
# harmless. These warnings are also disabled in src/sage/all.py.
26
warnings.filterwarnings('ignore', category=DeprecationWarning,
27
message='.*collections[.]abc.*')
28
29
cmdline_args = sys.argv[2:]
30
have_cmdline_args = bool(cmdline_args)
31
32
direct_children_time = 0
33
import_counter = 0
34
parent = None
35
index_to_parent = dict()
36
all_modules = dict()
37
38
DEFAULT_LEVEL = 0
39
40
41
def new_import(name, globals={}, locals={}, fromlist=[], level=DEFAULT_LEVEL):
42
"""
43
The new import function
44
45
Note that ``name`` is not unique, it can be `sage.foo.bar` or `bar`.
46
"""
47
global all_modules, import_counter, parent, direct_children_time
48
old_direct_children_time = direct_children_time
49
direct_children_time = 0
50
old_parent = parent
51
parent = this_import_counter = import_counter
52
import_counter += 1
53
t1 = time.time()
54
module = old_import(name, globals, locals, fromlist, level)
55
t2 = time.time()
56
parent = old_parent
57
elapsed_time = t2 - t1
58
module_time = elapsed_time - direct_children_time
59
direct_children_time = old_direct_children_time + elapsed_time
60
index_to_parent[this_import_counter] = module
61
data = all_modules.get(module, None)
62
if data is not None:
63
data['parents'].append(parent)
64
data['import_names'].add(name)
65
data['cumulative_time'] += elapsed_time
66
data['time'] += module_time
67
return module
68
data = {'cumulative_time': elapsed_time,
69
'time': module_time,
70
'import_names': set([name]),
71
'parents': [parent]}
72
all_modules[module] = data
73
return module
74
75
76
old_import = __builtins__.__import__
77
__builtins__.__import__ = new_import
78
gc.disable()
79
from sage.all import *
80
gc.enable()
81
__builtins__.__import__ = old_import
82
83
for data in all_modules.values():
84
data['parents'] = set(index_to_parent.get(i, None)
85
for i in data['parents'])
86
87
88
module_by_speed = sorted(((data['time'], module, data)
89
for module, data in all_modules.items()),
90
key=lambda x: x[0])
91
92
93
def print_separator():
94
print('=' * 72)
95
96
97
def print_headline(line):
98
print('=={0:=<68}=='.format(' ' + line + ' '))
99
100
101
width = 10
102
fmt_header = '{0:>' + str(width) + '} {1:>' + str(width) + '} {2:>' + str(width) + '} {3}'
103
fmt_number = '{0:>' + str(width) + '.3f} {1:>' + str(width) + '.3f} {2:>' + str(width) + '} {3}'
104
105
106
def print_table(module_list, limit):
107
global fmt_header, fmt_number
108
print(fmt_header.format('exclude/ms', 'include/ms', '#parents', 'module name'))
109
for t, module, data in module_list[-limit:]:
110
print(fmt_number.format(1000 * t, 1000 * data['cumulative_time'],
111
len(data['parents']), module.__name__))
112
113
114
def guess_module_name(src):
115
module = []
116
src, ext = os.path.splitext(src)
117
while src and src != '/':
118
head, tail = os.path.split(os.path.abspath(src))
119
if (tail == 'src' or any(os.path.exists(os.path.join(head, tail, f))
120
for f in ('setup.py', 'pyproject.toml'))):
121
return '.'.join(module)
122
module.insert(0, tail)
123
src = head
124
return None
125
126
127
if not have_cmdline_args:
128
print('== Slowest module imports (excluding / including children) ==')
129
print_table(module_by_speed, 50)
130
print('Total time (sum over exclusive time): {:.3f}ms'.format(1000 * sum(data[0] for data in module_by_speed)))
131
print('Use sage -startuptime <module_name|file_name>... to get more details about specific modules.')
132
else:
133
for module_arg in cmdline_args:
134
matching_modules = [m for m in all_modules if m.__name__ == module_arg]
135
if not matching_modules:
136
if '/' in module_arg or any(module_arg.endswith(ext) for ext in ('.py', '.pyx')) or os.path.isdir(module_arg):
137
file_name = module_arg
138
module_arg = guess_module_name(file_name)
139
if not module_arg:
140
print('Warning: "' + file_name + '" does not appear to be a Python module source file or package directory.')
141
continue
142
else:
143
matching_modules = [m for m in all_modules if m.__name__.startswith(module_arg)]
144
else:
145
matching_modules = [m for m in all_modules if m.__name__.endswith(module_arg)]
146
if not matching_modules:
147
print('Warning: No modules loaded at startup correspond to {}'.format(module_arg))
148
for module_name in matching_modules:
149
parents = all_modules[module_name]['parents']
150
print()
151
print_separator()
152
print_headline('Slowest modules importing {0}'.format(module_name.__name__))
153
print_table([m for m in module_by_speed if m[1] in parents], 10)
154
print()
155
print_headline('Slowest modules imported by {0}'.format(module_name.__name__))
156
print_table([m for m in module_by_speed if module_name in m[2]['parents']], 10)
157
print()
158
data = all_modules[module_name]
159
print_headline('module ' + module_name.__name__)
160
print('Time to import: {0:.3f}ms'.format(1000 * data['time']))
161
print('Cumulative time: {0:.3f}ms'.format(1000 * data['cumulative_time']))
162
print('Names: {0}'.format(', '.join(data['import_names'])))
163
print('File: {0}'.format(module_name.__file__))
164
165