mwrap.git  about / heads / tags
LD_PRELOAD malloc wrapper + line stats for Ruby
blob ef3872b2e70909a5d1515ddc1eaa6f684acf06c5 3465 bytes (raw)
$ git show heavy:lib/mwrap_rack.rb	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
 
# Copyright (C) 2018 all contributors <mwrap@80x24.org>
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
# frozen_string_literal: true
require 'mwrap'
require 'rack'
require 'cgi'

# Usage: mwrap rackup ...
class MwrapRack
  module HtmlResponse
    def response
      [ 200, {
          'Expires' => 'Fri, 01 Jan 1980 00:00:00 GMT',
          'Pragma' => 'no-cache',
          'Cache-Control' => 'no-cache, max-age=0, must-revalidate',
          'Content-Type' => 'text/html; charset=UTF-8',
        }, self ]
    end
  end

  class Each < Struct.new(:script_name, :min, :sort)
    include HtmlResponse
    HEADER = '<tr><th>' + %w(total allocations frees mean_life max_life
                location).join('</th><th>') + '</th></tr>'
    FIELDS = %w(total allocations frees mean_life max_life location)
    def each
      Mwrap.quiet do
        t = -"Mwrap.each(#{min})"
        sn = script_name
        all = []
        f = FIELDS.dup
        sc = FIELDS.index(sort || 'total') || 0
        f[sc] = -"<b>#{f[sc]}</b>"
        f.map! do |hdr|
          if hdr.start_with?('<b>')
            hdr
          else
            -%Q(<a\nhref="#{sn}/each/#{min}?sort=#{hdr}">#{hdr}</a>)
          end
        end
        Mwrap.each(min) do |loc, total, allocations, frees, age_sum, max_life|
          mean_life = frees == 0 ? Float::INFINITY : age_sum/frees.to_f
          all << [total,allocations,frees,mean_life,max_life,loc]
        end
        all.sort_by! { |cols| -cols[sc] }

        yield(-"<html><head><title>#{t}</title></head>" \
               "<body><h1>#{t}</h1>\n" \
               "<h2>Current generation: #{GC.count}</h2>\n<table>\n" \
               "<tr><th>#{f.join('</th><th>')}</th></tr>\n")
        all.each do |cols|
          loc = cols.pop
          cols[3] = sprintf('%0.3f', cols[3]) # mean_life
          href = -(+"#{sn}/at/#{CGI.escape(loc)}").encode!(xml: :attr)
          yield(%Q(<tr><td>#{cols.join('</td><td>')}<td><a\nhref=#{
                  href}>#{-loc.encode(xml: :text)}</a></td></tr>\n))
          cols.clear
        end.clear
        yield "</table></body></html>\n"
      end
    end
  end

  class EachAt < Struct.new(:loc)
    include HtmlResponse
    HEADER = '<tr><th>size</th><th>generation</th></tr>'

    def each
      t = loc.name.encode(xml: :text)
      yield(-"<html><head><title>#{t}</title></head>" \
             "<body><h1>live allocations at #{t}</h1>" \
             "<h2>Current generation: #{GC.count}</h2>\n<table>#{HEADER}")
      loc.each do |size, generation|
        yield("<tr><td>#{size}</td><td>#{generation}</td></tr>\n")
      end
      yield "</table></body></html>\n"
    end
  end

  def r404
    [404,{'Content-Type'=>'text/plain'},["Not found\n"]]
  end

  def call(env)
    case env['PATH_INFO']
    when %r{\A/each/(\d+)\z}
      min = $1.to_i
      m = env['QUERY_STRING'].match(/\bsort=(\w+)/)
      Each.new(env['SCRIPT_NAME'], min, m ? m[1] : nil).response
    when %r{\A/at/(.*)\z}
      loc = -CGI.unescape($1)
      loc = Mwrap[loc] or return r404
      EachAt.new(loc).response
    when '/'
      n = 2000
      u = 'https://80x24.org/mwrap/README.html'
      b = -('<html><head><title>Mwrap demo</title></head>' \
          "<body><p><a href=\"each/#{n}\">allocations &gt;#{n} bytes</a>" \
          "<p><a href=\"#{u}\">#{u}</a></body></html>\n")
      [ 200, {'Content-Type'=>'text/html','Content-Length'=>-b.size.to_s},[b]]
    else
      r404
    end
  end
end

git clone https://80x24.org/mwrap.git