已经存在一些使用cProfile讨论python概要分析的帖子,以及分析输出的挑战,因为下面的示例代码中的输出文件 restats 不是纯文本文件。下面的代码段只是来自docs.python.org/2/library/profile的样本,不能直接重现。
import cProfile
import re
cProfile.run('re.compile("foo|bar")', 'restats')
这里有一个讨论:Profile a python script using cProfile into an external file,在docs.python.org上有更多关于如何使用 pstats.Stats 分析输出的详细信息(仍然只是一个示例,并且不可复制):
import pstats
p = pstats.Stats('restats')
p.strip_dirs().sort_stats(-1).print_stats()
我可能在这里遗漏了一些非常重要的细节,但我真的想将输出存储在 pandas DataFrame 中并从那里做进一步的分析。
我认为这很简单,因为运行cProfile.run()
的iPython中的输出看起来相当整洁:
In[]:
cProfile.run('re.compile("foo|bar")'
Out[]:
有关如何以相同格式将其变为pandas DataFrame的任何建议吗?
答案 0 :(得分:3)
看起来https://github.com/ssanderson/pstats-view可能会做你想要的事情(尽管有与可视化数据和使其交互相关的不必要的依赖关系):
myData
答案 1 :(得分:3)
我知道这已经找到了答案,但是对于那些不想下载另一个模块的人来说,这是一个容易完成的粗略而准备好的脚本:
px:PXDataSource
首先运行上面的命令,用粗壮的内容填充%%capture profile_results ## uses %%capture magic to send stdout to variable
cProfile.run("your_function( **run_parms )")
,其中包含通常打印的profile_results
的输出。
cProfile
它不会因优雅或令人愉悦的风格而赢得任何奖项,但确实会迫使结果表成为可过滤的数据框格式。
## Parse the stdout text and split it into a table
data=[]
started=False
for l in profile_results.stdout.split("\n"):
if not started:
if l==" ncalls tottime percall cumtime percall filename:lineno(function)":
started=True
data.append(l)
else:
data.append(l)
content=[]
for l in data:
fs = l.find(" ",8)
content.append(tuple([l[0:fs] , l[fs:fs+9], l[fs+9:fs+18], l[fs+18:fs+27], l[fs+27:fs+36], l[fs+36:]]))
prof_df = pd.DataFrame(content[1:], columns=content[0])
答案 2 :(得分:1)
如果您在cmd中使用
python -m cProfile your_script.py
您可以将输出推送到一个csv文件,然后用熊猫解析
python -m cProfile your_script.py >> output.txt
然后用熊猫解析输出
df = pd.read_csv('output.txt', skiprows=5, sep=' ', names=['ncalls','tottime','percall','cumti me','percall','filename:lineno(function)'])
df[['percall.1', 'filename']] = df['percall.1'].str.split(' ', expand=True, n=1)
df = df.drop('filename:lineno(function)', axis=1)
答案 3 :(得分:1)
如果人们不想使用 %%capture 或通过 CSV,在拼凑在一起的解决方案下,在这种情况下,通过 (1) 按累积时间对每个 cProfile 进行排序和 (1) 比较同一文件夹中的多个 cProfile 2) 仅将每个 .prof 的最高结果 (pstats.Stats(f, stream = p_output).sort_stats("cumulative").print_stats(1)
) 添加到数据框(以及 .prof 文件名的一部分,以标识测量来自哪个配置文件)。
请参阅 here 以获取一些原始代码(确实使用 CSV 作为中介)。
import io
import pstats
import pandas as pd
import glob
all_files = glob.glob(profiledir + "/*.prof")
li = []
for f in all_files:
p_output = io.StringIO()
prof_stats = pstats.Stats(f, stream = p_output).sort_stats("cumulative").print_stats(1)
p_output = p_output.getvalue()
p_output = 'ncalls' + p_output.split('ncalls')[-1]
result = '\n'.join([','.join(line.rstrip().split(None,5)) for line in p_output.split('\n')])
df = pd.read_csv(io.StringIO(result), sep=",", header=0)
df['module name'] = f.split(' ')[0].split('\\')[1] # differs depending on your file naming convention
li.append(df)
df = pd.concat(li, axis=0, ignore_index=True)
答案 4 :(得分:0)
您可以使用此功能来完成此任务
def convert_to_df(path, offset=6):
"""
path: path to file
offset: line number from where the columns start
"""
with open(path, "r") as f:
core_profile = f.readlines()
core_profile = core_profile[offset:]
cols = core_profile[0].split()
n = len(cols[:-1])
data = [_.split() for _ in core_profile[1:]]
data = [_ if len(_)==n+1 else _[:n]+[" ".join(_[n+1:])] for _ in data]
data_ = pd.DataFrame(data, columns=cols)
return data_