// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile

import (
    "io/ioutil"
    "log"
    "os"
    "os/signal"
    "path/filepath"
    "runtime"
    "runtime/pprof"
    "sync/atomic"
)

const (
    cpuMode = iota
    memMode
    blockMode
    traceMode
)

// Profile represents an active profiling session.
type Profile struct {
    // quiet suppresses informational messages during profiling.
    quiet bool

    // noShutdownHook controls whether the profiling package should
    // hook SIGINT to write profiles cleanly.
    noShutdownHook bool

    // mode holds the type of profiling that will be made
    mode int

    // path holds the base path where various profiling files are  written.
    // If blank, the base path will be generated by ioutil.TempDir.
    path string

    // memProfileRate holds the rate for the memory profile.
    memProfileRate int

    // closer holds a cleanup function that run after each profile
    closer func()

    // stopped records if a call to profile.Stop has been made
    stopped uint32
}

// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *Profile) { p.noShutdownHook = true }

// Quiet suppresses informational messages during profiling.
func Quiet(p *Profile) { p.quiet = true }

// CPUProfile enables cpu profiling.
// It disables any previous profiling settings.
func CPUProfile(p *Profile) { p.mode = cpuMode }

// DefaultMemProfileRate is the default memory profiling rate.
// See also http://golang.org/pkg/runtime/#pkg-variables
const DefaultMemProfileRate = 4096

// MemProfile enables memory profiling.
// It disables any previous profiling settings.
func MemProfile(p *Profile) {
    p.memProfileRate = DefaultMemProfileRate
    p.mode = memMode
}

// MemProfileRate enables memory profiling at the preferred rate.
// It disables any previous profiling settings.
func MemProfileRate(rate int) func(*Profile) {
    return func(p *Profile) {
        p.memProfileRate = rate
        p.mode = memMode
    }
}

// BlockProfile enables block (contention) profiling.
// It disables any previous profiling settings.
func BlockProfile(p *Profile) { p.mode = blockMode }

// Trace profile controls if execution tracing will be enabled. It disables any previous profiling settings.
func TraceProfile(p *Profile) { p.mode = traceMode }

// ProfilePath controls the base path where various profiling
// files are written. If blank, the base path will be generated
// by ioutil.TempDir.
func ProfilePath(path string) func(*Profile) {
    return func(p *Profile) {
        p.path = path
    }
}

// Stop stops the profile and flushes any unwritten data.
func (p *Profile) Stop() {
    if !atomic.CompareAndSwapUint32(&p.stopped, 0, 1) {
        // someone has already called close
        return
    }
    p.closer()
    atomic.StoreUint32(&started, 0)
}

// started is non zero if a profile is running.
var started uint32

// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*Profile)) interface {
    Stop()
} {
    if !atomic.CompareAndSwapUint32(&started, 0, 1) {
        log.Fatal("profile: Start() already called")
    }

    var prof Profile
    for _, option := range options {
        option(&prof)
    }

    path, err := func() (string, error) {
        if p := prof.path; p != "" {
            return p, os.MkdirAll(p, 0777)
        }
        return ioutil.TempDir("", "profile")
    }()

    if err != nil {
        log.Fatalf("profile: could not create initial output directory: %v", err)
    }

    logf := func(format string, args ...interface{}) {
        if !prof.quiet {
            log.Printf(format, args...)
        }
    }

    switch prof.mode {
    case cpuMode:
        fn := filepath.Join(path, "cpu.pprof")
        f, err := os.Create(fn)
        if err != nil {
            log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
        }
        logf("profile: cpu profiling enabled, %s", fn)
        pprof.StartCPUProfile(f)
        prof.closer = func() {
            pprof.StopCPUProfile()
            f.Close()
            logf("profile: cpu profiling disabled, %s", fn)
        }

    case memMode:
        fn := filepath.Join(path, "mem.pprof")
        f, err := os.Create(fn)
        if err != nil {
            log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
        }
        old := runtime.MemProfileRate
        runtime.MemProfileRate = prof.memProfileRate
        logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
        prof.closer = func() {
            pprof.Lookup("heap").WriteTo(f, 0)
            f.Close()
            runtime.MemProfileRate = old
            logf("profile: memory profiling disabled, %s", fn)
        }

    case blockMode:
        fn := filepath.Join(path, "block.pprof")
        f, err := os.Create(fn)
        if err != nil {
            log.Fatalf("profile: could not create block profile %q: %v", fn, err)
        }
        runtime.SetBlockProfileRate(1)
        logf("profile: block profiling enabled, %s", fn)
        prof.closer = func() {
            pprof.Lookup("block").WriteTo(f, 0)
            f.Close()
            runtime.SetBlockProfileRate(0)
            logf("profile: block profiling disabled, %s", fn)
        }

    case traceMode:
        fn := filepath.Join(path, "trace.out")
        f, err := os.Create(fn)
        if err != nil {
            log.Fatalf("profile: could not create trace output file %q: %v", fn, err)
        }
        if err := startTrace(f); err != nil {
            log.Fatalf("profile: could not start trace: %v", err)
        }
        logf("profile: trace enabled, %s", fn)
        prof.closer = func() {
            stopTrace()
            logf("profile: trace disabled, %s", fn)
        }
    }

    if !prof.noShutdownHook {
        go func() {
            c := make(chan os.Signal, 1)
            signal.Notify(c, os.Interrupt)
            <-c

            log.Println("profile: caught interrupt, stopping profiles")
            prof.Stop()

            os.Exit(0)
        }()
    }

    return &prof
}

profile.go的更多相关文章

  1. CoreCRM 开发实录 —— Profile

    再简单的功能,也需要一坨代码的支持.Profile 的编辑功能主要就是修改个人的信息.比如用户名.头像.性别.电话--虽然只是一个编辑界面,但添加下来,涉及了6个文件的修改和7个新创建的文件.各种生成 ...

  2. Xamarin+Prism开发详解一:PCL跨平台类库与Profile的关系

    在[Xamarin+Prism小试牛刀:定制跨平台Outlook邮箱应用]中提到过以下错误,不知道大伙还记得不: 无法安装程序包"Microsoft.Identity.Client 1.0. ...

  3. source /etc/profile报错-bash: id:command is not found

    由于误操作导致 source /etc/profile 报错 -bash: id:command is not found 此时,linux下很多命令到不能能用,包括vi ls 等... 可以使用 e ...

  4. 【译】Spring 4 @Profile注解示例

    前言 译文链接:http://websystique.com/spring/spring-profile-example/ 本文将探索Spring中的@Profile注解,可以实现不同环境(开发.测试 ...

  5. Linix登录报"/etc/profile: line 11: syntax error near unexpected token `$'{\r''"

    同事反馈他在一测试服务器(CentOS Linux release 7.2.1511)上修改了/etc/profile文件后,使用source命令不能生效,让我帮忙看看,结果使用SecureCRT一登 ...

  6. Spring profile配置应用

    spring配置文件中可以配置多套不同环境配置,如下: <beans xml.....>     <beans profile="dev">     < ...

  7. 项目实现不同环境不同配置文件-maven profile

    最近接触的项目都是在很多地方都落地的项目,需要支持不同的环境使用不同的配置文件.一直以来都以为是人工的去写不同的配置文件,手动的去修改运用的配置文件.感觉自己还是太low呀.maven的使用的还停留在 ...

  8. 修改/etc/profile和/etc/environment导致图形界面无法登陆的问题

    在使用ubuntu开发时,往往要修改PATH变量,有时会通过修改/etc/profile和/etc/environment来修改默认的PATH变量,但是一旦出错,很容易造成无法登陆进入图形界面的问题. ...

  9. RF Firefox Profile

    默认情况下,robot framework是启动不带任何配置信息的firefox,如果需要启动带有profile的话,增加一个参数即可,如 Open Browser https://aws-qa5.i ...

  10. Linux知识:/root/.bashrc与/etc/profile的异同

    Linux知识:/root/.bashrc与/etc/profile的异同 要搞清bashrc与profile的区别,首先要弄明白什么是交互式shell和非交互式shell,什么是login shel ...

随机推荐

  1. obj-c编程02:给类自动合成存取方法

    我们在此篇对obj-c编程01中的Box的例子稍加改动,一是添加的自动合成存取器,二是将Box按照其标准的写法分成3个文件,即头文件Box.h,类实现文件Box.m,以及主文件test.m. 1.Bo ...

  2. 开发composer包,打通github和packagist,并自动更新

    1. 首先需要本地安装好composer,并配置好环境变量,在命令行输入composer,显示以下信息就表示正常安装 2. 在github对应项目的根目录下进行初始化composer 初始化完成后,就 ...

  3. Emmet之html语法

    一.简写语法 Emmet 用和 CSS 选择器相似的语法来描述元素的嵌套层级关系和属性,实现 HTML/XML/CSS 等代码的智能自动补全. 其通过文件名后缀识别文件类型,从而使用对应的自动补全语法 ...

  4. angularjs学习笔记之一

    directive 通过AngularJS模块API中的.directive()方法,我们可以通过传入一个字符串和一个函数来 注册一个新指令.其中字符串是这个指令的名字,指令名应该是驼峰命名风格的,函 ...

  5. Spring多数据源解决方案

    Figure 2 多数据源的选择逻辑渗透至客户端 解决方案 Figure 3 采用Proxy模式来封转数据源选择逻辑 通过采用Proxy模式我们在方案实现中实现一个虚拟的数据源.并且通过它来封装数据源 ...

  6. JS基础:this的指向以及call、apply的作用

    this 的指向 在具体的实际应用中,this 的指向无法在函数定义时确定,而是在函数执行的时候才确定的,根据执行时的环境大致可以分为以下3种: 1.当函数作为普通函数调用时,this 指向全局对象 ...

  7. 通过slave_exec_mode=IDEMPOTENT跳过主从复制中的错误

    通过slave_exec_mode=IDEMPOTENT跳过主从复制中的错误 set global slave_exec_mode=IDEMPOTENT slave_exec_mode 有两种模式 S ...

  8. Java错误和异常

    Java 异常结构图 在 Java 中,所有的异常都有一个共同的祖先 Throwable(可抛出).Throwable 指定代码中可用异常传播机制通过 Java 应用程序传输的任何问题的共性.  Th ...

  9. Angular集成admin-lte框架

    其实上一篇里面提到的集成datatables.net就是admin-lte里面的一个子插件,不过这个子插件,他是自带types定义文件的,admin-lte这个东西在DefinitelyTyped里面 ...

  10. Go语言开发区块链只需180行代码

    区块链开发用什么语言?通过本文你将使用Go语言开发自己的区块链(或者说用go语言搭建区块链).理解哈希函数是如何保持区块链的完整性.掌握如何用Go语言编程创造并添加新的块.实现多个节点通过竞争生成块. ...