kamal-railsbench 0.9.9.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/BUGS +2 -0
  2. data/CHANGELOG +2124 -0
  3. data/GCPATCH +73 -0
  4. data/INSTALL +75 -0
  5. data/LICENSE +222 -0
  6. data/Manifest.txt +53 -0
  7. data/PROBLEMS +56 -0
  8. data/README +337 -0
  9. data/Rakefile +51 -0
  10. data/bin/railsbench +80 -0
  11. data/config/benchmarking.rb +21 -0
  12. data/config/benchmarks.rb +21 -0
  13. data/config/benchmarks.yml +2 -0
  14. data/images/empty.png +0 -0
  15. data/images/minus.png +0 -0
  16. data/images/plus.png +0 -0
  17. data/install.rb +70 -0
  18. data/latest_changes.txt +18 -0
  19. data/lib/benchmark.rb +576 -0
  20. data/lib/railsbench/benchmark.rb +576 -0
  21. data/lib/railsbench/benchmark_specs.rb +63 -0
  22. data/lib/railsbench/gc_info.rb +158 -0
  23. data/lib/railsbench/perf_info.rb +146 -0
  24. data/lib/railsbench/perf_utils.rb +202 -0
  25. data/lib/railsbench/railsbenchmark.rb +640 -0
  26. data/lib/railsbench/version.rb +9 -0
  27. data/lib/railsbench/write_headers_only.rb +15 -0
  28. data/postinstall.rb +12 -0
  29. data/ruby184gc.patch +516 -0
  30. data/ruby185gc.patch +562 -0
  31. data/ruby186gc.patch +564 -0
  32. data/ruby19gc.patch +2425 -0
  33. data/script/convert_raw_data_files +49 -0
  34. data/script/generate_benchmarks +171 -0
  35. data/script/perf_bench +74 -0
  36. data/script/perf_comp +151 -0
  37. data/script/perf_comp_gc +113 -0
  38. data/script/perf_diff +48 -0
  39. data/script/perf_diff_gc +53 -0
  40. data/script/perf_html +103 -0
  41. data/script/perf_plot +225 -0
  42. data/script/perf_plot_gc +254 -0
  43. data/script/perf_prof +87 -0
  44. data/script/perf_run +39 -0
  45. data/script/perf_run_gc +40 -0
  46. data/script/perf_table +104 -0
  47. data/script/perf_tex +58 -0
  48. data/script/perf_times +66 -0
  49. data/script/perf_times_gc +94 -0
  50. data/script/run_urls +57 -0
  51. data/setup.rb +1585 -0
  52. data/test/railsbench_test.rb +11 -0
  53. data/test/test_helper.rb +2 -0
  54. metadata +133 -0
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.length < 1
4
+ $stderr.puts "usage: perf_prof iterations options"
5
+ $stderr.puts "example: perf_prof 100 \"-bm=default -log\""
6
+ exit 1
7
+ end
8
+
9
+ bindir = File.dirname(__FILE__)
10
+ require "#{bindir}/../lib/railsbench/perf_utils"
11
+
12
+ determine_rails_root_or_die!
13
+
14
+ perf_data_dir = (ENV['RAILS_PERF_DATA'] ||= ENV['HOME'])
15
+
16
+ iterations = ARGV[0]
17
+ options = ARGV[1]
18
+ config = ARGV[2]
19
+ benchmark = ""
20
+
21
+ ruby_prof_opts="-ruby_prof=0.1/1"
22
+ warmup="-warmup"
23
+
24
+ warmup = "" if options =~ /-warmup/
25
+ benchmark = $1 if options =~ /-bm=([^ ]+)/
26
+ if options =~ /(-ruby_prof=[^ ]+)/
27
+ ruby_prof_opts = $1
28
+ options = options.sub($1, '')
29
+ end
30
+ profile_type = 'graph'
31
+ if options =~ /(-profile_type=([^ ]+))/
32
+ profile_type = $2
33
+ ruby_prof_opts << " " << $1
34
+ options = options.sub($1, '')
35
+ end
36
+ extension = case profile_type
37
+ when 'grind' then 'dat'
38
+ when 'flat' then 'txt'
39
+ else 'html'
40
+ end
41
+ date = Time.now.strftime '%m-%d'
42
+
43
+ if config
44
+ benchmark_file="#{perf_data_dir}/#{date}.#{benchmark}.#{config}.#{profile_type}.#{extension}"
45
+ else
46
+ benchmark_file="#{perf_data_dir}/perf_run.#{benchmark}.#{profile_type}.#{extension}"
47
+ end
48
+ ENV['RAILS_BENCHMARK_FILE'] = benchmark_file
49
+
50
+ set_gc_variables([options])
51
+ disable_gc_stats
52
+
53
+ null = (RUBY_PLATFORM =~ /win32/) ? 'nul' : '/dev/null'
54
+
55
+ perf_options="#{iterations} #{options} #{warmup} #{ruby_prof_opts}"
56
+ perf_cmd = "ruby #{bindir}/run_urls #{perf_options} >#{null}"
57
+ system(perf_cmd) || die("perf_prof: #{perf_cmd} returned #{$?}")
58
+
59
+ benchmark_file.sub!('.multi.', '.stack.') if profile_type == 'multi'
60
+ puts "profile data written to #{benchmark_file}"
61
+
62
+ if profile_type == 'grind'
63
+ system("kcachegrind #{benchmark_file} 2>/dev/null &") unless RUBY_PLATFORM =~ /win32/
64
+ else
65
+ case RUBY_PLATFORM
66
+ when /win32/ then system("start #{benchmark_file.gsub(/\//, '\\')}")
67
+ when /darwin/ then system("osascript -e 'tell application \"Safari\" to open location \"#{benchmark_file}\"'")
68
+ end
69
+ end
70
+
71
+ __END__
72
+
73
+ # Copyright (C) 2005-2008 Stefan Kaes
74
+ #
75
+ # This program is free software; you can redistribute it and/or modify
76
+ # it under the terms of the GNU General Public License as published by
77
+ # the Free Software Foundation; either version 2 of the License, or
78
+ # (at your option) any later version.
79
+ #
80
+ # This program is distributed in the hope that it will be useful,
81
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
82
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83
+ # GNU General Public License for more details.
84
+ #
85
+ # You should have received a copy of the GNU General Public License
86
+ # along with this program; if not, write to the Free Software
87
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.length == 0 || ARGV.length > 3 || ARGV.first == 'help'
4
+ $stderr.puts "usage: perf_run iterations options [conf-name]"
5
+ $stderr.puts "example: perf_run 100 \"-bm=default -log\" pdata"
6
+ exit 1
7
+ end
8
+
9
+ bindir = File.dirname(__FILE__)
10
+ require "#{bindir}/../lib/railsbench/perf_utils"
11
+
12
+ determine_rails_root_or_die!
13
+
14
+ iterations = ARGV[0]
15
+ options = ARGV[1]
16
+
17
+ benchmark = "default"
18
+ benchmark = $1 if options =~ /-bm=([^ ]+)/
19
+
20
+ benchmark_file = benchmark_file_name(benchmark, ARGV[2])
21
+ perf_run("perf_run", iterations, options, benchmark_file)
22
+
23
+ __END__
24
+
25
+ # Copyright (C) 2005-2008 Stefan Kaes
26
+ #
27
+ # This program is free software; you can redistribute it and/or modify
28
+ # it under the terms of the GNU General Public License as published by
29
+ # the Free Software Foundation; either version 2 of the License, or
30
+ # (at your option) any later version.
31
+ #
32
+ # This program is distributed in the hope that it will be useful,
33
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
34
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
+ # GNU General Public License for more details.
36
+ #
37
+ # You should have received a copy of the GNU General Public License
38
+ # along with this program; if not, write to the Free Software
39
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.length < 2 || ARGV.first == 'help'
4
+ $stderr.puts "usage: perf_run_gc iterations options [conf-name]"
5
+ $stderr.puts "example: perf_run_gc 100 \"-bm=default -log\" pdata"
6
+ exit 1
7
+ end
8
+
9
+ bindir = File.dirname(__FILE__)
10
+ require "#{bindir}/../lib/railsbench/perf_utils"
11
+
12
+ determine_rails_root_or_die!
13
+
14
+ iterations = ARGV[0]
15
+ options = ARGV[1]
16
+
17
+ benchmark = "default"
18
+ benchmark = $1 if options =~ /-bm=([^ ]+)/
19
+
20
+ benchmark_file = benchmark_file_name(benchmark, ARGV[2], "", :gc)
21
+
22
+ perf_run_gc("perf_run_gc", iterations, options, benchmark_file)
23
+
24
+ __END__
25
+
26
+ # Copyright (C) 2005-2008 Stefan Kaes
27
+ #
28
+ # This program is free software; you can redistribute it and/or modify
29
+ # it under the terms of the GNU General Public License as published by
30
+ # the Free Software Foundation; either version 2 of the License, or
31
+ # (at your option) any later version.
32
+ #
33
+ # This program is distributed in the hope that it will be useful,
34
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
35
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36
+ # GNU General Public License for more details.
37
+ #
38
+ # You should have received a copy of the GNU General Public License
39
+ # along with this program; if not, write to the Free Software
40
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
4
+ require 'railsbench/perf_info'
5
+
6
+ # extract options
7
+
8
+ selection = []
9
+ title = "Performance Graph"
10
+ files = []
11
+ names = []
12
+ labels = []
13
+ perf_data = []
14
+ font_size = 14
15
+ output_file = "graph.png"
16
+ colors = nil
17
+
18
+ ARGV.each do |arg|
19
+ case arg
20
+ when /^-only=(.*)$/
21
+ selection = $1.split(',').map{|s| s.strip.to_i}
22
+ when /^-title=(.*)$/
23
+ title = $1 unless $1.strip.empty?
24
+ when '-line'
25
+ graph_type = Gruff::Line
26
+ when '-bar'
27
+ graph_type = Gruff::Bar
28
+ when /^-width=(\d+)$/
29
+ graph_width = $1.to_i
30
+ when /^-geometry=(\d+x\d+)$/
31
+ graph_width = $1
32
+ when /^-colors=(.*)$/
33
+ colors = $1.split(/ *,/)
34
+ when /^-names=(.+)$/
35
+ names = $1.split(',')
36
+ when /^-labels=(.+)$/
37
+ labels = $1.split(',')
38
+ when /^-font_size=(\d+)$/
39
+ font_size = $1.to_i
40
+ when /^-out=(.+)$/
41
+ output_file = $1
42
+ else
43
+ files << File.open_or_die(arg)
44
+ names << File.basename(arg).sub(/\.txt$/, '').sub(/^\d\d-\d\d\.[^\.]+./, '')
45
+ end
46
+ end
47
+
48
+ files.length > 0 or die "usage: perf_table [options] file1 file2 ..."
49
+
50
+ pi = nil
51
+ files.each do |file|
52
+ pi = PerfInfo.new(file)
53
+ iter = pi.iterations
54
+ urls = pi.requests_per_key
55
+ perf_data << pi.keys.map{ |key| iter*urls/pi.timings_mean(key) }
56
+ file.close
57
+ end
58
+
59
+ selection = (1..(perf_data.last.length)).to_a if selection.empty?
60
+ if labels.empty?
61
+ labels = pi.keys.restrict_to(selection.map{|i| i-1})
62
+ end
63
+ perf_data = perf_data.map{|d| d.restrict_to(selection.map{|i| i-1})}
64
+
65
+ #puts selection.inspect
66
+ #puts labels.length
67
+ #puts labels.inspect
68
+ #puts perf_data.length
69
+ #puts perf_data.inspect
70
+ #puts names.inspect
71
+
72
+ # puts labels.zip(perf_data).inspect
73
+ puts "<table border=1>"
74
+ puts "<tr><td></td>"
75
+ labels.each{|l| puts "<th>#{l}</th>"}
76
+ puts "</tr>"
77
+ names.zip(perf_data).each do |row|
78
+ puts "<tr>"
79
+ puts "<th align='left'>#{row.first}</th>"
80
+ row.last.each do |cell|
81
+ puts "<td align='right'>#{sprintf "%6.2f", cell}</td>"
82
+ end
83
+ puts "</tr>"
84
+ end
85
+ puts "</table>"
86
+
87
+
88
+ __END__
89
+
90
+ # Copyright (C) 2007, 2008 Stefan Kaes
91
+ #
92
+ # This program is free software; you can redistribute it and/or modify
93
+ # it under the terms of the GNU General Public License as published by
94
+ # the Free Software Foundation; either version 2 of the License, or
95
+ # (at your option) any later version.
96
+ #
97
+ # This program is distributed in the hope that it will be useful,
98
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
99
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100
+ # GNU General Public License for more details.
101
+ #
102
+ # You should have received a copy of the GNU General Public License
103
+ # along with this program; if not, write to the Free Software
104
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless ARGV.include?('-notable')
4
+ puts "\\begin{tabular}{lrrrrrrr}"
5
+ $stdin.each_line do |l|
6
+ case l
7
+ when /^garbage collection/
8
+ unless ARGV.include?('-gc')
9
+ puts "\\end{tabular}"
10
+ exit
11
+ end
12
+ puts "<tr></tr><tr></tr>"
13
+ puts "<tr>"
14
+ puts "<th class='perf_header name' style='text-align:left'>GC statistics</th>"
15
+ puts "<th class='perf_header c1'>c1 total</th><th class='perf_header c2'>c2 total</th>"
16
+ puts "<th class='perf_header c1'>c1 #gc</th><th class='perf_header c2'>c2 #gc</th>"
17
+ puts "<th class='perf_header c1'>c1 gc%</th><th class='perf_header c2'>c2 #gc%</th>"
18
+ puts "<th class='perf_header factor'>c1/c2</th>"
19
+ puts "</tr>"
20
+ when /^page/
21
+ puts "\\textbf{page} & \\textbf{c1 total} & \\textbf{c2 total} & "
22
+ puts "\\textbf{c1 r/s} & \\textbf{c2 r/s} & "
23
+ puts "\\textbf{c1 ms/r} & \\textbf{c2 ms/r} & \\textbf{c1/c2}"
24
+ end
25
+ case l
26
+ when %r{^([A-Za-z0-9./?= ]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)\s+$}
27
+ puts '\\\\'
28
+ if $1.strip == "all requests"
29
+ puts "\\textit{#{$1.strip}} & "
30
+ else
31
+ puts "#{$1.strip} & "
32
+ end
33
+ puts "#{$2} & #{$3} & "
34
+ puts "#{$4} & #{$5} & "
35
+ puts "#{$6} & #{$7} & "
36
+ puts "#{$8}"
37
+ end
38
+ end
39
+ puts "\\end{tabular}"
40
+ end
41
+
42
+ __END__
43
+
44
+ # Copyright (C) 2005-2008 Stefan Kaes
45
+ #
46
+ # This program is free software; you can redistribute it and/or modify
47
+ # it under the terms of the GNU General Public License as published by
48
+ # the Free Software Foundation; either version 2 of the License, or
49
+ # (at your option) any later version.
50
+ #
51
+ # This program is distributed in the hope that it will be useful,
52
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
53
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54
+ # GNU General Public License for more details.
55
+ #
56
+ # You should have received a copy of the GNU General Public License
57
+ # along with this program; if not, write to the Free Software
58
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
4
+ require 'railsbench/perf_info'
5
+
6
+ files = []
7
+ if ARGV.length==0
8
+ $stderr.puts "usage: perf_times file1 file2 ..."
9
+ $stderr.exit 1
10
+ else
11
+ ARGV.each do |arg|
12
+ files << File.open_or_die(arg)
13
+ end
14
+ end
15
+
16
+ files.each do |file|
17
+ pi = PerfInfo.new(file)
18
+ iter = pi.iterations
19
+ options = pi.options
20
+
21
+ printf "\nperf data file: #{file.path}\n"
22
+ printf " requests=#{iter}, options=#{options}\n\n"
23
+ k = 'loading environment'
24
+ printf "%-32s %9.5f\n\n", k, pi.load_time_mean
25
+ printf "%-32s %9s %7s %7s %7s\n", 'page request', 'total', 'stddev%', 'r/s', 'ms/r'
26
+
27
+ pi.keys.each do |k|
28
+ t = pi.timings_mean(k)
29
+ devp = pi.timings_stddev_percentage(k)
30
+ urls = pi.requests_per_key
31
+ printf "%-32s %9.5f %7.4f %7.2f %7.2f\n",
32
+ truncate(k), t, devp, (iter*urls)/t, t*1000/(iter*urls)
33
+ end
34
+
35
+ printf "\n%-32s %9.5f %7.4f %7.2f %7.2f\n",
36
+ "all requests", pi.total_time_mean, pi.total_time_stddev_percentage,
37
+ pi.request_count/pi.total_time_mean, pi.total_time_mean*1000/pi.request_count
38
+
39
+ if pi.gc_stats?
40
+ printf "\n%-32s %9s %7s %7s %7s\n",
41
+ "garbage collection statistics", "time", "stddev%", "count", "total%"
42
+ printf "%-32s %9.5f %7.4f %7.2f %7.2f\n",
43
+ "", pi.gc_time_mean, pi.gc_time_stddev_percentage, pi.gc_calls_mean, (pi.gc_time_mean/pi.total_time_mean)*100
44
+ end
45
+
46
+ file.close
47
+
48
+ end
49
+
50
+ __END__
51
+
52
+ # Copyright (C) 2005-2008 Stefan Kaes
53
+ #
54
+ # This program is free software; you can redistribute it and/or modify
55
+ # it under the terms of the GNU General Public License as published by
56
+ # the Free Software Foundation; either version 2 of the License, or
57
+ # (at your option) any later version.
58
+ #
59
+ # This program is distributed in the hope that it will be useful,
60
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
61
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62
+ # GNU General Public License for more details.
63
+ #
64
+ # You should have received a copy of the GNU General Public License
65
+ # along with this program; if not, write to the Free Software
66
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ options = ""
4
+ if ARGV.length==0
5
+ puts "usage: perf_times_gc file1 file2 ..."
6
+ exit 1
7
+ end
8
+ files=[]
9
+ ARGV.each do |arg|
10
+ fn = arg
11
+ fn = fn.sub(/^\/([cdefgh])(\/)/, '\1:\2') if RUBY_PLATFORM =~ /win32/
12
+ begin
13
+ if File.stat(fn).readable?
14
+ files << File.open(fn)
15
+ else
16
+ print "file #{fn} is unreadable\n"
17
+ exit 1
18
+ end
19
+ rescue
20
+ print "file #{fn} does not exist\n"
21
+ exit 1
22
+ end
23
+ end
24
+
25
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
26
+ require 'railsbench/gc_info'
27
+
28
+ files.each_with_index do |file, idx|
29
+ puts "="*32 if idx>0
30
+
31
+ gci = GCInfo.new(file)
32
+
33
+ printf "GC data file: #{File.expand_path(file.path)}\n\n"
34
+ printf "requests processed : %9d\n", gci.num_requests
35
+ printf "collections : %9d\n", gci.collections
36
+ printf "garbage total : %9d\n", gci.garbage_produced
37
+ printf "gc time total (sec) : %12.2f\n", gci.time_total.to_f/1000
38
+ printf "garbage per request : %12.2f\n", gci.garbage_produced.to_f/gci.num_requests
39
+ printf "requests per collection: %12.2f\n", gci.num_requests.to_f/gci.collections
40
+
41
+ printf "\n %12s %8s %9s %9s\n", "mean", "stddev%", "min", "max"
42
+ number_format = "%12.2f %8.1f %9d %9d"
43
+
44
+ printf "gc time(ms): #{number_format}\n",
45
+ gci.time_mean, gci.time_stddev_percentage, gci.time_min, gci.time_max
46
+
47
+ printf "heap slots : #{number_format}\n",
48
+ gci.processed_mean, gci.processed_stddev_percentage, gci.processed_min, gci.processed_max
49
+
50
+ printf "live : #{number_format}\n",
51
+ gci.live_mean, gci.live_stddev_percentage, gci.live_min, gci.live_max
52
+
53
+ printf "freed : #{number_format}\n",
54
+ gci.freed_mean, gci.freed_stddev_percentage, gci.freed_min, gci.freed_max
55
+
56
+ printf "freelist : #{number_format}\n",
57
+ gci.freelist_mean, gci.freelist_stddev_percentage, gci.freelist_min, gci.freelist_max
58
+
59
+ printf "\nheap topology:\n"
60
+ printf "%9s %6s\n", "slot_size", "#heaps"
61
+ heaps_count = {}
62
+ gci.topology.each{|size| heaps_count[size] = (heaps_count[size] || 0) + 1}
63
+ heaps_count.keys.sort.each do |size|
64
+ printf "%9d %6d\n", size, heaps_count[size]
65
+ end
66
+
67
+ if gci.mallocs > 0
68
+ printf "\nleak anlysis:\n"
69
+ printf "mallocs/bytes : %10d / %10d\n", gci.mallocs, gci.malloced
70
+ printf "leaks/bytes : %10d / %10d\n", gci.leaks, gci.leaked
71
+ printf "leaked/request: %10.2f bytes\n", gci.leaked.to_f/gci.num_requests
72
+ end
73
+
74
+ file.close
75
+
76
+ end
77
+
78
+ __END__
79
+
80
+ # Copyright (C) 2005-2008 Stefan Kaes
81
+ #
82
+ # This program is free software; you can redistribute it and/or modify
83
+ # it under the terms of the GNU General Public License as published by
84
+ # the Free Software Foundation; either version 2 of the License, or
85
+ # (at your option) any later version.
86
+ #
87
+ # This program is distributed in the hope that it will be useful,
88
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
89
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90
+ # GNU General Public License for more details.
91
+ #
92
+ # You should have received a copy of the GNU General Public License
93
+ # along with this program; if not, write to the Free Software
94
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA