[QUIZ] FasterGenerator (#66)

Newbie jumping in here.

Not being familiar with all the various Ruby packages and libs, I
first want to thank ya for posting a good set of test cases that I can
review, but was wondering if you also might post the code used to do
the timing?

I will, yes, on Sunday. :slight_smile:

I pulled down copies on the Generator library, before and after the change. I then modified the class names so they could all peacefully coexist, loaded them, and ran a trivial benchemark:

...snip..

Benchmark.bmbm do |x|
  x.report("Current Generator") do
    generator = CurrentGenerator.new(enum)
    tests.times { generator.next until generator.end? }
  end

I have small problem with this. Won't this mean the loop will only run 1 time?

The first time it correctly loops, but the next time "generator.end?" will be true, and the following 999 runs will consequently does not execute generator.next at all, right?

If we change the row to

test.times do
   generator.rewind
   generator.next until generator.end?
end

Isn't that giving us the desired test-behaviour?

/Christoffer

ยทยทยท

On Feb 10, 2006, at 17:23 , James Edward Gray II wrote:

On Feb 10, 2006, at 10:08 AM, Matthew Moss wrote:

James Edward Gray II wrote:

It would be interesting to add a testcase with an endless internal iterator. I don't know the new implementation of Generator, so I can't say whether an endless iterator should be supported.

That's an interesting point we will certainly talk more about as we start to see some solutions. Generator *can* handle endless iterators. Quiz solvers can decide whether or not to limit themselves with that additional requirement...

More importantly than endless generators, it seems to me, is ones that depend on other shared state. The hardest part about generators is the fact that (to do them correctly) they must be suspended between calls to g.yield. Here's an illustration of what I mean:

    x = 1
    g = Generator.new do |g|
      5.times {|i| g.yield [x,i].max}
    end

    until g.end?
      x = 10 if g.current > 2
      puts g.next
    end

This outputs 1, 1, 2, 3, 10.

The next question is, why is the API for this class so crappy? I would have expected the output to be 1, 1, 2, 10, 10. But creating the generator automatically advances to the first yield, and "next" advances to the next one while returning the previous one. This is just wrong.

Perhaps a more interesting quiz would be BetterGenerator that looks like Python's upcoming PEP 342 (PEP 0 โ€“ Index of Python Enhancement Proposals (PEPs) | peps.python.org).

Luke Blanshard

ยทยทยท

On Feb 10, 2006, at 8:24 AM, Pit Capitain wrote:

Mine does, of course, pull all the items in at once and has all the problems discussed with that approach. Attached is my implementation and the altered versions I have been using in benchmarks.

James Edward Gray II

callcc_generator.rb (7.17 KB)

faster_generator.rb (3.8 KB)

thread_generator.rb (7.49 KB)

time_generators.rb (1.11 KB)

ยทยทยท

On Feb 12, 2006, at 11:10 AM, Jacob Fugal wrote:

Ok, since last night I've corrected my implementation to not evaluate
ahead, as per H. Yamamoto's and Luke Blanshard's comments.

Ok, since last night I've corrected my implementation to not evaluate
ahead, as per H. Yamamoto's and Luke Blanshard's comments.

I did the same, and it's pretty much killed my implementation :(. It
turns out to be quite similar to the new standard generator
implementation, but I didn't look beforehand, I promise :slight_smile: I've used
this kind of setup before in Java. Previously I had it running the block
in variable-size chunks with optimisation for non-block usage, when an
enum that responds_to? :length is supplied to the constructor. Like in
those performance tests :wink:

Anyway, it now satisfies the extra conditions discussed I think, but
it's performance isn't too hot anymore. Particularly on 1.8, threading
seems to be fairly slow anyway. I also ran it under 1.9 against the 1.9
generator for comparison (it's a sliver quicker, but I suspect that's
because my one isn't very robust). These numbers are with 100 tests,
1000 elements as used in Jacob's benchmark.

(Incidentally, Jacob, Under 1.8 yours was testing about twice as fast as
mine, but it seems to deadlock about half of the time? I have to
interrupt after leaving it for up to a minute. I'm on Ruby 1.8.4
i686-linux).

$ ruby bench.rb

### Construction ###

Rehearsal --------------------------------------------------------------
1.8.4-2005-12-24 Generator 0.020000 0.010000 0.030000 ( 0.111110)
My generator 0.010000 0.000000 0.010000 ( 0.065179)
----------------------------------------------------- total: 0.040000sec

                                 user system total real
1.8.4-2005-12-24 Generator 0.000000 0.010000 0.010000 ( 0.015034)
My generator 0.010000 0.000000 0.010000 ( 0.010767)

### next() ###

Rehearsal --------------------------------------------------------------
1.8.4-2005-12-24 Generator 19.640000 0.420000 20.060000 ( 22.134238)
My generator 10.720000 0.090000 10.810000 ( 11.349895)
---------------------------------------------------- total: 30.870000sec

                                 user system total real
1.8.4-2005-12-24 Generator 19.310000 0.250000 19.560000 ( 20.453355)
My generator 9.950000 0.060000 10.010000 ( 10.507884)

$ ruby9 bench.rb

### Construction ###

Rehearsal --------------------------------------------------------------
1.9.0-2006-02-13 Generator 0.000000 0.000000 0.000000 ( 0.057187)
My generator 0.010000 0.000000 0.010000 ( 0.005367)
----------------------------------------------------- total: 0.010000sec

                                 user system total real
1.9.0-2006-02-13 Generator 0.000000 0.000000 0.000000 ( 0.003844)
My generator 0.010000 0.000000 0.010000 ( 0.004790)

### next() ###

Rehearsal --------------------------------------------------------------
1.9.0-2006-02-13 Generator 3.780000 0.030000 3.810000 ( 4.021680)
My generator 3.610000 0.020000 3.630000 ( 3.758884)
----------------------------------------------------- total: 7.440000sec

                                 user system total real
1.9.0-2006-02-13 Generator 3.950000 0.030000 3.980000 ( 4.021709)
My generator 3.590000 0.030000 3.620000 ( 3.762839)

bench.rb (832 Bytes)

fgenerator.rb (4.99 KB)

queuetest.rb (358 Bytes)

ยทยทยท

On Mon, 2006-02-13 at 02:10 +0900, Jacob Fugal wrote:

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk

James Gray wrote:

I'm pretty sure they learned the same lesson changing the standard
library. Have a look at these commit messages:

   * lib/generator.rb: uses Mutex instead of Thread.critical.
     [ruby-dev:28184]

Then later:

   Sorry, reverted. Mutex is damn slow.....

:slight_smile:

James Edward Gray II

Aha! Well, then we have a strong candidate for the next quiz, namely
BetterMutex? :slight_smile:

Jesse

ยทยทยท

--
Posted via http://www.ruby-forum.com/\.

We all owe Ross a *huge* thank you for this effort!

James Edward Gray II

ยทยทยท

On Feb 14, 2006, at 10:42 AM, Ross Bamford wrote:

Here's some I ran up on Ruby 1.8.4-2005-12-24, and results of test runs
too.

Oops, it was actually three that passed endless but not realtime - I
missed the result for Caleb Clausen's entry when I said that.

ยทยทยท

On Wed, 2006-02-15 at 01:42 +0900, Ross Bamford wrote:

I also (having too little to do, and too much time to do it in) ran
James' original test-cases, plus the realtime test posted in the NG and
a simple endless iterator test (posted below the results). Two passed
all, two passed endless but not realtime, and the others didn't pass
either (but still passed the basic tests of course).

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk

As James said, thanks for doing this Ross.

I hadn't added test_realtime to my test set, but now I have and this
bug is fixed. I have attached the fixed version for anyone who cares.
For the hell of it, I also optimized by manually inlining some method
calls, and eliminating redundant bounds checking. This should now
pass all tests and run much faster.

These are basically the optimizations:

   def current
- raise EOFError if spent?
- @array[@index]
+ @array.fetch(@index) rescue raise EOFError
   end

   def end?
- spent?
+ @index >= @array.size
   end

   def next
- result = current
+ begin
+ result = @array.fetch(@index)
+ rescue
+ raise EOFError
+ end
     @index += 1
     result
   end

   def next?
- not end?
+ @index < @array.size
   end

Dave

my_generator.rb (1.98 KB)

my_generator.diff.txt (1.21 KB)

ยทยทยท

On 2/14/06, Ross Bamford <rossrt@roscopeco.co.uk> wrote:

###### Supporting infinite iterators but *not* realtime. #####

### TESTING: davelee_generator.rb
Loaded suite tests
Started
....E
Finished in 1.075006 seconds.

  1) Error:
test_realtime(TC_TGenerator):
NoMethodError: undefined method `size' for nil:NilClass
    ./davelee_generator.rb:82:in `spent?'
    ./davelee_generator.rb:32:in `current'
    ./davelee_generator.rb:55:in `next'
    tests.rb:179:in `test_realtime'
    tests.rb:177:in `test_realtime'
    tests.rb:174:in `test_realtime'

5 tests, 1557 assertions, 0 failures, 1 errors

### next() ###

...

CalebClausenSyncGenerator 0.660000 0.000000 0.660000 ( 0.710609)
CalebClausenGenerator 0.440000 0.000000 0.440000 ( 0.495331)

Interesting. I saw much larger speedups (4-10x) from using the
non-Sync version on my system. Maybe my results weren't statistically
significant.... If it's only 1/3 faster, it hardly seems worth it to
have the non-Sync version at all.

(Also, I would have thought that mine should pass the realtime
tests.... but I never tried it.)

Thanks for this summary, Ross.

ยทยทยท

On 2/14/06, Ross Bamford <rossrt@roscopeco.co.uk> wrote:

Oh and don't be too impressed with those, Pit Capitain has already told you one of the flaws with my approach... :wink:

James Edward Gray II

ยทยทยท

On Feb 10, 2006, at 10:28 AM, James Edward Gray II wrote:

### Construction ###

James's FasterGenerator 0.000000 0.000000 0.000000 ( 0.003751)

### next() ###

James's FasterGenerator 0.030000 0.000000 0.030000 ( 0.037034)

It's not my implementation I am trying to hide, it's the current Generator code the benchmark uses as a baseline. I realize it's readily available, but I think solving this one is more fun if you don't peek. :slight_smile:

James Edward Gray II

ยทยทยท

On Feb 10, 2006, at 10:34 AM, Matthew Moss wrote:

I wasn't looking to see your implementation of Generator, I was to see your benchmarking code.

Off topic a bit, but what os/hardware are you using to get these numbers?

Dave

ยทยทยท

On 2/10/06, James Edward Gray II <james@grayproductions.net> wrote:

Here are the corrected numbers:

### Construction ###

Rehearsal -----------------------------------------------------------
Current Generator 0.320000 0.320000 0.640000 ( 0.642583)
Old callcc Generator 0.610000 0.870000 1.480000 ( 1.480780)
James's FasterGenerator 0.000000 0.000000 0.000000 ( 0.003751)
-------------------------------------------------- total: 2.120000sec

                               user system total real
Current Generator 0.740000 0.720000 1.460000 ( 1.464659)
Old callcc Generator 0.220000 1.500000 1.720000 ( 1.714859)
James's FasterGenerator 0.010000 0.000000 0.010000 ( 0.003258)

### next() ###

Rehearsal -----------------------------------------------------------
Current Generator 16.610000 0.130000 16.740000 ( 17.032537)
Old callcc Generator 8.070000 32.740000 40.810000 ( 41.072265)
James's FasterGenerator 0.030000 0.000000 0.030000 ( 0.037034)
------------------------------------------------- total: 57.580000sec

                               user system total real
Current Generator 16.630000 0.120000 16.750000 ( 16.878429)
Old callcc Generator 7.440000 32.720000 40.160000 ( 40.336902)
James's FasterGenerator 0.040000 0.000000 0.040000 ( 0.035432)

Actually, there's no way (I can think of) to get the output you
expect, and it has nothing to do with an initial advance or anything.
My implementation doesn't advance to the yields until required, yet
has the same output. This is because of these two lines:

x = 10 if g.current > 2
puts g.next

g.current returns the current value. g.current is not greater than two
until g.current == 3. g.next then returns the same as g.current, while
also advancing the internal counter. The behavior your describing
would require changing the value of g.current by assigning to x. Can't
be done.

Jacob Fugal

ยทยทยท

On 2/12/06, Luke Blanshard <luke@blanshard.us> wrote:

    x = 1
    g = Generator.new do |g|
      5.times {|i| g.yield [x,i].max}
    end

    until g.end?
      x = 10 if g.current > 2
      puts g.next
    end

This outputs 1, 1, 2, 3, 10.

The next question is, why is the API for this class so crappy? I would
have expected the output to be 1, 1, 2, 10, 10. But creating the
generator automatically advances to the first yield, and "next" advances
to the next one while returning the previous one. This is just wrong.

Yes, you are right. That was silly of me.

I like your fix. Adding rewind() fixes things up.

Thank you.

James Edward Gray II

ยทยทยท

On Feb 12, 2006, at 3:23 AM, Christoffer Lernรถ wrote:

Benchmark.bmbm do |x|
  x.report("Current Generator") do
    generator = CurrentGenerator.new(enum)
    tests.times { generator.next until generator.end? }
  end

I have small problem with this. Won't this mean the loop will only run 1 time?

Mine looks like a clone of James':

class MyGenerator
     attr_reader :index
     def initialize(enum = nil)
         if enum then
             @array = enum.to_a
         else
             @array = Array.new
             yield self
         end
         @index = 0
     end
     def current
         raise EOFError unless next?
         @array[@index]
     end
     def next
         value = current
         @index += 1
         return value
     end
     def next?
         return @index < @array.length
     end
     def rewind
         @index = 0
         self
     end
     def each(&block)
         @array.each(&block)
     end
     def yield(value)
         @array << value
     end
     def pos
         return @index
     end
     def end?
         return !next?
     end
end

/Christoffer

ยทยทยท

On Feb 12, 2006, at 19:23 , James Edward Gray II wrote:

On Feb 12, 2006, at 11:10 AM, Jacob Fugal wrote:

Ok, since last night I've corrected my implementation to not evaluate
ahead, as per H. Yamamoto's and Luke Blanshard's comments.

Mine does, of course, pull all the items in at once and has all the problems discussed with that approach. Attached is my implementation and the altered versions I have been using in benchmarks.

James Edward Gray II

Here's my solution for this week's quiz. Normally, I just watch the
quizzing, but this one happens to be one that I'm already doing, as
part of a larger library of external iterators.

The key insight is to realize that Continuations were used in the
original because an independant call stack is needed (to run #each
in), separate from the call stack of the user of Generator. However,
Continuations are only one way to get another call stack; you could
also use a Thread, which doesn't have the same performance problems
in ruby.

In order to implement Generator#current, I had to invent Queue#peek,
which tells you what the next element is without taking it from the
Queue. Actually, I'm using a SizedQueue, not a plain Queue. Otherwise,
the memory used by the queue could grow without bounds.

#rewind was also a small challenge, until I realized that you could
just restart the Thread. (Hopefully, the enum or block will return
the same results the second time through.)

It's not allowed in the original, but this version permits you to
pass both an enum and a block to the generator. The results of the
block are passed up once the enum is exhausted.

Another interesting new feature is Generator#<<, which allows you to
add more items to the Generator once it has been created. This was
originally a misunderstood implementation of yield.

It's clear that this version is faster than the original callcc-
based Generator, but I'm not sure how to compare with James'
results. I was unable to run his benchmark to completion on my
machine. Somewhat modified, I see differences of around 3 orders
of magnitude, but performance of the callcc-based version seems
non-linearly dependant on input size.

I also found that bumping the queue size up to 400 from the original
32 made about a 4x difference in running time. I guess context
switches are expensive...

I am curious to see how James made his own solution so blazing fast.

The requirement for synchronous generators took me by surprise at
the last minute. It was easy enough to add synchronicity, but it
looks like there would be a performance cost from the extra
context switches. And is maybe not needed in the majority of cases.
So, I put the synchronous capability in a subclass. Sure enough,
when I ran the benchmark, the synchronous version pretty much
wipes out any performance gain from the bigger queue.

Benchmarks: (take with a grain of salt)

### Construction ###

Rehearsal -----------------------------------------------------------------
Caleb's Generator 0.020000 0.000000 0.020000 ( 0.015167)
Caleb's Synchronous Generator 0.000000 0.000000 0.000000 ( 0.003251)
Old callcc Generator 0.000000 0.000000 0.000000 ( 0.004067)
-------------------------------------------------------- total: 0.020000sec

                                    user system total real
Caleb's Generator 0.010000 0.000000 0.010000 ( 0.014414)
Caleb's Synchronous Generator 0.010000 0.000000 0.010000 ( 0.003384)
Old callcc Generator 0.000000 0.000000 0.000000 ( 0.004027)

### next() ###

Rehearsal -----------------------------------------------------------------
Caleb's Generator 0.050000 0.000000 0.050000 ( 0.092768)
Caleb's Synchronous Generator 0.270000 0.000000 0.270000 ( 0.306566)
each 0.000000 0.000000 0.000000 ( 0.000732)
Old callcc Generator 8.410000 0.960000 9.370000 ( 10.738060)
-------------------------------------------------------- total: 9.690000sec

                                    user system total real
Caleb's Generator 0.030000 0.000000 0.030000 ( 0.069023)
Caleb's Synchronous Generator 0.200000 0.000000 0.200000 ( 0.256574)
each 0.000000 0.000000 0.000000 ( 0.000392)
Old callcc Generator 7.400000 0.960000 8.360000 ( 8.679449)

mygenerator.rb (2.36 KB)

Hmm, while I didn't run into any deadlocks with my testing, I'm not
too surprised. I'm not very threading-savvy and could easily have made
some critical mistake. :slight_smile:

I also realized that the implementation I posted to the list doesn't
rewind correctly. Currently it just drops back the @position marker,
but doesn't reset the @values array or generating block. This is bad
if the generator is rewound and the block should generate different
values on different runs (e.g. it's time dependent or sensitive to the
environment).

Jacob Fugal

ยทยทยท

On 2/12/06, Ross Bamford <rossrt@roscopeco.co.uk> wrote:

(Incidentally, Jacob, Under 1.8 yours was testing about twice as fast as
mine, but it seems to deadlock about half of the time? I have to
interrupt after leaving it for up to a minute. I'm on Ruby 1.8.4
i686-linux).

It does pass all the tests (including a new one based on Luke
Blanshard's stateful code), but I can't imagine what on earth is going
on here (see assertion counts):

[rosco@jukebox 66]$ ruby tests.rb davelee_generator.rb
Loaded suite tests
Started
......
Finished in 1.067421 seconds.

6 tests, 1561 assertions, 0 failures, 0 errors

[rosco@jukebox 66]$ ruby tests.rb davelee_generator.rb
Loaded suite tests
Started
......
Finished in 1.078261 seconds.

6 tests, 422 assertions, 0 failures, 0 errors

[rosco@jukebox 66]$ ruby tests.rb davelee_generator.rb
Loaded suite tests
Started
......
Finished in 1.012041 seconds.

6 tests, 1561 assertions, 0 failures, 0 errors

[rosco@jukebox 66]$ ruby tests.rb davelee_generator.rb
Loaded suite tests
Started
......
Finished in 1.065682 seconds.

6 tests, 682 assertions, 0 failures, 0 errors

[rosco@jukebox 66]$ ruby tests.rb davelee_generator.rb
Loaded suite tests
Started
......
Finished in 1.071149 seconds.

6 tests, 422 assertions, 0 failures, 0 errors

It seems to be jumping early out of the endless test judging by the
number of missing assertions. It only happens sometimes (1561 is a full
pass) and it does happen with the old version too (only just noticed
it).

I ran updated timings since they don't use endless iterators anyway.
Here's the result (on 1.8.4):

### Construction ###

Rehearsal -------------------------------------------------------------
New Thread Generator 0.270000 0.050000 0.320000 ( 0.379841)
Old callcc Generator 0.290000 0.090000 0.380000 ( 0.381635)
RossBamfordGenerator 1.150000 0.060000 1.210000 ( 1.269793)
JesseYoonGenerator 2.700000 0.100000 2.800000 ( 2.797546)
JacobFugalGenerator 0.020000 0.000000 0.020000 ( 0.022782)
JEGIIGenerator 0.010000 0.000000 0.010000 ( 0.008398)
HorndudeGenerator 1.290000 0.020000 1.310000 ( 1.308930)
DaveLeeGenerator 0.010000 0.000000 0.010000 ( 0.007556)
ChristofferLernoGenerator 0.000000 0.000000 0.000000 ( 0.004950)
CalebClausenSyncGenerator 3.610000 0.070000 3.680000 ( 3.696594)
CalebClausenGenerator 7.940000 0.130000 8.070000 ( 8.151407)
--------------------------------------------------- total: 17.810000sec

                                user system total real
New Thread Generator 5.050000 0.090000 5.140000 ( 5.184013)
Old callcc Generator 0.100000 0.080000 0.180000 ( 0.183245)
RossBamfordGenerator 6.490000 0.050000 6.540000 ( 6.663615)
JesseYoonGenerator 8.170000 0.110000 8.280000 ( 8.356455)
JacobFugalGenerator 0.040000 0.000000 0.040000 ( 0.150496)
JEGIIGenerator 0.000000 0.000000 0.000000 ( 0.003616)
HorndudeGenerator 2.310000 0.020000 2.330000 ( 2.325253)
DaveLeeGenerator 0.010000 0.000000 0.010000 ( 0.010512)
ChristofferLernoGenerator 0.000000 0.000000 0.000000 ( 0.004091)
CalebClausenSyncGenerator 10.320000 0.160000 10.480000 ( 10.493258)
CalebClausenGenerator 15.580000 0.190000 15.770000 ( 15.832376)

### next() ###

Rehearsal -------------------------------------------------------------
New Thread Generator 0.560000 0.000000 0.560000 ( 0.618782)
Old callcc Generator 1.670000 0.330000 2.000000 ( 2.090583)
RossBamfordGenerator 0.560000 0.010000 0.570000 ( 0.634513)
JesseYoonGenerator 1.960000 0.010000 1.970000 ( 2.037655)
JacobFugalGenerator 0.520000 0.000000 0.520000 ( 0.568505)
JEGIIGenerator 0.040000 0.000000 0.040000 ( 0.124053)
HorndudeGenerator 0.020000 0.000000 0.020000 ( 0.054959)
DaveLeeGenerator 0.030000 0.000000 0.030000 ( 0.080798)
ChristofferLernoGenerator 0.060000 0.000000 0.060000 ( 0.123206)
CalebClausenSyncGenerator 0.740000 0.010000 0.750000 ( 0.801426)
CalebClausenGenerator 0.490000 0.000000 0.490000 ( 0.561398)
---------------------------------------------------- total: 7.010000sec

                                user system total real
New Thread Generator 0.550000 0.000000 0.550000 ( 0.561499)
Old callcc Generator 1.740000 0.060000 1.800000 ( 1.809145)
RossBamfordGenerator 0.560000 0.000000 0.560000 ( 0.558627)
JesseYoonGenerator 1.610000 0.010000 1.620000 ( 1.626749)
JacobFugalGenerator 0.500000 0.010000 0.510000 ( 0.501115)
JEGIIGenerator 0.040000 0.000000 0.040000 ( 0.043879)
HorndudeGenerator 0.010000 0.000000 0.010000 ( 0.007551)
DaveLeeGenerator 0.040000 0.010000 0.050000 ( 0.034707)
ChristofferLernoGenerator 0.060000 0.000000 0.060000 ( 0.064452)
CalebClausenSyncGenerator 0.750000 0.000000 0.750000 ( 0.754337)
CalebClausenGenerator 0.530000 0.010000 0.540000 ( 0.533183)

ยทยทยท

On Wed, 2006-02-15 at 02:54 +0900, Dave Lee wrote:

I hadn't added test_realtime to my test set, but now I have and this
bug is fixed. I have attached the fixed version for anyone who cares.
For the hell of it, I also optimized by manually inlining some method
calls, and eliminating redundant bounds checking. This should now
pass all tests and run much faster.

--
Ross Bamford - rosco@roscopeco.REMOVE.co.uk

It's not my implementation I am trying to hide, it's the current
Generator code the benchmark uses as a baseline. I realize it's
readily available, but I think solving this one is more fun if you
don't peek. :slight_smile:

Okay.... ummm.... sure.... I won't peek. No, you can't make me.

(In case I still wasn't clear, I wasn't asking to peek at ANY
implementation of Generator, but rather wanted exactly what you
posted, which has nothing to do with Generator but everything to do
with benchmark, i.e., the thing I wanted to know about.)

A dual processor G5 at 2.0 Ghz (each processor), running Mac OS X (10.4.4). The box has 2 Gigs of RAM.

James Edward Gray II

ยทยทยท

On Feb 10, 2006, at 12:45 PM, Dave Lee wrote:

On 2/10/06, James Edward Gray II <james@grayproductions.net> wrote:

Here are the corrected numbers:

### Construction ###

Rehearsal -----------------------------------------------------------
Current Generator 0.320000 0.320000 0.640000 ( 0.642583)
Old callcc Generator 0.610000 0.870000 1.480000 ( 1.480780)
James's FasterGenerator 0.000000 0.000000 0.000000 ( 0.003751)
-------------------------------------------------- total: 2.120000sec

                               user system total real
Current Generator 0.740000 0.720000 1.460000 ( 1.464659)
Old callcc Generator 0.220000 1.500000 1.720000 ( 1.714859)
James's FasterGenerator 0.010000 0.000000 0.010000 ( 0.003258)

### next() ###

Rehearsal -----------------------------------------------------------
Current Generator 16.610000 0.130000 16.740000 ( 17.032537)
Old callcc Generator 8.070000 32.740000 40.810000 ( 41.072265)
James's FasterGenerator 0.030000 0.000000 0.030000 ( 0.037034)
------------------------------------------------- total: 57.580000sec

                               user system total real
Current Generator 16.630000 0.120000 16.750000 ( 16.878429)
Old callcc Generator 7.440000 32.720000 40.160000 ( 40.336902)
James's FasterGenerator 0.040000 0.000000 0.040000 ( 0.035432)

Off topic a bit, but what os/hardware are you using to get these numbers?