From: Joe Van Dyk Date: 2005-07-13T08:55:51+09:00 Subject: Re: Updating GUIs On 7/12/05, Joe Van Dyk wrote: > On 7/12/05, Lothar Scholz wrote: > > Hello Joe, > > > > JVD> I'm doing this on a TkCanvas. > > > > If you use TkCanvas it is very unlikely that the speed problem is > > caused by the update call. This part is very optimized in TK. > > > > JVD> Should I try to convert the rotate function to C and then see if it's > > JVD> fast enough? I'm still making a gazillion function calls (say, 300 > > JVD> polygons and 30 points each and update twice a second, that's 18,000 > > JVD> function calls a second). No wonder it's slow. :( Perhaps using > > JVD> TkCanvas was a mistake for this. > > > > Have you isolated your rotation code and calculated the values without > > passing the parameters to TkCanvas. How fast is this ? > > > > The only TK related problem is to pass 18000 floating point numbers to > > the canvas widget. Don't know how heavyweight the RubyTK layer is but > > it means converting them to strings and back to floating points. So > > maybe this parameter setting is the reason for the problem, but you > > must measure it not trying to guess it. > > > > I've seen more complicated TkCanvas scenarios 7 years ago when > > CPU speed was 400 MHz and TK did not show a problem. > > This is taking me about a third of a second to do. Seems a bit high > if I want to do this at least twice a second and leave room on the > machine to do other things: > > > # rotate function > def rotate(deg, x, y, c_x = 0, c_y = 0) > rad = (deg * Math::PI)/180.0 > s_rad = Math::sin(rad) > c_rad = Math::cos(rad) > x -= c_x > y -= c_y > [c_x + (x * c_rad - y * s_rad), c_y + (x * s_rad + y * c_rad)] > end > > class Player > attr_accessor :x, :y, :polygon, :heading > def initalize > @x = @y = @heading = 0 > @polygon = [] > end > end > > players = [] > 500.times do > p = Player.new > p.x = rand 1000000 > p.y = rand 1000000 > p.heading = rand 360 > p.polygon = [] # Why do I need this here? If it's not, p.polygon is nil. :( > 40.times do > p.polygon << [rand(10), rand(10)] > end > players << p > end > > start_time = Time.now > players.each do |player| > player.polygon = player.polygon.collect do |x,y| > rotate(player.heading, x, y, player.x, player.y) > end > end > end_time = Time.now > puts end_time - start_time > > > So what's the next step when trying to optimize this? Convert the > rotate function to C? Or can I use a different algorithm? On a very fast machine, the above code ran in 0.14 seconds. On a pentium1 machine, it ran in 2.04 seconds. When I used the following C function to do the rotation, it pretty much halved the execution time to 0.06 seconds on the fast machine and 0.94 seconds on the Pentium1 machine. I'm pretty new to C extensions, is there anything else I can do to improve the speed? It would seem that moving the code that loops around the Players and collects the polygon points to C would help much more, but I don't know how to do that yet in C. static VALUE rotate(VALUE self, /* Module */ VALUE _degree, /* Rotate Degree */ VALUE _x, VALUE _y, /* Point */ VALUE _c_x, VALUE _c_y) /* Center to rotate around */ { double degree = NUM2DBL(_degree); long x = NUM2LONG(_x); long y = NUM2LONG(_y); long c_x = NUM2LONG(_c_x); long c_y = NUM2LONG(_c_y); double rad = (degree * M_PI) / 180.0; double s_rad = sin(rad); double c_rad = cos(rad); x -= c_x; y -= c_y; VALUE return_array = rb_ary_new(); rb_ary_push(return_array, rb_float_new(c_x + (x * c_rad - y * s_rad))); rb_ary_push(return_array, rb_float_new(c_y + (x * s_rad + y * c_rad))); return return_array; }