mwrap user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: mwrap-public@80x24.org
Subject: [PATCH 19/19] mwrap_rack: Rack app to track live allocations
Date: Mon, 16 Jul 2018 21:19:33 +0000	[thread overview]
Message-ID: <20180716211933.5835-20-e@80x24.org> (raw)
In-Reply-To: <20180716211933.5835-1-e@80x24.org>

Might as well be able to see and inspect what allocations
are alive when developing a Rack application.

Demo is available at https://80x24.org/MWRAP/each/2000 (note:
"MWRAP" is capitalized)  This is also running "repobrowse",
which will eventually replace cgit on 80x24.org, but is NOT
running the main HTTPS termination at https://80x24.org/

Note: this demo machine is 32-bit, so yes, it will overflow
---
 lib/mwrap_rack.rb | 105 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 lib/mwrap_rack.rb

diff --git a/lib/mwrap_rack.rb b/lib/mwrap_rack.rb
new file mode 100644
index 0000000..ef3872b
--- /dev/null
+++ b/lib/mwrap_rack.rb
@@ -0,0 +1,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
-- 
EW


      parent reply	other threads:[~2018-07-16 21:19 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-16 21:19 [PATCH 0/19] the heavy version of mwrap Eric Wong
2018-07-16 21:19 ` [PATCH 01/19] support per-allocation headers for per-alloc tracking Eric Wong
2018-07-16 21:19 ` [PATCH 02/19] mwrap: use malloc to do our own memalign Eric Wong
2018-07-16 21:19 ` [PATCH 03/19] hold RCU read lock to insert each allocation Eric Wong
2018-07-16 21:19 ` [PATCH 04/19] realloc: do not copy if allocation failed Eric Wong
2018-07-16 21:19 ` [PATCH 05/19] internal_memalign: do not assume real_malloc succeeds Eric Wong
2018-07-16 21:19 ` [PATCH 06/19] ensure ENOMEM is preserved in errno when appropriate Eric Wong
2018-07-16 21:19 ` [PATCH 07/19] memalign: check alignment on all public functions Eric Wong
2018-07-16 21:19 ` [PATCH 08/19] reduce stack usage from file names Eric Wong
2018-07-16 21:19 ` [PATCH 09/19] resolve real_malloc earlier for C++ programs Eric Wong
2018-07-16 21:19 ` [PATCH 10/19] allow analyzing live allocations via Mwrap[location] Eric Wong
2018-07-16 21:19 ` [PATCH 11/19] alias Mwrap.clear to Mwrap.reset Eric Wong
2018-07-16 21:19 ` [PATCH 12/19] implement accessors for SourceLocation Eric Wong
2018-07-16 21:19 ` [PATCH 13/19] mwrap_aref: quiet -Wshorten-64-to-32 warning Eric Wong
2018-07-16 21:19 ` [PATCH 14/19] fixes for FreeBSD 11.1 Eric Wong
2018-07-16 21:19 ` [PATCH 15/19] use memrchr to extract address under glibc Eric Wong
2018-07-16 21:19 ` [PATCH 16/19] do not track allocations for constructor and Init_ Eric Wong
2018-07-16 21:19 ` [PATCH 17/19] disable memalign tracking by default Eric Wong
2018-07-16 21:19 ` [PATCH 18/19] support Mwrap.quiet to temporarily disable allocation tracking Eric Wong
2018-07-16 21:19 ` Eric Wong [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://80x24.org/mwrap/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180716211933.5835-20-e@80x24.org \
    --to=e@80x24.org \
    --cc=mwrap-public@80x24.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).