deadly slow !!

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

deadly slow !!

Howard Oh
Folks,

Add a method loose below.
It won't be harmful to your image just by add it, unless you invoke it
with unproper parameter.

SequenceableCollection>>codeBookOf: anInteger

        anInteger <= 0 ifTrue: [^self class new].
        ^anInteger = 1
                ifTrue:
                        [self collect: [:obj| self class with: obj ]]
                ifFalse:
                        [|newAnswerStream|
                        newAnswerStream := WriteStream on: (self class new: (self size
raisedTo: anInteger)).
                        (self codeBookOf: anInteger-1) do: [:oneSubAnswer|
                                self do: [:oneObjectToAdd|
                                        newAnswerStream nextPut: oneSubAnswer, (self class with:
oneObjectToAdd)]].
                        newAnswerStream contents]


This method is not a problem when anInteger is small.

Try, #(true false) codeBookOf: 3


It is a problem when anInteger is big. Try below after a good backup of
your image.


#(nil 0) codeBookOf: 25 "Number 25 maybe not be big enough for your
PC."


makes my PC(P-4 2.4GHz 512MB DDR ram) nearly stop!

Memory paging goes up to 1.2GB, and Dolphin.exe eats up to 380MB.
CPU usage goes up to 50% but soon or later it drops down to 2%.
That seems to me like the #codeBookOf: has been answered, and workspace
is idle.
But workspace is still hanging and memory allocation is still 1.2GB.
The answered object(Array) is not kept in a workspace variable so it
must have gone garbage collected right away(or 10 sec later). But still
1.2GB, hard disk is turning like as if it's going to blow.

As soon as I kill Dolphin.exe from process list, memory allocation
drops down to 550MB and disk rests in peace.


Can anyone explain this phenomenon?


Reply | Threaded
Open this post in threaded view
|

Re: deadly slow !!

John Brant
Howard Oh wrote:

> SequenceableCollection>>codeBookOf: anInteger
>
> anInteger <= 0 ifTrue: [^self class new].
> ^anInteger = 1
> ifTrue:
> [self collect: [:obj| self class with: obj ]]
> ifFalse:
> [|newAnswerStream|
> newAnswerStream := WriteStream on: (self class new: (self size
> raisedTo: anInteger)).
> (self codeBookOf: anInteger-1) do: [:oneSubAnswer|
> self do: [:oneObjectToAdd|
> newAnswerStream nextPut: oneSubAnswer, (self class with:
> oneObjectToAdd)]].
> newAnswerStream contents]
> ...
> #(nil 0) codeBookOf: 25 "Number 25 maybe not be big enough for your
> PC."
> ...
> Can anyone explain this phenomenon?

Of course, this will be slow. If this worked, you would have created a
collection of size 33,554,432 (2 raisedTo: 25). Each element in that
collection would have contained a 25 element collection. The amount of
space just for the pointers would be (33554432*4) + (33554432*25*4) =
3,489,660,928 bytes (plus a few more bytes for object headers, etc.).
Furthermore, since the algorithm isn't too efficient on how it computes
the arrays, you would have needed enough space to hold the #codeBookOf: 24.

You should think about the problem differently. The i'th item in the
collection is just the result "printing" i to base "self size" using the
items in the collection as your characters. For example, you could use
something like:

codeBookOf: anInteger at: anIndex
        | index current |
        index := anIndex - 1.
        current := OrderedCollection new: anInteger.
        anInteger
                timesRepeat:
                        [current addFirst: (self at: index \\ self size + 1).
                        index := index // self size].
        ^current

Then you can evaluate:

        Number fromString: '2r',
                (String withAll: ('01' codeBookOfSize: 32 at: 1234567))

This returns 1234566 since we are converting from Smalltalk's 1 based
indexing to a zero based scheme.


John Brant


Reply | Threaded
Open this post in threaded view
|

Re: deadly slow !!

Howard Oh
John,

Your #codeBookOf:at: is really a great approach for avoiding wasting
memory for #codeBookOf:.
I will add your version right away except for the OrderedCollection
hard typing. I would like to give more flexibility to this method.

And your calculation seems to explain 380MB allocation well.

What is still not understood is why the big memory wont go away after
CPU usage becomes nearly zero, like for small parameters for
#codeBookOf: does.

Best Regards


Reply | Threaded
Open this post in threaded view
|

Re: deadly slow !!

Andy Bower-3
In reply to this post by Howard Oh
Howard,

> Folks,
>
> Add a method loose below.
> It won't be harmful to your image just by add it, unless you invoke it
> with unproper parameter.
>
> SequenceableCollection>>codeBookOf: anInteger
>
> anInteger <= 0 ifTrue: [^self class new].
> ^anInteger = 1
> ifTrue:
> [self collect: [:obj| self class with: obj ]]
> ifFalse:
> [|newAnswerStream|
> newAnswerStream := WriteStream on: (self class new: (self size
> raisedTo: anInteger)).
> (self codeBookOf: anInteger-1) do: [:oneSubAnswer|
> self do: [:oneObjectToAdd|
> newAnswerStream nextPut: oneSubAnswer, (self class with:
> oneObjectToAdd)]].
> newAnswerStream contents]
>
>
> This method is not a problem when anInteger is small.
>
> Try, #(true false) codeBookOf: 3
>
>
> It is a problem when anInteger is big. Try below after a good backup
> of your image.
>
>
> #(nil 0) codeBookOf: 25 "Number 25 maybe not be big enough for your
> PC."
>
>
> makes my PC(P-4 2.4GHz 512MB DDR ram) nearly stop!
>
> Memory paging goes up to 1.2GB, and Dolphin.exe eats up to 380MB.
> CPU usage goes up to 50% but soon or later it drops down to 2%.
> That seems to me like the #codeBookOf: has been answered, and
> workspace is idle.
> But workspace is still hanging and memory allocation is still 1.2GB.
> The answered object(Array) is not kept in a workspace variable so it
> must have gone garbage collected right away(or 10 sec later). But
> still 1.2GB, hard disk is turning like as if it's going to blow.
>
> As soon as I kill Dolphin.exe from process list, memory allocation
> drops down to 550MB and disk rests in peace.
>
>
> Can anyone explain this phenomenon?

Well, you are running out of stack in the VM (quite why I'm not sure).
I don't know what the method is meant to do but you have a line in
there:

(self class new: (self size raisedTo: anInteger))

So, as a miniumm you are allocating Array objects with 2^25 + 2^24 +
2^23 etc objects in them. The first term alone is worth 130Mb and that
is even without the array being filled with any objects at all so
heaven knows how much actually gets allocated.

If I run the above, what I see is this. 50% CPU and memory usage going
up until it gets to around 75% the amount of physical RAM. At that
point CPU drops to 1%-2% but look at the disk light; the machine is
into paging and is hence disk-bound. This is why the CPU drops but the
algorithm is still continuing. If I leave it for another 5 mins or so,
the Dolphin process eventually collapses and writes a crash dump. So
the reason why the memory doesn't appear to go away for you is that you
aren't letting it "finish".

Whatever the algorithm does it needs to be coded differently, I'm
afraid. If you look at the crash dump that is written following the
crash you will see that it holds:

---
21:44:05 PM, 1/17/2006: Dolphin.exe caused an unhandled Win32 Exception
C00000FD
at 7C9377C9 in module 7C900000 (C:\WINDOWS\system32\ntdll.dll)
---

C00000FD is a stack overflow.

Best regards

--
Andy Bower
Dolphin Support
www.object-arts.com


Reply | Threaded
Open this post in threaded view
|

Re: deadly slow !!

John Brant
In reply to this post by Howard Oh
Howard Oh wrote:

> Your #codeBookOf:at: is really a great approach for avoiding wasting
> memory for #codeBookOf:.
> I will add your version right away except for the OrderedCollection
> hard typing. I would like to give more flexibility to this method.
>
> And your calculation seems to explain 380MB allocation well.

It was 3,489,660,928 bytes (over 3GB). I believe Windows has a maximum
process size of 3GB.

> What is still not understood is why the big memory wont go away after
> CPU usage becomes nearly zero, like for small parameters for
> #codeBookOf: does.

Dolphin is still executing -- the CPU usage becomes nearly zero since
most of the time is spent by the OS paging to disk.


John Brant


Reply | Threaded
Open this post in threaded view
|

Re: deadly slow !!

Howard Oh
In reply to this post by Andy Bower-3
Oh~

That explains.

I didn't know that memory paging was a CPU free operation.
I couldn't dare think a process so slow be CPU free.

Thanks everybody.

Best Regards


Reply | Threaded
Open this post in threaded view
|

Re: deadly slow !!

Howard Oh
In reply to this post by John Brant
John,

I've refactored #codeBookOf: method by applying "MethodObject"
technique.
Subclassing SequencableCollection, named "CodeBook" which can answer to
#size, #at, #at:put:.
It works similar to Interval which is not a real collection but answers
properly to Collection protocol.

CodeBook>>size

        ^self codes size raisedTo: self codeLength


CodeBook>>at: anInteger

        ^((self multiQuoAndRem indexValue: anInteger-1)) collect: [:each| self
codes at: each ]


CodeBook>>at: anInteger put: anObject
        "Replace the element at index anInteger of the receiver with anObject.
        Intervals are immutable."

        ^self shouldNotImplement


CodeBook>>species

               ^Array


It can #do: #select: #collect:  without any heavy memory allocation,
although if i want the memory problem I can simply #asArray.  :-)
I'm very happy using CodeBook object.

Thank you very much for inspiring me John.

Best Regards