Basic memory profiling setup.

This makes it a bit easier to profile memory usage of certain components and
plot them using Gnuplot. In the past I would write one-off scripts for this and
throw them away, only to figure out I needed them again later on.

Profiling samples are written to profile/samples and can be plotted using
corresponding Gnuplot scripts found in profile/plot. The latter requires
Gnuplot to be installed.
This commit is contained in:
Yorick Peterse 2014-04-29 13:38:56 +02:00
parent 70fcc8534c
commit 53c45c621b
6 changed files with 72 additions and 0 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@ lib/oga/xml/lexer.rb
lib/oga/xml/parser.rb lib/oga/xml/parser.rb
benchmark/fixtures/big.xml benchmark/fixtures/big.xml
profile/samples/*.txt
profile/samples/lexer/*.txt

8
profile/lexer/big_xml.rb Normal file
View File

@ -0,0 +1,8 @@
require_relative '../profile_helper'
xml = read_big_xml
lexer = Oga::XML::Lexer.new(xml)
profile_memory('lexer/big_xml')
lexer.advance { |tok| }

View File

@ -0,0 +1,20 @@
#!/usr/bin/env gnuplot
set title "Lexing 10MB of XML"
set xlabel "Sample"
set ylabel "Memory (MB)"
set yrange [0:*]
set term qt persist
set grid
set style line 1 lc rgb "#0060ad" lt 1 lw 2 pt 7 ps 1
plot "profile/samples/lexer/big_xml.txt" \
using 0:($1 / 1024 ** 2) \
with linespoints ls 1 \
title "Memory"
# vim: set ft=gnuplot:

41
profile/profile_helper.rb Normal file
View File

@ -0,0 +1,41 @@
require_relative '../lib/oga'
##
# Returns memory usage in bytes. This relies on the /proc filesystem, it won't
# work without it.
#
# @return [Fixnum]
#
def memory_usage
return File.read('/proc/self/status').match(/VmRSS:\s+(\d+)/)[1].to_i * 1024
end
##
# Reads a big XML file and returns it as a String.
#
# @return [String]
#
def read_big_xml
return File.read(File.expand_path('../../benchmark/fixtures/big.xml', __FILE__))
end
##
# Writes memory samples to a file until the thread is killed.
#
# @param [String] name The name of the samples file.
# @param [Fixnum] interval The sample interval. The default is 200 ms.
# @return [Thread]
#
def profile_memory(name, interval = 0.2)
return Thread.new do
path = File.expand_path("../samples/#{name}.txt", __FILE__)
handle = File.open(path, 'w')
handle.sync = true
loop do
handle.write("#{memory_usage}\n")
sleep(interval)
end
end
end

0
profile/samples/.gitkeep Normal file
View File

View File