// 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. 如何用Dreamweaver编辑rails的html.erb文件

    默认情况下用dw是以普通的text文件打开html.erb文件,这多少让人有点不爽.其实dw打开erb文件也是相当的容易,下面就简单说下在mac os X下如何让dw支持erb文件: 首先找到dw的用 ...

  2. ruby 2.x.x之新特性散谈

    ruby入门看的是经典的<ruby编程语言>,可是那描述的是v1.9的老版本啊!下面聊一下ruby2.x.x的新特性,x是0-n都有可能啊. 1.关键字参数(Keyword argumen ...

  3. JAVA线程与线程、进程与进程间通信

    I.线程与线程间通信 一.基本概念以及线程与进程之间的区别联系: 关于进程和线程,首先从定义上理解就有所不同1.进程是什么?是具有一定独立功能的程序.它是系统进行资源分配和调度的一个独立单位,重点在系 ...

  4. 超精简易用cocoaPods的安装和使用

    cocoaPods 安装和使用 第一步:替换ruby源 $ gem sources -l                                查看当前ruby的源 $ gem sources ...

  5. java并发包分析之———AQS框架

    一.什么是同步器   多线程并发的执行,之间通过某种 共享 状态来同步,只有当状态满足 xxxx 条件,才能触发线程执行 xxxx . 这个共同的语义可以称之为同步器.可以认为以上所有的锁机制都可以基 ...

  6. 新知识:JQuery语法基础与操作

     jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架).jQuery设计的宗旨是"write ...

  7. neo4j-rest-client使用摘要

    1.使用它的原因,与django搭配的最好的neomodel目前只支持到v2.2,我已给官方发了issue,官方也回复了,马上修改并发布(老外对开源项目的负责态度让人感动) 2.这个库的文档中大概描述 ...

  8. Ruby中如何复制对象 (deep clone)(转载)

    Ruby中如何复制对象 (deep clone) 用Ruby复制一个对象(object)也许没有你想像的那么容易. 今天我google了半天, 做个总结吧. 先从最简单的开始, b = a 是复制吗? ...

  9. C#将一个枚举里面所有描述和value绑定到下拉列表的方法

    /// <summary> /// 获取枚举值的描述,如果没有描述,则返回枚举名称 /// </summary> /// <param name="en&quo ...

  10. Stack和Vector源码分析

    Stack和Vector源码分析 Stack和Vector源码分析stack源码分析1.Stack是什么2.Stack的结构图3.Stack继承关系4.Stack的主要方法5.Stack源码Vecto ...