<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>oneapm (OneAPM - 蓝海讯通)</title>
    <link>https://ruby-china.org/oneapm</link>
    <description>Software makes the world run. OneAPM makes the software run.</description>
    <language>en-us</language>
    <item>
      <title>RubyConf China 2016  盖楼活动获奖公布</title>
      <description>&lt;p&gt;由于盖楼活动和社区的规则有冲突，所以帖子被关进了小黑屋：&lt;a href="https://ruby-china.org/topics/31093" rel="nofollow" target="_blank"&gt;https://ruby-china.org/topics/31093&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;感谢管理员的提醒，下次我们办活动会优化一下规则。也欢迎各位有提供有什么更好地免费赠送的方法，帖子下面留言告诉我们哈～～～～&lt;/p&gt;

&lt;p&gt;当然礼物还是要送的哈！&lt;/p&gt;

&lt;p&gt;下面是获奖名单：&lt;/p&gt;

&lt;p&gt;RUBYCHINA 正版超大熊猫鼠标垫&lt;/p&gt;

&lt;p&gt;8 &lt;a href="/Catherine" class="user-mention" title="@Catherine"&gt;&lt;i&gt;@&lt;/i&gt;Catherine&lt;/a&gt; ；18 &lt;a href="/hongbowang" class="user-mention" title="@hongbowang"&gt;&lt;i&gt;@&lt;/i&gt;hongbowang&lt;/a&gt; ；38 &lt;a href="/duanjs" class="user-mention" title="@duanjs"&gt;&lt;i&gt;@&lt;/i&gt;duanjs&lt;/a&gt;；48 &lt;a href="/xiaoc123" class="user-mention" title="@xiaoc123"&gt;&lt;i&gt;@&lt;/i&gt;xiaoc123&lt;/a&gt; ；58 &lt;a href="/thxagain" class="user-mention" title="@thxagain"&gt;&lt;i&gt;@&lt;/i&gt;thxagain&lt;/a&gt; ；68 &lt;a href="/taohuayuan" class="user-mention" title="@taohuayuan"&gt;&lt;i&gt;@&lt;/i&gt;taohuayuan&lt;/a&gt; ；78 &lt;a href="/anlian" class="user-mention" title="@anlian"&gt;&lt;i&gt;@&lt;/i&gt;anlian&lt;/a&gt; ；88 重复；98 &lt;a href="/qinfanpeng" class="user-mention" title="@qinfanpeng"&gt;&lt;i&gt;@&lt;/i&gt;qinfanpeng&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;请各位填写表单：&lt;a href="https://jinshuju.net/f/ypY2UG" rel="nofollow" target="_blank"&gt;https://jinshuju.net/f/ypY2UG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;——————————————————
RubyConf China 2016 普通票（截止活动结束一共 145 楼）
中奖楼层取整，即如果计算结果出现小数，则舍去小数：
活动截止时总楼层数&lt;em&gt;（ 1/6 ）＝24 &lt;a href="/hasyung" class="user-mention" title="@hasyung"&gt;&lt;i&gt;@&lt;/i&gt;hasyung&lt;/a&gt; 
活动截止时总楼层数&lt;/em&gt;（ 2/6 ）＝48 &lt;a href="/xiao123" class="user-mention" title="@xiao123"&gt;&lt;i&gt;@&lt;/i&gt;xiao123&lt;/a&gt;
活动截止时总楼层数&lt;em&gt;（ 3/6 ）＝72 &lt;a href="/taohuayuan" class="user-mention" title="@taohuayuan"&gt;&lt;i&gt;@&lt;/i&gt;taohuayuan&lt;/a&gt;
活动截止时总楼层数&lt;/em&gt;（ 4/6 ）＝96 &lt;a href="/zkai" class="user-mention" title="@zkai"&gt;&lt;i&gt;@&lt;/i&gt;zkai&lt;/a&gt; 
活动截止时总楼层数*（5/6）＝120 &lt;a href="/drshu" class="user-mention" title="@drshu"&gt;&lt;i&gt;@&lt;/i&gt;drshu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;请填写表单：&lt;a href="https://jinshuju.net/f/ypY2UG" rel="nofollow" target="_blank"&gt;https://jinshuju.net/f/ypY2UG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/xiao123" class="user-mention" title="@xiao123"&gt;&lt;i&gt;@&lt;/i&gt;xiao123&lt;/a&gt; &lt;a href="/taohuayuan" class="user-mention" title="@taohuayuan"&gt;&lt;i&gt;@&lt;/i&gt;taohuayuan&lt;/a&gt; 你们只能要一个奖，看你要鼠标垫还是票哈。&lt;/p&gt;

&lt;p&gt;&lt;a href="/drshu" class="user-mention" title="@drshu"&gt;&lt;i&gt;@&lt;/i&gt;drshu&lt;/a&gt; 你看看，是不是打个飞机回去，哈哈哈。&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Tue, 20 Sep 2016 14:32:02 +0800</pubDate>
      <link>https://ruby-china.org/topics/31103</link>
      <guid>https://ruby-china.org/topics/31103</guid>
    </item>
    <item>
      <title>[北京][海淀西小口] 蓝海讯通 (OneAPM) 诚聘 Ruby 开发工程师一名 [有图有真相]</title>
      <description>&lt;h2 id="公司介绍"&gt;公司介绍&lt;/h2&gt;
&lt;p&gt;OneAPM, 即北京蓝海讯通科技股份有限公司，是中国基础软件 领域的新兴领军企业。专注于提供新一代 ITOM(IT 运维管理) 软件和服务，致力于帮助企业用户降低 IT 成本，提高业务生产力。&lt;/p&gt;

&lt;p&gt;现在，OneAPM 能够为企业级用户提供一站式的 IT 管理解决方案，通过一个探针就可以完成日志分析、安全防护、APM 基础组件监控、集成报警以及大数据分析等多种功能，为企业用户提供全栈式的性能管理以及 IT 运维管理服务。目前，OneAPM 能够提供本地化部署模式和 SaaS 部署模式，支持所有主流编程语言和框架。&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;公司网址：&lt;a href="http://www.oneapm.com" rel="nofollow" target="_blank" title=""&gt;www.oneapm.com&lt;/a&gt; *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;办公地点：海淀东升科技园北领地 A 区 5 号楼 2-4 层（近地铁 8 号线西小口站）&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="职位介绍"&gt;职位介绍&lt;/h2&gt;
&lt;p&gt;职位名称：Ruby 开发工程师
岗位职责：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;使用 Ruby on Rails 开发 Web 应用后台程序。&lt;/li&gt;
&lt;li&gt;设计 Web 应用逻辑，用户鉴权和认证。根据逻辑设计程序模块，类结构，数据结构和数据库结构。&lt;/li&gt;
&lt;li&gt;设计分布式应用以及各模块之间的远程调用。&lt;/li&gt;
&lt;li&gt;设计并部署大型 Web 应用的架构，了解 load balancing, 反向代理，web 服务器，缓存机制以及数据库。&lt;/li&gt;
&lt;li&gt;应用性能分析和优化。&lt;/li&gt;
&lt;li&gt;大规模文件系统的设计。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;任职要求：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;精通 Ruby，2 年以上 Ruby On Rails 经验.4 年以上互联网应用开发经验。&lt;/li&gt;
&lt;li&gt;精通 HTML，CSS，JSP，Ajax，JS 等 Web 应用开发技术。&lt;/li&gt;
&lt;li&gt;精通社交网站的设计与实现，精通 Ruby 远程调用技术和数据库编程。&lt;/li&gt;
&lt;li&gt;了解大型 Web 应用程序系统架构，包括负载均衡器，反向代理，Web 服务器，RoR 服务器，数据库，memcached 等技术。&lt;/li&gt;
&lt;li&gt;了解 Linux 文件系统优先。&lt;/li&gt;
&lt;li&gt;了解或者精通 Git 优先。&lt;/li&gt;
&lt;li&gt;熟悉 Linux 操作系统基本原理，熟悉各种系统调用优先。&lt;/li&gt;
&lt;li&gt;熟悉 c/c++，java 一门语言者优先。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="福利待遇"&gt;福利待遇&lt;/h2&gt;
&lt;p&gt;薪资 15k－20k，5 个月基数的季度奖金，技术特别牛的薪资可谈，五险一金＋补充医疗保险，十天年假，每月一天带薪病假。
免费下午茶，各种兴趣小组（台球、羽毛球、跑团……）&lt;/p&gt;
&lt;h2 id="收简历邮箱：wangjiale@oneapm.com（请在标题注明应聘职位）"&gt;收简历邮箱：wangjiale@oneapm.com（请在标题注明应聘职位）&lt;/h2&gt;&lt;h2 id="我们有丰富多彩的员工活动"&gt;我们有丰富多彩的员工活动&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;各类兴趣小组，每周都会组织活动，公司提供经费的哦～&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/76a7aef6d6ce1a3db33c8008f41a7d73.jpg" title="" alt=""&gt;
&lt;strong&gt;偶尔会组织有意思的小游戏哦&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/0c7adf02325cb4177726170caaf0ed1a.jpg" title="" alt=""&gt;
&lt;strong&gt;星座生日会，帮你找到同星座的小伙伴，金牛座吃烤串，双子座大披萨，接下来是什么？敬请期待……&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/dccf9637860cf0d43a73165b59e45e86.jpg" title="" alt=""&gt;
&lt;strong&gt;每季度对于特殊贡献的小伙伴们，我们都有各种奖励哦&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/4fd23d4339bc808b7c84e498c1701ab3.jpg" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="办公环境"&gt;办公环境&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;公司处在环境优美的东升科技园北领地内，工作累的时候你可以到园区溜达溜达，喂喂鱼，喂喂鸭子&lt;/strong&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/daf340d0db88e1c51fea0aa27eff4cfe.jpg" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Mon, 20 Jun 2016 17:12:02 +0800</pubDate>
      <link>https://ruby-china.org/topics/30326</link>
      <guid>https://ruby-china.org/topics/30326</guid>
    </item>
    <item>
      <title>[年末福利] 部署 Cloud Insight，拿京东购物卡</title>
      <description>&lt;h4 id="做运维最经常经历的是什么？加班！"&gt;做运维最经常经历的是什么？加班！&lt;/h4&gt;&lt;h4 id="做运维最讨厌的一件事是什么？加班！！"&gt;做运维最讨厌的一件事是什么？加班！！&lt;/h4&gt;&lt;h4 id="做运维跟对象吵架最多的原因是什么？加班！！！"&gt;做运维跟对象吵架最多的原因是什么？加班！！！&lt;/h4&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2016/00a0b3b86748c980361c4dce37cb17f3.jpg" title="" alt=""&gt;
&lt;strong&gt;没关系，快过年了，OneAPM 来发点福利。&lt;/strong&gt;
&lt;strong&gt;&lt;em&gt;部署试用 &lt;a href="http://www.oneapm.com/ci/feature.html?utm_source=RubyChina&amp;amp;utm_medium=Activity&amp;amp;utm_term=%5B%E5%B9%B4%E6%9C%AB%E7%A6%8F%E5%88%A9%5D%E9%83%A8%E7%BD%B2%20Cloud%20Insight%EF%BC%8C%E6%8B%BF%E4%BA%AC%E4%B8%9C%E8%B4%AD%E7%89%A9%E5%8D%A1&amp;amp;utm_campaign=CiActivity&amp;amp;from=maacmjdq" rel="nofollow" target="_blank" title=""&gt;Cloud Insight&lt;/a&gt; ——也称 Ci，领取京东购物卡！&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="参与方法"&gt;参与方法&lt;/h2&gt;
&lt;p&gt;符合以下要求的 Cloud Insight 新注册用户将获得 &lt;strong&gt;100 - 200 元京东购物卡&lt;/strong&gt;，名额暂定 30 人，&lt;em&gt;机会多多，送完为止&lt;/em&gt;。&lt;/p&gt;
&lt;h4 id="活动一："&gt;活动一：&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://user.oneapm.com/account/register.do?from=ci?utm_source=RubyChina&amp;amp;utm_medium=Activity&amp;amp;utm_term=%5B%E5%B9%B4%E6%9C%AB%E7%A6%8F%E5%88%A9%5D%E9%83%A8%E7%BD%B2%20Cloud%20Insight%EF%BC%8C%E6%8B%BF%E4%BA%AC%E4%B8%9C%E8%B4%AD%E7%89%A9%E5%8D%A1&amp;amp;utm_campaign=CiActivity&amp;amp;from=maacmjdq" rel="nofollow" target="_blank" title=""&gt;点此注册&lt;/a&gt; OneAPM，部署试用 Ci 并回复此帖贴上带数据截图及试用感想（300 字以上），例如：
&lt;img src="https://l.ruby-china.com/photo/2016/4ef6430c0aecf0315073cc9161e9eb3c.png" title="" alt=""&gt;
&lt;em&gt;“Cloud Insight 数据比较全，就是之前接触不深很多指标不太懂。”&lt;/em&gt;&lt;/p&gt;
&lt;h4 id="活动二："&gt;活动二：&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://user.oneapm.com/account/register.do?from=ci?utm_source=RubyChina&amp;amp;utm_medium=Activity&amp;amp;utm_term=%5B%E5%B9%B4%E6%9C%AB%E7%A6%8F%E5%88%A9%5D%E9%83%A8%E7%BD%B2%20Cloud%20Insight%EF%BC%8C%E6%8B%BF%E4%BA%AC%E4%B8%9C%E8%B4%AD%E7%89%A9%E5%8D%A1&amp;amp;utm_campaign=CiActivity&amp;amp;from=maacmjdq" rel="nofollow" target="_blank" title=""&gt;点此注册&lt;/a&gt; OneAPM，部署并深度试用 Ci 并将带数据截图及 1000 字以上使用体验（吐槽、夸奖、建议均可）发送至邮箱：zhanglu@oneapm.com&lt;/p&gt;
&lt;h2 id="安装简单"&gt;安装简单&lt;/h2&gt;
&lt;p&gt;不用担心！安装只需要&lt;strong&gt;一条指令&lt;/strong&gt;，简单易懂！（实在不懂也可&lt;a href="http://www.oneapm.com/docs/ci/started/index.html" rel="nofollow" target="_blank" title=""&gt;参考文档&lt;/a&gt;）
&lt;img src="https://l.ruby-china.com/photo/2016/1da42507e9c90c47053584aa43318c53.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="除此之外，我们还要安利一下这款 高质量、有态度 的监控产品：Cloud Insight。"&gt;除此之外，我们还要安利一下这款 &lt;strong&gt;&lt;em&gt;高质量、有态度&lt;/em&gt;&lt;/strong&gt; 的监控产品：Cloud Insight。&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;旨在实现高效运维和协作，让运维人新的一年不再频繁加班！&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;解决集群监控、云监控难题&lt;/li&gt;
&lt;li&gt;资源不足的中小型创业公司也能拥有高效运维体验&lt;/li&gt;
&lt;li&gt;支持包括 Docker 在内的多种操作系统、云主机、数据库、中间件等的监控&lt;/li&gt;
&lt;li&gt;首款 DevOps+ChatOps 监控产品，集合报警功能，完美的事件流展现
&lt;img src="https://l.ruby-china.com/photo/2016/9013e16da919753e1dea0df3b13678c5.jpg" title="" alt=""&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="次时代监控产品——Cloud Insight"&gt;次时代监控产品——Cloud Insight&lt;/h3&gt;
&lt;p&gt;Cloud Insight 将所有性能指标作为时间序列数据来处理，提供对数据的聚合、过滤、分组、计算；方便运维人员来聚合不同主机的数据，发现数据之间的关系，以及组合出满足自身业务的抽象性能指标。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;一张图路转粉系列&lt;/em&gt;
&lt;img src="https://l.ruby-china.com/photo/2016/3c56eab49363b99a3a93f2f2c4791bee.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="Tips"&gt;Tips&lt;/h3&gt;
&lt;p&gt;1.活动时间：1.15 日 13:00 至 1.31 日 13:00
2.领卡机制：
   参与活动一可获百元京东购物卡一张。
   参与活动二可获百元京东购物卡两张。
   活动一、二不可同时参加，且参加活动一、活动二的同时，请转发本活动至朋友圈或者技术群，并提交转发截图。
3.我们会在收到帖子或邮件后，五个工作日内赠送购物卡。&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Fri, 15 Jan 2016 11:53:50 +0800</pubDate>
      <link>https://ruby-china.org/topics/28740</link>
      <guid>https://ruby-china.org/topics/28740</guid>
    </item>
    <item>
      <title>OneAPM ｜到底神秘数字是什么？# 激动人心的开奖时间来啦～</title>
      <description>&lt;p&gt;铛！(￣︶￣)/
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
铛！(￢∀￢)
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
铛！ ┬─┬ノ ( º _ ºノ)
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
铛！ (╯' - ')╯ ┻━┻
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
｜
o(*≧▽≦) ツ┏━┓
&lt;img src="https://l.ruby-china.com/photo/2015/5d8072a3fb20ef19e5eb1fd70db3ce32.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这里插入一条硬广：&lt;/p&gt;
&lt;h2 id="坑爹的后端架构优化需求？加班！没时间陪女朋友？自己搭建开源监控平台？"&gt;坑爹的后端架构优化需求？加班！没时间陪女朋友？自己搭建开源监控平台？&lt;/h2&gt;&lt;h2 id="OneAPM，您身边的性能监控专家：立即获取性能监控神器"&gt;OneAPM，您身边的性能监控专家：&lt;a href="http://www.oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Activity&amp;amp;utm_term=shaung&amp;amp;utm_campaign=OtcActivity&amp;amp;from=maacocrc" rel="nofollow" target="_blank" title=""&gt;立即获取性能监控神器&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;双十一在即，Ruby China 创立四周年了，而我司 Ruby 产品的日活也达到了一个有纪念意义的数值。
这样一个&lt;strong&gt;三喜临门&lt;/strong&gt;的时间节点，我们当然要 &lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt; &lt;img title=":gift:" alt="🎁" src="https://twemoji.ruby-china.com/2/svg/1f381.svg" class="twemoji"&gt; &lt;img title=":dancers:" alt="👯" src="https://twemoji.ruby-china.com/2/svg/1f46f.svg" class="twemoji"&gt; &lt;strong&gt;回馈用户 !&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;晒出你购物车最想买的一件或几件东西！！！并附一句想对 OneAPM 说的话，比男/女朋友更贴心的 OneAPM 来帮你&lt;/p&gt;
&lt;h3 id="清 空 购 物 车 ！"&gt;&lt;em&gt;清 空 购 物 车！&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;我们将在 2015.11.10 12:00 选出一名幸运用户，帮你购买想要的商品。
抽奖方法：我们已经将一个神秘数字以图片形式私密上传到某论坛，数值范围（0-1000）。
所贴购物车商品总价值最接近神秘数字的朋友，就是幸运用户！&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Wed, 28 Oct 2015 17:12:25 +0800</pubDate>
      <link>https://ruby-china.org/topics/27871</link>
      <guid>https://ruby-china.org/topics/27871</guid>
    </item>
    <item>
      <title>DIY Ruby CPU 分析 [更新到 Part IV]</title>
      <description>&lt;p&gt;&lt;strong&gt;【编者按】原文作者 Emil Soman，Rubyist，除此之外竟然同时也是&lt;/strong&gt;&lt;em&gt;艺术家，吉他手&lt;/em&gt;&lt;strong&gt;，Garden City RubyConf 组织者。本文是 DIY Ruby CPU Profiling 的第一部分，由 &lt;a href="http://www.oneapm.com/index.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=rubyCpu1&amp;amp;utm_campaign=SeptArti&amp;amp;from=matefisporo" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 工程师编译整理。&lt;/strong&gt;
&lt;strong&gt;原文链接：&lt;a href="http://crypt.codemancers.com/posts/2015-03-12-diy-ruby-cpu-profiling-part-ii/" rel="nofollow" target="_blank" title=""&gt;http://crypt.codemancers.com/posts/2015-03-12-diy-ruby-cpu-profiling-part-ii/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://news.oneapm.com/content/images/2015/09/1-4.jpg" title="" alt="alt"&gt;
在 Codemancers，我们正在建设 Rbkit——一个针对 Ruby 语言的——拥有新炫酷功能的代码分析器。我目前正在实现一个嵌在 rbkit gem 里的 CPU 分析器，这将有助 rbkit UI 重建分析 Ruby 进程调用图，并在屏幕上得出有用的可视化展示。在这个过程中，我学到了许多新东西，很乐意在本系列的博客文章中与您分享。&lt;/p&gt;

&lt;p&gt;我们打算一步一步从基础开始，专门为 Ruby 编写一个初级的 CPU 分析器！在完成时我们将学到：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;什么是 CPU 分析&lt;/li&gt;
&lt;li&gt;分析模式——工具和采样&lt;/li&gt;
&lt;li&gt;CPU Time 和 Wall Time ——它们分别是什么意思，如何测量？&lt;/li&gt;
&lt;li&gt;写一个简单的 C 扩展并用于 Ruby 中&lt;/li&gt;
&lt;li&gt;Ruby Tracepoints——调用和返回&lt;/li&gt;
&lt;li&gt;C 语言中的信号处理&lt;/li&gt;
&lt;li&gt;用一个信号暂停 Ruby 进程并用调用堆查看&lt;/li&gt;
&lt;li&gt;用分析数据进行一些有用但笨拙的试验&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Part I. 介绍 CPU 分析"&gt;Part I. 介绍 CPU 分析&lt;/h3&gt;
&lt;p&gt;通过对你的程序进行 CPU 分析，可以发现相较于 CPU 使用率，你的程序是多么宝贵。为了分析程序，你需要使用一个分析工具并按照下列步骤操作：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;开始 CPU 剖析&lt;/li&gt;
&lt;li&gt;执行你想要分析的代码&lt;/li&gt;
&lt;li&gt;停止 CPU 剖析并得到剖析结果&lt;/li&gt;
&lt;li&gt;分析结果&lt;/li&gt;
&lt;li&gt;通过分析剖析结果，你会发现使整个程序缓慢的瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="分析模式"&gt;分析模式&lt;/h4&gt;
&lt;p&gt;CPU 剖析可以分为以下两种方法：&lt;/p&gt;
&lt;h4 id="1. 工具"&gt;1. 工具&lt;/h4&gt;
&lt;p&gt;在这种模式下，分析工具利用一些 hooks，由解释器提供或者插入程序中，来了解调用图并测量在调用图中每个方法的执行时间。举个例子，看一下下面这段 Ruby 代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_many_square_roots&lt;/span&gt;
    &lt;span class="n"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_square_roots&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我已经插入了一些内容，来帮助了解如果 Ruby 解释器给了我们方法的调用和返回的 hooks，它们如何执行：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="c1"&gt;# method call hook gets executed&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_many_square_roots&lt;/span&gt;
    &lt;span class="n"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="c1"&gt;# method end hook gets executed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_square_roots&lt;/span&gt;
  &lt;span class="c1"&gt;# method call hook gets executed&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="c1"&gt;# method end hook gets executed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="c1"&gt;# method call hook gets executed&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# method end hook gets executed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在，如果我们能够打印出当前时间和这些 hooks 内部当前方法的名称，会得到看起来像这种形式的输出结果：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sec:00 usec:201007  called      main
sec:00 usec:201108  called      find_many_square_roots
sec:00 usec:692123  returned    find_many_square_roots
sec:00 usec:692178  called      find_many_squares
sec:00 usec:846540  returned    find_many_squares
sec:00 usec:846594  called      find_many_square_roots
sec:01 usec:336166  returned    find_many_square_roots
sec:01 usec:336215  called      find_many_squares
sec:01 usec:484880  returned    find_many_squares
sec:01 usec:484945  called      find_many_square_roots
sec:01 usec:959254  returned    find_many_square_roots
sec:01 usec:959315  called      find_many_squares
sec:02 usec:106474  returned    find_many_squares
sec:02 usec:106526  returned    main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正如你所看到的，此输出可以告诉我们在每一种方法里面花了多长时间。同时也告诉我们，每一个方法调用的次数。这大概就解释了性能分析工具是如何工作的。&lt;/p&gt;
&lt;h6 id="优点："&gt;优点：&lt;/h6&gt;
&lt;p&gt;高精度
我们得到了方法调用数
易于实施&lt;/p&gt;
&lt;h6 id="缺点："&gt;缺点：&lt;/h6&gt;
&lt;p&gt;每个被分析的方法执行 hooks 时的额外开销&lt;/p&gt;
&lt;h4 id="2. 采样"&gt;2. 采样&lt;/h4&gt;
&lt;p&gt;在采样模式下，分析器每隔 x 时间单元打断一次程序，并查看调用堆并记录它的信息（被称为“样品”）。一旦该程序完成运行，分析器收集所有样品并找出每个方法出现在所有样品中的次数。
很难想象？让我们来看看同样的例子代码，看看如果我们使用采样分析器，输出结果会有怎样的不同。
采样分析器的输出结果如下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call stack at 0.5sec: main/find_many_square_roots
Call stack at 1.0sec: main/find_many_square_roots
Call stack at 1.5sec: main/find_many_square_roots
Call stack at 2.0sec: main/find_many_squares
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，程序每 0.5 秒被中断一次并且调用堆栈被记录。因此，通过这个程序执行的过程我们得到了 4 个样品，&lt;code&gt;find_many_square_roots&lt;/code&gt; 记录于 3 个样品中， &lt;code&gt;find_many_squares&lt;/code&gt; 只存在于一个样品中。从本次采样中，我们得到 &lt;code&gt;find_many_square_roots&lt;/code&gt; 占用了 75％ CPU，与此同时 &lt;code&gt;find_many_squares&lt;/code&gt; 只占用了 25％ 的 CPU。这就大概解释了分析器是怎么样工作的。&lt;/p&gt;
&lt;h6 id="优点："&gt;优点：&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;与工具分析相比开销可忽略不计&lt;/li&gt;
&lt;li&gt;很容易找到缓慢/长时间运行的方法&lt;/li&gt;
&lt;/ul&gt;
&lt;h6 id="缺点："&gt;缺点：&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;不擅长测量短时间运行的方法&lt;/li&gt;
&lt;li&gt;我们没有得到方法调用数&lt;/li&gt;
&lt;li&gt;很难自己写出采样分析器&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="概括"&gt;概括&lt;/h4&gt;
&lt;p&gt;我们只是调查了 CPU 分析的含义和两种常用的 CPU 分析方法。在第 2 部分，我们将探讨对描述 CPU 使用情况的 2 个单位进行测量—— CPU Time 和 Wall Time。我们也会亲手写一些代码来获取进行测量。感谢您的阅读！&lt;/p&gt;

&lt;p&gt;========================================装  订  线  内  不  准  写  字=============================================&lt;/p&gt;

&lt;p&gt;在第一部分中我们学习了 CPU 分析的含义和进行 CPU 分析的两种方法，在这一部分我们将研究 CPU time 和 Wall time，这些部分总被用来测量执行开销。我们也会写一些实现这些测量方法的代码作为建立 CPU 分析的第一步。&lt;/p&gt;
&lt;h2 id="Part II. CPU time 和 Wall time"&gt;Part II. CPU time 和 Wall time&lt;/h2&gt;&lt;h3 id="Wall time"&gt;Wall time&lt;/h3&gt;
&lt;p&gt;Wall time 是在一个方法被调用和返回之间的真实时间。因此，如果你想要测量一个方法执行的「Wall clock time」，理论上可以用秒表来测量。只要在方法开始执行时打开秒表，在方法返回时按下停止。这个时间通常也被称为真实时间。&lt;/p&gt;

&lt;p&gt;关于 Wall time 很重要的一点是，可以预见，每次试图测量同一段代码可能得到不同的结果。这是因为一系列后台进程会影响 Wall time. 当 CPU 同时运行多个进程的时候，操作系统给同时运行的进程排期并且试图为它们公平的分配 CPU 空间。这意味着 CPU 花费的总时间被分成多个片而我们的方法只占用其中的一些时间片。因此，当 Wall clock 开始计时，我们的进程可能会闲置并且为并行运行的其他进程让路。这意味着花费在其他进程的时间将增加我们的 Wall time!&lt;/p&gt;
&lt;h3 id="CPU time"&gt;CPU time&lt;/h3&gt;
&lt;p&gt;CPU time 是指 CPU 执行方法的时间。CPU time 的度量单位是用于执行方法的 CPU 时钟周期。如果我们了解 CPU 频率，它的单位是周期每秒，也可以称作赫兹，那么我们可以将其转换为时间。如果 CPU 执行某一方法花了 x 个时钟周期，这个 CPU 频率是 y 赫兹，那么 CPU 执行方法的时间为 x/y 秒。有时操作系统会为我们自动进行转换从而使我们免于进行这种计算。
CPU 时间不等同于 Wall time，其中的差别在于方法的指令类型。我们可以宽泛的将指令分为两种类型：CPU 密集型 和 I/O 密集型。在执行 I/O 指令时，CPU 空闲下来可以转去执行其他 CPU 密集型指令。因此，如果我们的方法在 I/O 指令上花费时间，CPU 可以不把时间投入在该方法上，而是去处理其他事情，直到 I/O 操作完成。这段时间内 Wall time 在计时而 CPU time 停止计时，落后于 Wall time.&lt;/p&gt;

&lt;p&gt;我们来看看一个需要 5 分钟来执行的慢方法的情况。如果想知道这个方法花费了多长时间，你的 Wall clock 可以显示「执行该方法需要五分钟」，但 CPU 会显示「执行该方法中用时 3 分钟」。所以应该听从哪一个说法呢？究竟哪个时间能够更准确的测量执行方法的时间？&lt;/p&gt;

&lt;p&gt;答案是：看情况。这取决于你希望测量的方法的类型。如果该方法的大部分时间用于 I/O 操作，或者该方法没有直接处理 CPU 密集型指令，由 CPU time 描述的时间开销将十分不准确。对于这些类型的方法，通过 Wall time 来测量时间更加合适。而对于其他情况，坚持通过 CPU time 来测量是很可靠的。&lt;/p&gt;
&lt;h3 id="测量 CPU time 和 Wall time"&gt;测量 CPU time 和 Wall time&lt;/h3&gt;
&lt;p&gt;鉴于想要写一个 CPU 分析器，我们需要一种测量 CPU time 和 Wall time 的方法。下面来看一看已经能够测量这两项的 Ruby 的 Benchmark module 中的代码。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;measure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# :yield:&lt;/span&gt;
  &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BENCHMARK_CLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt;
  &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;BENCHMARK_CLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;Benchmark&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Tms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utime&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stime&lt;/span&gt;  &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cutime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cutime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cstime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cstime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;r1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由此可见，Ruby 通过两种进程类中的方法来测量时间：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;通过&lt;code&gt;times&lt;/code&gt;测量 CPU time.&lt;/li&gt;
&lt;li&gt;通过&lt;code&gt;clock_gettime&lt;/code&gt;来测量真实时间，也就是 Wall time.
但是&lt;code&gt;times&lt;/code&gt;方法返回的结果为 1 秒，这表示通过分析器用&lt;code&gt;times&lt;/code&gt;只能测量仅需要几秒就能完成的 方法的 CPU time. 然而&lt;code&gt;clock_gettime&lt;/code&gt;就有趣多了。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="clock_gettime"&gt;clock_gettime&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Process::clock_gettime&lt;/code&gt;是早在 Ruby 2.1 版本就已经被添加的方法，它使用 POSIX &lt;code&gt;clock_gettime()&lt;/code&gt;功能并回退到 OS 仿真来获得时间以防&lt;code&gt;clock_gettime&lt;/code&gt;在 OS 中失效或无法实施。该功能接受&lt;code&gt;clock_id&lt;/code&gt;及时间结果作为参数。有很多可以被选为这种计时器的&lt;code&gt;clock_ids&lt;/code&gt;，但我们感兴趣的是：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;CLOCK_MONOTONIC&lt;/code&gt;: 这个计时器测量逃走的 Wall clock time，因为过去的任意时间点不会被系统时钟的变化影响，最适合测量 Wall time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CLOCK_PROCESS_CUPTIME_ID&lt;/code&gt;: 这个计时器测量每一个进程的 CPU time，意即计算进程中所有线程的时间。我们可以用它来测量 CPU time.
让我们利用这个来写一些代码：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DiyProf&lt;/span&gt;
  &lt;span class="c1"&gt;# These methods make use of `clock_gettime` method introduced in Ruby 2.1&lt;/span&gt;
  &lt;span class="c1"&gt;# to measure CPU time and Wall clock time.&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cpu_time&lt;/span&gt;
    &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CLOCK_PROCESS_CPUTIME_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:microsecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wall_time&lt;/span&gt;
    &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CLOCK_MONOTONIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:microsecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以在 benchmark 代码中使用这些方法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"****CPU Bound****"&lt;/span&gt;
&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wall_time&lt;/span&gt;
&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wall_time&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"CPU time&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Wall time&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;w1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;****IO Bound****"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'tempfile'&lt;/span&gt;

&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wall_time&lt;/span&gt;
&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="no"&gt;Tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'file'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cpu_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;wall_time&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"CPU time&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Wall time&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s2"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;w2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;w1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行这些代码会得出类似以下的结果：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;****CPU Bound****
CPU time    =   5038
Wall time   =   5142

****IO Bound****
CPU time    =   337898
Wall time   =   475864
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些清楚地展现了单个 CPU 内核的情况，在仅运行 CPU 密集型指令时 CPU time 和 Wall time 几乎相等，而运行 I/O 密集型指令时 CPU time 总是少于 Wall time.&lt;/p&gt;
&lt;h3 id="概括"&gt;概括&lt;/h3&gt;
&lt;p&gt;我们学习了 CPU time 和 Wall time 的含义与差异，以及什么时候用哪种。与此同时，写了一些 Ruby 代码来测量 CPU time 和 Wall time 来为我们做的 CPU 分析器测量时间。在第三部分我们将讨论 Ruby TracePoint API 并利用它做一个仪表分析器。&lt;/p&gt;

&lt;p&gt;========================================装  订  线  内  不  准  写  字=============================================&lt;/p&gt;

&lt;p&gt;在第一部分我们了解到仪表分析器如何工作，在第二部分我们学习到如何使用 CPU time 和 Wall time 测量执行时间。建议在继续学习之前先阅读一下那些内容。本章我们将应用学到的目前为止知识做一个很基础的仪表 CPU 分析器。&lt;/p&gt;
&lt;h3 id="Part III. DIY 仪表 CPU 分析器"&gt;Part III. DIY 仪表 CPU 分析器&lt;/h3&gt;&lt;h5 id="Ruby 的仪表盘"&gt;Ruby 的仪表盘&lt;/h5&gt;
&lt;p&gt;在第一部分，我们学到了仪表分析工具利用能够被分析工具安装或由语言自身提供的 hooks 来工作。幸运的是，Ruby 早就拥有这些 hooks 并且提供纤巧的&lt;code&gt;TracePoint&lt;/code&gt;类来使用这些 hooks。 &lt;/p&gt;
&lt;h5 id="TracePoint API"&gt;TracePoint API&lt;/h5&gt;
&lt;p&gt;执行代码时，Ruby VM 发送一系列事件到不同的节点。Ruby 允许利用&lt;code&gt;TracePoint&lt;/code&gt;类进行事件回调。&lt;code&gt;TracePoint&lt;/code&gt;的 API 文档列出了所有可以监听的事件，但我们只对下面两个感兴趣：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;：call&lt;/code&gt;,当 Ruby 方法调用时被触发。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;:return&lt;/code&gt;, 当 Ruby 方法返回时被触发。
我们可以通过&lt;code&gt;TracePoint.new&lt;/code&gt;方法创造 tracepoint 对象并传递一个事件类型进行监听，同时传递部分在事件触发时执行的代码。下面是为&lt;code&gt;:call&lt;/code&gt;和&lt;code&gt;：return&lt;/code&gt;事件创造 tracepoint 的代码。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:return&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Method: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, event: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;被传到回调代码块的参数&lt;code&gt;trace&lt;/code&gt;使你能够访问一系列 tracepoint 的属性，通过它们更加了解被触发的事件。举个例子，我们需要通过&lt;code&gt;method_id&lt;/code&gt;属性得到 method name，通过&lt;code&gt;event&lt;/code&gt;属性得到被触发的事件名。上文提到的回调代码块中将显示出方法名和被触发的事件类型，每一次都会伴随着 Ruby 方法的调用或返回。
建立 tracepoint 之后，需要将其变成可用状态： &lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一旦 tracepoint 变成可用状态，我们便可以创建方法对它进行调用，并且看我们出发的回调命令是否被执行。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;hello&lt;/span&gt;

&lt;span class="c1"&gt;#=&amp;gt; Method: hello, event: call&lt;/span&gt;
&lt;span class="c1"&gt;#=&amp;gt; Method: hello, event: return&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不错，我们的回调命令如预期的一样被执行了两次。&lt;/p&gt;
&lt;h5 id="diy_prof gem"&gt;diy_prof gem&lt;/h5&gt;
&lt;p&gt;最后我们将结合之前学过的东西创造一个 RubyGem，并将这个 gem 命名为 diy_prof. 关于此 gem 的资源放在 &lt;a href="https://github.com/emilsoman/diy_prof" rel="nofollow" target="_blank" title=""&gt;github&lt;/a&gt; 上。
现在我们就用 bundler 来建造这个 gem：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="n"&gt;diy_prof&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就造出了我们将要做的项目的骨架。接着，我们将建立在 Part II 中介绍过的包含&lt;code&gt;cpu_time&lt;/code&gt;和&lt;code&gt;wall_time&lt;/code&gt;方法的 &lt;code&gt;TimeHelpers&lt;/code&gt;模块：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/diy_prof/time_helpers.rb&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DiyProf::TimeHelpers&lt;/span&gt;
  &lt;span class="c1"&gt;# These methods make use of `clock_gettime` method introduced in Ruby 2.1&lt;/span&gt;
  &lt;span class="c1"&gt;# to measure CPU time and Wall clock time.&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;cpu_time&lt;/span&gt;
    &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CLOCK_PROCESS_CPUTIME_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:microsecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wall_time&lt;/span&gt;
    &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clock_gettime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CLOCK_MONOTONIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:microsecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们还需要请求 gem 主文件中的这个文件&lt;code&gt;lib/diy_prof.rb&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/diy_prof.rb&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'diy_prof/version'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'diy_prof/time_helpers'&lt;/span&gt;
&lt;span class="c1"&gt;# Rest of the original file ..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下一步，当一个&lt;code&gt;:call&lt;/code&gt;或&lt;code&gt;return&lt;/code&gt;事件发生时，我们将通过 gem 里的 TracePoint API 来显示时间。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DiyProf&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tracer&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TimeHelpers&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;clock_type: :cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@tracepoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:return&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clock_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:wall&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;wall_time&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cpu_time&lt;/span&gt;
        &lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"%-20s:%-20s%-20s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;enable&lt;/span&gt;
      &lt;span class="vi"&gt;@tracepoint.enable&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;disable&lt;/span&gt;
      &lt;span class="vi"&gt;@tracepoint.disable&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同时，我们需要再一次调用这个 gem 主文件中的文件：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/diy_prof.rb&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'diy_prof/version'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'diy_prof/time_helpers'&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'diy_prof/tracer'&lt;/span&gt;
&lt;span class="c1"&gt;# Rest of the original file ..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在，让我们来写一个例子脚本来测试至今为止创造了什么。我们将使用在 Part I 中见过的那个例子：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# examples/demo.rb&lt;/span&gt;

&lt;span class="vg"&gt;$:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;"../lib"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'diy_prof'&lt;/span&gt;

&lt;span class="c1"&gt;### Begin sample program ###&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_many_square_roots&lt;/span&gt;
    &lt;span class="n"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_square_roots&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="c1"&gt;### End sample program ###&lt;/span&gt;

&lt;span class="n"&gt;tracer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;clock_type: :cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="n"&gt;tracer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果运行了以上 Ruby 程序，我们将得到下列结果：
&lt;img src="https://l.ruby-china.com/photo/2015/17bba4d79581b233279d996e72e57f33.png" title="" alt=""&gt;
第一列显示的是被触发事件的 CPU time，第二列是被触发的事件名，第三列是被调用或返回的方法名。这个结果与在 Part I 中学习仪表分析器如何工作时看到的结果很相似。可以看到，我们能够轻松地通过这个结果重建调用，因为我们可以知道各个方法间的调用关系。写一个能解析这个结果并按执行时间有序显示方法列的脚本并不是很难。但这太无聊了，我们可以建造更有趣的东西。看着吧，下一部分将学习我们能够利用这些数据来做的其他事情。&lt;/p&gt;
&lt;h5 id="概括"&gt;概括&lt;/h5&gt;
&lt;p&gt;我们学习了 Ruby 的 TracePoint API 以及如何用它监听方法的调用和返回。同时我们整合写过的代码建立了一个能够显示 Ruby 程序的执行 trace 的 gem。在第四部分我们将学习如何有效利用 gem 收集到的数据并通过它们创造一些很酷的调用图。感谢阅读！如果你想要阅读 DIY CPU 分析系列的其他最新文章，请关注我们的 twitter &lt;a href="/codemancershq." class="user-mention" title="@codemancershq."&gt;&lt;i&gt;@&lt;/i&gt;codemancershq.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;========================================装  订  线  内  不  准  写  字=============================================&lt;/p&gt;

&lt;p&gt;在第一部分我们了解了 CPU 分析器是如何工作的，在第二部分我们学习了如何通过 CPU time 和 Wall time 测量程序的执行时间，在第三部分我们学习了如何用 Ruby 的 TracePoint API 来跟踪 Ruby VM 中的方法调用和返回。我们还着手建立了自己的 DiyProf gem. 建议在继续之前先阅读这些。在这部分我们将利用通过 TracePoint API 收集到的数据创造一个简单的可视化调用图。&lt;/p&gt;
&lt;h3 id="Part IV. 调用图"&gt;Part IV. 调用图&lt;/h3&gt;
&lt;p&gt;在第三部分，我们通过 Ruby 的 TracePoint API 来展示方法的调用和返回 trace. 如果可以解析这些 trace 并通过它们制作调用图，应该会更有用。调用图是用一种树形图来代表方法调用，进行基本的可视化。就像下图：
&lt;img src="https://l.ruby-china.com/photo/2015/101ae75c23533fd5ecd5b1cd9a874523.png" title="" alt=""&gt;
上图告诉我们&lt;code&gt;other_method&lt;/code&gt;从&lt;code&gt;inner_method{1，2，3}&lt;/code&gt;中调用了三个方法，而&lt;code&gt;inner_method_3&lt;/code&gt;调用了另一个名为&lt;code&gt;inner_most_method&lt;/code&gt;的方法。&lt;/p&gt;
&lt;h5 id="Graphviz 和 DOT 语言"&gt;Graphviz 和 DOT 语言&lt;/h5&gt;
&lt;p&gt;Graphviz 是一种图形可视化工具，可以生成文本格式的图形说明，并生成 PDF 等多种格式的图表。为了用文本格式描述图形，Graphviz 使用一种名为 DOT 的语言，通过简单的声明描述节点和节点之间的关系。
在继续之前，先确保安装了 Graphviz 且 dot 命令在 $PATH 中可用。遵循安装步骤的官方文件即可。
举个例子，&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;digraph&lt;/span&gt; &lt;span class="n"&gt;graph_name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存上述几条作为一个样本，dot 并运行下列命令。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="no"&gt;Tpdf&lt;/span&gt; &lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述命令将会生成一个直观的图，如下所示：
&lt;img src="https://l.ruby-china.com/photo/2015/8e97d241e5ce1a2761043f4da7dc0628.png" title="" alt=""&gt;
还有另一种代表图的方法，通过分离节点和关系，如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;digraph&lt;/span&gt; &lt;span class="n"&gt;graph_name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;connections&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因此下列 DOT 符号代表同样的图：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;digraph&lt;/span&gt; &lt;span class="n"&gt;graph_name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还可以为节点和关系添加附加标签。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;digraph&lt;/span&gt; &lt;span class="n"&gt;graph_name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"a &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt; foo: bar"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"b &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt; foo: baz"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"xyz"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上述 DOT 代码代表下图：
&lt;img src="https://l.ruby-china.com/photo/2015/cbf68a61fe0a837547d1a6507b7c58b1.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h5 id="Graphviz 调用图"&gt;Graphviz 调用图&lt;/h5&gt;
&lt;p&gt;我们想要为我们的 DiyProf gem 创造一个报告类，通过它来持续收集所有方法调用并创造一个 DOT 文件来代表调用图。
我们将在进入 DotReporter 类下面添加一个 &lt;code&gt;record&lt;/code&gt;方法，DotReporter 类能够在调用发生时推送方法信息进堆，在方法返回时从堆中抛出方法信息。当方法信息被从堆中抛出，它在堆中花费的时间则被记录，并且向调用树添加方法调用信息。看下列代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DiyProf&lt;/span&gt;
  &lt;span class="c1"&gt;# Struct that will hold a method name and a timestamp&lt;/span&gt;
  &lt;span class="no"&gt;CallInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DotReporter&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
      &lt;span class="c1"&gt;# A stack for pushing/popping methods when methods get called/returned&lt;/span&gt;
      &lt;span class="vi"&gt;@call_stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="c1"&gt;# Nodes for all methods&lt;/span&gt;
      &lt;span class="vi"&gt;@methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
      &lt;span class="c1"&gt;# Connections between the nodes&lt;/span&gt;
      &lt;span class="vi"&gt;@calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;
      &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="ss"&gt;:call&lt;/span&gt;
        &lt;span class="vi"&gt;@call_stack&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;CallInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="ss"&gt;:return&lt;/span&gt;
        &lt;span class="c1"&gt;# Return cannot be the first event in the call stack&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@call_stack.empty&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

        &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@call_stack.pop&lt;/span&gt;
        &lt;span class="c1"&gt;# Set execution time of method in call info&lt;/span&gt;
        &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;
        &lt;span class="n"&gt;add_method_to_call_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;add_method_to_call_tree&lt;/code&gt; 为被添加的方法增加节点和关系。下面是实现这一功能的代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Struct that holds the time spent in a method&lt;/span&gt;
&lt;span class="c1"&gt;# and the total number of times a method was called&lt;/span&gt;
&lt;span class="no"&gt;MethodInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Struct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:total_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:self_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_method_to_call_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# Add method as a node to the call graph&lt;/span&gt;
  &lt;span class="vi"&gt;@methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;MethodInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# Update total time(spent inside the method and methods called inside this method)&lt;/span&gt;
  &lt;span class="vi"&gt;@methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;total_time&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;
  &lt;span class="c1"&gt;# Update self time(spent inside the method and not methods called inside this method)&lt;/span&gt;
  &lt;span class="c1"&gt;# This will be subtracted when children are added to the graph&lt;/span&gt;
  &lt;span class="vi"&gt;@methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;self_time&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;
  &lt;span class="c1"&gt;# Update total no of times the method was called&lt;/span&gt;
  &lt;span class="vi"&gt;@methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

  &lt;span class="c1"&gt;# If the method has a parent in the call stack&lt;/span&gt;
  &lt;span class="c1"&gt;# Add a connection from the parent node to this method&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@call_stack.last&lt;/span&gt;
    &lt;span class="vi"&gt;@calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="vi"&gt;@calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="vi"&gt;@calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Take away self time of parent&lt;/span&gt;
    &lt;span class="vi"&gt;@methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;MethodInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;self_time&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在我们在&lt;code&gt;@methods&lt;/code&gt;和&lt;code&gt;@calls&lt;/code&gt;中都有节点和关系了，可以但不是必须要生成一个如下的文件：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;digraph&lt;/span&gt; &lt;span class="no"&gt;G&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;graph_nodes&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;graph_links&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下面是将在&lt;code&gt;@methods&lt;/code&gt;和&lt;code&gt;@calls&lt;/code&gt;中出现的代码，准备如下的 DOT 文件：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dot_notation&lt;/span&gt;
  &lt;span class="n"&gt;dot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%Q(
    digraph G {
      &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;graph_nodes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;
      &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;graph_links&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;
    }
  )&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;graph_nodes&lt;/span&gt;
  &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="vi"&gt;@methods.each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method_info&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; [label=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;ncalls: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;method_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;ntotal time: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;method_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;total_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;nself time: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;method_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self_time&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;];&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;nodes&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;graph_links&lt;/span&gt;
  &lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="vi"&gt;@calls.each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;links&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; [label=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;];&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;links&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 github repo 上检查&lt;code&gt;lib/diy_prof/dot_reporter.rb&lt;/code&gt;文件，看看它们是怎样彼此配合的。我们同时还需要利用规定的报告类在第三部分写过的 Tracer 类中做一些改变：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;DiyProf&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tracer&lt;/span&gt;
    &lt;span class="c1"&gt;# We'll need to initialize the Tracer with DotReporter.new&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@reporter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reporter&lt;/span&gt;
      &lt;span class="vi"&gt;@tracepoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:return&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="c1"&gt;# Use the reporter instead of just printing the traces&lt;/span&gt;
          &lt;span class="n"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpu_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;# New method added to collect the report after profiling&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;result&lt;/span&gt;
      &lt;span class="vi"&gt;@reporter.result&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在我们的 tracer 能够生成 DOT 格式的报告了，我们将它用在先前部分中写过的样本程序上：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_many_square_roots&lt;/span&gt;
    &lt;span class="n"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_square_roots&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_profiling&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;
&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DiyProf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stop_profiling&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'tempfile'&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'dot'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"dot -Tpdf &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; -o call_graph.pdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们将得到一个如下所示的调用图：
&lt;img src="https://l.ruby-china.com/photo/2015/596bad12085c1e7e35873301596db3f3.png" title="" alt=""&gt;
恭喜你已经进行到这一步，检查拥有完整代码的 github repo.&lt;/p&gt;
&lt;h5 id="额外令人开心的事！"&gt;额外令人开心的事！&lt;/h5&gt;
&lt;p&gt;如果能基于本身或方法总时间区分节点大小岂不是很酷？DOT 语法允许节点和 edges 拥有一系列属性。就像我们可以用&lt;code&gt;size&lt;/code&gt;和&lt;code&gt;fontsize&lt;/code&gt;属性来区分节点和节点内的内容。我将把如何用过这些来使最重要的方法在调用图中着重显示，这个问题将留给你们。&lt;/p&gt;
&lt;h5 id="概括"&gt;概括&lt;/h5&gt;
&lt;p&gt;我们学习了关于 Graphviz 和 DOT 语言及如何它们创造基于 Ruby TracePoint API 收集到的数据的调用图表。在第五部分，我们将着手建立一个简单的 RUby 分析器，尤其会学到一些基本的 C 里的信号中断和处理。感谢阅读，如果想要获取关于 DIY CPU 分析系列的最新博客内容，请关注我们的推特  &lt;a href="/codemancershq." class="user-mention" title="@codemancershq."&gt;&lt;i&gt;@&lt;/i&gt;codemancershq.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=RubyCpu3&amp;amp;utm_campaign=OctArti&amp;amp;from=matefiocrt" rel="nofollow" target="_blank" title=""&gt;OneAPM for Ruby&lt;/a&gt; 能够深入到所有 Ruby 应用内部完成&lt;a href="http://www.oneapm.com/" rel="nofollow" target="_blank" title=""&gt;应用性能管理&lt;/a&gt;和监控，包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章，请访问 &lt;a href="http://news.oneapm.com/?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=RubyCpu3&amp;amp;utm_campaign=OctArti&amp;amp;from=matefiocrt" rel="nofollow" target="_blank" title=""&gt;OneAPM 官方博客&lt;/a&gt;。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Tue, 27 Oct 2015 19:00:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/27855</link>
      <guid>https://ruby-china.org/topics/27855</guid>
    </item>
    <item>
      <title>Otto 开发初探——微服务依赖管理新利器</title>
      <description>&lt;p&gt;在搭建运行在笔记本之上的开发环境时，Vagrant 的表现非常优秀。不过在将程序迁往生产环境之时，在 Vagrant 的配置文件中所存储的配置环境 Vagrantfile 就不能直接用在生产服务器之上了。Otto 在 Vagrant 基础上进行了有效的拓展，允许使用单个配置文件对开发与生产环境进行定义、配置与部署。&lt;/p&gt;

&lt;p&gt;Otto 在管理基于微服务的应用时，解决了服务依赖关系上的重大挑战。在微服务架构中，系统被拆分为许多独立可展开的部件，而不是作为单个庞大的应用。也就是说，我们必须部署许多小型应用，而不是单个的大型应用，这样一来管理复杂性也增加了。图一展示了有多个依赖的应用。要加速本地开发环境，开发人员必须了解所有的依赖，并配置相应的 Vagrant 环境。通过遍历依赖层次结构，构建适应所有依赖关系的 Vagrant 环境，Otto 简化了基础设置配置。如果程序所依赖的服务有依赖，Otto 会自动解决、获取与构建这些依赖。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/847b873740677055a078d45deb9b5c4d.jpg" title="" alt="Otto开发初探——微服务依赖管理新利器"&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;扩展 Otto 以解支撑代理&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Otto 的&lt;a href="https://ottoproject.io/intro/getting-started" rel="nofollow" target="_blank" title=""&gt;入门指南&lt;/a&gt;包括工具的安装，构建&lt;a href="https://github.com/hashicorp/otto-getting-started" rel="nofollow" target="_blank" title=""&gt;简单 Ruby web 应用&lt;/a&gt;的开发环境，配置与部署 &lt;a href="http://aws.amazon.com/cn/" rel="nofollow" target="_blank" title=""&gt;AWS&lt;/a&gt; 环境的方法。Otto 底层使用了 Vagrant，自动生成用来配置本地开发环境的 Vagrantfile。生成的 Vagrantfile 是一个运行时构件，用户无法修改。只有创建自定义程序，并与主要的 Vagrantfile 合并，用户才能对 Vagrantfile 的生成产生影响。&lt;/p&gt;

&lt;p&gt;根据入门指南，在配置本地开发环境时，由于所有出站流量必须通过公司的代理服务器，这里遭遇了瓶颈。所有在开发 VM 上的 apt-get 安装都失败了。根据下面这些步骤，可以设法利用 Otto 所产生的 Vagrantfile 来解决代理配置。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;第一步：&lt;/strong&gt;首先，创建一个名为 otto-proxy 的目录，包括定义 vagrant-proxyconf 配置的 Vagrantfile 片段，参见图二。&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Vagrant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_plugin?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"vagrant-proxyconf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;http&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://proxy.cmu.edu:8080"&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;https&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://proxy.cmu.edu:8080"&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ftp&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://proxy.cmu.edu:8080"&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;no_proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"localhost,127.0.0.1,localaddress"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;图二：Vagrantfile 片段的内容定义了 vagrant-proxyconf 配置。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;第二步：&lt;/strong&gt;接下来，我创建了定义自定义程序的 Otto &lt;a href="https://ottoproject.io/intro/getting-started/appfile.html" rel="nofollow" target="_blank" title=""&gt;Appfile&lt;/a&gt;，如图三所示，自定义部分定义了一个可合并的 Vagrantfile 片段。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;application {
  name = "otto-proxy"
  type = "custom"
}
customization "dev-dep" {
  vagrantfile = "./Vagrantfile"
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;图三：这个 appfile 定义了一个简单的自定义程序，简单指出了配置开发环境时需要合并的 Vagrantfile。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;第三步：&lt;/strong&gt;最终，修改了 Otto 入门指南中样例项目的 &lt;a href="https://ottoproject.io/intro/getting-started/appfile.html" rel="nofollow" target="_blank" title=""&gt;appfile&lt;/a&gt;。修改后的 appfile 见图四。增加的代码以黄色标出。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;application {
  name = "otto-getting-started"
  type = "ruby"
  dependency {
    source = "../otto-proxy"
  }  
}

project {
  name = "otto-getting-started"
  infrastructure = "otto-getting-started"
}

infrastructure "otto-getting-started" {
  type = "aws"
  flavor = "simple"
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;图四：修改后的 otto-getting-started appfile，包括 otto-proxy 应用。&lt;/p&gt;

&lt;p&gt;目前，在运行 otto 开发命令来配置本地开发环境时，Vagrant 虚拟机上的软件包管理器通过公司代理服务器搭建了出站连接。&lt;/p&gt;

&lt;p&gt;点击&lt;a href="https://github.com/SLS-ALL/otto-proxy" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;查看 otto-proxy 项目的源代码，点击&lt;a href="https://github.com/SLS-ALL/otto-getting-started" rel="nofollow" target="_blank" title=""&gt;这里&lt;/a&gt;查看修改后的 otto-getting-started 项目。&lt;/p&gt;

&lt;p&gt;需要注意的是：Otto 在现有的 &lt;a href="http://devops.com/2014/05/05/meet-infrastructure-code/" rel="nofollow" target="_blank" title=""&gt;infrastructure-as-code&lt;/a&gt; 工具之上增加了新一层抽象。但是通过 appfile 中自定义的依赖关系与自定义标签，如果必要的话，开发者可以控制底层工具的运作方式。Otto 还处于初始阶段，目前是 0.1 版本，除了特殊情况，一般可能无法满足生产环境使用，不过很有希望成为自动化环境配置与部署的一线工具。&lt;/p&gt;

&lt;p&gt;原文链接：&lt;a href="https://insights.sei.cmu.edu/devops/2015/10/developing-with-otto-devops.html" rel="nofollow" target="_blank" title=""&gt;Developing with Otto: A First Look&lt;/a&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Thu, 15 Oct 2015 14:19:32 +0800</pubDate>
      <link>https://ruby-china.org/topics/27683</link>
      <guid>https://ruby-china.org/topics/27683</guid>
    </item>
    <item>
      <title>从后端到页面：如何全方位监控 Ruby 应用？</title>
      <description>&lt;p&gt;&lt;strong&gt;【编者按】本文参考&lt;a href="http://www.rails365.net/articles/2015-09-22-bu-shu-zhi-yong-oneapm-zuo-wei-ni-de-jian-kong-ping-tai-yi" rel="nofollow" target="_blank" title=""&gt;技术分享&lt;/a&gt; ，由 &lt;a href="http://www.oneapm.com/index.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=monirudy&amp;amp;utm_campaign=OctArti&amp;amp;from=matefiocmr" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 工程师补充整理，并且已经征得原作者的同意。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="为什么选择 OneAPM ?"&gt;为什么选择 OneAPM ?&lt;/h2&gt;
&lt;p&gt;在&lt;a href="http://www.oneapm.com/" rel="nofollow" target="_blank" title=""&gt;性能监控&lt;/a&gt;领域，业界比较有名的是 New Relic 还有 Appdynamic，不过这两家公司都在在国外，在国内访问速度很慢暂且不提，毕竟，国外的东西说不定啥时候就被那个啥了 (你懂的)，所以笔者一直在等待中国也有类似的产品出来。在国内的话，首先访问会比较快，而且只有中国人才最懂中国人，做出来的产品也会符合中国用户的审美和需求。如果这个产品稳定、口碑好、不出问题，那就是很不错的选择，国内最早开始深耕应用性能管理行业的 &lt;a href="http://www.oneapm.com/index.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=monirudy&amp;amp;utm_campaign=OctArti&amp;amp;from=matefiocmr" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 应该就是一个典型的代表。另外，OneAPM 使用起来很简单，官网有一些教程，按照那教程，只需花费几分钟的时间，操作几个步骤就可以搞定了，笔者使用了 Ruby Insight，装一个 gem 就能搞定，然后页面性能监控（Bi）甚至自动起来了，完全避免了手动部署的麻烦。&lt;/p&gt;
&lt;h2 id="使用 OneAPM 监控 Ruby 应用"&gt;使用 OneAPM 监控 Ruby 应用&lt;/h2&gt;
&lt;p&gt;登录 OneAPM 官网，注册账号，进入主页面，选择「应用监控」，添加一个应用，选择「Ruby」那个 tab，里面列出了 5 个步骤，按照这些步骤就可以设置成功：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;第一步是把授权编号复制，这个是要用到的。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;第二步是复制 oneapm.yml 文件存放到 config 目录下。这个是主要的配置文件。刚才复制的授权编号也是要放到这个文件中的。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;第三步是把那个 gem 添加到 Gemfile 文件，并进行 bundle install 就好了。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;现在主要的问题是第二步，那个配置文件里面的项目名和你建立的应用的项目名的对应。&lt;/p&gt;

&lt;p&gt;License_key 就是授权编号，一段字符串，为了保密，笔者是存到配置文件中的。其他的内容都基本没改，唯一有改的地方就是 app_name，这个名字就是要跟你建立的 OneAPM 应用的名字一致才行。&lt;/p&gt;

&lt;p&gt;笔者在线上就有一个 OneAPM 应用就叫 Rails365，把里面的 app_name 替换成 Rails365 就好了。&lt;/p&gt;

&lt;p&gt;按照官方教程说的，重新启动并部署你的项目，试着访问几个页面，稍等片刻，就能很快在 OneAPM 的监控页面上看到数据了。&lt;/p&gt;

&lt;p&gt;或许用 Rails 的 Notifications 结合 Hightcharts 图表显示也能实现类似 OneAPM 的效果，至少能得到每个页面的访问时间，数据库语句的执行时间，但是现在有更方便的 OneAPM，我们就可以尝试去用它。如果要进一步，还可以去研究那个 gem 的源码，知道它是如何实现的。&lt;/p&gt;
&lt;h2 id="OneAPM for Ruby"&gt;OneAPM for Ruby&lt;/h2&gt;
&lt;p&gt;来简单说说 Ai Ruby 探针的功能：&lt;/p&gt;

&lt;p&gt;安装好 OneAPM Ruby Agent 之后进入总览页面，能够对 Web 事务响应时间，&lt;a href="http://news.oneapm.com/tag/apdex/" rel="nofollow" target="_blank" title=""&gt;Apdex 值&lt;/a&gt;（满意度），吞吐量，Web 慢事务，错误率，服务器信息，告警事件有个总体了解。
&lt;img src="https://l.ruby-china.com/photo/2015/dadc905cf8fc0fcf677f341d5617fd2a.png" title="" alt=""&gt;
比较中意 Web 事务的功能，可以点进具体事务进行分析。如图，点进 Web 事务功能后，可以看到响应时间占比最高的事务。
&lt;img src="https://l.ruby-china.com/photo/2015/560ce47a2c95dd972350da2b26dc4b03.png" title="" alt=""&gt;
为了分析慢事务原因，点进 articles/index 这个较慢的事务，通过 Breakdown Table 可以看到事务的细分内容。
&lt;img src="https://l.ruby-china.com/photo/2015/5196cebddfa0ae460675a6b5094cc6c9.png" title="" alt=""&gt;
对数据库，外部服务也可以进行监控，能监控到 SQL 语句。对 RubyVM 的监控也是有的。
&lt;img src="https://l.ruby-china.com/photo/2015/d144e1c349344373e298fbee7de7abc4.png" title="" alt=""&gt;
错误信息功能也比较有用，不仅可以看到错误发生的时间、次数、类型、请求地址，还能看到详细的堆栈信息，显示代码行数。
&lt;img src="https://l.ruby-china.com/photo/2015/d7708af398912e66ac89e4a153ca2564.png" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/73614a29e838823d952236fd62f6ac5a.png" title="" alt=""&gt;
关于应用监控的各种配置，可以在「应用设置」中自行修改，这一点还是比较灵活易用的。
&lt;img src="https://l.ruby-china.com/photo/2015/81d80e31d4ce7554795ebb844f5e84a8.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="OneAPM 的网站监控平台（Browser Insight）"&gt;OneAPM 的网站监控平台（Browser Insight）&lt;/h2&gt;
&lt;p&gt;在网站开发完成并且上线之后，随着业务的完善与增多，访问网站的人也越来越多，这个时候你就需要维护网站了。不仅仅是业务上的维护，还包括运维，监控等。你可能会监控每天的访问量有多少，增长了没，这个时候可以用常用的 Google Analyse，百度统计，站长工具等来完成。不过，这些工具主要统计浏览量，来源分析等，进而帮助公司运营人员的决策，营销推广，可是，网站的访问量上来之后，必定会遇到性能瓶颈。这个时候就需要找出那些低性能代码或影响页面加载等问题的来源，页面性能监控软件就变得尤为重要了。通过观察每个页面的访问时间来查看哪些页面甚至哪些代码是有问题或者可以优化的，OneAPM 的 Browser Insight（Bi）就是解决这个事情的。它能帮助网站进行性能监控，包括页面的响应时间、AJAX 错误、脚本错误等。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;（一）总览页面&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;下图是总览页面，由于屏幅的问题没有截取全。在 Bi 的总览页面我们可以看到该功能的大概显示，包括响应时间、Web 事务、页面 Trace 以及分地域的页面加载时间等，让研发或者运维对监控的页面有一个大概的了解。&lt;/p&gt;

&lt;p&gt;从左边的功能列表可以看到， &lt;a href="http://www.oneapm.com/index.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=monirudy&amp;amp;utm_campaign=OctArti&amp;amp;from=matefiocmr" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 的 Bi 主要是从受访页面、AJAX、脚本错误、浏览器、地理和运营商这几个维度来监控分析前端页面的。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/a445330b2452951355447961737e12a6.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;（二）受访页面&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;下图是受访页面的功能页面，可以看到，不但从 5 个维度分解了加载时间，而且还有加载时间的排序，甚至有慢加载追踪，可以比较详细的定位到各种资源加载。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/62167e94634ade1643d9532f46e0b975.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;还有一个值得说下的是受访页面的这几个加载时间的维度的区分，OneAPM 做的比较有自己的特点，在总览页面有对于几个时间的具体分析注释。 &lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/2565ceae32af63866d46b1a55e15c837.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;（三）AJAX、页面错误&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这两个维度分别从 AJAX 和 HTTPS 角度来分析监控页面的错误或者时间缓慢的调用页面，虽然维度不一样但是界面比较相似，就不给大家一一列举了，简单看一下界面就好了。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/5ed96296fad6c7d46f2d765e0ffa49e2.png" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/3d2dd15a1d1c1a24da8a363d7d932b43.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;（四）浏览器、运营商、地理&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;这三个功能应该算是 OneAPM 的 Bi 的另外一个核心功能点了，浏览器可以按照将访问页面的浏览器一一识别出来，方便研发或者运维人员有针对性的优化页面。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/a9b313b1e2f1e3b34f6cfe517713c676.png" title="" alt=""&gt;
地理界面可以从国内还有国外两个维度查看访问被监控页面的响应时间等，国内的还可以深入到地级市的使用加载情况。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/705c34f0e7ac7ffb8cd47e3ea703b9e2.png" title="" alt=""&gt;
运营商界面是针对于网络运营商的监控，可以看到各个运营商所提供的网速的情况，而且还可以区分网络制式，做的确实很精细了。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/5a51f49d344c2913e8843ed93cb32d24.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;##总结&lt;/p&gt;

&lt;p&gt;或许通过其他工具例如 Rails 的 Notifications 结合 Hightcharts 图表也能有类似的效果，但是 OneAPM 确实很方便实用的达到了性能监控分析的这一目的。从国内来讲，OneAPM 确实是性能监控方面比较靠得住的厂家，大家可以免费注册试用一下。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=monirudy&amp;amp;utm_campaign=OctArti&amp;amp;from=matefiocmr" rel="nofollow" target="_blank" title=""&gt;OneAPM for Ruby&lt;/a&gt; 能够深入到所有 Ruby 应用内部完成应用性能管理和监控，包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章，请访问 &lt;a href="http://news.oneapm.com/" rel="nofollow" target="_blank" title=""&gt;OneAPM 官方博客&lt;/a&gt;。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Mon, 12 Oct 2015 11:04:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/27640</link>
      <guid>https://ruby-china.org/topics/27640</guid>
    </item>
    <item>
      <title>DIY Ruby CPU 分析——Part I</title>
      <description>&lt;p&gt;&lt;strong&gt;【编者按】原文作者 Emil Soman，Rubyist，除此之外竟然同时也是&lt;/strong&gt;&lt;em&gt;艺术家，吉他手&lt;/em&gt;&lt;strong&gt;，Garden City RubyConf 组织者。本文是 DIY Ruby CPU Profiling 的第一部分，由 &lt;a href="http://www.oneapm.com/index.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=rubyCpu1&amp;amp;utm_campaign=SeptArti&amp;amp;from=matefisporo" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 工程师编译整理。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://news.oneapm.com/content/images/2015/09/1-4.jpg" title="" alt="alt"&gt;&lt;/p&gt;

&lt;p&gt;在 Codemancers，我们正在建设 Rbkit——一个针对 Ruby 语言的——拥有新炫酷功能的代码分析器。我目前正在实现一个嵌在 rbkit gem 里的 CPU 分析器，这将有助 rbkit UI 重建分析 Ruby 进程调用图，并在屏幕上得出有用的可视化展示。在这个过程中，我学到了许多新东西，很乐意在本系列的博客文章中与您分享。&lt;/p&gt;

&lt;p&gt;我们打算一步一步从基础开始，专门为 Ruby 编写一个初级的 CPU 分析器！在完成时我们将学到：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;什么是 CPU 分析&lt;/li&gt;
&lt;li&gt;分析模式——工具和采样&lt;/li&gt;
&lt;li&gt;CPU Time 和 Wall Time ——它们分别是什么意思，如何测量？&lt;/li&gt;
&lt;li&gt;写一个简单的 C 扩展并用于 Ruby 中&lt;/li&gt;
&lt;li&gt;Ruby Tracepoints——调用和返回&lt;/li&gt;
&lt;li&gt;C 语言中的信号处理&lt;/li&gt;
&lt;li&gt;用一个信号暂停 Ruby 进程并用调用堆查看&lt;/li&gt;
&lt;li&gt;&lt;p&gt;用分析数据进行一些有用但笨拙的试验
###Part I. 介绍 CPU 分析
通过对你的程序进行 CPU 分析，可以发现相较于 CPU 使用率，你的程序是多么宝贵。为了分析程序，你需要使用一个分析工具并按照下列步骤操作：&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开始 CPU 剖析&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;执行你想要分析的代码&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;停止 CPU 剖析并得到剖析结果&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;分析结果&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;通过分析剖析结果，你会发现使整个程序缓慢的瓶颈。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="分析模式"&gt;分析模式&lt;/h4&gt;
&lt;p&gt;CPU 剖析可以分为以下两种方法：&lt;/p&gt;
&lt;h4 id="1. 工具"&gt;1. 工具&lt;/h4&gt;
&lt;p&gt;在这种模式下，分析工具利用一些 hooks，由解释器提供或者插入程序中，来了解调用图并测量在调用图中每个方法的执行时间。举个例子，看一下下面这段 Ruby 代码：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_many_square_roots&lt;/span&gt;
    &lt;span class="n"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_square_roots&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我已经插入了一些内容，来帮助了解如果 Ruby 解释器给了我们方法的调用和返回的 hooks，它们如何执行：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;
  &lt;span class="c1"&gt;# method call hook gets executed&lt;/span&gt;
  &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;find_many_square_roots&lt;/span&gt;
    &lt;span class="n"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="c1"&gt;# method end hook gets executed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_square_roots&lt;/span&gt;
  &lt;span class="c1"&gt;# method call hook gets executed&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="c1"&gt;# method end hook gets executed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_many_squares&lt;/span&gt;
  &lt;span class="c1"&gt;# method call hook gets executed&lt;/span&gt;
  &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;# method end hook gets executed&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在，如果我们能够打印出当前时间和这些 hooks 内部当前方法的名称，会得到看起来像这种形式的输出结果：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sec:00 usec:201007  called      main
sec:00 usec:201108  called      find_many_square_roots
sec:00 usec:692123  returned    find_many_square_roots
sec:00 usec:692178  called      find_many_squares
sec:00 usec:846540  returned    find_many_squares
sec:00 usec:846594  called      find_many_square_roots
sec:01 usec:336166  returned    find_many_square_roots
sec:01 usec:336215  called      find_many_squares
sec:01 usec:484880  returned    find_many_squares
sec:01 usec:484945  called      find_many_square_roots
sec:01 usec:959254  returned    find_many_square_roots
sec:01 usec:959315  called      find_many_squares
sec:02 usec:106474  returned    find_many_squares
sec:02 usec:106526  returned    main
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;正如你所看到的，此输出可以告诉我们在每一种方法里面花了多长时间。同时也告诉我们，每一个方法调用的次数。这大概就解释了性能分析工具是如何工作的。&lt;/p&gt;
&lt;h6 id="优点："&gt;优点：&lt;/h6&gt;
&lt;p&gt;高精度
我们得到了方法调用数
易于实施&lt;/p&gt;
&lt;h6 id="缺点："&gt;缺点：&lt;/h6&gt;
&lt;p&gt;每个被分析的方法执行 hooks 时的额外开销&lt;/p&gt;
&lt;h4 id="2. 采样"&gt;2. 采样&lt;/h4&gt;
&lt;p&gt;在采样模式下，分析器每隔 x 时间单元打断一次程序，并查看调用堆并记录它的信息（被称为“样品”）。一旦该程序完成运行，分析器收集所有样品并找出每个方法出现在所有样品中的次数。
很难想象？让我们来看看同样的例子代码，看看如果我们使用采样分析器，输出结果会有怎样的不同。
采样分析器的输出结果如下：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Call stack at 0.5sec: main/find_many_square_roots
Call stack at 1.0sec: main/find_many_square_roots
Call stack at 1.5sec: main/find_many_square_roots
Call stack at 2.0sec: main/find_many_squares
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个例子中，程序每 0.5 秒被中断一次并且调用堆栈被记录。因此，通过这个程序执行的过程我们得到了 4 个样品，&lt;code&gt;find_many_square_roots&lt;/code&gt; 记录于 3 个样品中， &lt;code&gt;find_many_squares&lt;/code&gt; 只存在于一个样品中。从本次采样中，我们得到 &lt;code&gt;find_many_square_roots&lt;/code&gt; 占用了 75％ CPU，与此同时 &lt;code&gt;find_many_squares&lt;/code&gt; 只占用了 25％ 的 CPU。这就大概解释了分析器是怎么样工作的。&lt;/p&gt;
&lt;h6 id="优点："&gt;优点：&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;与工具分析相比开销可忽略不计&lt;/li&gt;
&lt;li&gt;很容易找到缓慢/长时间运行的方法&lt;/li&gt;
&lt;/ul&gt;
&lt;h6 id="缺点："&gt;缺点：&lt;/h6&gt;
&lt;ul&gt;
&lt;li&gt;不擅长测量短时间运行的方法&lt;/li&gt;
&lt;li&gt;我们没有得到方法调用数&lt;/li&gt;
&lt;li&gt;很难自己写出采样分析器&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="概括"&gt;概括&lt;/h4&gt;
&lt;p&gt;我们只是调查了 CPU 分析的含义和两种常用的 CPU 分析方法。在第 2 部分，我们将探讨对描述 CPU 使用情况的 2 个单位进行测量—— CPU Time 和 Wall Time。我们也会亲手写一些代码来获取进行测量。感谢您的阅读！&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=rubyCpu1&amp;amp;utm_campaign=SeptArti&amp;amp;from=matefisporo" rel="nofollow" target="_blank" title=""&gt;OneAPM for Ruby&lt;/a&gt; 能够深入到所有 Ruby 应用内部完成应用性能管理和监控，包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章，请访问 &lt;a href="http://news.oneapm.com/?utm_source=Community&amp;amp;utm_medium=Article&amp;amp;utm_term=rubyCpu1&amp;amp;utm_campaign=SeptArti&amp;amp;from=matefisporo" rel="nofollow" target="_blank" title=""&gt;OneAPM 官方博客&lt;/a&gt;。&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Fri, 25 Sep 2015 14:34:56 +0800</pubDate>
      <link>https://ruby-china.org/topics/27481</link>
      <guid>https://ruby-china.org/topics/27481</guid>
    </item>
    <item>
      <title>不要让「缓慢」毁了你的应用 | 试用应用性能监控神器，赢取 Cherry G80-3000 机械键盘！</title>
      <description>&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/4d610c2622abca73c0bab115f5408c70.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;用户无法注册了？还是接口突然失效了？想要搭一个性能监控系统，可是功能单一的工具，不能适配如此复杂的环境。试试 OneAPM 吧！&lt;/p&gt;

&lt;p&gt;OneAPM 能够深入到所有应用内部完成应用性能管理和监控，包括代码级别性能问题的可见性、快速识别与追溯性能瓶颈、真实用户体验监控、服务器监控和端到端的应用性能管理。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One APM for Ruby 支持几乎所有 Ruby 常见框架。&lt;/li&gt;
&lt;li&gt;追溯性能瓶颈至：性能表现差的 SQL 语句、第三方 API、Web Services、Caching Layers、后台任务等。&lt;/li&gt;
&lt;li&gt;关键事务 Top 5，平均响应时间、吞吐量这些性能数据的展示，帮助你快速定位性能瓶颈；慢 SQL 追踪、慢事务的深度 Traces 记录，协助你完成应用性能管理从抽象到具象的追溯过程。&lt;/li&gt;
&lt;li&gt;智能的报警机制，让你在性能瓶颈出现前，修复性能问题，防止性能问题导致用户流失。&lt;/li&gt;
&lt;li&gt;论深度，可以定位到代码行，可以抓取到堆栈和线程信息。论广度，从服务器到页面全方位监控。&lt;/li&gt;
&lt;li&gt;论外观，国际水平的页面，直观友好的可视化数据展示。论服务，及时响应、认真负责的客户服务。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;更多功能，等你来探索～&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;不参加活动，直接去官网：&lt;a href="http://www.oneapm.com/index.html?from=maacsprc" rel="nofollow" target="_blank" title=""&gt;OneAPM 官网&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h2 id="最喜欢 OneAPM 的活动了！！！！"&gt;最喜欢 OneAPM 的活动了！！！！&lt;/h2&gt;
&lt;hr&gt;
&lt;h2 id="Step 1 部署应用，带我飞"&gt;Step 1 部署应用，带我飞&lt;/h2&gt;
&lt;p&gt;目前注册的账户都可以&lt;strong&gt;享受 15 天的专业版使用权限&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;活动注册通道：&lt;a href="https://user.oneapm.com/account/register.do?from=maacsprc" rel="nofollow" target="_blank" title=""&gt;https://user.oneapm.com/account/register.do?from=maacsprc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;成功添加应用，&lt;strong&gt;并将有数据的界面截图发送到本帖中&lt;/strong&gt;，即可获得  Minecraft 游戏或者任意一款价值 50 元之内的 iOS App。Android 或 Windows Phone 的用户请不要着急，可以选择价值 50 元之内的书籍礼物。&lt;/p&gt;
&lt;h2 id="完成之后，请提交表单：https://jinshuju.net/f/JrbXII"&gt;完成之后，请提交表单：&lt;a href="https://jinshuju.net/f/JrbXII" rel="nofollow" target="_blank" title=""&gt;https://jinshuju.net/f/JrbXII&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/128ee6d2572d2f60111c66269a0d185b.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="Step 2  在本站发帖，分享有价值的使用体验， 送 Cherry 樱桃 G80-3000 机械键盘"&gt;Step 2  在本站发帖，分享有价值的使用体验，送 Cherry 樱桃 G80-3000 机械键盘&lt;/h2&gt;
&lt;p&gt;啪啪响的机械键盘！&lt;/p&gt;

&lt;p&gt;分享参考：
&lt;a href="https://cnodejs.org/topic/55f7c56122faedef379f66bc" rel="nofollow" target="_blank" title=""&gt;https://cnodejs.org/topic/55f7c56122faedef379f66bc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cnodejs.org/topic/56002229152fdd025f0f4f52" rel="nofollow" target="_blank" title=""&gt;https://cnodejs.org/topic/56002229152fdd025f0f4f52&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="分享好了，我要键盘：https://jinshuju.net/f/vSGv3e"&gt;分享好了，我要键盘：&lt;a href="https://jinshuju.net/f/vSGv3e" rel="nofollow" target="_blank" title=""&gt;https://jinshuju.net/f/vSGv3e&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/f2d06eaf171532719b1e9fe09ed81117.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="活动细则"&gt;活动细则&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;本次活动时间：2015.9.21-10.31&lt;/li&gt;
&lt;li&gt;这次活动两种礼品可以同时获取。&lt;/li&gt;
&lt;li&gt;Step 1 部署任意应用，送礼品，仅针对本次活动中注册的新用户，参与人数不受限制，活动期间每周二发放礼品。&lt;/li&gt;
&lt;li&gt; Step 2 在本社区发帖，分享使用体验，送 Cherry 樱桃 G80-3000 机械键盘，新老用户均可参加，参与人数限制 10，活动期间每周三寄送键盘。&lt;/li&gt;
&lt;li&gt;Step 2 活动，对于毫无价值的分享内容 OneAPM 有权取消获奖资格。&lt;/li&gt;
&lt;li&gt;本活动最终解释权归 OneAPM 所有。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="OneAPM 官网"&gt;&lt;a href="http://www.oneapm.com/index.html?from=maacsprc" rel="nofollow" target="_blank" title=""&gt;OneAPM 官网&lt;/a&gt;&lt;/h2&gt;</description>
      <author>oneapm</author>
      <pubDate>Wed, 23 Sep 2015 11:57:10 +0800</pubDate>
      <link>https://ruby-china.org/topics/27442</link>
      <guid>https://ruby-china.org/topics/27442</guid>
    </item>
    <item>
      <title> [Rubyist 少数派调查] 你喜欢经典神器，还是走在时代尖端？</title>
      <description>&lt;p&gt;&lt;img src="http://i.v2ex.co/bNi5Dz7q.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;这个夏天，我们从 RubyChina 获得了不少真爱粉，为了回馈社区我们打算举行一次有奖调查活动。&lt;/p&gt;

&lt;p&gt;问题有：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rails 到底该选什么 Server？Unicorn？Puma？Thin？&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;开发工具哪家强！Atom，新时代利器？Sublime，快速，性感，跨平台？Vim，上古神器！&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;填写问卷之后，就可以查看所有人的数据啦～&lt;/p&gt;

&lt;p&gt;问卷地址：&lt;a href="http://form.mikecrm.com/f.php?t=1loDmV" rel="nofollow" target="_blank" title=""&gt;http://form.mikecrm.com/f.php?t=1loDmV&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="活动规则"&gt;活动规则&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;参与问卷调查的前十名用户均可获得&lt;a href="https://bearychat.com/?hmsr=rubychina&amp;amp;hmmd=&amp;amp;hmpl=&amp;amp;hmkw=&amp;amp;hmci=" rel="nofollow" target="_blank" title=""&gt;BearyChat&lt;/a&gt;小清新 T 恤一件&amp;amp;夏日清凉小扇子一把。&lt;/li&gt;
&lt;li&gt;参与调查的第 6 名，第 25 名，第 50 名，第 75 名，最后一名用户，我们将赠送［重大决策按钮］或［长草很久的书籍］。&lt;/li&gt;
&lt;li&gt;本活动仅在&lt;strong&gt;Ruby-China&lt;/strong&gt;举行，截止时间：2015/8/24 23:59，获奖用户我们将在下周二公布。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="礼物咧"&gt;礼物咧&lt;/h2&gt;&lt;h3 id="重大决策按钮"&gt;重大决策按钮&lt;/h3&gt;
&lt;p&gt;每按一下地球上就会有一件大事发生的按钮，比如说让某个人消失什么的（大雾）。总之［重大决策按钮］就是可编程的一个按键啦。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://i.v2ex.co/RO97W9t1b.jpeg" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="长草很久的书籍"&gt;长草很久的书籍&lt;/h3&gt;
&lt;p&gt;[长草很久的书籍］，告诉我们想要的书，我们来帮你拔草，100 元以下都没问题。
&lt;img src="http://i.v2ex.co/2awF3D0pl.jpeg" title="" alt=""&gt;&lt;/p&gt;
&lt;h3 id="清凉一夏"&gt;清凉一夏&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://bearychat.com/?hmsr=rubychina&amp;amp;hmmd=&amp;amp;hmpl=&amp;amp;hmkw=&amp;amp;hmci=" rel="nofollow" target="_blank" title=""&gt;BearyChat&lt;/a&gt;小清新 T 恤一件&amp;amp;夏日清凉小扇子一把。&lt;/p&gt;

&lt;p&gt;&lt;img src="http://i.v2ex.co/Hj9iD32pb.jpeg" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="开奖啦"&gt;开奖啦&lt;/h2&gt;
&lt;p&gt;除去内部测试人员，本次调查参与人员 156，共收到反馈 156。除去 3 名内部测试人员序号，本次活动序号从 [#4] 开始。&lt;/p&gt;
&lt;h3 id="清凉一夏"&gt;清凉一夏&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/846e8049285639888c120075527b2ad6.jpg" title="" alt=""&gt;
由于 [#12] 的朋友说明放弃奖品，获得清凉一夏的朋友是，获奖序号是 [#4][#5][#6][#7][#8][#9][#10]  [#11][#13][#14]。&lt;/p&gt;

&lt;p&gt;&lt;a href="/hhuai" class="user-mention" title="@hhuai"&gt;&lt;i&gt;@&lt;/i&gt;hhuai&lt;/a&gt; &lt;a href="/chiangdi" class="user-mention" title="@chiangdi"&gt;&lt;i&gt;@&lt;/i&gt;chiangdi&lt;/a&gt; &lt;a href="/hanrong" class="user-mention" title="@hanrong"&gt;&lt;i&gt;@&lt;/i&gt;hanrong&lt;/a&gt; &lt;a href="/kikyous" class="user-mention" title="@kikyous"&gt;&lt;i&gt;@&lt;/i&gt;kikyous&lt;/a&gt; &lt;a href="/DeathKing" class="user-mention" title="@DeathKing"&gt;&lt;i&gt;@&lt;/i&gt;DeathKing&lt;/a&gt; &lt;a href="/ywjno" class="user-mention" title="@ywjno"&gt;&lt;i&gt;@&lt;/i&gt;ywjno&lt;/a&gt; &lt;a href="/dongli1985" class="user-mention" title="@dongli1985"&gt;&lt;i&gt;@&lt;/i&gt;dongli1985&lt;/a&gt; &lt;a href="/leekelby" class="user-mention" title="@leekelby"&gt;&lt;i&gt;@&lt;/i&gt;leekelby&lt;/a&gt; @默兮 礼品将在本周内寄出！&lt;/p&gt;

&lt;p&gt;&lt;a href="/DeathKing" class="user-mention" title="@DeathKing"&gt;&lt;i&gt;@&lt;/i&gt;DeathKing&lt;/a&gt; &lt;a href="/leekelby" class="user-mention" title="@leekelby"&gt;&lt;i&gt;@&lt;/i&gt;leekelby&lt;/a&gt; 麻烦本周内将收货地址，姓名，手机 发送到:tengfanglingzi@oneapm.com&lt;/p&gt;
&lt;h3 id="长草很久的书籍"&gt;长草很久的书籍&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/a92bf275cf675596f5146f8b6239f426.jpg" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/8ccd8de681db50421e22ce126669e10b.jpg" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/8ff5ce5ca382065ff1850d617e6d96fc.jpg" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/5febff0f4736697eff04c56a0ae34181.jpg" title="" alt=""&gt;
&lt;img src="https://l.ruby-china.com/photo/2015/698279060fdb5e47f4724f0cf450fe50.jpg" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;获奖的有：[#9][#28][#53][#78][#159]&lt;/p&gt;

&lt;p&gt;&lt;a href="/ywjno" class="user-mention" title="@ywjno"&gt;&lt;i&gt;@&lt;/i&gt;ywjno&lt;/a&gt; &lt;a href="/chad_lwm" class="user-mention" title="@chad_lwm"&gt;&lt;i&gt;@&lt;/i&gt;chad_lwm&lt;/a&gt; &lt;a href="/759803573" class="user-mention" title="@759803573"&gt;&lt;i&gt;@&lt;/i&gt;759803573&lt;/a&gt;  麻烦本周内将书的购买链接，发送到:tengfanglingzi@oneapm.com，要附上 RubyChina ID 哦！&lt;/p&gt;

&lt;p&gt;&lt;a href="/martin" class="user-mention" title="@martin"&gt;&lt;i&gt;@&lt;/i&gt;martin&lt;/a&gt; 你想要的书，我们已经寄出啦！&lt;/p&gt;

&lt;p&gt;&lt;a href="/geekontheway" class="user-mention" title="@geekontheway"&gt;&lt;i&gt;@&lt;/i&gt;geekontheway&lt;/a&gt; 你在问卷中说明希望获得清凉一夏，我们会按照你的意愿提供奖品。有什么问题可以发邮件跟我沟通。tengfanglingzi@oneapm.com&lt;/p&gt;
&lt;h3 id="重大决策按钮"&gt;重大决策按钮&lt;/h3&gt;
&lt;p&gt;每按一下地球上就会有一件大事发生的按钮，比如说让某个人消失什么的（大雾）。总之［重大决策按钮］就是可编程的一个按键啦。虽然希望获得按钮的朋友很多，但是很遗憾都跟大奖插肩而过。［重大决策按钮］将在下次活动中和大家见面！如果你希望获得其他的礼品，欢迎留下你的评论。&lt;/p&gt;
&lt;h3 id="性能监控神器 www.oneapm.com"&gt;性能监控神器 &lt;a href="http://www.oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Activity&amp;amp;utm_term=Rubyist&amp;amp;utm_campaign=AugActivity&amp;amp;from=opcofiaurc" rel="nofollow" target="_blank" title=""&gt;www.oneapm.com&lt;/a&gt;
&lt;/h3&gt;</description>
      <author>oneapm</author>
      <pubDate>Fri, 21 Aug 2015 14:08:10 +0800</pubDate>
      <link>https://ruby-china.org/topics/27020</link>
      <guid>https://ruby-china.org/topics/27020</guid>
    </item>
    <item>
      <title>[北京][8.16] Rails 应用开发入门培训 2.0</title>
      <description>&lt;h2 id="Hello Rubyist!"&gt;Hello Rubyist!&lt;/h2&gt;&lt;h4 id="还记得上一次的 Rails 应用开发入门培训吗？"&gt;还记得上一次的 Rails 应用开发入门培训吗？&lt;/h4&gt;&lt;h4 id="由于上次培训效果还不错，应大家的要求，我们的第二次培训即将展开！"&gt;由于上次培训效果还不错，应大家的要求，我们的第二次培训即将展开！&lt;/h4&gt;
&lt;p&gt;&lt;img src="http://7xkdjw.com1.z0.glb.clouddn.com/QQ%E5%9B%BE%E7%89%8720150727094110.png" title="" alt="Mou icon"&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="http://7xkdjw.com1.z0.glb.clouddn.com/QQ%E5%9B%BE%E7%89%8720150727094132.png" title="" alt="Mou icon"&gt;&lt;/p&gt;
&lt;h6 id="拍摄于：国内APM领域No.1公司的秘密基地"&gt;拍摄于：国内 APM 领域 No.1 公司的秘密基地&lt;/h6&gt;&lt;h4 id="锵！锵！锵！这是上次培训的抓拍！"&gt;锵！锵！锵！这是上次培训的抓拍！&lt;/h4&gt;
&lt;p&gt;作为一家&lt;strong&gt;专注技术&lt;/strong&gt;的&lt;strong&gt;有诚意&lt;/strong&gt;的公司，&lt;/p&gt;

&lt;p&gt;我们希望更多人了解 ROR 的魅力，参与敏捷开发。&lt;/p&gt;

&lt;p&gt;于是有了这个零基础也可以参与的入门级别培训。&lt;/p&gt;

&lt;p&gt;除了资深 Ruby 开发工程师带来的的 Ruby On Rails 技术干货，&lt;/p&gt;

&lt;p&gt;零食，饮料，帅哥，美女都可以有！&lt;/p&gt;

&lt;p&gt;但是！希望如果有人临时不来，提前跟我们说一声，感谢大家。&lt;/p&gt;
&lt;h3 id="完全免费！ 限30人！ 妹子优先！"&gt;
&lt;em&gt;完全免费！&lt;/em&gt; &lt;em&gt;限 30 人！&lt;/em&gt; &lt;em&gt;妹子优先！&lt;/em&gt;
&lt;/h3&gt;&lt;h6 id="报名截止日期：2015年8月12日"&gt;报名截止日期：2015 年 8 月 12 日&lt;/h6&gt;&lt;h5 id="培训内容："&gt;培训内容：&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt; 一分钟上传文件的实现&lt;/li&gt;
&lt;li&gt; 最简单的 web 表单实现&lt;/li&gt;
&lt;li&gt; 三分钟微博实现&lt;/li&gt;
&lt;li&gt; 应用 bootstrap&lt;/li&gt;
&lt;li&gt; 应用 font-awesome&lt;/li&gt;
&lt;li&gt; 一分钟查看应用性能&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;要求：
搭建好 ruby on rails 环境，本地没有环境的装上 virtualbox，不要装 5.0 的，要装 4.x 的版本，到时候用虚拟机开发。&lt;/p&gt;

&lt;p&gt;（不会安环境？&lt;a href="http://blog.csdn.net/felomeng/article/details/14221529" rel="nofollow" target="_blank" title=""&gt;可以参考这里&lt;/a&gt;)&lt;/p&gt;
&lt;h5 id="讲师：Ruby资深开发工程师李哲"&gt;讲师：Ruby 资深开发工程师李哲&lt;/h5&gt;&lt;h5 id="时间：2015年8月16日 10：00~11：30"&gt;时间：2015 年 8 月 16 日 10:00~11:30&lt;/h5&gt;&lt;h5 id="地点：北京市海淀区西小口路66号——东升科技园A区5号楼4层——OneAPM总部AI会议室"&gt;地点：北京市海淀区西小口路 66 号——东升科技园 A 区 5 号楼 4 层——OneAPM 总部 AI 会议室&lt;/h5&gt;&lt;h3 id="报名戳这里：我要参加"&gt;报名戳这里：&lt;a href="https://jinshuju.net/f/L2tLK0" rel="nofollow" target="_blank" title=""&gt;我要参加&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;img src="http://7xkdjw.com1.z0.glb.clouddn.com/OneAPM.png" title="" alt="Mou icon"&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Fri, 07 Aug 2015 15:53:36 +0800</pubDate>
      <link>https://ruby-china.org/topics/26815</link>
      <guid>https://ruby-china.org/topics/26815</guid>
    </item>
    <item>
      <title>Rails Girls · 七城：OneAPM 全程技术支持</title>
      <description>&lt;p&gt;来自芬兰的 &lt;a href="http://railsgirls.com/" rel="nofollow" target="_blank" title=""&gt;Rails Girls&lt;/a&gt;，是一个专为女性提供免费编程培训的公益活动，为女性提供为时 1 天的 Web 开发入门工作坊，帮助她们更好地认识编程艺术，掌握 Ruby on Rails 技术，并在最快的时间内实施自己的想法。炎炎夏日，Rails Girls 再次重装上阵，将在深圳、上海、武汉、广州、成都、西安、北京七个城市举办为期一天的 Web 开发入门工作坊。国内知名的应用性能管理平台 &lt;a href="http://www.oneapm.com/activity/railsgirls.html" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 将对本次活动给予全方位的技术支持，助力 Rails Girls 带领更多中国女孩看到「冰冷」代码背后「天马行空」的创意世界。&lt;/p&gt;

&lt;p&gt;Rails Girls 已经在全球很多国家成功地组织了工作坊，今年也是在中国开展的第四年。在本次活动中，学员会在志愿者教练的指导下，使用基于 Ruby 语言的 Rails 框架，亲手搭建一个漂亮的网站，实现自己的「小创意」。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/4525ae67b01b47a95cf2411c772dd40e.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;除了向现场的女同学教授 Ruby on Rails 技术，帮助她们迅速内实现自己的想法之外，Rails Girls 还致力于向投身科技事业的女孩提供项目规划上的指引，通过其背后强大的 Ruby 社区，让大家接触到更多的可使用的工具平台，帮助大家完善框架性能。而能够为 Ruby 提供性能监测管理的 &lt;a href="http://www.oneapm.com/activity/railsgirls.html" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 就是本次七城活动的技术支持厂商之一。&lt;/p&gt;

&lt;p&gt;OneAPM 支持包括 &lt;a href="http://www.oneapm.com/activity/railsgirls.html" rel="nofollow" target="_blank" title=""&gt;Rails&lt;/a&gt; 在内的各种 Ruby Web 框架的性能监控，查看 Rails 的应用性能表现，随时随地掌控性能。具体应用功能包括：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;性能总览：帮助用户了解服务端响应时间、吞吐量、Apdex、错误率等多种信息，方便地查看当前 Ruby 应用的整体状态。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;慢事务追踪：该功能通过分析 Web 事务或后台任务中代码类的执行时间、数据库查询耗时、第三方服务耗时占比，准确定位应用性能瓶颈。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;慢 SQL 分析：记录发生缓慢的 SQL，并可以查看相关的 URL，执行计划、参数等详细信息。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;错误信息抓取：每次发布新特性后，看看错误信息功能抓取到的 HTTP 错误。无须等到用户出现问题之后，再通过查看日志文件来查找故障的根源。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通过以上应用体验，&lt;a href="http://oneapm.com/index.html?utm_source=Common&amp;amp;utm_medium=Articles&amp;amp;utm_campaign=TechnicalArticles&amp;amp;from=matefiseco" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt; 帮助「程序媛」们打造一个满「十分」的编程作业。Rails Girls 也是一场聚会，这里有一拍即合的创业伙伴，也有志趣相投的朋友、知己和爱人。同时也能够帮助更多有梦想的女孩进入蓬勃发展的互联网行业，实现自己的创意和人生理想。&lt;/p&gt;

&lt;p&gt;OneAPM 希望用自由开放的态度带给大家更多实践的机会，带领大家拥抱这个全新的技术世界。布道、引导、交流、探讨……只要你有一颗好奇心，不要犹豫，赶快来&lt;a href="https://jinshuju.net/f/imuuNd" rel="nofollow" target="_blank" title=""&gt;报名参加&lt;/a&gt;吧！OneAPM 将携手 Rails Girls，一起铸就女孩们的青春梦！&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Thu, 06 Aug 2015 10:52:49 +0800</pubDate>
      <link>https://ruby-china.org/topics/26793</link>
      <guid>https://ruby-china.org/topics/26793</guid>
    </item>
    <item>
      <title>ActiveRecord has_many 的 extension 功能</title>
      <description>&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;

  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:line_items&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stock_count = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以改写为以下的形式：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;

  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:line_items&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;out_of_stock&lt;/span&gt;
      &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"stock_count = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;out_of_stock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在某些场合下，我们想在&lt;code&gt;has_many&lt;/code&gt;的关系后执行一个自定义的方法，这个时候可以使用&lt;code&gt;has_many&lt;/code&gt;的&lt;code&gt;extension&lt;/code&gt;功能&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;本文由&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;工程师原创，欢迎大家来&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;做客，共同讨论各种技术问题，&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;提供包括&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;Ruby&lt;/a&gt;在内的主流 6 种编程语言，以及浏览器端、移动端、服务器软硬件环境的性能监测服务。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Wed, 29 Jul 2015 18:44:06 +0800</pubDate>
      <link>https://ruby-china.org/topics/26694</link>
      <guid>https://ruby-china.org/topics/26694</guid>
    </item>
    <item>
      <title>Vim 的多光标插件 - vim-multiple-cursors</title>
      <description>&lt;p&gt;周末听老罗讲了他的 FreeMac 项目，其中谈到了一些 vim 使用技巧，有位同学提到了 vim 能否实现多光标的效果，我自己是从大概 2011 年转到 vim 上的，那个时候好像确实没有这样的插件，在 2013 年左右的时候我发现有了一个，就是下面这个&lt;code&gt;vim-multiple-cursors&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="vim-multiple-cursors"&gt;vim-multiple-cursors&lt;/h2&gt;
&lt;p&gt;github: &lt;a href="https://github.com/terryma/vim-multiple-cursors" rel="nofollow" target="_blank" title=""&gt;https://github.com/terryma/vim-multiple-cursors&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="效果"&gt;效果&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/71c68569a4ccdafa82ddae02f8a8a9ce.gif" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/12949efe953981aad414e4da9fb77cb5.gif" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/e2dc95d56d8736cf444674522be936f5.gif" title="" alt=""&gt;&lt;/p&gt;
&lt;h4 id="下面是我的一些配置，仅供入门的同学们参考，:smile:"&gt;下面是我的一些配置，仅供入门的同学们参考，&lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt;
&lt;/h4&gt;
&lt;p&gt;我使用&lt;code&gt;Vundle&lt;/code&gt;来管理插件的，下面是我的 vimfiles 链接：&lt;a href="https://github.com/markgeek/vimfiles" rel="nofollow" target="_blank" title=""&gt;https://github.com/markgeek/vimfiles&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;还有一些&lt;code&gt;tmux&lt;/code&gt;，&lt;code&gt;git&lt;/code&gt;，&lt;code&gt;bash&lt;/code&gt;的配置文件：&lt;a href="https://github.com/markgeek/dots" rel="nofollow" target="_blank" title=""&gt;https://github.com/markgeek/dots&lt;/a&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Mon, 27 Jul 2015 09:55:31 +0800</pubDate>
      <link>https://ruby-china.org/topics/26656</link>
      <guid>https://ruby-china.org/topics/26656</guid>
    </item>
    <item>
      <title>OneAPM Ruby 探针本地开发模式使用简介</title>
      <description>&lt;p&gt;OneAPM 的 Ruby 探针最近的版本（1.2.0）推出了本地开发模式（目前只适用于 Rails 框架），可以帮助开发者更好的在本地提前发现初级的性能问题，让开发者更容易的找出这些潜在的问题，欢迎大家来使用啊，发现任何问题都可以和我们联系，我们会第一时间为您解决这些问题。&lt;/p&gt;

&lt;p&gt;OneAPM Ruby 探针的安装方法请参考此链接：&lt;a href="https://oneapm.kf5.com/posts/view/43717/" rel="nofollow" target="_blank" title=""&gt;https://oneapm.kf5.com/posts/view/43717/&lt;/a&gt;，不要忘记替换配置文件中的授权编号。&lt;/p&gt;

&lt;p&gt;安装 OneAPM 的 Ruby 探针后，在配置文件的&lt;code&gt;development&lt;/code&gt;节点中，启用&lt;code&gt;developer mode&lt;/code&gt;即可。&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default_settings&lt;/span&gt;
  &lt;span class="na"&gt;monitor_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;developer_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My Application (Development)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在开发模式下启动你的 server，随便访问几个页面。如果你的本地开发端口为 3000，那么开发者模式的信息展示可以访问&lt;code&gt;http://localhost:3000/oneapm&lt;/code&gt;，默认只保留最近的 100 个请求的性能分析数据。&lt;/p&gt;

&lt;p&gt;下面是几张截图：&lt;/p&gt;
&lt;h2 id="事务列表"&gt;事务列表&lt;/h2&gt;
&lt;p&gt;此列表按请求时间列出了最近的请求 URL，可以点击 URL 查看更加详细的信息。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/a81830ee83bda69859547a61040d859b.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;点击线程列表，可以查看当前 server 内的线程信息：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/d3163cd64f67d38e7be07c59a4349227.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="事务的概览信息"&gt;事务的概览信息&lt;/h2&gt;
&lt;p&gt;此页面展示了这个请求的构成信息，会提取最耗时的几项展示出来。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/cf89ceb21d8dc912311559cf6fa6dc32.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="事务的详细调用堆栈信息"&gt;事务的详细调用堆栈信息&lt;/h2&gt;
&lt;p&gt;此页面展示了 Rack 的调用、数据库调用、外部 URL 请求的相关信息。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/009965ed928f8ccd2d14c03ebe7e383d.png" title="" alt=""&gt;&lt;/p&gt;
&lt;h2 id="数据库信息"&gt;数据库信息&lt;/h2&gt;
&lt;p&gt;此页面展示了在这个请求当中发生的数据库请求信息。通过点击查询时间可以看到 SQL Explain 信息。&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/b6c8a299be9c3f912634ca89c15cc427.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;点击查询时间后的页面：&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/5c2340fd5b2a1fbd1903b64a5ef36a4c.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;欢迎大家来使用我们的 Ruby 探针开发模式。&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;本文由&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;工程师原创，欢迎大家来&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;做客，共同讨论各种技术问题，&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;提供包括&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;Ruby&lt;/a&gt;在内的主流 6 种编程语言，以及浏览器端、移动端、服务器软硬件环境的性能监测服务。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Tue, 14 Jul 2015 16:30:04 +0800</pubDate>
      <link>https://ruby-china.org/topics/26475</link>
      <guid>https://ruby-china.org/topics/26475</guid>
    </item>
    <item>
      <title>[北京][2015年7月25日] Rails 入门培训</title>
      <description>&lt;h2 id="Hello Rubist!"&gt;Hello Rubist!&lt;/h2&gt;
&lt;p&gt;Rails 应用开发入门培训开始啦！！！&lt;/p&gt;

&lt;p&gt;&lt;img src="https://l.ruby-china.com/photo/2015/b32b467797417519a4dbc2b8bbd7be5d.jpg" title="" alt=""&gt;&lt;/p&gt;
&lt;h6 id="拍摄于：国内APM领域No.1公司的秘密基地"&gt;拍摄于：国内 APM 领域 No.1 公司的秘密基地&lt;/h6&gt;
&lt;p&gt;暗恋 Ruby 已久却又没有太多开发经验的小伙伴别紧张，
这是&lt;strong&gt;零基础&lt;/strong&gt;也可以参与的入门级别培训。
作为一家&lt;strong&gt;专注技术&lt;/strong&gt;的有诚意的公司，
我们希望更多人了解&lt;strong&gt;ROR&lt;/strong&gt;的魅力，参与敏捷开发。
届时将由帅气的资深 Ruby 开发工程师带来 Ruby On Rails 技术分享，
此外零食，饮料，帅哥，美女也都可以有！&lt;/p&gt;
&lt;h3 id="完全免费！ 限30人！ 妹子优先！"&gt;
&lt;em&gt;完全免费！&lt;/em&gt; &lt;em&gt;限 30 人！&lt;/em&gt; &lt;em&gt;妹子优先！&lt;/em&gt;
&lt;/h3&gt;&lt;h3 id="Ruby爱好者速速报名！"&gt;&lt;em&gt;Ruby 爱好者速速报名！&lt;/em&gt;&lt;/h3&gt;&lt;h6 id="报名截止日期：2015年7月21日"&gt;报名截止日期：2015 年 7 月 21 日&lt;/h6&gt;&lt;h5 id="培训内容："&gt;培训内容：&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Rails 入门&lt;/li&gt;
&lt;li&gt;Rails 的流行插件及使用简介&lt;/li&gt;
&lt;li&gt;一分钟登陆、注册、忘记密码的实现&lt;/li&gt;
&lt;li&gt;一分钟上传文件的实现&lt;/li&gt;
&lt;li&gt;最简单的 web 表单实现&lt;/li&gt;
&lt;li&gt;三分钟微博实现&lt;/li&gt;
&lt;li&gt;应用 bootstrap&lt;/li&gt;
&lt;li&gt;应用 font-awesome&lt;/li&gt;
&lt;li&gt;一分钟查看应用性能&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="建议准备："&gt;建议准备：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;笔记本电脑&lt;/li&gt;
&lt;li&gt;Rails 环境 (推荐使用 Mac OS 或 Linux）
（不会安环境？&lt;a href="https://ruby-china.org/wiki/install_ruby_guide" title=""&gt;可以参考这里&lt;/a&gt;）&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;
&lt;h5 id="讲师：Ruby资深开发工程师李哲"&gt;讲师：Ruby 资深开发工程师李哲&lt;/h5&gt;&lt;h5 id="时间：2015年7月25日 10：00~11：30"&gt;时间：2015 年 7 月 25 日 10:00~11:30&lt;/h5&gt;&lt;h5 id="地点：北京市海淀区西小口路66——东升科技园A区5号楼4层——OneAPM总部AI会议室"&gt;地点：北京市海淀区西小口路 66——东升科技园 A 区 5 号楼 4 层——OneAPM 总部 AI 会议室&lt;/h5&gt;
&lt;p&gt;报名戳这里  &lt;a href="https://jinshuju.net/f/x2Xw1Z" rel="nofollow" target="_blank" title=""&gt;我要参加&lt;/a&gt;
&lt;img src="http://7xkdjw.com1.z0.glb.clouddn.com/OneAPM.png" title="" alt="Mou icon"&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Tue, 14 Jul 2015 16:27:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/26474</link>
      <guid>https://ruby-china.org/topics/26474</guid>
    </item>
    <item>
      <title>ActionCable 0.1.0 发布了，以后 Rails 里用 WebSocket 就简单多了</title>
      <description>&lt;p&gt;&lt;strong&gt;ActionCable 0.1.0&lt;/strong&gt; 发布了，以后用 Rails 集成 WebSocket 就更简单了。&lt;/p&gt;

&lt;p&gt;前期的代码基本都是&lt;a href="https://github.com/dhh" rel="nofollow" target="_blank" title=""&gt;dhh&lt;/a&gt;和他在 basecamp 的同事&lt;a href="https://github.com/lifo" rel="nofollow" target="_blank" title=""&gt;lifo&lt;/a&gt;两个人完成的，lifo 也是框架&lt;a href="https://github.com/lifo/cramp" rel="nofollow" target="_blank" title=""&gt;cramp&lt;/a&gt;的作者&lt;/p&gt;

&lt;p&gt;详见下面的链接：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/actioncable" rel="nofollow" target="_blank" title=""&gt;https://github.com/rails/actioncable&lt;/a&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Fri, 10 Jul 2015 11:04:36 +0800</pubDate>
      <link>https://ruby-china.org/topics/26417</link>
      <guid>https://ruby-china.org/topics/26417</guid>
    </item>
    <item>
      <title>Ruby Profiler 详解之 StackProf-CPU 和对象分配的采样剖析</title>
      <description>&lt;h2 id="简介"&gt;简介&lt;/h2&gt;
&lt;p&gt;stackprof 是基于采样的一个调优工具，采样有什么好处呢？好处就是你可以线上使用，按照内置的算法抓取一部分数据，只影响一小部分性能。它会产生一系列的 dump 文件，然后你在线下分析这些文件，从而定位出问题，google 有一篇基于采样的论文，也基本证明了采样是可行的。而 stackprof 也是深受 google 的 perftools 的影响，采用了采样的方式来做调优。&lt;/p&gt;
&lt;h2 id="基本使用方法"&gt;基本使用方法&lt;/h2&gt;&lt;h3 id="CPU模式"&gt;CPU 模式&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;StackProf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;mode: :cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;out: &lt;/span&gt;&lt;span class="s1"&gt;'./stackprof.dump'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# 你的代码&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里我们给出一段示例代码，来作为测试目标：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"stackprof"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Compute&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m1&lt;/span&gt;
    &lt;span class="s2"&gt;"string"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m2&lt;/span&gt;
    &lt;span class="s2"&gt;"string"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;
    &lt;span class="mi"&gt;100_000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;m1&lt;/span&gt;
      &lt;span class="n"&gt;m2&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;StackProf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;mode: :cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;out: &lt;/span&gt;&lt;span class="s1"&gt;'./stackprof.dump'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="no"&gt;Compute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存为 test.rb，同时执行&lt;code&gt;ruby test.rb&lt;/code&gt;就会在当前目录下生成 stackprof.dump 文件，我们用 stackprof 打开这个文件：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stackprof stackprof.dump --text
&lt;/code&gt;&lt;/pre&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==================================
  Mode: cpu(1000)
  Samples: 1793 (0.61% miss rate)
  GC: 587 (32.74%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      1106  (61.7%)        1106  (61.7%)     Compute#m2
        98   (5.5%)          98   (5.5%)     Compute#m1
      1206  (67.3%)           2   (0.1%)     block in Compute#start
      1206  (67.3%)           0   (0.0%)     &amp;lt;main&amp;gt;
      1206  (67.3%)           0   (0.0%)     Compute#start
      1206  (67.3%)           0   (0.0%)     &amp;lt;main&amp;gt;
      1206  (67.3%)           0   (0.0%)     block in &amp;lt;main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里可以很明显的看出是 m2 方法比较慢，占据了大部分的执行时间，相比其他的调优工具，它只是列出了用户自己的方法所占时间比，在 ruby-prof 中的测试中，它是会显示&lt;code&gt;String#*&lt;/code&gt;这个方法的占比的，但是对于我们来说，它的意义不大，而 stackprof 是不会理会标准库里的方法的。同时 stackprof 也是可以过滤方法的，比如我们发现了 m2 这个方法有问题，那么就可以把它过滤出来，看看细节：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stackprof stackprof.dump --text --method 'Compute#m2'

Compute#m2 (/Users/lizhe/Workspace/ruby-performance-tuning/test.rb:9)
  samples:  1106 self (61.7%)  /   1106 total (61.7%)
  callers:
    1106  (  100.0%)  block in Compute#start
  code:
                                  |     9  |   end
 1106   (61.7%) /  1106  (61.7%)  |    10  |
                                  |    11  |   def start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们可以看到 m2 这个方法定义在哪一个文件的哪一行，同时是谁调用了它，以及还显示了它在源码中的上下文。假如有多个方法调用了 m2，还会显示出这几个方法，以及他们调用 m2 所占的比例，也就是上面的 callers 部分，因为只有一个 start 方法调用了 m2，所以它是 100%。&lt;/p&gt;
&lt;h3 id="对象分配模式（内存占用排查）"&gt;对象分配模式（内存占用排查）&lt;/h3&gt;
&lt;p&gt;只需要把&lt;code&gt;mode&lt;/code&gt;改为&lt;code&gt;object&lt;/code&gt;即可，输出的结果则变成对象分配的数量以及在哪里分配的，这里看一个小例子：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m1&lt;/span&gt;
  &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="s2"&gt;"even"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"odd"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;m1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如何知道这段代码的执行会带来多少的对象分配呢？可以用 stackprof 来做这件事：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"stackprof"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m1&lt;/span&gt;
  &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="s2"&gt;"even"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"odd"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;StackProf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="ss"&gt;mode: :object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;out: &lt;/span&gt;&lt;span class="s1"&gt;'stackprof.dump'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;m1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样来分析输出的文件&lt;code&gt;stackprof.dump&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==================================
  Mode: object(1)
  Samples: 1002 (0.00% miss rate)
  GC: 0 (0.00%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
      1000  (99.8%)        1000  (99.8%)     block in Object#m1
      1002 (100.0%)           2   (0.2%)     Object#m1
      1002 (100.0%)           0   (0.0%)     block in &amp;lt;main&amp;gt;
      1002 (100.0%)           0   (0.0%)     &amp;lt;main&amp;gt;
      1002 (100.0%)           0   (0.0%)     &amp;lt;main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过结果可以看出，共有 1002 次对象分配，在 m1 的 block 中有 1000 次分配，除去这 1000 次，还有 2 次。你能知道为什么是 1002 次吗？&lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt;，自己想一想吧。试着把程序改成下面这样，自己运行一下 stackprof 试一试：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"stackprof"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m1&lt;/span&gt;
  &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;  &lt;span class="s2"&gt;"even"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"odd"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;StackProf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt; &lt;span class="ss"&gt;mode: :object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;out: &lt;/span&gt;&lt;span class="s1"&gt;'stackprof.dump'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;m1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="在rack中的使用方法"&gt;在 rack 中的使用方法&lt;/h2&gt;
&lt;p&gt;stackprof 本身实现了一个 rack middleware，所以可以很方便的挂载到一个 rack 应用中：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="no"&gt;StackProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Middleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;enabled: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mode: :cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;save_every: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 rails 中使用，先在 Gemfile 中添加 stackprof，然后添加 middleware：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="no"&gt;StackProf&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Middleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;enabled: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mode: :cpu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;save_every: &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后请求你的应用，多请求几次，每 5 秒钟它会保存一次输出结果到 tmp 目录中，查看其中某一个结果：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==================================
  Mode: cpu(1000)
  Samples: 155 (0.00% miss rate)
  GC: 11 (7.10%)
==================================
     TOTAL    (pct)     SAMPLES    (pct)     FRAME
        18  (11.6%)          18  (11.6%)     Hike::Index#entries
        12   (7.7%)          12   (7.7%)     Hike::Index#stat
         9   (5.8%)           9   (5.8%)     #&amp;lt;Module:0x007fb72a0c7b08&amp;gt;.load_with_autoloading
        18  (11.6%)           9   (5.8%)     Sprockets::Cache::FileStore#[]
         6   (3.9%)           6   (3.9%)     block (2 levels) in BindingOfCaller::BindingExtensions#callers
         5   (3.2%)           5   (3.2%)     Time.parse
         5   (3.2%)           5   (3.2%)     Sprockets::Mime#mime_types
         5   (3.2%)           5   (3.2%)     Pathname#chop_basename
         4   (2.6%)           4   (2.6%)     block in ActionView::PathResolver#find_template_paths
         4   (2.6%)           4   (2.6%)     block in BetterErrors::ExceptionExtension#set_backtrace
        15   (9.7%)           3   (1.9%)     block in ActiveSupport::Dependencies#load_file
         2   (1.3%)           2   (1.3%)     Temple::Mixins::CompiledDispatcher::DispatchNode#initialize
         5   (3.2%)           2   (1.3%)     ActionDispatch::Cookies::EncryptedCookieJar#initialize
         2   (1.3%)           2   (1.3%)     ActiveSupport::KeyGenerator#generate_key
         2   (1.3%)           2   (1.3%)     block in ActionView::PathResolver#query
         4   (2.6%)           2   (1.3%)     Slim::Parser#initialize
       113  (72.9%)           2   (1.3%)     ActionView::Renderer#render_template
         2   (1.3%)           2   (1.3%)     Hike::Trail#stat
         2   (1.3%)           2   (1.3%)     block in ActiveSupport::Dependencies#search_for_file
        22  (14.2%)           2   (1.3%)     block in Temple::Filters::MultiFlattener#on_multi
        20  (12.9%)           2   (1.3%)     Temple::Filters::ControlFlow#dispatcher
        15   (9.7%)           2   (1.3%)     ActionView::Renderer#render_partial
         1   (0.6%)           1   (0.6%)     block in Slim::Parser#initialize
         1   (0.6%)           1   (0.6%)     Pathname#prepend_prefix
         1   (0.6%)           1   (0.6%)     String#blank?
         1   (0.6%)           1   (0.6%)     ActiveSupport::SafeBuffer#initialize
        10   (6.5%)           1   (0.6%)     Sprockets::Asset#dependency_fresh?
         1   (0.6%)           1   (0.6%)     Sprockets::Asset#init_with
         1   (0.6%)           1   (0.6%)     Hike::Index#sort_matches
         1   (0.6%)           1   (0.6%)     block in ActiveSupport::Dependencies::Loadable#require
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;利用上面介绍的 stackprof 的 cpu 模式和 object 模式，你可以对你本地甚至线上的应用进行调优了，不过一搬来说，我们还是要结合 ruby-prof 一起使用。&lt;/p&gt;

&lt;p&gt;参考链接： &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tmm1/stackprof" rel="nofollow" target="_blank" title=""&gt;https://github.com/tmm1/stackprof&lt;/a&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;本文由&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;工程师原创，欢迎大家来&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;做客，共同讨论各种技术问题，&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;提供包括&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;Ruby&lt;/a&gt;在内的主流 6 种编程语言，以及浏览器端、移动端、服务器软硬件环境的性能监测服务。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Sat, 04 Jul 2015 02:03:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/26324</link>
      <guid>https://ruby-china.org/topics/26324</guid>
    </item>
    <item>
      <title>Ruby 基础 - RubyGem，如何测试 Gem</title>
      <description>&lt;p&gt;上一节：&lt;a href="https://ruby-china.org/topics/26292" title=""&gt;Ruby 基础 - RubyGem，如何开发一个自己的 Gem&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="如何测试一个Gem"&gt;如何测试一个 Gem&lt;/h2&gt;
&lt;p&gt;gem 开发完了，想要给别人用，那就需要测试啊，测试一个 gem 其实很简单，这里我们用 minitest 为例，rspec 也一样适用。先来看看我们当前这个 gem 的目录结构：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-rw-rw-r-- 1 lizhe lizhe   90  7月  2 15:52 Gemfile
-rw-rw-r-- 1 lizhe lizhe  379  7月  3 10:09 Gemfile.lock
drwxrwxr-x 3 lizhe lizhe 4096  7月  2 15:52 lib
-rw-rw-r-- 1 lizhe lizhe 1062  7月  2 15:52 LICENSE.txt
-rw-rw-r-- 1 lizhe lizhe  923  7月  3 10:09 mygem.gemspec
drwxrwxr-x 2 lizhe lizhe 4096  7月  2 18:33 pkg
-rw-rw-r-- 1 lizhe lizhe  187  7月  3 10:35 Rakefile
-rw-rw-r-- 1 lizhe lizhe  556  7月  2 15:52 README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;打开 mygem.gemspec，添加&lt;code&gt;minitest&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"minitest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 5.7.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行&lt;code&gt;bundle install&lt;/code&gt;安装&lt;code&gt;minitest&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;新建一个&lt;code&gt;test&lt;/code&gt;文件夹，存放我们的测试的用例，然后新建一个&lt;code&gt;test_helper.rb&lt;/code&gt;文件，放在里面。&lt;code&gt;test_helper.rb&lt;/code&gt;的内容如下：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vg"&gt;$LOAD_PATH&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"./lib"&lt;/span&gt; &lt;span class="c1"&gt;# 把lib添加到load path&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'minitest/autorun'&lt;/span&gt;  &lt;span class="c1"&gt;# 引进minitest&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mygem'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再来新建一个测试用例，&lt;code&gt;test_mygem.rb&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"test_helper"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MygemTest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Minitest&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Test&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_hello_output&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Mygem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"hello from my gem"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在就来执行测试吧：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ruby test/test_mygem.rb

/home/lizhe/.rvm/rubies/ruby-2.1.5/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- test_helper (LoadError)
    from /home/lizhe/.rvm/rubies/ruby-2.1.5/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:54:in `require'
    from test/test_mygem.rb:1:in `&amp;lt;main&amp;gt;'  
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出错了！找不到&lt;code&gt;test_helper&lt;/code&gt;，因为它没有在加载路径里嘛，那就来换个方式，&lt;code&gt;require_relative 'test_helper'&lt;/code&gt;，因为我们的命令是在 gem 根目录下的，所以相对路径就是当前的路径，如果是在 test 目录下执行，就需要写成&lt;code&gt;require_relative '../test_helper'&lt;/code&gt;了，还挺麻烦。好，执行一下试一试：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ruby test/test_mygem.rb 

Run options: --seed 30741

# Running:

.

Finished in 0.000793s, 1260.9959 runs/s, 1260.9959 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="利用Rake::TestTask简化测试流程"&gt;利用 Rake::TestTask 简化测试流程&lt;/h2&gt;
&lt;p&gt;前面的测试方法中，我们要手动添加 lib 目录到 load path，然后在每个测试用例文件中要&lt;code&gt;require_relative 'test_helper'&lt;/code&gt;，很是麻烦，现在来简化这一个流程。&lt;/p&gt;

&lt;p&gt;首先添加&lt;code&gt;Rake::TestTask&lt;/code&gt;到&lt;code&gt;Rakefile&lt;/code&gt;中：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rake/testtask'&lt;/span&gt;

&lt;span class="no"&gt;Rake&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;libs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'test'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'lib'&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test/test_*.rb"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在把 test_helper 中的&lt;code&gt;$LOAD_PATH &amp;lt;&amp;lt; './lib'&lt;/code&gt;去掉，再把测试用例文件中的&lt;code&gt;require_relative&lt;/code&gt;替换为&lt;code&gt;require&lt;/code&gt;，因为 rak test task 已经把 test 和 lib 两个目录都添加到 load path 中了，然后执行&lt;code&gt;rake test&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rake test

Run options: --seed 29947

# Running:

.

Finished in 0.000969s, 1031.6447 runs/s, 1031.6447 assertions/s.

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;进一步简化，每个测试用例文件都要&lt;code&gt;require 'test_helper'&lt;/code&gt;，也是够麻烦的，能不能让它自动执行这个动作呢？可以，只需要再加上一个选项即可：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rake/testtask'&lt;/span&gt;

&lt;span class="no"&gt;Rake&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;libs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'test'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'lib'&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test/test_*.rb"&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ruby_opts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"-r test_helper"&lt;/span&gt; &lt;span class="c1"&gt;# 添加ruby运行参数，require指定的文件&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在把测试用例中的&lt;code&gt;require 'test_helper'&lt;/code&gt;这一行也去掉，执行&lt;code&gt;rake test&lt;/code&gt;，同样可以运行测试，又少写了一行，&lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt;&lt;/p&gt;

&lt;p&gt;现在来设置默认的 task：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rake/testtask'&lt;/span&gt;

&lt;span class="no"&gt;Rake&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;libs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'test'&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'lib'&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"test/test_*.rb"&lt;/span&gt;
  &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ruby_opts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;"-r test_helper"&lt;/span&gt; &lt;span class="c1"&gt;# 添加ruby运行参数，require指定的文件&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:default&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样我就可以直接执行&lt;code&gt;rake&lt;/code&gt;就可以跑测试了，连那个&lt;code&gt;test&lt;/code&gt;都省了。&lt;/p&gt;

&lt;p&gt;如果我们有多个测使用例，这个 rake test task 会跑所有测试，如果想跑指定的某一个怎么做呢？指定一个 TEST 参数即可：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rake test TEST=test/test_mygem.rb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;参考链接：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://ruby-doc.org/stdlib-2.2.2/libdoc/rake/rdoc/Rake/TestTask.html" rel="nofollow" target="_blank" title=""&gt;Rake::TestTask&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;本文由&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;工程师原创，欢迎大家来&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;做客，共同讨论各种技术问题，&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;提供包括&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;Ruby&lt;/a&gt;在内的主流 6 种编程语言，以及浏览器端、移动端、服务器软硬件环境的性能监测服务。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Fri, 03 Jul 2015 11:43:53 +0800</pubDate>
      <link>https://ruby-china.org/topics/26303</link>
      <guid>https://ruby-china.org/topics/26303</guid>
    </item>
    <item>
      <title>Ruby 基础 - RubyGem，如何开发一个自己的 Gem</title>
      <description>&lt;h2 id="什么是 RubyGem"&gt;什么是 RubyGem&lt;/h2&gt;
&lt;p&gt;RubyGem 是 Ruby 语言的标准源码打包格式。&lt;/p&gt;

&lt;p&gt;大家一直都在用&lt;code&gt;gem&lt;/code&gt;这个命令，但是很少有人知道这个东西是怎么来的，这里我从网上扒下一些资料汇总一下，分享给大家。最后面会有这些链接，想进一步了解的，可以点进去看看。Ruby 语言深受其他几种脚本语言的影响，其中就有 Perl，而 Perl 有个 CPAN（Comprehensive Perl Archive Network），这个东西也就像是现在的 RubyGems.org，但是当时 Ruby 是没有这样一个东西的。像 CPAN 和 RubyGem，它们仅仅是定义好的一种源码的打包和安装方式，另外还有一些组织，会提供这种免费的公共的源码包的存储，这也就现在大家每天都要使用的安装方式：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install rails
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 RubyGem 的发展历史当中，有几位重要的人物，这里也作为八卦知识给大家晒一晒，就当做大家茶余饭后的谈点吧。Ruby 社区的人应该都知道 Jim Weirich 这个人，他已经在 2014 年 2 月份去世了，是一个可爱的白胡子大叔，他和另外的四位 Rich Kilmer, Chad Fowler, David Black, Paul Brannan 在 2003 年制定了 RubyGem 的基本规范和实现，但是其实 RubyGem 最早是 Ryan Leavengood 在 2001 年开发的，可惜没有流行起来，最后到了 2003 年，前面的 5 个人经过 Ryan Leavengood 的同意，使用了 RubyGem 这个名称，开发了新版的 RubyGem，其中并没有使用 Ryan Leavengood 的代码。这里附上 rubygems 的执行文件链接，看看注释，里面有上面几个人的名字 &lt;a href="https://github.com/rubygems/rubygems/blob/master/bin/gem" rel="nofollow" target="_blank" title=""&gt;rubygems/blob/master/bin/gem&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;rubygems 有默认的源，也可以更改，国内的基本就是&lt;code&gt;https://rubygems.taobao.org&lt;/code&gt;了，有些公司有自己的需求，也会搭建自己的私源。当前的官方源为&lt;code&gt;https://rubygems.org&lt;/code&gt;，这个源也是几经辗转，早期的 Ruby 用户都知道&lt;code&gt;http://gems.rubyforge.org&lt;/code&gt;和&lt;code&gt;http://gemcutter.org&lt;/code&gt;，甚至 github 都曾经作为源使用过，也就是&lt;code&gt;http://gems.github.com&lt;/code&gt;，这三个现在都已经弃用了。&lt;/p&gt;

&lt;p&gt;看看，一个简单的&lt;code&gt;gem install&lt;/code&gt;历史还不少啊。&lt;/p&gt;
&lt;h2 id="RubyGem的基本使用方法"&gt;RubyGem 的基本使用方法&lt;/h2&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem install rails  //安装rails
gem install rails -v 4.2.0   //安装指定版本的rails
gem search rails  //查找所有名称中含有rails的gem
gem search ^rails  //查找所有名称中以rails开头的gem
gem search ^rails -d  //查找所有名称中以rails开头的gem，并显示描述
gem build package.gemspec  //构建一个gem，就是把你自己写的gem源码，打包成一个.gem文件
gem push pack-1.0.gem  //发布到源上，默认是rubygems.org
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里只是简单列出了最常用的使用方法，大家看看就好，命令很有限，也很简单，执行&lt;code&gt;gem --help&lt;/code&gt;，基本上所有的东西你都能 10 分钟内学会。&lt;/p&gt;
&lt;h2 id="如何制作一个自己的RubyGem"&gt;如何制作一个自己的 RubyGem&lt;/h2&gt;
&lt;p&gt;前几年还是有这样那样的工具，现在用&lt;code&gt;bundler&lt;/code&gt;就够了。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ bundler gem mygem
      create  mygem/Gemfile
      create  mygem/Rakefile
      create  mygem/LICENSE.txt
      create  mygem/README.md
      create  mygem/.gitignore
      create  mygem/mygem.gemspec
      create  mygem/lib/mygem.rb
      create  mygem/lib/mygem/version.rb
Initializing git repo in /home/lizhe/Workspace/mygem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;一个 bundler 命令就搞定了。来看看 mygem 这个文件夹下的东西：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total 24
-rw-rw-r-- 1 lizhe lizhe   90  7月  2 15:52 Gemfile
drwxrwxr-x 3 lizhe lizhe 4096  7月  2 15:52 lib
-rw-rw-r-- 1 lizhe lizhe 1062  7月  2 15:52 LICENSE.txt
-rw-rw-r-- 1 lizhe lizhe  850  7月  2 15:52 mygem.gemspec
-rw-rw-r-- 1 lizhe lizhe   29  7月  2 15:52 Rakefile
-rw-rw-r-- 1 lizhe lizhe  556  7月  2 15:52 README.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在来看看 gemspec 这个文件，它描述了这个 Gem 的各种信息&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# coding: utf-8&lt;/span&gt;
&lt;span class="n"&gt;lib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'../lib'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vg"&gt;$LOAD_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vg"&gt;$LOAD_PATH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'mygem/version'&lt;/span&gt;

&lt;span class="no"&gt;Gem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Specification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"mygem"&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Mygem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;VERSION&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authors&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lizhe"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lizhe@oneapm.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{TODO: Write a short summary. Required.}&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;description&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{TODO: Write a longer description. Optional.}&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;homepage&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;license&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"MIT"&lt;/span&gt;

  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;files&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`git ls-files -z`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\x0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executables&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;%r{^bin/}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test_files&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;%r{^(test|spec|features)/}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require_paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"bundler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 1.7"&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_development_dependency&lt;/span&gt; &lt;span class="s2"&gt;"rake"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 10.0"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我发现有人看到这个文件的内容时，倒是关心那个&lt;code&gt;'git ls-files -z'.split("\x0")&lt;/code&gt;是什么意思？以及那个&lt;code&gt;\x0&lt;/code&gt;是什么？附上一个链接，解释一下，&lt;a href="http://stackoverflow.com/questions/25192836/what-does-the-ruby-method-split-x0-return" rel="nofollow" target="_blank" title=""&gt;参考链接&lt;/a&gt;。这个文件最上面先把 lib 文件夹添加到 load path 中，Gem::Specification 的第一部分主要是描述这个 gem 的信息，包括名称，版本等等，第二部分是这个 gem 都包括哪些文件，执行文件，测试文件以及哪些路径下的文件可以添加到 load path 中。第三部分是开发 mygem 需要依赖的其他 gem。这些信息都可以自定义，先按照默认走。让我们 build 第一个 gem 吧。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rake build

rake aborted!
WARNING:  See http://guides.rubygems.org/specification-reference/ for help
ERROR:  While executing gem ... (Gem::InvalidSpecificationException)
    "FIXME" or "TODO" is not a description
/home/lizhe/.rvm/gems/ruby-2.1.5@global/gems/bundler-1.7.12/lib/bundler/gem_helper.rb:149:in `sh'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/gems/bundler-1.7.12/lib/bundler/gem_helper.rb:57:in `build_gem'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/gems/bundler-1.7.12/lib/bundler/gem_helper.rb:39:in `block in install'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/bin/ruby_executable_hooks:15:in `eval'
/home/lizhe/.rvm/gems/ruby-2.1.5@global/bin/ruby_executable_hooks:15:in `&amp;lt;main&amp;gt;'
Tasks: TOP =&amp;gt; build
(See full trace by running task with --trace)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个警告是提醒我们需要替换 gemspec 中的&lt;code&gt;FIXME&lt;/code&gt;和&lt;code&gt;TODO&lt;/code&gt;，这个警告如果不解决是无法 build 一个 gem 的，直接删除掉 summary 和 description 中的&lt;code&gt;TODO&lt;/code&gt;：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{Write a short summary. Required.}&lt;/span&gt;
&lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;description&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;%q{Write a longer description. Optional.}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再来执行：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rake build

mygem 0.0.1 built to pkg/mygem-0.0.1.gem.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好了，第一个 gem 诞生了。它就在当前目录的 pkg 下：mygem-0.0.1.gem。如何使用呢？不考虑 bundler 的情况下，如果你开起了一个 irb 或者 pry 的 session 时，一般都会这样写：&lt;code&gt;require "mygem"&lt;/code&gt;，如果你现在这样做，那肯定不行，因为它还没有被安装到 ruby 的 load path 中，那就把它安装上。&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rake install

mygem 0.0.1 built to pkg/mygem-0.0.1.gem.
mygem (0.0.1) installed.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装好了，那就来使用一下，打开 irb：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require "mygem"
=&amp;gt; true
Mygem
=&amp;gt; Mygem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看，已经可以使用这个 module 了，不过这个 gem 啥也干不了，那么我们就给它添加一个方法吧，打开 lib/mygem.rb，添加一个方法：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"mygem/version"&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Mygem&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;
    &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="s2"&gt;"hello from my gem"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;保存，然后执行&lt;code&gt;rake install&lt;/code&gt;，这个命令会先 build 然后 install，再重新打开 irb：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;require "mygem"
=&amp;gt; true
Mygem.hello
=&amp;gt; "hello from my gem"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;能够正常运行了，那就来发布第一个 gem 吧：&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rake release
// 输入你在rubygems.org上的账号和密码
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你的一个 rails 应用正好需要输出一个&lt;code&gt;hello from my gem&lt;/code&gt;，那么现在你可以在 Gemfile 中添加这个 gem 了：&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'mygem'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加完执行&lt;code&gt;bundle install&lt;/code&gt;，你就可以在你的 rails 应用中使用它了。&lt;img title=":smile:" alt="😄" src="https://twemoji.ruby-china.com/2/svg/1f604.svg" class="twemoji"&gt;&lt;/p&gt;

&lt;p&gt;下一节：&lt;a href="https://ruby-china.org/topics/26303" title=""&gt;Ruby 基础 - RubyGem，如何测试 Gem&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.linuxjournal.com/article/8967" rel="nofollow" target="_blank" title=""&gt;RubyGems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.rubyinside.com/gemcutter-is-the-new-official-default-rubygem-host-2659.html" rel="nofollow" target="_blank" title=""&gt;Gemcutter Is The New Official Default RubyGem Host&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/blog/515-gem-building-is-defunct" rel="nofollow" target="_blank" title=""&gt;Gem Building is Defunct&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;

&lt;p&gt;&lt;strong&gt;本文由&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;工程师原创，欢迎大家来&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;做客，共同讨论各种技术问题，&lt;a href="http://oneapm.com/index.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;OneAPM&lt;/a&gt;提供包括&lt;a href="http://www.oneapm.com/ai/ruby.html?utm_source=RubyChina&amp;amp;utm_medium=Post&amp;amp;utm_content=lizhe&amp;amp;utm_campaign=TechnicalPost&amp;amp;from=opcofisiru" rel="nofollow" target="_blank" title=""&gt;Ruby&lt;/a&gt;在内的主流 6 种编程语言，以及浏览器端、移动端、服务器软硬件环境的性能监测服务。&lt;/strong&gt;&lt;/p&gt;</description>
      <author>oneapm</author>
      <pubDate>Thu, 02 Jul 2015 18:45:45 +0800</pubDate>
      <link>https://ruby-china.org/topics/26292</link>
      <guid>https://ruby-china.org/topics/26292</guid>
    </item>
  </channel>
</rss>
