File indexing completed on 2024-05-05 04:36:54

0001 ##
0002 # This file is part of KDevelop
0003 # Copyright (C) 2013-2015 Miquel Sabaté Solà <mikisabate@gmail.com>
0004 #
0005 # This program is free software: you can redistribute it and/or modify
0006 # it under the terms of the GNU General Public License as published by
0007 # the Free Software Foundation, either version 3 of the License, or
0008 # (at your option) any later version.
0009 #
0010 # This program is distributed in the hope that it will be useful,
0011 # but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 # GNU General Public License for more details.
0014 #
0015 # You should have received a copy of the GNU General Public License
0016 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 
0018 
0019 require 'find'
0020 require 'fileutils'
0021 require 'benchmark'
0022 
0023 
0024 # This script can be called as follows:
0025 #   --syntax -> check that there's no syntax error when parsing the Ruby
0026 #               standard library.
0027 #   --valgrind -> generate files inside the /tmp/kdev-ruby directory containing
0028 #                 the results as given by memcheck, massif and callgrind.
0029 # There's also the --memcheck, --massif and --callgrind options to run only the
0030 # specified tool instead of all of them.
0031 
0032 
0033 # Public: Print beautifully
0034 #
0035 # msg   - A String containing the message to be printed.
0036 # error - True if this is an error message, false otherwise (Default: false)
0037 def putb(msg, error = false)
0038   num = error ? 31 : 32
0039   puts "\033[#{num}m#{msg}\033[0m"
0040 end
0041 
0042 # Returns true if our beloved user requested some candy from valgrind.
0043 #
0044 # param - A String containing the name of the tool.
0045 def valgrind(param)
0046   ARGV.include?("--#{param}") || ARGV.include?('--valgrind')
0047 end
0048 
0049 # Public: execute a valgrind tool.
0050 #
0051 # tool - A String containing the name of the Valgrind's tool.
0052 # opts - A String containing the options to be passed to Valgrind.
0053 # file - A String containing the path to the log file.
0054 def execute(tool, opts, file)
0055   FileUtils.rm_rf file
0056   putb "Calling Valgrind\'s #{tool} tool with: #{opts}"
0057   `valgrind #{opts} #{PARSER} #{TMP} 1`
0058   putb "#{tool.capitalize} output left at #{file}" unless file.empty?
0059 end
0060 
0061 
0062 # Setup some basic constants
0063 TMP_D = '/tmp/kdev-ruby'
0064 TMP = File.join(TMP_D, 'stdlib.rb')
0065 PARSER = '../ruby-parser'
0066 if ENV['MRI'].nil?
0067   putb 'You have to set the MRI environment variable.', true
0068   exit
0069 end
0070 LIB = File.join(ENV['MRI'], 'lib/')
0071 
0072 
0073 # If the -c parameter has been passed, just check the syntax for each of
0074 # the files inside the MRI lib/ directory.
0075 if ARGV.include? '--syntax'
0076   res = { fails: 0, oks: 0 }
0077   Find.find(LIB) do |path|
0078     if path.end_with? '.rb'
0079       print "#{path.gsub(LIB, '')} "
0080       got = `#{PARSER} #{path}`
0081 
0082       if got.include? 'syntax error'
0083         puts '=> Fail!'
0084         res[:fails] += 1
0085       else
0086         puts '=> OK'
0087         res[:oks] += 1
0088       end
0089     end
0090   end
0091 
0092   totals = (res[:oks] + res[:fails]).to_f
0093   win = (100 * res[:oks].to_f/ totals).round(2)
0094   damn = (100 * res[:fails].to_f/ totals).round(2)
0095   puts "Holy says: Oks: #{res[:oks]} (#{win}%), Fails: #{res[:fails]} (#{damn}%)"
0096   exit
0097 end
0098 
0099 # Generate the stdlib file
0100 putb "Generating temporary file '#{TMP}' from '#{LIB}'"
0101 FileUtils.mkdir_p TMP_D
0102 FileUtils.rm_rf TMP
0103 File.open(TMP, 'a+', 0644) do |f|
0104   Find.find(LIB) do |path|
0105     next unless path.end_with? '.rb'
0106     # Writing to the file. Note that we remove __END__ so it doesn't stop
0107     # at the middle of the script.
0108     f.write IO.read(path).gsub('__END__', '')
0109   end
0110 end
0111 ok = false
0112 
0113 #
0114 # Valgrind is in da house !
0115 #
0116 
0117 if valgrind 'memcheck'
0118   file = File.join(TMP_D, 'memcheck.txt')
0119   opts = "--track-origins=yes --tool=memcheck --leak-check=full --show-reachable=yes -v --log-file=#{file}"
0120   execute 'memcheck', opts, file
0121   ok = true
0122 end
0123 
0124 if valgrind 'callgrind'
0125   callgrind = File.join(TMP_D, 'callgrind.out')
0126   opts = '--tool=callgrind -q -v --dump-instr=yes'
0127   execute 'callgrind', opts, callgrind
0128   out = Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/callgrind*").first
0129   FileUtils.mv out, callgrind
0130   ok = true
0131 end
0132 
0133 if valgrind 'massif'
0134   massif = File.join(TMP_D, 'massif.out')
0135   opts = '--tool=massif --tool=massif -q -v --stacks=yes'
0136   execute 'massif', opts, massif
0137   out = Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/massif*").first
0138   FileUtils.mv out, massif
0139   ok = true
0140 end
0141 
0142 #
0143 # Benchmarking like a boss
0144 #
0145 
0146 if ARGV.include? '--bench'
0147   Benchmark.bm do |x|
0148     x.report('parser: ') { 10.times { `#{PARSER} #{TMP}` } }
0149   end
0150   ok = true
0151 end
0152 
0153 # Try to GTFO !
0154 exit if ok
0155 
0156 #
0157 # Wow ! You're a looser !!
0158 #
0159 puts <<-USAGE
0160 Usage: ruby holy.rb [options]
0161   --syntax \t Just check the syntax parsing.
0162   --bench \t Let's benchmark this thing !
0163   --valgrind \t Execute all the tools from Valgrind that we're able to execute.
0164   --memcheck \t Just call Valgrind's memcheck tool.
0165   --massif \t Just call Valgrind's massif tool.
0166   --callgrind \t Just call Valgrind's callgrind tool.
0167 USAGE