[racket] universe program using 100% cpu on Mac (also poor Raspberry Pi performance)

From: Sean Kanaley (skanaley at gmail.com)
Date: Tue Dec 30 08:15:52 EST 2014

Hi Darren,

I think there are three common kinds of unit tests --

1. Interaction window while developing the function, to ensure it seems to
do what you think it does. It's probably simple yet covers the majority of
cases. These might be copy and pasted into unit tests as a simple sanity
check for basically no extra effort.

2. Corner case checks. The ones you have to go out of your way to think
about. I'm sure there's differing opinions here, but these can be left out
until a bug is revealed, saving you the time of effectively presenting a
proof by exhaustion for every atom of code you write.

3. Redundant checks like you said, e.g. pressing left does in fact make it
go left. My view on this is you don't actually write these as part of the
initial development, because not only is the redundancy clear in short
functions, but the test is going to be subject to the same lazy copy paste
errors that the function is, possibly resulting in functioning but wrong
unit tests (ouch). Where these are helpful is when you refactor. When your
program is complete, but you decide to change the features, and as a result
may want to modify the movement logic, these *formerly* redundant tests now
serve as the sole specification for what your program must continue doing,
regardless of how much you butcher the code. In a way it's like you saved a
backup copy of the code, except in such a way that running it allows the
compiler to find differences in the code for you. But you don't really need
the trouble of a backup copy at the beginning of development (where you may
end up deleting a function altogether!).

On Mon, Dec 29, 2014 at 11:28 PM, Darren Cruse <darren.cruse at gmail.com>
wrote:

> Hi Matthias just saw your reply.
>
> Regarding the tests I like what you said about "for a large function -- a
> reader quickly gets the idea of how the function works from reading some
> tests".
>
> But if I'm honest the example that you gave is the kind of example that
> bothers me - in that it's *not* a large function.  The test you gave
> reminds me of the majority that I see - and it struck me recently I think
> what bothers me is that such tests are in effect a tautology
> <http://www.merriam-webster.com/dictionary/tautology>
>
> i.e. most of these tests like this, esp. since they are written by the
> same programmer writing the function under test, are literally just a
> restating of the exact same assumptions the programmer has made in writing
> the function.  So they are *literally* redundant.  Yet they must be
> maintained as the programmer maintains and modifies the code going
> forward.  So there is a cost to them, but to me I honestly don't see much
> if any benefit.
>
> Which isn't to say that good tests can't be written if they are testing a
> large and complex function (as you said).  What I question is the common
> belief nowadays that they're always of value even in simple cases.
>
> Anyway hope you'll forgive my heresy.  I turned 50 this year maybe I just
> an old dog now too set in his ways.  I know I'm very much in the minority
> in this view.  No offense intended.
>
> But more to the point - here's what I did while I should have been writing
> tests:
>
> pong-world.rkt via whalesong
> <http://htmlpreview.github.io/?https://github.com/darrencruse/pong-world-racket/blob/master/whalesong/build/pong-world.html>
> :)
>
> The biggest challenge - other than what looks like some problems with
> multiple/deeply nested overlay/place-image positioning, is that whalesong
> seems to not support "on-release", so for now this works best if you click
> and hold where it says "hit space to serve" and then you can use your mouse
> and play the game against yourself.
>
> This was done using the soegaard/whalesong
> <https://github.com/soegaard/whalesong> version of whalesong btw.
>
> Darren
>
>
>
>
> On Mon, Dec 29, 2014 at 8:00 PM, Matthias Felleisen <matthias at ccs.neu.edu>
> wrote:
>
>>
>> TESTS: Say I want to eliminate a common pattern from your handle-key-down
>> function. If it comes with some tests, four to be precise, a simple run --
>> without playing -- assures me of basic qualities. If you express tests like
>> those below and you formulate them first, you get an idea of how to code
>> the function. And -- for a large function -- a reader quickly gets the idea
>> of how the function works from reading some tests.
>>
>> (check-expect (handle-key-down initial-state "w")  (set-left-moving
>> initial-state UP-DIR))
>>
>> (define (handle-key-down world a-key)
>>   (cond
>>     [(key=? a-key "w") (set-left-moving world UP-DIR)]
>>     [(key=? a-key "s") (set-left-moving world DOWN-DIR)]
>>     [(key=? a-key "up") (set-right-moving world UP-DIR)]
>>     [(key=? a-key "down") (set-right-moving world DOWN-DIR)]
>>     [else world]))
>>
>> (define (set-left-moving world dir)
>>   (set-left-paddle world (set-paddle-moving (pong-world-left-paddle
>> world) dir PADDLE-SPEED)))
>>
>> (define (set-right-moving world dir)
>>   (set-right-paddle world (set-paddle-moving (pong-world-right-paddle
>> world) dir PADDLE-SPEED)))
>>
>>
>> GAME PAD: I am happy to see that you used on-pad. Your game does give me
>> an idea on how to improve the whole 'pad situation'.
>>
>> -- Matthias
>>
>>
>>
>>
>>
>> On Dec 29, 2014, at 1:43 PM, Darren Cruse wrote:
>>
>> Thanks Matthias and it will be quite fun to tell the others at my next
>> meetup who code reviewed this for me! :)
>>
>> I'll make the changes you suggested though (forgive me) I'll have to
>> think about what constitutes useful tests for this.  Somehow I've never
>> fully bought into TDD though I know I'm one of the last holdouts in the
>> civilized world. :)  Can I get out of it saying I was just doing this for
>> fun? :)
>>
>> I'm most of all pleased that you didn't see something I'd fundamentally
>> misunderstood, e.g. that would explain why the game performed poorly on the
>> raspberry pi.
>>
>> fwiw Racket is the first lispy language I've ever gotten serious about
>> learning.  I'm one of those who'd been thrown off by the parens for too
>> long.  I really like using it now that I'm over the initial learning
>> curve.  I think my biggest wish would be it had a good story for doing
>> smartphone/tablet apps, or that Whalesong was more of a going concern (not
>> that I've tried it I wonder if this pong game would run under it without a
>> ton of work?)
>>
>> Thanks again for your time,
>>
>> Darren
>>
>>
>> On Mon, Dec 29, 2014 at 10:39 AM, Matthias Felleisen <
>> matthias at ccs.neu.edu> wrote:
>>
>>>
>>> Hi Darren, thanks for the link to the repo. I cloned it, successfully
>>> played with and without sound on a mac book -- inside of drracket and from
>>> the command line-- and never observed a load over 60% for drracket and
>>> ditto for plain racket. That doesn't mean that your 100% problem doesn't
>>> exist, it's just that I can't reproduce it.
>>>
>>> A couple of comments on the code:
>>>
>>>  -- I'd place the main function at the top of the function section of
>>> the file
>>>       right below the constant definitions and data definitions
>>> [I modified 2e to bring this across but you might be reading the stable
>>> version.]
>>>
>>>  -- I also run (main initial-state) out of the repl not the main buffer.
>>>
>>>  -- Your file is missing tests.
>>>
>>>  -- Some functions are also missing proper signatures and purpose
>>> statements.
>>>
>>> But I know "it works" see my homepage :-)
>>>
>>> -- Matthias
>>>
>>>
>>>
>>> On Dec 29, 2014, at 10:46 AM, Darren Cruse wrote:
>>>
>>> Re:
>>>
>>>> Could you post the code somewhere so we can experiment with it?
>>>
>>>
>>> Here it is it's all in one file:
>>> pong-world.rkt
>>> <https://github.com/darrencruse/pong-world-racket/blob/master/pong-world.rkt>
>>>
>>> On Mon, Dec 29, 2014 at 8:05 AM, Matthias Felleisen <
>>> matthias at ccs.neu.edu> wrote:
>>>
>>>>
>>>> On Dec 28, 2014, at 9:51 PM, Darren Cruse wrote:
>>>>
>>>> One thing I can see is that on-draw is called for every on-tick on all
>>>> three platforms btw.
>>>>
>>>> And even in cases where the program is idling and on-tick has simply
>>>> returned the world state it was given unmodified.
>>>>
>>>> Is that normal I wonder?  Part of me thought that since to-draw is a
>>>> function of the world state, and the world state hasn't changed, that it
>>>> would *not* call to-draw in that case.
>>>>
>>>>
>>>> I experimented with this 'optimization' and, if I recall correctly, it
>>>> didn't make much of a difference and got in the way of imperative world
>>>> programs. So I took it out. Mea culpa, I should have commented on this
>>>> experiment inside the code.
>>>>
>>>>
>>>>
>>>> (but it calls to-draw for every on-tick even on the Windows machine
>>>> which is using only 6% cpu - so maybe I'm wrong to look to that as the
>>>> problem)
>>>>
>>>>
>>>>
>>>> My Mac-based experiments suggest that this call is not the cause of
>>>> performance problems.
>>>>
>>>> ;; ---
>>>>
>>>> Could you post the code somewhere so we can experiment with it?
>>>>
>>>> Thanks -- Matthias
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20141230/1658c6a2/attachment.html>

Posted on the users mailing list.