ruby - 将命名配置文件样本树合并为自上而下的总和

标签 ruby profiling

我有一个名称数组,可以像这样用 Ruby 表示:

samples = [
  %w[a],
  %w[a c],
  %w[a],
  %w[a],
  %w[b],
  %w[b],
  %w[a],
  %w[a e],
  %w[a e],
  %w[a c d],
  %w[a c d],
  %w[b],
  %w[b c e],
  %w[b c e],
  %w[a c],
  %w[a e],
  %w[a e]
]

这些是采样分析器的输出,其中每个名称列表代表特定样本的调用堆栈。我想将它们显示为自上而下的命名值树,其中每个节点的值是对该特定调用路径的命中总和。

对于上面的示例输入,输出树应该是:

root:0
  a:4
    e:4
    c:2
      d:2
  b:3
    c:0
      e:2

(我不想要如上所示的 ASCII 输出,而是表示它的树结构。)

生成此输出的简单、高效的代码是什么?
我有自己的解决方案,我会将其作为答案发布,但在我看来不太理想。

编辑:我忘记包括树应该在每个级别按降序排序的事实。我添加了示例节点并更改了输出以反射(reflect)这一点。

最佳答案

[编辑] 具有函数式编程的递归 Tree 类(为了简单起见,我使用 ostruct):

require 'ostruct'

class Tree < OpenStruct 
  def self.new_from_array(plain)
    Tree.new(:node => "root", :count => 0, :children => children_from_array(plain))
  end

  def self.children_from_array(plain)
    plain.group_by(&:first).map do |node, group|
      terminal, leaves = group.map { |xs| xs.drop(1) }.partition(&:empty?)
      Tree.new(:node => node, :count => terminal.size, :children => children_from_array(leaves))
    end.sort_by(&:count).reverse    
  end

  def inspect(indent=0)
    node_info = " "*indent + "#{self.node}: #{self.count}" 
    ([node_info] + self.children.map { |tree| tree.inspect(indent+2) }).join("\n")
  end  
end

例子:

>> Tree.new_from_array(samples)
=>
root: 0
  a: 4
    e: 4
    c: 2
      d: 2
  b: 3
    c: 0
      e: 2

您可以自定义 inspect 以满足您的可视化需求。

关于ruby - 将命名配置文件样本树合并为自上而下的总和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6190021/

相关文章:

ruby - 安装 RMagick gem

ruby - 在 Shopify Ruby 中使用 "contain"运算符来处理 cart.discount_code - 不起作用

java - Thread.sleep 和 BufferedReader.readLine 在我的 java tcp 服务器中使用最多的 cpu 周期。为什么?

time - 你如何衡量一个函数执行所需的时间?

android - 使用 pg 选项在 Android 上进行分析

ruby - 处理在 keyup 事件上发生的 javascript 弹出窗口

ruby-on-rails - 清理网址

ruby-on-rails - Rails 在 Ubuntu 中使用不正确的 Ruby

c++ - vector < boolean >访问

ruby - 了解 ruby​​-prof 输出