zoukankan      html  css  js  c++  java
  • Python 性能分析工具py-spy与Scalene

    Py-Spy介绍

    引用官方的介绍:

    Py-Spy是Python程序的抽样分析器。 它允许您可视化查看Python程序在哪些地方花了更多时间,整个监控方式无需重新启动程序或以任何方式修改工程代码。 Py-Spy的开销非常低:它是用Rust编写的,速度与编译的Python程序不在同一个进程中运行。 这意味着Py-Spy可以安全地用于生成生产环境中的Python应用调优分析。
    github:https://github.com/benfred/py-spy

    安装

    pip install py-spy

    安装后使用py-spy - h可以验证安装,并查看使用帮助。

    py-spy从命令行工作,并获取要从中采样的程序的PID或要运行的python程序的命令行。py-spy具有三个子命令record, topdump

    • record生成火焰图
    • top实时查看每个函数运行时间并统计
    • dump显示每个python线程的当前调用堆栈

    使用py-spy 生成火焰图

    ​ py-spy是一个非常好用而且简单的库,看完他的readme 介绍文档基本就可以入手使用spy。这个工具一是可以生成profile 火焰图,二是可以定位到程序中最耗时间的代码的位置。它的优点在于完全不用修改代码,相比较其他的一些性能调查工具,py-spy这一点非常棒,当你debug 一个线上正在运行的程序的时候,只需要提供进程id,py-spy 就可以直接生成火焰图。

    py-spy record -o profile.svg --pid 12345

    或者

     py-spy record -o profile.svg-python myprogram.py

    "12345" 为程序运行的pid,当运行这行命令的时候,py-spy 开始抽样的程序simlple 并且生成火焰图,我们可以等待1分钟左右 ctrl+c 结束,这时候会在运行这行命令的当前目录下生成 profile.svg 火焰图, 如下图:

    undefined

     火焰图的分析非常简单直观,主要是看"平顶",看图中最下方那个峰顶是平的,那么程序的性能问题就可以从这里入手去解决,这里不详细介绍火焰图看法,不明白的同学可以自行百度。
    

    ​ 通过生成火焰图分析程序瓶颈大概率可以找到并解决80%的程序性能问题,但是还有一种问题,如果我的火焰图没有平顶,但是程序依旧很慢,该如何定位问题?

    没有平顶情况下,定位程序中耗时最多函数/代码

    如下图,通过火焰图并没有发现程序中的平顶
    undefined

    Top功能

    这时候要用到py-spy 提供的 top 命令,Top显示了在python程序中花费最多时间的功能的实时视图,类似于unix top命令。

    py-spy top --pid 12345

    py-spy top-python myprogram.py

    ​ 输入上述命令后,在控制台会显示程序实时的运行状态,这里可以介绍一下图中4个参数的含义, 然后可以通过按1,2,3,4 四个按键,让程序按照下图所述排序。

      1按%Own排序(当前在该函数中花费的时间的百分比)
      2按%Total排序(函数及其子级中当前的时间百分比)
      3按OwnTime排序(函数中花费的总时间)
      4按TotalTime排序(该函数及其子项花费的总时间)

    ​ 比较直观的 使用3 , 可以比较直接的看出程序运行中,所占比消耗时间最多的函数,然后从函数如图进行分析,如下图,可以看出 是wrap 装饰器函数消耗的时间最长,我们用wrapt 这个c写的装饰器进行替换后效率有了明显的提升。

    ​ undefined

    总结 : 使用py-spy 相对于其他一些python性能分析工具,优势在于使用非常简单,而且无须对代码做任何改动,并且可以在保护现场情况下,直接生成火焰图,还可查看实时程序运行状态。

     

    火焰图怎么看

    首先你需要知道:

    X方向是采样时间。

    Y方向是函数调用栈。

    如果给你一个这样的火焰图,你应该得出什么信息:

    1.a()是开始的执行函数,但没有消耗cpu,在这个函数里执行了b(),h()。

    2.a()的两个分支b()h(),这表明a()里面可能有一个条件语句,继续可以看到b()分支消耗的 CPU 大大高于h()。

    3.h()函数没有消耗cpu,cpu全被i()函数占有。

    4.b()函数这条支路继续往上,一直到d(),由d()函数的子函数e()消耗一部分cpu,f()下的g()消耗一部分cpu,你会发现d()的最右边往上缺了一块,这块就是d()执行消耗的cpu。

    结论:

    消耗cpu的函数为e(),g(),d(),i()。

    因此,如果要调查性能问题,首先应该调查g(),其次是i()

     

    Scalene

    Scalene 是一个 Python 的高性能 CPU内存分析器,它可以做到很多其他Python分析器不能做到的事情。它在能提供更多详细信息的同时,比其他的分析器要快几个数量级。

    1. Scalene 是 很快的。它使用采样的方式而不是直接测量或者依靠Python的追踪工具。它的开销一般不超过10-20% (通常更少)。

    2. Scalene 是 精确的。和大部分其他的Python分析器不同,Scalene 在 行级别 下执行CPU分析,在你的程序中指出对应代码行的执行时间。和大多数分析器所返回的功能级分析结果相比,这种程度的细节可能会更有用。

    3. Scalane 可以区分在Python中运行的时间和在native代码(包括库)中花费的时间。大多数的Python程序员并不会去优化native代码(通常在Python实现中或者所依赖的外部库),所以区分这两种运行时间,有助于开发者能够将优化的工作专注于他们能够实际改善的代码上。

    4. Scalene 可以 分析内存使用情况。除了追踪CPU使用情况,Scalene还指出对应代码行的内存增长。这是通过指定内存分配器来实现的。

    5. NEW! Scalene 会生成 每行 的内存分析,以此更容易的追踪内存泄露。

    6. NEW! Scalene 会分析 内存拷贝量, 从而易于发现意外的内存拷贝。特别是因为跨越Python和底层库的边界导致的意外 (例如:意外的把 numpy 数组转化成了Python数组,反之亦然)。

    安装

    Scalene 通过 pip 包的形式进行分发,可以运行在Mac OS X和Linux平台(包括在Windows WSL2中运行的Ubuntu)。

    你可以通过下面的方式安装:

    % pip install scalene

    或者

    % python -m pip install scalene

    注意: 现在这样安装Scalene,是不会安装内存分析的库,所以你只能用它来执行CPU的分析。如果要使用它的内存分析能力,你需要下载这个代码仓库。

    NEW: 你现在可以通过以下命令,在 Mac OS X 上使用 brew 安装内存分析的部分:

    % brew tap emeryberger/scalene
    % brew install --head libscalene

    这将会安装一个你可以使用的 scalene 脚本(下面会提到)。

    使用

    下面的命令会让 Scalene 在提供的示例程序上执行 行级别的CPU分析。

    % python -m scalene test/testme.py

    如果你使用Homebrew安装 Scalene 库,你只需要执行 scalene 就可以执行行级别的CPU和内存分析:

    % scalene test/testme.py

    否则,你需要运行 make 来先构建一个指定的内存分配器:

    % make

    在 Mac OS X 系统上进行分析(不使用Homebrew安装):

    % DYLD_INSERT_LIBRARIES=$PWD/libscalene.dylib PYTHONMALLOC=malloc python -m scalene test/testme.py

    在Linux系统上分析:

    % LD_PRELOAD=$PWD/libscalene.so PYTHONMALLOC=malloc python -m scalene test/testme.py

    执行时增加 --help 来查看全部配置:

    % python3 -m scalene --help
    usage: scalene [-h] [-o OUTFILE] [--profile-interval PROFILE_INTERVAL]
    [--wallclock]
    prog

    Scalene: a high-precision CPU and memory profiler.
    https://github.com/emeryberger/Scalene

    for CPU profiling only:
    % python -m scalene yourprogram.py
    for CPU and memory profiling (Mac OS X):
    % DYLD_INSERT_LIBRARIES=$PWD/libscalene.dylib PYTHONMALLOC=malloc python -m scalene yourprogram.py
    for CPU and memory profiling (Linux):
    % LD_PRELOAD=$PWD/libscalene.so PYTHONMALLOC=malloc python -m scalene yourprogram.py

    positional arguments:
    prog program to be profiled

    optional arguments:
    -h, --help show this help message and exit
    -o OUTFILE, --outfile OUTFILE
    file to hold profiler output (default: stdout)
    --profile-interval PROFILE_INTERVAL
    output profiles every so many seconds.
    --wallclock use wall clock time (default: virtual time)

    对比其他分析器

    性能和功能

    下面的表格把 scalene 和不同分析器的性能做了比较。运行的示例程序 (benchmarks/julia1_nopil.py) 来自于 Gorelick 和 Ozsvald 的 《高性能Python编程》。所有的这些结果都是在 2016款 MacBook Pro上运行的。

    这个表格是其他分析器 vs. Scalene 的功能比较。

    输出

    Scalene 打印被分析程序中带注释的源代码,以及程序在同目录和子目录使用到的任何模块。下面是一个来自 pystone.py pystone.py 的片段,只使用了CPU分析:

    benchmarks/pystone.py: % of CPU time = 100.00% out of   3.66s.
    | CPU % | CPU % |
    Line | (Python) | (native) | [benchmarks/pystone.py]
    --------------------------------------------------------------------------------
    [... lines omitted ...]
    137 | 0.27% | 0.14% | def Proc1(PtrParIn):
    138 | 1.37% | 0.11% | PtrParIn.PtrComp = NextRecord = PtrGlb.copy()
    139 | 0.27% | 0.22% | PtrParIn.IntComp = 5
    140 | 1.37% | 0.77% | NextRecord.IntComp = PtrParIn.IntComp
    141 | 2.47% | 0.93% | NextRecord.PtrComp = PtrParIn.PtrComp
    142 | 1.92% | 0.78% | NextRecord.PtrComp = Proc3(NextRecord.PtrComp)
    143 | 0.27% | 0.17% | if NextRecord.Discr == Ident1:
    144 | 0.82% | 0.30% | NextRecord.IntComp = 6
    145 | 2.19% | 0.79% | NextRecord.EnumComp = Proc6(PtrParIn.EnumComp)
    146 | 1.10% | 0.39% | NextRecord.PtrComp = PtrGlb.PtrComp
    147 | 0.82% | 0.06% | NextRecord.IntComp = Proc7(NextRecord.IntComp, 10)
    148 | | | else:
    149 | | | PtrParIn = NextRecord.copy()
    150 | 0.82% | 0.32% | NextRecord.PtrComp = None
    151 | | | return PtrParIn

     

    refer:

    https://yq.aliyun.com/articles/741628

    http://www.python88.com/topic/62116

  • 相关阅读:
    文档库文件上传Webpart(原创)
    SharePointWebControls帮助类
    使用反射创建动态程序集
    Silverlight Workflow 工作流设计器和工作流编辑器的若干截图,先睹为快(Workflow Designer)
    Using Networking to Retrieve Data and Populate a DataGrid
    昕友silverlight表单设计器的使用 (原创 Form Designer)
    Bing翻译和Google翻译的比较
    具有某接口与是某类型
    UI Automation in WPF/Silverlight
    RTP/RTCP/RTSP/SIP/SDP
  • 原文地址:https://www.cnblogs.com/-wenli/p/13374186.html
Copyright © 2011-2022 走看看