On 19 May 2010, at 14:13, Heath Kehoe wrote:

> Hello all,
> 
> I have recently implemented a build system based on Rake for a decently-sized 
> project (~8000 source files) which builds code and data for several libraries 
> and applications targeting four separate platforms.
> 
> I was new to both rake and ruby when I started; and it's a testament to the 
> awesomeness of both that I was able to learn them quickly to be able to 
> implement a fairly complicated system in less than a month.
> 
> Anyway, I wanted to pass along some comments.
> 
> Firstly, when I first got stuff building with rake (replacing a build 
> environment that used gnu make) I noticed that a null build (where everything 
> was up to date) took a really long time. I used the ruby profiler and found 
> that approx. half the run time was spent doing file stats (exist? and mtime), 
> with an average of 70 calls *per file* during a rake run. As it runs under 
> Cygwin on Windows those file stat operations are more expensive than they are 
> on Linux. I should note that I'm using ruby 1.8.7 and the rake that gem 
> installed (0.8.7).

Yeah, this is a problem for ruby on windows generally, and somewhat hard to 
overcome in the generic case.

> If you look at the FileTask code, the needed? method calls File.exist? then 
> timestamp, which calls File.exist? then File.mtime. That's three stats in a 
> row right there for the file itself; then each prerequisite is asked for its 
> timestamp which generates two stats for each (for FileTasks that is). My 
> approach was to create a simple global cache that uses the filename as the 
> key and stores the file's mtime.
> Now, I'm not saying rake should adopt this specific optimization; however I 
> think you should consider some type of caching to reduce the quantity of 
> exist?/mtime calls. Perhaps the FileTask could simply cache its own 
> exist?/mtime results (invalidated when execute runs).

It's a bit hacky and incomplete, but here's an intro implementation...

  class FileTask < Task
    NOFILESTAT = File::Stat.allocate
    class << NOFILESTAT
      def mtime
        Rake::EARLY
      end
      # TODO fixup other methods that are busted by the fact we had to hack
      # with allocate.
    end

    # Is this file task needed?  Yes if it doesn't exist, or if its time stamp
    # is out of date.
    def needed?
      stat == NOFILESTAT || out_of_date?(timestamp)
    end

    # Time stamp for file task.
    def timestamp
      stat.mtime
    end

    def execute(*a)
      super.tap { @stat = nil }
    end

    private
    def stat(refresh = false)
      return @stat if @stat && !refresh
      @stat = begin
        File.stat(name)
      rescue Errno::ENOENT
        NOFILESTAT
      end
    end
  ...

_______________________________________________
Rake-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rake-devel

Reply via email to