class MetadataAnalysis

Constants

GRANULARITY
Unit

Public Class Methods

new(md) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 12
def initialize(md)
  @md = md
end

Public Instance Methods

block_length_histograms() click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 16
def block_length_histograms
  @md.devices.each do |dev|
    puts "device #{dev.dev_id}"
    block_length_histogram(dev)
    puts ""
  end
end
fragmentations() click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 24
def fragmentations
  @md.devices.each do |dev|
    puts "device #{dev.dev_id}"
    printf("  %10s %10s %10s %10s\n",
           'io size', 'seeks/io', 'distance/seek', 'distance/io')
    puts "  -------------------------------------------------"

    power = 0
    loop do
      io_size = 8 * 4 ** power

      r = fragmentation(dev, @md.superblock.data_block_size, io_size)
      break if r.nil?
      seeks, dist = r

      printf("  %10s\t%.3f\t%s\t\t%s\n",
             segments_to_human(io_size),
             seeks, segments_to_human(dist.to_i),
             segments_to_human(seeks * dist.to_i))

      power += 1
    end
  end
end

Private Instance Methods

block_length_histogram(dev) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 194
def block_length_histogram(dev)
  histogram = Hash.new {|hash, key| hash[key] = 0}

  dev.mappings.each do |m|
    histogram[nearest_power(m.length)] += m.length
  end

  format_histogram(histogram.sort)
end
format_histogram(pairs) click to toggle source

assumes the pairs are sorted

# File lib/thinp_xml/thinp/analysis.rb, line 184
def format_histogram(pairs)
  width = 80

  m = pairs.inject(0) {|m, p| m = [m, p[1]].max}

  pairs.each do |bin, count|
    printf("%-8d: %s\n", 2 ** bin, '*' * (width * count / m))
  end
end
fragmentation(dev, block_size, io_size) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 144
def fragmentation(dev, block_size, io_size)
  # Break the mappings up into logical segments.  Each segment will
  # have one or more physical segments.
  logical_segments = to_logical_segments(mappings_to_phys_segments(dev.mappings, block_size))

  total_ios = 0.0
  total_seeks = 0.0
  total_seek_distance = 0.0

  logical_segments.each do |lseg|
    # calculate the nr of different ios of |io_size| can fit into
    nr_ios = unique_ios_per_lseg(lseg, io_size, GRANULARITY)
    next if nr_ios == 0
    
    total_ios += nr_ios

    # now we look at the junctions between physical segments
    pre = 0
    post = lseg.length
    psegs = lseg.physical_segments
    if psegs.length > 1
      0.upto(psegs.length - 2) do |i|
        l = psegs[i].length
        pre += l
        post -= l
        nr_seeks = ios_that_overlap_junction(pre, post, io_size, GRANULARITY)

        total_seeks += nr_seeks

        # FIXME: check we can handle these large numbers
        total_seek_distance += nr_seeks * ((psegs[i].data_begin + psegs[i].length) - psegs[i + 1].data_begin).abs
      end
    end
  end

  (total_ios == 0) ? nil :
    [total_seeks / total_ios, total_seeks > 0 ? total_seek_distance / total_seeks : 0]
end
ios_that_overlap_junction(pre, post, io_size, granularity) click to toggle source

|pre| and |post| are the length in the lseg before and after the junction FIXME: check this

# File lib/thinp_xml/thinp/analysis.rb, line 115
def ios_that_overlap_junction(pre, post, io_size, granularity)
  pre /= granularity
  post /= granularity
  io_size /= granularity

  intersections = io_size - 1
  r = intersections

  if pre < io_size
    r -= intersections - pre
  end

  if post < io_size
    r -= intersections - post
  end

  r
end
mappings_to_phys_segments(mappings, block_size) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 76
def mappings_to_phys_segments(mappings, block_size)
  mappings.map do |m|
    PhysicalSegment.new(m.origin_begin * block_size,
                        m.data_begin * block_size,
                        m.length * block_size)
  end
end
nearest_power(n) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 204
def nearest_power(n)
  1.upto(32) do |p|
    if 2 ** p > n
      return p - 1
    end
  end
end
rand_io(max, io_size) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 72
def rand_io(max, io_size)
  round_down(rand(max - io_size), 8)
end
round_down(n, d) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 68
def round_down(n, d)
  (n / d) * d
end
segments_to_human(size) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 54
def segments_to_human(size)
  units = [Unit.new(2048 * 1024, 'g'),
           Unit.new(2048, 'm'),
           Unit.new(2, 'k')]

  units.each do |u|
    if size >= u.factor
      return "%.2f #{u.abbrev}" % [Float(size) / Float(u.factor)]
    end
  end

  "#{size * 512}b"
end
to_logical_segments(p_segs) click to toggle source

FIXME: test this

# File lib/thinp_xml/thinp/analysis.rb, line 85
def to_logical_segments(p_segs)
  l_segs = Array.new

  if p_segs.empty?
    return l_segs
  end

  while !p_segs.empty?
    a = Array.new

    p = p_segs.shift
    a << p

    while !p_segs.empty? && (p_segs[0].origin_begin == p.origin_begin + p.length)
      p = p_segs.shift
      a << p
    end

    l_segs << LogicalSegment.new(a.inject(0) {|tot, ps| tot + ps.length}, a)
  end

  l_segs
end
unique_ios_per_lseg(lseg, io_size, granularity) click to toggle source
# File lib/thinp_xml/thinp/analysis.rb, line 109
def unique_ios_per_lseg(lseg, io_size, granularity)
  (lseg.length < io_size) ? 0 : ((lseg.length - io_size) / granularity) + 1
end